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: update policy command to support OCI trust policy #1173

Merged
merged 27 commits into from
Feb 21, 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
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
4 changes: 2 additions & 2 deletions cmd/notation/policy/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ import "github.com/spf13/cobra"
func Cmd() *cobra.Command {
command := &cobra.Command{
Use: "policy [command]",
Short: "Manage trust policy configuration",
Long: "Manage trust policy configuration for signature verification.",
Short: "Manage OCI trust policy configuration for OCI artifact signature verification",
Long: "Manage OCI trust policy configuration for OCI artifact signature verification.",
}

command.AddCommand(
Expand Down
62 changes: 43 additions & 19 deletions cmd/notation/policy/import.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

import (
"encoding/json"
"errors"
"fmt"
"os"

Expand All @@ -34,13 +35,14 @@
var opts importOpts
command := &cobra.Command{
Use: "import [flags] <file_path>",
Short: "Import trust policy configuration from a JSON file",
Long: `Import trust policy configuration from a JSON file.
Short: "Import OCI trust policy configuration from a JSON file",
Long: `Import OCI trust policy configuration from a JSON file.

** This command is in preview and under development. **

Example - Import trust policy configuration from a file:
Example - Import OCI trust policy configuration from a JSON file and store as "trustpolicy.oci.json":
notation policy import my_policy.json

Example - Import OCI trust policy and override existing configuration without prompt:
notation policy import --force my_policy.json
`,
Args: func(cmd *cobra.Command, args []string) error {
if len(args) != 1 {
Expand All @@ -53,49 +55,71 @@
return runImport(cmd, 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 OCI trust policy configuration without 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)
return fmt.Errorf("failed to read OCI trust policy configuration: %w", err)
}

// parse and validate
var doc trustpolicy.Document
var doc trustpolicy.OCIDocument
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 OCI 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 OCI trust policy configuration: %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 := trustpolicy.LoadOCIDocument(); err == nil {
if !opts.force {
confirmed, err := cmdutil.AskForConfirmation(os.Stdin, "The OCI trust policy configuration 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 OCI trust policy configuration will be overwritten")
}
} else {
fmt.Fprintln(os.Stderr, "Warning: existing trust policy configuration file will be overwritten")
}

// 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)
return fmt.Errorf("failed to obtain path of OCI trust policy configuration: %w", err)

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

View check run for this annotation

Codecov / codecov/patch

cmd/notation/policy/import.go#L96

Added line #L96 was not covered by tests
}
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 OCI trust policy configuration: %w", err)
}
// user has confirmed to overwrite the existing trust policy configuration,
// delete the old trust policy file `trustpolicy.json` if exists
if err := deleteOldTrustPolicyFile(); err != nil {
if !errors.Is(err, os.ErrNotExist) {
fmt.Fprintf(os.Stderr, "Warning: failed to delete old trust policy configuration trustpolicy.json: %s\n", err)
}
} else {
fmt.Fprintln(os.Stdout, "Deleted old trust policy configuration trustpolicy.json.")
}
_, err = fmt.Fprintln(os.Stdout, "Trust policy configuration imported successfully.")

_, err = fmt.Fprintf(os.Stdout, "Successfully imported OCI trust policy configuration to %s.\n", policyPath)
return err
}

// deleteOldTrustPolicyFile deletes the old trust policy configuration if exists.
func deleteOldTrustPolicyFile() error {
oldPolicyPath, err := dir.ConfigFS().SysPath(dir.PathTrustPolicy)
if err != nil {
return err
}

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

View check run for this annotation

Codecov / codecov/patch

cmd/notation/policy/import.go#L119-L120

Added lines #L119 - L120 were not covered by tests
if _, err := os.Stat(oldPolicyPath); err != nil {
return err
}
return os.Remove(oldPolicyPath)
}
42 changes: 23 additions & 19 deletions cmd/notation/policy/show.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,13 @@ func showCmd() *cobra.Command {
var opts showOpts
command := &cobra.Command{
Use: "show [flags]",
Short: "Show trust policy configuration",
Long: `Show trust policy configuration.
Short: "Show OCI trust policy configuration",
Long: `Show OCI trust policy configuration.

** This command is in preview and under development. **

Example - Show current trust policy configuration:
Example - Show current OCI trust policy configuration:
notation policy show

Example - Save current trust policy configuration to a file:
Example - Save current OCI trust policy configuration to a file:
notation policy show > my_policy.json
`,
Args: cobra.ExactArgs(0),
Expand All @@ -52,31 +50,37 @@ Example - Save current trust policy configuration to a file:
}

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)
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 <path-to-policy.json>`")
return fmt.Errorf("failed to show OCI trust policy as it does not exist.\nYou can import one using `notation policy import <path-to-policy.json>`")
}
return fmt.Errorf("failed to show trust policy: %w", err)
return fmt.Errorf("failed to show OCI trust policy: %w", err)
}
var doc trustpolicy.Document
var 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 <path-to-policy.json>`\n")
// not returning to show the invalid policy configuration
fmt.Fprintf(os.Stderr, "Existing OCI trust policy configuration is invalid, you may update or create a new one via `notation policy import <path-to-policy.json>`. See https://github.com/notaryproject/specifications/blob/8cf800c60b7315a43f0adbcae463d848a353b412/specs/trust-store-trust-policy.md#trust-policy-for-oci-artifacts for a trust policy example.\n")
os.Stdout.Write(policyJSON)
return err
}

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

func loadOCITrustPolicy() ([]byte, error) {
data, err := fs.ReadFile(dir.ConfigFS(), dir.PathOCITrustPolicy)
if err != nil && errors.Is(err, fs.ErrNotExist) {
if _, err := fs.Stat(dir.ConfigFS(), dir.PathTrustPolicy); err != nil {
return nil, err
}
fmt.Fprintf(os.Stderr, "Warning: old trust policy `trustpolicy.json` is deprecated; please update the trust policy configuration via `notation policy import`.\n")
return fs.ReadFile(dir.ConfigFS(), dir.PathTrustPolicy)
}
return data, err
}
14 changes: 7 additions & 7 deletions specs/commandline/policy.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

## Description

As part of signature verification workflow of signed OCI artifacts, users need to configure trust policy configuration file to specify trusted identities that signed the artifacts, the level of signature verification to use and other settings. For more details, see [OCI trust policy specification and examples](https://github.com/notaryproject/specifications/blob/main/specs/trust-store-trust-policy.md#oci-trust-policy).
As part of signature verification workflow of signed OCI artifacts, users need to configure trust policy configuration to specify trusted identities that signed the artifacts, the level of signature verification to use and other settings. For more details, see [OCI trust policy specification and examples](https://github.com/notaryproject/specifications/blob/main/specs/trust-store-trust-policy.md#oci-trust-policy).

The `notation policy` command provides a user-friendly way to manage trust policies for signed OCI images. It allows users to show trust policy configuration, import/export a trust policy configuration file from/to a JSON file. Users who want to manage trust policies for signed arbitrary blobs, please refer to `notation blob policy` command.
The `notation policy` command provides a user-friendly way to manage trust policies for signed OCI images. It allows users to show trust policy configuration, import/export trust policy configuration from/to a JSON file. Users who want to manage trust policies for signed arbitrary blobs, please refer to `notation blob policy` command.

To get started, user can refer to the following trust policy configuration sample `trustpolicy.json` that is applicable for verifying signed OCI artifacts using `notation verify` command. In this sample, there are four policies configured for different requirements:

Expand Down Expand Up @@ -74,14 +74,14 @@ To get started, user can refer to the following trust policy configuration sampl
### notation policy command

```text
Manage trust policy configuration for OCI artifact signature verification.
Manage OCI trust policy configuration for OCI artifact signature verification.

Usage:
notation policy [command]

Available Commands:
import import trust policy configuration from a JSON file
show show trust policy configuration
import import OCI trust policy configuration from a JSON file
show show OCI trust policy configuration

Flags:
-h, --help help for policy
Expand All @@ -90,13 +90,13 @@ Flags:
### notation policy import

```text
Import OCI trust policy configuration from a JSON file
Import OCI trust policy configuration from a JSON file.

Usage:
notation policy import [flags] <file_path>

Flags:
--force override the existing trust policy configuration, never prompt
--force override the existing OCI trust policy configuration without prompt
-h, --help help for import
```

Expand Down
28 changes: 14 additions & 14 deletions specs/notation-cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,20 @@ This spec contains reference information on using notation commands. Each comman

## Notation Commands

| Command | Description |
| ------------------------------------------- | ---------------------------------------------------------------------- |
| [blob](./commandline/blob.md) | Sign, verify and inspect singatures associated with blobs |
| [certificate](./commandline/certificate.md) | Manage certificates in trust store |
| [inspect](./commandline/inspect.md) | Inspect OCI signatures |
| [key](./commandline/key.md) | Manage keys used for signing |
| [list](./commandline/list.md) | List signatures of a signed OCI artifact |
| [login](./commandline/login.md) | Log into OCI registries |
| [logout](./commandline/logout.md) | Log out from the logged in OCI registries |
| [plugin](./commandline/plugin.md) | Manage plugins |
| [policy](./commandline/policy.md) | Manage trust policy configuration for OCI signature verification |
| [sign](./commandline/sign.md) | Sign OCI artifacts |
| [verify](./commandline/verify.md) | Verify OCI artifacts |
| [version](./commandline/version.md) | Print the version of notation CLI |
| Command | Description |
| ------------------------------------------- | ----------------------------------------------------------------------------- |
| [blob](./commandline/blob.md) | Sign, verify and inspect singatures associated with blobs |
| [certificate](./commandline/certificate.md) | Manage certificates in trust store |
| [inspect](./commandline/inspect.md) | Inspect OCI signatures |
| [key](./commandline/key.md) | Manage keys used for signing |
| [list](./commandline/list.md) | List signatures of a signed OCI artifact |
| [login](./commandline/login.md) | Log into OCI registries |
| [logout](./commandline/logout.md) | Log out from the logged in OCI registries |
| [plugin](./commandline/plugin.md) | Manage plugins |
| [policy](./commandline/policy.md) | Manage OCI trust policy configuration for OCI artifact signature verification |
| [sign](./commandline/sign.md) | Sign OCI artifacts |
| [verify](./commandline/verify.md) | Verify OCI artifacts |
| [version](./commandline/version.md) | Print the version of notation CLI |

## Notation Outline

Expand Down
Loading
Loading