Skip to content

Add bundle auto-detection to Rego sigstore builtins#3269

Open
st3penta wants to merge 7 commits intoconforma:mainfrom
st3penta:EC-1700
Open

Add bundle auto-detection to Rego sigstore builtins#3269
st3penta wants to merge 7 commits intoconforma:mainfrom
st3penta:EC-1700

Conversation

@st3penta
Copy link
Copy Markdown
Contributor

@st3penta st3penta commented May 4, 2026

The Rego sigstore builtins (verify_attestation and verify_image)
only supported the legacy .att tag path for signature and
attestation verification. Images with attestations stored as OCI
referrer bundles (cosign v3 --new-bundle-format) were invisible
to Rego policies.

Add HasBundles(ctx, ref) to the oci.Client interface so bundle
detection can be mocked in unit tests, then use it in both
builtins to auto-detect the format before verification. When
bundles are present, switch to the bundle verification path with
NewBundleFormat=true and the appropriate parser/verifier. When
no bundles are found or detection fails, fall back to the legacy
path unchanged. Refactor ApplicationSnapshotImage.hasBundles()
to delegate to the new interface method.

Add an acceptance test scenario that pushes attestations and
signatures as OCI referrers and verifies them through the Rego
builtins end-to-end.

Ref: https://issues.redhat.com/browse/EC-1700

Co-Authored-By: Claude Opus 4.6 noreply@anthropic.com

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 4, 2026

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Detects OCI Sigstore bundles via a new Client.HasBundles call and branches verification into bundle-format (OCI referrer) or legacy paths; adds bundle-aware attestation parsing and protobuf bundle referrer creation, extends OCI client interface and tests, and updates acceptance BDD for bundle-format attestations.

Changes

Bundle Format Attestation Support

Layer / File(s) Summary
Data Shape / Interfaces
internal/utils/oci/client.go, internal/utils/oci/fake/client.go
Adds HasBundles(context.Context, name.Reference) (bool, error) to Client; defaultClient.HasBundles implemented using cosign.GetBundles; FakeClient exposes a mocked HasBundles.
Bundle Detection Wiring
internal/evaluation_target/application_snapshot_image/application_snapshot_image.go
Replaces local cosign bundle check with oci.NewClient(ctx).HasBundles(ctx, a.reference) and removes ociremote import.
Verification Branching (Core)
internal/rego/sigstore/sigstore.go
sigstoreVerifyImage and sigstoreVerifyAttestation call HasBundles and branch: when bundles present enable checkOpts.NewBundleFormat, use cosign.IntotoSubjectClaimVerifier + VerifyImageAttestations; otherwise use cosign.SimpleClaimVerifier + VerifyImageSignatures.
Attestation Parsing / Result Formatting
internal/rego/sigstore/sigstore.go
attestationResult gains useBundles bool; in bundle mode reads each signature payload as DSSE, validates payloadType == "application/vnd.in-toto+json", derives provenance with ProvenanceFromBundlePayload, and skips malformed/non-matching payloads; legacy path uses ProvenanceFromSignature.
Referrer Creation / Bundle Output
acceptance/image/image.go
uploadToTransparencyLog now returns (*bundle.RekorBundle, *models.LogEntryAnon, error); CreateAndPushAttestationReferrer builds a Sigstore protobuf bundle from the raw tlog entry and writes the referrer with cosignRemote.WriteAttestationNewBundleFormat.
Signature/Attestation Extraction
acceptance/image/image.go
AttestationSignaturesFrom, RawAttestationSignaturesFrom, ImageSignaturesFrom, RawImageSignaturesFrom now merge OCI referrer maps with legacy tag-based maps; legacy entries overwrite referrer entries for identical keys.
Unit Test Adjustments
internal/evaluation_target/..._test.go, internal/image/validate_test.go
Tests updated to expect an initial HasBundles mock call (commonly returning false, nil) and to adjust call indexing where necessary.
Bundle-Focused Tests
internal/rego/sigstore/sigstore_test.go
Adds bundleDSSEPayload helper and new tests exercising bundle-format verification, malformed payload handling, non-in-toto payload skipping, and fallback behavior when HasBundles is false or errors.
Acceptance BDD
features/validate_image.feature
Adds "sigstore functions with bundle-format attestations" scenario that provisions a bundle key, creates referrers, and validates an image via Rekor and the bundle public key.

Sequence Diagram

sequenceDiagram
    participant CLI as CLI
    participant Eval as Evaluator
    participant OCI as OCI Client
    participant Verifier as Sigstore Verifier
    participant Parser as Attestation Parser

    CLI->>Eval: ValidateImage(ctx, image)
    Eval->>OCI: HasBundles(ctx, imageRef)
    alt Bundles present
        OCI-->>Eval: true
        Eval->>Verifier: VerifyImageAttestations (NewBundleFormat=true)
        Verifier->>OCI: Fetch referrers / bundles
        OCI-->>Verifier: bundles/referrers
        Verifier->>Parser: attestationResult(attestations, useBundles=true)
        Parser->>Parser: Parse DSSE envelope(s), validate payloadType
        Parser-->>Verifier: provenance/attestation entries
        Verifier-->>Eval: verification result
    else No bundles or detection error
        OCI-->>Eval: false / error
        Eval->>Verifier: VerifyImageSignatures (legacy)
        Verifier->>OCI: Fetch tag-based signatures
        OCI-->>Verifier: signatures
        Verifier->>Parser: attestationResult(signatures, useBundles=false)
        Parser->>Parser: ProvenanceFromSignature
        Parser-->>Verifier: provenance/attestation entries
        Verifier-->>Eval: verification result
    end
    Eval-->>CLI: final result
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 32.35% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: adding automatic bundle detection to the Rego sigstore builtins, which aligns with all the code changes in the PR.
Description check ✅ Passed The description comprehensively explains the problem (Rego builtins didn't support bundle format), the solution (adding HasBundles interface and auto-detection logic), and the fallback behavior, all of which match the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Comment @coderabbitai help to get the list of available commands and usage tips.

@qodo-code-review
Copy link
Copy Markdown
Contributor

Review Summary by Qodo

Add bundle auto-detection to Rego sigstore builtins with fallback support

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Add HasBundles() method to oci.Client interface for testable bundle detection
• Auto-detect Sigstore bundles in verify_attestation and verify_image Rego builtins
  - Uses bundle verification path with NewBundleFormat=true when bundles present
  - Falls back to legacy path when no bundles found or detection fails
  - Skips non-in-toto payload types silently
• Refactor ApplicationSnapshotImage.hasBundles() to use new Client.HasBundles() method
• Add comprehensive unit tests covering bundle and legacy verification paths
• Add acceptance test scenario for bundle-format attestation verification
Diagram
flowchart LR
  A["oci.Client Interface"] -->|HasBundles| B["Bundle Detection"]
  B -->|Bundles Found| C["Bundle Verification Path"]
  B -->|No Bundles/Error| D["Legacy Verification Path"]
  C -->|verify_attestation| E["ProvenanceFromBundlePayload"]
  C -->|verify_image| F["IntotoSubjectClaimVerifier"]
  D -->|verify_attestation| G["ProvenanceFromSignature"]
  D -->|verify_image| H["SimpleClaimVerifier"]
Loading

Grey Divider

File Changes

1. internal/utils/oci/client.go ✨ Enhancement +10/-0

Add HasBundles method to Client interface

internal/utils/oci/client.go


2. internal/utils/oci/fake/client.go 🧪 Tests +5/-0

Implement HasBundles in FakeClient mock

internal/utils/oci/fake/client.go


3. internal/evaluation_target/application_snapshot_image/application_snapshot_image.go ✨ Enhancement +2/-4

Refactor hasBundles to use Client interface

internal/evaluation_target/application_snapshot_image/application_snapshot_image.go


View more (6)
4. internal/evaluation_target/application_snapshot_image/application_snapshot_image_test.go 🧪 Tests +6/-2

Add HasBundles mock expectations to tests

internal/evaluation_target/application_snapshot_image/application_snapshot_image_test.go


5. internal/rego/sigstore/sigstore.go ✨ Enhancement +60/-10

Add bundle auto-detection to verify_attestation and verify_image

internal/rego/sigstore/sigstore.go


6. internal/rego/sigstore/sigstore_test.go 🧪 Tests +291/-0

Add comprehensive bundle and fallback test cases

internal/rego/sigstore/sigstore_test.go


7. internal/image/validate_test.go 🧪 Tests +6/-0

Add HasBundles mock expectations to validation tests

internal/image/validate_test.go


8. acceptance/image/image.go ✨ Enhancement +24/-16

Support referrer attestation and signature extraction

acceptance/image/image.go


9. features/validate_image.feature 🧪 Tests +23/-0

Add acceptance test for bundle-format attestations

features/validate_image.feature


Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Copy Markdown
Contributor

qodo-code-review Bot commented May 4, 2026

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (0) 📎 Requirement gaps (0)

Context used
✅ Tickets: EC-1700

Grey Divider


Action required

1. verify_image checks attestations 🐞 Bug ⛨ Security
Description
When bundles are detected, sigstoreVerifyImage() calls VerifyImageAttestations() with
IntotoSubjectClaimVerifier and returns those results as image signatures. This can allow
ec.sigstore.verify_image to succeed even if there are no image signatures, as long as attestations
exist.
Code

internal/rego/sigstore/sigstore.go[R135-152]

+	client := ecoci.NewClient(ctx)
+	useBundles, err := client.HasBundles(ctx, ref)
+	if err != nil {
+		logger.WithField("error", err).Debug("bundle detection failed, falling back to legacy path")
+		useBundles = false
+	}
+
+	var signatures []oci.Signature
+	if useBundles {
+		logger.Debug("bundles detected, using bundle verification path")
+		checkOpts.NewBundleFormat = true
+		checkOpts.ClaimVerifier = cosign.IntotoSubjectClaimVerifier
+		signatures, _, err = client.VerifyImageAttestations(ref, checkOpts)
+	} else {
+		checkOpts.ClaimVerifier = cosign.SimpleClaimVerifier
+		logger.Debug("verifying image signatures")
+		signatures, _, err = client.VerifyImageSignatures(ref, checkOpts)
+	}
Evidence
The builtin named/declared as verifying an image signature switches to attestation verification on
the bundle path. Repo acceptance code also treats signature referrers and attestation referrers as
distinct artifact types, reinforcing that VerifyImageAttestations is not the same thing as verifying
image signatures.

internal/rego/sigstore/sigstore.go[89-110]
internal/rego/sigstore/sigstore.go[135-152]
acceptance/image/image.go[407-415]
acceptance/image/image.go[702-711]
acceptance/examples/sigstore.rego[23-56]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`ec.sigstore.verify_image` is intended to verify *image signatures*, but when `HasBundles` is true it verifies *attestations* instead (`VerifyImageAttestations`) and returns those as `signatures`.

### Issue Context
The acceptance helpers create distinct referrers for signatures vs attestations (different artifact types). Switching `verify_image` to verify attestations changes the security meaning of policies that rely on `verify_image` to assert an image was signed.

### Fix Focus Areas
- internal/rego/sigstore/sigstore.go[135-152]

### Suggested fix
- In the `useBundles` branch of `sigstoreVerifyImage`, keep `checkOpts.NewBundleFormat = true` but call `VerifyImageSignatures(ref, checkOpts)` (not `VerifyImageAttestations`).
- Keep `checkOpts.ClaimVerifier = cosign.SimpleClaimVerifier` for image signatures (the attestation-specific verifier should remain in `verify_attestation`).
- Update/extend unit tests so the bundle path asserts `VerifyImageSignatures` is used, and ensure the acceptance scenario still passes with referrer signatures present.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Bundle parse errors skipped 🐞 Bug ◔ Observability
Description
In bundle mode, attestationResult() silently drops entries when Payload() fails or when the payload
is not valid DSSE JSON, rather than returning an error term for the user. This makes malformed
bundle data harder to diagnose because the builtin may report success with empty attestations/errors
until downstream policy checks fail generically.
Code

internal/rego/sigstore/sigstore.go[R384-400]

+		if useBundles {
+			payload, pErr := s.Payload()
+			if pErr != nil {
+				log.WithField("error", pErr).Debug("skipping bundle entry: cannot read payload")
+				continue
+			}
+			var dsseEnvelope struct {
+				PayloadType string `json:"payloadType"`
+			}
+			if jErr := json.Unmarshal(payload, &dsseEnvelope); jErr != nil {
+				log.WithField("error", jErr).Debug("skipping bundle entry: not a valid DSSE envelope")
+				continue
+			}
+			if dsseEnvelope.PayloadType != "application/vnd.in-toto+json" {
+				log.WithField("payloadType", dsseEnvelope.PayloadType).Debug("skipping bundle entry with non-in-toto payloadType")
+				continue
+			}
Evidence
The bundle path uses continue on payload read failure and JSON unmarshal failure; legacy parsing
paths add "parsing attestation" errors to the output, so this is a regression in surfaced detail for
certain malformed inputs.

internal/rego/sigstore/sigstore.go[372-409]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`attestationResult(..., useBundles=true, ...)` currently skips malformed bundle entries (payload read / invalid JSON) without recording anything in `errors`, which reduces debuggability.

### Issue Context
Skipping non-in-toto payload types is fine (explicit requirement), but unreadable payloads or invalid DSSE envelope JSON are unexpected and should be surfaced in the builtin output similarly to other parsing errors.

### Fix Focus Areas
- internal/rego/sigstore/sigstore.go[384-400]

### Suggested fix
- When `s.Payload()` fails: append an error term like `"parsing attestation: cannot read payload: ..."` instead of `continue`.
- When DSSE envelope JSON unmarshal fails: append an error term like `"parsing attestation: not a valid DSSE envelope: ..."` instead of `continue`.
- Keep the existing behavior to silently skip non-in-toto `payloadType` entries.
- Add a unit test for the invalid-JSON DSSE envelope case to lock in the improved error reporting.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Comment on lines +135 to +152
client := ecoci.NewClient(ctx)
useBundles, err := client.HasBundles(ctx, ref)
if err != nil {
logger.WithField("error", err).Debug("bundle detection failed, falling back to legacy path")
useBundles = false
}

var signatures []oci.Signature
if useBundles {
logger.Debug("bundles detected, using bundle verification path")
checkOpts.NewBundleFormat = true
checkOpts.ClaimVerifier = cosign.IntotoSubjectClaimVerifier
signatures, _, err = client.VerifyImageAttestations(ref, checkOpts)
} else {
checkOpts.ClaimVerifier = cosign.SimpleClaimVerifier
logger.Debug("verifying image signatures")
signatures, _, err = client.VerifyImageSignatures(ref, checkOpts)
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. Verify_image checks attestations 🐞 Bug ⛨ Security

When bundles are detected, sigstoreVerifyImage() calls VerifyImageAttestations() with
IntotoSubjectClaimVerifier and returns those results as image signatures. This can allow
ec.sigstore.verify_image to succeed even if there are no image signatures, as long as attestations
exist.
Agent Prompt
### Issue description
`ec.sigstore.verify_image` is intended to verify *image signatures*, but when `HasBundles` is true it verifies *attestations* instead (`VerifyImageAttestations`) and returns those as `signatures`.

### Issue Context
The acceptance helpers create distinct referrers for signatures vs attestations (different artifact types). Switching `verify_image` to verify attestations changes the security meaning of policies that rely on `verify_image` to assert an image was signed.

### Fix Focus Areas
- internal/rego/sigstore/sigstore.go[135-152]

### Suggested fix
- In the `useBundles` branch of `sigstoreVerifyImage`, keep `checkOpts.NewBundleFormat = true` but call `VerifyImageSignatures(ref, checkOpts)` (not `VerifyImageAttestations`).
- Keep `checkOpts.ClaimVerifier = cosign.SimpleClaimVerifier` for image signatures (the attestation-specific verifier should remain in `verify_attestation`).
- Update/extend unit tests so the bundle path asserts `VerifyImageSignatures` is used, and ensure the acceptance scenario still passes with referrer signatures present.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

st3penta and others added 2 commits May 4, 2026 14:56
The Rego sigstore builtins need to detect whether an image has
Sigstore bundles (OCI referrers) before verification, but
cosign.GetBundles() is a package-level function that cannot be
mocked through the existing FakeClient. This makes the bundle
code path untestable in unit tests.

Add HasBundles(ctx, ref) to the Client interface, wrapping the
cosign.GetBundles() call and returning a boolean. Refactor
ApplicationSnapshotImage.hasBundles() to delegate to the new
method instead of calling cosign directly.

Ref: https://issues.redhat.com/browse/EC-1700

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The verify_attestation Rego builtin only supported the legacy
.att tag path for attestation verification. Images with
attestations stored as OCI referrer bundles (cosign v3
--new-bundle-format) were invisible to Rego policies.

Call HasBundles() before verification to auto-detect the format.
When bundles are present, set NewBundleFormat=true and parse
attestations via ProvenanceFromBundlePayload with DSSE envelope
payloadType filtering. When no bundles are found or detection
fails, fall back to the legacy path unchanged.

Ref: https://issues.redhat.com/browse/EC-1700

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
internal/rego/sigstore/sigstore_test.go (1)

557-560: ⚡ Quick win

Assert legacy mode explicitly in fallback tests.

These fallback cases verify the call path, but they don’t assert that checkOpts.NewBundleFormat is false. A regression that still enables bundle mode could slip through.

Suggested test hardening
 c.On(
 	"VerifyImageAttestations", goodImage, mock.Anything,
-).Return([]oci.Signature{goodSig}, false, nil)
+).Return([]oci.Signature{goodSig}, false, nil).Run(func(args mock.Arguments) {
+	checkOpts := args.Get(1).(*cosign.CheckOpts)
+	require.False(t, checkOpts.NewBundleFormat)
+})

 c.On(
 	"VerifyImageSignatures", goodImage, mock.Anything,
-).Return([]oci.Signature{sig}, false, nil)
+).Return([]oci.Signature{sig}, false, nil).Run(func(args mock.Arguments) {
+	checkOpts := args.Get(1).(*cosign.CheckOpts)
+	require.False(t, checkOpts.NewBundleFormat)
+})

As per coding guidelines "Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity."

Also applies to: 672-674

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/rego/sigstore/sigstore_test.go` around lines 557 - 560, The fallback
tests that mock HasBundles/VerifyImageAttestations need an explicit assertion
that bundle mode was not used: capture the options passed into the mocked
VerifyImageAttestations call (e.g., via mock.MatchedBy or the mock.Run callback
on the VerifyImageAttestations expectation) and assert that the
checkOpts.NewBundleFormat field is false; reference the mocked methods
VerifyImageAttestations and HasBundles and the variables goodImage/goodSig so
the assertion validates the fallback path rather than silently allowing bundle
mode.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@internal/utils/oci/client.go`:
- Around line 76-80: The HasBundles method is too coarse—change detection to be
artifact-type specific or add a fallback to the legacy verifier so mixed-format
images don't produce false negatives. Update the Client interface by replacing
or augmenting HasBundles(context.Context, name.Reference) (bool, error) with an
artifact-aware method (for example HasBundlesForType(ctx, ref, artifactType)
(bool, error) or HasBundles(ctx, ref) (map[string]bool, error)), implement the
corresponding logic in the OCI client, and then update callers
(internal/rego/sigstore/sigstore.go and
internal/evaluation_target/application_snapshot_image/application_snapshot_image.go)
to query by artifact type (or consult the map) and, if the bundle path has no
matching artifact type, fall back to the legacy
VerifyImageSignatures/VerifyImageAttestations paths instead of assuming no
verification is possible.

---

Nitpick comments:
In `@internal/rego/sigstore/sigstore_test.go`:
- Around line 557-560: The fallback tests that mock
HasBundles/VerifyImageAttestations need an explicit assertion that bundle mode
was not used: capture the options passed into the mocked VerifyImageAttestations
call (e.g., via mock.MatchedBy or the mock.Run callback on the
VerifyImageAttestations expectation) and assert that the
checkOpts.NewBundleFormat field is false; reference the mocked methods
VerifyImageAttestations and HasBundles and the variables goodImage/goodSig so
the assertion validates the fallback path rather than silently allowing bundle
mode.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Enterprise

Run ID: a2b8a858-e2fd-43e7-9d9f-6dc367b78bfd

📥 Commits

Reviewing files that changed from the base of the PR and between b345847 and ff5b0d3.

⛔ Files ignored due to path filters (1)
  • features/__snapshots__/validate_image.snap is excluded by !**/*.snap
📒 Files selected for processing (9)
  • acceptance/image/image.go
  • features/validate_image.feature
  • internal/evaluation_target/application_snapshot_image/application_snapshot_image.go
  • internal/evaluation_target/application_snapshot_image/application_snapshot_image_test.go
  • internal/image/validate_test.go
  • internal/rego/sigstore/sigstore.go
  • internal/rego/sigstore/sigstore_test.go
  • internal/utils/oci/client.go
  • internal/utils/oci/fake/client.go

Comment thread internal/utils/oci/client.go
st3penta and others added 2 commits May 4, 2026 16:47
Same bundle auto-detection as verify_attestation, applied to
verify_image. When bundles are detected, switch from
SimpleClaimVerifier + VerifyImageSignatures to
IntotoSubjectClaimVerifier + VerifyImageAttestations with
NewBundleFormat=true, matching the ApplicationSnapshotImage
pattern. Legacy path unchanged.

Ref: https://issues.redhat.com/browse/EC-1700

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add a scenario that pushes attestations and signatures as OCI
referrers (bundle format) and verifies them through the Rego
sigstore builtins. Consolidate referrer signatures into the
acceptance test output maps so snapshot template variables
resolve for referrer-format entries.

Ref: https://issues.redhat.com/browse/EC-1700

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@internal/rego/sigstore/sigstore.go`:
- Around line 135-152: The repo-level HasBundles check (ecoci.NewClient ->
client.HasBundles) is being used as an exclusive switch causing attestations or
signatures to be skipped; change VerifyImageAttestations/VerifyImageSignatures
flow so you attempt the bundle verification (client.VerifyImageAttestations with
checkOpts.NewBundleFormat=true and
ClaimVerifier=cosign.IntotoSubjectClaimVerifier) and if it returns no matching
signatures for the specific ref/artifact, fall back to the legacy path (set
ClaimVerifier=cosign.SimpleClaimVerifier and call client.VerifyImageSignatures)
instead of relying solely on useBundles; ensure the logic inspects the returned
signatures slice/err from VerifyImageAttestations before deciding to skip
VerifyImageSignatures so artifact-specific bundles don’t suppress legacy
verification.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Enterprise

Run ID: b6926d90-9cea-472f-8ced-84fd70f94480

📥 Commits

Reviewing files that changed from the base of the PR and between 972813c and 3baad42.

⛔ Files ignored due to path filters (1)
  • features/__snapshots__/validate_image.snap is excluded by !**/*.snap
📒 Files selected for processing (4)
  • acceptance/image/image.go
  • features/validate_image.feature
  • internal/rego/sigstore/sigstore.go
  • internal/rego/sigstore/sigstore_test.go
✅ Files skipped from review due to trivial changes (1)
  • features/validate_image.feature

Comment on lines +135 to +152
client := ecoci.NewClient(ctx)
useBundles, err := client.HasBundles(ctx, ref)
if err != nil {
logger.WithField("error", err).Debug("bundle detection failed, falling back to legacy path")
useBundles = false
}

var signatures []oci.Signature
if useBundles {
logger.Debug("bundles detected, using bundle verification path")
checkOpts.NewBundleFormat = true
checkOpts.ClaimVerifier = cosign.IntotoSubjectClaimVerifier
signatures, _, err = client.VerifyImageAttestations(ref, checkOpts)
} else {
checkOpts.ClaimVerifier = cosign.SimpleClaimVerifier
logger.Debug("verifying image signatures")
signatures, _, err = client.VerifyImageSignatures(ref, checkOpts)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Make bundle selection artifact-specific before skipping the legacy verifier.

HasBundles(ctx, ref) is only a repo-level presence check, but these branches treat it as an exclusive switch for both builtins. In a mixed repo, a bundle attestation can force ec.sigstore.verify_image onto VerifyImageAttestations, and any unrelated bundle can keep ec.sigstore.verify_attestation from ever checking a valid legacy .att tag. That makes partial bundle rollouts return false negatives or validate the wrong artifact type.

Prefer trying the bundle path only when it yields matching results, then falling back to the legacy path, or extend detection so it distinguishes signature bundles from attestation bundles.

Also applies to: 220-239

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/rego/sigstore/sigstore.go` around lines 135 - 152, The repo-level
HasBundles check (ecoci.NewClient -> client.HasBundles) is being used as an
exclusive switch causing attestations or signatures to be skipped; change
VerifyImageAttestations/VerifyImageSignatures flow so you attempt the bundle
verification (client.VerifyImageAttestations with checkOpts.NewBundleFormat=true
and ClaimVerifier=cosign.IntotoSubjectClaimVerifier) and if it returns no
matching signatures for the specific ref/artifact, fall back to the legacy path
(set ClaimVerifier=cosign.SimpleClaimVerifier and call
client.VerifyImageSignatures) instead of relying solely on useBundles; ensure
the logic inspects the returned signatures slice/err from
VerifyImageAttestations before deciding to skip VerifyImageSignatures so
artifact-specific bundles don’t suppress legacy verification.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
acceptance/rekor/rekor.go (1)

185-196: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use base64, not hex, inside the checkpoint body

Checkpoint notes encode the Merkle root as base64 per RFC 6962 and C2SP checkpoint format, but these two blocks interpolate rootHashHex. That makes the acceptance stub non-conformant with the standard format and can break any bundle path that parses or validates the checkpoint body. Keep InclusionProof.RootHash as hex if needed, but build the checkpoint string from a base64-encoded rootHash.

Suggested fix
 	rootHash := hasher.HashChildren(entryHash, entryUUID)
 	rootHashHex := hex.EncodeToString(rootHash)
+	checkpointRootHash := base64.StdEncoding.EncodeToString(rootHash)

-	checkpoint := fmt.Sprintf("rekor.sigstore.dev - %s\n%d\n%s\n\n", logID, treeSize, rootHashHex)
+	checkpoint := fmt.Sprintf("rekor.sigstore.dev - %s\n%d\n%s\n\n", logID, treeSize, checkpointRootHash)

Also applies to: 307-318

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@acceptance/rekor/rekor.go` around lines 185 - 196, The checkpoint string is
built using rootHashHex but the C2SP/RFC6962 checkpoint body requires the Merkle
root in base64; update the code that constructs checkpoint (the checkpoint
variable) to use a base64-encoded root (e.g.
base64.StdEncoding.EncodeToString(rootHashBytes)) instead of rootHashHex, while
leaving InclusionProof.RootHash as the hex string if other code depends on it;
adjust the creation of models.LogEntryAnon (and its
Verification.InclusionProof.Checkpoint) to use that base64 root in the
checkpoint string consistently (also apply the same change to the similar block
around the other occurrence).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@acceptance/rekor/rekor.go`:
- Around line 185-196: The checkpoint string is built using rootHashHex but the
C2SP/RFC6962 checkpoint body requires the Merkle root in base64; update the code
that constructs checkpoint (the checkpoint variable) to use a base64-encoded
root (e.g. base64.StdEncoding.EncodeToString(rootHashBytes)) instead of
rootHashHex, while leaving InclusionProof.RootHash as the hex string if other
code depends on it; adjust the creation of models.LogEntryAnon (and its
Verification.InclusionProof.Checkpoint) to use that base64 root in the
checkpoint string consistently (also apply the same change to the similar block
around the other occurrence).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Enterprise

Run ID: c839f99f-b56e-4183-8d81-cc0b1fd96c05

📥 Commits

Reviewing files that changed from the base of the PR and between 8b4ee18 and 4990cb2.

📒 Files selected for processing (1)
  • acceptance/rekor/rekor.go

The stub Rekor functions overwrote Verification with only
SignedEntryTimestamp, discarding the InclusionProof that
computeLogEntry* had already set. MakeNewBundle requires
InclusionProof for GenerateTransparencyLogEntry.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
st3penta and others added 2 commits May 5, 2026 11:53
The bundle-format attestation test was failing because HasBundles detection
caused verify_image to take the bundle path. Switch to a legacy tag-based
image signature and an attestation-only rego policy that only checks
verify_attestation, avoiding the verify_image/bundle interaction.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Both image signature and attestation are now attached as OCI referrers,
matching realistic deployment scenarios. This tests both verify_image and
verify_attestation through the bundle detection path.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant