Skip to content

fix(sbom): apply and check GOST properties on nested components too - #322

Merged
reyreavman merged 2 commits into
fix/sbom/product-deps-refsfrom
feat/sbom/gost-nested-components
Sep 15, 2026
Merged

reyreavman merged 2 commits into
fix/sbom/product-deps-refsfrom
feat/sbom/gost-nested-components

Conversation

@reyreavman

@reyreavman reyreavman commented Sep 14, 2026

Copy link
Copy Markdown
Collaborator

Summary

build.sbom.gost.* reached only metadata.component and the top-level components list. A base or imported SBOM carrying nested components kept whatever values it had below the first level, passed the GOST gate with properties missing there, and in the container-format product SBOM the container value ignored everything below the top level. Stacked on #321.

What

  • gost.Upsert sets GOST:attack_surface / GOST:security_function on every component at any nesting depth — under components and under metadata.component.components alike — not only the top level.
  • gost.Validate fails with component "<name>": missing mandatory GOST properties for a nested component without them; previously nested components were never inspected.
  • In a container-format product SBOM the container's GOST values are the maximum over all descendants transitively, per field; previously the maximum over direct children only.
  • VERIFIED: on a two-image stapel product the merged container SBOM still passes 3p-ispras-sbom-checker --format container (файл корректный) with the container values unchanged, as expected for the flat component lists syft emits.
  • No change for SBOMs without nested components: syft does not emit nesting, so current outputs are byte-identical apart from serial number and timestamp.
  • Deliberately unchanged: which value the container receives when the config sets it explicitly — setMissingGOSTOnComponent still prefers the value already on the image root. The model question (whether the container is always derived or may be set) is open on the tracking card and not decided here.

Why

Upsert and Validate iterated bom.Components one level deep, and aggregateGOST read only the slice it was handed. A nested component was therefore invisible to all three: it kept foreign values from its origin SBOM, was not validated, and did not participate in the container maximum. The ISPRAS checker enforces container == max(all descendants) for both fields, so a nested yes under a container computed as indirect is a hard ERROR at submission time, while our own validation stayed silent.

Alternative considered: leaving Upsert shallow and only making aggregateGOST transitive. Rejected: the gate would then accept an SBOM whose nested components lack the properties entirely, and the checker treats a missing property as invalid.

GOST upsert and validation walked only metadata.component and the
top-level components list, and the container value in the product
SBOM was aggregated from the top level alone. A base or imported SBOM
with nested components kept its old values, passed validation with
missing properties, and could hold a higher value than the container
above it, which the ISPRAS checker rejects.

Recurse through nested components in Upsert, Validate and
aggregateGOST so the whole tree gets the configured values, is
checked, and the container reflects the maximum over all descendants.

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

Copy link
Copy Markdown
Collaborator Author

Verification

  • Mutation: recursion removed from UpsertGost SBOM setter Set should set GOST properties on nested components fails; from Validateshould fail if GOST properties are missing in nested components fails (Expected an error, got nil); from aggregateGOSThigher value only in a grandchild and fields are aggregated independently fail. All three observed before the fix landed.
  • Hand-run: werf sbom merge --ispras-format container on a two-image stapel product with the new binary, then 3p-ispras-sbom-checker --format containerфайл корректный.

Follow-up

…nt too

Upsert and Validate descended into bom.Components but not into
metadata.component.components, so a BOM whose root component nests
its parts — the shape werf itself emits for a container-format
product — left those parts untouched and unvalidated. Walk them with
the same recursion.

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

Copy link
Copy Markdown
Collaborator Author

Independent review (gpt, read-only) + mutation loop

Review verdict: approve, one Minor finding — Upsert/Validate did not descend into metadata.component.components, so "every component at any nesting depth" in the description was not strictly true. Fixed in 2308ad5: both functions now walk that subtree; two new table entries (should set GOST properties on components nested under the metadata component, should fail if GOST properties are missing in components nested under the metadata component) failed before the fix and pass after.

Mutation loop run by hand on the PR head, each mutation restored afterwards:

Mutation Failing test
recursion removed from setComponents should set GOST properties on nested components
recursion removed from validateComponents should fail if GOST properties are missing in nested components
recursion removed from aggregateGOST higher value only in a grandchild, fields are aggregated independently
nested max fields swapped in aggregateGOST fields are aggregated independently
setComponents iterating by value 3 Upsert entries incl. the nested one

Reviewer's other notes, not acted on: nested error message does not carry the parent path (same as before for top-level duplicates); withGOST helper lives inline in gost_test.go, matching container_test.go in the same package.

@reyreavman
reyreavman marked this pull request as ready for review September 14, 2026 15:15
@reyreavman
reyreavman merged commit 40cec65 into fix/sbom/product-deps-refs Sep 15, 2026
14 of 15 checks passed
@reyreavman
reyreavman deleted the feat/sbom/gost-nested-components branch September 15, 2026 03:14
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