From a7e2a05c4783c046cdc7f4f5aab09edd96ea1c35 Mon Sep 17 00:00:00 2001 From: Dan Lorenc Date: Sat, 19 Jun 2021 07:41:28 -0500 Subject: [PATCH] Reorganize the upload and attach CLI commands. This is in preparation for #368. Signed-off-by: Dan Lorenc --- CHANGELOG.md | 3 ++ EXAMPLES.md | 2 +- README.md | 4 +- USAGE.md | 6 +-- cmd/cosign/cli/attach/attach.go | 40 +++++++++++++++++++ cmd/cosign/cli/{upload.go => attach/sig.go} | 16 ++++---- .../cli/{upload_blob.go => upload/blob.go} | 22 +++++----- .../blob_test.go} | 2 +- cmd/cosign/cli/upload/upload.go | 40 +++++++++++++++++++ cmd/cosign/main.go | 17 +++++++- test/e2e_test.go | 16 ++++---- test/e2e_test_secrets.sh | 4 +- 12 files changed, 135 insertions(+), 37 deletions(-) create mode 100644 cmd/cosign/cli/attach/attach.go rename cmd/cosign/cli/{upload.go => attach/sig.go} (89%) rename cmd/cosign/cli/{upload_blob.go => upload/blob.go} (84%) rename cmd/cosign/cli/{upload_blob_test.go => upload/blob_test.go} (98%) create mode 100644 cmd/cosign/cli/upload/upload.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 65c1b8e3b25..a8c14b43e33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ ### Enhancements +* BREAKING: Move `cosign upload-blob` to `cosign upload blob`. +* BREAKING: Move `cosign upload` to `cosign attach signature`. + ### Bug Fixes ### Contributors diff --git a/EXAMPLES.md b/EXAMPLES.md index a9d0fc42a09..38f478ec507 100644 --- a/EXAMPLES.md +++ b/EXAMPLES.md @@ -8,7 +8,7 @@ Use `cosign` to generate the payload, sign it with `gcloud kms`, then use `cosig $ cosign generate us-central1-docker.pkg.dev/dlorenc-vmtest2/test/taskrun > payload.json $ gcloud kms asymmetric-sign --digest-algorithm=sha256 --input-file=payload.json --signature-file=gcpkms.sig --key=foo --keyring=foo --version=1 --location=us-central # We have to base64 encode the signature -$ cat gcpkms.sig | base64 | cosign upload -signature - us-central1-docker.pkg.dev/dlorenc-vmtest2/test/taskrun +$ cat gcpkms.sig | base64 | cosign attach signature -signature - us-central1-docker.pkg.dev/dlorenc-vmtest2/test/taskrun ``` Now (on another machine) download the public key, payload, signatures and verify it! diff --git a/README.md b/README.md index 362961a8fcf..d0f3131a3a4 100644 --- a/README.md +++ b/README.md @@ -128,11 +128,11 @@ OCI registries are useful for storing more than just container images! This section shows how to leverage these for an easy-to-use, backwards-compatible artifact distribution system that integrates well with the rest of Sigstore. -You can publish an artifact with `cosign upload-blob`: +You can publish an artifact with `cosign upload blob`: ```shell $ echo "my first artifact" > artifact -$ cosign upload-blob -f artifact gcr.io/dlorenc-vmtest2/artifact +$ cosign upload blob -f artifact gcr.io/dlorenc-vmtest2/artifact Uploading file from [artifact] to [gcr.io/dlorenc-vmtest2/artifact:latest] with media type [text/plain; charset=utf-8] File is available directly at [us.gcr.io/v2/dlorenc-vmtest2/readme/blobs/sha256:b57400c0ad852a7c2f6f7da4a1f94547692c61f3e921a49ba3a41805ae8e1e99] us.gcr.io/dlorenc-vmtest2/readme@sha256:4aa3054270f7a70b4528f2064ee90961788e1e1518703592ae4463de3b889dec diff --git a/USAGE.md b/USAGE.md index 4488633aaa6..2825015f073 100644 --- a/USAGE.md +++ b/USAGE.md @@ -125,21 +125,21 @@ The signature is passed via the -signature flag. It can be a file: ```shell -$ cosign upload -signature file.sig dlorenc/demo +$ cosign attach signature -signature file.sig dlorenc/demo Pushing signature to: dlorenc/demo:sha256-87ef60f558bad79beea6425a3b28989f01dd417164150ab3baab98dcbf04def8.sig ``` the base64-encoded signature: ```shell -$ cosign upload -signature Qr883oPOj0dj82PZ0d9mQ2lrdM0lbyLSXUkjt6ejrxtHxwe7bU6Gr27Sysgk1jagf1htO/gvkkg71oJiwWryCQ== dlorenc/demo +$ cosign attach signature -signature Qr883oPOj0dj82PZ0d9mQ2lrdM0lbyLSXUkjt6ejrxtHxwe7bU6Gr27Sysgk1jagf1htO/gvkkg71oJiwWryCQ== dlorenc/demo Pushing signature to: dlorenc/demo:sha256-87ef60f558bad79beea6425a3b28989f01dd417164150ab3baab98dcbf04def.sig ``` or, `-` for stdin for chaining from other commands: ```shell -$ cosign generate dlorenc/demo | openssl... | cosign upload -signature -- dlorenc/demo +$ cosign generate dlorenc/demo | openssl... | cosign attach signature -signature -- dlorenc/demo Pushing signature to: dlorenc/demo:sha256-87ef60f558bad79beea6425a3b28989f01dd417164150ab3baab98dcbf04def.sig ``` diff --git a/cmd/cosign/cli/attach/attach.go b/cmd/cosign/cli/attach/attach.go new file mode 100644 index 00000000000..7c24235a428 --- /dev/null +++ b/cmd/cosign/cli/attach/attach.go @@ -0,0 +1,40 @@ +// +// Copyright 2021 The Sigstore Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package attach + +import ( + "context" + "flag" + + "github.com/peterbourgon/ff/v3/ffcli" +) + +func Attach() *ffcli.Command { + var ( + flagset = flag.NewFlagSet("cosign attach", flag.ExitOnError) + ) + + return &ffcli.Command{ + Name: "attach", + ShortUsage: "cosign attach", + ShortHelp: "attach contains tools to attach artifacts to other artifacts in a registry", + FlagSet: flagset, + Subcommands: []*ffcli.Command{Signature()}, + Exec: func(ctx context.Context, args []string) error { + return flag.ErrHelp + }, + } +} diff --git a/cmd/cosign/cli/upload.go b/cmd/cosign/cli/attach/sig.go similarity index 89% rename from cmd/cosign/cli/upload.go rename to cmd/cosign/cli/attach/sig.go index 8187a2059fb..b0d67f02c63 100644 --- a/cmd/cosign/cli/upload.go +++ b/cmd/cosign/cli/attach/sig.go @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package cli +package attach import ( "context" @@ -34,28 +34,28 @@ import ( sigPayload "github.com/sigstore/sigstore/pkg/signature/payload" ) -func Upload() *ffcli.Command { +func Signature() *ffcli.Command { var ( - flagset = flag.NewFlagSet("cosign upload", flag.ExitOnError) + flagset = flag.NewFlagSet("cosign attach signature", flag.ExitOnError) signature = flagset.String("signature", "", "the signature, path to the signature, or {-} for stdin") payload = flagset.String("payload", "", "path to the payload covered by the signature (if using another format)") ) return &ffcli.Command{ - Name: "upload", - ShortUsage: "cosign upload ", - ShortHelp: "upload signatures to the supplied container image", + Name: "signature", + ShortUsage: "cosign attach signature ", + ShortHelp: "attach signatures to the supplied container image", FlagSet: flagset, Exec: func(ctx context.Context, args []string) error { if len(args) != 1 { return flag.ErrHelp } - return UploadCmd(ctx, *signature, *payload, args[0]) + return SignatureCmd(ctx, *signature, *payload, args[0]) }, } } -func UploadCmd(ctx context.Context, sigRef, payloadRef, imageRef string) error { +func SignatureCmd(ctx context.Context, sigRef, payloadRef, imageRef string) error { var b64SigBytes []byte b64SigBytes, err := signatureBytes(sigRef) diff --git a/cmd/cosign/cli/upload_blob.go b/cmd/cosign/cli/upload/blob.go similarity index 84% rename from cmd/cosign/cli/upload_blob.go rename to cmd/cosign/cli/upload/blob.go index 2ced9421e23..774dda48cb6 100644 --- a/cmd/cosign/cli/upload_blob.go +++ b/cmd/cosign/cli/upload/blob.go @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package cli +package upload import ( "context" @@ -72,31 +72,31 @@ func (fs *Files) String() string { return strings.Join(s, ",") } -func UploadBlob() *ffcli.Command { +func Blob() *ffcli.Command { var ( - flagset = flag.NewFlagSet("cosign upload-blob", flag.ExitOnError) + flagset = flag.NewFlagSet("cosign upload blob", flag.ExitOnError) ct = flagset.String("ct", "", "content type to set") ) fmap := Files{} flagset.Var(&fmap, "f", ":[platform/arch]") return &ffcli.Command{ - Name: "upload-blob", - ShortUsage: "cosign upload-blob -f ", + Name: "blob", + ShortUsage: "cosign upload blob -f ", ShortHelp: "Upload one or more blobs to the supplied container image address", LongHelp: `Upload one or more blobs to the supplied container image address. EXAMPLES # upload a blob named foo to the location specified by - cosign upload-blob -f foo + cosign upload blob -f foo # upload a blob named foo to the location specified by , setting the os field to "MYOS". - cosign upload-blob -f foo:MYOS + cosign upload blob -f foo:MYOS # upload a blob named foo to the location specified by , setting the os field to "MYOS" and the platform field to "MYPLATFORM". - cosign upload-blob -f foo:MYOS/MYPLATFORM + cosign upload blob -f foo:MYOS/MYPLATFORM # upload two blobs named foo-darwin and foo-linux to the location specified by , setting the os fields - cosign upload-blob -f foo-darwin:darwin -f foo-linux:linux + cosign upload blob -f foo-darwin:darwin -f foo-linux:linux `, FlagSet: flagset, Exec: func(ctx context.Context, args []string) error { @@ -104,12 +104,12 @@ EXAMPLES return flag.ErrHelp } - return UploadBlobCmd(ctx, fmap.Files, *ct, args[0]) + return BlobCmd(ctx, fmap.Files, *ct, args[0]) }, } } -func UploadBlobCmd(ctx context.Context, files []cremote.File, contentType, imageRef string) error { +func BlobCmd(ctx context.Context, files []cremote.File, contentType, imageRef string) error { ref, err := name.ParseReference(imageRef) if err != nil { return err diff --git a/cmd/cosign/cli/upload_blob_test.go b/cmd/cosign/cli/upload/blob_test.go similarity index 98% rename from cmd/cosign/cli/upload_blob_test.go rename to cmd/cosign/cli/upload/blob_test.go index a40f3f597bb..16754c76e71 100644 --- a/cmd/cosign/cli/upload_blob_test.go +++ b/cmd/cosign/cli/upload/blob_test.go @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package cli +package upload import ( "reflect" diff --git a/cmd/cosign/cli/upload/upload.go b/cmd/cosign/cli/upload/upload.go new file mode 100644 index 00000000000..86ce19a8c62 --- /dev/null +++ b/cmd/cosign/cli/upload/upload.go @@ -0,0 +1,40 @@ +// +// Copyright 2021 The Sigstore Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package upload + +import ( + "context" + "flag" + + "github.com/peterbourgon/ff/v3/ffcli" +) + +func Upload() *ffcli.Command { + var ( + flagset = flag.NewFlagSet("cosign upload", flag.ExitOnError) + ) + + return &ffcli.Command{ + Name: "upload", + ShortUsage: "cosign upload", + ShortHelp: "upload contains tools to upload artifacts to a registry", + FlagSet: flagset, + Subcommands: []*ffcli.Command{Blob()}, + Exec: func(ctx context.Context, args []string) error { + return flag.ErrHelp + }, + } +} diff --git a/cmd/cosign/main.go b/cmd/cosign/main.go index cc64c8480c7..a104b5e0326 100644 --- a/cmd/cosign/main.go +++ b/cmd/cosign/main.go @@ -26,7 +26,9 @@ import ( "github.com/pkg/errors" "github.com/sigstore/cosign/cmd/cosign/cli" + "github.com/sigstore/cosign/cmd/cosign/cli/attach" "github.com/sigstore/cosign/cmd/cosign/cli/pivcli" + "github.com/sigstore/cosign/cmd/cosign/cli/upload" ) var ( @@ -40,8 +42,19 @@ func main() { ShortUsage: "cosign [flags] ", FlagSet: rootFlagSet, Subcommands: []*ffcli.Command{ - cli.Verify(), cli.Sign(), cli.Upload(), cli.Generate(), cli.Download(), cli.GenerateKeyPair(), cli.SignBlob(), - cli.UploadBlob(), cli.Copy(), cli.Clean(), cli.VerifyBlob(), cli.Triangulate(), cli.Version(), cli.PublicKey(), pivcli.PivKey()}, + // Key Management + cli.PublicKey(), cli.GenerateKeyPair(), + // Signing + cli.Verify(), cli.Sign(), cli.Generate(), cli.SignBlob(), cli.VerifyBlob(), + // Upload sub-tree + upload.Upload(), + // Upload sub-tree + attach.Attach(), + // PIV sub-tree + pivcli.PivKey(), + // PIV sub-tree + cli.Copy(), cli.Clean(), cli.Triangulate(), cli.Download(), + cli.Version()}, Exec: func(context.Context, []string) error { return flag.ErrHelp }, diff --git a/test/e2e_test.go b/test/e2e_test.go index d405d47032b..0344e2d81e4 100644 --- a/test/e2e_test.go +++ b/test/e2e_test.go @@ -39,6 +39,8 @@ import ( "github.com/google/go-containerregistry/pkg/v1/remote" "github.com/sigstore/cosign/cmd/cosign/cli" + "github.com/sigstore/cosign/cmd/cosign/cli/attach" + "github.com/sigstore/cosign/cmd/cosign/cli/upload" sget "github.com/sigstore/cosign/cmd/sget/cli" "github.com/sigstore/cosign/pkg/cosign" "github.com/sigstore/cosign/pkg/cosign/kubernetes" @@ -387,22 +389,22 @@ func TestUploadDownload(t *testing.T) { testCases := map[string]struct { signature string - signatureType cli.SignatureArgType + signatureType attach.SignatureArgType expectedErr bool }{ "file containing signature": { signature: "testsignaturefile", - signatureType: cli.FileSignature, + signatureType: attach.FileSignature, expectedErr: false, }, "raw signature as argument": { signature: "testsignatureraw", - signatureType: cli.RawSignature, + signatureType: attach.RawSignature, expectedErr: false, }, "empty signature as argument": { signature: "", - signatureType: cli.RawSignature, + signatureType: attach.RawSignature, expectedErr: true, }, } @@ -416,14 +418,14 @@ func TestUploadDownload(t *testing.T) { signature := base64.StdEncoding.EncodeToString([]byte(testCase.signature)) var sigRef string - if testCase.signatureType == cli.FileSignature { + if testCase.signatureType == attach.FileSignature { sigRef = mkfile(signature, td, t) } else { sigRef = signature } // Upload it! - err := cli.UploadCmd(ctx, sigRef, payloadPath, imgName) + err := attach.SignatureCmd(ctx, sigRef, payloadPath, imgName) if testCase.expectedErr { mustErr(err, t) } else { @@ -469,7 +471,7 @@ func TestUploadBlob(t *testing.T) { files := []cremote.File{{ Path: payloadPath, }} - must(cli.UploadBlobCmd(ctx, files, "", imgName), t) + must(upload.BlobCmd(ctx, files, "", imgName), t) // Check it ref, err := name.ParseReference(imgName) diff --git a/test/e2e_test_secrets.sh b/test/e2e_test_secrets.sh index fc51132ba8a..9948c0a9763 100755 --- a/test/e2e_test_secrets.sh +++ b/test/e2e_test_secrets.sh @@ -118,8 +118,8 @@ crane ls ${blobimg} | while read tag ; do crane delete "${blobimg}:${tag}" ; don # make a random blob cat /dev/urandom | head -n 10 | base64 > randomblob -# upload-blob and sign it -dgst=$(./cosign upload-blob -f randomblob ${blobimg}) +# upload blob and sign it +dgst=$(./cosign upload blob -f randomblob ${blobimg}) ./cosign sign -key ${signing_key} ${dgst} ./cosign verify -key ${verification_key} ${dgst} # For sanity