Skip to content

fix(cli): switch cosign verification from .sig tags to OCI referrers#533

Merged
Aureliolo merged 5 commits intomainfrom
fix/docker-cosign-verification
Mar 18, 2026
Merged

fix(cli): switch cosign verification from .sig tags to OCI referrers#533
Aureliolo merged 5 commits intomainfrom
fix/docker-cosign-verification

Conversation

@Aureliolo
Copy link
Copy Markdown
Owner

Summary

  • synthorg start and synthorg update fail with MANIFEST_UNKNOWN because the CLI looks for cosign .sig tags that don't exist -- cosign v2+ keyless signing stores signatures in Rekor, not the registry
  • Rewrite cli/internal/verify/cosign.go to use OCI referrers API (same pattern as provenance.go) instead of deprecated .sig tag lookup
  • Add --registry-referrers-mode=oci-1-1 to all 3 cosign sign commands in docker.yml so signatures are pushed as OCI referrers discoverable by the CLI
  • Add ErrNoCosignSignatures sentinel error for clean error typing
  • Replace cosignSigTag / cosignTagSuffix dead code with findCosignSignatures referrer query
  • Deduplicate cosignBundleAnnotation constant (was hardcoded in both cosign.go and provenance.go)
  • Accumulate all verification errors with errors.Join for better diagnostics (matches VerifyProvenance pattern)

Test plan

  • go vet ./... passes
  • go test ./... passes (all verify tests updated for referrer-based approach)
  • go build ./... passes
  • golangci-lint run passes
  • After next release: CI pushes OCI referrer signatures, synthorg start verifies successfully
  • cosign verify commands in release notes work with OCI referrers (cosign CLI auto-discovers)

Review coverage

Pre-reviewed by 4 agents (go-reviewer, go-conventions-enforcer, infra-reviewer, docs-consistency), 5 findings addressed:

  1. Accumulated bundle verification errors instead of silently discarding them
  2. Used errors.Join for per-referrer error collection (eliminated dead code branch)
  3. Deduplicated cosignBundleAnnotation constant across cosign.go and provenance.go
  4. Fixed TestErrNoCosignSignaturesIs to test errors.Is (not string match)
  5. Added unsupported algorithm test case to TestParseDigest

Closes #532

cosign v2+ keyless signing stores signatures in the Rekor transparency
log, not as .sig tags in the registry. The CLI was looking for .sig
tags (MANIFEST_UNKNOWN), breaking `synthorg start` and `synthorg update`.

- Rewrite cosign.go to query OCI referrers API (same approach as
  provenance.go) instead of fetching deprecated .sig tags
- Add --registry-referrers-mode=oci-1-1 to CI cosign sign commands
  so signatures are pushed as OCI referrers discoverable by the CLI
- Add ErrNoCosignSignatures sentinel error for clean error typing
- Replace FuzzCosignSigTag with FuzzParseDigest (old function removed)
- Update tests to use referrer-based mock registry
- Accumulate all bundle verification errors in verifyCosignReferrer
  instead of silently discarding them (improves diagnostics for
  crypto failures, wrong identity, expired certs)
- Accumulate all per-referrer errors in VerifyCosignSignature using
  errors.Join pattern (matches VerifyProvenance)
- Replace hardcoded "dev.sigstore.cosign/bundle" strings in
  provenance.go with cosignBundleAnnotation constant from cosign.go
- Fix TestErrNoCosignSignaturesIs to assert errors.Is (not string match)
- Add unsupported algorithm test case to TestParseDigest table

Pre-reviewed by 4 agents, 5 findings addressed.
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 17, 2026

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request modernizes the CLI's cosign signature verification process by migrating from a deprecated tag-based lookup to the OCI referrers API. This change ensures compatibility with current cosign signing practices, which store signatures in Rekor rather than registry tags, thereby fixing MANIFEST_UNKNOWN errors and improving the reliability of image verification within the system.

Highlights

  • Cosign Verification Update: The CLI's cosign verification mechanism was updated from using deprecated .sig tags to leveraging the OCI referrers API, resolving MANIFEST_UNKNOWN errors for synthorg start and synthorg update.
  • OCI Referrers Integration: The cli/internal/verify/cosign.go file was rewritten to discover and verify cosign signatures using OCI referrers, aligning with modern cosign v2+ keyless signing practices.
  • Build Process Adjustment: The docker.yml configuration was updated to include --registry-referrers-mode=oci-1-1 in cosign sign commands, ensuring signatures are pushed as OCI referrers discoverable by the CLI.
  • Error Handling Improvements: A new sentinel error ErrNoCosignSignatures was added for clearer error typing when no cosign signatures are found, and verification errors are now accumulated using errors.Join for better diagnostics.
  • Code Refactoring: Dead code related to cosignSigTag and cosignTagSuffix was removed, and the cosignBundleAnnotation constant was deduplicated across cosign.go and provenance.go.
Ignored Files
  • Ignored by pattern: .github/workflows/** (1)
    • .github/workflows/docker.yml
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 17, 2026

📝 Walkthrough

Summary by CodeRabbit

  • Chores

    • Switched image signature discovery to OCI referrer-based discovery and unified bundle annotation lookup.
    • Updated CI signing invocation to include registry referrer mode for consistency.
  • Bug Fixes

    • Improved detection and clearer error reporting when no signatures or unsupported digest algorithms are encountered.
  • Tests

    • Expanded and rewired unit and fuzz tests to cover referrer-based verification and digest parsing.

Walkthrough

Replaces legacy .sig tag lookup with OCI Referrers discovery for cosign signatures, adds referrer-based verification logic and error ErrNoCosignSignatures, updates CI cosign sign invocations to push referrers, and adjusts tests and fuzzing to the new referrer workflow.

Changes

Cohort / File(s) Summary
CI workflow
​.github/workflows/docker.yml
Add --registry-referrers-mode=oci-1-1 to all cosign sign --yes invocations so signatures are pushed as OCI referrers.
Verify implementation
cli/internal/verify/cosign.go
Remove legacy .sig tag lookup; add OCI referrers discovery (findCosignSignatures), per-referrer verification (verifyCosignReferrer), cosignArtifactType/cosignBundleAnnotation usage, and exported ErrNoCosignSignatures.
Provenance annotation usage
cli/internal/verify/provenance.go
Use cosignBundleAnnotation constant instead of hardcoded annotation key when locating Sigstore bundles.
Unit tests
cli/internal/verify/cosign_test.go
Refactor tests to simulate referrer-index flows, add manifest/layer annotation fields, remove .sig-tag test, add TestErrNoCosignSignaturesIs, and adapt fixtures to referrer-based artifacts.
Fuzz tests
cli/internal/verify/fuzz_test.go
Rename fuzz target to FuzzParseDigest and refocus fuzzing on parseDigest (including unsupported alg case).
Go mod manifest
go.mod
Adjust dependencies/imports for new verification code and tests (added errors and OCI descriptor usage).

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant CLI as "synthorg CLI"
  participant Registry as "OCI Registry"
  participant ReferrerIndex as "Referrers API"
  participant SigVerifier as "Sigstore bundle verifier"
  CLI->>Registry: Resolve image -> get digest
  CLI->>ReferrerIndex: Query /referrers?digest=<digest>
  ReferrerIndex-->>CLI: Return referrer index (descriptors)
  loop for each cosign referrer descriptor
    CLI->>Registry: Fetch manifest for referrer descriptor (by digest)
    Registry-->>CLI: Return manifest (annotations, layers)
    CLI->>Registry: Fetch signature blob (layer) if needed
    Registry-->>CLI: Return signature blob (bundle)
    CLI->>SigVerifier: Verify Sigstore bundle / signature
    SigVerifier-->>CLI: Verification result (ok / error)
  end
  alt any descriptor verifies
    CLI-->>User: Signature verified
  else none verify
    CLI-->>User: ErrNoCosignSignatures / verification failed
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 61.54% 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 PR title accurately and concisely summarizes the main change: switching cosign verification from deprecated .sig tags to OCI referrers.
Description check ✅ Passed The PR description is comprehensive and directly related to the changeset, explaining the problem, solution, and test coverage.
Linked Issues check ✅ Passed All coding requirements from issue #532 are met: CI adds --registry-referrers-mode=oci-1-1 to cosign sign commands [docker.yml], CLI rewrites cosign.go to use OCI referrers API [cosign.go], removes legacy .sig code [cosign.go, fuzz_test.go], adds ErrNoCosignSignatures sentinel error [cosign.go], deduplicates cosignBundleAnnotation constant [cosign.go, provenance.go], improves error handling with errors.Join [cosign.go], and updates tests [cosign_test.go, fuzz_test.go].
Out of Scope Changes check ✅ Passed All changes are scoped to the linked issue #532 requirements: cosign verification migration to OCI referrers, CI/CD pipeline updates, and related test adjustments. No unrelated modifications detected.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/docker-cosign-verification
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch fix/docker-cosign-verification
📝 Coding Plan
  • Generate coding plan for human review comments

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

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request is a well-executed refactoring that modernizes cosign signature verification by switching from deprecated .sig tags to OCI referrers. The changes are clean, introducing a new sentinel error for clarity, deduplicating constants, and improving error diagnostics with errors.Join. The test suite has been comprehensively updated to match the new logic, including new unit and fuzz tests. I have one suggestion to further improve the test code's consistency.

Comment on lines 98 to 100
if !strings.Contains(err.Error(), "no cosign signatures found") {
t.Errorf("expected ErrNoCosignSignatures, got: %v", err)
}
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.

medium

For better robustness and consistency with the newly added TestErrNoCosignSignaturesIs, it's preferable to use errors.Is to check for the sentinel error. Relying on strings.Contains for error checking can be brittle, as the error message string might change in the future.

Suggested change
if !strings.Contains(err.Error(), "no cosign signatures found") {
t.Errorf("expected ErrNoCosignSignatures, got: %v", err)
}
if !errors.Is(err, ErrNoCosignSignatures) {
t.Errorf("expected error to wrap ErrNoCosignSignatures, got: %v", err)
}

coderabbitai[bot]
coderabbitai bot previously approved these changes Mar 17, 2026
Addresses Gemini review feedback on TestVerifyCosignSignatureNoReferrers.
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

Caution

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

⚠️ Outside diff range comments (1)
cli/internal/verify/cosign_test.go (1)

201-205: 🧹 Nitpick | 🔵 Trivial

Tighten assertion to validate the intended failure mode.

err != nil alone can pass on unrelated regressions (e.g., transport/mocking issues) and not specifically invalid-bundle handling.

Suggested assertion hardening
 	err := VerifyCosignSignature(context.Background(), ref, nil, sigverify.CertificateIdentity{})
 	if err == nil {
 		t.Fatal("expected error for invalid bundle JSON")
 	}
+	if errors.Is(err, ErrNoCosignSignatures) {
+		t.Fatalf("expected invalid bundle-related error, got ErrNoCosignSignatures: %v", err)
+	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cli/internal/verify/cosign_test.go` around lines 201 - 205, The test
currently only checks err != nil which can hide unrelated failures; update the
assertion in cosign_test.go's test that calls VerifyCosignSignature to validate
the specific failure mode by matching the returned error to the expected cause —
either use errors.Is against the known sentinel error if VerifyCosignSignature
returns one (e.g., ErrInvalidBundle) or assert that err.Error() contains a
distinctive substring like "invalid bundle" (using strings.Contains) so the test
fails only when the error is not the expected invalid-bundle error.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@cli/internal/verify/cosign_test.go`:
- Around line 153-168: The test currently ignores json.Marshal errors for
sigManifest and referrerIdx (variables sigManifestJSON and referrerIdxJSON),
which can mask fixture construction failures; modify the test to check and fail
immediately on marshal errors (e.g., use t.Fatalf or require.NoError) right
after each json.Marshal call that produces sigManifestJSON and referrerIdxJSON
so the test fails fast when marshaling v1.IndexManifest or the signature
manifest fails.

---

Outside diff comments:
In `@cli/internal/verify/cosign_test.go`:
- Around line 201-205: The test currently only checks err != nil which can hide
unrelated failures; update the assertion in cosign_test.go's test that calls
VerifyCosignSignature to validate the specific failure mode by matching the
returned error to the expected cause — either use errors.Is against the known
sentinel error if VerifyCosignSignature returns one (e.g., ErrInvalidBundle) or
assert that err.Error() contains a distinctive substring like "invalid bundle"
(using strings.Contains) so the test fails only when the error is not the
expected invalid-bundle error.
🪄 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: ASSERTIVE

Plan: Pro

Run ID: cf0c0eeb-3fb2-4b96-8297-65f697c7b551

📥 Commits

Reviewing files that changed from the base of the PR and between 3d36713 and 38e31ea.

📒 Files selected for processing (1)
  • cli/internal/verify/cosign_test.go
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: CLI Test (macos-latest)
  • GitHub Check: CLI Test (windows-latest)
  • GitHub Check: Build Backend
  • GitHub Check: Build Sandbox
  • GitHub Check: Build Web
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (1)
cli/**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

Use native testing.F fuzz functions (Fuzz*) for property-based testing

Files:

  • cli/internal/verify/cosign_test.go
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T11:48:14.867Z
Learning: Applies to .github/workflows/docker.yml : CI Docker: build → scan → push to GHCR + cosign sign + SLSA L3 provenance via attest-build-provenance (images only pushed after Trivy/Grype scans pass).
🧬 Code graph analysis (1)
cli/internal/verify/cosign_test.go (1)
cli/internal/verify/cosign.go (1)
  • ErrNoCosignSignatures (30-30)
🔇 Additional comments (3)
cli/internal/verify/cosign_test.go (3)

26-26: Good edge-case coverage for unsupported digest algorithms.

This makes parseDigest behavior explicit beyond malformed formatting and hex validation.


64-100: Strong improvement: typed sentinel assertion for no-referrer path.

Switching to errors.Is(err, ErrNoCosignSignatures) avoids brittle string matching and aligns with the new error contract.


207-212: Nice regression guard for wrapping semantics.

This directly protects the errors.Is contract for ErrNoCosignSignatures.

- Fail fast on json.Marshal errors for test fixtures instead of
  silently ignoring them
- Assert error contains "cosign signature" in InvalidBundle test
  to prevent unrelated errors from passing the test
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

♻️ Duplicate comments (1)
cli/internal/verify/cosign_test.go (1)

73-79: ⚠️ Potential issue | 🟡 Minor

Fail fast on the empty referrer-index fixture.

This test still ignores json.Marshal for the empty index. If that fixture ever stops marshaling, the handler will quietly serve bad data, and switching to t.Fatalf in the handler would be unsafe because it runs in another goroutine. Precompute the JSON before httptest.NewServer and fail there instead.

Suggested change
 func TestVerifyCosignSignatureNoReferrers(t *testing.T) {
+	idx := v1.IndexManifest{
+		SchemaVersion: 2,
+		MediaType:     "application/vnd.oci.image.index.v1+json",
+		Manifests:     []v1.Descriptor{},
+	}
+	idxJSON, marshalErr := json.Marshal(idx)
+	if marshalErr != nil {
+		t.Fatalf("marshaling empty referrer index: %v", marshalErr)
+	}
+
 	// Mock registry that returns an empty referrer index.
 	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 		switch {
 		case r.URL.Path == "/v2/":
 			w.WriteHeader(http.StatusOK)
 		case strings.Contains(r.URL.Path, "/referrers/"):
 			// Empty referrer index -- no cosign signatures.
 			w.Header().Set("Content-Type", "application/vnd.oci.image.index.v1+json")
-			idx := v1.IndexManifest{
-				SchemaVersion: 2,
-				MediaType:     "application/vnd.oci.image.index.v1+json",
-				Manifests:     []v1.Descriptor{},
-			}
-			data, _ := json.Marshal(idx)
-			_, _ = w.Write(data)
+			_, _ = w.Write(idxJSON)
 		default:
 			w.WriteHeader(http.StatusNotFound)
 		}
 	}))
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cli/internal/verify/cosign_test.go` around lines 73 - 79, Precompute the JSON
for the empty v1.IndexManifest (the idx variable) and check the error from
json.Marshal before starting the httptest.NewServer so the test fails
immediately instead of inside the server goroutine; replace the inline
json.Marshal call inside the HTTP handler with writing the previously marshaled
data (data) and remove the ignored error, and if json.Marshal returns an error
call t.Fatalf from the test setup (not from the handler) to fail fast.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@cli/internal/verify/cosign_test.go`:
- Around line 207-213: Update the test that calls VerifyCosignSignature to not
only assert the top-level wrapper message but also assert the underlying
bundle-specific cause is present: after confirming err is non-nil and contains
the wrapper text ("no valid cosign signature" or "cosign signature"),
additionally inspect the error chain (using errors.Is / errors.As /
errors.Unwrap or checking strings.Contains on err.Error() for the known bundle
parse error message) to assert it contains the bundle-related message indicating
invalid bundle JSON; reference VerifyCosignSignature to locate the wrapper and
the bundle parse failure to know the exact substring to assert.

---

Duplicate comments:
In `@cli/internal/verify/cosign_test.go`:
- Around line 73-79: Precompute the JSON for the empty v1.IndexManifest (the idx
variable) and check the error from json.Marshal before starting the
httptest.NewServer so the test fails immediately instead of inside the server
goroutine; replace the inline json.Marshal call inside the HTTP handler with
writing the previously marshaled data (data) and remove the ignored error, and
if json.Marshal returns an error call t.Fatalf from the test setup (not from the
handler) to fail fast.
🪄 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: ASSERTIVE

Plan: Pro

Run ID: 96ad0d5b-f01f-4fba-a280-641eadb36398

📥 Commits

Reviewing files that changed from the base of the PR and between 38e31ea and 19fe579.

📒 Files selected for processing (1)
  • cli/internal/verify/cosign_test.go
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: CLI Test (windows-latest)
🧰 Additional context used
📓 Path-based instructions (1)
cli/**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

Use native testing.F fuzz functions (Fuzz*) for property-based testing

Files:

  • cli/internal/verify/cosign_test.go
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: Aureliolo/synthorg PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-15T11:48:14.867Z
Learning: Applies to .github/workflows/docker.yml : CI Docker: build → scan → push to GHCR + cosign sign + SLSA L3 provenance via attest-build-provenance (images only pushed after Trivy/Grype scans pass).
🧬 Code graph analysis (1)
cli/internal/verify/cosign_test.go (1)
cli/internal/verify/cosign.go (2)
  • ErrNoCosignSignatures (30-30)
  • VerifyCosignSignature (36-56)

Comment on lines +207 to +213
err = VerifyCosignSignature(context.Background(), ref, nil, sigverify.CertificateIdentity{})
if err == nil {
t.Fatal("expected error for invalid bundle JSON")
}
if !strings.Contains(err.Error(), "cosign signature") {
t.Errorf("expected cosign signature verification error, got: %v", err)
}
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 | 🟡 Minor

Assert the bundle-specific cause here.

VerifyCosignSignature in cli/internal/verify/cosign.go lines 29-55 wraps any referrer verification failure with no valid cosign signature..., so this assertion still passes if the test breaks for some unrelated reason. Please also check for the bundle-related cause from the joined error so this remains an invalid-bundle test.

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

In `@cli/internal/verify/cosign_test.go` around lines 207 - 213, Update the test
that calls VerifyCosignSignature to not only assert the top-level wrapper
message but also assert the underlying bundle-specific cause is present: after
confirming err is non-nil and contains the wrapper text ("no valid cosign
signature" or "cosign signature"), additionally inspect the error chain (using
errors.Is / errors.As / errors.Unwrap or checking strings.Contains on
err.Error() for the known bundle parse error message) to assert it contains the
bundle-related message indicating invalid bundle JSON; reference
VerifyCosignSignature to locate the wrapper and the bundle parse failure to know
the exact substring to assert.

Move json.Marshal for the empty v1.IndexManifest out of the HTTP
handler and into test setup with error checking, so marshal failures
fail the test immediately instead of being silently ignored.
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.

♻️ Duplicate comments (1)
cli/internal/verify/cosign_test.go (1)

211-217: ⚠️ Potential issue | 🟡 Minor

Assert the bundle-specific cause, not only the wrapper text.

Line 215 only checks "cosign signature", so unrelated failures can still pass. Please also assert a bundle-related cause from the joined error content.

Suggested tightening
 err = VerifyCosignSignature(context.Background(), ref, nil, sigverify.CertificateIdentity{})
 if err == nil {
 	t.Fatal("expected error for invalid bundle JSON")
 }
-if !strings.Contains(err.Error(), "cosign signature") {
-	t.Errorf("expected cosign signature verification error, got: %v", err)
+if !strings.Contains(err.Error(), "no valid cosign signature") {
+	t.Errorf("expected wrapped cosign signature verification error, got: %v", err)
+}
+if !strings.Contains(err.Error(), "bundle") {
+	t.Errorf("expected bundle-specific failure in error chain, got: %v", err)
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cli/internal/verify/cosign_test.go` around lines 211 - 217, The test
currently only asserts the wrapper text "cosign signature" and can miss
bundle-specific failures; update the test around the VerifyCosignSignature call
to also assert the bundle-specific cause by checking the joined error content
(e.g., ensure err.Error() contains a bundle-related substring such as "invalid
bundle" or the exact bundle parse error emitted by the code) instead of only the
generic check on "cosign signature" (locate the check using
VerifyCosignSignature and the existing strings.Contains assertions in
cosign_test.go).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@cli/internal/verify/cosign_test.go`:
- Around line 211-217: The test currently only asserts the wrapper text "cosign
signature" and can miss bundle-specific failures; update the test around the
VerifyCosignSignature call to also assert the bundle-specific cause by checking
the joined error content (e.g., ensure err.Error() contains a bundle-related
substring such as "invalid bundle" or the exact bundle parse error emitted by
the code) instead of only the generic check on "cosign signature" (locate the
check using VerifyCosignSignature and the existing strings.Contains assertions
in cosign_test.go).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 284d4fd5-aebc-4a41-8caf-a9c402378461

📥 Commits

Reviewing files that changed from the base of the PR and between 19fe579 and 79ec71b.

📒 Files selected for processing (1)
  • cli/internal/verify/cosign_test.go
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Build Web
  • GitHub Check: Build Backend
  • GitHub Check: CLI Test (windows-latest)
  • GitHub Check: CLI Test (macos-latest)
  • GitHub Check: Analyze (python)
🧰 Additional context used
📓 Path-based instructions (1)
cli/**/*.go

📄 CodeRabbit inference engine (CLAUDE.md)

Use native testing.F fuzz functions (Fuzz*) for property-based testing

Files:

  • cli/internal/verify/cosign_test.go
🧬 Code graph analysis (1)
cli/internal/verify/cosign_test.go (1)
cli/internal/verify/cosign.go (2)
  • VerifyCosignSignature (36-56)
  • ErrNoCosignSignatures (30-30)
🔇 Additional comments (4)
cli/internal/verify/cosign_test.go (4)

26-27: Good negative coverage for digest parsing.

Adding the unsupported algorithm case improves guard-rail coverage for parseDigest.


64-105: Referrer-empty path test is solid.

This now correctly validates the OCI referrers flow and typed sentinel handling via errors.Is(..., ErrNoCosignSignatures).


157-178: Nice fail-fast fixture marshaling checks.

The explicit marshal error handling makes fixture setup failures deterministic and debuggable.


220-224: Sentinel matching test is clear and useful.

This is a good targeted check that ErrNoCosignSignatures remains errors.Is-compatible when wrapped.

@Aureliolo Aureliolo merged commit 8ee5471 into main Mar 18, 2026
44 checks passed
@Aureliolo Aureliolo deleted the fix/docker-cosign-verification branch March 18, 2026 06:37
Aureliolo added a commit that referenced this pull request Mar 18, 2026
🤖 I have created a release *beep* *boop*
---


##
[0.3.3](v0.3.2...v0.3.3)
(2026-03-18)


### Features

* **backup:** implement automated backup and restore system
([#541](#541))
([867b7c1](867b7c1))
* **providers:** runtime provider management with CRUD, presets, and
multi-auth ([#540](#540))
([936c345](936c345)),
closes [#451](#451)
* **tools:** wire per-category sandbox backend selection
([#534](#534))
([311a1ab](311a1ab))


### Bug Fixes

* **cli:** switch cosign verification from .sig tags to OCI referrers
([#533](#533))
([8ee5471](8ee5471)),
closes [#532](#532)


### CI/CD

* bump wrangler from 4.74.0 to 4.75.0 in /.github in the minor-and-patch
group ([#535](#535))
([de15867](de15867))


### Maintenance

* bump github.com/google/go-containerregistry from 0.21.2 to 0.21.3 in
/cli in the minor-and-patch group
([#536](#536))
([4a09aed](4a09aed))
* bump litellm from 1.82.3 to 1.82.4 in the minor-and-patch group
([#538](#538))
([9f7f83d](9f7f83d))
* bump vue-tsc from 3.2.5 to 3.2.6 in /web in the minor-and-patch group
across 1 directory
([#537](#537))
([eb3dc4e](eb3dc4e))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Aureliolo added a commit that referenced this pull request Mar 18, 2026
…gn (#543)

## Summary

- v0.3.3 Docker workflow failed because `cosign sign
--registry-referrers-mode=oci-1-1` requires `COSIGN_EXPERIMENTAL=1` with
cosign-installer v4.1.0
- Add `COSIGN_EXPERIMENTAL: "1"` to the env block of all 3 image signing
steps (backend, web, sandbox)
- Also replaces em-dashes with ASCII dashes in error messages

## Root cause

```
Error: invalid argument "oci-1-1" for "--registry-referrers-mode" flag:
in order to use mode "oci-1-1", you must set COSIGN_EXPERIMENTAL=1
```

The `--registry-referrers-mode=oci-1-1` flag was added in PR #533 but
the cosign version pinned by `sigstore/cosign-installer@v4.1.0` gates
this behind the experimental flag.

## Test plan

- [ ] Merge this PR, then re-run the Docker workflow for v0.3.3 tag to
verify signing succeeds
- [ ] Alternatively, trigger a workflow_dispatch to test before the next
release
Aureliolo added a commit that referenced this pull request Mar 18, 2026
## Summary

The v0.3.3 release failed because cosign signing required
`COSIGN_EXPERIMENTAL=1` (fixed in #543). The v0.3.3 tag and draft
release have been deleted. This PR reverts the release artifacts so
Release Please can create a clean release on the next merge to main.

- Revert version 0.3.3 -> 0.3.2 in `pyproject.toml`, `__init__.py`,
`.release-please-manifest.json`
- Remove 0.3.3 changelog section from `CHANGELOG.md`
- Revert LICENSE change date

## What happened

1. PR #533 added `--registry-referrers-mode=oci-1-1` to cosign sign
commands
2. cosign v3.0.3 (installed by cosign-installer v4.1.0) requires
`COSIGN_EXPERIMENTAL=1` for that flag
3. All 3 image signing steps failed on the v0.3.3 tag push
4. Finalize-release never published the draft (waits for Docker + CLI
success)
5. PR #543 added the missing env var
6. Tag `v0.3.3` and draft release deleted manually
7. This PR resets version state so Release Please starts fresh

## After merge

Release Please will see new commits (including #543 cosign fix) and
create a release PR for v0.3.3 with the fix baked in.
Aureliolo added a commit that referenced this pull request Mar 18, 2026
🤖 I have created a release *beep* *boop*
---


##
[0.3.3](v0.3.2...v0.3.3)
(2026-03-18)


### Features

* **backup:** implement automated backup and restore system
([#541](#541))
([867b7c1](867b7c1))
* **providers:** runtime provider management with CRUD, presets, and
multi-auth ([#540](#540))
([936c345](936c345)),
closes [#451](#451)
* **tools:** wire per-category sandbox backend selection
([#534](#534))
([311a1ab](311a1ab))


### Bug Fixes

* **ci:** add COSIGN_EXPERIMENTAL=1 for OCI referrer mode in cosign sign
([#543](#543))
([226ed2f](226ed2f))
* **cli:** switch cosign verification from .sig tags to OCI referrers
([#533](#533))
([8ee5471](8ee5471)),
closes [#532](#532)


### CI/CD

* bump wrangler from 4.74.0 to 4.75.0 in /.github in the minor-and-patch
group ([#535](#535))
([de15867](de15867))


### Maintenance

* bump github.com/google/go-containerregistry from 0.21.2 to 0.21.3 in
/cli in the minor-and-patch group
([#536](#536))
([4a09aed](4a09aed))
* bump litellm from 1.82.3 to 1.82.4 in the minor-and-patch group
([#538](#538))
([9f7f83d](9f7f83d))
* bump vue-tsc from 3.2.5 to 3.2.6 in /web in the minor-and-patch group
across 1 directory
([#537](#537))
([eb3dc4e](eb3dc4e))
* **main:** release 0.3.3
([#539](#539))
([c3de2a2](c3de2a2))
* revert v0.3.3 release artifacts (Docker signing failed)
([#544](#544))
([7f48f52](7f48f52))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
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.

fix(cli): cosign signature verification fails with MANIFEST_UNKNOWN

1 participant