commands/sbom: describe a running device with --device (ENG-2199) - #285
hiagofranco wants to merge 3 commits into
Conversation
| "type": "ExternalIdentifier", | ||
| "externalIdentifierType": "other", | ||
| "identifier": entry.image_id, | ||
| "issuingAuthority": "https://avocadolinux.org/image-id", |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Agreed, fixed in 4eff7f7. ImageEntry now carries its authority; rootfs/initramfs emit https://avocadolinux.org/os-build-id, extensions keep .../image-id.
| /// 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) { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
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>
d57ec73 to
59d2053
Compare
jetm
left a comment
There was a problem hiding this comment.
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.
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.Closes ENG-2199.
Test plan
cargo fmt,cargo clippy --all-targets -- -D warningscargo test --bin avocado sbom: 85 passed. The integration suite was not run, because it prunes all docker volumes.🤖 Generated with Claude Code