Skip to content

Conversation

cmurphy
Copy link
Contributor

@cmurphy cmurphy commented Oct 8, 2025

The sign/sign-blob/attest/attest-blob and verify/verify-blob/verify-attestation/verify-blob-attestation commands contained a lot of code that was either copy and pasted to each command, or, more insidiously, functionally the same but written slightly differently between commands. This PR is an effort to reduce the existing duplication, make common updates simpler, prevent the commands from further diverging, and overall reduce LOC. The result is hopefully that the remainder of the code left in each command is mostly specific to that command itself.

This PR is best reviewed commit-by-commit, but can be merged by squash-and-merge.

Summary

Release Note

Documentation

@cmurphy cmurphy requested a review from a team as a code owner October 8, 2025 23:20
Copy link

codecov bot commented Oct 8, 2025

Codecov Report

❌ Patch coverage is 29.28490% with 623 lines in your changes missing coverage. Please review.
✅ Project coverage is 35.35%. Comparing base (2ef6022) to head (d565490).
⚠️ Report is 555 commits behind head on main.

Files with missing lines Patch % Lines
cmd/cosign/cli/signcommon/common.go 13.20% 343 Missing and 12 partials ⚠️
cmd/cosign/cli/verify/common.go 52.50% 137 Missing and 24 partials ⚠️
cmd/cosign/cli/attest/attest.go 0.00% 17 Missing ⚠️
cmd/cosign/cli/sign/sign_blob.go 29.16% 12 Missing and 5 partials ⚠️
cmd/cosign/cli/verify/verify.go 0.00% 17 Missing ⚠️
cmd/cosign/cli/verify/verify_attestation.go 0.00% 17 Missing ⚠️
cmd/cosign/cli/sign/sign.go 0.00% 12 Missing ⚠️
cmd/cosign/cli/attest/attest_blob.go 35.71% 7 Missing and 2 partials ⚠️
cmd/cosign/cli/verify/verify_blob.go 43.75% 5 Missing and 4 partials ⚠️
cmd/cosign/cli/verify/verify_blob_attestation.go 43.75% 5 Missing and 4 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4449      +/-   ##
==========================================
- Coverage   40.10%   35.35%   -4.75%     
==========================================
  Files         155      220      +65     
  Lines       10044    15155    +5111     
==========================================
+ Hits         4028     5358    +1330     
- Misses       5530     9109    +3579     
- Partials      486      688     +202     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Move the nearly identical code for parsing key options and creating a
key pair and token out of attest, attest-blob, sign, and sign-blob, and
into a common helper package. Move functions that had been shared out of
sign.go into the helper package too so that other commands do not have
to import the sign command package.

Signed-off-by: Colleen Murphy <colleenmurphy@google.com>
Signed-off-by: Colleen Murphy <colleenmurphy@google.com>
if err != nil {
return nil, nil, fmt.Errorf("marshalling timestamp: %w", err)
}
if err := os.WriteFile(ko.RFC3161TimestampPath, ts, 0600); err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

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

When calling cosign sign or cosign attest, this file doesn't need to be written since it's included as an annotation on the image.

It looks like we support fetching a timestamp only with the new bundle format for cosign sign (I think this might have been a regression, I recall supporting it before the bundle format was added), but we support it with the old and new bundle format for cosign attest. Can we gate whether we write this file on if we're signing a container vs a blob?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

When calling cosign sign or cosign attest, this file doesn't need to be written since it's included as an annotation on the image.

I see where I went wrong, in cosign sign this function is only called by signDigestBundle when NewBundleFormat is set, so this path is skipped so no file is written. It's not the case for cosign attest which is my mistake.

It looks like we support fetching a timestamp only with the new bundle format for cosign sign (I think this might have been a regression, I recall supporting it before the bundle format was added),

Fetching a timestamp without the new bundle format should still work, it's part of this I think:

if ko.TSAServerURL != "" {
if ko.TSAClientCACert == "" && ko.TSAClientCert == "" { // no mTLS params or custom CA
s = tsa.NewSigner(s, client.NewTSAClient(ko.TSAServerURL))
} else {
s = tsa.NewSigner(s, client.NewTSAClientMTLS(ko.TSAServerURL,
ko.TSAClientCACert,
ko.TSAClientCert,
ko.TSAClientKey,
ko.TSAServerName,
))
}
}

Can we gate whether we write this file on if we're signing a container vs a blob?

Yes will fix

return fmt.Errorf("create bundle file: %w", err)
}
ui.Infof(ctx, "Wrote bundle to file %s", c.BundlePath)
return nil
Copy link
Contributor

Choose a reason for hiding this comment

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

Do you think the above should be de-duped as well? There's commonality between attest, sign and attest-blob with the construction of the attestation, but the latter is written to a file rather than OCI. Not sure if this deduplication is worth it to add complexity to WriteNewBundleWithSigningConfig, which I guess would have to conditionally write to OCI or a file.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes I'll update these

return fmt.Errorf("setting trusted material: %w", err)
}

if err = CheckSigstoreBundleUnsupportedOptions(*c, co); err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

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

To confirm, we call SetTrustedMaterial before CheckSigstoreBundleUnsupportedOptions because we need to know if a trusted root was fetched when using the bundle format? Just wondering if we can exit out earlier, but seems like no.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Right, this is also consistent with its behavior before.

@haydentherapper
Copy link
Contributor

This is fantastic! Thank you for splitting this change into the many commits, made this so straightforward to review!

Signed-off-by: Colleen Murphy <colleenmurphy@google.com>
Signed-off-by: Colleen Murphy <colleenmurphy@google.com>
Signed-off-by: Colleen Murphy <colleenmurphy@google.com>
Signed-off-by: Colleen Murphy <colleenmurphy@google.com>
Move flag checks when --new-bundle-format is used to a common helper
module and have all four verify commands use it. Remove redundant flag
checker code.

Signed-off-by: Colleen Murphy <colleenmurphy@google.com>
RootCerts and IntermediateCerts are already set on CheckOpts during
loadCertsKeylessVerification.

Signed-off-by: Colleen Murphy <colleenmurphy@google.com>
Move the setting of SigVerifier based on the key ref, key slot, or cert
and cert chain, to the common file.

For verifying blobs and blob attestations with a certificate instead of
a key, we return the cert which is used directly in the options list for
verification. For images, the cert and cert chain must be validated and
then unpacked into the SigVerifier, where the cosign Verify* functions
check its validity by extracting it from the verifier.

Signed-off-by: Colleen Murphy <colleenmurphy@google.com>
Signed-off-by: Colleen Murphy <colleenmurphy@google.com>
Signed-off-by: Colleen Murphy <colleenmurphy@google.com>
Signed-off-by: Colleen Murphy <colleenmurphy@google.com>
@haydentherapper haydentherapper merged commit b529ddf into sigstore:main Oct 13, 2025
29 checks passed
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.

3 participants