Skip to content

fix(sbom): key artifact fallback index tag by image name - #219

Open
reyreavman wants to merge 1 commit into
mainfrom
fix/sbom/attach-lost-update
Open

fix(sbom): key artifact fallback index tag by image name#219
reyreavman wants to merge 1 commit into
mainfrom
fix/sbom/attach-lost-update

Conversation

@reyreavman

Copy link
Copy Markdown
Collaborator

Summary

Two werf images with identical content share one digest, and the SBOM fallback
index was keyed by that digest alone, so both images wrote into the same mutable
index and lost each other's entries. The tag is now keyed by digest and image
name, which removes the shared object instead of guarding it.

Key changes

  • pkg/oci/artifact/fallback.go
    • FallbackTag(parentDigest, imageName) produces sha256-<hex>-<slug(imageName)>;
      the image name is encoded with slug.LimitedSlug within a 56-char budget
      (128 tag limit − prefix − digest hex − separator). An empty image name keeps
      the digest-only form written by previous versions.
    • New FallbackTagDigestPrefix and ParseFallbackTagDigest; the latter accepts
      both the per-image and the legacy digest-only form.
    • imageName threaded through Attach, waitForConsistency, tagMutexKey,
      pullFallbackIndex and pushFallbackIndex.
    • PullFallbackIndex now merges the per-image indexes of a digest into one
      read-only view, so digest-scoped readers keep their previous semantics.
  • pkg/storage/repo_stages_storage.go: GetOrphanedArtifactNames parses the
    digest via ParseFallbackTagDigest instead of trimming the whole suffix.
  • pkg/sbom/image/image.go: FallbackTag wrapper takes the image name.
  • Tests: per-image tag encoding and ParseFallbackTagDigest cases in
    digest_test.go, updated tagMutexKey cases, and regressions_test.go now
    asserts one annotated entry per per-image tag.

Why

werf sbom merge failed with no artifact of type "application/vnd.dsse.envelope.v1+json" found for digest ... whenever two images resolved to the same digest: their SBOM
attaches raced on one index and one entry was dropped.

Serializing the read-modify-write in-process (#210) is not sufficient, because the
index is re-read from the registry between lock acquisition and push, and a registry
gives no read-after-write guarantee. The e2e job of #217 already contains that fix
and still reproduced the failure. Keying the tag per image leaves no shared object
to lose updates on, on any number of processes or hosts.

Review focus / risks

  • Storage format change. SBOMs pushed under the old digest-only tag are not
    found by name anymore and are regenerated on the next build (cache miss, not an
    error). Old indexes stay until cleanup collects them with the parent digest.
    Mixed werf versions will not see each other's SBOMs until a rebuild.
  • GetAttachedContentAny (werf sbom get --digest, attestation get) now lists
    repository tags instead of fetching a single tag.
  • The mutex and consistency wait from fix(sbom): prevent storage fallback inconsistency #210 are kept: they still guard repeated
    writes to the same tag.
  • Pre-existing and untouched: pkg/oci/artifact/store.go:123 passes s.opts...
    instead of s.remoteOptions(ctx), unlike the neighbouring GetAttached, so that
    path runs without registry auth. Worth a separate issue.

Two werf images with identical content share one digest, and the fallback
index was keyed by that digest alone. Both images then attached their SBOM
to the same mutable index, so concurrent attaches read the same state and
overwrote each other's entry: `werf sbom merge` failed with "no artifact of
type ... found for digest".

Serializing the read-modify-write in-process was not enough, because the
index is re-read from the registry, which gives no read-after-write
guarantee.

Key the tag by the parent digest and the image name instead, so that each
image owns its index and there is no shared object left to lose updates on.
An empty image name keeps the digest-only form, which is also the form
written by previous versions, and cleanup keeps recognizing both.

Readers that are not scoped to an image, `werf sbom get --digest` and
attestation listing, now merge the per-image indexes of a digest into one
view, so their behaviour is unchanged.

Signed-off-by: Radmir Khurum <radmir.khurum@flant.com>
@reyreavman reyreavman changed the title fix(sbom, oci): key artifact fallback index tag by image name fix(sbom): key artifact fallback index tag by image name Aug 4, 2026
@reyreavman
reyreavman marked this pull request as ready for review August 4, 2026 13:23
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.

1 participant