Skip to content

Commit

Permalink
Feature: Allow cosign to sign digests before they are uploaded.
Browse files Browse the repository at this point in the history
🎁 This feature allows `cosign` to sign a digest that doesn't exist yet, to support scenarios such as signing an image prior to pushing it.

This adapts the ideas from the two prior approaches, which were closed by stale-bot.

Fixes: #1905

/kind feature

Signed-off-by: Matt Moore <mattmoor@chainguard.dev>
  • Loading branch information
mattmoor committed May 7, 2023
1 parent 3121a17 commit cd988ee
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 2 deletions.
8 changes: 7 additions & 1 deletion cmd/cosign/cli/sign/sign.go
Expand Up @@ -48,6 +48,7 @@ import (
"github.com/sigstore/cosign/v2/pkg/cosign/pkcs11key"
cremote "github.com/sigstore/cosign/v2/pkg/cosign/remote"
"github.com/sigstore/cosign/v2/pkg/oci"
ociempty "github.com/sigstore/cosign/v2/pkg/oci/empty"
"github.com/sigstore/cosign/v2/pkg/oci/mutate"
ociremote "github.com/sigstore/cosign/v2/pkg/oci/remote"
"github.com/sigstore/cosign/v2/pkg/oci/walk"
Expand Down Expand Up @@ -179,7 +180,12 @@ func SignCmd(ro *options.RootOptions, ko options.KeyOpts, signOpts options.SignO

if digest, ok := ref.(name.Digest); ok && !signOpts.Recursive {
se, err := ociremote.SignedEntity(ref, opts...)
if err != nil {
if err == ociremote.ErrEntityNotFound {
se, err = ociempty.SignedImage(ref)
if err != nil {
return fmt.Errorf("creating empty placeholder: %w", err)
}
} else if err != nil {
return fmt.Errorf("accessing image: %w", err)
}
err = signDigest(ctx, digest, staticPayload, ko, signOpts, annotations, dd, sv, se)
Expand Down
6 changes: 5 additions & 1 deletion pkg/oci/remote/remote.go
Expand Up @@ -36,6 +36,10 @@ var (
remoteIndex = remote.Index
remoteGet = remote.Get
remoteWrite = remote.Write

// ErrEntityNotFound is the error that SignedEntity returns when the
// provided ref does not exist.
ErrEntityNotFound = errors.New("entity not found in registry")
)

// SignedEntity provides access to a remote reference, and its signatures.
Expand All @@ -46,7 +50,7 @@ func SignedEntity(ref name.Reference, options ...Option) (oci.SignedEntity, erro
got, err := remoteGet(ref, o.ROpt...)
var te *transport.Error
if errors.As(err, &te) && te.StatusCode == http.StatusNotFound {
return nil, errors.New("entity not found in registry")
return nil, ErrEntityNotFound
} else if err != nil {
return nil, err
}
Expand Down
5 changes: 5 additions & 0 deletions test/e2e_test_secrets.sh
Expand Up @@ -36,6 +36,7 @@ signing_key=cosign.key
verification_key=cosign.pub
img="${TEST_INSTANCE_REPO}/test"
img2="${TEST_INSTANCE_REPO}/test-2"
img3="${TEST_INSTANCE_REPO}/test-3"
legacy_img="${TEST_INSTANCE_REPO}/legacy-test"
for image in $img $img2 $legacy_img
do
Expand Down Expand Up @@ -73,6 +74,10 @@ do
./cosign verify --key ${verification_key} "${multiarch_img}@$(crane digest --platform=$arch ${multiarch_img})"
done

# sign an image that doesn't exist (yet) in the registry
faux_digest=$(head -10 /dev/urandom | sha256sum | cut -d' ' -f 1)
./cosign sign --key ${signing_key} "$img3@sha256:${faux_digest}"

## confirm use of OCI media type in signature image
crane manifest $(./cosign triangulate $img) | grep -q "application/vnd.oci.image.config.v1+json"

Expand Down

0 comments on commit cd988ee

Please sign in to comment.