diff --git a/cmd/finch/nerdctl.go b/cmd/finch/nerdctl.go index a1abd8dfb..6fd76edc4 100644 --- a/cmd/finch/nerdctl.go +++ b/cmd/finch/nerdctl.go @@ -140,6 +140,21 @@ func (nc *nerdctlCommand) run(cmdName string, args []string) error { envVars[evar] = eval } + passedEnvs := []string{"COSIGN_PASSWORD"} + var passedEnvArgs []string + for _, e := range passedEnvs { + v, b := nc.systemDeps.LookupEnv(e) + if b { + passedEnvArgs = append(passedEnvArgs, fmt.Sprintf("%s=%s", e, v)) + } + } + + // Add -E to sudo command in order to preserve existing environment variables, more info: + // https://stackoverflow.com/questions/8633461/how-to-keep-environment-variables-when-using-sudo/8633575#8633575 + limaArgs := append([]string{"shell", limaInstanceName, "sudo", "-E"}, passedEnvArgs...) + + limaArgs = append(limaArgs, []string{nerdctlCmdName, cmdName}...) + var finalArgs []string for key, val := range envVars { finalArgs = append(finalArgs, "-e", fmt.Sprintf("%s=%s", key, val)) @@ -147,7 +162,7 @@ func (nc *nerdctlCommand) run(cmdName string, args []string) error { finalArgs = append(finalArgs, nerdctlArgs...) // Add -E to sudo command in order to preserve existing environment variables, more info: // https://stackoverflow.com/questions/8633461/how-to-keep-environment-variables-when-using-sudo/8633575#8633575 - limaArgs := append([]string{"shell", limaInstanceName, "sudo", "-E", nerdctlCmdName, cmdName}, finalArgs...) + limaArgs = append(limaArgs, finalArgs...) if nc.shouldReplaceForHelp(cmdName, args) { return nc.creator.RunWithReplacingStdout([]command.Replacement{{Source: "nerdctl", Target: "finch"}}, limaArgs...) diff --git a/cmd/finch/nerdctl_test.go b/cmd/finch/nerdctl_test.go index 2828a5c9a..f218ee05c 100644 --- a/cmd/finch/nerdctl_test.go +++ b/cmd/finch/nerdctl_test.go @@ -15,10 +15,10 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/runfinch/finch/pkg/flog" + "github.com/runfinch/finch/pkg/command" "github.com/runfinch/finch/pkg/mocks" - - "github.com/runfinch/finch/pkg/flog" ) var testStdoutRs = []command.Replacement{ @@ -40,7 +40,7 @@ func TestNerdctlCommand_runAdaptor(t *testing.T) { name string cmd *cobra.Command args []string - mockSvc func(*mocks.LimaCmdCreator, *mocks.Logger, *gomock.Controller) + mockSvc func(*mocks.LimaCmdCreator, *mocks.Logger, *gomock.Controller, *mocks.NerdctlCommandSystemDeps) }{ { name: "happy path", @@ -48,11 +48,12 @@ func TestNerdctlCommand_runAdaptor(t *testing.T) { Use: "info", }, args: []string{}, - mockSvc: func(lcc *mocks.LimaCmdCreator, logger *mocks.Logger, ctrl *gomock.Controller) { + mockSvc: func(lcc *mocks.LimaCmdCreator, logger *mocks.Logger, ctrl *gomock.Controller, ncsd *mocks.NerdctlCommandSystemDeps) { getVMStatusC := mocks.NewCommand(ctrl) lcc.EXPECT().CreateWithoutStdio("ls", "-f", "{{.Status}}", limaInstanceName).Return(getVMStatusC) getVMStatusC.EXPECT().Output().Return([]byte("Running"), nil) logger.EXPECT().Debugf("Status of virtual machine: %s", "Running") + ncsd.EXPECT().LookupEnv("COSIGN_PASSWORD").Return("", false) c := mocks.NewCommand(ctrl) lcc.EXPECT().Create("shell", limaInstanceName, "sudo", "-E", nerdctlCmdName, "info").Return(c) c.EXPECT().Run() @@ -69,7 +70,7 @@ func TestNerdctlCommand_runAdaptor(t *testing.T) { lcc := mocks.NewLimaCmdCreator(ctrl) ncsd := mocks.NewNerdctlCommandSystemDeps(ctrl) logger := mocks.NewLogger(ctrl) - tc.mockSvc(lcc, logger, ctrl) + tc.mockSvc(lcc, logger, ctrl, ncsd) assert.NoError(t, newNerdctlCommand(lcc, ncsd, logger, nil).runAdapter(tc.cmd, tc.args)) }) @@ -103,6 +104,7 @@ func TestNerdctlCommand_run(t *testing.T) { lcc.EXPECT().CreateWithoutStdio("ls", "-f", "{{.Status}}", limaInstanceName).Return(getVMStatusC) getVMStatusC.EXPECT().Output().Return([]byte("Running"), nil) logger.EXPECT().Debugf("Status of virtual machine: %s", "Running") + ncsd.EXPECT().LookupEnv("COSIGN_PASSWORD").Return("", false) c := mocks.NewCommand(ctrl) lcc.EXPECT().Create("shell", limaInstanceName, "sudo", "-E", nerdctlCmdName, "build", "-t", "demo", ".").Return(c) c.EXPECT().Run() @@ -204,6 +206,7 @@ func TestNerdctlCommand_run(t *testing.T) { getVMStatusC.EXPECT().Output().Return([]byte("Running"), nil) logger.EXPECT().Debugf("Status of virtual machine: %s", "Running") logger.EXPECT().SetLevel(flog.Debug) + ncsd.EXPECT().LookupEnv("COSIGN_PASSWORD").Return("", false) c := mocks.NewCommand(ctrl) lcc.EXPECT().Create("shell", limaInstanceName, "sudo", "-E", nerdctlCmdName, "pull", "test:tag").Return(c) c.EXPECT().Run() @@ -229,6 +232,7 @@ func TestNerdctlCommand_run(t *testing.T) { c := mocks.NewCommand(ctrl) ncsd.EXPECT().LookupEnv("ARG2") ncsd.EXPECT().LookupEnv("ARG3") + ncsd.EXPECT().LookupEnv("COSIGN_PASSWORD").Return("", false) lcc.EXPECT().Create("shell", limaInstanceName, "sudo", "-E", nerdctlCmdName, "run", "-e", "ARG1=val1", "--rm", "alpine:latest", "env").Return(c) c.EXPECT().Run() @@ -254,6 +258,7 @@ func TestNerdctlCommand_run(t *testing.T) { c := mocks.NewCommand(ctrl) ncsd.EXPECT().LookupEnv("ARG2") ncsd.EXPECT().LookupEnv("ARG3").Return("val3", true) + ncsd.EXPECT().LookupEnv("COSIGN_PASSWORD").Return("", false) lcc.EXPECT().Create("shell", limaInstanceName, "sudo", "-E", nerdctlCmdName, "run", "-e", "ARG3=val3", "--rm", "alpine:latest", "env").Return(c) c.EXPECT().Run() @@ -282,6 +287,7 @@ func TestNerdctlCommand_run(t *testing.T) { c := mocks.NewCommand(ctrl) ncsd.EXPECT().LookupEnv("ARG2") ncsd.EXPECT().LookupEnv("NOTSETARG") + ncsd.EXPECT().LookupEnv("COSIGN_PASSWORD").Return("", false) lcc.EXPECT(). Create("shell", limaInstanceName, "sudo", "-E", nerdctlCmdName, "run", "-e", "ARG1=val1", "--rm", "alpine:latest", "env"). Return(c) @@ -311,6 +317,7 @@ func TestNerdctlCommand_run(t *testing.T) { c := mocks.NewCommand(ctrl) ncsd.EXPECT().LookupEnv("ARG2").Return("val2", true) ncsd.EXPECT().LookupEnv("NOTSETARG") + ncsd.EXPECT().LookupEnv("COSIGN_PASSWORD").Return("", false) lcc.EXPECT(). Create("shell", limaInstanceName, "sudo", "-E", nerdctlCmdName, "run", "-e", "ARG2=val2", "--rm", "alpine:latest", "env"). Return(c) @@ -354,6 +361,7 @@ func TestNerdctlCommand_run(t *testing.T) { getVMStatusC.EXPECT().Output().Return([]byte("Running"), nil) logger.EXPECT().Debugf("Status of virtual machine: %s", "Running") logger.EXPECT().Debugf(`Resolving special IP "host-gateway" to %q for host %q`, "192.168.5.2", "name") + ncsd.EXPECT().LookupEnv("COSIGN_PASSWORD").Return("", false) c := mocks.NewCommand(ctrl) lcc.EXPECT().Create("shell", limaInstanceName, "sudo", "-E", nerdctlCmdName, "run", "--rm", "--add-host", "name:192.168.5.2", "alpine:latest").Return(c) @@ -377,6 +385,7 @@ func TestNerdctlCommand_run(t *testing.T) { lcc.EXPECT().CreateWithoutStdio("ls", "-f", "{{.Status}}", limaInstanceName).Return(getVMStatusC) getVMStatusC.EXPECT().Output().Return([]byte("Running"), nil) logger.EXPECT().Debugf("Status of virtual machine: %s", "Running") + ncsd.EXPECT().LookupEnv("COSIGN_PASSWORD").Return("", false) c := mocks.NewCommand(ctrl) lcc.EXPECT().Create("shell", limaInstanceName, "sudo", "-E", nerdctlCmdName, "run", "--rm", "--add-host", "name:0.0.0.0", "alpine:latest").Return(c) @@ -400,6 +409,7 @@ func TestNerdctlCommand_run(t *testing.T) { lcc.EXPECT().CreateWithoutStdio("ls", "-f", "{{.Status}}", limaInstanceName).Return(getVMStatusC) getVMStatusC.EXPECT().Output().Return([]byte("Running"), nil) logger.EXPECT().Debugf("Status of virtual machine: %s", "Running") + ncsd.EXPECT().LookupEnv("COSIGN_PASSWORD").Return("", false) c := mocks.NewCommand(ctrl) lcc.EXPECT().Create("shell", limaInstanceName, "sudo", "-E", nerdctlCmdName, "run", "--rm", "--add-host", "alpine:latest").Return(c) @@ -424,6 +434,7 @@ func TestNerdctlCommand_run(t *testing.T) { getVMStatusC.EXPECT().Output().Return([]byte("Running"), nil) logger.EXPECT().Debugf("Status of virtual machine: %s", "Running") logger.EXPECT().Debugf(`Resolving special IP "host-gateway" to %q for host %q`, "192.168.5.2", "name") + ncsd.EXPECT().LookupEnv("COSIGN_PASSWORD").Return("", false) c := mocks.NewCommand(ctrl) lcc.EXPECT().Create("shell", limaInstanceName, "sudo", "-E", nerdctlCmdName, "run", "--rm", "--add-host=name:192.168.5.2", "alpine:latest").Return(c) @@ -447,6 +458,7 @@ func TestNerdctlCommand_run(t *testing.T) { lcc.EXPECT().CreateWithoutStdio("ls", "-f", "{{.Status}}", limaInstanceName).Return(getVMStatusC) getVMStatusC.EXPECT().Output().Return([]byte("Running"), nil) logger.EXPECT().Debugf("Status of virtual machine: %s", "Running") + ncsd.EXPECT().LookupEnv("COSIGN_PASSWORD").Return("", false) c := mocks.NewCommand(ctrl) lcc.EXPECT().Create("shell", limaInstanceName, "sudo", "-E", nerdctlCmdName, "run", "--rm", "--add-host=name:0.0.0.0", "alpine:latest").Return(c) @@ -470,6 +482,7 @@ func TestNerdctlCommand_run(t *testing.T) { lcc.EXPECT().CreateWithoutStdio("ls", "-f", "{{.Status}}", limaInstanceName).Return(getVMStatusC) getVMStatusC.EXPECT().Output().Return([]byte("Running"), nil) logger.EXPECT().Debugf("Status of virtual machine: %s", "Running") + ncsd.EXPECT().LookupEnv("COSIGN_PASSWORD").Return("", false) lcc.EXPECT().RunWithReplacingStdout( testStdoutRs, "shell", limaInstanceName, "sudo", "-E", nerdctlCmdName, "pull", "test:tag", "--help").Return(nil) }, @@ -491,11 +504,84 @@ func TestNerdctlCommand_run(t *testing.T) { lcc.EXPECT().CreateWithoutStdio("ls", "-f", "{{.Status}}", limaInstanceName).Return(getVMStatusC) getVMStatusC.EXPECT().Output().Return([]byte("Running"), nil) logger.EXPECT().Debugf("Status of virtual machine: %s", "Running") + ncsd.EXPECT().LookupEnv("COSIGN_PASSWORD").Return("", false) lcc.EXPECT().RunWithReplacingStdout( testStdoutRs, "shell", limaInstanceName, "sudo", "-E", nerdctlCmdName, "pull", "test:tag", "--help"). Return(fmt.Errorf("failed to replace")) }, }, + { + name: "with COSIGN_PASSWORD env var and --sign=cosign", + cmdName: "push", + args: []string{"--sign=cosign", "test:tag"}, + wantErr: nil, + mockSvc: func( + t *testing.T, + lcc *mocks.LimaCmdCreator, + ncsd *mocks.NerdctlCommandSystemDeps, + logger *mocks.Logger, + ctrl *gomock.Controller, + fs afero.Fs, + ) { + getVMStatusC := mocks.NewCommand(ctrl) + lcc.EXPECT().CreateWithoutStdio("ls", "-f", "{{.Status}}", limaInstanceName).Return(getVMStatusC) + getVMStatusC.EXPECT().Output().Return([]byte("Running"), nil) + logger.EXPECT().Debugf("Status of virtual machine: %s", "Running") + ncsd.EXPECT().LookupEnv("COSIGN_PASSWORD").Return("test", true) + c := mocks.NewCommand(ctrl) + lcc.EXPECT().Create("shell", limaInstanceName, "sudo", "-E", "COSIGN_PASSWORD=test", nerdctlCmdName, + "push", "--sign=cosign", "test:tag").Return(c) + c.EXPECT().Run() + }, + }, + { + name: "with COSIGN_PASSWORD env var and --verify=cosign", + cmdName: "pull", + args: []string{"--verify=cosign", "test:tag"}, + wantErr: nil, + mockSvc: func( + t *testing.T, + lcc *mocks.LimaCmdCreator, + ncsd *mocks.NerdctlCommandSystemDeps, + logger *mocks.Logger, + ctrl *gomock.Controller, + fs afero.Fs, + ) { + getVMStatusC := mocks.NewCommand(ctrl) + lcc.EXPECT().CreateWithoutStdio("ls", "-f", "{{.Status}}", limaInstanceName).Return(getVMStatusC) + getVMStatusC.EXPECT().Output().Return([]byte("Running"), nil) + logger.EXPECT().Debugf("Status of virtual machine: %s", "Running") + ncsd.EXPECT().LookupEnv("COSIGN_PASSWORD").Return("test", true) + c := mocks.NewCommand(ctrl) + lcc.EXPECT().Create("shell", limaInstanceName, "sudo", "-E", "COSIGN_PASSWORD=test", nerdctlCmdName, + "pull", "--verify=cosign", "test:tag").Return(c) + c.EXPECT().Run() + }, + }, + { + name: "with COSIGN_PASSWORD env var without cosign arg", + cmdName: "pull", + args: []string{"test:tag"}, + wantErr: nil, + mockSvc: func( + t *testing.T, + lcc *mocks.LimaCmdCreator, + ncsd *mocks.NerdctlCommandSystemDeps, + logger *mocks.Logger, + ctrl *gomock.Controller, + fs afero.Fs, + ) { + getVMStatusC := mocks.NewCommand(ctrl) + lcc.EXPECT().CreateWithoutStdio("ls", "-f", "{{.Status}}", limaInstanceName).Return(getVMStatusC) + getVMStatusC.EXPECT().Output().Return([]byte("Running"), nil) + logger.EXPECT().Debugf("Status of virtual machine: %s", "Running") + ncsd.EXPECT().LookupEnv("COSIGN_PASSWORD").Return("test", true) + c := mocks.NewCommand(ctrl) + lcc.EXPECT().Create("shell", limaInstanceName, "sudo", "-E", "COSIGN_PASSWORD=test", + nerdctlCmdName, "pull", "test:tag").Return(c) + c.EXPECT().Run() + }, + }, } for _, tc := range testCases { diff --git a/e2e/container/container_test.go b/e2e/container/container_test.go index db4f463ef..297ec0113 100644 --- a/e2e/container/container_test.go +++ b/e2e/container/container_test.go @@ -79,6 +79,7 @@ func TestContainer(t *testing.T) { tests.NetworkInspect(o) tests.NetworkLs(o) tests.NetworkRm(o) + testCosign(o) }) gomega.RegisterFailHandler(ginkgo.Fail) diff --git a/e2e/container/cosign_data/test-1.key b/e2e/container/cosign_data/test-1.key new file mode 100644 index 000000000..118e1fe95 --- /dev/null +++ b/e2e/container/cosign_data/test-1.key @@ -0,0 +1,11 @@ +-----BEGIN ENCRYPTED COSIGN PRIVATE KEY----- +eyJrZGYiOnsibmFtZSI6InNjcnlwdCIsInBhcmFtcyI6eyJOIjozMjc2OCwiciI6 +OCwicCI6MX0sInNhbHQiOiIvYW9saHRuZEZTSHZsQjBZSnBTOVI1VlcyOE5HUmox +VkJNL2VDZWlvVEV3PSJ9LCJjaXBoZXIiOnsibmFtZSI6Im5hY2wvc2VjcmV0Ym94 +Iiwibm9uY2UiOiJGRGpKU1BTdnN4WmQ0N2orRlgvUjlPbVB0WlpkTVh4dyJ9LCJj +aXBoZXJ0ZXh0IjoibzlCOXJJbmZPNXZaeE9PMFBSdFdjYlNUQmxibXA5OVVWTnEv +ZFhJN0hzd09yZFpVeTA1MmdUT3AyVkFsSjk2aTNFZitiY095QlU1MWt1UDd2R2gy +U1ljU2VkbWQvejEzM3owNUovZytjUll3bHRuNkowOTgwZ0xUR1NKdWxobFNIYWpC +Q25LS1RmY2tIb0dUU0dsZkU1aFk1UFdyRGlQTmc3VVA4bk1lc2JCWlRPMnFjaUdE +bTI0a21ON1RIOEljRlJ4T3Y1NkFNWm1tTUE9PSJ9 +-----END ENCRYPTED COSIGN PRIVATE KEY----- diff --git a/e2e/container/cosign_data/test-1.pub b/e2e/container/cosign_data/test-1.pub new file mode 100644 index 000000000..598bfa34c --- /dev/null +++ b/e2e/container/cosign_data/test-1.pub @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEfkODzHTFabSz0T+X758IqIB6pi3u +Km4JQCcEDFv94s6J4msvNOhmiAv3PQ/b9dutQ7QODWJAdm3cp6CMd87e1w== +-----END PUBLIC KEY----- diff --git a/e2e/container/cosign_data/test-2.key b/e2e/container/cosign_data/test-2.key new file mode 100644 index 000000000..e4e97c381 --- /dev/null +++ b/e2e/container/cosign_data/test-2.key @@ -0,0 +1,11 @@ +-----BEGIN ENCRYPTED COSIGN PRIVATE KEY----- +eyJrZGYiOnsibmFtZSI6InNjcnlwdCIsInBhcmFtcyI6eyJOIjozMjc2OCwiciI6 +OCwicCI6MX0sInNhbHQiOiJiYlVrSzkzdmY2dEhIM1czNTJ1UWM2ajNidzduUjdW +cTdReHJaRVlJYXM4PSJ9LCJjaXBoZXIiOnsibmFtZSI6Im5hY2wvc2VjcmV0Ym94 +Iiwibm9uY2UiOiJBWlhuSThncGhjbzdFdDBVOGhzKy91Tk5OdFpyTWNBOSJ9LCJj +aXBoZXJ0ZXh0IjoiaVJsUG9IRlJnQmJTamc2NnhvTTM4dm0vNExwelJXeUlKZi8x +dFIraEJ3dHdRMTQwZjBsQlpHdHRRMXZYcEE4UktHK09vTnNUcFNUSGh6R2phd3VN +ZXNzaVdsWkxHVTVjSTU5UVZ4TW40bGI4ME5iNWF2NlA5ZjVYT2x2aHhXbnMzUnpt +R091L0hCOHd1ZnBUUnBlQlZNLzZkZmFyV05ZbE92VzRYaWVvZXNEQ0hOV3JWbzFJ +WWdCbysxTEFYbzdYWkQ4cXNVWFdJd3ZONkE9PSJ9 +-----END ENCRYPTED COSIGN PRIVATE KEY----- diff --git a/e2e/container/cosign_data/test-2.pub b/e2e/container/cosign_data/test-2.pub new file mode 100644 index 000000000..49248d56c --- /dev/null +++ b/e2e/container/cosign_data/test-2.pub @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAERyYVqiPX1IGvTiAuJCZIOfPllOm/ +HTi7DaswFLwNXVOOC7FLP3L9YzQ0q24bFBqkSQqgWeycKsOOPCbF0nMLHQ== +-----END PUBLIC KEY----- diff --git a/e2e/container/cosign_test.go b/e2e/container/cosign_test.go new file mode 100644 index 000000000..c23380b0a --- /dev/null +++ b/e2e/container/cosign_test.go @@ -0,0 +1,85 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package container + +import ( + "fmt" + "os" + "path/filepath" + + "github.com/onsi/ginkgo/v2" + "github.com/onsi/gomega" + "github.com/runfinch/common-tests/command" + "github.com/runfinch/common-tests/ffs" + "github.com/runfinch/common-tests/fnet" + "github.com/runfinch/common-tests/option" +) + +const ( + alpineImage = "public.ecr.aws/docker/library/alpine:latest" + registryImage = "public.ecr.aws/docker/library/registry:latest" +) + +var testCosign = func(o *option.Option) { + ginkgo.Describe("Cosign", func() { + var buildContext string + var port int + var registry string + var tag string + ginkgo.BeforeEach(func() { + command.RemoveAll(o) + buildContext = ffs.CreateBuildContext(fmt.Sprintf(`FROM %s + CMD ["echo", "bar"] + `, alpineImage)) + ginkgo.DeferCleanup(os.RemoveAll, buildContext) + filename := "htpasswd" + // The htpasswd is generated by + // ` run --entrypoint htpasswd public.ecr.aws/docker/library/httpd:2 -Bbn testUser testPassword`. + // We don't want to generate it on the fly because: + // 1. Pulling the httpd image can take a long time, sometimes even more 10 seconds. + // 2. It's unlikely that we will have to update this in the future. + // 3. It's not the thing we want to validate by the functional tests. We only want the output produced by it. + //nolint:gosec // This password is only used for testing purpose. + htpasswd := "testUser:$2y$05$wE0sj3r9O9K9q7R0MXcfPuIerl/06L1IsxXkCuUr3QZ8lHWwicIdS" + htpasswdDir := filepath.Dir(ffs.CreateTempFile(filename, htpasswd)) + ginkgo.DeferCleanup(os.RemoveAll, htpasswdDir) + port = fnet.GetFreePort() + command.Run(o, "run", + "-dp", fmt.Sprintf("%d:5000", port), + "--name", "registry", + "-v", fmt.Sprintf("%s:/auth", htpasswdDir), + "-e", "REGISTRY_AUTH=htpasswd", + "-e", "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm", + "-e", fmt.Sprintf("REGISTRY_AUTH_HTPASSWD_PATH=/auth/%s", filename), + registryImage) + registry = fmt.Sprintf(`localhost:%d`, port) + tag = fmt.Sprintf(`%s/test-login:tag`, registry) + }) + + ginkgo.AfterEach(func() { + command.RemoveAll(o) + }) + + ginkgo.It("should succeed to verify the signature of the image only when it is signed with the matched key", func() { + command.Run(o, "build", "-t", tag, buildContext) + gomega.Expect(os.Setenv("COSIGN_PASSWORD", "test-1")).To(gomega.Succeed()) + command.Run(o, "login", registry, "-u", "testUser", "-p", "testPassword") + ginkgo.DeferCleanup(func() { + command.Run(o, "logout", registry) + }) + command.Run(o, "push", "--sign=cosign", "--cosign-key=./cosign_data/test-1.key", tag) + command.Run(o, "pull", "--verify=cosign", "--cosign-key=./cosign_data/test-1.pub", tag) + command.Run(o, "run", "-d", "--verify=cosign", "--cosign-key=./cosign_data/test-1.pub", tag) + + gomega.Expect(command.RunWithoutSuccessfulExit(o, "pull", "--verify=cosign", "--cosign-key=./cosign_data/test-2.pub", + tag).Err.Contents()).Should(gomega.ContainSubstring("no matching signatures")) + gomega.Expect(command.RunWithoutSuccessfulExit(o, "run", "-d", "--verify=cosign", "--cosign-key=./cosign_data/test-2.pub", + tag).Err.Contents()).Should(gomega.ContainSubstring("no matching signatures")) + gomega.Expect(command.RunWithoutSuccessfulExit(o, "pull", "--verify=cosign", "--cosign-key=./cosign_data/test-2.pub", + alpineImage).Err.Contents()).Should(gomega.ContainSubstring("no matching signatures")) + gomega.Expect(command.RunWithoutSuccessfulExit(o, "run", "-d", "--verify=cosign", "--cosign-key=./cosign_data/test-2.pub", + alpineImage).Err.Contents()).Should(gomega.ContainSubstring("no matching signatures")) + }) + }) +}