Background
sbomit handles package registry downloads well. OCI images don't work this way. An image pull produces a manifest request followed by separate blob requests for each layer. Without the manifest, there's no way to know which layer digests belong to which image.
This also splits into two distinct concerns: what witness can see vs. what sbomit can resolve.
What Witness Captures
| Signal |
When |
What it gives us |
| Network attestor |
During build |
HTTP exchanges — manifest requests + layer pulls for all base images, including intermediate stages |
| OCI attestor |
Post-build |
Layer digests, diff IDs, filesystem changes on the final image tarball |
Everything inside a docker build stage is otherwise opaque to witness. The network attestor is our only window into what was consumed during the build itself.
What sbomit Needs to Resolve
To map layer digests to an image identity, sbomit needs the manifest. Two options:
- Witness records the manifest response payload - sbomit gets it inline. Downside: attestations grow significantly; opt-in vs. default is an open question.
- sbomit re-fetches the manifest from the URL in the network trace. Breaks entirely for private registries - sbomit won't have the auth tokens from the original build.
Option 1 is more robust. If payload recording is off, sbomit should at minimum flag unresolved image layer downloads.
Proposed Resolution Flow
- Network attestor captures image pulls during the build (including intermediate stage base images)
- Post-build, OCI attestor analyzes the final image - layers, diff IDs, per-layer filesystem changes
- sbomit cross-references layer digests from the network trace against the final image's layer list to establish file-level provenance for unmodified base image content
Use an existing library (go-containerregistry / crane) rather than building custom parsers for OCI Spec and legacy Docker manifest _formats.
Based on input from @jkjell and @Vyom-Yadav
Background
sbomit handles package registry downloads well. OCI images don't work this way. An image pull produces a manifest request followed by separate blob requests for each layer. Without the manifest, there's no way to know which layer digests belong to which image.
This also splits into two distinct concerns: what witness can see vs. what sbomit can resolve.
What Witness Captures
Everything inside a
docker buildstage is otherwise opaque to witness. The network attestor is our only window into what was consumed during the build itself.What sbomit Needs to Resolve
To map layer digests to an image identity, sbomit needs the manifest. Two options:
Option 1 is more robust. If payload recording is off, sbomit should at minimum flag unresolved image layer downloads.
Proposed Resolution Flow
Use an existing library (
go-containerregistry/ crane) rather than building custom parsers for OCI Spec and legacy Docker manifest _formats.Based on input from @jkjell and @Vyom-Yadav