diff --git a/cmd/notation/common.go b/cmd/notation/common.go index 46f0871d1..674da7f84 100644 --- a/cmd/notation/common.go +++ b/cmd/notation/common.go @@ -39,25 +39,6 @@ var ( setFlagPlainHTTP = func(fs *pflag.FlagSet, p *bool) { fs.BoolVar(p, flagPlainHTTP.Name, false, flagPlainHTTP.Usage) } - - flagMediaType = &pflag.Flag{ - Name: "media-type", - Usage: "specify the media type of the manifest read from file or stdin", - DefValue: defaultMediaType, - } - setFlagMediaType = func(fs *pflag.FlagSet, p *string) { - fs.StringVar(p, flagMediaType.Name, defaultMediaType, flagMediaType.Usage) - } - - flagLocal = &pflag.Flag{ - Name: "local", - Shorthand: "l", - Usage: "reference is a local file", - DefValue: "false", - } - setFlagLocal = func(fs *pflag.FlagSet, p *bool) { - fs.BoolVarP(p, flagLocal.Name, flagLocal.Shorthand, false, flagLocal.Usage) - } ) type SecureFlagOpts struct { @@ -74,25 +55,3 @@ func (opts *SecureFlagOpts) ApplyFlags(fs *pflag.FlagSet) { opts.Username = os.Getenv(defaultUsernameEnv) opts.Password = os.Getenv(defaultPasswordEnv) } - -type CommonFlagOpts struct { - Local bool - MediaType string -} - -// ApplyFlags set flags and their default values for the FlagSet -func (opts *CommonFlagOpts) ApplyFlags(fs *pflag.FlagSet) { - setFlagMediaType(fs, &opts.MediaType) - setFlagLocal(fs, &opts.Local) -} - -type RemoteFlagOpts struct { - SecureFlagOpts - CommonFlagOpts -} - -// ApplyFlags set flags and their default values for the FlagSet -func (opts *RemoteFlagOpts) ApplyFlags(fs *pflag.FlagSet) { - opts.SecureFlagOpts.ApplyFlags(fs) - opts.CommonFlagOpts.ApplyFlags(fs) -} diff --git a/cmd/notation/main.go b/cmd/notation/main.go index 53d7098dc..185927862 100644 --- a/cmd/notation/main.go +++ b/cmd/notation/main.go @@ -20,7 +20,9 @@ func main() { keyCommand(), pluginCommand(), loginCommand(nil), - logoutCommand(nil)) + logoutCommand(nil), + versionCommand(), + ) if err := cmd.Execute(); err != nil { log.Fatal(err) } diff --git a/cmd/notation/manifest.go b/cmd/notation/manifest.go index f701b2b8d..b9d82baf2 100644 --- a/cmd/notation/manifest.go +++ b/cmd/notation/manifest.go @@ -3,32 +3,17 @@ package main import ( "context" "errors" - "io" - "math" - "os" "github.com/notaryproject/notation-go" - "github.com/opencontainers/go-digest" "oras.land/oras-go/v2/registry" ) -func getManifestDescriptorFromContext(ctx context.Context, opts *RemoteFlagOpts, ref string) (notation.Descriptor, error) { +func getManifestDescriptorFromContext(ctx context.Context, opts *SecureFlagOpts, ref string) (notation.Descriptor, error) { if ref == "" { return notation.Descriptor{}, errors.New("missing reference") } - return getManifestDescriptorFromContextWithReference(ctx, opts, ref) -} - -func getManifestDescriptorFromContextWithReference(ctx context.Context, opts *RemoteFlagOpts, ref string) (notation.Descriptor, error) { - if opts.Local { - mediaType := opts.MediaType - if ref == "-" { - return getManifestDescriptorFromReader(os.Stdin, mediaType) - } - return getManifestDescriptorFromFile(ref, mediaType) - } - return getManifestDescriptorFromReference(ctx, &opts.SecureFlagOpts, ref) + return getManifestDescriptorFromReference(ctx, opts, ref) } func getManifestDescriptorFromReference(ctx context.Context, opts *SecureFlagOpts, reference string) (notation.Descriptor, error) { @@ -42,28 +27,3 @@ func getManifestDescriptorFromReference(ctx context.Context, opts *SecureFlagOpt } return repo.Resolve(ctx, ref.ReferenceOrDefault()) } - -func getManifestDescriptorFromFile(path, mediaType string) (notation.Descriptor, error) { - file, err := os.Open(path) - if err != nil { - return notation.Descriptor{}, err - } - defer file.Close() - return getManifestDescriptorFromReader(file, mediaType) -} - -func getManifestDescriptorFromReader(r io.Reader, mediaType string) (notation.Descriptor, error) { - lr := &io.LimitedReader{ - R: r, - N: math.MaxInt64, - } - digest, err := digest.SHA256.FromReader(lr) - if err != nil { - return notation.Descriptor{}, err - } - return notation.Descriptor{ - MediaType: mediaType, - Digest: digest, - Size: math.MaxInt64 - lr.N, - }, nil -} diff --git a/cmd/notation/sign.go b/cmd/notation/sign.go index 75030be2a..b1c7a83bc 100644 --- a/cmd/notation/sign.go +++ b/cmd/notation/sign.go @@ -7,7 +7,6 @@ import ( "time" "github.com/notaryproject/notation-go" - "github.com/notaryproject/notation-go/crypto/timestamp" "github.com/notaryproject/notation/internal/cmd" "github.com/notaryproject/notation/internal/envelope" "github.com/spf13/cobra" @@ -15,12 +14,10 @@ import ( type signOpts struct { cmd.SignerFlagOpts - RemoteFlagOpts - timestamp string - expiry time.Duration - originReference string - pluginConfig []string - reference string + SecureFlagOpts + expiry time.Duration + pluginConfig []string + reference string } func signCommand(opts *signOpts) *cobra.Command { @@ -28,9 +25,9 @@ func signCommand(opts *signOpts) *cobra.Command { opts = &signOpts{} } command := &cobra.Command{ - Use: "sign [reference]", - Short: "Sign OCI artifacts", - Long: `Sign OCI artifacts + Use: "sign [flags] ", + Short: "Sign artifacts", + Long: `Sign artifacts Prerequisite: a signing key needs to be configured using the command "notation key". @@ -38,14 +35,11 @@ Example - Sign a container image using the default signing key, with the default notation sign /: Example - Sign a container image using the default signing key, with the COSE envelope: - notation sign --envelope-type cose /: + notation sign --signature-format cose /: Example - Sign a container image using the specified key name notation sign --key /: -Example - Sign a container image using a local testing key and certificate file directly - notation sign --key-file --cert-file /: - Example - Sign a container image using the image digest notation sign /@ `, @@ -61,11 +55,8 @@ Example - Sign a container image using the image digest }, } opts.SignerFlagOpts.ApplyFlags(command.Flags()) - opts.RemoteFlagOpts.ApplyFlags(command.Flags()) - - cmd.SetPflagTimestamp(command.Flags(), &opts.timestamp) + opts.SecureFlagOpts.ApplyFlags(command.Flags()) cmd.SetPflagExpiry(command.Flags(), &opts.expiry) - cmd.SetPflagReference(command.Flags(), &opts.originReference) cmd.SetPflagPluginConfig(command.Flags(), &opts.pluginConfig) return command @@ -103,28 +94,16 @@ func runSign(command *cobra.Command, cmdOpts *signOpts) error { } func prepareSigningContent(ctx context.Context, opts *signOpts) (notation.Descriptor, notation.SignOptions, error) { - manifestDesc, err := getManifestDescriptorFromContext(ctx, &opts.RemoteFlagOpts, opts.reference) + manifestDesc, err := getManifestDescriptorFromContext(ctx, &opts.SecureFlagOpts, opts.reference) if err != nil { return notation.Descriptor{}, notation.SignOptions{}, err } - if identity := opts.originReference; identity != "" { - manifestDesc.Annotations = map[string]string{ - "identity": identity, - } - } - var tsa timestamp.Timestamper - if endpoint := opts.timestamp; endpoint != "" { - if tsa, err = timestamp.NewHTTPTimestamper(nil, endpoint); err != nil { - return notation.Descriptor{}, notation.SignOptions{}, err - } - } pluginConfig, err := cmd.ParseFlagPluginConfig(opts.pluginConfig) if err != nil { return notation.Descriptor{}, notation.SignOptions{}, err } return manifestDesc, notation.SignOptions{ Expiry: cmd.GetExpiry(opts.expiry), - TSA: tsa, PluginConfig: pluginConfig, }, nil } diff --git a/cmd/notation/sign_test.go b/cmd/notation/sign_test.go index 5170b6708..0333a2127 100644 --- a/cmd/notation/sign_test.go +++ b/cmd/notation/sign_test.go @@ -15,31 +15,20 @@ func TestSignCommand_BasicArgs(t *testing.T) { command := signCommand(opts) expected := &signOpts{ reference: "ref", - RemoteFlagOpts: RemoteFlagOpts{ - SecureFlagOpts: SecureFlagOpts{ - Username: "user", - Password: "password", - }, - CommonFlagOpts: CommonFlagOpts{ - MediaType: defaultMediaType, - }, + SecureFlagOpts: SecureFlagOpts{ + Username: "user", + Password: "password", }, SignerFlagOpts: cmd.SignerFlagOpts{ Key: "key", - KeyFile: "keyfile", - CertFile: "certfile", EnvelopeType: envelope.JWS, }, - pluginConfig: []string{"key0=val0"}, } if err := command.ParseFlags([]string{ expected.reference, "-u", expected.Username, "--password", expected.Password, - "--key", expected.Key, - "--key-file", expected.KeyFile, - "--cert-file", expected.CertFile, - "--plugin-config", "key0=val0"}); err != nil { + "--key", expected.Key}); err != nil { t.Fatalf("Parse Flag failed: %v", err) } if err := command.Args(command, command.Flags().Args()); err != nil { @@ -55,39 +44,25 @@ func TestSignCommand_MoreArgs(t *testing.T) { command := signCommand(opts) expected := &signOpts{ reference: "ref", - RemoteFlagOpts: RemoteFlagOpts{ - SecureFlagOpts: SecureFlagOpts{ - Username: "user", - Password: "password", - PlainHTTP: true, - }, - CommonFlagOpts: CommonFlagOpts{ - MediaType: "mediaT", - Local: true, - }, + SecureFlagOpts: SecureFlagOpts{ + Username: "user", + Password: "password", + PlainHTTP: true, }, SignerFlagOpts: cmd.SignerFlagOpts{ Key: "key", - KeyFile: "keyfile", - CertFile: "certfile", EnvelopeType: envelope.COSE, }, - expiry: 24 * time.Hour, - pluginConfig: []string{"key0=val0"}, + expiry: 24 * time.Hour, } if err := command.ParseFlags([]string{ expected.reference, "-u", expected.Username, "-p", expected.Password, "--key", expected.Key, - "--key-file", expected.KeyFile, - "--cert-file", expected.CertFile, "--plain-http", - "--media-type", expected.MediaType, - "-l", - "--envelope-type", expected.SignerFlagOpts.EnvelopeType, - "--expiry", expected.expiry.String(), - "--plugin-config", "key0=val0"}); err != nil { + "--signature-format", expected.SignerFlagOpts.EnvelopeType, + "--expiry", expected.expiry.String()}); err != nil { t.Fatalf("Parse Flag failed: %v", err) } if err := command.Args(command, command.Flags().Args()); err != nil { @@ -103,31 +78,17 @@ func TestSignCommand_CorrectConfig(t *testing.T) { command := signCommand(opts) expected := &signOpts{ reference: "ref", - RemoteFlagOpts: RemoteFlagOpts{ - CommonFlagOpts: CommonFlagOpts{ - MediaType: "mediaT", - Local: true, - }, - }, SignerFlagOpts: cmd.SignerFlagOpts{ Key: "key", - KeyFile: "keyfile", - CertFile: "certfile", EnvelopeType: envelope.JWS, }, - expiry: 365 * 24 * time.Hour, - pluginConfig: []string{"key0=val0", "key1=val1"}, - originReference: "originref", + expiry: 365 * 24 * time.Hour, + pluginConfig: []string{"key0=val0", "key1=val1"}, } if err := command.ParseFlags([]string{ expected.reference, "--key", expected.Key, - "--key-file", expected.KeyFile, - "--cert-file", expected.CertFile, - "--media-type", expected.MediaType, - "-r", expected.originReference, - "--local", - "--envelope-type", expected.SignerFlagOpts.EnvelopeType, + "--signature-format", expected.SignerFlagOpts.EnvelopeType, "--expiry", expected.expiry.String(), "--plugin-config", "key0=val0", "--plugin-config", "key1=val1"}); err != nil { diff --git a/cmd/notation/verify.go b/cmd/notation/verify.go index 4d4f66086..e5fd71a5f 100644 --- a/cmd/notation/verify.go +++ b/cmd/notation/verify.go @@ -27,11 +27,7 @@ func verifyCommand(opts *verifyOpts) *cobra.Command { command := &cobra.Command{ Use: "verify [flags] ", Short: "Verify Artifacts", - Long: `Verify signatures associated with the artifact. - -Prerequisite: a trusted certificate needs to be generated or added using the command "notation cert". - -notation verify [--plugin-config =...] [--username ] [--password ] `, + Long: "Verify signatures associated with the artifact.", Args: func(cmd *cobra.Command, args []string) error { if len(args) == 0 { return errors.New("missing reference") diff --git a/go.mod b/go.mod index 31b9e416a..9cb9aa152 100644 --- a/go.mod +++ b/go.mod @@ -5,8 +5,8 @@ go 1.19 require ( github.com/distribution/distribution/v3 v3.0.0-20220729163034-26163d82560f github.com/docker/docker-credential-helpers v0.7.0 - github.com/notaryproject/notation-core-go v0.1.0-alpha.4 - github.com/notaryproject/notation-go v0.11.0-alpha.4 + github.com/notaryproject/notation-core-go v0.1.0-alpha.4.0.20221017041709-56bd40a80d26 + github.com/notaryproject/notation-go v0.11.0-alpha.4.0.20221025011337-7ad4eca1a568 github.com/opencontainers/go-digest v1.0.0 github.com/spf13/cobra v1.6.0 github.com/spf13/pflag v1.0.5 diff --git a/go.sum b/go.sum index a14fad87d..2732ca41a 100644 --- a/go.sum +++ b/go.sum @@ -19,8 +19,12 @@ github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7P github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/notaryproject/notation-core-go v0.1.0-alpha.4 h1:0OhA2PjwT0TAouHOrU4K+8H9YM6E/e4/ocoq+JiHeOw= github.com/notaryproject/notation-core-go v0.1.0-alpha.4/go.mod h1:s8DZptmN1rZS0tBLTPt/w+d4o6eAcGWTYYJlXaJhQ4U= +github.com/notaryproject/notation-core-go v0.1.0-alpha.4.0.20221017041709-56bd40a80d26 h1:tAM+m4MocXBXdRBr8GDWABWHw3XiO3PE9+L38aEECLc= +github.com/notaryproject/notation-core-go v0.1.0-alpha.4.0.20221017041709-56bd40a80d26/go.mod h1:s8DZptmN1rZS0tBLTPt/w+d4o6eAcGWTYYJlXaJhQ4U= github.com/notaryproject/notation-go v0.11.0-alpha.4 h1:PNptLtrhW0jyw10hUWU+KNzvzeuBBZmg+/1IUaGYE10= github.com/notaryproject/notation-go v0.11.0-alpha.4/go.mod h1:4xYTcW4wfsXkXw3piUA53uSW82RwdXyipSEtiiRVrCw= +github.com/notaryproject/notation-go v0.11.0-alpha.4.0.20221025011337-7ad4eca1a568 h1:omjj1Ssrf85KFLyFP4pC50G9xqb7jUhy6RvBjJZ0tgY= +github.com/notaryproject/notation-go v0.11.0-alpha.4.0.20221025011337-7ad4eca1a568/go.mod h1:pTGrgvkitZClSoQY31P4LgBExtRRXg1AD/9tkFmxaS0= github.com/opencontainers/distribution-spec/specs-go v0.0.0-20220620172159-4ab4752c3b86 h1:Oumw+lPnO8qNLTY2mrqPJZMoGExLi/0h/DdikoLTXVU= github.com/opencontainers/distribution-spec/specs-go v0.0.0-20220620172159-4ab4752c3b86/go.mod h1:aA4vdXRS8E1TG7pLZOz85InHi3BiPdErh8IpJN6E0x4= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= diff --git a/internal/cmd/flags.go b/internal/cmd/flags.go index 5afbcaec8..f948b06bf 100644 --- a/internal/cmd/flags.go +++ b/internal/cmd/flags.go @@ -14,30 +14,14 @@ var ( PflagKey = &pflag.Flag{ Name: "key", Shorthand: "k", - Usage: "signing key name", + Usage: "signing key name, for a key previously added to notation's key list.", } SetPflagKey = func(fs *pflag.FlagSet, p *string) { fs.StringVarP(p, PflagKey.Name, PflagKey.Shorthand, "", PflagKey.Usage) } - PflagKeyFile = &pflag.Flag{ - Name: "key-file", - Usage: "signing key file", - } - SetPflagKeyFile = func(fs *pflag.FlagSet, p *string) { - fs.StringVar(p, PflagKeyFile.Name, "", PflagKeyFile.Usage) - } - - PflagCertFile = &pflag.Flag{ - Name: "cert-file", - Usage: "signing certificate file", - } - SetPflagCertFile = func(fs *pflag.FlagSet, p *string) { - fs.StringVar(p, PflagCertFile.Name, "", PflagCertFile.Usage) - } - PflagEnvelopeType = &pflag.Flag{ - Name: "envelope-type", + Name: "signature-format", Usage: "signature envelope format, options: 'jws', 'cose'", } SetPflagSignatureFormat = func(fs *pflag.FlagSet, p *string) { @@ -56,7 +40,7 @@ var ( PflagExpiry = &pflag.Flag{ Name: "expiry", Shorthand: "e", - Usage: "expire duration", + Usage: "optional expiry that provides a \"best by use\" time for the artifact. The duration is specified in minutes(m) and/or hours(h). For example: 12h, 30m, 3h20m", } SetPflagExpiry = func(fs *pflag.FlagSet, p *time.Duration) { fs.DurationVarP(p, PflagExpiry.Name, PflagExpiry.Shorthand, time.Duration(0), PflagExpiry.Usage) diff --git a/internal/cmd/options.go b/internal/cmd/options.go index 99defc1a8..3751c4d8f 100644 --- a/internal/cmd/options.go +++ b/internal/cmd/options.go @@ -7,15 +7,11 @@ import ( // SignerFlagOpts cmd opts for using cmd.GetSigner type SignerFlagOpts struct { Key string - KeyFile string - CertFile string EnvelopeType string } // ApplyFlags set flags and their default values for the FlagSet func (opts *SignerFlagOpts) ApplyFlags(fs *pflag.FlagSet) { SetPflagKey(fs, &opts.Key) - SetPflagKeyFile(fs, &opts.KeyFile) - SetPflagCertFile(fs, &opts.CertFile) SetPflagSignatureFormat(fs, &opts.EnvelopeType) } diff --git a/internal/cmd/signer.go b/internal/cmd/signer.go index 872f727ba..8c11cb130 100644 --- a/internal/cmd/signer.go +++ b/internal/cmd/signer.go @@ -21,10 +21,6 @@ func GetSigner(opts *SignerFlagOpts) (notation.Signer, error) { if err != nil { return nil, err } - if keyPath := opts.KeyFile; keyPath != "" { - certPath := opts.CertFile - return signature.NewSignerFromFiles(keyPath, certPath, mediaType) - } // Construct a signer from preconfigured key pair in config.json // if key name is provided as the CLI argument key, err := configutil.ResolveKey(opts.Key) diff --git a/specs/commandline/sign.md b/specs/commandline/sign.md index 02280ad03..995ce60b6 100644 --- a/specs/commandline/sign.md +++ b/specs/commandline/sign.md @@ -12,20 +12,17 @@ Signs an OCI artifact that is stored in a registry. Upon successful signing, the Sign artifacts Usage: - notation sign [flags] + notation sign [flags] Flags: - --cert-file string Location of file containing a complete certificate chain for the signing key. Use this flag with '--key-file'. - -e, --expiry duration Optional expiry that provides a "best by use" time for the artifact. The duration is specified in minutes(m), hours(h) or days(d). For example: 30d, 12h, 30m, 1d3h20m - -h, --help Help for sign - -k, --key string Signing key name, for a key previously added to notation's key list. - --key-file string Location of file containing signing key file. Use this flag with '--cert-file'. - -p, --password string Password or identity token for registry operations (default to $NOTATION_PASSWORD if not specified) - --plugin-config strings List of {key}={value} pairs that are passed as is to a plugin, if the key (--key) is associated with a signing plugin, refer plugin documentation to set appropriate values - -u, --username string Username for registry operations (default to $NOTATION_USERNAME if not specified) - -Global Flags: - --plain-http Registry access via plain HTTP + -e, --expiry duration optional expiry that provides a "best by use" time for the artifact. The duration is specified in minutes(m) and/or hours(h). For example: 12h, 30m, 3h20m + -h, --help help for sign + -k, --key string signing key name, for a key previously added to notation's key list. + -p, --password string password for registry operations (default to $NOTATION_PASSWORD if not specified) + --plain-http registry access via plain HTTP + --plugin-config strings {key}={value} pairs that are passed as it is to a plugin, refer plugin's documentation to set appropriate values + --signature-format string signature envelope format, options: 'jws', 'cose' (default "jws") + -u, --username string username for registry operations (default to $NOTATION_USERNAME if not specified) ``` ## Usage @@ -85,9 +82,3 @@ notation key list # Sign a container image using the specified key name notation sign --key /: ``` - -### Sign a container image using a local key and certificate which are not added in the signing key list - -```shell -notation sign --key-file --cert-file /: -```