Skip to content

commands/sbom: describe a running device with --device (ENG-2199) - #285

Open
hiagofranco wants to merge 3 commits into
avocado-linux:mainfrom
hiagofranco:hfranco-eng-2199
Open

hiagofranco wants to merge 3 commits into
avocado-linux:mainfrom
hiagofranco:hfranco-eng-2199

Conversation

@hiagofranco

Copy link
Copy Markdown
Collaborator

Summary

avocado sbom --device [user@]host[:port] describes a running device. It asks avocadoctl over SSH for the active runtime and its merged extensions, then emits the build SBOM filtered to that set.

  • Devices carry no rpmdb, so the join key is the image id. The first commit adds it to the SBOM scopes.
  • Extensions merged on the device that the build doesn't cover (loose, HITL, unknown id) are listed as uncovered, not dropped.
  • A runtime or OS build mismatch with the local build only warns.

Closes ENG-2199.

Test plan

  • cargo fmt, cargo clippy --all-targets -- -D warnings
  • cargo test --bin avocado sbom: 85 passed. The integration suite was not run, because it prunes all docker volumes.
  • On a Raspberry Pi 4:
    • fresh device: same package list as the build SBOM
    • extension disabled on the device: dropped
    • loose extension: listed as uncovered
    • OTA adding docker and tunnels: picked up on re-run, with docker∩tunnels = 114
    • build mismatch: warns
    • unreachable device: clear error
  • The device documents pass SHACL against SPDX 3.0.1

🤖 Generated with Claude Code

@hiagofranco
hiagofranco requested a review from jetm September 23, 2026 19:01
@hiagofranco hiagofranco self-assigned this Sep 23, 2026
Comment thread src/commands/sbom/generate.rs Outdated
"type": "ExternalIdentifier",
"externalIdentifierType": "other",
"identifier": entry.image_id,
"issuingAuthority": "https://avocadolinux.org/image-id",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

problem: rootfs/initramfs emit os_build_id/initramfs_build_id under the same issuingAuthority as the extension scopes' image ids, but they are different kinds of id. An image id is uuid5 of the image file's sha256 (the key Connect stores artifacts under). os_build_id is uuid5 of the rootfs package set plus tree hash, and it never equals any uploaded image's id: the OS bundle's id is uuid5 of the .aos sha256 (var_image.rs). With externalIdentifierType: "other", the authority is the only field a consumer can use to tell identifier kinds apart, so a reader that resolves .../image-id values as images silently misses every OS scope. Nothing reads these fields yet, but the shape becomes public at 1.0, so now is the cheap moment to split them: carry the authority on ImageEntry and emit a distinct one for the build ids (e.g. https://avocadolinux.org/os-build-id). device.rs compares ImageIds in memory, so it is unaffected.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, fixed in 4eff7f7. ImageEntry now carries its authority; rootfs/initramfs emit https://avocadolinux.org/os-build-id, extensions keep .../image-id.

Comment thread src/commands/sbom/generate.rs Outdated
/// Fold another runtime's mapping in, for a document covering several
/// runtimes. `rootfs`/`initramfs` are shared scopes, so a later merge
/// wins if two runtimes' manifests disagree (rare in practice).
pub(crate) fn merge(&mut self, other: ImageIds) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

problem: merge lets whichever runtime is merged last overwrite the shared rootfs/initramfs build ids, and read_images iterates a BTreeMap, so that is the alphabetically last runtime, not the one matching the scanned sysroot. Disagreement is an ordinary workflow, not a rare one: each runtime keeps its own var-staging manifest, so building prod, updating the base packages, then rebuilding only dev leaves prod's stale os_build_id in place; the loop merges dev then prod, and the document pairs the current rootfs package list with the old build id. Runtimes can also resolve different rootfs definitions (resolve_runtime_rootfs), which changes the build id by design. When manifests disagree on a shared scope, drop that entry and warn. merge_lets_a_later_runtimes_shared_scopes_win pins the overwrite as intended and should become a conflict-omission test. Upload and --device build from a single runtime's manifest, so they are unaffected.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, fixed in 4eff7f7. merge now drops a shared scope whose ids disagree across runtimes (and keeps it dropped if a later runtime agrees with one side), and avocado sbom warns. The test is now merge_drops_a_shared_scope_the_runtimes_disagree_on.

hiagofranco and others added 2 commits September 24, 2026 09:48
Extension scopes carry the runtime manifest's image_id as an
externalIdentifier and its sha256 as verifiedUsing; rootfs and
initramfs carry os_build_id and initramfs_build_id. This gives a
device-reported image set something to join against. spdxIds are
unchanged.

avocado sbom reads the manifests from the volume, connect upload passes
the one it already has. A missing manifest only warns.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
avocado sbom --device [user@]host[:port] asks avocadoctl on the device
for the active runtime and its merged extensions, and emits the build
SBOM filtered to that set. Merged images the build does not cover
(loose .raw, HITL, unknown image ids) are listed without contents.
Runtime or OS build mismatches with the local build are warned about.

ssh runs in the SDK container, as in runtime deploy; DeviceSpec moves
to utils/device.rs so both share it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

@jetm jetm left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No blocking findings at 59d2053.

I checked the device JSON shapes against avocadoctl main (varlink Runtime and [ExtensionStatus], camelCase fields, the HITL origin string), the DeviceSpec move and its tests, the spdxId rename for dangling references, and the device-mode namespace. cargo test --bin avocado sbom passes (85/85). A few non-blocking notes on coverage edge cases and test depth were left out of this review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants