Discover SBOMs attached to images via OCI referrers and tags#1701
Discover SBOMs attached to images via OCI referrers and tags#1701st3penta merged 1 commit intoconforma:mainfrom
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughGo module dependencies updated; SBOM policy refactored to set-based aggregation and extended to discover SBOMs via OCI Referrers API and legacy Changes
Sequence Diagram(s)sequenceDiagram
participant Policy as SBOM Policy
participant OCI as OCI Referrers API
participant Tags as Image Tag Refs
participant Blob as OCI Blob Store
participant Parser as SBOM Parser
Policy->>OCI: query ec.oci.image_referrers(image)
OCI-->>Policy: referrer entries (artifactType, digest)
alt artifactType ∈ _sbom_artifact_types
Policy->>Blob: ec.oci.blob(digest)
Blob-->>Policy: blob payload (JSON)
Policy->>Parser: json.unmarshal / parse
Parser-->>Policy: SBOM object (CycloneDX/SPDX)
Policy->>Policy: add to cyclonedx/spdx sets
end
Policy->>Tags: query ec.oci.image_tag_refs(image)
Tags-->>Policy: tag refs
alt tag endsWith ".sbom"
Policy->>Blob: ec.oci.blob(tag)
Blob-->>Policy: blob payload (JSON)
Policy->>Parser: parse SBOM
Parser-->>Policy: SBOM object
Policy->>Policy: add to cyclonedx/spdx sets
end
Policy->>Policy: union/deduplicate sets -> all_sboms
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes 🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
policy/lib/sbom/sbom_test.rego (1)
8-12:⚠️ Potential issue | 🟠 MajorTest expectations use arrays but actual values are now sets.
If
cyclonedx_sbomsandspdx_sbomsare now sets (from thecontains ... ifrules), thenexpectedvalues should use set literals{...}rather than array literals[...]. In Rego,{x} == [x]evaluates tofalse.Verify that
lib.assert_equalhandles this type coercion, or update expectations to use set syntax.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@policy/lib/sbom/sbom_test.rego` around lines 8 - 12, The test test_all_sboms is comparing arrays to values that are now sets (sbom.cyclonedx_sboms and sbom.spdx_sboms), so update the expectation to use Rego set literals instead of arrays: replace the expected := ["hurricane","tornado","spandex","latex"] with a set literal { ... } or otherwise coerce sbom.all_sboms into an array before calling lib.assert_equal; ensure you reference test_all_sboms, expected, sbom.cyclonedx_sboms, sbom.spdx_sboms, sbom.all_sboms and lib.assert_equal when making the change so types match.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@policy/lib/sbom/sbom.rego`:
- Around line 18-40: The refactor turned previously-array SBOM rules into
set-based "contains ... if" rules (cyclonedx_sboms,
_cyclonedx_sboms_from_attestations, _cyclonedx_sboms_from_oci,
_cyclonedx_sboms_from_image, spdx_sboms, _spdx_*), which breaks callers that
expect arrays (array.concat and indexed "some index, s in ..."); restore array
semantics by returning arrays instead of sets for lib.sbom.cyclonedx_sboms and
lib.sbom.spdx_sboms — e.g. change the rules for cyclonedx_sboms and spdx_sboms
and their helpers to produce arrays (array comprehensions or explicit array
construction) so array.concat(lib.sbom.spdx_sboms, lib.sbom.cyclonedx_sboms) and
indexed loops (some index, s in sbom.cyclonedx_sboms) continue to work and
indices remain stable for error messages.
---
Outside diff comments:
In `@policy/lib/sbom/sbom_test.rego`:
- Around line 8-12: The test test_all_sboms is comparing arrays to values that
are now sets (sbom.cyclonedx_sboms and sbom.spdx_sboms), so update the
expectation to use Rego set literals instead of arrays: replace the expected :=
["hurricane","tornado","spandex","latex"] with a set literal { ... } or
otherwise coerce sbom.all_sboms into an array before calling lib.assert_equal;
ensure you reference test_all_sboms, expected, sbom.cyclonedx_sboms,
sbom.spdx_sboms, sbom.all_sboms and lib.assert_equal when making the change so
types match.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 482270c9-bebe-45ca-a844-aada71049e90
⛔ Files ignored due to path filters (1)
go.sumis excluded by!**/*.sum
📒 Files selected for processing (3)
go.modpolicy/lib/sbom/sbom.regopolicy/lib/sbom/sbom_test.rego
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
policy/release/sbom_cyclonedx/sbom_cyclonedx_test.rego (1)
528-543:⚠️ Potential issue | 🟡 MinorMissing OCI mocks in
assert_not_allowedhelper.Similar to the SPDX test file,
assert_allowed(lines 522-525) was updated with OCI mocks, butassert_not_allowedwas not updated. This should be addressed for consistency and to prevent potential test issues.🐛 Proposed fix
assert_not_allowed(purl, disallowed_packages) if { expected := {{ "code": "sbom_cyclonedx.allowed", "msg": sprintf("Package is not allowed: %s", [purl]), }} att := json.patch(_sbom_1_5_attestation, [{ "op": "add", "path": "/statement/predicate/components/0/purl", "value": purl, }]) # regal ignore:with-outside-test-context lib.assert_equal_results(sbom_cyclonedx.deny, expected) with input.attestations as [att] # regal ignore:with-outside-test-context -with data.rule_data.disallowed_packages as disallowed_packages + with data.rule_data.disallowed_packages as disallowed_packages + # regal ignore:with-outside-test-context + with ec.oci.image_referrers as [] + # regal ignore:with-outside-test-context + with ec.oci.image_tag_refs as [] }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@policy/release/sbom_cyclonedx/sbom_cyclonedx_test.rego` around lines 528 - 543, The test helper assert_not_allowed is missing the OCI mock setup that assert_allowed includes; update assert_not_allowed (used with sbom_cyclonedx.deny and _sbom_1_5_attestation) to add the same OCI mock context as assert_allowed so the attestation input includes OCI artifact/component mocks before calling lib.assert_equal_results; ensure you still patch the purl into the attestation and keep the with data.rule_data.disallowed_packages as disallowed_packages binding when invoking the rule.policy/release/sbom_spdx/sbom_spdx_test.rego (1)
117-132:⚠️ Potential issue | 🟡 MinorMissing OCI mocks in
assert_not_allowedhelper.The
assert_allowedhelper (lines 111-114) was updated withec.oci.image_referrers as []andec.oci.image_tag_refs as [], butassert_not_allowedwas not. This inconsistency could cause test failures or unintended OCI registry calls.🐛 Proposed fix
assert_not_allowed(purl, disallowed_packages) if { expected := {{ "code": "sbom_spdx.allowed", "msg": sprintf("Package is not allowed: %s", [purl]), }} att := json.patch(_sbom_attestation, [{ "op": "add", "path": "/statement/predicate/packages/0/externalRefs/0/referenceLocator", "value": purl, }]) # regal ignore:with-outside-test-context lib.assert_equal_results(sbom_spdx.deny, expected) with input.attestations as [att] # regal ignore:with-outside-test-context -with data.rule_data.disallowed_packages as disallowed_packages + with data.rule_data.disallowed_packages as disallowed_packages + # regal ignore:with-outside-test-context + with ec.oci.image_referrers as [] + # regal ignore:with-outside-test-context + with ec.oci.image_tag_refs as [] }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@policy/release/sbom_spdx/sbom_spdx_test.rego` around lines 117 - 132, The test helper assert_not_allowed is missing OCI mocks which assert_allowed added; update assert_not_allowed to include the same external context mocks (set ec.oci.image_referrers as [] and ec.oci.image_tag_refs as []) in the with-input override used for invoking sbom_spdx.deny so the test uses empty referrer/tag lists and avoids real OCI calls—apply this change in the same with input.attestations as [att] ... with data.rule_data.disallowed_packages as disallowed_packages block that wraps the sbom_spdx.deny assertion involving _sbom_attestation.acceptance/go.mod (1)
127-127:⚠️ Potential issue | 🟠 MajorUpdate
github.com/docker/clito fix HIGH severity privilege escalation on Windows.
github.com/docker/cli v29.0.3+incompatiblecontains CVE-2025-15558 (GHSA-p436-gjf2-799p): a local privilege escalation vulnerability where the Docker CLI plugin manager searches for plugins in a writable directory (C:\ProgramData\Docker\cli-pluginson Windows), allowing a low-privileged attacker to inject malicious plugin executables. This is fixed in v29.2.0 and later. Update the dependency or investigate the transitive dependency chain to enable a version upgrade.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@acceptance/go.mod` at line 127, The go.mod currently pins "github.com/docker/cli v29.0.3+incompatible" which is vulnerable; update that requirement to v29.2.0 or newer to remediate CVE-2025-15558: run a module upgrade for github.com/docker/cli (e.g. go get github.com/docker/cli@v29.2.0) and then run go mod tidy and tests; if the dependency is indirect, run go mod graph to find the direct module that pulls in github.com/docker/cli and update that module or add a replace directive so the resolved version of github.com/docker/cli is >= v29.2.0.
🧹 Nitpick comments (1)
policy/release/pre_build_script_task/pre_build_script_task_test.rego (1)
14-16: Inconsistentwithclause indentation.Several
withclauses have inconsistent indentation - some usewithwith a tab character after it (e.g., line 14:with \t\tinput.image), while others follow the standard pattern. This appears to be a formatting artifact.Also applies to: 42-44, 66-68, 87-89, 98-100, 107-109, 133-135, 142-144, 164-166, 178-180, 201-203
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@policy/release/pre_build_script_task/pre_build_script_task_test.rego` around lines 14 - 16, The failing/dirty formatting is inconsistent use of a tab after the with keyword in multiple with clauses (e.g., "with input.image as {...}", "with ec.oci.image_referrers as []", "with ec.oci.image_tag_refs as []" in pre_build_script_task_test.rego); fix by normalizing indentation to a single space after every with keyword across all occurrences (including the other reported ranges 42-44, 66-68, 87-89, 98-100, 107-109, 133-135, 142-144, 164-166, 178-180, 201-203) so each clause reads "with <symbol> as <value>" for symbols like input.image, ec.oci.image_referrers, and ec.oci.image_tag_refs.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In `@acceptance/go.mod`:
- Line 127: The go.mod currently pins "github.com/docker/cli
v29.0.3+incompatible" which is vulnerable; update that requirement to v29.2.0 or
newer to remediate CVE-2025-15558: run a module upgrade for
github.com/docker/cli (e.g. go get github.com/docker/cli@v29.2.0) and then run
go mod tidy and tests; if the dependency is indirect, run go mod graph to find
the direct module that pulls in github.com/docker/cli and update that module or
add a replace directive so the resolved version of github.com/docker/cli is >=
v29.2.0.
In `@policy/release/sbom_cyclonedx/sbom_cyclonedx_test.rego`:
- Around line 528-543: The test helper assert_not_allowed is missing the OCI
mock setup that assert_allowed includes; update assert_not_allowed (used with
sbom_cyclonedx.deny and _sbom_1_5_attestation) to add the same OCI mock context
as assert_allowed so the attestation input includes OCI artifact/component mocks
before calling lib.assert_equal_results; ensure you still patch the purl into
the attestation and keep the with data.rule_data.disallowed_packages as
disallowed_packages binding when invoking the rule.
In `@policy/release/sbom_spdx/sbom_spdx_test.rego`:
- Around line 117-132: The test helper assert_not_allowed is missing OCI mocks
which assert_allowed added; update assert_not_allowed to include the same
external context mocks (set ec.oci.image_referrers as [] and
ec.oci.image_tag_refs as []) in the with-input override used for invoking
sbom_spdx.deny so the test uses empty referrer/tag lists and avoids real OCI
calls—apply this change in the same with input.attestations as [att] ... with
data.rule_data.disallowed_packages as disallowed_packages block that wraps the
sbom_spdx.deny assertion involving _sbom_attestation.
---
Nitpick comments:
In `@policy/release/pre_build_script_task/pre_build_script_task_test.rego`:
- Around line 14-16: The failing/dirty formatting is inconsistent use of a tab
after the with keyword in multiple with clauses (e.g., "with input.image as
{...}", "with ec.oci.image_referrers as []", "with ec.oci.image_tag_refs as []"
in pre_build_script_task_test.rego); fix by normalizing indentation to a single
space after every with keyword across all occurrences (including the other
reported ranges 42-44, 66-68, 87-89, 98-100, 107-109, 133-135, 142-144, 164-166,
178-180, 201-203) so each clause reads "with <symbol> as <value>" for symbols
like input.image, ec.oci.image_referrers, and ec.oci.image_tag_refs.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 24076678-eb2b-48f3-a96b-138d4d7b19c5
⛔ Files ignored due to path filters (2)
acceptance/go.sumis excluded by!**/*.sumgo.sumis excluded by!**/*.sum
📒 Files selected for processing (9)
acceptance/go.modgo.modpolicy/lib/sbom/sbom.regopolicy/lib/sbom/sbom_test.regopolicy/release/base_image_registries/base_image_registries_test.regopolicy/release/pre_build_script_task/pre_build_script_task_test.regopolicy/release/sbom/sbom_test.regopolicy/release/sbom_cyclonedx/sbom_cyclonedx_test.regopolicy/release/sbom_spdx/sbom_spdx_test.rego
✅ Files skipped from review due to trivial changes (1)
- go.mod
🚧 Files skipped from review as they are similar to previous changes (1)
- policy/lib/sbom/sbom.rego
Codecov Report✅ All modified and coverable lines are covered by tests.
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
🧹 Nitpick comments (1)
policy/lib/sbom/sbom.rego (1)
84-97: Missing error handling for malformed SBOM blobs.
json.unmarshalwill fail if the blob content is not valid JSON. In Rego, a failing builtin causes the rule to not produce a value (which is acceptable), but consider whether logging or surfacing malformed SBOMs would be useful for debugging discovery issues.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@policy/lib/sbom/sbom.rego` around lines 84 - 97, The current SBOM discovery rules (_sboms_from_referrers and _sboms_from_tag_refs) call json.unmarshal(blob) but don't record or surface when that builtin fails; add companion rules (e.g., _malformed_sboms_from_referrers and _malformed_sboms_from_tag_refs) that iterate the same sources (ec.oci.image_referrers, ec.oci.image_tag_refs), bind blob := ec.oci.blob(...), and capture refs where the unmarshal fails using the "not sbom := json.unmarshal(blob)" pattern so malformed blobs are recorded (store ref/blob or emit into a diagnostic collection) for debugging; keep the original _sboms_* rules unchanged so valid SBOMs still get produced.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@policy/lib/sbom/sbom.rego`:
- Around line 84-97: The current SBOM discovery rules (_sboms_from_referrers and
_sboms_from_tag_refs) call json.unmarshal(blob) but don't record or surface when
that builtin fails; add companion rules (e.g., _malformed_sboms_from_referrers
and _malformed_sboms_from_tag_refs) that iterate the same sources
(ec.oci.image_referrers, ec.oci.image_tag_refs), bind blob := ec.oci.blob(...),
and capture refs where the unmarshal fails using the "not sbom :=
json.unmarshal(blob)" pattern so malformed blobs are recorded (store ref/blob or
emit into a diagnostic collection) for debugging; keep the original _sboms_*
rules unchanged so valid SBOMs still get produced.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 861f71c8-280d-419f-83aa-305eca29533b
⛔ Files ignored due to path filters (2)
acceptance/go.sumis excluded by!**/*.sumgo.sumis excluded by!**/*.sum
📒 Files selected for processing (9)
acceptance/go.modgo.modpolicy/lib/sbom/sbom.regopolicy/lib/sbom/sbom_test.regopolicy/release/base_image_registries/base_image_registries_test.regopolicy/release/pre_build_script_task/pre_build_script_task_test.regopolicy/release/sbom/sbom_test.regopolicy/release/sbom_cyclonedx/sbom_cyclonedx_test.regopolicy/release/sbom_spdx/sbom_spdx_test.rego
✅ Files skipped from review due to trivial changes (2)
- policy/release/pre_build_script_task/pre_build_script_task_test.rego
- acceptance/go.mod
🚧 Files skipped from review as they are similar to previous changes (3)
- policy/release/base_image_registries/base_image_registries_test.rego
- policy/release/sbom_cyclonedx/sbom_cyclonedx_test.rego
- policy/release/sbom_spdx/sbom_spdx_test.rego
simonbaird
left a comment
There was a problem hiding this comment.
Lgtm, but consider my naming nitpicks.
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
policy/lib/sbom/sbom.rego (1)
22-29:⚠️ Potential issue | 🟠 MajorKeep the exported SBOM arrays in a stable order.
Lines 22-29 rebuild
cyclonedx_sbomsandspdx_sbomsfrom sets. That keeps deduplication, but it drops discovery order, so downstreamsome index, s in ...consumers get arbitrary indices and the exact-order assertions inpolicy/lib/sbom/sbom_test.regobecome brittle. Deduplicate internally with sets if you want, but materialize the public arrays from an ordered source list so first-seen order stays stable.#!/bin/bash echo "=== public SBOM array materialization ===" sed -n '20,30p' policy/lib/sbom/sbom.rego echo echo "=== consumers that use SBOM indices ===" rg -n -C2 'some\s+index\s*,\s*\w+\s+in\s+sbom\.(cyclonedx_sboms|spdx_sboms)' --glob='*.rego' echo echo "=== tests that assert exact SBOM array contents ===" rg -n -C2 'sbom\.(cyclonedx_sboms|spdx_sboms|all_sboms)' policy/lib/sbom/sbom_test.rego🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@policy/lib/sbom/sbom.rego` around lines 22 - 29, The public arrays cyclonedx_sboms and spdx_sboms are being built from private set rules (_cyclonedx_sboms, _spdx_sboms) which loses discovery order; change them to materialize from an ordered source list (e.g. a concatenation of _cyclonedx_sboms_from_input, _cyclonedx_sboms_from_pipelinerun, _cyclonedx_sboms_from_image and similar spdx sources) and perform deduplication while iterating that ordered list so the first-seen item is kept; update the rules that reference cyclonedx_sboms/spdx_sboms so they keep stable indices while internals still use sets for membership if needed (refer to symbols: cyclonedx_sboms, spdx_sboms, _cyclonedx_sboms_from_input, _cyclonedx_sboms_from_pipelinerun, _cyclonedx_sboms_from_image, _spdx_sboms_from_input, _spdx_sboms_from_pipelinerun, _spdx_sboms_from_image, and _cyclonedx_sboms/_spdx_sboms).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@policy/lib/sbom/sbom_test.rego`:
- Around line 201-205: The tests call the wrong helper module: replace calls to
data.lib.assert_equal with data.lib.assertions.assert_equal so the correct
exported helper is used; update each assertion invocation in sbom_test.rego
(e.g., the calls that use lib.assert_equal wrapping sbom.cyclonedx_sboms,
sbom.sbom_for_image, etc.) to reference data.lib.assertions.assert_equal,
keeping the same arguments and with statements.
---
Duplicate comments:
In `@policy/lib/sbom/sbom.rego`:
- Around line 22-29: The public arrays cyclonedx_sboms and spdx_sboms are being
built from private set rules (_cyclonedx_sboms, _spdx_sboms) which loses
discovery order; change them to materialize from an ordered source list (e.g. a
concatenation of _cyclonedx_sboms_from_input, _cyclonedx_sboms_from_pipelinerun,
_cyclonedx_sboms_from_image and similar spdx sources) and perform deduplication
while iterating that ordered list so the first-seen item is kept; update the
rules that reference cyclonedx_sboms/spdx_sboms so they keep stable indices
while internals still use sets for membership if needed (refer to symbols:
cyclonedx_sboms, spdx_sboms, _cyclonedx_sboms_from_input,
_cyclonedx_sboms_from_pipelinerun, _cyclonedx_sboms_from_image,
_spdx_sboms_from_input, _spdx_sboms_from_pipelinerun, _spdx_sboms_from_image,
and _cyclonedx_sboms/_spdx_sboms).
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: f5f0359f-f3c1-4a5f-903f-039646ffd34b
⛔ Files ignored due to path filters (2)
acceptance/go.sumis excluded by!**/*.sumgo.sumis excluded by!**/*.sum
📒 Files selected for processing (9)
acceptance/go.modgo.modpolicy/lib/sbom/sbom.regopolicy/lib/sbom/sbom_test.regopolicy/release/base_image_registries/base_image_registries_test.regopolicy/release/pre_build_script_task/pre_build_script_task_test.regopolicy/release/sbom/sbom_test.regopolicy/release/sbom_cyclonedx/sbom_cyclonedx_test.regopolicy/release/sbom_spdx/sbom_spdx_test.rego
✅ Files skipped from review due to trivial changes (1)
- policy/release/pre_build_script_task/pre_build_script_task_test.rego
🚧 Files skipped from review as they are similar to previous changes (4)
- policy/release/base_image_registries/base_image_registries_test.rego
- policy/release/sbom/sbom_test.rego
- policy/release/sbom_cyclonedx/sbom_cyclonedx_test.rego
- go.mod
Use the new ec.oci.image_referrers and ec.oci.image_tag_refs builtins to discover SBOMs attached directly to the image being validated. Referrers with recognized SBOM artifact types (CycloneDX, SPDX) and legacy cosign .sbom tag references are fetched and parsed alongside the existing SLSA Provenance-based discovery. Convert SBOM collection rules from arrays to sets for natural deduplication when the same SBOM is discovered via multiple methods. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Ref: https://redhat.atlassian.net/browse/EC-1655
Use the new ec.oci.image_referrers and ec.oci.image_tag_refs builtins to discover SBOMs attached directly to the image being validated. Referrers with recognized SBOM artifact types (CycloneDX, SPDX) and legacy cosign .sbom tag references are fetched and parsed alongside the existing SLSA Provenance-based discovery.
Convert SBOM collection rules from arrays to sets for natural deduplication when the same SBOM is discovered via multiple methods.
Co-Authored-By: Claude Opus 4.6 noreply@anthropic.com
Ref: https://redhat.atlassian.net/browse/EC-1655