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

Open
wants to merge 24 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
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
35 changes: 35 additions & 0 deletions cmd/notation/blob/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 blob provides the command for blob trust policy configuration.
JeyJeyGao marked this conversation as resolved.
Show resolved Hide resolved
package blob

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

// Cmd returns the command for blob
JeyJeyGao marked this conversation as resolved.
Show resolved Hide resolved
func Cmd() *cobra.Command {
command := &cobra.Command{
Use: "blob [commnad]",
JeyJeyGao marked this conversation as resolved.
Show resolved Hide resolved
Short: "Sign, verify and inspect signatures associated with blobs",
Long: "Sign, inspect, and verify signatures and configure trust policies.",
JeyJeyGao marked this conversation as resolved.
Show resolved Hide resolved
JeyJeyGao marked this conversation as resolved.
Show resolved Hide resolved
}

command.AddCommand(
policy.Cmd(),
)

return command
}
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 command for blob trust policy.
JeyJeyGao marked this conversation as resolved.
Show resolved Hide resolved
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
}
99 changes: 99 additions & 0 deletions cmd/notation/blob/policy/import.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// 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 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
JeyJeyGao marked this conversation as resolved.
Show resolved Hide resolved
`,
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 trust policy configuration, never prompt")
JeyJeyGao marked this conversation as resolved.
Show resolved Hide resolved
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)
}

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

View check run for this annotation

Codecov / codecov/patch

cmd/notation/blob/policy/import.go#L67-L68

Added lines #L67 - L68 were not covered by tests
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 79 in cmd/notation/blob/policy/import.go

View check run for this annotation

Codecov / codecov/patch

cmd/notation/blob/policy/import.go#L78-L79

Added lines #L78 - L79 were not covered by tests
if !confirmed {
return nil
}
}
} else {
fmt.Fprintln(os.Stderr, "Warning: existing blob trust policy configuration file will be overwritten")
JeyJeyGao marked this conversation as resolved.
Show resolved Hide resolved
}

// 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 92 in cmd/notation/blob/policy/import.go

View check run for this annotation

Codecov / codecov/patch

cmd/notation/blob/policy/import.go#L91-L92

Added lines #L91 - L92 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)
}

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

_, err = fmt.Fprintln(os.Stdout, "Blob trust policy configuration imported successfully.")
JeyJeyGao marked this conversation as resolved.
Show resolved Hide resolved
return err
}
79 changes: 79 additions & 0 deletions cmd/notation/blob/policy/show.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// 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"
"io"
"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 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 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 <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 {
err = doc.Validate()
}
if err != nil {
fmt.Fprintf(os.Stderr, "Error: %s\n", err.Error())
JeyJeyGao marked this conversation as resolved.
Show resolved Hide resolved
fmt.Fprintf(os.Stderr, "Existing blob trust policy configuration is invalid, you may update or create a new one via `notation blob policy import <path-to-policy.json>`\n")
JeyJeyGao marked this conversation as resolved.
Show resolved Hide resolved
// not returning to show the invalid policy configuration
}

// show policy content
_, err = os.Stdout.Write(policyJSON)
return err
JeyJeyGao marked this conversation as resolved.
Show resolved Hide resolved
}

// 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)
}
2 changes: 2 additions & 0 deletions cmd/notation/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -51,6 +52,7 @@ func main() {
},
}
cmd.AddCommand(
blob.Cmd(),
signCommand(nil),
verifyCommand(nil),
listCommand(nil),
Expand Down
1 change: 1 addition & 0 deletions cmd/notation/policy/cmd.go
JeyJeyGao marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
18 changes: 14 additions & 4 deletions cmd/notation/policy/import.go
JeyJeyGao marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,14 @@
},
RunE: func(cmd *cobra.Command, args []string) error {
opts.filePath = args[0]
return runImport(cmd, opts)
return runImport(opts)
},
}
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 {
func runImport(opts importOpts) error {
// read configuration
policyJSON, err := os.ReadFile(opts.filePath)
if err != nil {
Expand All @@ -75,7 +75,7 @@

// optional confirmation
if !opts.force {
if _, err := trustpolicy.LoadDocument(); 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
Expand All @@ -89,13 +89,23 @@
}

// write
policyPath, err := dir.ConfigFS().SysPath(dir.PathTrustPolicy)
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)
}

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

View check run for this annotation

Codecov / codecov/patch

cmd/notation/policy/import.go#L103-L104

Added lines #L103 - L104 were not covered by tests
if err := osutil.RemoveIfExists(oldPolicyPath); err != nil {
fmt.Fprintf(os.Stderr, "Warning: failed to clear old trust policy %q: %v\n", oldPolicyPath, err)
}

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

View check run for this annotation

Codecov / codecov/patch

cmd/notation/policy/import.go#L106-L107

Added lines #L106 - L107 were not covered by tests

_, err = fmt.Fprintln(os.Stdout, "Trust policy configuration imported successfully.")
return err
}
Loading
Loading