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: upgrade to OCI 1.1 #916

Merged
merged 21 commits into from
Apr 16, 2024
Merged
Show file tree
Hide file tree
Changes from 16 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
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
shizhMSFT marked this conversation as resolved.
Show resolved Hide resolved
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.21`.
Two-Hearts marked this conversation as resolved.
Show resolved Hide resolved

## Windows with WSL or Linux

Expand Down
13 changes: 7 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 ignored.")
Two-Hearts marked this conversation as resolved.
Show resolved Hide resolved
}
return runInspect(cmd, opts)
},
}
Expand All @@ -115,7 +114,7 @@ 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"})
experimental.HideFlags(command, "", []string{"allow-referrers-api"})
Two-Hearts marked this conversation as resolved.
Show resolved Hide resolved
return command
}

Expand All @@ -129,7 +128,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
12 changes: 7 additions & 5 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,14 +81,16 @@ 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 ignored.")
Two-Hearts marked this conversation as resolved.
Show resolved Hide resolved
}
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"})
Two-Hearts marked this conversation as resolved.
Show resolved Hide resolved
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"})
Two-Hearts marked this conversation as resolved.
Show resolved Hide resolved
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 set, Notation will always generate an image index
Two-Hearts marked this conversation as resolved.
Show resolved Hide resolved
// according to the Referrers tag schema to store signature.
//
// When forceReferrersTag is not set, Notation will first try to store the
Two-Hearts marked this conversation as resolved.
Show resolved Hide resolved
// 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 NOT set 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("Generating the referrers tag schema")
if err := remoteRepo.SetReferrersCapability(false); err != nil {
return nil, err
}
} else {
logger.Info("Trying to use the Referrers API, fallback if not supported")
}
Two-Hearts marked this conversation as resolved.
Show resolved Hide resolved
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
30 changes: 18 additions & 12 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, use '--force-referrers-tag=false' instead.")
Two-Hearts marked this conversation as resolved.
Show resolved Hide resolved
opts.forceReferrersTag = false
} else {
fmt.Fprintln(os.Stderr, "Warning: flag '--allow-referrers-api' is deprecated, use '--force-referrers-tag' instead.")
Two-Hearts marked this conversation as resolved.
Show resolved Hide resolved
}
}
return runSign(cmd, opts)
},
}
Expand All @@ -112,8 +120,9 @@ 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")
command.MarkFlagsMutuallyExclusive("oci-layout", "force-referrers-tag", "allow-referrers-api")
experimental.HideFlags(command, experimentalExamples, []string{"allow-referrers-api", "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
Loading