From e067e69d0d9881f5d369deed41240353ae3774e2 Mon Sep 17 00:00:00 2001 From: Junjie Gao Date: Tue, 24 Dec 2024 06:04:41 +0000 Subject: [PATCH 01/24] feat: add blob policy commands Signed-off-by: Junjie Gao --- cmd/notation/blob/cmd.go | 45 ++++ cmd/notation/blob/policy.go | 71 ++++++ cmd/notation/internal/policy/import.go | 91 ++++++++ cmd/notation/internal/policy/show.go | 86 ++++++++ cmd/notation/main.go | 2 + cmd/notation/policy/import.go | 52 +---- cmd/notation/policy/show.go | 45 +--- go.mod | 6 +- go.sum | 8 +- test/e2e/internal/notation/host.go | 10 + test/e2e/internal/notation/init.go | 15 +- test/e2e/run.sh | 2 +- test/e2e/suite/command/blob/blob_test.go | 26 +++ test/e2e/suite/command/blob/policy.go | 203 ++++++++++++++++++ .../trustpolicies/blob_trust_policy.json | 32 +++ 15 files changed, 588 insertions(+), 106 deletions(-) create mode 100644 cmd/notation/blob/cmd.go create mode 100644 cmd/notation/blob/policy.go create mode 100644 cmd/notation/internal/policy/import.go create mode 100644 cmd/notation/internal/policy/show.go create mode 100644 test/e2e/suite/command/blob/blob_test.go create mode 100644 test/e2e/suite/command/blob/policy.go create mode 100644 test/e2e/testdata/config/trustpolicies/blob_trust_policy.json diff --git a/cmd/notation/blob/cmd.go b/cmd/notation/blob/cmd.go new file mode 100644 index 000000000..6717bfab1 --- /dev/null +++ b/cmd/notation/blob/cmd.go @@ -0,0 +1,45 @@ +// 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 blob + +import "github.com/spf13/cobra" + +func Cmd() *cobra.Command { + command := &cobra.Command{ + Use: "blob [commnad]", + Short: "Sign, verify and inspect singatures associated with blobs", + Long: "Sign, inspect, and verify signatures and configure trust policies.", + } + + command.AddCommand( + policyCmd(), + ) + + return command +} + +func policyCmd() *cobra.Command { + command := &cobra.Command{ + Use: "policy [command]", + Short: "manage trust policy configuration for signed blobs", + Long: "Manage trust policy configuration for arbitrary blob signature verification.", + } + + command.AddCommand( + importCmd(), + showCmd(), + ) + + return command +} diff --git a/cmd/notation/blob/policy.go b/cmd/notation/blob/policy.go new file mode 100644 index 000000000..79ecc19b0 --- /dev/null +++ b/cmd/notation/blob/policy.go @@ -0,0 +1,71 @@ +// 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 blob + +import ( + "fmt" + + "github.com/notaryproject/notation/cmd/notation/internal/policy" + "github.com/spf13/cobra" +) + +type importOpts struct { + filePath string + force bool +} + +func importCmd() *cobra.Command { + var opts importOpts + command := &cobra.Command{ + Use: "import [flags] ", + Short: "import trust policy configuration from a JSON file", + Long: `Import blob trust policy configuration from a JSON file. + +Example - Import trust policy configuration from a file: + notation blob policy import my_policy.json +`, + Args: func(cmd *cobra.Command, args []string) error { + if len(args) != 1 { + return fmt.Errorf("requires 1 argument but received %d.\nUsage: notation blob policy import \nPlease specify a trust policy file location as the argument", len(args)) + } + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + opts.filePath = args[0] + return policy.Import(opts.filePath, opts.force, false) + }, + } + command.Flags().BoolVar(&opts.force, "force", false, "override the existing trust policy configuration, never prompt") + return command +} + +func showCmd() *cobra.Command { + command := &cobra.Command{ + Use: "show [flags]", + Short: "show trust policy configuration", + Long: `Show blob trust policy configuration. + +Example - Show current blob trust policy configuration: + notation blob policy show + +Example - Save current blob trust policy configuration to a file: + notation blob policy show > my_policy.json +`, + Args: cobra.ExactArgs(0), + RunE: func(cmd *cobra.Command, args []string) error { + return policy.Show(false) + }, + } + return command +} diff --git a/cmd/notation/internal/policy/import.go b/cmd/notation/internal/policy/import.go new file mode 100644 index 000000000..d50daf199 --- /dev/null +++ b/cmd/notation/internal/policy/import.go @@ -0,0 +1,91 @@ +// 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 policy + +import ( + "encoding/json" + "fmt" + "os" + + "github.com/notaryproject/notation-go/dir" + "github.com/notaryproject/notation-go/verifier/trustpolicy" + "github.com/notaryproject/notation/cmd/notation/internal/cmdutil" + "github.com/notaryproject/notation/internal/osutil" +) + +type policy interface { + Validate() error +} + +// Import imports trust policy configuration from a JSON file. +// +// - If force is true, it will override the existing trust policy configuration +// without prompting. +// - If isOciPolicy is true, it will import OCI trust policy configuration. +// Otherwise, it will import blob trust policy configuration. +func Import(filePath string, force, isOCIPolicy bool) error { + // read configuration + policyJSON, err := os.ReadFile(filePath) + if err != nil { + return fmt.Errorf("failed to read trust policy file: %w", err) + } + + // parse and validate + var doc policy = &trustpolicy.OCIDocument{} + if !isOCIPolicy { + doc = &trustpolicy.BlobDocument{} + } + if err = json.Unmarshal(policyJSON, doc); err != nil { + return fmt.Errorf("failed to parse trust policy configuration: %w", err) + } + if err = doc.Validate(); err != nil { + return fmt.Errorf("failed to validate trust policy: %w", err) + } + + // optional confirmation + if !force { + var err error + if isOCIPolicy { + _, err = trustpolicy.LoadDocument() + } else { + _, err = trustpolicy.LoadBlobDocument() + } + if err == nil { + confirmed, err := cmdutil.AskForConfirmation(os.Stdin, "The trust policy file already exists, do you want to overwrite it?", force) + if err != nil { + return err + } + if !confirmed { + return nil + } + } + } else { + fmt.Fprintln(os.Stderr, "Warning: existing trust policy configuration file will be overwritten") + } + + // write + trustPolicyName := dir.PathOCITrustPolicy + if !isOCIPolicy { + trustPolicyName = dir.PathBlobTrustPolicy + } + policyPath, err := dir.ConfigFS().SysPath(trustPolicyName) + if err != nil { + return fmt.Errorf("failed to obtain path of trust policy file: %w", err) + } + if err = osutil.WriteFile(policyPath, policyJSON); err != nil { + return fmt.Errorf("failed to write trust policy file: %w", err) + } + _, err = fmt.Fprintln(os.Stdout, "Trust policy configuration imported successfully.") + return err +} diff --git a/cmd/notation/internal/policy/show.go b/cmd/notation/internal/policy/show.go new file mode 100644 index 000000000..2a7522b6f --- /dev/null +++ b/cmd/notation/internal/policy/show.go @@ -0,0 +1,86 @@ +// 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 policy + +import ( + "encoding/json" + "errors" + "fmt" + "io" + "io/fs" + "os" + + "github.com/notaryproject/notation-go/dir" + "github.com/notaryproject/notation-go/verifier/trustpolicy" +) + +// Show shows trust policy configuration. +// +// - If isOciPolicy is true, it will show OCI trust policy configuration. +// Otherwise, it will show blob trust policy configuration. +func Show(isOCIPolicy bool) error { + var ( + policyJSON []byte + err error + doc policy + ) + if isOCIPolicy { + doc = &trustpolicy.OCIDocument{} + policyJSON, err = loadOCIDocument() + } else { + doc = &trustpolicy.BlobDocument{} + policyJSON, err = loadBlobDocument() + } + if err != nil { + if errors.Is(err, fs.ErrNotExist) { + return fmt.Errorf("failed to show trust policy as the trust policy file does not exist.\nYou can import one using `notation policy import `") + } + return fmt.Errorf("failed to show trust policy: %w", err) + } + + if err = json.Unmarshal(policyJSON, &doc); err == nil { + err = doc.Validate() + } + if err != nil { + fmt.Fprintf(os.Stderr, "Error: %s\n", err.Error()) + fmt.Fprintf(os.Stderr, "Existing trust policy configuration is invalid, you may update or create a new one via `notation policy import `\n") + // not returning to show the invalid policy configuration + } + + // show policy content + _, err = os.Stdout.Write(policyJSON) + return err +} + +func loadOCIDocument() ([]byte, error) { + f, err := dir.ConfigFS().Open(dir.PathOCITrustPolicy) + if err != nil { + if !os.IsNotExist(err) { + return nil, err + } + f, err = dir.ConfigFS().Open(dir.PathTrustPolicy) + if err != nil { + return nil, err + } + } + return io.ReadAll(f) +} + +func loadBlobDocument() ([]byte, error) { + f, err := dir.ConfigFS().Open(dir.PathBlobTrustPolicy) + if err != nil { + return nil, err + } + return io.ReadAll(f) +} diff --git a/cmd/notation/main.go b/cmd/notation/main.go index 712668a9f..7f33a1202 100644 --- a/cmd/notation/main.go +++ b/cmd/notation/main.go @@ -17,6 +17,7 @@ import ( "os" "github.com/notaryproject/notation-go/dir" + "github.com/notaryproject/notation/cmd/notation/blob" "github.com/notaryproject/notation/cmd/notation/cert" "github.com/notaryproject/notation/cmd/notation/plugin" "github.com/notaryproject/notation/cmd/notation/policy" @@ -51,6 +52,7 @@ func main() { }, } cmd.AddCommand( + blob.Cmd(), signCommand(nil), verifyCommand(nil), listCommand(nil), diff --git a/cmd/notation/policy/import.go b/cmd/notation/policy/import.go index ec3d3e854..d7fba0f20 100644 --- a/cmd/notation/policy/import.go +++ b/cmd/notation/policy/import.go @@ -14,14 +14,9 @@ package policy import ( - "encoding/json" "fmt" - "os" - "github.com/notaryproject/notation-go/dir" - "github.com/notaryproject/notation-go/verifier/trustpolicy" - "github.com/notaryproject/notation/cmd/notation/internal/cmdutil" - "github.com/notaryproject/notation/internal/osutil" + "github.com/notaryproject/notation/cmd/notation/internal/policy" "github.com/spf13/cobra" ) @@ -50,52 +45,9 @@ Example - Import trust policy configuration from a file: }, RunE: func(cmd *cobra.Command, args []string) error { opts.filePath = args[0] - return runImport(cmd, opts) + return policy.Import(opts.filePath, opts.force, true) }, } command.Flags().BoolVar(&opts.force, "force", false, "override the existing trust policy configuration, never prompt") return command } - -func runImport(command *cobra.Command, opts importOpts) error { - // read configuration - policyJSON, err := os.ReadFile(opts.filePath) - if err != nil { - return fmt.Errorf("failed to read trust policy file: %w", err) - } - - // parse and validate - var doc trustpolicy.Document - if err = json.Unmarshal(policyJSON, &doc); err != nil { - return fmt.Errorf("failed to parse trust policy configuration: %w", err) - } - if err = doc.Validate(); err != nil { - return fmt.Errorf("failed to validate trust policy: %w", err) - } - - // optional confirmation - if !opts.force { - if _, err := trustpolicy.LoadDocument(); err == nil { - confirmed, err := cmdutil.AskForConfirmation(os.Stdin, "The trust policy file already exists, do you want to overwrite it?", opts.force) - if err != nil { - return err - } - if !confirmed { - return nil - } - } - } else { - fmt.Fprintln(os.Stderr, "Warning: existing trust policy configuration file will be overwritten") - } - - // write - policyPath, err := dir.ConfigFS().SysPath(dir.PathTrustPolicy) - if err != nil { - return fmt.Errorf("failed to obtain path of trust policy file: %w", err) - } - if err = osutil.WriteFile(policyPath, policyJSON); err != nil { - return fmt.Errorf("failed to write trust policy file: %w", err) - } - _, err = fmt.Fprintln(os.Stdout, "Trust policy configuration imported successfully.") - return err -} diff --git a/cmd/notation/policy/show.go b/cmd/notation/policy/show.go index dca73c942..b1c46c929 100644 --- a/cmd/notation/policy/show.go +++ b/cmd/notation/policy/show.go @@ -14,22 +14,11 @@ package policy import ( - "encoding/json" - "errors" - "fmt" - "io/fs" - "os" - - "github.com/notaryproject/notation-go/dir" - "github.com/notaryproject/notation-go/verifier/trustpolicy" + "github.com/notaryproject/notation/cmd/notation/internal/policy" "github.com/spf13/cobra" ) -type showOpts struct { -} - func showCmd() *cobra.Command { - var opts showOpts command := &cobra.Command{ Use: "show [flags]", Short: "Show trust policy configuration", @@ -45,38 +34,8 @@ Example - Save current trust policy configuration to a file: `, Args: cobra.ExactArgs(0), RunE: func(cmd *cobra.Command, args []string) error { - return runShow(cmd, opts) + return policy.Show(true) }, } return command } - -func runShow(command *cobra.Command, opts showOpts) error { - // get policy file path - policyPath, err := dir.ConfigFS().SysPath(dir.PathTrustPolicy) - if err != nil { - return fmt.Errorf("failed to obtain path of trust policy file: %w", err) - } - - // core process - policyJSON, err := os.ReadFile(policyPath) - if err != nil { - if errors.Is(err, fs.ErrNotExist) { - return fmt.Errorf("failed to show trust policy as the trust policy file does not exist.\nYou can import one using `notation policy import `") - } - return fmt.Errorf("failed to show trust policy: %w", err) - } - var doc trustpolicy.Document - if err = json.Unmarshal(policyJSON, &doc); err == nil { - err = doc.Validate() - } - if err != nil { - fmt.Fprintf(os.Stderr, "Error: %s\n", err.Error()) - fmt.Fprintf(os.Stderr, "Existing trust policy configuration is invalid, you may update or create a new one via `notation policy import `\n") - // not returning to show the invalid policy configuration - } - - // show policy content - _, err = os.Stdout.Write(policyJSON) - return err -} diff --git a/go.mod b/go.mod index 042764960..2c2f28c0a 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/notaryproject/notation go 1.23 require ( - github.com/notaryproject/notation-core-go v1.2.0-rc.1.0.20241129024749-95d89543c9f9 + github.com/notaryproject/notation-core-go v1.2.0-rc.2 github.com/notaryproject/notation-go v1.2.0-beta.1.0.20241202020354-95bac0082974 github.com/notaryproject/tspclient-go v1.0.0-rc.1 github.com/opencontainers/go-digest v1.0.0 @@ -31,3 +31,7 @@ require ( golang.org/x/sync v0.6.0 // indirect golang.org/x/sys v0.28.0 // indirect ) + +replace github.com/notaryproject/notation-go => github.com/notaryproject/notation-go v1.2.0-beta.1.0.20241213001949-cefd007065f1 + +replace github.com/notaryproject/notation-core-go => github.com/notaryproject/notation-core-go v1.2.0-rc.2 diff --git a/go.sum b/go.sum index 653841d30..8bf720180 100644 --- a/go.sum +++ b/go.sum @@ -35,10 +35,10 @@ 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-rc.1.0.20241129024749-95d89543c9f9 h1:FURo9xpGLKmghWCcWypCPQTlcOGKxzayeXacGfb8WUU= -github.com/notaryproject/notation-core-go v1.2.0-rc.1.0.20241129024749-95d89543c9f9/go.mod h1:Umjn4NKGmuHpVffMgKVcUnArNG3Qtd3duKYpPILUBg4= -github.com/notaryproject/notation-go v1.2.0-beta.1.0.20241202020354-95bac0082974 h1:EQ9DC25U7hWbBIOlwINxPhr9QEyixg1/Fo5ZZW+3JSU= -github.com/notaryproject/notation-go v1.2.0-beta.1.0.20241202020354-95bac0082974/go.mod h1:6a3/g7yD/8dxxBpimzUWthH8DLBrzHs4RTzdz9CALvw= +github.com/notaryproject/notation-core-go v1.2.0-rc.2 h1:0jOItalNwBNUhyuc5PPHQxO3jIZ5xRYq+IvRMQXNbuE= +github.com/notaryproject/notation-core-go v1.2.0-rc.2/go.mod h1:7aIcavfywFvBQoYyfVFJB501kt7Etqyubrt5mhJBG2c= +github.com/notaryproject/notation-go v1.2.0-beta.1.0.20241213001949-cefd007065f1 h1:5AclBjBR5Wi/wZzUjTtHG8N72b1Jd+6JkqG+aHPFiBw= +github.com/notaryproject/notation-go v1.2.0-beta.1.0.20241213001949-cefd007065f1/go.mod h1:l7C6xVLPy5cBb+6MpsM9iLyFrVYxgS6+QjBdrl/KSY8= 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-rc.1 h1:KcHxlqg6Adt4kzGLw012i0YMLlwGwToiR129c6IQ7Ys= diff --git a/test/e2e/internal/notation/host.go b/test/e2e/internal/notation/host.go index 0ad17854f..88d892606 100644 --- a/test/e2e/internal/notation/host.go +++ b/test/e2e/internal/notation/host.go @@ -238,6 +238,16 @@ func AddTrustPolicyOption(trustpolicyName string) utils.HostOption { } } +// AddBlobTrustPolicyOption adds a valid trust policy for testing. +func AddBlobTrustPolicyOption(trustpolicyName string) utils.HostOption { + return func(vhost *utils.VirtualHost) error { + return copyFile( + filepath.Join(NotationE2ETrustPolicyDir, trustpolicyName), + vhost.AbsolutePath(NotationDirName, BlobTrustPolicyName), + ) + } +} + // AddConfigJsonOption adds a valid config.json for testing. func AddConfigJsonOption(configJsonName string) utils.HostOption { return func(vhost *utils.VirtualHost) error { diff --git a/test/e2e/internal/notation/init.go b/test/e2e/internal/notation/init.go index 110a7dde1..96a58d88d 100644 --- a/test/e2e/internal/notation/init.go +++ b/test/e2e/internal/notation/init.go @@ -23,13 +23,14 @@ import ( ) const ( - NotationDirName = "notation" - TrustPolicyName = "trustpolicy.json" - TrustStoreDirName = "truststore" - TrustStoreTypeCA = "ca" - PluginDirName = "plugins" - PluginName = "e2e-plugin" - ConfigJsonName = "config.json" + NotationDirName = "notation" + TrustPolicyName = "trustpolicy.json" + BlobTrustPolicyName = "trustpolicy.blob.json" + TrustStoreDirName = "truststore" + TrustStoreTypeCA = "ca" + PluginDirName = "plugins" + PluginName = "e2e-plugin" + ConfigJsonName = "config.json" ) const ( diff --git a/test/e2e/run.sh b/test/e2e/run.sh index 4a8e28f05..1eb9daeed 100755 --- a/test/e2e/run.sh +++ b/test/e2e/run.sh @@ -118,4 +118,4 @@ export NOTATION_E2E_PLUGIN_TAR_GZ_PATH=$CWD/plugin/bin/$PLUGIN_NAME.tar.gz export NOTATION_E2E_MALICIOUS_PLUGIN_ARCHIVE_PATH=$CWD/testdata/malicious-plugin # run tests -ginkgo -r -p -v \ No newline at end of file +ginkgo -r -p -v --focus "blob trust policy maintainer" \ No newline at end of file diff --git a/test/e2e/suite/command/blob/blob_test.go b/test/e2e/suite/command/blob/blob_test.go new file mode 100644 index 000000000..b500e346f --- /dev/null +++ b/test/e2e/suite/command/blob/blob_test.go @@ -0,0 +1,26 @@ +// 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 blob + +import ( + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +func TestCommand(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Blob Command Suite") +} diff --git a/test/e2e/suite/command/blob/policy.go b/test/e2e/suite/command/blob/policy.go new file mode 100644 index 000000000..8328af50f --- /dev/null +++ b/test/e2e/suite/command/blob/policy.go @@ -0,0 +1,203 @@ +// 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 blob + +import ( + "os" + "path/filepath" + "strings" + + . "github.com/notaryproject/notation/test/e2e/internal/notation" + "github.com/notaryproject/notation/test/e2e/internal/utils" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +const validBlobTrustPolicyName = "blob_trust_policy.json" + +var _ = Describe("blob trust policy maintainer", func() { + When("showing configuration", func() { + It("should show error and hint if policy doesn't exist", func() { + Host(Opts(), func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { + notation.ExpectFailure(). + Exec("blob", "policy", "show"). + MatchErrKeyWords("failed to show trust policy", "notation policy import") + }) + }) + + It("should show error and hint if policy without read permission", func() { + Host(Opts(AddBlobTrustPolicyOption(validBlobTrustPolicyName)), func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { + trustPolicyPath := vhost.AbsolutePath(NotationDirName, BlobTrustPolicyName) + os.Chmod(trustPolicyPath, 0200) + notation.ExpectFailure(). + Exec("blob", "policy", "show"). + MatchErrKeyWords("failed to show trust policy", "permission denied") + }) + }) + + It("should show exist policy", func() { + content, err := os.ReadFile(filepath.Join(NotationE2ETrustPolicyDir, validBlobTrustPolicyName)) + Expect(err).NotTo(HaveOccurred()) + Host(Opts(AddBlobTrustPolicyOption(validBlobTrustPolicyName)), func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { + notation.Exec("blob", "policy", "show"). + MatchContent(string(content)) + }) + }) + + It("should display error hint when showing invalid policy", func() { + policyName := "invalid_format_trustpolicy.json" + content, err := os.ReadFile(filepath.Join(NotationE2ETrustPolicyDir, policyName)) + Expect(err).NotTo(HaveOccurred()) + Host(Opts(AddBlobTrustPolicyOption(policyName)), func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { + notation.Exec("blob", "policy", "show"). + MatchErrKeyWords("existing trust policy configuration is invalid"). + MatchContent(string(content)) + }) + }) + }) + + When("importing configuration without existing trust policy configuration", func() { + opts := Opts() + It("should fail if no file path is provided", func() { + Host(opts, func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { + notation.ExpectFailure(). + Exec("blob", "policy", "import"). + MatchErrKeyWords("requires 1 argument but received 0") + + }) + }) + + It("should fail if more than one file path is provided", func() { + Host(opts, func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { + notation.ExpectFailure(). + Exec("blob", "policy", "import", "a", "b"). + MatchErrKeyWords("requires 1 argument but received 2") + }) + }) + + It("should fail if provided file doesn't exist", func() { + Host(opts, func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { + notation.ExpectFailure(). + Exec("blob", "policy", "import", "/??/???") + }) + }) + + It("should fail if identity is malformed", func() { + Host(opts, func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { + notation.ExpectFailure(). + Exec("blob", "policy", "import", filepath.Join(NotationE2ETrustPolicyDir, "malformed_trusted_identity_trustpolicy.json")) + }) + }) + + It("should import successfully", func() { + Host(opts, func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { + notation.Exec("blob", "policy", "import", filepath.Join(NotationE2ETrustPolicyDir, validBlobTrustPolicyName)) + }) + }) + + It("should import successfully by force", func() { + Host(opts, func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { + notation.Exec("blob", "policy", "import", filepath.Join(NotationE2ETrustPolicyDir, validBlobTrustPolicyName), "--force") + }) + }) + }) + + When("importing configuration with existing trust policy configuration", func() { + opts := Opts(AddBlobTrustPolicyOption(validBlobTrustPolicyName)) + It("should fail if no file path is provided", func() { + Host(opts, func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { + notation.ExpectFailure(). + Exec("blob", "policy", "import"). + MatchErrKeyWords("requires 1 argument but received 0") + }) + }) + + It("should fail if provided file doesn't exist", func() { + Host(opts, func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { + notation.ExpectFailure(). + Exec("blob", "policy", "import", "/??/???", "--force") + }) + }) + + It("should fail if store is malformed", func() { + Host(opts, func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { + notation.WithInput(strings.NewReader("Y\n")).ExpectFailure(). + Exec("blob", "policy", "import", filepath.Join(NotationE2ETrustPolicyDir, "malformed_trust_store_trustpolicy.json")) + }) + }) + + It("should fail if identity is malformed", func() { + Host(opts, func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { + notation.WithInput(strings.NewReader("Y\n")).ExpectFailure(). + Exec("blob", "policy", "import", filepath.Join(NotationE2ETrustPolicyDir, "malformed_trusted_identity_trustpolicy.json")) + }) + }) + + It("should cancel import with N", func() { + Host(opts, func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { + notation.WithInput(strings.NewReader("N\n")).Exec("blob", "policy", "import", filepath.Join(NotationE2ETrustPolicyDir, "skip_trustpolicy.json")) + // validate + content, err := os.ReadFile(filepath.Join(NotationE2ETrustPolicyDir, validBlobTrustPolicyName)) + Expect(err).NotTo(HaveOccurred()) + notation.Exec("blob", "policy", "show").MatchContent(string(content)) + }) + }) + + It("should cancel import by default", func() { + Host(opts, func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { + notation.Exec("blob", "policy", "import", filepath.Join(NotationE2ETrustPolicyDir, "skip_trustpolicy.json")) + // validate + content, err := os.ReadFile(filepath.Join(NotationE2ETrustPolicyDir, validBlobTrustPolicyName)) + Expect(err).NotTo(HaveOccurred()) + notation.Exec("blob", "policy", "show").MatchContent(string(content)) + }) + }) + + It("should skip confirmation if existing policy is malformed", func() { + Host(Opts(AddBlobTrustPolicyOption("invalid_format_trustpolicy.json")), func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { + policyFileName := "skip_trustpolicy.json" + notation.Exec("blob", "policy", "import", filepath.Join(NotationE2ETrustPolicyDir, policyFileName)).MatchKeyWords(). + MatchKeyWords("Trust policy configuration imported successfully.") + // validate + content, err := os.ReadFile(filepath.Join(NotationE2ETrustPolicyDir, policyFileName)) + Expect(err).NotTo(HaveOccurred()) + notation.Exec("blob", "policy", "show").MatchContent(string(content)) + }) + }) + + It("should confirm import", func() { + Host(opts, func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { + policyFileName := "skip_trustpolicy.json" + notation.WithInput(strings.NewReader("Y\n")).Exec("blob", "policy", "import", filepath.Join(NotationE2ETrustPolicyDir, policyFileName)). + MatchKeyWords("Trust policy configuration imported successfully.") + // validate + content, err := os.ReadFile(filepath.Join(NotationE2ETrustPolicyDir, policyFileName)) + Expect(err).NotTo(HaveOccurred()) + notation.Exec("blob", "policy", "show").MatchContent(string(content)) + }) + }) + + It("should confirm import by force", func() { + Host(opts, func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { + policyFileName := "skip_trustpolicy.json" + notation.Exec("blob", "policy", "import", filepath.Join(NotationE2ETrustPolicyDir, policyFileName), "--force"). + MatchKeyWords("Trust policy configuration imported successfully.") + // validate + content, err := os.ReadFile(filepath.Join(NotationE2ETrustPolicyDir, policyFileName)) + Expect(err).NotTo(HaveOccurred()) + notation.Exec("blob", "policy", "show").MatchContent(string(content)) + }) + }) + }) +}) diff --git a/test/e2e/testdata/config/trustpolicies/blob_trust_policy.json b/test/e2e/testdata/config/trustpolicies/blob_trust_policy.json new file mode 100644 index 000000000..c94bf4567 --- /dev/null +++ b/test/e2e/testdata/config/trustpolicies/blob_trust_policy.json @@ -0,0 +1,32 @@ +{ + "version": "1.0", + "trustPolicies": [ + { + "name": "wabbit-networks-policy", + "signatureVerification": { + "level": "strict" + }, + "trustStores": [ + "ca:wabbit-networks" + ], + "trustedIdentities": [ + "x509.subject: C=US, ST=WA, L=Seattle, O=wabbit-networks.io, OU=Security Tools" + ] + }, + { + "name": "skip-verification-policy", + "signatureVerification": { + "level" : "skip" + } + }, + { + "name": "global-verification-policy", + "globalPolicy": true, + "signatureVerification": { + "level" : "audit" + }, + "trustStores": ["ca:acme-rockets"], + "trustedIdentities": ["*"] + } + ] +} \ No newline at end of file From 588f3e582a4e16fa8d019bcb9dad3f170b7347bc Mon Sep 17 00:00:00 2001 From: Junjie Gao Date: Tue, 24 Dec 2024 07:24:27 +0000 Subject: [PATCH 02/24] fix: add e2e test cases Signed-off-by: Junjie Gao --- cmd/notation/internal/policy/import.go | 9 ++++++ internal/osutil/file.go | 11 +++++++ internal/osutil/file_test.go | 45 ++++++++++++++++++++++++++ test/e2e/run.sh | 2 +- test/e2e/suite/command/policy.go | 37 +++++++++++++++++++++ 5 files changed, 103 insertions(+), 1 deletion(-) diff --git a/cmd/notation/internal/policy/import.go b/cmd/notation/internal/policy/import.go index d50daf199..e14653cec 100644 --- a/cmd/notation/internal/policy/import.go +++ b/cmd/notation/internal/policy/import.go @@ -86,6 +86,15 @@ func Import(filePath string, force, isOCIPolicy bool) error { if err = osutil.WriteFile(policyPath, policyJSON); err != nil { return fmt.Errorf("failed to write trust policy file: %w", err) } + + // cleanup old trust policy + if isOCIPolicy { + oldPolicyPath, _ := dir.ConfigFS().SysPath(dir.PathTrustPolicy) + if err := osutil.RemoveIfExists(oldPolicyPath); err != nil { + _, _ = fmt.Fprintf(os.Stderr, "Warning: failed to cleanup old trust policy %q: %v\n", oldPolicyPath, err) + } + } + _, err = fmt.Fprintln(os.Stdout, "Trust policy configuration imported successfully.") return err } diff --git a/internal/osutil/file.go b/internal/osutil/file.go index 06f69792a..d85390f5f 100644 --- a/internal/osutil/file.go +++ b/internal/osutil/file.go @@ -60,6 +60,17 @@ func WriteFileWithPermission(path string, data []byte, perm fs.FileMode, overwri return file.Close() } +// RemoveIfExists removes a file if it exists. +func RemoveIfExists(filepath string) error { + if _, err := os.Stat(filepath); err != nil { + if os.IsNotExist(err) { + return nil + } + return err + } + return os.Remove(filepath) +} + // CopyToDir copies the src file to dst. Existing file will be overwritten. func CopyToDir(src, dst string) (int64, error) { sourceFileStat, err := os.Stat(src) diff --git a/internal/osutil/file_test.go b/internal/osutil/file_test.go index 59226f9b1..d22d509a5 100644 --- a/internal/osutil/file_test.go +++ b/internal/osutil/file_test.go @@ -269,3 +269,48 @@ func TestValidateChecksum(t *testing.T) { t.Fatalf("expected nil err, but got %v", err) } } + +func TestRemoveIfExists(t *testing.T) { + t.Run("remove existing file", func(t *testing.T) { + tempDir := t.TempDir() + filename := filepath.Join(tempDir, "file.txt") + data := []byte("data") + if err := WriteFile(filename, data); err != nil { + t.Fatal(err) + } + if err := RemoveIfExists(filename); err != nil { + t.Fatal(err) + } + if _, err := os.Stat(filename); !os.IsNotExist(err) { + t.Fatal("file should be removed") + } + }) + + t.Run("remove non-existing file", func(t *testing.T) { + tempDir := t.TempDir() + filename := filepath.Join(tempDir, "file.txt") + if err := RemoveIfExists(filename); err != nil { + t.Fatal(err) + } + }) + + t.Run("remove file in directory without permission", func(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("skipping test on Windows") + } + tempDir := t.TempDir() + filename := filepath.Join(tempDir, "file.txt") + data := []byte("data") + if err := WriteFile(filename, data); err != nil { + t.Fatal(err) + } + if err := os.Chmod(tempDir, 0000); err != nil { + t.Fatal(err) + } + defer os.Chmod(tempDir, 0700) + + if err := RemoveIfExists(filename); err == nil { + t.Fatal("expected an error when removing file from restricted directory") + } + }) +} diff --git a/test/e2e/run.sh b/test/e2e/run.sh index 1eb9daeed..cebc33d68 100755 --- a/test/e2e/run.sh +++ b/test/e2e/run.sh @@ -118,4 +118,4 @@ export NOTATION_E2E_PLUGIN_TAR_GZ_PATH=$CWD/plugin/bin/$PLUGIN_NAME.tar.gz export NOTATION_E2E_MALICIOUS_PLUGIN_ARCHIVE_PATH=$CWD/testdata/malicious-plugin # run tests -ginkgo -r -p -v --focus "blob trust policy maintainer" \ No newline at end of file +ginkgo -r -p -v \ No newline at end of file diff --git a/test/e2e/suite/command/policy.go b/test/e2e/suite/command/policy.go index 118939c58..9e687fb8f 100644 --- a/test/e2e/suite/command/policy.go +++ b/test/e2e/suite/command/policy.go @@ -218,4 +218,41 @@ var _ = Describe("trust policy maintainer", func() { }) }) }) + + When("importing policy with existing old policy", func() { + It("should delete old policy", func() { + Host(Opts(AddTrustPolicyOption("trustpolicy.json")), func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { + newPolicyName := "any_registry_scope_trust_policy.json" + notation.WithInput(strings.NewReader("Y\n")).Exec("policy", "import", filepath.Join(NotationE2ETrustPolicyDir, newPolicyName)). + MatchKeyWords("Trust policy configuration imported successfully.") + // validate + content, err := os.ReadFile(filepath.Join(NotationE2ETrustPolicyDir, newPolicyName)) + Expect(err).NotTo(HaveOccurred()) + notation.Exec("policy", "show").MatchContent(string(content)) + + // check old policy doesn't exist + oldPolicyPath := vhost.AbsolutePath(NotationDirName, "trustpolicy.json") + _, err = os.Stat(oldPolicyPath) + Expect(os.IsNotExist(err)).To(BeTrue()) + }) + }) + }) + + When("showing policy when both the old and oci policy exist", func() { + It("should show the oci policy", func() { + Host(Opts(), func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { + // add oci policy + newPolicyName := "any_registry_scope_trust_policy.json" + notation.WithInput(strings.NewReader("Y\n")).Exec("policy", "import", filepath.Join(NotationE2ETrustPolicyDir, newPolicyName)). + MatchKeyWords("Trust policy configuration imported successfully.") + + // add old policy + vhost.SetOption(AddTrustPolicyOption("trustpolicy.json")) + + content, err := os.ReadFile(filepath.Join(NotationE2ETrustPolicyDir, newPolicyName)) + Expect(err).NotTo(HaveOccurred()) + notation.Exec("policy", "show").MatchContent(string(content)) + }) + }) + }) }) From 1ff85478526e1e59c6cd507e1396e86ac8135b19 Mon Sep 17 00:00:00 2001 From: Junjie Gao Date: Tue, 24 Dec 2024 08:03:33 +0000 Subject: [PATCH 03/24] fix: improve code Signed-off-by: Junjie Gao --- cmd/notation/blob/cmd.go | 16 +----------- cmd/notation/blob/policy.go | 15 ++++++++++++ cmd/notation/internal/policy/import.go | 7 ++++-- cmd/notation/internal/policy/show.go | 2 ++ test/e2e/internal/notation/init.go | 1 + test/e2e/run.sh | 2 +- test/e2e/suite/command/policy.go | 34 +++++++++++++++++++++++++- 7 files changed, 58 insertions(+), 19 deletions(-) diff --git a/cmd/notation/blob/cmd.go b/cmd/notation/blob/cmd.go index 6717bfab1..9d236547b 100644 --- a/cmd/notation/blob/cmd.go +++ b/cmd/notation/blob/cmd.go @@ -15,6 +15,7 @@ package blob import "github.com/spf13/cobra" +// Cmd returns the command for blob func Cmd() *cobra.Command { command := &cobra.Command{ Use: "blob [commnad]", @@ -28,18 +29,3 @@ func Cmd() *cobra.Command { return command } - -func policyCmd() *cobra.Command { - command := &cobra.Command{ - Use: "policy [command]", - Short: "manage trust policy configuration for signed blobs", - Long: "Manage trust policy configuration for arbitrary blob signature verification.", - } - - command.AddCommand( - importCmd(), - showCmd(), - ) - - return command -} diff --git a/cmd/notation/blob/policy.go b/cmd/notation/blob/policy.go index 79ecc19b0..6ff9ee7c8 100644 --- a/cmd/notation/blob/policy.go +++ b/cmd/notation/blob/policy.go @@ -20,6 +20,21 @@ import ( "github.com/spf13/cobra" ) +func policyCmd() *cobra.Command { + command := &cobra.Command{ + Use: "policy [command]", + Short: "manage trust policy configuration for signed blobs", + Long: "Manage trust policy configuration for arbitrary blob signature verification.", + } + + command.AddCommand( + importCmd(), + showCmd(), + ) + + return command +} + type importOpts struct { filePath string force bool diff --git a/cmd/notation/internal/policy/import.go b/cmd/notation/internal/policy/import.go index e14653cec..2a80ba395 100644 --- a/cmd/notation/internal/policy/import.go +++ b/cmd/notation/internal/policy/import.go @@ -89,9 +89,12 @@ func Import(filePath string, force, isOCIPolicy bool) error { // cleanup old trust policy if isOCIPolicy { - oldPolicyPath, _ := dir.ConfigFS().SysPath(dir.PathTrustPolicy) + oldPolicyPath, err := dir.ConfigFS().SysPath(dir.PathTrustPolicy) + if err != nil { + return fmt.Errorf("failed to obtain path of trust policy file: %w", err) + } if err := osutil.RemoveIfExists(oldPolicyPath); err != nil { - _, _ = fmt.Fprintf(os.Stderr, "Warning: failed to cleanup old trust policy %q: %v\n", oldPolicyPath, err) + _, _ = fmt.Fprintf(os.Stderr, "Warning: failed to clear old trust policy %q: %v\n", oldPolicyPath, err) } } diff --git a/cmd/notation/internal/policy/show.go b/cmd/notation/internal/policy/show.go index 2a7522b6f..6bfa1ee86 100644 --- a/cmd/notation/internal/policy/show.go +++ b/cmd/notation/internal/policy/show.go @@ -74,6 +74,7 @@ func loadOCIDocument() ([]byte, error) { return nil, err } } + defer f.Close() return io.ReadAll(f) } @@ -82,5 +83,6 @@ func loadBlobDocument() ([]byte, error) { if err != nil { return nil, err } + defer f.Close() return io.ReadAll(f) } diff --git a/test/e2e/internal/notation/init.go b/test/e2e/internal/notation/init.go index 96a58d88d..d7a60320e 100644 --- a/test/e2e/internal/notation/init.go +++ b/test/e2e/internal/notation/init.go @@ -25,6 +25,7 @@ import ( const ( NotationDirName = "notation" TrustPolicyName = "trustpolicy.json" + OCITrustPolicyName = "trustpolicy.oci.json" BlobTrustPolicyName = "trustpolicy.blob.json" TrustStoreDirName = "truststore" TrustStoreTypeCA = "ca" diff --git a/test/e2e/run.sh b/test/e2e/run.sh index cebc33d68..4a8e28f05 100755 --- a/test/e2e/run.sh +++ b/test/e2e/run.sh @@ -118,4 +118,4 @@ export NOTATION_E2E_PLUGIN_TAR_GZ_PATH=$CWD/plugin/bin/$PLUGIN_NAME.tar.gz export NOTATION_E2E_MALICIOUS_PLUGIN_ARCHIVE_PATH=$CWD/testdata/malicious-plugin # run tests -ginkgo -r -p -v \ No newline at end of file +ginkgo -r -p -v \ No newline at end of file diff --git a/test/e2e/suite/command/policy.go b/test/e2e/suite/command/policy.go index 9e687fb8f..ea8a91c3c 100644 --- a/test/e2e/suite/command/policy.go +++ b/test/e2e/suite/command/policy.go @@ -44,7 +44,7 @@ var _ = Describe("trust policy maintainer", func() { }) }) - It("should show exist policy", func() { + It("should show exist old policy", func() { content, err := os.ReadFile(filepath.Join(NotationE2ETrustPolicyDir, TrustPolicyName)) Expect(err).NotTo(HaveOccurred()) Host(Opts(AddTrustPolicyOption(TrustPolicyName)), func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { @@ -63,6 +63,16 @@ var _ = Describe("trust policy maintainer", func() { MatchContent(string(content)) }) }) + + It("should failed if without permission to read policy", func() { + Host(Opts(AddTrustPolicyOption(TrustPolicyName)), func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { + trustPolicyPath := vhost.AbsolutePath(NotationDirName, TrustPolicyName) + os.Chmod(trustPolicyPath, 0000) + notation.ExpectFailure(). + Exec("policy", "show"). + MatchErrKeyWords("failed to show trust policy", "permission denied") + }) + }) }) When("importing configuration without existing trust policy configuration", func() { @@ -91,6 +101,13 @@ var _ = Describe("trust policy maintainer", func() { }) }) + It("should failed if provide file is malformed json", func() { + Host(opts, func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { + notation.ExpectFailure(). + Exec("policy", "import", filepath.Join(NotationE2ETrustPolicyDir, "invalid_format_trustpolicy.json")) + }) + }) + It("should fail if registry scope is malformed", func() { Host(opts, func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { notation.ExpectFailure(). @@ -123,6 +140,21 @@ var _ = Describe("trust policy maintainer", func() { notation.Exec("policy", "import", filepath.Join(NotationE2ETrustPolicyDir, TrustPolicyName), "--force") }) }) + + It("should failed if without permission to write policy", func() { + Host(opts, func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { + notation. + Exec("policy", "import", filepath.Join(NotationE2ETrustPolicyDir, TrustPolicyName)) + + trustPolicyPath := vhost.AbsolutePath(NotationDirName) + os.Chmod(trustPolicyPath, 0000) + defer os.Chmod(trustPolicyPath, 0755) + + notation.ExpectFailure(). + Exec("policy", "import", filepath.Join(NotationE2ETrustPolicyDir, TrustPolicyName), "--force"). + MatchErrKeyWords("failed to write trust policy file") + }) + }) }) When("importing configuration with existing trust policy configuration", func() { From 88aee76179b1b017c18cc8a0f38ac85463c76361 Mon Sep 17 00:00:00 2001 From: Junjie Gao Date: Tue, 24 Dec 2024 08:06:20 +0000 Subject: [PATCH 04/24] fix: improve code Signed-off-by: Junjie Gao --- cmd/notation/blob/cmd.go | 1 + go.mod | 6 +----- go.sum | 8 ++++---- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/cmd/notation/blob/cmd.go b/cmd/notation/blob/cmd.go index 9d236547b..dbbd54a98 100644 --- a/cmd/notation/blob/cmd.go +++ b/cmd/notation/blob/cmd.go @@ -11,6 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +// Package blob provides the command for blob trust policy configuration. package blob import "github.com/spf13/cobra" diff --git a/go.mod b/go.mod index 2c2f28c0a..042764960 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/notaryproject/notation go 1.23 require ( - github.com/notaryproject/notation-core-go v1.2.0-rc.2 + github.com/notaryproject/notation-core-go v1.2.0-rc.1.0.20241129024749-95d89543c9f9 github.com/notaryproject/notation-go v1.2.0-beta.1.0.20241202020354-95bac0082974 github.com/notaryproject/tspclient-go v1.0.0-rc.1 github.com/opencontainers/go-digest v1.0.0 @@ -31,7 +31,3 @@ require ( golang.org/x/sync v0.6.0 // indirect golang.org/x/sys v0.28.0 // indirect ) - -replace github.com/notaryproject/notation-go => github.com/notaryproject/notation-go v1.2.0-beta.1.0.20241213001949-cefd007065f1 - -replace github.com/notaryproject/notation-core-go => github.com/notaryproject/notation-core-go v1.2.0-rc.2 diff --git a/go.sum b/go.sum index 8bf720180..653841d30 100644 --- a/go.sum +++ b/go.sum @@ -35,10 +35,10 @@ 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-rc.2 h1:0jOItalNwBNUhyuc5PPHQxO3jIZ5xRYq+IvRMQXNbuE= -github.com/notaryproject/notation-core-go v1.2.0-rc.2/go.mod h1:7aIcavfywFvBQoYyfVFJB501kt7Etqyubrt5mhJBG2c= -github.com/notaryproject/notation-go v1.2.0-beta.1.0.20241213001949-cefd007065f1 h1:5AclBjBR5Wi/wZzUjTtHG8N72b1Jd+6JkqG+aHPFiBw= -github.com/notaryproject/notation-go v1.2.0-beta.1.0.20241213001949-cefd007065f1/go.mod h1:l7C6xVLPy5cBb+6MpsM9iLyFrVYxgS6+QjBdrl/KSY8= +github.com/notaryproject/notation-core-go v1.2.0-rc.1.0.20241129024749-95d89543c9f9 h1:FURo9xpGLKmghWCcWypCPQTlcOGKxzayeXacGfb8WUU= +github.com/notaryproject/notation-core-go v1.2.0-rc.1.0.20241129024749-95d89543c9f9/go.mod h1:Umjn4NKGmuHpVffMgKVcUnArNG3Qtd3duKYpPILUBg4= +github.com/notaryproject/notation-go v1.2.0-beta.1.0.20241202020354-95bac0082974 h1:EQ9DC25U7hWbBIOlwINxPhr9QEyixg1/Fo5ZZW+3JSU= +github.com/notaryproject/notation-go v1.2.0-beta.1.0.20241202020354-95bac0082974/go.mod h1:6a3/g7yD/8dxxBpimzUWthH8DLBrzHs4RTzdz9CALvw= 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-rc.1 h1:KcHxlqg6Adt4kzGLw012i0YMLlwGwToiR129c6IQ7Ys= From 8fe215eb9860b08495130b2b3638e108a8bc221f Mon Sep 17 00:00:00 2001 From: Junjie Gao Date: Tue, 24 Dec 2024 08:22:04 +0000 Subject: [PATCH 05/24] fix: improve code Signed-off-by: Junjie Gao --- cmd/notation/internal/policy/import.go | 3 +-- test/e2e/suite/command/policy.go | 6 ++++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/cmd/notation/internal/policy/import.go b/cmd/notation/internal/policy/import.go index 2a80ba395..4f60c8041 100644 --- a/cmd/notation/internal/policy/import.go +++ b/cmd/notation/internal/policy/import.go @@ -55,7 +55,6 @@ func Import(filePath string, force, isOCIPolicy bool) error { // optional confirmation if !force { - var err error if isOCIPolicy { _, err = trustpolicy.LoadDocument() } else { @@ -87,7 +86,7 @@ func Import(filePath string, force, isOCIPolicy bool) error { return fmt.Errorf("failed to write trust policy file: %w", err) } - // cleanup old trust policy + // clear old trust policy if isOCIPolicy { oldPolicyPath, err := dir.ConfigFS().SysPath(dir.PathTrustPolicy) if err != nil { diff --git a/test/e2e/suite/command/policy.go b/test/e2e/suite/command/policy.go index ea8a91c3c..8464dbc8b 100644 --- a/test/e2e/suite/command/policy.go +++ b/test/e2e/suite/command/policy.go @@ -66,8 +66,10 @@ var _ = Describe("trust policy maintainer", func() { It("should failed if without permission to read policy", func() { Host(Opts(AddTrustPolicyOption(TrustPolicyName)), func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { - trustPolicyPath := vhost.AbsolutePath(NotationDirName, TrustPolicyName) - os.Chmod(trustPolicyPath, 0000) + notationPath := vhost.AbsolutePath(NotationDirName) + os.Chmod(notationPath, 0000) + defer os.Chmod(notationPath, 0755) + notation.ExpectFailure(). Exec("policy", "show"). MatchErrKeyWords("failed to show trust policy", "permission denied") From e67b5fdac5b8913034d717c8f7f7b3b96f5aa5ce Mon Sep 17 00:00:00 2001 From: Junjie Gao Date: Tue, 24 Dec 2024 08:24:08 +0000 Subject: [PATCH 06/24] fix: improve code Signed-off-by: Junjie Gao --- cmd/notation/internal/policy/import.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/notation/internal/policy/import.go b/cmd/notation/internal/policy/import.go index 4f60c8041..bc6c93cce 100644 --- a/cmd/notation/internal/policy/import.go +++ b/cmd/notation/internal/policy/import.go @@ -93,7 +93,7 @@ func Import(filePath string, force, isOCIPolicy bool) error { return fmt.Errorf("failed to obtain path of trust policy file: %w", err) } if err := osutil.RemoveIfExists(oldPolicyPath); err != nil { - _, _ = fmt.Fprintf(os.Stderr, "Warning: failed to clear old trust policy %q: %v\n", oldPolicyPath, err) + fmt.Fprintf(os.Stderr, "Warning: failed to clear old trust policy %q: %v\n", oldPolicyPath, err) } } From 1eb1908da8f49e74737ae5a6792849ae5c56d913 Mon Sep 17 00:00:00 2001 From: Junjie Gao Date: Tue, 24 Dec 2024 08:32:15 +0000 Subject: [PATCH 07/24] fix: improve code Signed-off-by: Junjie Gao --- cmd/notation/internal/policy/show.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/notation/internal/policy/show.go b/cmd/notation/internal/policy/show.go index 6bfa1ee86..b8b3b6a76 100644 --- a/cmd/notation/internal/policy/show.go +++ b/cmd/notation/internal/policy/show.go @@ -31,9 +31,9 @@ import ( // Otherwise, it will show blob trust policy configuration. func Show(isOCIPolicy bool) error { var ( + doc policy policyJSON []byte err error - doc policy ) if isOCIPolicy { doc = &trustpolicy.OCIDocument{} From 77d87e503dd63f1c288d97196f30dcaeacf9f8b1 Mon Sep 17 00:00:00 2001 From: Junjie Gao Date: Fri, 27 Dec 2024 07:36:18 +0000 Subject: [PATCH 08/24] fix: split blob and OCI policy commands Signed-off-by: Junjie Gao --- cmd/notation/blob/cmd.go | 7 +- cmd/notation/blob/policy.go | 86 ------------------- cmd/notation/blob/policy/cmd.go | 35 ++++++++ .../{internal => blob}/policy/import.go | 74 ++++++++-------- .../{internal => blob}/policy/show.go | 60 ++++++------- cmd/notation/policy/cmd.go | 1 + cmd/notation/policy/import.go | 62 ++++++++++++- cmd/notation/policy/show.go | 55 +++++++++++- test/e2e/suite/command/blob/policy.go | 4 +- 9 files changed, 219 insertions(+), 165 deletions(-) delete mode 100644 cmd/notation/blob/policy.go create mode 100644 cmd/notation/blob/policy/cmd.go rename cmd/notation/{internal => blob}/policy/import.go (60%) rename cmd/notation/{internal => blob}/policy/show.go (55%) diff --git a/cmd/notation/blob/cmd.go b/cmd/notation/blob/cmd.go index dbbd54a98..f23cecf6d 100644 --- a/cmd/notation/blob/cmd.go +++ b/cmd/notation/blob/cmd.go @@ -14,7 +14,10 @@ // Package blob provides the command for blob trust policy configuration. package blob -import "github.com/spf13/cobra" +import ( + "github.com/notaryproject/notation/cmd/notation/blob/policy" + "github.com/spf13/cobra" +) // Cmd returns the command for blob func Cmd() *cobra.Command { @@ -25,7 +28,7 @@ func Cmd() *cobra.Command { } command.AddCommand( - policyCmd(), + policy.Cmd(), ) return command diff --git a/cmd/notation/blob/policy.go b/cmd/notation/blob/policy.go deleted file mode 100644 index 6ff9ee7c8..000000000 --- a/cmd/notation/blob/policy.go +++ /dev/null @@ -1,86 +0,0 @@ -// 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 blob - -import ( - "fmt" - - "github.com/notaryproject/notation/cmd/notation/internal/policy" - "github.com/spf13/cobra" -) - -func policyCmd() *cobra.Command { - command := &cobra.Command{ - Use: "policy [command]", - Short: "manage trust policy configuration for signed blobs", - Long: "Manage trust policy configuration for arbitrary blob signature verification.", - } - - command.AddCommand( - importCmd(), - showCmd(), - ) - - return command -} - -type importOpts struct { - filePath string - force bool -} - -func importCmd() *cobra.Command { - var opts importOpts - command := &cobra.Command{ - Use: "import [flags] ", - Short: "import trust policy configuration from a JSON file", - Long: `Import blob trust policy configuration from a JSON file. - -Example - Import trust policy configuration from a file: - notation blob policy import my_policy.json -`, - Args: func(cmd *cobra.Command, args []string) error { - if len(args) != 1 { - return fmt.Errorf("requires 1 argument but received %d.\nUsage: notation blob policy import \nPlease specify a trust policy file location as the argument", len(args)) - } - return nil - }, - RunE: func(cmd *cobra.Command, args []string) error { - opts.filePath = args[0] - return policy.Import(opts.filePath, opts.force, false) - }, - } - command.Flags().BoolVar(&opts.force, "force", false, "override the existing trust policy configuration, never prompt") - return command -} - -func showCmd() *cobra.Command { - command := &cobra.Command{ - Use: "show [flags]", - Short: "show trust policy configuration", - Long: `Show blob trust policy configuration. - -Example - Show current blob trust policy configuration: - notation blob policy show - -Example - Save current blob trust policy configuration to a file: - notation blob policy show > my_policy.json -`, - Args: cobra.ExactArgs(0), - RunE: func(cmd *cobra.Command, args []string) error { - return policy.Show(false) - }, - } - return command -} diff --git a/cmd/notation/blob/policy/cmd.go b/cmd/notation/blob/policy/cmd.go new file mode 100644 index 000000000..002f0ef7e --- /dev/null +++ b/cmd/notation/blob/policy/cmd.go @@ -0,0 +1,35 @@ +// 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 policy provides the import and show command for blob trust policy. +package policy + +import ( + "github.com/spf13/cobra" +) + +// Cmd returns the command for policy including import and show. +func Cmd() *cobra.Command { + command := &cobra.Command{ + Use: "policy [command]", + Short: "manage trust policy configuration for signed blobs", + Long: "Manage trust policy configuration for arbitrary blob signature verification.", + } + + command.AddCommand( + importCmd(), + showCmd(), + ) + + return command +} diff --git a/cmd/notation/internal/policy/import.go b/cmd/notation/blob/policy/import.go similarity index 60% rename from cmd/notation/internal/policy/import.go rename to cmd/notation/blob/policy/import.go index bc6c93cce..c71ec585b 100644 --- a/cmd/notation/internal/policy/import.go +++ b/cmd/notation/blob/policy/import.go @@ -22,30 +22,47 @@ import ( "github.com/notaryproject/notation-go/verifier/trustpolicy" "github.com/notaryproject/notation/cmd/notation/internal/cmdutil" "github.com/notaryproject/notation/internal/osutil" + "github.com/spf13/cobra" ) -type policy interface { - Validate() error +type importOpts struct { + filePath string + force bool } -// Import imports trust policy configuration from a JSON file. -// -// - If force is true, it will override the existing trust policy configuration -// without prompting. -// - If isOciPolicy is true, it will import OCI trust policy configuration. -// Otherwise, it will import blob trust policy configuration. -func Import(filePath string, force, isOCIPolicy bool) error { +func importCmd() *cobra.Command { + var opts importOpts + command := &cobra.Command{ + Use: "import [flags] ", + Short: "import trust policy configuration from a JSON file", + Long: `Import blob trust policy configuration from a JSON file. + +Example - Import trust policy configuration from a file: + notation blob policy import my_policy.json +`, + Args: func(cmd *cobra.Command, args []string) error { + if len(args) != 1 { + return fmt.Errorf("requires 1 argument but received %d.\nUsage: notation blob policy import \nPlease specify a trust policy file location as the argument", len(args)) + } + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + opts.filePath = args[0] + return runImport(opts) + }, + } + command.Flags().BoolVar(&opts.force, "force", false, "override the existing trust policy configuration, never prompt") + return command +} + +func runImport(opts importOpts) error { // read configuration - policyJSON, err := os.ReadFile(filePath) + policyJSON, err := os.ReadFile(opts.filePath) if err != nil { return fmt.Errorf("failed to read trust policy file: %w", err) } - // parse and validate - var doc policy = &trustpolicy.OCIDocument{} - if !isOCIPolicy { - doc = &trustpolicy.BlobDocument{} - } + doc := &trustpolicy.BlobDocument{} if err = json.Unmarshal(policyJSON, doc); err != nil { return fmt.Errorf("failed to parse trust policy configuration: %w", err) } @@ -54,14 +71,10 @@ func Import(filePath string, force, isOCIPolicy bool) error { } // optional confirmation - if !force { - if isOCIPolicy { - _, err = trustpolicy.LoadDocument() - } else { - _, err = trustpolicy.LoadBlobDocument() - } + if !opts.force { + _, err = trustpolicy.LoadBlobDocument() if err == nil { - confirmed, err := cmdutil.AskForConfirmation(os.Stdin, "The trust policy file already exists, do you want to overwrite it?", force) + confirmed, err := cmdutil.AskForConfirmation(os.Stdin, "The trust policy file already exists, do you want to overwrite it?", opts.force) if err != nil { return err } @@ -74,11 +87,7 @@ func Import(filePath string, force, isOCIPolicy bool) error { } // write - trustPolicyName := dir.PathOCITrustPolicy - if !isOCIPolicy { - trustPolicyName = dir.PathBlobTrustPolicy - } - policyPath, err := dir.ConfigFS().SysPath(trustPolicyName) + policyPath, err := dir.ConfigFS().SysPath(dir.PathBlobTrustPolicy) if err != nil { return fmt.Errorf("failed to obtain path of trust policy file: %w", err) } @@ -86,17 +95,6 @@ func Import(filePath string, force, isOCIPolicy bool) error { return fmt.Errorf("failed to write trust policy file: %w", err) } - // clear old trust policy - if isOCIPolicy { - oldPolicyPath, err := dir.ConfigFS().SysPath(dir.PathTrustPolicy) - if err != nil { - return fmt.Errorf("failed to obtain path of trust policy file: %w", err) - } - if err := osutil.RemoveIfExists(oldPolicyPath); err != nil { - fmt.Fprintf(os.Stderr, "Warning: failed to clear old trust policy %q: %v\n", oldPolicyPath, err) - } - } - _, err = fmt.Fprintln(os.Stdout, "Trust policy configuration imported successfully.") return err } diff --git a/cmd/notation/internal/policy/show.go b/cmd/notation/blob/policy/show.go similarity index 55% rename from cmd/notation/internal/policy/show.go rename to cmd/notation/blob/policy/show.go index b8b3b6a76..b0ec79160 100644 --- a/cmd/notation/internal/policy/show.go +++ b/cmd/notation/blob/policy/show.go @@ -23,38 +23,45 @@ import ( "github.com/notaryproject/notation-go/dir" "github.com/notaryproject/notation-go/verifier/trustpolicy" + "github.com/spf13/cobra" ) -// Show shows trust policy configuration. -// -// - If isOciPolicy is true, it will show OCI trust policy configuration. -// Otherwise, it will show blob trust policy configuration. -func Show(isOCIPolicy bool) error { - var ( - doc policy - policyJSON []byte - err error - ) - if isOCIPolicy { - doc = &trustpolicy.OCIDocument{} - policyJSON, err = loadOCIDocument() - } else { - doc = &trustpolicy.BlobDocument{} - policyJSON, err = loadBlobDocument() +func showCmd() *cobra.Command { + command := &cobra.Command{ + Use: "show [flags]", + Short: "show trust policy configuration", + Long: `Show blob trust policy configuration. + +Example - Show current blob trust policy configuration: + notation blob policy show + +Example - Save current blob trust policy configuration to a file: + notation blob policy show > my_policy.json +`, + Args: cobra.ExactArgs(0), + RunE: func(cmd *cobra.Command, args []string) error { + return runShow() + }, } + return command +} + +func runShow() error { + policyJSON, err := loadBlobDocument() if err != nil { if errors.Is(err, fs.ErrNotExist) { - return fmt.Errorf("failed to show trust policy as the trust policy file does not exist.\nYou can import one using `notation policy import `") + return fmt.Errorf("failed to show blob trust policy as the trust policy file does not exist.\nYou can import one using `notation blob policy import `") } return fmt.Errorf("failed to show trust policy: %w", err) } + doc := &trustpolicy.BlobDocument{} if err = json.Unmarshal(policyJSON, &doc); err == nil { err = doc.Validate() } if err != nil { fmt.Fprintf(os.Stderr, "Error: %s\n", err.Error()) - fmt.Fprintf(os.Stderr, "Existing trust policy configuration is invalid, you may update or create a new one via `notation policy import `\n") + fmt.Fprintf(os.Stderr, "Existing blob trust policy configuration is invalid, you may update or create a new one via `notation blob policy import `\n") // not returning to show the invalid policy configuration } @@ -63,21 +70,8 @@ func Show(isOCIPolicy bool) error { return err } -func loadOCIDocument() ([]byte, error) { - f, err := dir.ConfigFS().Open(dir.PathOCITrustPolicy) - if err != nil { - if !os.IsNotExist(err) { - return nil, err - } - f, err = dir.ConfigFS().Open(dir.PathTrustPolicy) - if err != nil { - return nil, err - } - } - defer f.Close() - return io.ReadAll(f) -} - +// loadBlobDocument loads the blob trust policy from notation configuration +// directory. func loadBlobDocument() ([]byte, error) { f, err := dir.ConfigFS().Open(dir.PathBlobTrustPolicy) if err != nil { diff --git a/cmd/notation/policy/cmd.go b/cmd/notation/policy/cmd.go index a8b646859..3e63070f4 100644 --- a/cmd/notation/policy/cmd.go +++ b/cmd/notation/policy/cmd.go @@ -11,6 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +// Package policy provides the import and show command for OCI trust policy. package policy import "github.com/spf13/cobra" diff --git a/cmd/notation/policy/import.go b/cmd/notation/policy/import.go index d7fba0f20..4aa0283dc 100644 --- a/cmd/notation/policy/import.go +++ b/cmd/notation/policy/import.go @@ -14,9 +14,14 @@ package policy import ( + "encoding/json" "fmt" + "os" - "github.com/notaryproject/notation/cmd/notation/internal/policy" + "github.com/notaryproject/notation-go/dir" + "github.com/notaryproject/notation-go/verifier/trustpolicy" + "github.com/notaryproject/notation/cmd/notation/internal/cmdutil" + "github.com/notaryproject/notation/internal/osutil" "github.com/spf13/cobra" ) @@ -45,9 +50,62 @@ Example - Import trust policy configuration from a file: }, RunE: func(cmd *cobra.Command, args []string) error { opts.filePath = args[0] - return policy.Import(opts.filePath, opts.force, true) + return runImport(opts) }, } command.Flags().BoolVar(&opts.force, "force", false, "override the existing trust policy configuration, never prompt") return command } + +func runImport(opts importOpts) error { + // read configuration + policyJSON, err := os.ReadFile(opts.filePath) + if err != nil { + return fmt.Errorf("failed to read trust policy file: %w", err) + } + + doc := &trustpolicy.OCIDocument{} + if err = json.Unmarshal(policyJSON, doc); err != nil { + return fmt.Errorf("failed to parse trust policy configuration: %w", err) + } + if err = doc.Validate(); err != nil { + return fmt.Errorf("failed to validate trust policy: %w", err) + } + + // optional confirmation + if !opts.force { + _, err = trustpolicy.LoadDocument() + if err == nil { + confirmed, err := cmdutil.AskForConfirmation(os.Stdin, "The trust policy file already exists, do you want to overwrite it?", opts.force) + if err != nil { + return err + } + if !confirmed { + return nil + } + } + } else { + fmt.Fprintln(os.Stderr, "Warning: existing trust policy configuration file will be overwritten") + } + + // write + policyPath, err := dir.ConfigFS().SysPath(dir.PathOCITrustPolicy) + if err != nil { + return fmt.Errorf("failed to obtain path of trust policy file: %w", err) + } + if err = osutil.WriteFile(policyPath, policyJSON); err != nil { + return fmt.Errorf("failed to write trust policy file: %w", err) + } + + // clear old trust policy + oldPolicyPath, err := dir.ConfigFS().SysPath(dir.PathTrustPolicy) + if err != nil { + return fmt.Errorf("failed to obtain path of trust policy file: %w", err) + } + if err := osutil.RemoveIfExists(oldPolicyPath); err != nil { + fmt.Fprintf(os.Stderr, "Warning: failed to clear old trust policy %q: %v\n", oldPolicyPath, err) + } + + _, err = fmt.Fprintln(os.Stdout, "Trust policy configuration imported successfully.") + return err +} diff --git a/cmd/notation/policy/show.go b/cmd/notation/policy/show.go index b1c46c929..edbaed80f 100644 --- a/cmd/notation/policy/show.go +++ b/cmd/notation/policy/show.go @@ -14,7 +14,15 @@ package policy import ( - "github.com/notaryproject/notation/cmd/notation/internal/policy" + "encoding/json" + "errors" + "fmt" + "io" + "io/fs" + "os" + + "github.com/notaryproject/notation-go/dir" + "github.com/notaryproject/notation-go/verifier/trustpolicy" "github.com/spf13/cobra" ) @@ -34,8 +42,51 @@ Example - Save current trust policy configuration to a file: `, Args: cobra.ExactArgs(0), RunE: func(cmd *cobra.Command, args []string) error { - return policy.Show(true) + return runShow() }, } return command } + +func runShow() error { + policyJSON, err := loadOCIDocument() + if err != nil { + if errors.Is(err, fs.ErrNotExist) { + return fmt.Errorf("failed to show trust policy as the trust policy file does not exist.\nYou can import one using `notation policy import `") + } + return fmt.Errorf("failed to show trust policy: %w", err) + } + + doc := &trustpolicy.OCIDocument{} + if err = json.Unmarshal(policyJSON, &doc); err == nil { + err = doc.Validate() + } + if err != nil { + fmt.Fprintf(os.Stderr, "Error: %s\n", err.Error()) + fmt.Fprintf(os.Stderr, "Existing trust policy configuration is invalid, you may update or create a new one via `notation policy import `\n") + // not returning to show the invalid policy configuration + } + + // show policy content + _, err = os.Stdout.Write(policyJSON) + return err +} + +// loadOCIDocument loads OCI trust policy from notation configuration directory. +// +// It tries to load OCI trust policy (trustpolicy.oci.json) first, if it does +// not exist, it falls back to old trust policy (trustpolicy.json). +func loadOCIDocument() ([]byte, error) { + f, err := dir.ConfigFS().Open(dir.PathOCITrustPolicy) + if err != nil { + if !os.IsNotExist(err) { + return nil, err + } + f, err = dir.ConfigFS().Open(dir.PathTrustPolicy) + if err != nil { + return nil, err + } + } + defer f.Close() + return io.ReadAll(f) +} diff --git a/test/e2e/suite/command/blob/policy.go b/test/e2e/suite/command/blob/policy.go index 8328af50f..1214270b9 100644 --- a/test/e2e/suite/command/blob/policy.go +++ b/test/e2e/suite/command/blob/policy.go @@ -32,7 +32,7 @@ var _ = Describe("blob trust policy maintainer", func() { Host(Opts(), func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { notation.ExpectFailure(). Exec("blob", "policy", "show"). - MatchErrKeyWords("failed to show trust policy", "notation policy import") + MatchErrKeyWords("failed to show blob trust policy", "notation blob policy import") }) }) @@ -61,7 +61,7 @@ var _ = Describe("blob trust policy maintainer", func() { Expect(err).NotTo(HaveOccurred()) Host(Opts(AddBlobTrustPolicyOption(policyName)), func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { notation.Exec("blob", "policy", "show"). - MatchErrKeyWords("existing trust policy configuration is invalid"). + MatchErrKeyWords("existing blob trust policy configuration is invalid"). MatchContent(string(content)) }) }) From b1ed2fac28139a1766b77ec3551d541a1460b0ce Mon Sep 17 00:00:00 2001 From: Junjie Gao Date: Fri, 27 Dec 2024 07:41:53 +0000 Subject: [PATCH 09/24] fix: simplify code Signed-off-by: Junjie Gao --- cmd/notation/blob/cmd.go | 2 +- cmd/notation/blob/policy/import.go | 7 +++---- cmd/notation/blob/policy/show.go | 2 +- cmd/notation/policy/import.go | 8 ++++---- cmd/notation/policy/show.go | 2 +- 5 files changed, 10 insertions(+), 11 deletions(-) diff --git a/cmd/notation/blob/cmd.go b/cmd/notation/blob/cmd.go index f23cecf6d..4a83becfc 100644 --- a/cmd/notation/blob/cmd.go +++ b/cmd/notation/blob/cmd.go @@ -23,7 +23,7 @@ import ( func Cmd() *cobra.Command { command := &cobra.Command{ Use: "blob [commnad]", - Short: "Sign, verify and inspect singatures associated with blobs", + Short: "Sign, verify and inspect signatures associated with blobs", Long: "Sign, inspect, and verify signatures and configure trust policies.", } diff --git a/cmd/notation/blob/policy/import.go b/cmd/notation/blob/policy/import.go index c71ec585b..b1277d425 100644 --- a/cmd/notation/blob/policy/import.go +++ b/cmd/notation/blob/policy/import.go @@ -62,8 +62,8 @@ func runImport(opts importOpts) error { return fmt.Errorf("failed to read trust policy file: %w", err) } - doc := &trustpolicy.BlobDocument{} - if err = json.Unmarshal(policyJSON, doc); err != nil { + var doc trustpolicy.BlobDocument + if err = json.Unmarshal(policyJSON, &doc); err != nil { return fmt.Errorf("failed to parse trust policy configuration: %w", err) } if err = doc.Validate(); err != nil { @@ -72,8 +72,7 @@ func runImport(opts importOpts) error { // optional confirmation if !opts.force { - _, err = trustpolicy.LoadBlobDocument() - if err == nil { + if _, err = trustpolicy.LoadBlobDocument(); err == nil { confirmed, err := cmdutil.AskForConfirmation(os.Stdin, "The trust policy file already exists, do you want to overwrite it?", opts.force) if err != nil { return err diff --git a/cmd/notation/blob/policy/show.go b/cmd/notation/blob/policy/show.go index b0ec79160..c7c5955ec 100644 --- a/cmd/notation/blob/policy/show.go +++ b/cmd/notation/blob/policy/show.go @@ -55,7 +55,7 @@ func runShow() error { return fmt.Errorf("failed to show trust policy: %w", err) } - doc := &trustpolicy.BlobDocument{} + var doc trustpolicy.BlobDocument if err = json.Unmarshal(policyJSON, &doc); err == nil { err = doc.Validate() } diff --git a/cmd/notation/policy/import.go b/cmd/notation/policy/import.go index 4aa0283dc..1e1f3191b 100644 --- a/cmd/notation/policy/import.go +++ b/cmd/notation/policy/import.go @@ -64,8 +64,9 @@ func runImport(opts importOpts) error { return fmt.Errorf("failed to read trust policy file: %w", err) } - doc := &trustpolicy.OCIDocument{} - if err = json.Unmarshal(policyJSON, doc); err != nil { + // parse and validate + var doc trustpolicy.Document + if err = json.Unmarshal(policyJSON, &doc); err != nil { return fmt.Errorf("failed to parse trust policy configuration: %w", err) } if err = doc.Validate(); err != nil { @@ -74,8 +75,7 @@ func runImport(opts importOpts) error { // optional confirmation if !opts.force { - _, err = trustpolicy.LoadDocument() - if err == nil { + if _, err := trustpolicy.LoadOCIDocument(); err == nil { confirmed, err := cmdutil.AskForConfirmation(os.Stdin, "The trust policy file already exists, do you want to overwrite it?", opts.force) if err != nil { return err diff --git a/cmd/notation/policy/show.go b/cmd/notation/policy/show.go index edbaed80f..758aedfbc 100644 --- a/cmd/notation/policy/show.go +++ b/cmd/notation/policy/show.go @@ -57,7 +57,7 @@ func runShow() error { return fmt.Errorf("failed to show trust policy: %w", err) } - doc := &trustpolicy.OCIDocument{} + var doc trustpolicy.Document if err = json.Unmarshal(policyJSON, &doc); err == nil { err = doc.Validate() } From 91be43c4694b533483ed6c697f2cd35d62b6a0c1 Mon Sep 17 00:00:00 2001 From: Junjie Gao Date: Fri, 27 Dec 2024 07:46:20 +0000 Subject: [PATCH 10/24] fix: simplify code Signed-off-by: Junjie Gao --- cmd/notation/blob/policy/show.go | 1 - cmd/notation/policy/show.go | 1 - 2 files changed, 2 deletions(-) diff --git a/cmd/notation/blob/policy/show.go b/cmd/notation/blob/policy/show.go index c7c5955ec..eccea6a37 100644 --- a/cmd/notation/blob/policy/show.go +++ b/cmd/notation/blob/policy/show.go @@ -54,7 +54,6 @@ func runShow() error { } return fmt.Errorf("failed to show trust policy: %w", err) } - var doc trustpolicy.BlobDocument if err = json.Unmarshal(policyJSON, &doc); err == nil { err = doc.Validate() diff --git a/cmd/notation/policy/show.go b/cmd/notation/policy/show.go index 758aedfbc..c4d1e6055 100644 --- a/cmd/notation/policy/show.go +++ b/cmd/notation/policy/show.go @@ -56,7 +56,6 @@ func runShow() error { } return fmt.Errorf("failed to show trust policy: %w", err) } - var doc trustpolicy.Document if err = json.Unmarshal(policyJSON, &doc); err == nil { err = doc.Validate() From d70dd18889118f725a328c05753077da2619677a Mon Sep 17 00:00:00 2001 From: Junjie Gao Date: Fri, 27 Dec 2024 08:01:55 +0000 Subject: [PATCH 11/24] fix: update error message Signed-off-by: Junjie Gao --- cmd/notation/blob/policy/import.go | 16 ++++++++-------- test/e2e/suite/command/blob/policy.go | 6 +++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/cmd/notation/blob/policy/import.go b/cmd/notation/blob/policy/import.go index b1277d425..25ac1485c 100644 --- a/cmd/notation/blob/policy/import.go +++ b/cmd/notation/blob/policy/import.go @@ -59,21 +59,21 @@ func runImport(opts importOpts) error { // read configuration policyJSON, err := os.ReadFile(opts.filePath) if err != nil { - return fmt.Errorf("failed to read trust policy file: %w", err) + return fmt.Errorf("failed to read blob trust policy file: %w", err) } var doc trustpolicy.BlobDocument if err = json.Unmarshal(policyJSON, &doc); err != nil { - return fmt.Errorf("failed to parse trust policy configuration: %w", err) + return fmt.Errorf("failed to parse blob trust policy configuration: %w", err) } if err = doc.Validate(); err != nil { - return fmt.Errorf("failed to validate trust policy: %w", err) + return fmt.Errorf("failed to validate blob trust policy: %w", err) } // optional confirmation if !opts.force { if _, err = trustpolicy.LoadBlobDocument(); err == nil { - confirmed, err := cmdutil.AskForConfirmation(os.Stdin, "The trust policy file already exists, do you want to overwrite it?", opts.force) + confirmed, err := cmdutil.AskForConfirmation(os.Stdin, "The blob trust policy file already exists, do you want to overwrite it?", opts.force) if err != nil { return err } @@ -82,18 +82,18 @@ func runImport(opts importOpts) error { } } } else { - fmt.Fprintln(os.Stderr, "Warning: existing trust policy configuration file will be overwritten") + fmt.Fprintln(os.Stderr, "Warning: existing blob trust policy configuration file will be overwritten") } // write policyPath, err := dir.ConfigFS().SysPath(dir.PathBlobTrustPolicy) if err != nil { - return fmt.Errorf("failed to obtain path of trust policy file: %w", err) + return fmt.Errorf("failed to obtain path of blob trust policy file: %w", err) } if err = osutil.WriteFile(policyPath, policyJSON); err != nil { - return fmt.Errorf("failed to write trust policy file: %w", err) + return fmt.Errorf("failed to write blob trust policy file: %w", err) } - _, err = fmt.Fprintln(os.Stdout, "Trust policy configuration imported successfully.") + _, err = fmt.Fprintln(os.Stdout, "Blob trust policy configuration imported successfully.") return err } diff --git a/test/e2e/suite/command/blob/policy.go b/test/e2e/suite/command/blob/policy.go index 1214270b9..06b35e31b 100644 --- a/test/e2e/suite/command/blob/policy.go +++ b/test/e2e/suite/command/blob/policy.go @@ -168,7 +168,7 @@ var _ = Describe("blob trust policy maintainer", func() { Host(Opts(AddBlobTrustPolicyOption("invalid_format_trustpolicy.json")), func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { policyFileName := "skip_trustpolicy.json" notation.Exec("blob", "policy", "import", filepath.Join(NotationE2ETrustPolicyDir, policyFileName)).MatchKeyWords(). - MatchKeyWords("Trust policy configuration imported successfully.") + MatchKeyWords("Blob trust policy configuration imported successfully.") // validate content, err := os.ReadFile(filepath.Join(NotationE2ETrustPolicyDir, policyFileName)) Expect(err).NotTo(HaveOccurred()) @@ -180,7 +180,7 @@ var _ = Describe("blob trust policy maintainer", func() { Host(opts, func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { policyFileName := "skip_trustpolicy.json" notation.WithInput(strings.NewReader("Y\n")).Exec("blob", "policy", "import", filepath.Join(NotationE2ETrustPolicyDir, policyFileName)). - MatchKeyWords("Trust policy configuration imported successfully.") + MatchKeyWords("Blob trust policy configuration imported successfully.") // validate content, err := os.ReadFile(filepath.Join(NotationE2ETrustPolicyDir, policyFileName)) Expect(err).NotTo(HaveOccurred()) @@ -192,7 +192,7 @@ var _ = Describe("blob trust policy maintainer", func() { Host(opts, func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { policyFileName := "skip_trustpolicy.json" notation.Exec("blob", "policy", "import", filepath.Join(NotationE2ETrustPolicyDir, policyFileName), "--force"). - MatchKeyWords("Trust policy configuration imported successfully.") + MatchKeyWords("Blob trust policy configuration imported successfully.") // validate content, err := os.ReadFile(filepath.Join(NotationE2ETrustPolicyDir, policyFileName)) Expect(err).NotTo(HaveOccurred()) From 62c874c9b93f1ceaff2626d2deaeb536427024f9 Mon Sep 17 00:00:00 2001 From: Junjie Gao Date: Fri, 27 Dec 2024 08:05:50 +0000 Subject: [PATCH 12/24] fix: optimize readability Signed-off-by: Junjie Gao --- cmd/notation/blob/policy/cmd.go | 2 +- cmd/notation/blob/policy/show.go | 6 +++--- cmd/notation/policy/show.go | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cmd/notation/blob/policy/cmd.go b/cmd/notation/blob/policy/cmd.go index 002f0ef7e..4e25c156c 100644 --- a/cmd/notation/blob/policy/cmd.go +++ b/cmd/notation/blob/policy/cmd.go @@ -18,7 +18,7 @@ import ( "github.com/spf13/cobra" ) -// Cmd returns the command for policy including import and show. +// Cmd returns the commands for policy including import and show. func Cmd() *cobra.Command { command := &cobra.Command{ Use: "policy [command]", diff --git a/cmd/notation/blob/policy/show.go b/cmd/notation/blob/policy/show.go index eccea6a37..713bf2057 100644 --- a/cmd/notation/blob/policy/show.go +++ b/cmd/notation/blob/policy/show.go @@ -47,7 +47,7 @@ Example - Save current blob trust policy configuration to a file: } func runShow() error { - policyJSON, err := loadBlobDocument() + policyJSON, err := loadBlobTrustPolicy() if err != nil { if errors.Is(err, fs.ErrNotExist) { return fmt.Errorf("failed to show blob trust policy as the trust policy file does not exist.\nYou can import one using `notation blob policy import `") @@ -69,9 +69,9 @@ func runShow() error { return err } -// loadBlobDocument loads the blob trust policy from notation configuration +// loadBlobTrustPolicy loads the blob trust policy from notation configuration // directory. -func loadBlobDocument() ([]byte, error) { +func loadBlobTrustPolicy() ([]byte, error) { f, err := dir.ConfigFS().Open(dir.PathBlobTrustPolicy) if err != nil { return nil, err diff --git a/cmd/notation/policy/show.go b/cmd/notation/policy/show.go index c4d1e6055..1ee98b007 100644 --- a/cmd/notation/policy/show.go +++ b/cmd/notation/policy/show.go @@ -49,7 +49,7 @@ Example - Save current trust policy configuration to a file: } func runShow() error { - policyJSON, err := loadOCIDocument() + policyJSON, err := loadOCITrustPolicy() if err != nil { if errors.Is(err, fs.ErrNotExist) { return fmt.Errorf("failed to show trust policy as the trust policy file does not exist.\nYou can import one using `notation policy import `") @@ -71,11 +71,11 @@ func runShow() error { return err } -// loadOCIDocument loads OCI trust policy from notation configuration directory. +// loadOCITrustPolicy loads OCI trust policy from notation configuration directory. // // It tries to load OCI trust policy (trustpolicy.oci.json) first, if it does // not exist, it falls back to old trust policy (trustpolicy.json). -func loadOCIDocument() ([]byte, error) { +func loadOCITrustPolicy() ([]byte, error) { f, err := dir.ConfigFS().Open(dir.PathOCITrustPolicy) if err != nil { if !os.IsNotExist(err) { From 3494909e5e08ef488697847022f86b9d363fa735 Mon Sep 17 00:00:00 2001 From: Junjie Gao Date: Fri, 27 Dec 2024 08:10:25 +0000 Subject: [PATCH 13/24] fix: improve readability Signed-off-by: Junjie Gao --- cmd/notation/blob/policy/show.go | 4 +--- cmd/notation/policy/show.go | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/cmd/notation/blob/policy/show.go b/cmd/notation/blob/policy/show.go index 713bf2057..dd9a1b862 100644 --- a/cmd/notation/blob/policy/show.go +++ b/cmd/notation/blob/policy/show.go @@ -15,10 +15,8 @@ package policy import ( "encoding/json" - "errors" "fmt" "io" - "io/fs" "os" "github.com/notaryproject/notation-go/dir" @@ -49,7 +47,7 @@ Example - Save current blob trust policy configuration to a file: func runShow() error { policyJSON, err := loadBlobTrustPolicy() if err != nil { - if errors.Is(err, fs.ErrNotExist) { + if os.IsNotExist(err) { return fmt.Errorf("failed to show blob trust policy as the trust policy file does not exist.\nYou can import one using `notation blob policy import `") } return fmt.Errorf("failed to show trust policy: %w", err) diff --git a/cmd/notation/policy/show.go b/cmd/notation/policy/show.go index 1ee98b007..9d9c70896 100644 --- a/cmd/notation/policy/show.go +++ b/cmd/notation/policy/show.go @@ -15,10 +15,8 @@ package policy import ( "encoding/json" - "errors" "fmt" "io" - "io/fs" "os" "github.com/notaryproject/notation-go/dir" @@ -51,7 +49,7 @@ Example - Save current trust policy configuration to a file: func runShow() error { policyJSON, err := loadOCITrustPolicy() if err != nil { - if errors.Is(err, fs.ErrNotExist) { + if os.IsNotExist(err) { return fmt.Errorf("failed to show trust policy as the trust policy file does not exist.\nYou can import one using `notation policy import `") } return fmt.Errorf("failed to show trust policy: %w", err) From 5ab618b1e9dab7081245ccc989ff6b1f55b392ff Mon Sep 17 00:00:00 2001 From: Junjie Gao Date: Mon, 30 Dec 2024 03:15:07 +0000 Subject: [PATCH 14/24] fix: replace os.IsNotExist(err) with errors.Is(err, fs.ErrNotExist) Signed-off-by: Junjie Gao --- cmd/notation/blob/policy/import.go | 2 +- cmd/notation/blob/policy/show.go | 6 ++++-- cmd/notation/policy/show.go | 6 ++++-- internal/osutil/file.go | 3 ++- internal/osutil/file_test.go | 4 +++- test/e2e/internal/utils/validator/validator.go | 4 +++- test/e2e/suite/command/policy.go | 4 +++- 7 files changed, 20 insertions(+), 9 deletions(-) diff --git a/cmd/notation/blob/policy/import.go b/cmd/notation/blob/policy/import.go index 25ac1485c..0406768ea 100644 --- a/cmd/notation/blob/policy/import.go +++ b/cmd/notation/blob/policy/import.go @@ -34,7 +34,7 @@ func importCmd() *cobra.Command { var opts importOpts command := &cobra.Command{ Use: "import [flags] ", - Short: "import trust policy configuration from a JSON file", + Short: "Import trust policy configuration from a JSON file", Long: `Import blob trust policy configuration from a JSON file. Example - Import trust policy configuration from a file: diff --git a/cmd/notation/blob/policy/show.go b/cmd/notation/blob/policy/show.go index dd9a1b862..f8d9872ea 100644 --- a/cmd/notation/blob/policy/show.go +++ b/cmd/notation/blob/policy/show.go @@ -15,8 +15,10 @@ package policy import ( "encoding/json" + "errors" "fmt" "io" + "io/fs" "os" "github.com/notaryproject/notation-go/dir" @@ -27,7 +29,7 @@ import ( func showCmd() *cobra.Command { command := &cobra.Command{ Use: "show [flags]", - Short: "show trust policy configuration", + Short: "Show trust policy configuration", Long: `Show blob trust policy configuration. Example - Show current blob trust policy configuration: @@ -47,7 +49,7 @@ Example - Save current blob trust policy configuration to a file: func runShow() error { policyJSON, err := loadBlobTrustPolicy() if err != nil { - if os.IsNotExist(err) { + if errors.Is(err, fs.ErrNotExist) { return fmt.Errorf("failed to show blob trust policy as the trust policy file does not exist.\nYou can import one using `notation blob policy import `") } return fmt.Errorf("failed to show trust policy: %w", err) diff --git a/cmd/notation/policy/show.go b/cmd/notation/policy/show.go index 9d9c70896..5bce6a5b2 100644 --- a/cmd/notation/policy/show.go +++ b/cmd/notation/policy/show.go @@ -15,8 +15,10 @@ package policy import ( "encoding/json" + "errors" "fmt" "io" + "io/fs" "os" "github.com/notaryproject/notation-go/dir" @@ -49,7 +51,7 @@ Example - Save current trust policy configuration to a file: func runShow() error { policyJSON, err := loadOCITrustPolicy() if err != nil { - if os.IsNotExist(err) { + if errors.Is(err, fs.ErrNotExist) { return fmt.Errorf("failed to show trust policy as the trust policy file does not exist.\nYou can import one using `notation policy import `") } return fmt.Errorf("failed to show trust policy: %w", err) @@ -76,7 +78,7 @@ func runShow() error { func loadOCITrustPolicy() ([]byte, error) { f, err := dir.ConfigFS().Open(dir.PathOCITrustPolicy) if err != nil { - if !os.IsNotExist(err) { + if !errors.Is(err, fs.ErrNotExist) { return nil, err } f, err = dir.ConfigFS().Open(dir.PathTrustPolicy) diff --git a/internal/osutil/file.go b/internal/osutil/file.go index d85390f5f..1242f0941 100644 --- a/internal/osutil/file.go +++ b/internal/osutil/file.go @@ -16,6 +16,7 @@ package osutil import ( "crypto/sha256" "encoding/hex" + "errors" "fmt" "io" "io/fs" @@ -63,7 +64,7 @@ func WriteFileWithPermission(path string, data []byte, perm fs.FileMode, overwri // RemoveIfExists removes a file if it exists. func RemoveIfExists(filepath string) error { if _, err := os.Stat(filepath); err != nil { - if os.IsNotExist(err) { + if errors.Is(err, fs.ErrNotExist) { return nil } return err diff --git a/internal/osutil/file_test.go b/internal/osutil/file_test.go index d22d509a5..8d5865b8a 100644 --- a/internal/osutil/file_test.go +++ b/internal/osutil/file_test.go @@ -15,6 +15,8 @@ package osutil import ( "bytes" + "errors" + "io/fs" "os" "path/filepath" "runtime" @@ -281,7 +283,7 @@ func TestRemoveIfExists(t *testing.T) { if err := RemoveIfExists(filename); err != nil { t.Fatal(err) } - if _, err := os.Stat(filename); !os.IsNotExist(err) { + if _, err := os.Stat(filename); !errors.Is(err, fs.ErrNotExist) { t.Fatal("file should be removed") } }) diff --git a/test/e2e/internal/utils/validator/validator.go b/test/e2e/internal/utils/validator/validator.go index d6d793754..194f265da 100644 --- a/test/e2e/internal/utils/validator/validator.go +++ b/test/e2e/internal/utils/validator/validator.go @@ -14,6 +14,8 @@ package validator import ( + "errors" + "io/fs" "os" . "github.com/onsi/gomega" @@ -29,5 +31,5 @@ func CheckFileExist(f string) { func CheckFileNotExist(f string) { _, err := os.Stat(f) Expect(err).Should(HaveOccurred()) - Expect(os.IsNotExist(err)).To(BeTrue()) + Expect(errors.Is(err, fs.ErrNotExist)).To(BeTrue()) } diff --git a/test/e2e/suite/command/policy.go b/test/e2e/suite/command/policy.go index 8464dbc8b..b1d31c714 100644 --- a/test/e2e/suite/command/policy.go +++ b/test/e2e/suite/command/policy.go @@ -14,6 +14,8 @@ package command import ( + "errors" + "io/fs" "os" "path/filepath" "strings" @@ -267,7 +269,7 @@ var _ = Describe("trust policy maintainer", func() { // check old policy doesn't exist oldPolicyPath := vhost.AbsolutePath(NotationDirName, "trustpolicy.json") _, err = os.Stat(oldPolicyPath) - Expect(os.IsNotExist(err)).To(BeTrue()) + Expect(errors.Is(err, fs.ErrNotExist)).To(BeTrue()) }) }) }) From cf1fc19456880a6ceb7b5799f94bab94abaf5261 Mon Sep 17 00:00:00 2001 From: Junjie Gao Date: Mon, 30 Dec 2024 03:17:10 +0000 Subject: [PATCH 15/24] fix: update help doc Signed-off-by: Junjie Gao --- cmd/notation/blob/policy/cmd.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/notation/blob/policy/cmd.go b/cmd/notation/blob/policy/cmd.go index 4e25c156c..595270649 100644 --- a/cmd/notation/blob/policy/cmd.go +++ b/cmd/notation/blob/policy/cmd.go @@ -22,7 +22,7 @@ import ( func Cmd() *cobra.Command { command := &cobra.Command{ Use: "policy [command]", - Short: "manage trust policy configuration for signed blobs", + Short: "Manage trust policy configuration for signed blobs", Long: "Manage trust policy configuration for arbitrary blob signature verification.", } From 8ecf320cbd59be070c2096dc85765ba60dffc4e3 Mon Sep 17 00:00:00 2001 From: Junjie Gao Date: Mon, 30 Dec 2024 03:39:14 +0000 Subject: [PATCH 16/24] fix: add E2E test cases Signed-off-by: Junjie Gao --- test/e2e/suite/command/blob/policy.go | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/test/e2e/suite/command/blob/policy.go b/test/e2e/suite/command/blob/policy.go index 06b35e31b..68af357c9 100644 --- a/test/e2e/suite/command/blob/policy.go +++ b/test/e2e/suite/command/blob/policy.go @@ -111,6 +111,28 @@ var _ = Describe("blob trust policy maintainer", func() { notation.Exec("blob", "policy", "import", filepath.Join(NotationE2ETrustPolicyDir, validBlobTrustPolicyName), "--force") }) }) + + It("should failed if without permission to write policy", func() { + Host(opts, func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { + notation. + Exec("blob", "policy", "import", filepath.Join(NotationE2ETrustPolicyDir, validBlobTrustPolicyName)) + + trustPolicyPath := vhost.AbsolutePath(NotationDirName) + os.Chmod(trustPolicyPath, 0000) + defer os.Chmod(trustPolicyPath, 0755) + + notation.ExpectFailure(). + Exec("blob", "policy", "import", filepath.Join(NotationE2ETrustPolicyDir, validBlobTrustPolicyName), "--force"). + MatchErrKeyWords("failed to write blob trust policy file") + }) + }) + + It("should failed if provide file is malformed json", func() { + Host(opts, func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { + notation.ExpectFailure(). + Exec("blob", "policy", "import", filepath.Join(NotationE2ETrustPolicyDir, "invalid_format_trustpolicy.json")) + }) + }) }) When("importing configuration with existing trust policy configuration", func() { From b595f640f7effb3f5df2722e6af4bb0e97d7739f Mon Sep 17 00:00:00 2001 From: Junjie Gao Date: Mon, 30 Dec 2024 07:26:02 +0000 Subject: [PATCH 17/24] fix: resolve comments Signed-off-by: Junjie Gao --- cmd/notation/blob/cmd.go | 2 +- cmd/notation/blob/policy/import.go | 6 +++--- cmd/notation/blob/policy/show.go | 6 +++--- cmd/notation/policy/import.go | 4 ++-- cmd/notation/policy/show.go | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/cmd/notation/blob/cmd.go b/cmd/notation/blob/cmd.go index 4a83becfc..c491b81fb 100644 --- a/cmd/notation/blob/cmd.go +++ b/cmd/notation/blob/cmd.go @@ -11,7 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package blob provides the command for blob trust policy configuration. +// Package blob provides blob sign, verify, inspect, and policy commands. package blob import ( diff --git a/cmd/notation/blob/policy/import.go b/cmd/notation/blob/policy/import.go index 0406768ea..6391b975c 100644 --- a/cmd/notation/blob/policy/import.go +++ b/cmd/notation/blob/policy/import.go @@ -51,7 +51,7 @@ Example - Import trust policy configuration from a file: return runImport(opts) }, } - command.Flags().BoolVar(&opts.force, "force", false, "override the existing trust policy configuration, never prompt") + command.Flags().BoolVar(&opts.force, "force", false, "override the existing blob trust policy configuration, never prompt") return command } @@ -82,7 +82,7 @@ func runImport(opts importOpts) error { } } } else { - fmt.Fprintln(os.Stderr, "Warning: existing blob trust policy configuration file will be overwritten") + fmt.Fprintln(os.Stderr, "Warning: existing blob trust policy file will be overwritten") } // write @@ -94,6 +94,6 @@ func runImport(opts importOpts) error { return fmt.Errorf("failed to write blob trust policy file: %w", err) } - _, err = fmt.Fprintln(os.Stdout, "Blob trust policy configuration imported successfully.") + _, err = fmt.Fprintln(os.Stdout, "Successfully imported blob trust policy file.") return err } diff --git a/cmd/notation/blob/policy/show.go b/cmd/notation/blob/policy/show.go index f8d9872ea..38b7f5380 100644 --- a/cmd/notation/blob/policy/show.go +++ b/cmd/notation/blob/policy/show.go @@ -59,9 +59,9 @@ func runShow() error { err = doc.Validate() } if err != nil { - fmt.Fprintf(os.Stderr, "Error: %s\n", err.Error()) - fmt.Fprintf(os.Stderr, "Existing blob trust policy configuration is invalid, you may update or create a new one via `notation blob policy import `\n") - // not returning to show the invalid policy configuration + fmt.Fprintf(os.Stderr, "Existing blob trust policy file is invalid, you may update or create a new one via `notation blob policy import `\n") + os.Stdout.Write(policyJSON) + return err } // show policy content diff --git a/cmd/notation/policy/import.go b/cmd/notation/policy/import.go index 1e1f3191b..b6a5110df 100644 --- a/cmd/notation/policy/import.go +++ b/cmd/notation/policy/import.go @@ -85,7 +85,7 @@ func runImport(opts importOpts) error { } } } else { - fmt.Fprintln(os.Stderr, "Warning: existing trust policy configuration file will be overwritten") + fmt.Fprintln(os.Stderr, "Warning: existing trust policy file will be overwritten") } // write @@ -106,6 +106,6 @@ func runImport(opts importOpts) error { fmt.Fprintf(os.Stderr, "Warning: failed to clear old trust policy %q: %v\n", oldPolicyPath, err) } - _, err = fmt.Fprintln(os.Stdout, "Trust policy configuration imported successfully.") + _, err = fmt.Fprintln(os.Stdout, "Successfully imported trust policy file.") return err } diff --git a/cmd/notation/policy/show.go b/cmd/notation/policy/show.go index 5bce6a5b2..7e5461b31 100644 --- a/cmd/notation/policy/show.go +++ b/cmd/notation/policy/show.go @@ -62,7 +62,7 @@ func runShow() error { } if err != nil { fmt.Fprintf(os.Stderr, "Error: %s\n", err.Error()) - fmt.Fprintf(os.Stderr, "Existing trust policy configuration is invalid, you may update or create a new one via `notation policy import `\n") + fmt.Fprintf(os.Stderr, "Existing trust policy file is invalid, you may update or create a new one via `notation policy import `\n") // not returning to show the invalid policy configuration } From 43878ed1267736cea28c8415cc3f8bf213c4b232 Mon Sep 17 00:00:00 2001 From: Junjie Gao Date: Mon, 30 Dec 2024 07:29:59 +0000 Subject: [PATCH 18/24] fix: remove the change of oci policy commands Signed-off-by: Junjie Gao --- cmd/notation/policy/cmd.go | 1 - cmd/notation/policy/import.go | 22 +++------ cmd/notation/policy/show.go | 39 ++++++---------- test/e2e/internal/notation/init.go | 1 - test/e2e/suite/command/policy.go | 75 +----------------------------- 5 files changed, 22 insertions(+), 116 deletions(-) diff --git a/cmd/notation/policy/cmd.go b/cmd/notation/policy/cmd.go index 3e63070f4..a8b646859 100644 --- a/cmd/notation/policy/cmd.go +++ b/cmd/notation/policy/cmd.go @@ -11,7 +11,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package policy provides the import and show command for OCI trust policy. package policy import "github.com/spf13/cobra" diff --git a/cmd/notation/policy/import.go b/cmd/notation/policy/import.go index b6a5110df..ec3d3e854 100644 --- a/cmd/notation/policy/import.go +++ b/cmd/notation/policy/import.go @@ -50,14 +50,14 @@ Example - Import trust policy configuration from a file: }, RunE: func(cmd *cobra.Command, args []string) error { opts.filePath = args[0] - return runImport(opts) + return runImport(cmd, opts) }, } command.Flags().BoolVar(&opts.force, "force", false, "override the existing trust policy configuration, never prompt") return command } -func runImport(opts importOpts) error { +func runImport(command *cobra.Command, opts importOpts) error { // read configuration policyJSON, err := os.ReadFile(opts.filePath) if err != nil { @@ -75,7 +75,7 @@ func runImport(opts importOpts) error { // optional confirmation if !opts.force { - if _, err := trustpolicy.LoadOCIDocument(); err == nil { + if _, err := trustpolicy.LoadDocument(); err == nil { confirmed, err := cmdutil.AskForConfirmation(os.Stdin, "The trust policy file already exists, do you want to overwrite it?", opts.force) if err != nil { return err @@ -85,27 +85,17 @@ func runImport(opts importOpts) error { } } } else { - fmt.Fprintln(os.Stderr, "Warning: existing trust policy file will be overwritten") + fmt.Fprintln(os.Stderr, "Warning: existing trust policy configuration file will be overwritten") } // write - policyPath, err := dir.ConfigFS().SysPath(dir.PathOCITrustPolicy) + policyPath, err := dir.ConfigFS().SysPath(dir.PathTrustPolicy) if err != nil { return fmt.Errorf("failed to obtain path of trust policy file: %w", err) } if err = osutil.WriteFile(policyPath, policyJSON); err != nil { return fmt.Errorf("failed to write trust policy file: %w", err) } - - // clear old trust policy - oldPolicyPath, err := dir.ConfigFS().SysPath(dir.PathTrustPolicy) - if err != nil { - return fmt.Errorf("failed to obtain path of trust policy file: %w", err) - } - if err := osutil.RemoveIfExists(oldPolicyPath); err != nil { - fmt.Fprintf(os.Stderr, "Warning: failed to clear old trust policy %q: %v\n", oldPolicyPath, err) - } - - _, err = fmt.Fprintln(os.Stdout, "Successfully imported trust policy file.") + _, err = fmt.Fprintln(os.Stdout, "Trust policy configuration imported successfully.") return err } diff --git a/cmd/notation/policy/show.go b/cmd/notation/policy/show.go index 7e5461b31..dca73c942 100644 --- a/cmd/notation/policy/show.go +++ b/cmd/notation/policy/show.go @@ -17,7 +17,6 @@ import ( "encoding/json" "errors" "fmt" - "io" "io/fs" "os" @@ -26,7 +25,11 @@ import ( "github.com/spf13/cobra" ) +type showOpts struct { +} + func showCmd() *cobra.Command { + var opts showOpts command := &cobra.Command{ Use: "show [flags]", Short: "Show trust policy configuration", @@ -42,14 +45,21 @@ Example - Save current trust policy configuration to a file: `, Args: cobra.ExactArgs(0), RunE: func(cmd *cobra.Command, args []string) error { - return runShow() + return runShow(cmd, opts) }, } return command } -func runShow() error { - policyJSON, err := loadOCITrustPolicy() +func runShow(command *cobra.Command, opts showOpts) error { + // get policy file path + policyPath, err := dir.ConfigFS().SysPath(dir.PathTrustPolicy) + if err != nil { + return fmt.Errorf("failed to obtain path of trust policy file: %w", err) + } + + // core process + policyJSON, err := os.ReadFile(policyPath) if err != nil { if errors.Is(err, fs.ErrNotExist) { return fmt.Errorf("failed to show trust policy as the trust policy file does not exist.\nYou can import one using `notation policy import `") @@ -62,7 +72,7 @@ func runShow() error { } if err != nil { fmt.Fprintf(os.Stderr, "Error: %s\n", err.Error()) - fmt.Fprintf(os.Stderr, "Existing trust policy file is invalid, you may update or create a new one via `notation policy import `\n") + fmt.Fprintf(os.Stderr, "Existing trust policy configuration is invalid, you may update or create a new one via `notation policy import `\n") // not returning to show the invalid policy configuration } @@ -70,22 +80,3 @@ func runShow() error { _, err = os.Stdout.Write(policyJSON) return err } - -// loadOCITrustPolicy loads OCI trust policy from notation configuration directory. -// -// It tries to load OCI trust policy (trustpolicy.oci.json) first, if it does -// not exist, it falls back to old trust policy (trustpolicy.json). -func loadOCITrustPolicy() ([]byte, error) { - f, err := dir.ConfigFS().Open(dir.PathOCITrustPolicy) - if err != nil { - if !errors.Is(err, fs.ErrNotExist) { - return nil, err - } - f, err = dir.ConfigFS().Open(dir.PathTrustPolicy) - if err != nil { - return nil, err - } - } - defer f.Close() - return io.ReadAll(f) -} diff --git a/test/e2e/internal/notation/init.go b/test/e2e/internal/notation/init.go index d7a60320e..96a58d88d 100644 --- a/test/e2e/internal/notation/init.go +++ b/test/e2e/internal/notation/init.go @@ -25,7 +25,6 @@ import ( const ( NotationDirName = "notation" TrustPolicyName = "trustpolicy.json" - OCITrustPolicyName = "trustpolicy.oci.json" BlobTrustPolicyName = "trustpolicy.blob.json" TrustStoreDirName = "truststore" TrustStoreTypeCA = "ca" diff --git a/test/e2e/suite/command/policy.go b/test/e2e/suite/command/policy.go index b1d31c714..118939c58 100644 --- a/test/e2e/suite/command/policy.go +++ b/test/e2e/suite/command/policy.go @@ -14,8 +14,6 @@ package command import ( - "errors" - "io/fs" "os" "path/filepath" "strings" @@ -46,7 +44,7 @@ var _ = Describe("trust policy maintainer", func() { }) }) - It("should show exist old policy", func() { + It("should show exist policy", func() { content, err := os.ReadFile(filepath.Join(NotationE2ETrustPolicyDir, TrustPolicyName)) Expect(err).NotTo(HaveOccurred()) Host(Opts(AddTrustPolicyOption(TrustPolicyName)), func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { @@ -65,18 +63,6 @@ var _ = Describe("trust policy maintainer", func() { MatchContent(string(content)) }) }) - - It("should failed if without permission to read policy", func() { - Host(Opts(AddTrustPolicyOption(TrustPolicyName)), func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { - notationPath := vhost.AbsolutePath(NotationDirName) - os.Chmod(notationPath, 0000) - defer os.Chmod(notationPath, 0755) - - notation.ExpectFailure(). - Exec("policy", "show"). - MatchErrKeyWords("failed to show trust policy", "permission denied") - }) - }) }) When("importing configuration without existing trust policy configuration", func() { @@ -105,13 +91,6 @@ var _ = Describe("trust policy maintainer", func() { }) }) - It("should failed if provide file is malformed json", func() { - Host(opts, func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { - notation.ExpectFailure(). - Exec("policy", "import", filepath.Join(NotationE2ETrustPolicyDir, "invalid_format_trustpolicy.json")) - }) - }) - It("should fail if registry scope is malformed", func() { Host(opts, func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { notation.ExpectFailure(). @@ -144,21 +123,6 @@ var _ = Describe("trust policy maintainer", func() { notation.Exec("policy", "import", filepath.Join(NotationE2ETrustPolicyDir, TrustPolicyName), "--force") }) }) - - It("should failed if without permission to write policy", func() { - Host(opts, func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { - notation. - Exec("policy", "import", filepath.Join(NotationE2ETrustPolicyDir, TrustPolicyName)) - - trustPolicyPath := vhost.AbsolutePath(NotationDirName) - os.Chmod(trustPolicyPath, 0000) - defer os.Chmod(trustPolicyPath, 0755) - - notation.ExpectFailure(). - Exec("policy", "import", filepath.Join(NotationE2ETrustPolicyDir, TrustPolicyName), "--force"). - MatchErrKeyWords("failed to write trust policy file") - }) - }) }) When("importing configuration with existing trust policy configuration", func() { @@ -254,41 +218,4 @@ var _ = Describe("trust policy maintainer", func() { }) }) }) - - When("importing policy with existing old policy", func() { - It("should delete old policy", func() { - Host(Opts(AddTrustPolicyOption("trustpolicy.json")), func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { - newPolicyName := "any_registry_scope_trust_policy.json" - notation.WithInput(strings.NewReader("Y\n")).Exec("policy", "import", filepath.Join(NotationE2ETrustPolicyDir, newPolicyName)). - MatchKeyWords("Trust policy configuration imported successfully.") - // validate - content, err := os.ReadFile(filepath.Join(NotationE2ETrustPolicyDir, newPolicyName)) - Expect(err).NotTo(HaveOccurred()) - notation.Exec("policy", "show").MatchContent(string(content)) - - // check old policy doesn't exist - oldPolicyPath := vhost.AbsolutePath(NotationDirName, "trustpolicy.json") - _, err = os.Stat(oldPolicyPath) - Expect(errors.Is(err, fs.ErrNotExist)).To(BeTrue()) - }) - }) - }) - - When("showing policy when both the old and oci policy exist", func() { - It("should show the oci policy", func() { - Host(Opts(), func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { - // add oci policy - newPolicyName := "any_registry_scope_trust_policy.json" - notation.WithInput(strings.NewReader("Y\n")).Exec("policy", "import", filepath.Join(NotationE2ETrustPolicyDir, newPolicyName)). - MatchKeyWords("Trust policy configuration imported successfully.") - - // add old policy - vhost.SetOption(AddTrustPolicyOption("trustpolicy.json")) - - content, err := os.ReadFile(filepath.Join(NotationE2ETrustPolicyDir, newPolicyName)) - Expect(err).NotTo(HaveOccurred()) - notation.Exec("policy", "show").MatchContent(string(content)) - }) - }) - }) }) From fad665c5e8dada994def136c8ddc62efcb1e1117 Mon Sep 17 00:00:00 2001 From: Junjie Gao Date: Mon, 30 Dec 2024 07:33:44 +0000 Subject: [PATCH 19/24] fix: remove unused file Signed-off-by: Junjie Gao --- internal/osutil/file.go | 12 --------- internal/osutil/file_test.go | 47 ------------------------------------ 2 files changed, 59 deletions(-) diff --git a/internal/osutil/file.go b/internal/osutil/file.go index 1242f0941..06f69792a 100644 --- a/internal/osutil/file.go +++ b/internal/osutil/file.go @@ -16,7 +16,6 @@ package osutil import ( "crypto/sha256" "encoding/hex" - "errors" "fmt" "io" "io/fs" @@ -61,17 +60,6 @@ func WriteFileWithPermission(path string, data []byte, perm fs.FileMode, overwri return file.Close() } -// RemoveIfExists removes a file if it exists. -func RemoveIfExists(filepath string) error { - if _, err := os.Stat(filepath); err != nil { - if errors.Is(err, fs.ErrNotExist) { - return nil - } - return err - } - return os.Remove(filepath) -} - // CopyToDir copies the src file to dst. Existing file will be overwritten. func CopyToDir(src, dst string) (int64, error) { sourceFileStat, err := os.Stat(src) diff --git a/internal/osutil/file_test.go b/internal/osutil/file_test.go index 8d5865b8a..59226f9b1 100644 --- a/internal/osutil/file_test.go +++ b/internal/osutil/file_test.go @@ -15,8 +15,6 @@ package osutil import ( "bytes" - "errors" - "io/fs" "os" "path/filepath" "runtime" @@ -271,48 +269,3 @@ func TestValidateChecksum(t *testing.T) { t.Fatalf("expected nil err, but got %v", err) } } - -func TestRemoveIfExists(t *testing.T) { - t.Run("remove existing file", func(t *testing.T) { - tempDir := t.TempDir() - filename := filepath.Join(tempDir, "file.txt") - data := []byte("data") - if err := WriteFile(filename, data); err != nil { - t.Fatal(err) - } - if err := RemoveIfExists(filename); err != nil { - t.Fatal(err) - } - if _, err := os.Stat(filename); !errors.Is(err, fs.ErrNotExist) { - t.Fatal("file should be removed") - } - }) - - t.Run("remove non-existing file", func(t *testing.T) { - tempDir := t.TempDir() - filename := filepath.Join(tempDir, "file.txt") - if err := RemoveIfExists(filename); err != nil { - t.Fatal(err) - } - }) - - t.Run("remove file in directory without permission", func(t *testing.T) { - if runtime.GOOS == "windows" { - t.Skip("skipping test on Windows") - } - tempDir := t.TempDir() - filename := filepath.Join(tempDir, "file.txt") - data := []byte("data") - if err := WriteFile(filename, data); err != nil { - t.Fatal(err) - } - if err := os.Chmod(tempDir, 0000); err != nil { - t.Fatal(err) - } - defer os.Chmod(tempDir, 0700) - - if err := RemoveIfExists(filename); err == nil { - t.Fatal("expected an error when removing file from restricted directory") - } - }) -} From 71f522ae44175ae2b6bc443c1629d6aa6e791040 Mon Sep 17 00:00:00 2001 From: Junjie Gao Date: Mon, 30 Dec 2024 07:43:49 +0000 Subject: [PATCH 20/24] fix: E2E test Signed-off-by: Junjie Gao --- test/e2e/suite/command/blob/policy.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/e2e/suite/command/blob/policy.go b/test/e2e/suite/command/blob/policy.go index 68af357c9..f60b46dfd 100644 --- a/test/e2e/suite/command/blob/policy.go +++ b/test/e2e/suite/command/blob/policy.go @@ -60,8 +60,8 @@ var _ = Describe("blob trust policy maintainer", func() { content, err := os.ReadFile(filepath.Join(NotationE2ETrustPolicyDir, policyName)) Expect(err).NotTo(HaveOccurred()) Host(Opts(AddBlobTrustPolicyOption(policyName)), func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { - notation.Exec("blob", "policy", "show"). - MatchErrKeyWords("existing blob trust policy configuration is invalid"). + notation.ExpectFailure().Exec("blob", "policy", "show"). + MatchErrKeyWords("existing blob trust policy file is invalid"). MatchContent(string(content)) }) }) @@ -190,7 +190,7 @@ var _ = Describe("blob trust policy maintainer", func() { Host(Opts(AddBlobTrustPolicyOption("invalid_format_trustpolicy.json")), func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { policyFileName := "skip_trustpolicy.json" notation.Exec("blob", "policy", "import", filepath.Join(NotationE2ETrustPolicyDir, policyFileName)).MatchKeyWords(). - MatchKeyWords("Blob trust policy configuration imported successfully.") + MatchKeyWords("Successfully imported blob trust policy file.") // validate content, err := os.ReadFile(filepath.Join(NotationE2ETrustPolicyDir, policyFileName)) Expect(err).NotTo(HaveOccurred()) @@ -202,7 +202,7 @@ var _ = Describe("blob trust policy maintainer", func() { Host(opts, func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { policyFileName := "skip_trustpolicy.json" notation.WithInput(strings.NewReader("Y\n")).Exec("blob", "policy", "import", filepath.Join(NotationE2ETrustPolicyDir, policyFileName)). - MatchKeyWords("Blob trust policy configuration imported successfully.") + MatchKeyWords("Successfully imported blob trust policy file.") // validate content, err := os.ReadFile(filepath.Join(NotationE2ETrustPolicyDir, policyFileName)) Expect(err).NotTo(HaveOccurred()) @@ -214,7 +214,7 @@ var _ = Describe("blob trust policy maintainer", func() { Host(opts, func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { policyFileName := "skip_trustpolicy.json" notation.Exec("blob", "policy", "import", filepath.Join(NotationE2ETrustPolicyDir, policyFileName), "--force"). - MatchKeyWords("Blob trust policy configuration imported successfully.") + MatchKeyWords("Successfully imported blob trust policy file.") // validate content, err := os.ReadFile(filepath.Join(NotationE2ETrustPolicyDir, policyFileName)) Expect(err).NotTo(HaveOccurred()) From ec7fe13e59b4b23ce911f6bd00c0e5aa2d53cfc1 Mon Sep 17 00:00:00 2001 From: Junjie Gao Date: Mon, 6 Jan 2025 06:10:07 +0000 Subject: [PATCH 21/24] fix: resolve comment for Two-Hearts Signed-off-by: Junjie Gao --- cmd/notation/blob/cmd.go | 6 +++--- cmd/notation/blob/policy/cmd.go | 2 +- cmd/notation/blob/policy/import.go | 7 +++++-- cmd/notation/blob/policy/show.go | 4 ++-- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/cmd/notation/blob/cmd.go b/cmd/notation/blob/cmd.go index c491b81fb..212a4959c 100644 --- a/cmd/notation/blob/cmd.go +++ b/cmd/notation/blob/cmd.go @@ -19,11 +19,11 @@ import ( "github.com/spf13/cobra" ) -// Cmd returns the command for blob +// Cmd returns the commands for blob func Cmd() *cobra.Command { command := &cobra.Command{ - Use: "blob [commnad]", - Short: "Sign, verify and inspect signatures associated with blobs", + Use: "blob [command]", + Short: "Sign, inspect, and verify signatures and configure trust policies", Long: "Sign, inspect, and verify signatures and configure trust policies.", } diff --git a/cmd/notation/blob/policy/cmd.go b/cmd/notation/blob/policy/cmd.go index 595270649..d6f2e9dea 100644 --- a/cmd/notation/blob/policy/cmd.go +++ b/cmd/notation/blob/policy/cmd.go @@ -11,7 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package policy provides the import and show command for blob trust policy. +// Package policy provides the import and show commands for blob trust policy. package policy import ( diff --git a/cmd/notation/blob/policy/import.go b/cmd/notation/blob/policy/import.go index 6391b975c..91bdc8687 100644 --- a/cmd/notation/blob/policy/import.go +++ b/cmd/notation/blob/policy/import.go @@ -34,11 +34,14 @@ func importCmd() *cobra.Command { var opts importOpts command := &cobra.Command{ Use: "import [flags] ", - Short: "Import trust policy configuration from a JSON file", + Short: "Import blob trust policy configuration from a JSON file", Long: `Import blob trust policy configuration from a JSON file. -Example - Import trust policy configuration from a file: +Example - Import blob trust policy configuration from a file: notation blob policy import my_policy.json + +Example - Import blob trust policy and override existing configuration: + notation blob policy import my_policy.json --force `, Args: func(cmd *cobra.Command, args []string) error { if len(args) != 1 { diff --git a/cmd/notation/blob/policy/show.go b/cmd/notation/blob/policy/show.go index 38b7f5380..d66ee0bf6 100644 --- a/cmd/notation/blob/policy/show.go +++ b/cmd/notation/blob/policy/show.go @@ -29,7 +29,7 @@ import ( func showCmd() *cobra.Command { command := &cobra.Command{ Use: "show [flags]", - Short: "Show trust policy configuration", + Short: "Show blob trust policy configuration", Long: `Show blob trust policy configuration. Example - Show current blob trust policy configuration: @@ -59,7 +59,7 @@ func runShow() error { err = doc.Validate() } if err != nil { - fmt.Fprintf(os.Stderr, "Existing blob trust policy file is invalid, you may update or create a new one via `notation blob policy import `\n") + fmt.Fprintf(os.Stderr, "Existing blob trust policy file is invalid, you may update or create a new one via `notation blob policy import `. Please visit https://github.com/notaryproject/specifications/blob/main/specs/trust-store-trust-policy.md#trust-policy-for-blobs to find a valid blob trust policy example.\n") os.Stdout.Write(policyJSON) return err } From 4d132673fc922e952761bd3ede124167afa960b9 Mon Sep 17 00:00:00 2001 From: Junjie Gao Date: Tue, 7 Jan 2025 05:21:21 +0000 Subject: [PATCH 22/24] fix: resolve comments for Patrick Signed-off-by: Junjie Gao --- cmd/notation/blob/cmd.go | 4 ++-- cmd/notation/blob/policy/import.go | 4 ++-- cmd/notation/blob/policy/show.go | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cmd/notation/blob/cmd.go b/cmd/notation/blob/cmd.go index 212a4959c..6eae032a2 100644 --- a/cmd/notation/blob/cmd.go +++ b/cmd/notation/blob/cmd.go @@ -23,8 +23,8 @@ import ( func Cmd() *cobra.Command { command := &cobra.Command{ Use: "blob [command]", - Short: "Sign, inspect, and verify signatures and configure trust policies", - Long: "Sign, inspect, and verify signatures and configure trust policies.", + Short: "Sign, inspect, verify signatures, and configure trust policies for blob artifacts", + Long: "Sign, inspect, verify signatures, and configure trust policies for blob artifacts.", } command.AddCommand( diff --git a/cmd/notation/blob/policy/import.go b/cmd/notation/blob/policy/import.go index 91bdc8687..84af27174 100644 --- a/cmd/notation/blob/policy/import.go +++ b/cmd/notation/blob/policy/import.go @@ -40,7 +40,7 @@ func importCmd() *cobra.Command { Example - Import blob trust policy configuration from a file: notation blob policy import my_policy.json -Example - Import blob trust policy and override existing configuration: +Example - Import blob trust policy and override existing configuration without prompt: notation blob policy import my_policy.json --force `, Args: func(cmd *cobra.Command, args []string) error { @@ -54,7 +54,7 @@ Example - Import blob trust policy and override existing configuration: return runImport(opts) }, } - command.Flags().BoolVar(&opts.force, "force", false, "override the existing blob trust policy configuration, never prompt") + command.Flags().BoolVar(&opts.force, "force", false, "override the existing blob trust policy configuration without prompt") return command } diff --git a/cmd/notation/blob/policy/show.go b/cmd/notation/blob/policy/show.go index d66ee0bf6..1b11a8040 100644 --- a/cmd/notation/blob/policy/show.go +++ b/cmd/notation/blob/policy/show.go @@ -59,7 +59,7 @@ func runShow() error { err = doc.Validate() } if err != nil { - fmt.Fprintf(os.Stderr, "Existing blob trust policy file is invalid, you may update or create a new one via `notation blob policy import `. Please visit https://github.com/notaryproject/specifications/blob/main/specs/trust-store-trust-policy.md#trust-policy-for-blobs to find a valid blob trust policy example.\n") + fmt.Fprintf(os.Stderr, "Existing blob trust policy file is invalid, you may update or create a new one via `notation blob policy import `. See https://github.com/notaryproject/specifications/blob/main/specs/trust-store-trust-policy.md#trust-policy-for-blobs for a blob trust policy example.\n") os.Stdout.Write(policyJSON) return err } From b76c4eb212ba22aff4f65a300eda143c9b362d47 Mon Sep 17 00:00:00 2001 From: Junjie Gao Date: Tue, 7 Jan 2025 09:03:42 +0000 Subject: [PATCH 23/24] fix: resolve comment Signed-off-by: Junjie Gao --- cmd/notation/blob/policy/import.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/notation/blob/policy/import.go b/cmd/notation/blob/policy/import.go index 84af27174..8bca4ce98 100644 --- a/cmd/notation/blob/policy/import.go +++ b/cmd/notation/blob/policy/import.go @@ -41,7 +41,7 @@ Example - Import blob trust policy configuration from a file: notation blob policy import my_policy.json Example - Import blob trust policy and override existing configuration without prompt: - notation blob policy import my_policy.json --force + notation blob policy import --force my_policy.json `, Args: func(cmd *cobra.Command, args []string) error { if len(args) != 1 { From 4360cfb5df9e9b07b612b243f3f48828665171d8 Mon Sep 17 00:00:00 2001 From: Junjie Gao Date: Tue, 7 Jan 2025 09:10:17 +0000 Subject: [PATCH 24/24] fix: update error message link Signed-off-by: Junjie Gao --- cmd/notation/blob/policy/show.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/notation/blob/policy/show.go b/cmd/notation/blob/policy/show.go index 1b11a8040..5b3257e20 100644 --- a/cmd/notation/blob/policy/show.go +++ b/cmd/notation/blob/policy/show.go @@ -59,7 +59,7 @@ func runShow() error { err = doc.Validate() } if err != nil { - fmt.Fprintf(os.Stderr, "Existing blob trust policy file is invalid, you may update or create a new one via `notation blob policy import `. See https://github.com/notaryproject/specifications/blob/main/specs/trust-store-trust-policy.md#trust-policy-for-blobs for a blob trust policy example.\n") + fmt.Fprintf(os.Stderr, "Existing blob trust policy file is invalid, you may update or create a new one via `notation blob policy import `. See https://github.com/notaryproject/specifications/blob/8cf800c60b7315a43f0adbcae463d848a353b412/specs/trust-store-trust-policy.md#trust-policy-for-blobs for a blob trust policy example.\n") os.Stdout.Write(policyJSON) return err }