diff --git a/cmd/cosign/cli/dockerfile/cmdgroup.go b/cmd/cosign/cli/dockerfile/cmdgroup.go new file mode 100644 index 00000000000..f345b979cc8 --- /dev/null +++ b/cmd/cosign/cli/dockerfile/cmdgroup.go @@ -0,0 +1,39 @@ +// 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 dockerfile + +import ( + "context" + "flag" + + "github.com/peterbourgon/ff/v3/ffcli" +) + +func Dockerfile() *ffcli.Command { + var ( + flagset = flag.NewFlagSet("cosign dockerfile", flag.ExitOnError) + ) + + return &ffcli.Command{ + Name: "dockerfile", + ShortUsage: "cosign dockerfile", + ShortHelp: "Provides utilities for discovering images in and performing operations on Dockerfiles", + FlagSet: flagset, + Subcommands: []*ffcli.Command{VerifyDockerfile()}, + Exec: func(ctx context.Context, args []string) error { + return flag.ErrHelp + }, + } +} diff --git a/cmd/cosign/cli/verify_dockerfile.go b/cmd/cosign/cli/dockerfile/verify.go similarity index 80% rename from cmd/cosign/cli/verify_dockerfile.go rename to cmd/cosign/cli/dockerfile/verify.go index 09f1f1c212b..71b95b3554c 100644 --- a/cmd/cosign/cli/verify_dockerfile.go +++ b/cmd/cosign/cli/dockerfile/verify.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package cli +package dockerfile import ( "bufio" @@ -25,24 +25,25 @@ import ( "github.com/peterbourgon/ff/v3/ffcli" "github.com/pkg/errors" + "github.com/sigstore/cosign/cmd/cosign/cli" ) // VerifyCommand verifies a signature on a supplied container image type VerifyDockerfileCommand struct { - VerifyCommand + cli.VerifyCommand BaseOnly bool } // Verify builds and returns an ffcli command func VerifyDockerfile() *ffcli.Command { - cmd := VerifyDockerfileCommand{VerifyCommand: VerifyCommand{}} - flagset := flag.NewFlagSet("cosign verify-dockerfile", flag.ExitOnError) + cmd := VerifyDockerfileCommand{VerifyCommand: cli.VerifyCommand{}} + flagset := flag.NewFlagSet("cosign dockerfile verify", flag.ExitOnError) flagset.BoolVar(&cmd.BaseOnly, "base-image-only", false, "only verify the base image (the last FROM image in the Dockerfile)") - applyVerifyFlags(&cmd.VerifyCommand, flagset) + cli.ApplyVerifyFlags(&cmd.VerifyCommand, flagset) return &ffcli.Command{ - Name: "verify-dockerfile", - ShortUsage: "cosign verify-dockerfile -key || ", + Name: "verify", + ShortUsage: "cosign dockerfile verify -key || ", ShortHelp: "Verify a signature on the base image specified in the Dockerfile", LongHelp: `Verify signature and annotations on images in a Dockerfile by checking claims against the transparency log. @@ -51,34 +52,34 @@ Shell-like variables in the Dockerfile's FROM lines will be substituted with val EXAMPLES # verify cosign claims and signing certificates on the FROM images in the Dockerfile - cosign verify-dockerfile + cosign dockerfile verify # only verify the base image (the last FROM image) - cosign verify-dockerfile -base-image-only + cosign dockerfile verify -base-image-only # additionally verify specified annotations - cosign verify-dockerfile -a key1=val1 -a key2=val2 + cosign dockerfile verify -a key1=val1 -a key2=val2 # (experimental) additionally, verify with the transparency log - COSIGN_EXPERIMENTAL=1 cosign verify-dockerfile + COSIGN_EXPERIMENTAL=1 cosign dockerfile verify # verify images with public key - cosign verify-dockerfile -key cosign.pub + cosign dockerfile verify -key cosign.pub # verify images with public key provided by URL - cosign verify-dockerfile -key https://host.for/ + cosign dockerfile verify -key https://host.for/ # verify images with public key stored in Azure Key Vault - cosign verify-dockerfile -key azurekms://[VAULT_NAME][VAULT_URI]/[KEY] + cosign dockerfile verify -key azurekms://[VAULT_NAME][VAULT_URI]/[KEY] # verify images with public key stored in AWS KMS - cosign verify-dockerfile -key awskms://[ENDPOINT]/[ID/ALIAS/ARN] + cosign dockerfile verify -key awskms://[ENDPOINT]/[ID/ALIAS/ARN] # verify images with public key stored in Google Cloud KMS - cosign verify-dockerfile -key gcpkms://projects/[PROJECT]/locations/global/keyRings/[KEYRING]/cryptoKeys/[KEY] + cosign dockerfile verify -key gcpkms://projects/[PROJECT]/locations/global/keyRings/[KEYRING]/cryptoKeys/[KEY] # verify images with public key stored in Hashicorp Vault - cosign verify-dockerfile -key hashivault://[KEY] `, + cosign dockerfile verify -key hashivault://[KEY] `, FlagSet: flagset, Exec: cmd.Exec, diff --git a/cmd/cosign/cli/verify_dockerfile_test.go b/cmd/cosign/cli/dockerfile/verify_test.go similarity index 99% rename from cmd/cosign/cli/verify_dockerfile_test.go rename to cmd/cosign/cli/dockerfile/verify_test.go index 92af6892712..86672c6f321 100644 --- a/cmd/cosign/cli/verify_dockerfile_test.go +++ b/cmd/cosign/cli/dockerfile/verify_test.go @@ -11,7 +11,7 @@ // 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 +package dockerfile import ( "os" diff --git a/cmd/cosign/cli/verify.go b/cmd/cosign/cli/verify.go index e1a53849728..3ce57c488b2 100644 --- a/cmd/cosign/cli/verify.go +++ b/cmd/cosign/cli/verify.go @@ -46,7 +46,7 @@ type VerifyCommand struct { Annotations *map[string]interface{} } -func applyVerifyFlags(cmd *VerifyCommand, flagset *flag.FlagSet) { +func ApplyVerifyFlags(cmd *VerifyCommand, flagset *flag.FlagSet) { annotations := annotationsMap{} flagset.StringVar(&cmd.KeyRef, "key", "", "path to the public key file, URL, KMS URI or Kubernetes Secret") flagset.StringVar(&cmd.CertEmail, "cert-email", "", "the email expected in a valid fulcio cert") @@ -66,7 +66,7 @@ func applyVerifyFlags(cmd *VerifyCommand, flagset *flag.FlagSet) { func Verify() *ffcli.Command { cmd := VerifyCommand{} flagset := flag.NewFlagSet("cosign verify", flag.ExitOnError) - applyVerifyFlags(&cmd, flagset) + ApplyVerifyFlags(&cmd, flagset) return &ffcli.Command{ Name: "verify", diff --git a/cmd/cosign/cli/verify_manifest.go b/cmd/cosign/cli/verify_manifest.go index fae64481add..3ef7c8e667b 100644 --- a/cmd/cosign/cli/verify_manifest.go +++ b/cmd/cosign/cli/verify_manifest.go @@ -46,7 +46,7 @@ type VerifyManifestCommand struct { func VerifyManifest() *ffcli.Command { cmd := VerifyManifestCommand{VerifyCommand: VerifyCommand{}} flagset := flag.NewFlagSet("cosign verify-manifest", flag.ExitOnError) - applyVerifyFlags(&cmd.VerifyCommand, flagset) + ApplyVerifyFlags(&cmd.VerifyCommand, flagset) return &ffcli.Command{ Name: "verify-manifest", diff --git a/cmd/cosign/main.go b/cmd/cosign/main.go index ed757f6dd22..436193e8fff 100644 --- a/cmd/cosign/main.go +++ b/cmd/cosign/main.go @@ -28,6 +28,7 @@ import ( "github.com/sigstore/cosign/cmd/cosign/cli" "github.com/sigstore/cosign/cmd/cosign/cli/attach" + "github.com/sigstore/cosign/cmd/cosign/cli/dockerfile" "github.com/sigstore/cosign/cmd/cosign/cli/download" "github.com/sigstore/cosign/cmd/cosign/cli/pivcli" "github.com/sigstore/cosign/cmd/cosign/cli/upload" @@ -55,7 +56,6 @@ func main() { cli.SignBlob(), cli.VerifyAttestation(), cli.VerifyBlob(), - cli.VerifyDockerfile(), cli.VerifyManifest(), // Upload sub-tree upload.Upload(), @@ -63,6 +63,8 @@ func main() { download.Download(), // Attach sub-tree attach.Attach(), + // Dockerfile sub-tree + dockerfile.Dockerfile(), // PIV sub-tree pivcli.PivKey(), // PIV sub-tree diff --git a/test/e2e_test.sh b/test/e2e_test.sh index 59da414dcc8..224e34bbdd9 100755 --- a/test/e2e_test.sh +++ b/test/e2e_test.sh @@ -46,17 +46,17 @@ popd go build -o cosign ./cmd/cosign go test -tags=e2e -race ./... -# Test `cosign verify-dockerfile` +# Test `cosign dockerfile verify` export DISTROLESS_PUB_KEY=distroless.pub wget -O ${DISTROLESS_PUB_KEY} https://raw.githubusercontent.com/GoogleContainerTools/distroless/main/cosign.pub -./cosign verify-dockerfile -key ${DISTROLESS_PUB_KEY} ./test/testdata/single_stage.Dockerfile -if (./cosign verify-dockerfile -key ${DISTROLESS_PUB_KEY} ./test/testdata/unsigned_build_stage.Dockerfile); then false; fi -./cosign verify-dockerfile -base-image-only -key ${DISTROLESS_PUB_KEY} ./test/testdata/unsigned_build_stage.Dockerfile -./cosign verify-dockerfile -key ${DISTROLESS_PUB_KEY} ./test/testdata/fancy_from.Dockerfile -test_image="gcr.io/distroless/base" ./cosign verify-dockerfile -key ${DISTROLESS_PUB_KEY} ./test/testdata/with_arg.Dockerfile +./cosign dockerfile verify -key ${DISTROLESS_PUB_KEY} ./test/testdata/single_stage.Dockerfile +if (./cosign dockerfile verify -key ${DISTROLESS_PUB_KEY} ./test/testdata/unsigned_build_stage.Dockerfile); then false; fi +./cosign dockerfile verify -base-image-only -key ${DISTROLESS_PUB_KEY} ./test/testdata/unsigned_build_stage.Dockerfile +./cosign dockerfile verify -key ${DISTROLESS_PUB_KEY} ./test/testdata/fancy_from.Dockerfile +test_image="gcr.io/distroless/base" ./cosign dockerfile verify -key ${DISTROLESS_PUB_KEY} ./test/testdata/with_arg.Dockerfile # Image exists, but is unsigned -if (test_image="ubuntu" ./cosign verify-dockerfile -key ${DISTROLESS_PUB_KEY} ./test/testdata/with_arg.Dockerfile); then false; fi -./cosign verify-dockerfile -key ${DISTROLESS_PUB_KEY} ./test/testdata/with_lowercase.Dockerfile +if (test_image="ubuntu" ./cosign dockerfile verify -key ${DISTROLESS_PUB_KEY} ./test/testdata/with_arg.Dockerfile); then false; fi +./cosign dockerfile verify -key ${DISTROLESS_PUB_KEY} ./test/testdata/with_lowercase.Dockerfile # Test `cosign verify-manifest` ./cosign verify-manifest -key ${DISTROLESS_PUB_KEY} ./test/testdata/signed_manifest.yaml