diff --git a/cmd/notation/cert/cleanupTest.go b/cmd/notation/cert/cleanupTest.go new file mode 100644 index 000000000..5aafc5fc1 --- /dev/null +++ b/cmd/notation/cert/cleanupTest.go @@ -0,0 +1,132 @@ +// Copyright The Notary Project 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 cert + +import ( + "errors" + "fmt" + "io/fs" + "os" + "path/filepath" + + "github.com/notaryproject/notation-go/config" + "github.com/notaryproject/notation-go/dir" + "github.com/notaryproject/notation/v2/cmd/notation/internal/display" + "github.com/notaryproject/notation/v2/cmd/notation/internal/truststore" + "github.com/spf13/cobra" +) + +type certCleanupTestOpts struct { + name string + confirmed bool +} + +func certCleanupTestCommand(opts *certCleanupTestOpts) *cobra.Command { + if opts == nil { + opts = &certCleanupTestOpts{} + } + command := &cobra.Command{ + Use: "cleanup-test [flags] ", + Short: `Clean up a test RSA key and its corresponding certificate that were generated using the "generate-test" command.`, + Args: func(cmd *cobra.Command, args []string) error { + if len(args) == 0 { + return errors.New("missing certificate common name") + } + if !truststore.IsValidFileName(args[0]) { + return errors.New("certificate common name must follow [a-zA-Z0-9_.-]+ format") + } + opts.name = args[0] + return nil + }, + Long: `Clean up a test RSA key and its corresponding certificate that were generated using the "generate-test" command. + +Example - Clean up a test key and corresponding certificate named "wabbit-networks.io": + notation cert cleanup-test wabbit-networks.io +`, + RunE: func(cmd *cobra.Command, args []string) error { + return cleanupTestCert(opts) + }, + } + command.Flags().BoolVarP(&opts.confirmed, "yes", "y", false, "do not prompt for confirmation") + return command +} + +func cleanupTestCert(opts *certCleanupTestOpts) error { + name := opts.name + relativeKeyPath, relativeCertPath := dir.LocalKeyPath(name) + certPath, _ := dir.ConfigFS().SysPath(relativeCertPath) // err is always nil + certFileName := filepath.Base(certPath) + keyPath, _ := dir.ConfigFS().SysPath(relativeKeyPath) // err is always nil + prompt := fmt.Sprintf(`The test key %s and its corresponding certificate will be cleaned up with the following changes: +- Delete certificate %s.crt from trust store %s of type ca +- Remove key %s from the key list +- Delete key file: %s +- Delete certificate file: %s + +Are you sure you want to continue?`, name, name, name, name, keyPath, certPath) + confirmed, err := display.AskForConfirmation(os.Stdin, prompt, opts.confirmed) + if err != nil { + return err + } + if !confirmed { + return nil + } + + // 1. remove from trust store + err = truststore.DeleteCert("ca", name, certFileName, true) + if err != nil { + if !errors.Is(err, fs.ErrNotExist) { + return fmt.Errorf("failed to delete certificate %s from trust store %s of type ca: %w", certFileName, name, err) + } + fmt.Printf("Certificate %s does not exist in trust store %s of type ca\n", certFileName, name) + } + + // 2. remove key from signingkeys.json config + exec := func(s *config.SigningKeys) error { + _, err := s.Remove(name) + return err + } + err = config.LoadExecSaveSigningKeys(exec) + if err != nil { + var keyNotFoundError config.KeyNotFoundError + if !errors.As(err, &keyNotFoundError) { + return fmt.Errorf("failed to remove key %s from the key list: %w", name, err) + } + fmt.Printf("Key %s does not exist in the key list\n", name) + } else { + fmt.Printf("Successfully removed key %s from the key list\n", name) + } + + // 3. delete key and certificate files from LocalKeyPath + err = os.Remove(keyPath) + if err != nil { + if !errors.Is(err, fs.ErrNotExist) { + return fmt.Errorf("failed to delete key file %s: %w", keyPath, err) + } + fmt.Printf("Key file %s does not exist\n", keyPath) + } else { + fmt.Printf("Successfully deleted key file: %s\n", keyPath) + } + err = os.Remove(certPath) + if err != nil { + if !errors.Is(err, fs.ErrNotExist) { + return fmt.Errorf("failed to delete certificate file %s: %w", certPath, err) + } + fmt.Printf("Certificate file %s does not exist\n", certPath) + } else { + fmt.Printf("Successfully deleted certificate file: %s\n", certPath) + } + fmt.Println("Cleanup completed successfully") + return nil +} diff --git a/cmd/notation/cert/cleanup_test.go b/cmd/notation/cert/cleanup_test.go new file mode 100644 index 000000000..69394ccd8 --- /dev/null +++ b/cmd/notation/cert/cleanup_test.go @@ -0,0 +1,47 @@ +// Copyright The Notary Project 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 cert + +import ( + "reflect" + "testing" +) + +func TestCertCleanupCommand(t *testing.T) { + opts := &certCleanupTestOpts{} + cmd := certCleanupTestCommand(opts) + expected := &certCleanupTestOpts{ + name: "name", + } + if err := cmd.ParseFlags([]string{ + "name"}); err != nil { + t.Fatalf("Parse Flag failed: %v", err) + } + if err := cmd.Args(cmd, cmd.Flags().Args()); err != nil { + t.Fatalf("Parse Args failed: %v", err) + } + if !reflect.DeepEqual(*expected, *opts) { + t.Fatalf("Expect cert generate-test opts: %v, got: %v", expected, opts) + } +} + +func TestCertCleanupTestCommand_MissingArgs(t *testing.T) { + cmd := certCleanupTestCommand(nil) + if err := cmd.ParseFlags(nil); err != nil { + t.Fatalf("Parse Flag failed: %v", err) + } + if err := cmd.Args(cmd, cmd.Flags().Args()); err == nil { + t.Fatal("Parse Args expected error, but ok") + } +} diff --git a/cmd/notation/cert/cmd.go b/cmd/notation/cert/cmd.go index 8fe3d6f0e..c50500deb 100644 --- a/cmd/notation/cert/cmd.go +++ b/cmd/notation/cert/cmd.go @@ -11,6 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +// Package cert provides implementation of the `notation certificate` command package cert import "github.com/spf13/cobra" @@ -29,6 +30,7 @@ func Cmd() *cobra.Command { certShowCommand(nil), certDeleteCommand(nil), certGenerateTestCommand(nil), + certCleanupTestCommand(nil), ) return command diff --git a/cmd/notation/cert/generateTest.go b/cmd/notation/cert/generateTest.go index 45b320548..72c78a54d 100644 --- a/cmd/notation/cert/generateTest.go +++ b/cmd/notation/cert/generateTest.go @@ -138,7 +138,7 @@ func generateTestCert(opts *certGenerateTestOpts) error { // write out fmt.Printf("%s: added to the key list\n", name) if opts.isDefault { - fmt.Printf("%s: mark as default signing key\n", name) + fmt.Printf("%s: marked as default signing key\n", name) } return nil } diff --git a/cmd/notation/internal/sign/sign_test.go b/cmd/notation/internal/sign/sign_test.go index 24a2a45c1..1f4bb3809 100644 --- a/cmd/notation/internal/sign/sign_test.go +++ b/cmd/notation/internal/sign/sign_test.go @@ -177,7 +177,7 @@ func TestGetSignerFailed(t *testing.T) { t.Run("key not found", func(t *testing.T) { dir.UserConfigDir = "./testdata/valid_signingkeys" - expectedErrMsg := `signing key not found` + expectedErrMsg := `signing key test2 not found` opts := &flag.SignerFlagOpts{ Key: "test2", } diff --git a/cmd/notation/internal/truststore/truststore.go b/cmd/notation/internal/truststore/truststore.go index 2d4e07323..73452d702 100644 --- a/cmd/notation/internal/truststore/truststore.go +++ b/cmd/notation/internal/truststore/truststore.go @@ -190,7 +190,7 @@ func DeleteCert(storeType, namedStore, cert string, confirmed bool) error { return err } // write out on success - fmt.Printf("Successfully deleted %s\n", cert) + fmt.Printf("Successfully deleted %s from trust store %s of type %s\n", cert, namedStore, storeType) return nil } diff --git a/go.mod b/go.mod index 93a86d454..4a85656c8 100644 --- a/go.mod +++ b/go.mod @@ -3,10 +3,10 @@ module github.com/notaryproject/notation/v2 go 1.24.0 require ( - github.com/notaryproject/notation-core-go v1.2.0 - github.com/notaryproject/notation-go v1.2.0-beta.1.0.20250310060348-fdcf9cc47604 + github.com/notaryproject/notation-core-go v1.2.1-0.20250304022306-ea37e4e6c39a + github.com/notaryproject/notation-go v1.2.0-beta.1.0.20250324062555-fcc1ce32f892 github.com/notaryproject/notation-plugin-framework-go v1.0.0 - github.com/notaryproject/tspclient-go v1.0.0 + github.com/notaryproject/tspclient-go v1.0.1-0.20250306063739-4f55b14d9f01 github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.1.1 github.com/sirupsen/logrus v1.9.3 diff --git a/go.sum b/go.sum index 94954ee43..b609251c2 100644 --- a/go.sum +++ b/go.sum @@ -36,14 +36,14 @@ github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh6 github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= -github.com/notaryproject/notation-core-go v1.2.0 h1:WElMG9X0YXJhBd0A4VOxLNalTLrTjvqtIAj7JHr5X08= -github.com/notaryproject/notation-core-go v1.2.0/go.mod h1:+y3L1dOs2/ZwJIU5Imo7BBvZ/M3CFjXkydGGdK09EtA= -github.com/notaryproject/notation-go v1.2.0-beta.1.0.20250310060348-fdcf9cc47604 h1:uw65pHgN+NXAqHssmlRJUkcl515AQgMIOdC6tbBHHXE= -github.com/notaryproject/notation-go v1.2.0-beta.1.0.20250310060348-fdcf9cc47604/go.mod h1:NXYZyzIawUSyv+C0Gs8bBYJ1q8a1gy78GEss8fPNZmY= +github.com/notaryproject/notation-core-go v1.2.1-0.20250304022306-ea37e4e6c39a h1:xagHqXDQKyG4hYCzf2yrMxNGdUf1FELEYojY7dZEgP0= +github.com/notaryproject/notation-core-go v1.2.1-0.20250304022306-ea37e4e6c39a/go.mod h1:26/FuY/XSwyGiafPFDOeUJBz+sPsWDpK+Ei4TWtcmTc= +github.com/notaryproject/notation-go v1.2.0-beta.1.0.20250324062555-fcc1ce32f892 h1:2bD9p585QwuFQry03o19yHZzeBJOCSuol6LR64KIfto= +github.com/notaryproject/notation-go v1.2.0-beta.1.0.20250324062555-fcc1ce32f892/go.mod h1:NXYZyzIawUSyv+C0Gs8bBYJ1q8a1gy78GEss8fPNZmY= github.com/notaryproject/notation-plugin-framework-go v1.0.0 h1:6Qzr7DGXoCgXEQN+1gTZWuJAZvxh3p8Lryjn5FaLzi4= github.com/notaryproject/notation-plugin-framework-go v1.0.0/go.mod h1:RqWSrTOtEASCrGOEffq0n8pSg2KOgKYiWqFWczRSics= -github.com/notaryproject/tspclient-go v1.0.0 h1:AwQ4x0gX8IHnyiZB1tggpn5NFqHpTEm1SDX8YNv4Dg4= -github.com/notaryproject/tspclient-go v1.0.0/go.mod h1:LGyA/6Kwd2FlM0uk8Vc5il3j0CddbWSHBj/4kxQDbjs= +github.com/notaryproject/tspclient-go v1.0.1-0.20250306063739-4f55b14d9f01 h1:Ay72jBeHKqBFk6TbJWywfwzefN3Ei7Py2OzCiWU/7nk= +github.com/notaryproject/tspclient-go v1.0.1-0.20250306063739-4f55b14d9f01/go.mod h1:3ZJPmpmdwufY23BkS+JPNktOVb5DXJ8Ik5zxvN7h670= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= diff --git a/specs/cmd/certificate.md b/specs/cmd/certificate.md index 9765f48c2..65eb129cc 100644 --- a/specs/cmd/certificate.md +++ b/specs/cmd/certificate.md @@ -148,7 +148,7 @@ Usage: notation certificate cleanup-test [flags] Flags: - -h, --help help for generate-test + -h, --help help for cleanup-test -y, --yes do not prompt for confirmation ``` diff --git a/test/e2e/go.mod b/test/e2e/go.mod index 584f4ac3a..6791a35f7 100644 --- a/test/e2e/go.mod +++ b/test/e2e/go.mod @@ -4,7 +4,7 @@ go 1.24.0 require ( github.com/notaryproject/notation-core-go v1.2.1-0.20250304022306-ea37e4e6c39a - github.com/notaryproject/notation-go v1.2.0-beta.1.0.20250310060348-fdcf9cc47604 + github.com/notaryproject/notation-go v1.2.0-beta.1.0.20250324062555-fcc1ce32f892 github.com/onsi/ginkgo/v2 v2.23.3 github.com/onsi/gomega v1.36.3 github.com/opencontainers/image-spec v1.1.1 @@ -17,11 +17,13 @@ require ( github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect + github.com/notaryproject/notation-plugin-framework-go v1.0.0 // indirect github.com/notaryproject/tspclient-go v1.0.1-0.20250306063739-4f55b14d9f01 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/veraison/go-cose v1.3.0 // indirect github.com/x448/float16 v0.8.4 // indirect golang.org/x/crypto v0.36.0 // indirect + golang.org/x/mod v0.23.0 // indirect golang.org/x/net v0.37.0 // indirect golang.org/x/sync v0.12.0 // indirect golang.org/x/sys v0.31.0 // indirect diff --git a/test/e2e/go.sum b/test/e2e/go.sum index 2082429f8..c9c1c2221 100644 --- a/test/e2e/go.sum +++ b/test/e2e/go.sum @@ -12,8 +12,10 @@ github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/Z github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/notaryproject/notation-core-go v1.2.1-0.20250304022306-ea37e4e6c39a h1:xagHqXDQKyG4hYCzf2yrMxNGdUf1FELEYojY7dZEgP0= github.com/notaryproject/notation-core-go v1.2.1-0.20250304022306-ea37e4e6c39a/go.mod h1:26/FuY/XSwyGiafPFDOeUJBz+sPsWDpK+Ei4TWtcmTc= -github.com/notaryproject/notation-go v1.2.0-beta.1.0.20250310060348-fdcf9cc47604 h1:uw65pHgN+NXAqHssmlRJUkcl515AQgMIOdC6tbBHHXE= -github.com/notaryproject/notation-go v1.2.0-beta.1.0.20250310060348-fdcf9cc47604/go.mod h1:NXYZyzIawUSyv+C0Gs8bBYJ1q8a1gy78GEss8fPNZmY= +github.com/notaryproject/notation-go v1.2.0-beta.1.0.20250324062555-fcc1ce32f892 h1:2bD9p585QwuFQry03o19yHZzeBJOCSuol6LR64KIfto= +github.com/notaryproject/notation-go v1.2.0-beta.1.0.20250324062555-fcc1ce32f892/go.mod h1:NXYZyzIawUSyv+C0Gs8bBYJ1q8a1gy78GEss8fPNZmY= +github.com/notaryproject/notation-plugin-framework-go v1.0.0 h1:6Qzr7DGXoCgXEQN+1gTZWuJAZvxh3p8Lryjn5FaLzi4= +github.com/notaryproject/notation-plugin-framework-go v1.0.0/go.mod h1:RqWSrTOtEASCrGOEffq0n8pSg2KOgKYiWqFWczRSics= github.com/notaryproject/tspclient-go v1.0.1-0.20250306063739-4f55b14d9f01 h1:Ay72jBeHKqBFk6TbJWywfwzefN3Ei7Py2OzCiWU/7nk= github.com/notaryproject/tspclient-go v1.0.1-0.20250306063739-4f55b14d9f01/go.mod h1:3ZJPmpmdwufY23BkS+JPNktOVb5DXJ8Ik5zxvN7h670= github.com/onsi/ginkgo/v2 v2.23.3 h1:edHxnszytJ4lD9D5Jjc4tiDkPBZ3siDeJJkUZJJVkp0= @@ -34,6 +36,8 @@ github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= +golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c= golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= diff --git a/test/e2e/plugin/go.mod b/test/e2e/plugin/go.mod index 9114003e0..ac052eb71 100644 --- a/test/e2e/plugin/go.mod +++ b/test/e2e/plugin/go.mod @@ -5,7 +5,7 @@ go 1.24.0 require ( github.com/golang-jwt/jwt v3.2.2+incompatible github.com/notaryproject/notation-core-go v1.2.1-0.20250304022306-ea37e4e6c39a - github.com/notaryproject/notation-go v1.2.0-beta.1.0.20250310060348-fdcf9cc47604 + github.com/notaryproject/notation-go v1.2.0-beta.1.0.20250324062555-fcc1ce32f892 github.com/notaryproject/notation-plugin-framework-go v1.0.0 github.com/spf13/cobra v1.9.1 ) diff --git a/test/e2e/plugin/go.sum b/test/e2e/plugin/go.sum index 5e158f990..902107360 100644 --- a/test/e2e/plugin/go.sum +++ b/test/e2e/plugin/go.sum @@ -40,8 +40,8 @@ github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZ github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= github.com/notaryproject/notation-core-go v1.2.1-0.20250304022306-ea37e4e6c39a h1:xagHqXDQKyG4hYCzf2yrMxNGdUf1FELEYojY7dZEgP0= github.com/notaryproject/notation-core-go v1.2.1-0.20250304022306-ea37e4e6c39a/go.mod h1:26/FuY/XSwyGiafPFDOeUJBz+sPsWDpK+Ei4TWtcmTc= -github.com/notaryproject/notation-go v1.2.0-beta.1.0.20250310060348-fdcf9cc47604 h1:uw65pHgN+NXAqHssmlRJUkcl515AQgMIOdC6tbBHHXE= -github.com/notaryproject/notation-go v1.2.0-beta.1.0.20250310060348-fdcf9cc47604/go.mod h1:NXYZyzIawUSyv+C0Gs8bBYJ1q8a1gy78GEss8fPNZmY= +github.com/notaryproject/notation-go v1.2.0-beta.1.0.20250324062555-fcc1ce32f892 h1:2bD9p585QwuFQry03o19yHZzeBJOCSuol6LR64KIfto= +github.com/notaryproject/notation-go v1.2.0-beta.1.0.20250324062555-fcc1ce32f892/go.mod h1:NXYZyzIawUSyv+C0Gs8bBYJ1q8a1gy78GEss8fPNZmY= github.com/notaryproject/notation-plugin-framework-go v1.0.0 h1:6Qzr7DGXoCgXEQN+1gTZWuJAZvxh3p8Lryjn5FaLzi4= github.com/notaryproject/notation-plugin-framework-go v1.0.0/go.mod h1:RqWSrTOtEASCrGOEffq0n8pSg2KOgKYiWqFWczRSics= github.com/notaryproject/tspclient-go v1.0.1-0.20250306063739-4f55b14d9f01 h1:Ay72jBeHKqBFk6TbJWywfwzefN3Ei7Py2OzCiWU/7nk= diff --git a/test/e2e/suite/command/blob/sign.go b/test/e2e/suite/command/blob/sign.go index 19cd74bd0..a1efc4f0b 100644 --- a/test/e2e/suite/command/blob/sign.go +++ b/test/e2e/suite/command/blob/sign.go @@ -120,7 +120,7 @@ var _ = Describe("notation blob sign", func() { It("with invalid key", func() { HostWithBlob(BaseOptions(), func(notation *utils.ExecOpts, blobPath string, vhost *utils.VirtualHost) { notation.ExpectFailure().Exec("blob", "sign", "--key", "invalid", blobPath). - MatchErrKeyWords("signing key not found") + MatchErrKeyWords("signing key invalid not found") }) }) diff --git a/test/e2e/suite/command/cert.go b/test/e2e/suite/command/cert.go index 418a8a6ca..ee5ea8f4f 100644 --- a/test/e2e/suite/command/cert.go +++ b/test/e2e/suite/command/cert.go @@ -14,10 +14,13 @@ package command import ( + "fmt" + "os" + "path/filepath" + . "github.com/notaryproject/notation/test/e2e/internal/notation" "github.com/notaryproject/notation/test/e2e/internal/utils" - // . "github.com/notaryproject/notation/test/e2e/suite/common" . "github.com/onsi/ginkgo/v2" ) @@ -44,7 +47,7 @@ var _ = Describe("notation cert", func() { Host(BaseOptions(), func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { notation.Exec("cert", "delete", "--type", "ca", "--store", "e2e", "e2e.crt", "-y"). MatchKeyWords( - "Successfully deleted e2e.crt", + "Successfully deleted e2e.crt from trust store e2e of type ca", ) }) }) @@ -105,4 +108,232 @@ var _ = Describe("notation cert", func() { ) }) }) + + It("cleanup test", func() { + Host(BaseOptions(), func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { + notation.Exec("cert", "generate-test", "e2e-test"). + MatchKeyWords( + "generating RSA Key with 2048 bits", + "generated certificate expiring on", + "wrote key:", "e2e-test.key", + "wrote certificate:", "e2e-test.crt", + "Successfully added e2e-test.crt to named store e2e-test of type ca", + "e2e-test: added to the key list", + ) + + notation.Exec("cert", "cleanup-test", "e2e-test", "-y"). + MatchKeyWords( + "Successfully deleted e2e-test.crt from trust store e2e-test of type ca", + "Successfully removed key e2e-test from the key list", + "Successfully deleted key file:", "e2e-test.key", + "Successfully deleted certificate file:", "e2e-test.crt", + "Cleanup completed successfully", + ) + }) + }) + + It("cleanup test with key set as default", func() { + Host(BaseOptions(), func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { + notation.Exec("cert", "generate-test", "e2e-test", "--default"). + MatchKeyWords( + "generating RSA Key with 2048 bits", + "generated certificate expiring on", + "wrote key:", "e2e-test.key", + "wrote certificate:", "e2e-test.crt", + "Successfully added e2e-test.crt to named store e2e-test of type ca", + "e2e-test: added to the key list", + "e2e-test: marked as default signing key", + ) + + notation.Exec("cert", "cleanup-test", "e2e-test", "-y"). + MatchKeyWords( + "Successfully deleted e2e-test.crt from trust store e2e-test of type ca", + "Successfully removed key e2e-test from the key list", + "Successfully deleted key file:", "e2e-test.key", + "Successfully deleted certificate file:", "e2e-test.crt", + "Cleanup completed successfully", + ) + }) + }) + + It("cleanup test with same name more than one time", func() { + Host(BaseOptions(), func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { + notation.Exec("cert", "generate-test", "e2e-test"). + MatchKeyWords( + "generating RSA Key with 2048 bits", + "generated certificate expiring on", + "wrote key:", "e2e-test.key", + "wrote certificate:", "e2e-test.crt", + "Successfully added e2e-test.crt to named store e2e-test of type ca", + "e2e-test: added to the key list", + ) + + notation.Exec("cert", "cleanup-test", "e2e-test", "-y"). + MatchKeyWords( + "Successfully deleted e2e-test.crt from trust store e2e-test of type ca", + "Successfully removed key e2e-test from the key list", + "Successfully deleted key file:", "e2e-test.key", + "Successfully deleted certificate file:", "e2e-test.crt", + "Cleanup completed successfully", + ) + + notation.Exec("cert", "generate-test", "e2e-test"). + MatchKeyWords( + "generating RSA Key with 2048 bits", + "generated certificate expiring on", + "wrote key:", "e2e-test.key", + "wrote certificate:", "e2e-test.crt", + "Successfully added e2e-test.crt to named store e2e-test of type ca", + "e2e-test: added to the key list", + ) + + notation.Exec("cert", "cleanup-test", "e2e-test", "-y"). + MatchKeyWords( + "Successfully deleted e2e-test.crt from trust store e2e-test of type ca", + "Successfully removed key e2e-test from the key list", + "Successfully deleted key file:", "e2e-test.key", + "Successfully deleted certificate file:", "e2e-test.crt", + "Cleanup completed successfully", + ) + }) + }) + + It("cleanup test with key never generated", func() { + Host(BaseOptions(), func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { + localKeyPath := vhost.AbsolutePath(NotationDirName, LocalKeysDirName, "e2e-test.key") + localCertPath := vhost.AbsolutePath(NotationDirName, LocalKeysDirName, "e2e-test.crt") + notation.Exec("cert", "cleanup-test", "e2e-test", "-y"). + MatchKeyWords( + "Certificate e2e-test.crt does not exist in trust store e2e-test of type ca", + "Key e2e-test does not exist in the key list", + fmt.Sprintf("Key file %s does not exist", localKeyPath), + fmt.Sprintf("Certificate file %s does not exist", localCertPath), + "Cleanup completed successfully", + ) + }) + }) + + It("cleanup test with certificate not in trust store", func() { + Host(BaseOptions(), func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { + notation.Exec("cert", "generate-test", "e2e-test") + + notation.Exec("cert", "delete", "--type", "ca", "--store", "e2e-test", "e2e-test.crt", "-y"). + MatchKeyWords( + "Successfully deleted e2e-test.crt from trust store e2e-test of type ca", + ) + + notation.Exec("cert", "cleanup-test", "e2e-test", "-y"). + MatchKeyWords( + "Certificate e2e-test.crt does not exist in trust store e2e-test of type ca", + "Successfully removed key e2e-test from the key list", + "Successfully deleted key file:", "e2e-test.key", + "Successfully deleted certificate file:", "e2e-test.crt", + "Cleanup completed successfully", + ) + }) + }) + + It("cleanup test without local key file", func() { + Host(BaseOptions(), func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { + notation.Exec("cert", "generate-test", "e2e-test") + + localKeyPath := vhost.AbsolutePath(NotationDirName, LocalKeysDirName, "e2e-test.key") + if err := os.Remove(localKeyPath); err != nil { + Fail(err.Error()) + } + notation.Exec("cert", "cleanup-test", "e2e-test", "-y"). + MatchKeyWords( + "Successfully deleted e2e-test.crt from trust store e2e-test of type ca", + "Successfully removed key e2e-test from the key list", + fmt.Sprintf("Key file %s does not exist", localKeyPath), + "Successfully deleted certificate file:", "e2e-test.crt", + "Cleanup completed successfully", + ) + }) + }) + + It("cleanup test without local certificate file", func() { + Host(BaseOptions(), func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { + notation.Exec("cert", "generate-test", "e2e-test") + + localCertPath := vhost.AbsolutePath(NotationDirName, LocalKeysDirName, "e2e-test.crt") + if err := os.Remove(localCertPath); err != nil { + Fail(err.Error()) + } + notation.Exec("cert", "cleanup-test", "e2e-test", "-y"). + MatchKeyWords( + "Successfully deleted e2e-test.crt from trust store e2e-test of type ca", + "Successfully removed key e2e-test from the key list", + "Successfully deleted key file:", "e2e-test.key", + fmt.Sprintf("Certificate file %s does not exist", localCertPath), + "Cleanup completed successfully", + ) + }) + }) + + It("cleanup test missing certificate common name", func() { + Host(BaseOptions(), func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { + notation.ExpectFailure().Exec("cert", "cleanup-test"). + MatchErrKeyWords( + "missing certificate common name", + ) + }) + }) + + It("cleanup test with empty certificate common name", func() { + Host(BaseOptions(), func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { + notation.ExpectFailure().Exec("cert", "cleanup-test", ""). + MatchErrKeyWords( + "certificate common name must follow [a-zA-Z0-9_.-]+ format", + ) + }) + }) + + It("cleanup test failed at deleting certificate from trust store", func() { + Host(BaseOptions(), func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { + notation.Exec("cert", "generate-test", "e2e-test") + + certPath := vhost.AbsolutePath(NotationDirName, TrustStoreDirName, "x509", TrustStoreTypeCA, "e2e-test") + os.Chmod(certPath, 0000) + defer os.Chmod(certPath, 0755) + + notation.ExpectFailure().Exec("cert", "cleanup-test", "e2e-test", "-y"). + MatchErrKeyWords( + "failed to delete certificate e2e-test.crt from trust store e2e-test of type ca", + "permission denied", + ) + }) + }) + + It("cleanup test failed at removing key from signingkeys.json", func() { + Host(BaseOptions(), func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { + notation.Exec("cert", "generate-test", "e2e-test") + + signingKeyPath := vhost.AbsolutePath(NotationDirName, SigningKeysFileName) + os.Chmod(signingKeyPath, 0000) + defer os.Chmod(signingKeyPath, 0600) + + notation.ExpectFailure().Exec("cert", "cleanup-test", "e2e-test", "-y"). + MatchErrKeyWords( + "failed to remove key e2e-test from the key list", + "permission denied", + ) + }) + }) + + It("cleanup test failed at deleting local key file", func() { + Host(BaseOptions(), func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { + notation.Exec("cert", "generate-test", "e2e-test") + + localKeysDir := vhost.AbsolutePath(NotationDirName, LocalKeysDirName) + os.Chmod(localKeysDir, 0000) + defer os.Chmod(localKeysDir, 0755) + + notation.ExpectFailure().Exec("cert", "cleanup-test", "e2e-test", "-y"). + MatchErrKeyWords( + fmt.Sprintf("failed to delete key file %s", filepath.Join(localKeysDir, "e2e-test.key")), + "permission denied", + ) + }) + }) }) diff --git a/test/e2e/suite/scenario/quickstart.go b/test/e2e/suite/scenario/quickstart.go index cec27a137..76347ea29 100644 --- a/test/e2e/suite/scenario/quickstart.go +++ b/test/e2e/suite/scenario/quickstart.go @@ -53,7 +53,7 @@ var _ = Describe("notation quickstart E2E test", Ordered, func() { MatchKeyWords( "Successfully added wabbit-networks.io.crt", "wabbit-networks.io: added to the key list", - "wabbit-networks.io: mark as default signing key") + "wabbit-networks.io: marked as default signing key") notation.Exec("key", "ls"). MatchKeyWords(