Skip to content

fix(sbom): regenerate the SBOM when the GOST configuration changes - #271

Merged
nervgh merged 2 commits into
mainfrom
fix/sbom/checksum-completeness
Aug 31, 2026
Merged

fix(sbom): regenerate the SBOM when the GOST configuration changes#271
nervgh merged 2 commits into
mainfrom
fix/sbom/checksum-completeness

Conversation

@reyreavman

Copy link
Copy Markdown
Collaborator

Summary

Changing build.sbom.gost did not regenerate the attached SBOM: the build reused the artifact from the previous run, so the document kept the old GOST properties. Reproduces from a clean checkout on any image whose SBOM has no base or imported document:

project: gost-repro
configVersion: 1
build:
  sbom:
    enable: true
    standard: "cyclonedx@1.6"
    gost:
      attackSurface: yes
      securityFunction: yes
---
image: app
from: registry.werf.io/werf/scratch

Build with --repo, flip attackSurface to no, build again — werf sbom get app still reports yes.

What

  • After a change to build.sbom.gost, the next build regenerates the SBOM artifact instead of reusing the attached one, including for images with no base or imported SBOM document, where the setting previously reached the checksum through nothing at all.
  • The SBOM artifact checksum layout changed, so the first build after upgrading regenerates every image's SBOM once; later builds reuse the cache as before.
  • Single-platform SBOM checksums change as well: the target platform now occupies a fixed part slot instead of being appended only when non-empty.
  • Two distinct settings can no longer collide through the part separator: a signer identity containing - used to absorb the platform slot boundary.
  • Deliberately unchanged: the packages directive (os-pm) and a scratch base stay out of the checksum — both already move the parent stage digest, which is the other half of the SBOM cache key.
  • Deliberately unchanged: MergeOpts.Checksum() still covers only base and imported document content.

Why

The SBOM section feeds no stage digest, and the GOST configuration reached the artifact checksum only as a side effect: prepareGostComponents upserts GOST properties into base and imported documents before the checksum is computed. An image with neither left the setting invisible to both halves of the cache key, while gost.Upsert still applied it to the result document at generation time — a silently stale compliance artifact. wiki/pages/sbom-cache-invalidation.md already documented the opposite behavior.

Putting the configuration inside MergeOpts.Checksum() was rejected: GOST is post-processing configuration rather than a merge input, and that channel would count the same setting twice for images that do have base or imported documents.

The SBOM artifact checksum is compared against the annotation on the
already attached artifact to decide whether a cached SBOM can be reused
for the same parent stage digest. GOST settings reached that checksum
only indirectly, through the base and imported documents that
prepareGostComponents happens to upsert, and not at all when an image has
neither - a scratch image, for example. Since the SBOM section feeds no
stage digest, changing build.sbom.gost left both halves of the cache key
intact and the user kept receiving an SBOM without the requested GOST
properties, even though the documented behavior is that the artifact is
regenerated with the new requirements.

Give the effective GOST configuration its own checksum parts so it is
accounted for through exactly one explicit channel, independent of
whether any base or imported document exists.

While the layout changes, drop the separator-joined encoding: parts were
concatenated with "-" and the platform part was appended only when
non-empty, so a value containing the separator absorbed a slot boundary
and distinct inputs collapsed onto the same checksum. Every part is now
always present and keyed, hashed as individual arguments. Mutation
testing on the collision case drove this: the first version of the test
passed under the old encoding too.

The os-pm packages directive and the scratch base stay out of the
checksum deliberately: the directive compiles into the generated install
command that feeds the Packages stage digest, and the stage appears and
disappears along with it, so any change already moves the parent digest.
The exclusions and the reasoning now live next to the computation.

Existing projects regenerate each SBOM once on the first build after
upgrading, then resume reusing the cache.

Signed-off-by: Radmir Khurum <radmir.khurum@flant.com>
@reyreavman

Copy link
Copy Markdown
Collaborator Author

Verification

  • Mutation: removed the two GOST parts → gost attack surface, gost security function and GOST config changes checksum even without base and import BOMs failed. Restored the separator-joined encoding → does not collide when a part value absorbs a slot boundary failed; the first version of that case passed under the old encoding too, which is why it was rewritten around a value that absorbs a slot boundary.
  • Not run: task test:e2e paths="./test/e2e/sbom/..." labelFilter="sbom" and task test:integration — the host is macOS without WERF_TEST_K8S_DOCKER_REGISTRY; test/e2e/sbom/gost_cache_invalidation_test.go has so far only been compiled.

Review focus

  • The checksum layout change invalidates every attached SBOM once. Confirm a one-time regeneration wave is acceptable for the release this lands in.
  • pkg/build/sbom_step_checksum_test.go is largely rewritten: two pre-existing cases asserted the old behavior — GOST config does not change unsigned checksum, and one whose name claimed os-pm coverage it never exercised.

Follow-up

  • BLOCKER: e2e (labelFilter="sbom") and integration green in CI — the GOST toggle scenario has never executed anywhere.

Signed-off-by: Radmir Khurum <radmir.khurum@flant.com>
@nervgh
nervgh marked this pull request as ready for review August 31, 2026 09:56
@nervgh
nervgh merged commit 5d74fbe into main Aug 31, 2026
14 of 15 checks passed
@nervgh
nervgh deleted the fix/sbom/checksum-completeness branch August 31, 2026 09:56
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.

2 participants