Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add blob policy import and show commands #1126

Merged
merged 27 commits into from
Jan 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
e067e69
feat: add blob policy commands
JeyJeyGao Dec 24, 2024
588f3e5
fix: add e2e test cases
JeyJeyGao Dec 24, 2024
1ff8547
fix: improve code
JeyJeyGao Dec 24, 2024
88aee76
fix: improve code
JeyJeyGao Dec 24, 2024
8fe215e
fix: improve code
JeyJeyGao Dec 24, 2024
e67b5fd
fix: improve code
JeyJeyGao Dec 24, 2024
1eb1908
fix: improve code
JeyJeyGao Dec 24, 2024
77d87e5
fix: split blob and OCI policy commands
JeyJeyGao Dec 27, 2024
b1ed2fa
fix: simplify code
JeyJeyGao Dec 27, 2024
91be43c
fix: simplify code
JeyJeyGao Dec 27, 2024
d70dd18
fix: update error message
JeyJeyGao Dec 27, 2024
62c874c
fix: optimize readability
JeyJeyGao Dec 27, 2024
3494909
fix: improve readability
JeyJeyGao Dec 27, 2024
5ab618b
fix: replace os.IsNotExist(err) with errors.Is(err, fs.ErrNotExist)
JeyJeyGao Dec 30, 2024
cf1fc19
fix: update help doc
JeyJeyGao Dec 30, 2024
8ecf320
fix: add E2E test cases
JeyJeyGao Dec 30, 2024
b595f64
fix: resolve comments
JeyJeyGao Dec 30, 2024
43878ed
fix: remove the change of oci policy commands
JeyJeyGao Dec 30, 2024
fad665c
fix: remove unused file
JeyJeyGao Dec 30, 2024
71f522a
fix: E2E test
JeyJeyGao Dec 30, 2024
ec7fe13
fix: resolve comment for Two-Hearts
JeyJeyGao Jan 6, 2025
4d13267
fix: resolve comments for Patrick
JeyJeyGao Jan 7, 2025
b76c4eb
fix: resolve comment
JeyJeyGao Jan 7, 2025
4360cfb
fix: update error message link
JeyJeyGao Jan 7, 2025
15d940e
Merge remote-tracking branch 'upstream/main' into feat/blob_policy_cmd
JeyJeyGao Jan 14, 2025
0cb99f7
fix: bump up
JeyJeyGao Jan 14, 2025
6b9922a
Merge remote-tracking branch 'upstream/main' into feat/blob_policy_cmd
JeyJeyGao Jan 14, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion cmd/notation/blob/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@
// Package blob provides the implementation of the `notation blob` command
package blob

import "github.com/spf13/cobra"
import (
"github.com/notaryproject/notation/cmd/notation/blob/policy"
"github.com/spf13/cobra"
)

func Cmd() *cobra.Command {
command := &cobra.Command{
Expand All @@ -25,6 +28,7 @@ func Cmd() *cobra.Command {

command.AddCommand(
signCommand(nil),
policy.Cmd(),
)

return command
Expand Down
35 changes: 35 additions & 0 deletions cmd/notation/blob/policy/cmd.go
Original file line number Diff line number Diff line change
@@ -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 commands for blob trust policy.
package policy

import (
"github.com/spf13/cobra"
)

// Cmd returns the commands 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
}
102 changes: 102 additions & 0 deletions cmd/notation/blob/policy/import.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// 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"
"github.com/spf13/cobra"
)

type importOpts struct {
filePath string
force bool
}

func importCmd() *cobra.Command {
var opts importOpts
command := &cobra.Command{
Use: "import [flags] <file_path>",
Short: "Import blob trust policy configuration from a JSON file",
Long: `Import blob trust policy configuration from a JSON 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 without prompt:
notation blob policy import --force 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 <path-to-policy.json>\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 blob trust policy configuration without 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 blob trust policy file: %w", err)
}

var doc trustpolicy.BlobDocument
if err = json.Unmarshal(policyJSON, &doc); err != nil {
return fmt.Errorf("failed to parse blob trust policy configuration: %w", err)
}
if err = doc.Validate(); err != nil {
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 blob trust policy file already exists, do you want to overwrite it?", opts.force)
if err != nil {
return err
}

Check warning on line 82 in cmd/notation/blob/policy/import.go

View check run for this annotation

Codecov / codecov/patch

cmd/notation/blob/policy/import.go#L81-L82

Added lines #L81 - L82 were not covered by tests
if !confirmed {
return nil
}
}
} else {
fmt.Fprintln(os.Stderr, "Warning: existing blob trust policy file will be overwritten")
}

// write
policyPath, err := dir.ConfigFS().SysPath(dir.PathBlobTrustPolicy)
if err != nil {
return fmt.Errorf("failed to obtain path of blob trust policy file: %w", err)
}

Check warning on line 95 in cmd/notation/blob/policy/import.go

View check run for this annotation

Codecov / codecov/patch

cmd/notation/blob/policy/import.go#L94-L95

Added lines #L94 - L95 were not covered by tests
if err = osutil.WriteFile(policyPath, policyJSON); err != nil {
return fmt.Errorf("failed to write blob trust policy file: %w", err)
}

_, err = fmt.Fprintln(os.Stdout, "Successfully imported blob trust policy file.")
return err
}
81 changes: 81 additions & 0 deletions cmd/notation/blob/policy/show.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// 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"
"github.com/spf13/cobra"
)

func showCmd() *cobra.Command {
command := &cobra.Command{
Use: "show [flags]",
Short: "Show blob 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 := 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 <path-to-policy.json>`")
}
return fmt.Errorf("failed to show trust policy: %w", err)
}
var doc trustpolicy.BlobDocument
if err = json.Unmarshal(policyJSON, &doc); err == nil {
Two-Hearts marked this conversation as resolved.
Show resolved Hide resolved
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 <path-to-policy.json>`. 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
}

// show policy content
_, err = os.Stdout.Write(policyJSON)
return err
}

// loadBlobTrustPolicy loads the blob trust policy from notation configuration
// directory.
func loadBlobTrustPolicy() ([]byte, error) {
f, err := dir.ConfigFS().Open(dir.PathBlobTrustPolicy)
if err != nil {
return nil, err
}
defer f.Close()
return io.ReadAll(f)
}
1 change: 1 addition & 0 deletions cmd/notation/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ func main() {
},
}
cmd.AddCommand(
blob.Cmd(),
signCommand(nil),
verifyCommand(nil),
listCommand(nil),
Expand Down
10 changes: 5 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ go 1.23

require (
github.com/notaryproject/notation-core-go v1.2.0-rc.2
github.com/notaryproject/notation-go v1.2.0-beta.1.0.20250107003620-26ce0894a624
github.com/notaryproject/tspclient-go v1.0.0
github.com/notaryproject/notation-go v1.2.0-beta.1.0.20250114004447-851cbabbc40a
github.com/notaryproject/tspclient-go v1.0.0-rc.1
github.com/opencontainers/go-digest v1.0.0
github.com/opencontainers/image-spec v1.1.0
github.com/sirupsen/logrus v1.9.3
github.com/spf13/cobra v1.8.1
github.com/spf13/pflag v1.0.5
golang.org/x/term v0.27.0
golang.org/x/term v0.28.0
oras.land/oras-go/v2 v2.5.0
)

Expand All @@ -26,8 +26,8 @@ require (
github.com/notaryproject/notation-plugin-framework-go v1.0.0 // indirect
github.com/veraison/go-cose v1.3.0 // indirect
github.com/x448/float16 v0.8.4 // indirect
golang.org/x/crypto v0.31.0 // indirect
golang.org/x/crypto v0.32.0 // indirect
golang.org/x/mod v0.22.0 // indirect
golang.org/x/sync v0.10.0 // indirect
golang.org/x/sys v0.28.0 // indirect
golang.org/x/sys v0.29.0 // indirect
)
17 changes: 10 additions & 7 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,12 @@ github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZ
github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
github.com/notaryproject/notation-core-go v1.2.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.20250107003620-26ce0894a624 h1:JCJ+64H1A/aYhNaUak+1DV4dY2uL3L5GFMRLzrh9tDM=
github.com/notaryproject/notation-go v1.2.0-beta.1.0.20250107003620-26ce0894a624/go.mod h1:1QaHYG/UOeAYhfLBipsSxquu3BheRm7a+5RODcc5nQg=
github.com/notaryproject/notation-go v1.2.0-beta.1.0.20250114004447-851cbabbc40a h1:4YIVP+nzfUtT3JgDRuQKBeyKSHaCe8lRIbui+nQYchc=
github.com/notaryproject/notation-go v1.2.0-beta.1.0.20250114004447-851cbabbc40a/go.mod h1:JA4E4DjnL8ojwRu1VnGtiAWgcg69KFvRTlAAMZ/VQ58=
github.com/notaryproject/notation-plugin-framework-go v1.0.0 h1:6Qzr7DGXoCgXEQN+1gTZWuJAZvxh3p8Lryjn5FaLzi4=
github.com/notaryproject/notation-plugin-framework-go v1.0.0/go.mod h1:RqWSrTOtEASCrGOEffq0n8pSg2KOgKYiWqFWczRSics=
github.com/notaryproject/tspclient-go v1.0.0 h1:AwQ4x0gX8IHnyiZB1tggpn5NFqHpTEm1SDX8YNv4Dg4=
github.com/notaryproject/tspclient-go v1.0.0/go.mod h1:LGyA/6Kwd2FlM0uk8Vc5il3j0CddbWSHBj/4kxQDbjs=
github.com/notaryproject/tspclient-go v1.0.0-rc.1 h1:KcHxlqg6Adt4kzGLw012i0YMLlwGwToiR129c6IQ7Ys=
github.com/notaryproject/tspclient-go v1.0.0-rc.1/go.mod h1:LGyA/6Kwd2FlM0uk8Vc5il3j0CddbWSHBj/4kxQDbjs=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
Expand Down Expand Up @@ -77,8 +77,9 @@ golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
Expand Down Expand Up @@ -117,8 +118,9 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
Expand All @@ -127,8 +129,9 @@ golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
Expand Down
10 changes: 10 additions & 0 deletions test/e2e/internal/notation/host.go
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,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 {
Expand Down
15 changes: 8 additions & 7 deletions test/e2e/internal/notation/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down
4 changes: 3 additions & 1 deletion test/e2e/internal/utils/validator/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
package validator

import (
"errors"
"io/fs"
"os"

. "github.com/onsi/gomega"
Expand All @@ -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())
}
Loading
Loading