Skip to content

Commit

Permalink
feat: upgrade to OCI 1.1 (#916)
Browse files Browse the repository at this point in the history
Signed-off-by: Patrick Zheng <patrickzheng@microsoft.com>
  • Loading branch information
Two-Hearts authored Apr 16, 2024
1 parent 4b9d016 commit 0f556be
Show file tree
Hide file tree
Showing 30 changed files with 469 additions and 198 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
go-version: ['1.20']
go-version: ['1.22']
fail-fast: true
steps:
- name: Set up Go ${{ matrix.go-version }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ jobs:
security-events: write
strategy:
matrix:
go-version: ['1.20']
go-version: ['1.22']
fail-fast: false
steps:
- name: Checkout repository
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release-github.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:
runs-on: ubuntu-20.04
strategy:
matrix:
go-version: ['1.20']
go-version: ['1.22']
fail-fast: true
steps:
- name: Set up Go ${{ matrix.go-version }}
Expand Down
2 changes: 1 addition & 1 deletion building.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ The notation repo contains the following:

- `notation` - A CLI for signing and verifying artifacts with Notation

Building above binaries require [golang](https://golang.org/dl/) with version `>= 1.20`.
Building above binaries require [golang](https://golang.org/dl/) with version `>= 1.22`.

## Windows with WSL or Linux

Expand Down
12 changes: 6 additions & 6 deletions cmd/notation/inspect.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,6 @@ Example - Inspect signatures on an OCI artifact identified by a tag (Notation w
Example - Inspect signatures on an OCI artifact identified by a digest and output as json:
notation inspect --output json <registry>/<repository>@<digest>
`
experimentalExamples := `
Example - [Experimental] Inspect signatures on an OCI artifact identified by a digest using the Referrers API, if not supported (returns 404), fallback to the Referrers tag schema
notation inspect --allow-referrers-api <registry>/<repository>@<digest>
`
command := &cobra.Command{
Use: "inspect [reference]",
Expand All @@ -106,6 +102,9 @@ Example - [Experimental] Inspect signatures on an OCI artifact identified by a d
if opts.maxSignatures <= 0 {
return fmt.Errorf("max-signatures value %d must be a positive number", opts.maxSignatures)
}
if cmd.Flags().Changed("allow-referrers-api") {
fmt.Fprintln(os.Stderr, "Warning: flag '--allow-referrers-api' is deprecated and will be removed in future versions.")
}
return runInspect(cmd, opts)
},
}
Expand All @@ -115,7 +114,6 @@ Example - [Experimental] Inspect signatures on an OCI artifact identified by a d
cmd.SetPflagOutput(command.Flags(), &opts.outputFormat, cmd.PflagOutputUsage)
command.Flags().IntVar(&opts.maxSignatures, "max-signatures", 100, "maximum number of signatures to evaluate or examine")
cmd.SetPflagReferrersAPI(command.Flags(), &opts.allowReferrersAPI, fmt.Sprintf(cmd.PflagReferrersUsageFormat, "inspect"))
experimental.HideFlags(command, experimentalExamples, []string{"allow-referrers-api"})
return command
}

Expand All @@ -129,7 +127,9 @@ func runInspect(command *cobra.Command, opts *inspectOpts) error {

// initialize
reference := opts.reference
sigRepo, err := getRemoteRepository(ctx, &opts.SecureFlagOpts, reference, opts.allowReferrersAPI)
// always use the Referrers API, if not supported, automatically fallback to
// the referrers tag schema
sigRepo, err := getRemoteRepository(ctx, &opts.SecureFlagOpts, reference, false)
if err != nil {
return err
}
Expand Down
14 changes: 8 additions & 6 deletions cmd/notation/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"context"
"errors"
"fmt"
"os"

notationregistry "github.com/notaryproject/notation-go/registry"
cmderr "github.com/notaryproject/notation/cmd/notation/internal/errors"
Expand Down Expand Up @@ -52,9 +53,6 @@ Example - List signatures of an OCI artifact identified by a tag (Notation will
notation list <registry>/<repository>:<tag>
`
experimentalExamples := `
Example - [Experimental] List signatures of an OCI artifact using the Referrers API. If it's not supported (returns 404), fallback to the Referrers tag schema
notation list --allow-referrers-api <registry>/<repository>@<digest>
Example - [Experimental] List signatures of an OCI artifact referenced in an OCI layout
notation list --oci-layout "<oci_layout_path>@<digest>"
Expand Down Expand Up @@ -83,16 +81,18 @@ Example - [Experimental] List signatures of an OCI artifact identified by a tag
if opts.maxSignatures <= 0 {
return fmt.Errorf("max-signatures value %d must be a positive number", opts.maxSignatures)
}
if cmd.Flags().Changed("allow-referrers-api") {
fmt.Fprintln(os.Stderr, "Warning: flag '--allow-referrers-api' is deprecated and will be removed in future versions.")
}
return runList(cmd.Context(), opts)
},
}
opts.LoggingFlagOpts.ApplyFlags(command.Flags())
opts.SecureFlagOpts.ApplyFlags(command.Flags())
cmd.SetPflagReferrersAPI(command.Flags(), &opts.allowReferrersAPI, fmt.Sprintf(cmd.PflagReferrersUsageFormat, "list"))
command.Flags().BoolVar(&opts.ociLayout, "oci-layout", false, "[Experimental] list signatures stored in OCI image layout")
experimental.HideFlags(command, "", []string{"allow-referrers-api", "oci-layout"})
command.Flags().IntVar(&opts.maxSignatures, "max-signatures", 100, "maximum number of signatures to evaluate or examine")
experimental.HideFlags(command, experimentalExamples, []string{"allow-referrers-api", "oci-layout"})
experimental.HideFlags(command, experimentalExamples, []string{"oci-layout"})
return command
}

Expand All @@ -102,7 +102,9 @@ func runList(ctx context.Context, opts *listOpts) error {

// initialize
reference := opts.reference
sigRepo, err := getRepository(ctx, opts.inputType, reference, &opts.SecureFlagOpts, opts.allowReferrersAPI)
// always use the Referrers API, if not supported, automatically fallback to
// the referrers tag schema
sigRepo, err := getRepository(ctx, opts.inputType, reference, &opts.SecureFlagOpts, false)
if err != nil {
return err
}
Expand Down
32 changes: 16 additions & 16 deletions cmd/notation/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import (

"github.com/notaryproject/notation-go/log"
notationregistry "github.com/notaryproject/notation-go/registry"
"github.com/notaryproject/notation/cmd/notation/internal/experimental"
notationauth "github.com/notaryproject/notation/internal/auth"
"github.com/notaryproject/notation/internal/httputil"
"github.com/notaryproject/notation/pkg/configutil"
Expand All @@ -41,10 +40,10 @@ const (

// getRepository returns a notationregistry.Repository given user input
// type and user input reference
func getRepository(ctx context.Context, inputType inputType, reference string, opts *SecureFlagOpts, allowReferrersAPI bool) (notationregistry.Repository, error) {
func getRepository(ctx context.Context, inputType inputType, reference string, opts *SecureFlagOpts, forceReferrersTag bool) (notationregistry.Repository, error) {
switch inputType {
case inputTypeRegistry:
return getRemoteRepository(ctx, opts, reference, allowReferrersAPI)
return getRemoteRepository(ctx, opts, reference, forceReferrersTag)
case inputTypeOCILayout:
layoutPath, _, err := parseOCILayoutReference(reference)
if err != nil {
Expand All @@ -57,17 +56,18 @@ func getRepository(ctx context.Context, inputType inputType, reference string, o
}

// getRemoteRepository returns a registry.Repository.
// When experimental feature is disabled OR allowReferrersAPI is not set,
// Notation always uses referrers tag schema to store and consume signatures
// by default.
// When experimental feature is enabled AND allowReferrersAPI is set, Notation
// tries the Referrers API, if not supported, fallback to use the Referrers
// tag schema.
// When forceReferrersTag is true, Notation will always generate an image index
// according to the Referrers tag schema to store signature.
//
// When forceReferrersTag is false, Notation will first try to store the
// signature as a referrer according to the Referrers API. If the Referrers API
// is not supported, fallback to use the referrers tag schema.
// This flag is always FALSE when verify/list/inspect signatures.
//
// References:
// https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc1/spec.md#listing-referrers
// https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc1/spec.md#referrers-tag-schema
func getRemoteRepository(ctx context.Context, opts *SecureFlagOpts, reference string, allowReferrersAPI bool) (notationregistry.Repository, error) {
// https://github.com/opencontainers/distribution-spec/blob/v1.1.0/spec.md#listing-referrers
// https://github.com/opencontainers/distribution-spec/blob/v1.1.0/spec.md#referrers-tag-schema
func getRemoteRepository(ctx context.Context, opts *SecureFlagOpts, reference string, forceReferrersTag bool) (notationregistry.Repository, error) {
logger := log.GetLogger(ctx)
ref, err := registry.ParseReference(reference)
if err != nil {
Expand All @@ -82,13 +82,13 @@ func getRemoteRepository(ctx context.Context, opts *SecureFlagOpts, reference st
return nil, err
}

if !experimental.IsDisabled() && allowReferrersAPI {
logger.Info("Trying to use the referrers API")
} else {
logger.Info("Using the referrers tag schema")
if forceReferrersTag {
logger.Info("The referrers tag schema is always attempted")
if err := remoteRepo.SetReferrersCapability(false); err != nil {
return nil, err
}
} else {
logger.Info("Allowed to access the referrers API, fallback if not supported")
}
return notationregistry.NewRepository(remoteRepo), nil
}
Expand Down
10 changes: 0 additions & 10 deletions cmd/notation/registry_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,13 @@ import (
"net/http/httptest"
"net/url"
"testing"

"github.com/notaryproject/notation/cmd/notation/internal/experimental"
)

const (
zeroDigest = "sha256:0000000000000000000000000000000000000000000000000000000000000000"
)

func TestRegistry_getRemoteRepositoryWithReferrersAPISupported(t *testing.T) {
t.Setenv("NOTATION_EXPERIMENTAL", "1")
if experimental.IsDisabled() {
t.Fatal("failed to enable experimental")
}
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodGet && r.URL.Path == "/v2/test/v1/referrers/"+zeroDigest {
w.WriteHeader(http.StatusOK)
Expand All @@ -56,10 +50,6 @@ func TestRegistry_getRemoteRepositoryWithReferrersAPISupported(t *testing.T) {
}

func TestRegistry_getRemoteRepositoryWithReferrersAPINotSupported(t *testing.T) {
t.Setenv("NOTATION_EXPERIMENTAL", "1")
if experimental.IsDisabled() {
t.Fatal("failed to enable experimental")
}
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodGet && r.URL.Path == "/v2/test/v1/referrers/"+zeroDigest {
w.WriteHeader(http.StatusNotFound)
Expand Down
32 changes: 19 additions & 13 deletions cmd/notation/sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,13 @@
package main

import (
"context"
"errors"
"fmt"
"os"
"strings"
"time"

"github.com/notaryproject/notation-go"
notationregistry "github.com/notaryproject/notation-go/registry"
"github.com/notaryproject/notation/cmd/notation/internal/experimental"
"github.com/notaryproject/notation/internal/cmd"
"github.com/notaryproject/notation/internal/envelope"
Expand All @@ -41,6 +39,7 @@ type signOpts struct {
userMetadata []string
reference string
allowReferrersAPI bool
forceReferrersTag bool
ociLayout bool
inputType inputType
}
Expand Down Expand Up @@ -72,11 +71,11 @@ Example - Sign an OCI artifact identified by a tag (Notation will resolve tag to
Example - Sign an OCI artifact stored in a registry and specify the signature expiry duration, for example 24 hours
notation sign --expiry 24h <registry>/<repository>@<digest>
Example - Sign an OCI artifact and store signature using the Referrers API. If it's not supported, fallback to the Referrers tag schema
notation sign --force-referrers-tag=false <registry>/<repository>@<digest>
`
experimentalExamples := `
Example - [Experimental] Sign an OCI artifact and store signature using the Referrers API. If it's not supported (returns 404), fallback to the Referrers tag schema
notation sign --allow-referrers-api <registry>/<repository>@<digest>
Example - [Experimental] Sign an OCI artifact referenced in an OCI layout
notation sign --oci-layout "<oci_layout_path>@<digest>"
Expand All @@ -102,6 +101,15 @@ Example - [Experimental] Sign an OCI artifact identified by a tag and referenced
return experimental.CheckFlagsAndWarn(cmd, "allow-referrers-api", "oci-layout")
},
RunE: func(cmd *cobra.Command, args []string) error {
// allow-referrers-api flag is set
if cmd.Flags().Changed("allow-referrers-api") {
if opts.allowReferrersAPI {
fmt.Fprintln(os.Stderr, "Warning: flag '--allow-referrers-api' is deprecated and will be removed in future versions, use '--force-referrers-tag=false' instead.")
opts.forceReferrersTag = false
} else {
fmt.Fprintln(os.Stderr, "Warning: flag '--allow-referrers-api' is deprecated and will be removed in future versions.")
}
}
return runSign(cmd, opts)
},
}
Expand All @@ -112,9 +120,10 @@ Example - [Experimental] Sign an OCI artifact identified by a tag and referenced
cmd.SetPflagPluginConfig(command.Flags(), &opts.pluginConfig)
cmd.SetPflagUserMetadata(command.Flags(), &opts.userMetadata, cmd.PflagUserMetadataSignUsage)
cmd.SetPflagReferrersAPI(command.Flags(), &opts.allowReferrersAPI, fmt.Sprintf(cmd.PflagReferrersUsageFormat, "sign"))
cmd.SetPflagReferrersTag(command.Flags(), &opts.forceReferrersTag, "force to store signatures using the referrers tag schema")
command.Flags().BoolVar(&opts.ociLayout, "oci-layout", false, "[Experimental] sign the artifact stored as OCI image layout")
command.MarkFlagsMutuallyExclusive("oci-layout", "allow-referrers-api")
experimental.HideFlags(command, experimentalExamples, []string{"allow-referrers-api", "oci-layout"})
command.MarkFlagsMutuallyExclusive("oci-layout", "force-referrers-tag", "allow-referrers-api")
experimental.HideFlags(command, experimentalExamples, []string{"oci-layout"})
return command
}

Expand All @@ -127,14 +136,11 @@ func runSign(command *cobra.Command, cmdOpts *signOpts) error {
if err != nil {
return err
}
if cmdOpts.allowReferrersAPI {
fmt.Fprintln(os.Stderr, "Warning: using the Referrers API to store signature. On success, must set the `--allow-referrers-api` flag to list, inspect, and verify the signature.")
}
sigRepo, err := getRepository(ctx, cmdOpts.inputType, cmdOpts.reference, &cmdOpts.SecureFlagOpts, cmdOpts.allowReferrersAPI)
sigRepo, err := getRepository(ctx, cmdOpts.inputType, cmdOpts.reference, &cmdOpts.SecureFlagOpts, cmdOpts.forceReferrersTag)
if err != nil {
return err
}
signOpts, err := prepareSigningOpts(ctx, cmdOpts, sigRepo)
signOpts, err := prepareSigningOpts(cmdOpts)
if err != nil {
return err
}
Expand Down Expand Up @@ -162,7 +168,7 @@ func runSign(command *cobra.Command, cmdOpts *signOpts) error {
return nil
}

func prepareSigningOpts(ctx context.Context, opts *signOpts, sigRepo notationregistry.Repository) (notation.SignOptions, error) {
func prepareSigningOpts(opts *signOpts) (notation.SignOptions, error) {
mediaType, err := envelope.GetEnvelopeMediaType(opts.SignerFlagOpts.SignatureFormat)
if err != nil {
return notation.SignOptions{}, err
Expand Down
Loading

0 comments on commit 0f556be

Please sign in to comment.