Skip to content

Bump cosign v2.4.1 to v3.0.4 and use trusted_root.json for verification#3108

Merged
simonbaird merged 1 commit intoconforma:mainfrom
SequeI:bumpCosign
Feb 13, 2026
Merged

Bump cosign v2.4.1 to v3.0.4 and use trusted_root.json for verification#3108
simonbaird merged 1 commit intoconforma:mainfrom
SequeI:bumpCosign

Conversation

@SequeI
Copy link
Contributor

@SequeI SequeI commented Feb 11, 2026

Upgrade from cosign/v2 to cosign/v3 so that ec sigstore initialize produces the modern sigstore TUF cache format (trusted_root.json + signing_config) used by current cosign and gitsign.

In the keyless verification path, ec now loads TrustedMaterial from trusted_root.json via cosign.TrustedRoot() before falling back to fetching individual Fulcio/CTLog/Rekor targets. This unifies the TUF library used for both initialization and verification.

Dependency changes:

  • cosign v2.4.1 -> v3.0.4
  • conftest v0.57.0 -> v0.66.0 (required for tablewriter v1 compat)
  • Go 1.24.6 -> 1.25.3 (required by conftest v0.66.0)

Adapt to breaking API changes:

  • cosign.LoadPrivateKey now takes an additional *[]signature.LoadOption
  • cosignRemote.WriteSignedImageIndexImages now takes a directory param
  • fake.NewSimpleClientset replaced with fake.NewClientset

Fix pre-existing acceptance test bug where the "Effective-time is honored" scenario used embedded quotes that the step regex could not match.

Update OPA snapshot and generated docs to reflect new OPA/conftest help text.

Closes #3107

@qodo-code-review
Copy link
Contributor

Review Summary by Qodo

Upgrade cosign to v3.0.4 and implement TrustedRoot.json verification

✨ Enhancement 🧪 Tests

Grey Divider

Walkthroughs

Description
• Upgrade cosign from v2.4.1 to v3.0.4 with TrustedRoot.json support
• Implement TUF-based verification using cosign.TrustedRoot() with fallback
• Adapt to breaking API changes in cosign v3 (LoadPrivateKey, WriteSignedImageIndexImages,
  fake.NewClientset)
• Update Go from 1.24.6 to 1.25.3 and conftest v0.57.0 to v0.66.0
• Fix acceptance test regex for "Effective-time is honored" scenario
• Update OPA/conftest documentation to reflect new help text
Diagram
flowchart LR
  A["cosign v2.4.1"] -->|upgrade| B["cosign v3.0.4"]
  B -->|enables| C["TrustedRoot.json support"]
  C -->|provides| D["TUF-based verification"]
  D -->|with fallback| E["Individual Fulcio/CTLog/Rekor targets"]
  F["Breaking API changes"] -->|adapt| G["LoadPrivateKey, WriteSignedImageIndexImages, fake.NewClientset"]
  H["Go 1.24.6"] -->|upgrade| I["Go 1.25.3"]
  J["conftest v0.57.0"] -->|upgrade| K["conftest v0.66.0"]
Loading

Grey Divider

File Changes

1. internal/policy/policy.go ✨ Enhancement +32/-17

Implement TrustedRoot.json verification with fallback logic

internal/policy/policy.go


2. cmd/validate/image_test.go 🧪 Tests +6/-6

Update LoadPrivateKey mock signature for cosign v3

cmd/validate/image_test.go


3. internal/validate/vsa/attest_test.go 🧪 Tests +4/-4

Update LoadPrivateKey and fake.NewClientset for v3 API

internal/validate/vsa/attest_test.go


View more (50)
4. acceptance/image/image.go ✨ Enhancement +8/-8

Update cosign imports and WriteSignedImageIndexImages call

acceptance/image/image.go


5. internal/validate/vsa/attest.go ✨ Enhancement +3/-3

Update cosign imports and LoadPrivateKey invocation

internal/validate/vsa/attest.go


6. internal/evaluation_target/application_snapshot_image/application_snapshot_image_test.go 🧪 Tests +4/-4

Update cosign v2 imports to v3

internal/evaluation_target/application_snapshot_image/application_snapshot_image_test.go


7. cmd/sigstore/initialize.go 📝 Documentation +2/-2

Update cosign imports and TUF cache documentation

cmd/sigstore/initialize.go


8. internal/image/validate_test.go 🧪 Tests +3/-3

Update cosign v2 imports to v3

internal/image/validate_test.go


9. internal/utils/private_key_test.go 🧪 Tests +2/-2

Replace fake.NewSimpleClientset with fake.NewClientset

internal/utils/private_key_test.go


10. internal/rego/sigstore/sigstore_test.go 🧪 Tests +4/-4

Update cosign v2 imports to v3

internal/rego/sigstore/sigstore_test.go


11. internal/version/version.go ✨ Enhancement +1/-1

Update cosign dependency path from v2 to v3

internal/version/version.go


12. internal/utils/oci/client.go ✨ Enhancement +3/-3

Update cosign v2 imports to v3

internal/utils/oci/client.go


13. acceptance/rekor/rekor.go ✨ Enhancement +2/-2

Update cosign v2 imports to v3

acceptance/rekor/rekor.go


14. internal/validate/vsa/vsa_test.go 🧪 Tests +2/-2

Update cosign v2 imports to v3

internal/validate/vsa/vsa_test.go


15. internal/policy/policy_test.go 🧪 Tests +2/-2

Update cosign v2 imports to v3

internal/policy/policy_test.go


16. acceptance/crypto/keys.go ✨ Enhancement +2/-2

Update cosign imports and LoadPrivateKey call signature

acceptance/crypto/keys.go


17. internal/rego/sigstore/sigstore.go ✨ Enhancement +2/-2

Update cosign v2 imports to v3

internal/rego/sigstore/sigstore.go


18. internal/attestation/slsa_provenance_02_test.go 🧪 Tests +2/-2

Update cosign v2 imports to v3

internal/attestation/slsa_provenance_02_test.go


19. internal/validate/vsa/rekor_retriever.go ✨ Enhancement +1/-1

Update cosign v2 imports to v3

internal/validate/vsa/rekor_retriever.go


20. internal/version/version_test.go 🧪 Tests +1/-1

Update cosign dependency path in test expectations

internal/version/version_test.go


21. cmd/sigstore/sigstore.go ✨ Enhancement +1/-1

Update cosign v2 imports to v3

cmd/sigstore/sigstore.go


22. internal/evaluation_target/application_snapshot_image/application_snapshot_image.go ✨ Enhancement +1/-1

Update cosign v2 imports to v3

internal/evaluation_target/application_snapshot_image/application_snapshot_image.go


23. cmd/validate/image.go ✨ Enhancement +1/-1

Update cosign v2 imports to v3

cmd/validate/image.go


24. acceptance/attestation/attestation.go ✨ Enhancement +2/-2

Update cosign v2 imports to v3

acceptance/attestation/attestation.go


25. internal/utils/oci/fake/client.go ✨ Enhancement +2/-2

Update cosign v2 imports to v3

internal/utils/oci/fake/client.go


26. internal/signature/certificate_test.go 🧪 Tests +2/-2

Update cosign v2 imports to v3

internal/signature/certificate_test.go


27. internal/validate/vsa/service_test.go 🧪 Tests +1/-1

Update cosign v2 imports to v3

internal/validate/vsa/service_test.go


28. internal/attestation/attestation.go ✨ Enhancement +3/-3

Update cosign v2 imports to v3

internal/attestation/attestation.go


29. internal/attestation/slsa_provenance_v1_test.go 🧪 Tests +1/-1

Update cosign v2 imports to v3

internal/attestation/slsa_provenance_v1_test.go


30. internal/attestation/attestation_test.go 🧪 Tests +1/-1

Update cosign v2 imports to v3

internal/attestation/attestation_test.go


31. internal/attestation/slsa_provenance_02.go ✨ Enhancement +1/-1

Update cosign v2 imports to v3

internal/attestation/slsa_provenance_02.go


32. internal/attestation/slsa_provenance_v1.go ✨ Enhancement +1/-1

Update cosign v2 imports to v3

internal/attestation/slsa_provenance_v1.go


33. internal/output/output_test.go 🧪 Tests +1/-1

Update cosign v2 imports to v3

internal/output/output_test.go


34. internal/output/output.go ✨ Enhancement +1/-1

Update cosign v2 imports to v3

internal/output/output.go


35. internal/signature/signature.go ✨ Enhancement +1/-1

Update cosign v2 imports to v3

internal/signature/signature.go


36. go.mod Dependencies +161/-133

Upgrade Go, cosign, conftest, and related dependencies

go.mod


37. acceptance/go.mod Dependencies +91/-90

Upgrade Go and cosign dependencies in acceptance tests

acceptance/go.mod


38. docs/modules/ROOT/pages/ec_opa_inspect.adoc 📝 Documentation +8/-8

Update OPA inspect command documentation formatting

docs/modules/ROOT/pages/ec_opa_inspect.adoc


39. docs/modules/ROOT/pages/ec_opa_build.adoc 📝 Documentation +6/-6

Fix indentation and formatting in OPA build documentation

docs/modules/ROOT/pages/ec_opa_build.adoc


40. docs/modules/ROOT/pages/ec_sigstore_initialize.adoc 📝 Documentation +3/-1

Update TUF cache path and add new initialization flags

docs/modules/ROOT/pages/ec_sigstore_initialize.adoc


41. docs/modules/ROOT/pages/ec_opa_test.adoc 📝 Documentation +2/-1

Add fail-on-empty flag to OPA test documentation

docs/modules/ROOT/pages/ec_opa_test.adoc


42. docs/modules/ROOT/pages/ec_opa_exec.adoc 📝 Documentation +4/-3

Update OPA exec command documentation and flag descriptions

docs/modules/ROOT/pages/ec_opa_exec.adoc


43. Dockerfile.dist ⚙️ Configuration changes +1/-1

Update Go version to 1.25.3 in build image

Dockerfile.dist


44. features/task_validate_image.feature 🐞 Bug fix +1/-1

Fix acceptance test regex for effective-time scenario

features/task_validate_image.feature


45. Dockerfile ⚙️ Configuration changes +1/-1

Update Go version to 1.25.3 in build image

Dockerfile


46. Makefile ⚙️ Configuration changes +1/-1

Update cosign version extraction to use v3

Makefile


47. docs/modules/ROOT/pages/ec_opa_bench.adoc 📝 Documentation +1/-0

Add metrics and benchmem flags documentation

docs/modules/ROOT/pages/ec_opa_bench.adoc


48. docs/modules/ROOT/pages/ec_opa_run.adoc 📝 Documentation +1/-1

Simplify OPA run command synopsis

docs/modules/ROOT/pages/ec_opa_run.adoc


49. tools/go.mod ⚙️ Configuration changes +1/-1

Update Go version to 1.25.3

tools/go.mod


50. tools/kubectl/go.mod ⚙️ Configuration changes +1/-1

Update Go version to 1.25.3

tools/kubectl/go.mod


51. .tool-versions ⚙️ Configuration changes +1/-1

Update golang version to 1.25.3

.tool-versions


52. acceptance/go.sum Additional files +346/-446

...

acceptance/go.sum


53. go.sum Additional files +420/-362

...

go.sum


Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Contributor

Code Review by Qodo

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

Grey Divider


Remediation recommended

1. Empty dir arg to cosignRemote 🐞 Bug ⛯ Reliability
Description
acceptance/image/createAndPushKeylessImage passes "" for the new directory argument to
cosignRemote.WriteSignedImageIndexImages. If cosign v3 uses this directory for
staging/reading/writing, an empty value can cause failures or writes in an unintended location
(e.g., current working directory), making acceptance tests flaky or polluting the workspace.
Code

acceptance/image/image.go[729]

+	if err := cosignRemote.WriteSignedImageIndexImages(ref, sii, ""); err != nil {
Evidence
The function already computes the on-disk OCI layout directory (imageDir) and loads the
SignedImageIndex from it, but does not pass that directory (or any explicit temp directory) to
WriteSignedImageIndexImages; it passes an empty string instead.

acceptance/image/image.go[712-731]

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

### Issue description
`cosignRemote.WriteSignedImageIndexImages` is called with an empty string for its new directory parameter. This may cause failures or cause the function to read/write from an unintended default location.

### Issue Context
The code already has `imageDir` (the OCI layout directory) and loads `sii` from it, so it’s likely the correct directory to pass, or alternatively a temp staging directory should be used.

### Fix Focus Areas
- acceptance/image/image.go[712-731]

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


2. TrustedRoot fallback not visible 🐞 Bug ✧ Quality
Description
When cosign.TrustedRoot() fails, the code falls back to fetching individual targets but only logs
the failure at debug level. With default logging set to warn, users typically won’t see that they
aren’t using trusted_root.json, reducing debuggability and making verification behavior harder to
reason about in production.
Code

internal/policy/policy.go[R428-434]

+		if !hasSigstoreEnvOverrides() {
+			if trustedRoot, trErr := cosign.TrustedRoot(); trErr == nil {
+				log.Debug("Using trusted root from TUF for verification")
+				opts.TrustedMaterial = trustedRoot
+			} else {
+				log.Debugf("Could not fetch trusted_root.json from TUF, falling back to individual targets: %v", trErr)
+			}
Evidence
The fallback path emits only Debug/Debugf logs. The repository’s logging initialization sets the
default log level to WarnLevel, which suppresses Debug logs unless verbose/debug flags are set.

internal/policy/policy.go[424-447]
internal/logging/logging.go[46-69]

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

### Issue description
Trusted root loading failures currently only emit debug logs, so users running with default logging won’t know they are on the fallback verification path.

### Issue Context
Default log level is Warn. The fallback is likely OK, but should be observable.

### Fix Focus Areas
- internal/policy/policy.go[428-434]
- internal/logging/logging.go[46-69]

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


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

@codecov
Copy link

codecov bot commented Feb 12, 2026

Codecov Report

❌ Patch coverage is 86.66667% with 4 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
internal/policy/policy.go 85.18% 4 Missing ⚠️
Flag Coverage Δ
acceptance 55.50% <73.33%> (+0.02%) ⬆️
generative 18.56% <3.33%> (-0.03%) ⬇️
integration 27.56% <3.33%> (-0.05%) ⬇️
unit 68.39% <83.33%> (+0.03%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
cmd/sigstore/initialize.go 100.00% <100.00%> (ø)
cmd/sigstore/sigstore.go 100.00% <ø> (ø)
cmd/validate/image.go 91.24% <ø> (ø)
internal/attestation/attestation.go 90.16% <ø> (ø)
internal/attestation/slsa_provenance_02.go 100.00% <ø> (ø)
internal/attestation/slsa_provenance_v1.go 100.00% <ø> (ø)
...ation_snapshot_image/application_snapshot_image.go 83.33% <ø> (ø)
internal/output/output.go 98.31% <ø> (ø)
internal/rego/sigstore/sigstore.go 94.14% <ø> (ø)
internal/signature/signature.go 82.75% <ø> (ø)
... and 6 more
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@simonbaird
Copy link
Member

Conflict was due to #3109 iiuc. Thanks @st3penta .

@simonbaird
Copy link
Member

FYI we don't consider the Codecov failure to be blocking, so this is potentially ready to merge.

Also, I filed a Jira just so we can have this visible in our RH scrum board.

} else {
log.Debugf("Could not fetch trusted_root.json from TUF, falling back to individual targets: %v", trErr)
}
}
Copy link
Member

Choose a reason for hiding this comment

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

This might help debugging one day:

Suggested change
}
} else {
log.Debugf("Found Sigstore env overrides. Ignoring any trusted root from TUF.")
}

Just an idea, not a blocker.

}
if opts.CTLogPubKeys, err = cosign.GetCTLogPubs(ctx); err != nil {
return nil, err
}
Copy link
Member

Choose a reason for hiding this comment

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

Would a debug log here be useful also? The removed line 440 isn't very good, but maybe we could log something inside this block.

Suggested change
}
}
log.Debug("Loaded roots, intermediates and CT log public keys")

Maybe you can think of a better log message.

return nil, err
}
}
log.Debug("Retrieved Rekor public keys")
Copy link
Member

Choose a reason for hiding this comment

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

Same thought here - perhaps this line can be kept and moved to after line 475 inside the if block.

return &opts, nil
}

func hasSigstoreEnvOverrides() bool {
Copy link
Member

Choose a reason for hiding this comment

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

It's fairly clear already, but maybe a little comment will help future readers, e.g.:

Suggested change
func hasSigstoreEnvOverrides() bool {
// If any of these env vars are found, we'll assume the user wants to use
// them instead of the TUF root values
func hasSigstoreEnvOverrides() bool {

(Again, feel free to improve my wording, I might be explaining it poorly or using the wrong terminology.)

Copy link
Member

@simonbaird simonbaird left a comment

Choose a reason for hiding this comment

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

I had a couple of minor debug log suggestions, but no serious blockers. Nice work!

Ps, if you want to make the PR tidier, you could rebase it on a fresh upstream/main which would remove the need for @st3penta 's merge commit.

os.Getenv("SIGSTORE_REKOR_PUBLIC_KEY") != "" ||
os.Getenv("SIGSTORE_TSA_CERTIFICATE_FILE") != ""
}

Copy link
Member

Choose a reason for hiding this comment

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

I did say we don't care much about the CodeCov complaint, but actually perhaps you could add some lazy unit testing for this function and get it above the threshold.

if trustedRoot, trErr := cosign.TrustedRoot(); trErr == nil {
log.Debug("Using trusted root from TUF for verification")
opts.TrustedMaterial = trustedRoot
} else {
Copy link
Member

Choose a reason for hiding this comment

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

I'm thinking about test coverage again - do you think it would it be possible to add some additional test cases in internal/policy/policy_test.go to cover these new code paths?

Copy link
Member

Choose a reason for hiding this comment

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

I don't think it's a blocker for merging this PR, just wondering if you think it's doable.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed all review comments, improved coverage too will just need actions to run to see if there is anything else to clean up

@simonbaird
Copy link
Member

Looks like #2852 is the source of the new merge conflict.

@simonbaird
Copy link
Member

Thanks for the revisions, looks good.

I might try to get the conflicts resolved and merge today to help avoid another round of mod file conflicts next week.

Upgrade from cosign/v2 to cosign/v3 so that `ec sigstore initialize`
produces the modern sigstore TUF cache format (trusted_root.json +
signing_config) used by current cosign and gitsign.

In the keyless verification path, ec now loads TrustedMaterial from
trusted_root.json via cosign.TrustedRoot() before falling back to
fetching individual Fulcio/CTLog/Rekor targets. This unifies the TUF
library used for both initialization and verification.

Dependency changes:
- cosign v2.4.1 -> v3.0.4
- conftest v0.57.0 -> v0.66.0 (required for tablewriter v1 compat)
- Go 1.24.6 -> 1.25.3 (required by conftest v0.66.0)

Adapt to breaking API changes:
- cosign.LoadPrivateKey now takes an additional *[]signature.LoadOption
- cosignRemote.WriteSignedImageIndexImages now takes a directory param
- fake.NewSimpleClientset replaced with fake.NewClientset

Fix pre-existing acceptance test bug where the "Effective-time is
honored" scenario used embedded quotes that the step regex could not
match.

Update OPA snapshot and generated docs to reflect new OPA/conftest
help text.

Signed-off-by: SequeI <asiek@redhat.com>
@simonbaird
Copy link
Member

If it goes green, I'm planning to hit merge.

@SequeI
Copy link
Contributor Author

SequeI commented Feb 13, 2026

Ooops.... I resolved conflicts before seeing your messages, my bad

@SequeI
Copy link
Contributor Author

SequeI commented Feb 13, 2026

Should be fine though once all green

@simonbaird
Copy link
Member

/ok-to-test

@simonbaird
Copy link
Member

🟢 🚀

@simonbaird simonbaird merged commit 54f6dc2 into conforma:main Feb 13, 2026
12 checks passed
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.

[RFE] Sigstore cache incompatibility between EC/COSIGN/GITSIGN

3 participants