fix(cli): switch cosign verification from .sig tags to OCI referrers#533
fix(cli): switch cosign verification from .sig tags to OCI referrers#533
Conversation
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.
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Scanned FilesNone |
Summary of ChangesHello, 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 Highlights
Ignored Files
Using Gemini Code AssistThe 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
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 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
|
📝 WalkthroughSummary by CodeRabbit
WalkthroughReplaces 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
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
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
✨ Simplify code
📝 Coding Plan
Comment |
There was a problem hiding this comment.
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.
cli/internal/verify/cosign_test.go
Outdated
| if !strings.Contains(err.Error(), "no cosign signatures found") { | ||
| t.Errorf("expected ErrNoCosignSignatures, got: %v", err) | ||
| } |
There was a problem hiding this comment.
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.
| 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) | |
| } |
Addresses Gemini review feedback on TestVerifyCosignSignatureNoReferrers.
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)
cli/internal/verify/cosign_test.go (1)
201-205: 🧹 Nitpick | 🔵 TrivialTighten assertion to validate the intended failure mode.
err != nilalone 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
📒 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.Ffuzz 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
parseDigestbehavior 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.Iscontract forErrNoCosignSignatures.
- 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
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
cli/internal/verify/cosign_test.go (1)
73-79:⚠️ Potential issue | 🟡 MinorFail fast on the empty referrer-index fixture.
This test still ignores
json.Marshalfor the empty index. If that fixture ever stops marshaling, the handler will quietly serve bad data, and switching tot.Fatalfin the handler would be unsafe because it runs in another goroutine. Precompute the JSON beforehttptest.NewServerand 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
📒 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.Ffuzz 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)
| 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) | ||
| } |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
♻️ Duplicate comments (1)
cli/internal/verify/cosign_test.go (1)
211-217:⚠️ Potential issue | 🟡 MinorAssert 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
📒 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.Ffuzz 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
ErrNoCosignSignaturesremainserrors.Is-compatible when wrapped.
🤖 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>
…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
## 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.
🤖 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>
Summary
synthorg startandsynthorg updatefail withMANIFEST_UNKNOWNbecause the CLI looks for cosign.sigtags that don't exist -- cosign v2+ keyless signing stores signatures in Rekor, not the registrycli/internal/verify/cosign.goto use OCI referrers API (same pattern asprovenance.go) instead of deprecated.sigtag lookup--registry-referrers-mode=oci-1-1to all 3cosign signcommands indocker.ymlso signatures are pushed as OCI referrers discoverable by the CLIErrNoCosignSignaturessentinel error for clean error typingcosignSigTag/cosignTagSuffixdead code withfindCosignSignaturesreferrer querycosignBundleAnnotationconstant (was hardcoded in both cosign.go and provenance.go)errors.Joinfor better diagnostics (matchesVerifyProvenancepattern)Test plan
go vet ./...passesgo test ./...passes (all verify tests updated for referrer-based approach)go build ./...passesgolangci-lint runpassessynthorg startverifies successfullycosign verifycommands 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:
errors.Joinfor per-referrer error collection (eliminated dead code branch)cosignBundleAnnotationconstant across cosign.go and provenance.goTestErrNoCosignSignaturesIsto testerrors.Is(not string match)TestParseDigestCloses #532