From 8f24b6a59de0d4a2ca113894a4b3a7833d55a3cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Batuhan=20Apayd=C4=B1n?= Date: Fri, 14 May 2021 18:16:10 +0300 Subject: [PATCH] clean command for deleting signature metadata from a given image (#324) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Batuhan Apaydın --- cmd/cosign/cli/clean.go | 77 +++++++++++++++++++++++++++++++++++++++++ cmd/cosign/main.go | 2 +- test/e2e_test.go | 28 +++++++++++++++ 3 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 cmd/cosign/cli/clean.go diff --git a/cmd/cosign/cli/clean.go b/cmd/cosign/cli/clean.go new file mode 100644 index 00000000000..509f82044fb --- /dev/null +++ b/cmd/cosign/cli/clean.go @@ -0,0 +1,77 @@ +// +// 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 cli + +import ( + "context" + "flag" + "fmt" + + "github.com/google/go-containerregistry/pkg/authn" + "github.com/google/go-containerregistry/pkg/name" + "github.com/google/go-containerregistry/pkg/v1/remote" + "github.com/peterbourgon/ff/v3/ffcli" + "github.com/sigstore/cosign/pkg/cosign" +) + +func Clean() *ffcli.Command { + var ( + flagset = flag.NewFlagSet("cosign clean", flag.ExitOnError) + ) + + return &ffcli.Command{ + Name: "clean", + ShortUsage: "cosign clean ", + ShortHelp: "Remove all signatures from an image", + FlagSet: flagset, + Exec: func(ctx context.Context, args []string) error { + if len(args) != 1 { + return flag.ErrHelp + } + + return CleanCmd(ctx, args[0]) + }, + } +} + +func CleanCmd(_ context.Context, imageRef string) error { + ref, err := name.ParseReference(imageRef) + if err != nil { + return err + } + // TODO: just return the descriptor directly if we have a digest reference. + desc, err := remote.Get(ref, remote.WithAuthFromKeychain(authn.DefaultKeychain)) + if err != nil { + return err + } + + dstRef, err := cosign.DestinationRef(ref, desc) + if err != nil { + return err + } + + signRef := dstRef.Context().Tag(cosign.Munge(desc.Descriptor)) + fmt.Println(signRef) + + fmt.Println("Deleting signature metadata...") + + err = remote.Delete(signRef, remote.WithAuthFromKeychain(authn.DefaultKeychain)) + if err != nil { + return err + } + + return nil +} diff --git a/cmd/cosign/main.go b/cmd/cosign/main.go index 392c964ef1a..0a5191493ca 100644 --- a/cmd/cosign/main.go +++ b/cmd/cosign/main.go @@ -41,7 +41,7 @@ func main() { FlagSet: rootFlagSet, Subcommands: []*ffcli.Command{ cli.Verify(), cli.Sign(), cli.Upload(), cli.Generate(), cli.Download(), cli.GenerateKeyPair(), cli.SignBlob(), - cli.VerifyBlob(), cli.Triangulate(), cli.Version(), cli.PublicKey(), pivcli.PivKey(), cli.Copy()}, + cli.VerifyBlob(), cli.Triangulate(), cli.Version(), cli.PublicKey(), pivcli.PivKey(), cli.Copy(), cli.Clean()}, Exec: func(context.Context, []string) error { return flag.ErrHelp }, diff --git a/test/e2e_test.go b/test/e2e_test.go index 986dda88b83..f02e712162e 100644 --- a/test/e2e_test.go +++ b/test/e2e_test.go @@ -100,6 +100,34 @@ func TestSignVerify(t *testing.T) { mustErr(verify(pubKeyPath, imgName, true, map[string]interface{}{"foo": "bar", "baz": "bat"}), t) } +func TestSignVerifyClean(t *testing.T) { + repo, stop := reg(t) + defer stop() + td := t.TempDir() + + imgName := path.Join(repo, "cosign-e2e") + + _, _, _ = mkimage(t, imgName) + + _, privKeyPath, pubKeyPath := keypair(t, td) + + ctx := context.Background() + + // Now sign the image + so := cli.SignOpts{KeyRef: privKeyPath, Pf: passFunc} + must(cli.SignCmd(ctx, so, imgName, true, "", false), t) + + // Now verify and download should work! + must(verify(pubKeyPath, imgName, true, nil), t) + must(cli.DownloadCmd(ctx, imgName), t) + + // Now clean signature from the given image + must(cli.CleanCmd(ctx, imgName), t) + + // It doesn't work + mustErr(verify(pubKeyPath, imgName, true, nil), t) +} + func TestBundle(t *testing.T) { // use rekor prod since we have hardcoded the public key defer setenv(t, cosign.ServerEnv, "https://rekor.sigstore.dev")()