Repository: sigstore/cosign
Pull request #3581 (2024-03-07 22:57:03)

chore(deps): bump gopkg.in/go-jose/go-jose.v2 from 2.6.1 to 2.6.3
Bumps gopkg.in/go-jose/go-jose.v2 from 2.6.1 to 2.6.3.


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=gopkg.in/go-jose/go-jose.v2&package-manager=go_modules&previous-version=2.6.1&new-version=2.6.3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/sigstore/cosign/network/alerts).

</details>


Patch:
diff --git a/cmd/cosign/cli/options/sign.go b/cmd/cosign/cli/options/sign.go
index c7cef860..70ec9aca 100644
--- a/cmd/cosign/cli/options/sign.go
+++ b/cmd/cosign/cli/options/sign.go
@@ -21,26 +21,27 @@ import (
 
 // SignOptions is the top level wrapper for the sign command.
 type SignOptions struct {
-	Key                   string
-	Cert                  string
-	CertChain             string
-	Upload                bool
-	Output                string // deprecated: TODO remove when the output flag is fully deprecated
-	OutputSignature       string // TODO: this should be the root output file arg.
-	OutputPayload         string
-	OutputCertificate     string
-	PayloadPath           string
-	Recursive             bool
-	Attachment            string
-	SkipConfirmation      bool
-	TlogUpload            bool
-	TSAClientCACert       string
-	TSAClientCert         string
-	TSAClientKey          string
-	TSAServerName         string
-	TSAServerURL          string
-	IssueCertificate      bool
-	SignContainerIdentity string
+	Key                     string
+	Cert                    string
+	CertChain               string
+	Upload                  bool
+	Output                  string // deprecated: TODO remove when the output flag is fully deprecated
+	OutputSignature         string // TODO: this should be the root output file arg.
+	OutputPayload           string
+	OutputCertificate       string
+	PayloadPath             string
+	Recursive               bool
+	Attachment              string
+	SkipConfirmation        bool
+	TlogUpload              bool
+	TSAClientCACert         string
+	TSAClientCert           string
+	TSAClientKey            string
+	TSAServerName           string
+	TSAServerURL            string
+	IssueCertificate        bool
+	SignContainerIdentity   string
+	RecordCreationTimestamp bool
 
 	Rekor       RekorOptions
 	Fulcio      FulcioOptions
@@ -130,4 +131,6 @@ func (o *SignOptions) AddFlags(cmd *cobra.Command) {
 
 	cmd.Flags().StringVar(&o.SignContainerIdentity, "sign-container-identity", "",
 		"manually set the .critical.docker-reference field for the signed identity, which is useful when image proxies are being used where the pull reference should match the signature")
+
+	cmd.Flags().BoolVar(&o.RecordCreationTimestamp, "record-creation-timestamp", false, "set the createdAt timestamp in the signature artifact to the time it was created; by default, cosign sets this to the zero value")
 }
diff --git a/cmd/cosign/cli/sign.go b/cmd/cosign/cli/sign.go
index 110a01a6..76f84a32 100644
--- a/cmd/cosign/cli/sign.go
+++ b/cmd/cosign/cli/sign.go
@@ -83,7 +83,10 @@ race conditions or (worse) malicious tampering.
   cosign sign --key cosign.key --tlog-upload=false <IMAGE DIGEST>
 
   # sign a container image by manually setting the container image identity
-  cosign sign --sign-container-identity <NEW IMAGE DIGEST> <IMAGE DIGEST>`,
+  cosign sign --sign-container-identity <NEW IMAGE DIGEST> <IMAGE DIGEST>
+
+  # sign a container image and honor the creation timestamp of the signature
+  cosign sign --key cosign.key --record-creation-timestamp <IMAGE DIGEST>`,
 
 		Args:             cobra.MinimumNArgs(1),
 		PersistentPreRun: options.BindViper,
diff --git a/cmd/cosign/cli/sign/sign.go b/cmd/cosign/cli/sign/sign.go
index 122aaa33..1289e7b1 100644
--- a/cmd/cosign/cli/sign/sign.go
+++ b/cmd/cosign/cli/sign/sign.go
@@ -329,7 +329,7 @@ func signDigest(ctx context.Context, digest name.Digest, payload []byte, ko opti
 	}
 
 	// Attach the signature to the entity.
-	newSE, err := mutate.AttachSignatureToEntity(se, ociSig, mutate.WithDupeDetector(dd))
+	newSE, err := mutate.AttachSignatureToEntity(se, ociSig, mutate.WithDupeDetector(dd), mutate.WithRecordCreationTimestamp(signOpts.RecordCreationTimestamp))
 	if err != nil {
 		return err
 	}
diff --git a/doc/cosign_sign.md b/doc/cosign_sign.md
index a6cf4885..de309400 100644
--- a/doc/cosign_sign.md
+++ b/doc/cosign_sign.md
@@ -64,6 +64,9 @@ cosign sign [flags]
 
   # sign a container image by manually setting the container image identity
   cosign sign --sign-container-identity <NEW IMAGE DIGEST> <IMAGE DIGEST>
+
+  # sign a container image and honor the creation timestamp of the signature
+  cosign sign --key cosign.key --record-creation-timestamp <IMAGE DIGEST>
 ```
 
 ### Options
@@ -93,6 +96,7 @@ cosign sign [flags]
       --output-payload string                                                                    write the signed payload to FILE
       --output-signature string                                                                  write the signature to FILE
       --payload string                                                                           path to a payload file to use rather than generating one
+      --record-creation-timestamp                                                                set the createdAt timestamp in the signature artifact to the time it was created; by default, cosign sets this to the zero value
   -r, --recursive                                                                                if a multi-arch image is specified, additionally sign each discrete image
       --registry-password string                                                                 registry basic auth password
       --registry-referrers-mode registryReferrersMode                                            mode for fetching references from the registry. allowed: legacy, oci-1-1
diff --git a/go.mod b/go.mod
index 1a63b154..888d6f03 100644
--- a/go.mod
+++ b/go.mod
@@ -144,7 +144,7 @@ require (
 	github.com/fsnotify/fsnotify v1.7.0 // indirect
 	github.com/go-chi/chi v4.1.2+incompatible // indirect
 	github.com/go-ini/ini v1.67.0 // indirect
-	github.com/go-jose/go-jose/v3 v3.0.2 // indirect
+	github.com/go-jose/go-jose/v3 v3.0.3 // indirect
 	github.com/go-logr/logr v1.4.1 // indirect
 	github.com/go-logr/stdr v1.2.2 // indirect
 	github.com/go-openapi/analysis v0.22.2 // indirect
@@ -264,7 +264,7 @@ require (
 	google.golang.org/genproto/googleapis/rpc v0.0.0-20240213162025-012b6fc9bca9 // indirect
 	google.golang.org/grpc v1.62.0 // indirect
 	google.golang.org/protobuf v1.32.0 // indirect
-	gopkg.in/go-jose/go-jose.v2 v2.6.1 // indirect
+	gopkg.in/go-jose/go-jose.v2 v2.6.3 // indirect
 	gopkg.in/inf.v0 v0.9.1 // indirect
 	gopkg.in/ini.v1 v1.67.0 // indirect
 	gopkg.in/yaml.v2 v2.4.0 // indirect
diff --git a/go.sum b/go.sum
index fc676655..c86d671f 100644
--- a/go.sum
+++ b/go.sum
@@ -283,8 +283,8 @@ github.com/go-chi/chi v4.1.2+incompatible h1:fGFk2Gmi/YKXk0OmGfBh0WgmN3XB8lVnEyN
 github.com/go-chi/chi v4.1.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
 github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A=
 github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
-github.com/go-jose/go-jose/v3 v3.0.2 h1:2Edjn8Nrb44UvTdp84KU0bBPs1cO7noRCybtS3eJEUQ=
-github.com/go-jose/go-jose/v3 v3.0.2/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ=
+github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k=
+github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ=
 github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
 github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
 github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
@@ -922,8 +922,8 @@ gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
 gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
-gopkg.in/go-jose/go-jose.v2 v2.6.1 h1:qEzJlIDmG9q5VO0M/o8tGS65QMHMS1w01TQJB1VPJ4U=
-gopkg.in/go-jose/go-jose.v2 v2.6.1/go.mod h1:zzZDPkNNw/c9IE7Z9jr11mBZQhKQTMzoEEIoEdZlFBI=
+gopkg.in/go-jose/go-jose.v2 v2.6.3 h1:nt80fvSDlhKWQgSWyHyy5CfmlQr+asih51R8PTWNKKs=
+gopkg.in/go-jose/go-jose.v2 v2.6.3/go.mod h1:zzZDPkNNw/c9IE7Z9jr11mBZQhKQTMzoEEIoEdZlFBI=
 gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
 gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
 gopkg.in/ini.v1 v1.56.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
diff --git a/pkg/oci/mutate/mutate.go b/pkg/oci/mutate/mutate.go
index f934cb35..59ba2c0c 100644
--- a/pkg/oci/mutate/mutate.go
+++ b/pkg/oci/mutate/mutate.go
@@ -377,5 +377,5 @@ func (so *signOpts) dedupeAndReplace(sig oci.Signature, basefn func() (oci.Signa
 		}
 		return ReplaceSignatures(replace)
 	}
-	return AppendSignatures(base, sig)
+	return AppendSignatures(base, so.rct, sig)
 }
diff --git a/pkg/oci/mutate/options.go b/pkg/oci/mutate/options.go
index a4c41b6f..342eea4e 100644
--- a/pkg/oci/mutate/options.go
+++ b/pkg/oci/mutate/options.go
@@ -33,8 +33,9 @@ type ReplaceOp interface {
 type SignOption func(*signOpts)
 
 type signOpts struct {
-	dd DupeDetector
-	ro ReplaceOp
+	dd  DupeDetector
+	ro  ReplaceOp
+	rct bool
 }
 
 func makeSignOpts(opts ...SignOption) *signOpts {
@@ -59,6 +60,12 @@ func WithReplaceOp(ro ReplaceOp) SignOption {
 	}
 }
 
+func WithRecordCreationTimestamp(rct bool) SignOption {
+	return func(so *signOpts) {
+		so.rct = rct
+	}
+}
+
 type signatureOpts struct {
 	annotations      map[string]string
 	bundle           *bundle.RekorBundle
diff --git a/pkg/oci/mutate/signatures.go b/pkg/oci/mutate/signatures.go
index 648cab04..4f3bd98f 100644
--- a/pkg/oci/mutate/signatures.go
+++ b/pkg/oci/mutate/signatures.go
@@ -19,12 +19,13 @@ import (
 	v1 "github.com/google/go-containerregistry/pkg/v1"
 	"github.com/google/go-containerregistry/pkg/v1/empty"
 	"github.com/google/go-containerregistry/pkg/v1/mutate"
+	"github.com/sigstore/cosign/v2/internal/pkg/now"
 	"github.com/sigstore/cosign/v2/pkg/oci"
 )
 
 // AppendSignatures produces a new oci.Signatures with the provided signatures
 // appended to the provided base signatures.
-func AppendSignatures(base oci.Signatures, sigs ...oci.Signature) (oci.Signatures, error) {
+func AppendSignatures(base oci.Signatures, recordCreationTimestamp bool, sigs ...oci.Signature) (oci.Signatures, error) {
 	adds := make([]mutate.Addendum, 0, len(sigs))
 	for _, sig := range sigs {
 		ann, err := sig.Annotations()
@@ -42,6 +43,19 @@ func AppendSignatures(base oci.Signatures, sigs ...oci.Signature) (oci.Signature
 		return nil, err
 	}
 
+	if recordCreationTimestamp {
+		t, err := now.Now()
+		if err != nil {
+			return nil, err
+		}
+
+		// Set the Created date to time of execution
+		img, err = mutate.CreatedAt(img, v1.Time{Time: t})
+		if err != nil {
+			return nil, err
+		}
+	}
+
 	return &sigAppender{
 		Image: img,
 		base:  base,
diff --git a/pkg/oci/static/file.go b/pkg/oci/static/file.go
index 6fc55d83..c3435be4 100644
--- a/pkg/oci/static/file.go
+++ b/pkg/oci/static/file.go
@@ -22,6 +22,7 @@ import (
 	"github.com/google/go-containerregistry/pkg/v1/empty"
 	"github.com/google/go-containerregistry/pkg/v1/mutate"
 	"github.com/google/go-containerregistry/pkg/v1/types"
+	"github.com/sigstore/cosign/v2/internal/pkg/now"
 	"github.com/sigstore/cosign/v2/pkg/oci"
 	"github.com/sigstore/cosign/v2/pkg/oci/signed"
 )
@@ -48,6 +49,19 @@ func NewFile(payload []byte, opts ...Option) (oci.File, error) {
 	// Add annotations from options
 	img = mutate.Annotations(img, o.Annotations).(v1.Image)
 
+	if o.RecordCreationTimestamp {
+		t, err := now.Now()
+		if err != nil {
+			return nil, err
+		}
+
+		// Set the Created date to time of execution
+		img, err = mutate.CreatedAt(img, v1.Time{Time: t})
+		if err != nil {
+			return nil, err
+		}
+	}
+
 	return &file{
 		SignedImage: signed.Image(img),
 		layer:       layer,
diff --git a/pkg/oci/static/options.go b/pkg/oci/static/options.go
index 100c988e..b240fb22 100644
--- a/pkg/oci/static/options.go
+++ b/pkg/oci/static/options.go
@@ -27,13 +27,14 @@ import (
 type Option func(*options)
 
 type options struct {
-	LayerMediaType   types.MediaType
-	ConfigMediaType  types.MediaType
-	Bundle           *bundle.RekorBundle
-	RFC3161Timestamp *bundle.RFC3161Timestamp
-	Cert             []byte
-	Chain            []byte
-	Annotations      map[string]string
+	LayerMediaType          types.MediaType
+	ConfigMediaType         types.MediaType
+	Bundle                  *bundle.RekorBundle
+	RFC3161Timestamp        *bundle.RFC3161Timestamp
+	Cert                    []byte
+	Chain                   []byte
+	Annotations             map[string]string
+	RecordCreationTimestamp bool
 }
 
 func makeOptions(opts ...Option) (*options, error) {
@@ -112,3 +113,10 @@ func WithCertChain(cert, chain []byte) Option {
 		o.Chain = chain
 	}
 }
+
+// WithRecordCreationTimestamp sets the feature flag to honor the creation timestamp to time of running
+func WithRecordCreationTimestamp(rct bool) Option {
+	return func(o *options) {
+		o.RecordCreationTimestamp = rct
+	}
+}


Test patch:
diff --git a/pkg/oci/mutate/signatures_test.go b/pkg/oci/mutate/signatures_test.go
index 25384a60..b5f2b10c 100644
--- a/pkg/oci/mutate/signatures_test.go
+++ b/pkg/oci/mutate/signatures_test.go
@@ -38,17 +38,17 @@ func TestAppendSignatures(t *testing.T) {
 		t.Fatalf("NewSignature() = %v", err)
 	}
 
-	oneSig, err := AppendSignatures(base, s1)
+	oneSig, err := AppendSignatures(base, false, s1)
 	if err != nil {
 		t.Fatalf("AppendSignatures() = %v", err)
 	}
 
-	twoSig, err := AppendSignatures(oneSig, s2)
+	twoSig, err := AppendSignatures(oneSig, false, s2)
 	if err != nil {
 		t.Fatalf("AppendSignatures() = %v", err)
 	}
 
-	threeSig, err := AppendSignatures(oneSig, s2, s3)
+	threeSig, err := AppendSignatures(oneSig, true, s2, s3)
 	if err != nil {
 		t.Fatalf("AppendSignatures() = %v", err)
 	}
@@ -73,7 +73,13 @@ func TestAppendSignatures(t *testing.T) {
 
 	if testCfg, err := threeSig.ConfigFile(); err != nil {
 		t.Fatalf("ConfigFile() = %v", err)
-	} else if !testCfg.Created.Time.IsZero() {
-		t.Errorf("Date of Signature was not Zero")
+	} else if testCfg.Created.Time.IsZero() {
+		t.Errorf("Date of Signature was Zero")
+	}
+
+	if testDefaultCfg, err := twoSig.ConfigFile(); err != nil {
+		t.Fatalf("ConfigFile() = %v", err)
+	} else if !testDefaultCfg.Created.Time.IsZero() {
+		t.Errorf("Date of Signature was Zero")
 	}
 }
diff --git a/pkg/oci/static/file_test.go b/pkg/oci/static/file_test.go
index 3dc5f304..0866f25d 100644
--- a/pkg/oci/static/file_test.go
+++ b/pkg/oci/static/file_test.go
@@ -32,6 +32,12 @@ func TestNewFile(t *testing.T) {
 		t.Fatalf("NewFile() = %v", err)
 	}
 
+	timestampedFile, err := NewFile([]byte(payload), WithLayerMediaType("foo"), WithAnnotations(map[string]string{"foo": "bar"}), WithRecordCreationTimestamp(true))
+
+	if err != nil {
+		t.Fatalf("NewFile() = %v", err)
+	}
+
 	layers, err := file.Layers()
 	if err != nil {
 		t.Fatalf("Layers() = %v", err)
@@ -129,6 +135,13 @@ func TestNewFile(t *testing.T) {
 		if !fileCfg.Created.Time.IsZero() {
 			t.Errorf("Date of Signature was not Zero")
 		}
+		tsCfg, err := timestampedFile.ConfigFile()
+		if err != nil {
+			t.Fatalf("ConfigFile() = %v", err)
+		}
+		if tsCfg.Created.Time.IsZero() {
+			t.Errorf("Date of Signature was Zero")
+		}
 	})
 
 	t.Run("check annotations", func(t *testing.T) {