diff --git a/cmd/cosign/cli/clean.go b/cmd/cosign/cli/clean.go index be86851015d..4968089af1c 100644 --- a/cmd/cosign/cli/clean.go +++ b/cmd/cosign/cli/clean.go @@ -29,7 +29,7 @@ import ( ) func Clean() *cobra.Command { - o := &options.RegistryOptions{} + c := &options.CleanOptions{} cmd := &cobra.Command{ Use: "clean", @@ -37,33 +37,50 @@ func Clean() *cobra.Command { Example: " cosign clean ", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - return CleanCmd(cmd.Context(), *o, args[0]) + return CleanCmd(cmd.Context(), c.Registry, c.CleanType, args[0]) }, } - o.AddFlags(cmd) + c.AddFlags(cmd) return cmd } -func CleanCmd(ctx context.Context, regOpts options.RegistryOptions, imageRef string) error { +func CleanCmd(ctx context.Context, regOpts options.RegistryOptions, cleanType, imageRef string) error { ref, err := name.ParseReference(imageRef) if err != nil { return err } remoteOpts := regOpts.GetRegistryClientOpts(ctx) + sigRef, err := ociremote.SignatureTag(ref, ociremote.WithRemoteOptions(remoteOpts...)) if err != nil { return err } - fmt.Println(sigRef) - - fmt.Fprintln(os.Stderr, "Deleting signature metadata...") - err = remote.Delete(sigRef, remoteOpts...) + attRef, err := ociremote.AttestationTag(ref, ociremote.WithRemoteOptions(remoteOpts...)) if err != nil { return err } + var cleanTags []name.Tag + switch cleanType { + case "signature": + cleanTags = []name.Tag{sigRef} + case "attestation": + cleanTags = []name.Tag{sigRef} + case "all": + cleanTags = []name.Tag{sigRef, attRef} + } + + for _, t := range cleanTags { + fmt.Fprintf(os.Stderr, "Removing %s from %s\n", t.String(), imageRef) + + err = remote.Delete(t, remoteOpts...) + if err != nil { + return err + } + } + return nil } diff --git a/cmd/cosign/cli/options/clean.go b/cmd/cosign/cli/options/clean.go new file mode 100644 index 00000000000..55390b6624e --- /dev/null +++ b/cmd/cosign/cli/options/clean.go @@ -0,0 +1,29 @@ +// Copyright 2022 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 options + +import "github.com/spf13/cobra" + +type CleanOptions struct { + Registry RegistryOptions + CleanType string +} + +var _ Interface = (*CleanOptions)(nil) + +func (c *CleanOptions) AddFlags(cmd *cobra.Command) { + c.Registry.AddFlags(cmd) + cmd.Flags().StringVarP(&c.CleanType, "type", "", "all", "a type of clean: (default: all)") +} diff --git a/doc/cosign_clean.md b/doc/cosign_clean.md index 6fe2fefdce9..7957360ae41 100644 --- a/doc/cosign_clean.md +++ b/doc/cosign_clean.md @@ -19,6 +19,7 @@ cosign clean [flags] --attachment-tag-prefix [AttachmentTagPrefix]sha256-[TargetImageDigest].[AttachmentName] optional custom prefix to use for attached image tags. Attachment images are tagged as: [AttachmentTagPrefix]sha256-[TargetImageDigest].[AttachmentName] -h, --help help for clean --k8s-keychain whether to use the kubernetes keychain instead of the default keychain (supports workload identity). + --type string a type of clean: (default: all) (default "all") ``` ### Options inherited from parent commands diff --git a/test/e2e_test.go b/test/e2e_test.go index cf470d7919b..98fbb9bdaad 100644 --- a/test/e2e_test.go +++ b/test/e2e_test.go @@ -167,8 +167,8 @@ func TestSignVerifyClean(t *testing.T) { must(download.SignatureCmd(ctx, options.RegistryOptions{}, imgName), t) // Now clean signature from the given image - must(cli.CleanCmd(ctx, options.RegistryOptions{}, imgName), t) - + must(cli.CleanCmd(ctx, options.RegistryOptions{}, "all", imgName), t) + 1 // It doesn't work mustErr(verify(pubKeyPath, imgName, true, nil, ""), t) } @@ -196,7 +196,7 @@ func TestImportSignVerifyClean(t *testing.T) { must(download.SignatureCmd(ctx, options.RegistryOptions{}, imgName), t) // Now clean signature from the given image - must(cli.CleanCmd(ctx, options.RegistryOptions{}, imgName), t) + must(cli.CleanCmd(ctx, options.RegistryOptions{}, "all", imgName), t) // It doesn't work mustErr(verify(pubKeyPath, imgName, true, nil, ""), t)