From 5f289b6aa02b354b030887beb196d3cd24d5430a Mon Sep 17 00:00:00 2001 From: Pritesh Bandi Date: Fri, 22 Dec 2023 23:03:25 -0800 Subject: [PATCH 1/5] chore: start using plugin-framework package Signed-off-by: Pritesh Bandi --- go.mod | 3 + go.sum | 2 + internal/mock/mocks.go | 23 +++-- internal/testdata/oci-layout/index.json | 20 +--- plugin/integration_test.go | 10 +- plugin/manager.go | 21 +++-- plugin/manager_test.go | 32 +++---- plugin/plugin.go | 70 ++++---------- plugin/plugin_test.go | 79 ++++++++-------- plugin/proto/algorithm.go | 113 ++++++++--------------- plugin/proto/algorithm_test.go | 71 +++++++------- plugin/proto/errors.go | 41 ++------ plugin/proto/errors_test.go | 24 ++--- plugin/proto/metadata.go | 22 +---- plugin/proto/metadata_test.go | 16 ++-- plugin/proto/proto.go | 56 ----------- plugin/proto/sign.go | 84 ----------------- plugin/proto/verify.go | 64 ------------- plugin/testdata/plugins/foo/notation-foo | 0 signer/plugin.go | 27 +++--- signer/plugin_test.go | 51 +++++----- signer/signer_test.go | 13 +-- verifier/verifier.go | 42 +++++---- verifier/verifier_test.go | 75 +++++++-------- 24 files changed, 316 insertions(+), 643 deletions(-) delete mode 100644 plugin/proto/sign.go delete mode 100644 plugin/proto/verify.go mode change 100644 => 100755 plugin/testdata/plugins/foo/notation-foo diff --git a/go.mod b/go.mod index eb7fc6d7..ce9c0600 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.20 require ( github.com/go-ldap/ldap/v3 v3.4.6 github.com/notaryproject/notation-core-go v1.0.1 + github.com/notaryproject/notation-plugin-framework-go v0.0.0-20231222132521-c8c68d2fe13b github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.1.0-rc5 github.com/veraison/go-cose v1.1.0 @@ -22,3 +23,5 @@ require ( github.com/x448/float16 v0.8.4 // indirect golang.org/x/sync v0.4.0 // indirect ) + +replace github.com/notaryproject/notation-plugin-framework-go => /Volumes/workplace/notaryproject/notation-plugin-framework-go diff --git a/go.sum b/go.sum index 6e154145..dcb02c30 100644 --- a/go.sum +++ b/go.sum @@ -17,6 +17,8 @@ github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/notaryproject/notation-core-go v1.0.1 h1:01doxjDERbd0vocLQrlJdusKrRLNNn50OJzp0c5I4Cw= github.com/notaryproject/notation-core-go v1.0.1/go.mod h1:rayl8WlKgS4YxOZgDO0iGGB4Ef515ZFZUFaZDmsPXgE= +github.com/notaryproject/notation-plugin-framework-go v0.0.0-20231222132521-c8c68d2fe13b h1:HA7UI2hTamsehj2820fyVU4hECtyv9yx9LvFeErErDg= +github.com/notaryproject/notation-plugin-framework-go v0.0.0-20231222132521-c8c68d2fe13b/go.mod h1:RqWSrTOtEASCrGOEffq0n8pSg2KOgKYiWqFWczRSics= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI= diff --git a/internal/mock/mocks.go b/internal/mock/mocks.go index 596be9dd..c5c3695c 100644 --- a/internal/mock/mocks.go +++ b/internal/mock/mocks.go @@ -18,8 +18,7 @@ import ( _ "embed" "github.com/notaryproject/notation-core-go/signature" - "github.com/notaryproject/notation-go/plugin" - "github.com/notaryproject/notation-go/plugin/proto" + pluginframework "github.com/notaryproject/notation-plugin-framework-go/plugin" "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) @@ -168,45 +167,45 @@ func (t Repository) PushSignature(ctx context.Context, mediaType string, blob [] } type PluginMock struct { - Metadata proto.GetMetadataResponse + Metadata pluginframework.GetMetadataResponse ExecuteResponse interface{} ExecuteError error } -func (p *PluginMock) GetMetadata(ctx context.Context, req *proto.GetMetadataRequest) (*proto.GetMetadataResponse, error) { +func (p *PluginMock) GetMetadata(ctx context.Context, req *pluginframework.GetMetadataRequest) (*pluginframework.GetMetadataResponse, error) { return &p.Metadata, nil } -func (p *PluginMock) VerifySignature(ctx context.Context, req *proto.VerifySignatureRequest) (*proto.VerifySignatureResponse, error) { - if resp, ok := p.ExecuteResponse.(*proto.VerifySignatureResponse); ok { +func (p *PluginMock) VerifySignature(ctx context.Context, req *pluginframework.VerifySignatureRequest) (*pluginframework.VerifySignatureResponse, error) { + if resp, ok := p.ExecuteResponse.(*pluginframework.VerifySignatureResponse); ok { return resp, nil } return nil, p.ExecuteError } -func (p *PluginMock) DescribeKey(ctx context.Context, req *proto.DescribeKeyRequest) (*proto.DescribeKeyResponse, error) { +func (p *PluginMock) DescribeKey(ctx context.Context, req *pluginframework.DescribeKeyRequest) (*pluginframework.DescribeKeyResponse, error) { panic("not implemented") // TODO: Implement } -func (p *PluginMock) GenerateSignature(ctx context.Context, req *proto.GenerateSignatureRequest) (*proto.GenerateSignatureResponse, error) { +func (p *PluginMock) GenerateSignature(ctx context.Context, req *pluginframework.GenerateSignatureRequest) (*pluginframework.GenerateSignatureResponse, error) { panic("not implemented") // TODO: Implement } -func (p *PluginMock) GenerateEnvelope(ctx context.Context, req *proto.GenerateEnvelopeRequest) (*proto.GenerateEnvelopeResponse, error) { +func (p *PluginMock) GenerateEnvelope(ctx context.Context, req *pluginframework.GenerateEnvelopeRequest) (*pluginframework.GenerateEnvelopeResponse, error) { panic("not implemented") // TODO: Implement } type PluginManager struct { - PluginCapabilities []proto.Capability + PluginCapabilities []pluginframework.Capability GetPluginError error PluginRunnerLoadError error PluginRunnerExecuteResponse interface{} PluginRunnerExecuteError error } -func (pm PluginManager) Get(ctx context.Context, name string) (plugin.Plugin, error) { +func (pm PluginManager) Get(ctx context.Context, name string) (pluginframework.Plugin, error) { return &PluginMock{ - Metadata: proto.GetMetadataResponse{ + Metadata: pluginframework.GetMetadataResponse{ Name: "plugin-name", Description: "for mocking in unit tests", Version: "1.0.0", diff --git a/internal/testdata/oci-layout/index.json b/internal/testdata/oci-layout/index.json index f784248d..73321250 100644 --- a/internal/testdata/oci-layout/index.json +++ b/internal/testdata/oci-layout/index.json @@ -1,19 +1 @@ -{ - "schemaVersion": 2, - "manifests": [ - { - "mediaType": "application/vnd.oci.image.manifest.v1+json", - "digest": "sha256:19dbd2e48e921426ee8ace4dc892edfb2ecdc1d1a72d5416c83670c30acecef0", - "size": 481, - "annotations": { - "io.containerd.image.name": "docker.io/library/alpine:v2", - "org.opencontainers.image.created": "2023-03-13T02:31:43Z", - "org.opencontainers.image.ref.name": "v2" - }, - "platform": { - "architecture": "amd64", - "os": "linux" - } - } - ] -} \ No newline at end of file +{"schemaVersion":2,"manifests":[{"mediaType":"application/vnd.oci.image.manifest.v1+json","digest":"sha256:19dbd2e48e921426ee8ace4dc892edfb2ecdc1d1a72d5416c83670c30acecef0","size":481,"annotations":{"io.containerd.image.name":"docker.io/library/alpine:v2","org.opencontainers.image.created":"2023-03-13T02:31:43Z","org.opencontainers.image.ref.name":"v2"},"platform":{"architecture":"amd64","os":"linux"}},{"mediaType":"application/vnd.oci.image.manifest.v1+json","digest":"sha256:1a0a67c6f7cfea22d50a18f48d857ed36cf8806e6542db1372675100db62d09b","size":723,"annotations":{"io.cncf.notary.x509chain.thumbprint#S256":"[\"9f5f5aecee24b5cfdc7a91f6d5ac5c3a5348feb17c934d403f59ac251549ea0d\"]","org.opencontainers.image.created":"2023-03-14T04:45:22Z"}},{"mediaType":"application/vnd.oci.image.manifest.v1+json","digest":"sha256:baeaea44f55c94499b7e082bd3c98ad5ec40fdf23ef89cdf4e5db6b83e4f18f5","size":728,"annotations":{"io.cncf.notary.x509chain.thumbprint#S256":"[\"9f5f5aecee24b5cfdc7a91f6d5ac5c3a5348feb17c934d403f59ac251549ea0d\"]","org.opencontainers.image.created":"2023-03-14T08:10:02Z"}}]} \ No newline at end of file diff --git a/plugin/integration_test.go b/plugin/integration_test.go index d48ad8e2..70b47a7d 100644 --- a/plugin/integration_test.go +++ b/plugin/integration_test.go @@ -23,16 +23,16 @@ import ( "testing" "github.com/notaryproject/notation-go/dir" - "github.com/notaryproject/notation-go/plugin/proto" + "github.com/notaryproject/notation-plugin-framework-go/plugin" ) -var exampleMetadata = proto.GetMetadataResponse{ +var exampleMetadata = plugin.GetMetadataResponse{ Name: "foo", Description: "friendly", Version: "1", URL: "example.com", SupportedContractVersions: []string{"1.0"}, - Capabilities: []proto.Capability{"cap"}} + Capabilities: []plugin.Capability{"cap"}} func preparePlugin(t *testing.T) string { root := t.TempDir() @@ -87,11 +87,11 @@ func TestIntegration(t *testing.T) { } // validate and create - plugin, err := mgr.Get(context.Background(), "foo") + actualPlugin, err := mgr.Get(context.Background(), "foo") if err != nil { t.Fatal(err) } - metadata, err := plugin.GetMetadata(context.Background(), &proto.GetMetadataRequest{}) + metadata, err := actualPlugin.GetMetadata(context.Background(), &plugin.GetMetadataRequest{}) if err != nil { t.Fatal(err) } diff --git a/plugin/manager.go b/plugin/manager.go index 65aea0bd..1d7202e5 100644 --- a/plugin/manager.go +++ b/plugin/manager.go @@ -25,12 +25,13 @@ import ( "github.com/notaryproject/notation-go/dir" "github.com/notaryproject/notation-go/internal/file" "github.com/notaryproject/notation-go/internal/semver" - "github.com/notaryproject/notation-go/plugin/proto" + "github.com/notaryproject/notation-plugin-framework-go/plugin" + pluginframework "github.com/notaryproject/notation-plugin-framework-go/plugin" ) // Manager manages plugins installed on the system. type Manager interface { - Get(ctx context.Context, name string) (Plugin, error) + Get(ctx context.Context, name string) (pluginframework.Plugin, error) List(ctx context.Context) ([]string, error) } @@ -47,7 +48,7 @@ func NewCLIManager(pluginFS dir.SysFS) *CLIManager { // Get returns a plugin on the system by its name. // // If the plugin is not found, the error is of type os.ErrNotExist. -func (m *CLIManager) Get(ctx context.Context, name string) (Plugin, error) { +func (m *CLIManager) Get(ctx context.Context, name string) (pluginframework.Plugin, error) { pluginPath := path.Join(name, binName(name)) path, err := m.pluginFS.SysPath(pluginPath) if err != nil { @@ -59,7 +60,7 @@ func (m *CLIManager) Get(ctx context.Context, name string) (Plugin, error) { } // List produces a list of the plugin names on the system. -func (m *CLIManager) List(ctx context.Context) ([]string, error) { +func (m *CLIManager) List(_ context.Context) ([]string, error) { var plugins []string fs.WalkDir(m.pluginFS, ".", func(dir string, d fs.DirEntry, err error) error { if err != nil { @@ -112,7 +113,7 @@ type CLIInstallOptions struct { // // If overwrite is set, version check is skipped. If existing // plugin is malfunctioning, it will be overwritten. -func (m *CLIManager) Install(ctx context.Context, installOpts CLIInstallOptions) (*proto.GetMetadataResponse, *proto.GetMetadataResponse, error) { +func (m *CLIManager) Install(ctx context.Context, installOpts CLIInstallOptions) (*plugin.GetMetadataResponse, *plugin.GetMetadataResponse, error) { // initialization overwrite := installOpts.Overwrite if installOpts.PluginPath == "" { @@ -147,12 +148,12 @@ func (m *CLIManager) Install(ctx context.Context, installOpts CLIInstallOptions) if err != nil { return nil, nil, fmt.Errorf("failed to create new CLI plugin: %w", err) } - newPluginMetadata, err := newPlugin.GetMetadata(ctx, &proto.GetMetadataRequest{}) + newPluginMetadata, err := newPlugin.GetMetadata(ctx, &plugin.GetMetadataRequest{}) if err != nil { return nil, nil, fmt.Errorf("failed to get metadata of new plugin: %w", err) } // check plugin existence and get existing plugin metadata - var existingPluginMetadata *proto.GetMetadataResponse + var existingPluginMetadata *plugin.GetMetadataResponse existingPlugin, err := m.Get(ctx, pluginName) if err != nil { // fail only if overwrite is not set @@ -160,7 +161,7 @@ func (m *CLIManager) Install(ctx context.Context, installOpts CLIInstallOptions) return nil, nil, fmt.Errorf("failed to check plugin existence: %w", err) } } else { // plugin already exists - existingPluginMetadata, err = existingPlugin.GetMetadata(ctx, &proto.GetMetadataRequest{}) + existingPluginMetadata, err = existingPlugin.GetMetadata(ctx, &plugin.GetMetadataRequest{}) if err != nil && !overwrite { // fail only if overwrite is not set return nil, nil, fmt.Errorf("failed to get metadata of existing plugin: %w", err) } @@ -203,7 +204,7 @@ func (m *CLIManager) Install(ctx context.Context, installOpts CLIInstallOptions) // Uninstall uninstalls a plugin on the system by its name. // If the plugin dir does not exist, os.ErrNotExist is returned. -func (m *CLIManager) Uninstall(ctx context.Context, name string) error { +func (m *CLIManager) Uninstall(_ context.Context, name string) error { pluginDirPath, err := m.pluginFS.SysPath(name) if err != nil { return err @@ -216,7 +217,7 @@ func (m *CLIManager) Uninstall(ctx context.Context, name string) error { // parsePluginFromDir checks if a dir is a valid plugin dir which contains // one and only one plugin executable file. The dir may contain extra lib files -// and LICENSE files. Sub-directories are ignored. +// and LICENSE files. Subdirectories are ignored. // // On success, the plugin executable file path, plugin name and // nil error are returned. diff --git a/plugin/manager_test.go b/plugin/manager_test.go index 8aa92f88..6e1ec523 100644 --- a/plugin/manager_test.go +++ b/plugin/manager_test.go @@ -25,7 +25,7 @@ import ( "testing/fstest" "github.com/notaryproject/notation-go/internal/mock/mockfs" - "github.com/notaryproject/notation-go/plugin/proto" + pluginframework "github.com/notaryproject/notation-plugin-framework-go/plugin" ) type testCommander struct { @@ -34,7 +34,7 @@ type testCommander struct { err error } -func (t testCommander) Output(ctx context.Context, path string, command proto.Command, req []byte) ([]byte, []byte, error) { +func (t testCommander) Output(ctx context.Context, path string, command pluginframework.Command, req []byte) ([]byte, []byte, error) { return t.stdout, t.stderr, t.err } @@ -50,7 +50,7 @@ type testInstallCommander struct { err error } -func (t testInstallCommander) Output(ctx context.Context, path string, command proto.Command, req []byte) ([]byte, []byte, error) { +func (t testInstallCommander) Output(ctx context.Context, path string, command pluginframework.Command, req []byte) ([]byte, []byte, error) { if path == t.existedPluginFilePath { return t.existedPluginStdout, t.existedPluginStderr, t.existedPluginErr } @@ -60,34 +60,34 @@ func (t testInstallCommander) Output(ctx context.Context, path string, command p return nil, nil, t.err } -var validMetadata = proto.GetMetadataResponse{ +var validMetadata = pluginframework.GetMetadataResponse{ Name: "foo", Description: "friendly", Version: "1.0.0", URL: "example.com", - SupportedContractVersions: []string{"1.0"}, Capabilities: []proto.Capability{proto.CapabilitySignatureGenerator}, + SupportedContractVersions: []string{"1.0"}, Capabilities: []pluginframework.Capability{pluginframework.CapabilitySignatureGenerator}, } -var validMetadataHigherVersion = proto.GetMetadataResponse{ +var validMetadataHigherVersion = pluginframework.GetMetadataResponse{ Name: "foo", Description: "friendly", Version: "1.1.0", URL: "example.com", - SupportedContractVersions: []string{"1.0"}, Capabilities: []proto.Capability{proto.CapabilitySignatureGenerator}, + SupportedContractVersions: []string{"1.0"}, Capabilities: []pluginframework.Capability{pluginframework.CapabilitySignatureGenerator}, } -var validMetadataLowerVersion = proto.GetMetadataResponse{ +var validMetadataLowerVersion = pluginframework.GetMetadataResponse{ Name: "foo", Description: "friendly", Version: "0.1.0", URL: "example.com", - SupportedContractVersions: []string{"1.0"}, Capabilities: []proto.Capability{proto.CapabilitySignatureGenerator}, + SupportedContractVersions: []string{"1.0"}, Capabilities: []pluginframework.Capability{pluginframework.CapabilitySignatureGenerator}, } -var validMetadataBar = proto.GetMetadataResponse{ +var validMetadataBar = pluginframework.GetMetadataResponse{ Name: "bar", Description: "friendly", Version: "1.0.0", URL: "example.com", - SupportedContractVersions: []string{"1.0"}, Capabilities: []proto.Capability{proto.CapabilitySignatureGenerator}, + SupportedContractVersions: []string{"1.0"}, Capabilities: []pluginframework.Capability{pluginframework.CapabilitySignatureGenerator}, } -var invalidMetadataName = proto.GetMetadataResponse{ +var invalidMetadataName = pluginframework.GetMetadataResponse{ Name: "foobar", Description: "friendly", Version: "1", URL: "example.com", - SupportedContractVersions: []string{"1.0"}, Capabilities: []proto.Capability{proto.CapabilitySignatureGenerator}, + SupportedContractVersions: []string{"1.0"}, Capabilities: []pluginframework.Capability{pluginframework.CapabilitySignatureGenerator}, } -var invalidContractVersionMetadata = proto.GetMetadataResponse{ +var invalidContractVersionMetadata = pluginframework.GetMetadataResponse{ Name: "foo", Description: "friendly", Version: "1", URL: "example.com", - SupportedContractVersions: []string{"110.0"}, Capabilities: []proto.Capability{proto.CapabilitySignatureGenerator}, + SupportedContractVersions: []string{"110.0"}, Capabilities: []pluginframework.Capability{pluginframework.CapabilitySignatureGenerator}, } func TestManager_Get(t *testing.T) { @@ -517,7 +517,7 @@ func TestManager_Uninstall(t *testing.T) { } } -func metadataJSON(m proto.GetMetadataResponse) []byte { +func metadataJSON(m pluginframework.GetMetadataResponse) []byte { d, err := json.Marshal(m) if err != nil { panic(err) diff --git a/plugin/plugin.go b/plugin/plugin.go index 0afb9ea6..adeb4871 100644 --- a/plugin/plugin.go +++ b/plugin/plugin.go @@ -31,45 +31,11 @@ import ( "github.com/notaryproject/notation-go/internal/slices" "github.com/notaryproject/notation-go/log" "github.com/notaryproject/notation-go/plugin/proto" + "github.com/notaryproject/notation-plugin-framework-go/plugin" ) var executor commander = &execCommander{} // for unit test -// GenericPlugin is the base requirement to be an plugin. -type GenericPlugin interface { - // GetMetadata returns the metadata information of the plugin. - GetMetadata(ctx context.Context, req *proto.GetMetadataRequest) (*proto.GetMetadataResponse, error) -} - -// SignPlugin defines the required methods to be a SignPlugin. -type SignPlugin interface { - GenericPlugin - - // DescribeKey returns the KeySpec of a key. - DescribeKey(ctx context.Context, req *proto.DescribeKeyRequest) (*proto.DescribeKeyResponse, error) - - // GenerateSignature generates the raw signature based on the request. - GenerateSignature(ctx context.Context, req *proto.GenerateSignatureRequest) (*proto.GenerateSignatureResponse, error) - - // GenerateEnvelope generates the Envelope with signature based on the - // request. - GenerateEnvelope(ctx context.Context, req *proto.GenerateEnvelopeRequest) (*proto.GenerateEnvelopeResponse, error) -} - -// VerifyPlugin defines the required method to be a VerifyPlugin. -type VerifyPlugin interface { - GenericPlugin - - // VerifySignature validates the signature based on the request. - VerifySignature(ctx context.Context, req *proto.VerifySignatureRequest) (*proto.VerifySignatureResponse, error) -} - -// Plugin defines required methods to be an Plugin. -type Plugin interface { - SignPlugin - VerifyPlugin -} - // CLIPlugin implements Plugin interface to CLI plugins. type CLIPlugin struct { name string @@ -77,7 +43,7 @@ type CLIPlugin struct { } // NewCLIPlugin returns a *CLIPlugin. -func NewCLIPlugin(ctx context.Context, name, path string) (*CLIPlugin, error) { +func NewCLIPlugin(_ context.Context, name, path string) (*CLIPlugin, error) { // validate file existence fi, err := os.Stat(path) if err != nil { @@ -99,8 +65,8 @@ func NewCLIPlugin(ctx context.Context, name, path string) (*CLIPlugin, error) { } // GetMetadata returns the metadata information of the plugin. -func (p *CLIPlugin) GetMetadata(ctx context.Context, req *proto.GetMetadataRequest) (*proto.GetMetadataResponse, error) { - var metadata proto.GetMetadataResponse +func (p *CLIPlugin) GetMetadata(ctx context.Context, req *plugin.GetMetadataRequest) (*plugin.GetMetadataResponse, error) { + var metadata plugin.GetMetadataResponse err := run(ctx, p.name, p.path, req, &metadata) if err != nil { return nil, err @@ -118,12 +84,12 @@ func (p *CLIPlugin) GetMetadata(ctx context.Context, req *proto.GetMetadataReque // DescribeKey returns the KeySpec of a key. // // if ContractVersion is not set, it will be set by the function. -func (p *CLIPlugin) DescribeKey(ctx context.Context, req *proto.DescribeKeyRequest) (*proto.DescribeKeyResponse, error) { +func (p *CLIPlugin) DescribeKey(ctx context.Context, req *plugin.DescribeKeyRequest) (*plugin.DescribeKeyResponse, error) { if req.ContractVersion == "" { req.ContractVersion = proto.ContractVersion } - var resp proto.DescribeKeyResponse + var resp plugin.DescribeKeyResponse err := run(ctx, p.name, p.path, req, &resp) return &resp, err } @@ -131,12 +97,12 @@ func (p *CLIPlugin) DescribeKey(ctx context.Context, req *proto.DescribeKeyReque // GenerateSignature generates the raw signature based on the request. // // if ContractVersion is not set, it will be set by the function. -func (p *CLIPlugin) GenerateSignature(ctx context.Context, req *proto.GenerateSignatureRequest) (*proto.GenerateSignatureResponse, error) { +func (p *CLIPlugin) GenerateSignature(ctx context.Context, req *plugin.GenerateSignatureRequest) (*plugin.GenerateSignatureResponse, error) { if req.ContractVersion == "" { req.ContractVersion = proto.ContractVersion } - var resp proto.GenerateSignatureResponse + var resp plugin.GenerateSignatureResponse err := run(ctx, p.name, p.path, req, &resp) return &resp, err } @@ -144,12 +110,12 @@ func (p *CLIPlugin) GenerateSignature(ctx context.Context, req *proto.GenerateSi // GenerateEnvelope generates the Envelope with signature based on the request. // // if ContractVersion is not set, it will be set by the function. -func (p *CLIPlugin) GenerateEnvelope(ctx context.Context, req *proto.GenerateEnvelopeRequest) (*proto.GenerateEnvelopeResponse, error) { +func (p *CLIPlugin) GenerateEnvelope(ctx context.Context, req *plugin.GenerateEnvelopeRequest) (*plugin.GenerateEnvelopeResponse, error) { if req.ContractVersion == "" { req.ContractVersion = proto.ContractVersion } - var resp proto.GenerateEnvelopeResponse + var resp plugin.GenerateEnvelopeResponse err := run(ctx, p.name, p.path, req, &resp) return &resp, err } @@ -157,17 +123,17 @@ func (p *CLIPlugin) GenerateEnvelope(ctx context.Context, req *proto.GenerateEnv // VerifySignature validates the signature based on the request. // // if ContractVersion is not set, it will be set by the function. -func (p *CLIPlugin) VerifySignature(ctx context.Context, req *proto.VerifySignatureRequest) (*proto.VerifySignatureResponse, error) { +func (p *CLIPlugin) VerifySignature(ctx context.Context, req *plugin.VerifySignatureRequest) (*plugin.VerifySignatureResponse, error) { if req.ContractVersion == "" { req.ContractVersion = proto.ContractVersion } - var resp proto.VerifySignatureResponse + var resp plugin.VerifySignatureResponse err := run(ctx, p.name, p.path, req, &resp) return &resp, err } -func run(ctx context.Context, pluginName string, pluginPath string, req proto.Request, resp interface{}) error { +func run(ctx context.Context, pluginName string, pluginPath string, req plugin.Request, resp interface{}) error { logger := log.GetLogger(ctx) // serialize request @@ -186,7 +152,7 @@ func run(ctx context.Context, pluginName string, pluginPath string, req proto.Re jsonErr := json.Unmarshal(stderr, &re) if jsonErr != nil { return proto.RequestError{ - Code: proto.ErrorCodeGeneric, + Code: plugin.ErrorCodeGeneric, Err: fmt.Errorf("response is not in JSON format. error: %v, stderr: %s", err, string(stderr))} } return re @@ -203,16 +169,16 @@ func run(ctx context.Context, pluginName string, pluginPath string, req proto.Re // commander is defined for mocking purposes. type commander interface { - // Output runs the command, passing req to the its stdin. + // Output runs the command, passing req to stdin. // It only returns an error if the binary can't be executed. // Returns stdout if err is nil, stderr if err is not nil. - Output(ctx context.Context, path string, command proto.Command, req []byte) (stdout []byte, stderr []byte, err error) + Output(ctx context.Context, path string, command plugin.Command, req []byte) (stdout []byte, stderr []byte, err error) } // execCommander implements the commander interface using exec.Command(). type execCommander struct{} -func (c execCommander) Output(ctx context.Context, name string, command proto.Command, req []byte) ([]byte, []byte, error) { +func (c execCommander) Output(ctx context.Context, name string, command plugin.Command, req []byte) ([]byte, []byte, error) { var stdout, stderr bytes.Buffer cmd := exec.CommandContext(ctx, name, string(command)) cmd.Stdin = bytes.NewReader(req) @@ -237,7 +203,7 @@ func ParsePluginName(fileName string) (string, error) { } // validate checks if the metadata is correctly populated. -func validate(metadata *proto.GetMetadataResponse) error { +func validate(metadata *plugin.GetMetadataResponse) error { if metadata.Name == "" { return errors.New("empty name") } diff --git a/plugin/plugin_test.go b/plugin/plugin_test.go index bf592663..bce8ff41 100644 --- a/plugin/plugin_test.go +++ b/plugin/plugin_test.go @@ -26,6 +26,7 @@ import ( "testing" "github.com/notaryproject/notation-go/plugin/proto" + "github.com/notaryproject/notation-plugin-framework-go/plugin" ) func TestGetMetadata(t *testing.T) { @@ -33,11 +34,11 @@ func TestGetMetadata(t *testing.T) { exitErr := errors.New("unknown error") stderr := []byte("sad") wantErr := proto.RequestError{ - Code: proto.ErrorCodeGeneric, + Code: plugin.ErrorCodeGeneric, Err: fmt.Errorf("response is not in JSON format. error: %v, stderr: %s", exitErr, string(stderr))} - plugin := CLIPlugin{} + cliPlugin := CLIPlugin{} executor = testCommander{stdout: nil, stderr: stderr, err: exitErr} - _, err := plugin.GetMetadata(context.Background(), &proto.GetMetadataRequest{}) + _, err := cliPlugin.GetMetadata(context.Background(), &plugin.GetMetadataRequest{}) if !errors.Is(err, wantErr) { t.Fatalf("should error. got err = %v, want %v", err, wantErr) } @@ -46,11 +47,11 @@ func TestGetMetadata(t *testing.T) { t.Run("plugin error is a valid json", func(t *testing.T) { stderr := []byte("{\"errorCode\":\"ACCESS_DENIED\"}") pluginErr := errors.New("plugin errors") - wantErr := proto.RequestError{Code: proto.ErrorCodeAccessDenied} + wantErr := proto.RequestError{Code: plugin.ErrorCodeAccessDenied} - plugin := CLIPlugin{} + cliPlugin := CLIPlugin{} executor = testCommander{stdout: nil, stderr: stderr, err: pluginErr} - _, err := plugin.GetMetadata(context.Background(), &proto.GetMetadataRequest{}) + _, err := cliPlugin.GetMetadata(context.Background(), &plugin.GetMetadataRequest{}) if !errors.Is(err, wantErr) { t.Fatalf("should error. got err = %v, want %v", err, wantErr) } @@ -60,11 +61,11 @@ func TestGetMetadata(t *testing.T) { exitErr := errors.New("system error") stderr := []byte("") wantErr := proto.RequestError{ - Code: proto.ErrorCodeGeneric, + Code: plugin.ErrorCodeGeneric, Err: fmt.Errorf("response is not in JSON format. error: %v, stderr: %s", exitErr, string(stderr))} - plugin := CLIPlugin{} + cliPlugin := CLIPlugin{} executor = testCommander{stdout: nil, stderr: stderr, err: exitErr} - _, err := plugin.GetMetadata(context.Background(), &proto.GetMetadataRequest{}) + _, err := cliPlugin.GetMetadata(context.Background(), &plugin.GetMetadataRequest{}) if !errors.Is(err, wantErr) { t.Fatalf("should error. got err = %v, want %v", err, wantErr) } @@ -74,15 +75,15 @@ func TestGetMetadata(t *testing.T) { func TestDescribeKey(t *testing.T) { t.Run("DescribeKey test", func(t *testing.T) { - keyResp := proto.DescribeKeyResponse{KeyID: "1", KeySpec: "RSA-4096"} + keyResp := plugin.DescribeKeyResponse{KeyID: "1", KeySpec: "RSA-4096"} output, err := json.Marshal(keyResp) if err != nil { t.Fatal("should not error.") } executor = testCommander{stdout: output, err: nil} - plugin := CLIPlugin{} - resp, err := plugin.DescribeKey(context.Background(), &proto.DescribeKeyRequest{}) + cliPlugin := CLIPlugin{} + resp, err := cliPlugin.DescribeKey(context.Background(), &plugin.DescribeKeyRequest{}) if err != nil { t.Fatalf("should not error. got err = %v", err) } @@ -94,7 +95,7 @@ func TestDescribeKey(t *testing.T) { func TestGenerateSignature(t *testing.T) { t.Run("GenerateSignature test", func(t *testing.T) { - keyResp := proto.GenerateSignatureResponse{ + keyResp := plugin.GenerateSignatureResponse{ KeyID: "1", Signature: []byte("xxxxx"), SigningAlgorithm: "ECDSA-SHA-256", @@ -106,8 +107,8 @@ func TestGenerateSignature(t *testing.T) { } executor = testCommander{stdout: output, err: nil} - plugin := CLIPlugin{} - resp, err := plugin.GenerateSignature(context.Background(), &proto.GenerateSignatureRequest{}) + cliPlugin := CLIPlugin{} + resp, err := cliPlugin.GenerateSignature(context.Background(), &plugin.GenerateSignatureRequest{}) if err != nil { t.Fatalf("should not error. got err = %v", err) } @@ -119,7 +120,7 @@ func TestGenerateSignature(t *testing.T) { func TestGenerateEnvelope(t *testing.T) { t.Run("GenerateEnvelope test", func(t *testing.T) { - keyResp := proto.GenerateEnvelopeResponse{ + keyResp := plugin.GenerateEnvelopeResponse{ SignatureEnvelope: []byte("{}"), SignatureEnvelopeType: "jws", Annotations: map[string]string{}, @@ -130,8 +131,8 @@ func TestGenerateEnvelope(t *testing.T) { } executor = testCommander{stdout: output, err: nil} - plugin := CLIPlugin{} - resp, err := plugin.GenerateEnvelope(context.Background(), &proto.GenerateEnvelopeRequest{}) + cliPlugin := CLIPlugin{} + resp, err := cliPlugin.GenerateEnvelope(context.Background(), &plugin.GenerateEnvelopeRequest{}) if err != nil { t.Fatalf("should not error. got err = %v", err) } @@ -143,8 +144,8 @@ func TestGenerateEnvelope(t *testing.T) { func TestVerifySignature(t *testing.T) { t.Run("VerifySignature test", func(t *testing.T) { - keyResp := proto.VerifySignatureResponse{ - VerificationResults: map[proto.Capability]*proto.VerificationResult{}, + keyResp := plugin.VerifySignatureResponse{ + VerificationResults: map[plugin.Capability]*plugin.VerificationResult{}, ProcessedAttributes: []interface{}{"attr1"}, } output, err := json.Marshal(keyResp) @@ -153,8 +154,8 @@ func TestVerifySignature(t *testing.T) { } executor = testCommander{stdout: output, err: nil} - plugin := CLIPlugin{} - resp, err := plugin.VerifySignature(context.Background(), &proto.VerifySignatureRequest{}) + cliPlugin := CLIPlugin{} + resp, err := cliPlugin.VerifySignature(context.Background(), &plugin.VerifySignatureRequest{}) if err != nil { t.Fatalf("should not error. got err = %v", err) } @@ -166,17 +167,17 @@ func TestVerifySignature(t *testing.T) { func TestValidateMetadata(t *testing.T) { tests := []struct { - m *proto.GetMetadataResponse + m *plugin.GetMetadataResponse wantErr bool }{ - {&proto.GetMetadataResponse{}, true}, - {&proto.GetMetadataResponse{Name: "name"}, true}, - {&proto.GetMetadataResponse{Name: "name", Description: "friendly"}, true}, - {&proto.GetMetadataResponse{Name: "name", Description: "friendly", Version: "1"}, true}, - {&proto.GetMetadataResponse{Name: "name", Description: "friendly", Version: "1", URL: "example.com"}, true}, - {&proto.GetMetadataResponse{Name: "name", Description: "friendly", Version: "1", URL: "example.com", Capabilities: []proto.Capability{"cap"}}, true}, - {&proto.GetMetadataResponse{Name: "name", Description: "friendly", Version: "1", URL: "example.com", SupportedContractVersions: []string{"1.0"}}, true}, - {&proto.GetMetadataResponse{Name: "name", Description: "friendly", Version: "1", URL: "example.com", SupportedContractVersions: []string{"1.0"}, Capabilities: []proto.Capability{"cap"}}, false}, + {&plugin.GetMetadataResponse{}, true}, + {&plugin.GetMetadataResponse{Name: "name"}, true}, + {&plugin.GetMetadataResponse{Name: "name", Description: "friendly"}, true}, + {&plugin.GetMetadataResponse{Name: "name", Description: "friendly", Version: "1"}, true}, + {&plugin.GetMetadataResponse{Name: "name", Description: "friendly", Version: "1", URL: "example.com"}, true}, + {&plugin.GetMetadataResponse{Name: "name", Description: "friendly", Version: "1", URL: "example.com", Capabilities: []plugin.Capability{"cap"}}, true}, + {&plugin.GetMetadataResponse{Name: "name", Description: "friendly", Version: "1", URL: "example.com", SupportedContractVersions: []string{"1.0"}}, true}, + {&plugin.GetMetadataResponse{Name: "name", Description: "friendly", Version: "1", URL: "example.com", SupportedContractVersions: []string{"1.0"}, Capabilities: []plugin.Capability{"cap"}}, false}, } for i, tt := range tests { t.Run(strconv.Itoa(i), func(t *testing.T) { @@ -218,7 +219,7 @@ func TestNewCLIPlugin_ValidError(t *testing.T) { } t.Run("command no response", func(t *testing.T) { executor = testCommander{} - _, err := p.GetMetadata(ctx, &proto.GetMetadataRequest{}) + _, err := p.GetMetadata(ctx, &plugin.GetMetadataRequest{}) if !strings.Contains(err.Error(), ErrNotCompliant.Error()) { t.Fatal("should fail the operation.") } @@ -226,7 +227,7 @@ func TestNewCLIPlugin_ValidError(t *testing.T) { t.Run("invalid json", func(t *testing.T) { executor = testCommander{stdout: []byte("content")} - _, err := p.GetMetadata(ctx, &proto.GetMetadataRequest{}) + _, err := p.GetMetadata(ctx, &plugin.GetMetadataRequest{}) if !strings.Contains(err.Error(), ErrNotCompliant.Error()) { t.Fatal("should fail the operation.") } @@ -234,15 +235,15 @@ func TestNewCLIPlugin_ValidError(t *testing.T) { t.Run("invalid metadata name", func(t *testing.T) { executor = testCommander{stdout: metadataJSON(invalidMetadataName)} - _, err := p.GetMetadata(ctx, &proto.GetMetadataRequest{}) + _, err := p.GetMetadata(ctx, &plugin.GetMetadataRequest{}) if !strings.Contains(err.Error(), "executable name must be") { t.Fatal("should fail the operation.") } }) t.Run("invalid metadata content", func(t *testing.T) { - executor = testCommander{stdout: metadataJSON(proto.GetMetadataResponse{Name: "foo"})} - _, err := p.GetMetadata(ctx, &proto.GetMetadataRequest{}) + executor = testCommander{stdout: metadataJSON(plugin.GetMetadataResponse{Name: "foo"})} + _, err := p.GetMetadata(ctx, &plugin.GetMetadataRequest{}) if !strings.Contains(err.Error(), "invalid metadata") { t.Fatal("should fail the operation.") } @@ -250,11 +251,11 @@ func TestNewCLIPlugin_ValidError(t *testing.T) { t.Run("valid", func(t *testing.T) { executor = testCommander{stdout: metadataJSON(validMetadata)} - _, err := p.GetMetadata(ctx, &proto.GetMetadataRequest{}) + _, err := p.GetMetadata(ctx, &plugin.GetMetadataRequest{}) if err != nil { t.Fatalf("should valid. got err = %v", err) } - metadata, err := p.GetMetadata(context.Background(), &proto.GetMetadataRequest{}) + metadata, err := p.GetMetadata(context.Background(), &plugin.GetMetadataRequest{}) if err != nil { t.Fatalf("should valid. got err = %v", err) } @@ -265,7 +266,7 @@ func TestNewCLIPlugin_ValidError(t *testing.T) { t.Run("invalid contract version", func(t *testing.T) { executor = testCommander{stdout: metadataJSON(invalidContractVersionMetadata)} - _, err := p.GetMetadata(ctx, &proto.GetMetadataRequest{}) + _, err := p.GetMetadata(ctx, &plugin.GetMetadataRequest{}) if err == nil { t.Fatal("should have an invalid contract version error") } diff --git a/plugin/proto/algorithm.go b/plugin/proto/algorithm.go index bcf300b1..b639abee 100644 --- a/plugin/proto/algorithm.go +++ b/plugin/proto/algorithm.go @@ -18,67 +18,53 @@ import ( "fmt" "github.com/notaryproject/notation-core-go/signature" -) - -// KeySpec is type of the signing algorithm, including algorithm and size. -type KeySpec string - -// one of the following supported key spec names. -// -// https://github.com/notaryproject/notaryproject/blob/main/specs/signature-specification.md#algorithm-selection -const ( - KeySpecRSA2048 KeySpec = "RSA-2048" - KeySpecRSA3072 KeySpec = "RSA-3072" - KeySpecRSA4096 KeySpec = "RSA-4096" - KeySpecEC256 KeySpec = "EC-256" - KeySpecEC384 KeySpec = "EC-384" - KeySpecEC521 KeySpec = "EC-521" + "github.com/notaryproject/notation-plugin-framework-go/plugin" ) // EncodeKeySpec returns the name of a keySpec according to the spec. -func EncodeKeySpec(k signature.KeySpec) (KeySpec, error) { +func EncodeKeySpec(k signature.KeySpec) (plugin.KeySpec, error) { switch k.Type { case signature.KeyTypeEC: switch k.Size { case 256: - return KeySpecEC256, nil + return plugin.KeySpecEC256, nil case 384: - return KeySpecEC384, nil + return plugin.KeySpecEC384, nil case 521: - return KeySpecEC521, nil + return plugin.KeySpecEC521, nil } case signature.KeyTypeRSA: switch k.Size { case 2048: - return KeySpecRSA2048, nil + return plugin.KeySpecRSA2048, nil case 3072: - return KeySpecRSA3072, nil + return plugin.KeySpecRSA3072, nil case 4096: - return KeySpecRSA4096, nil + return plugin.KeySpecRSA4096, nil } } return "", fmt.Errorf("invalid KeySpec %q", k) } // DecodeKeySpec parses keySpec name to a signature.keySpec type. -func DecodeKeySpec(k KeySpec) (keySpec signature.KeySpec, err error) { +func DecodeKeySpec(k plugin.KeySpec) (keySpec signature.KeySpec, err error) { switch k { - case KeySpecRSA2048: + case plugin.KeySpecRSA2048: keySpec.Size = 2048 keySpec.Type = signature.KeyTypeRSA - case KeySpecRSA3072: + case plugin.KeySpecRSA3072: keySpec.Size = 3072 keySpec.Type = signature.KeyTypeRSA - case KeySpecRSA4096: + case plugin.KeySpecRSA4096: keySpec.Size = 4096 keySpec.Type = signature.KeyTypeRSA - case KeySpecEC256: + case plugin.KeySpecEC256: keySpec.Size = 256 keySpec.Type = signature.KeyTypeEC - case KeySpecEC384: + case plugin.KeySpecEC384: keySpec.Size = 384 keySpec.Type = signature.KeyTypeEC - case KeySpecEC521: + case plugin.KeySpecEC521: keySpec.Size = 521 keySpec.Type = signature.KeyTypeEC default: @@ -88,92 +74,65 @@ func DecodeKeySpec(k KeySpec) (keySpec signature.KeySpec, err error) { return } -// HashAlgorithm is the type of a hash algorithm. -type HashAlgorithm string - -// one of the following supported hash algorithm names. -// -// https://github.com/notaryproject/notaryproject/blob/main/specs/signature-specification.md#algorithm-selection -const ( - HashAlgorithmSHA256 HashAlgorithm = "SHA-256" - HashAlgorithmSHA384 HashAlgorithm = "SHA-384" - HashAlgorithmSHA512 HashAlgorithm = "SHA-512" -) - // HashAlgorithmFromKeySpec returns the name of hash function according to the spec. -func HashAlgorithmFromKeySpec(k signature.KeySpec) (HashAlgorithm, error) { +func HashAlgorithmFromKeySpec(k signature.KeySpec) (plugin.HashAlgorithm, error) { switch k.Type { case signature.KeyTypeEC: switch k.Size { case 256: - return HashAlgorithmSHA256, nil + return plugin.HashAlgorithmSHA256, nil case 384: - return HashAlgorithmSHA384, nil + return plugin.HashAlgorithmSHA384, nil case 521: - return HashAlgorithmSHA512, nil + return plugin.HashAlgorithmSHA512, nil } case signature.KeyTypeRSA: switch k.Size { case 2048: - return HashAlgorithmSHA256, nil + return plugin.HashAlgorithmSHA256, nil case 3072: - return HashAlgorithmSHA384, nil + return plugin.HashAlgorithmSHA384, nil case 4096: - return HashAlgorithmSHA512, nil + return plugin.HashAlgorithmSHA512, nil } } return "", fmt.Errorf("invalid KeySpec %q", k) } -// SignatureAlgorithm is the type of signature algorithm -type SignatureAlgorithm string - -// one of the following supported signing algorithm names. -// -// https://github.com/notaryproject/notaryproject/blob/main/specs/signature-specification.md#algorithm-selection -const ( - SignatureAlgorithmECDSA_SHA256 SignatureAlgorithm = "ECDSA-SHA-256" - SignatureAlgorithmECDSA_SHA384 SignatureAlgorithm = "ECDSA-SHA-384" - SignatureAlgorithmECDSA_SHA512 SignatureAlgorithm = "ECDSA-SHA-512" - SignatureAlgorithmRSASSA_PSS_SHA256 SignatureAlgorithm = "RSASSA-PSS-SHA-256" - SignatureAlgorithmRSASSA_PSS_SHA384 SignatureAlgorithm = "RSASSA-PSS-SHA-384" - SignatureAlgorithmRSASSA_PSS_SHA512 SignatureAlgorithm = "RSASSA-PSS-SHA-512" -) - // EncodeSigningAlgorithm returns the signing algorithm name of an algorithm // according to the spec. -func EncodeSigningAlgorithm(alg signature.Algorithm) (SignatureAlgorithm, error) { +func EncodeSigningAlgorithm(alg signature.Algorithm) (plugin.SignatureAlgorithm, error) { switch alg { case signature.AlgorithmES256: - return SignatureAlgorithmECDSA_SHA256, nil + return plugin.SignatureAlgorithmECDSA_SHA256, nil case signature.AlgorithmES384: - return SignatureAlgorithmECDSA_SHA384, nil + return plugin.SignatureAlgorithmECDSA_SHA384, nil case signature.AlgorithmES512: - return SignatureAlgorithmECDSA_SHA512, nil + return plugin.SignatureAlgorithmECDSA_SHA512, nil case signature.AlgorithmPS256: - return SignatureAlgorithmRSASSA_PSS_SHA256, nil + return plugin.SignatureAlgorithmRSASSA_PSS_SHA256, nil case signature.AlgorithmPS384: - return SignatureAlgorithmRSASSA_PSS_SHA384, nil + return plugin.SignatureAlgorithmRSASSA_PSS_SHA384, nil case signature.AlgorithmPS512: - return SignatureAlgorithmRSASSA_PSS_SHA512, nil + return plugin.SignatureAlgorithmRSASSA_PSS_SHA512, nil } return "", fmt.Errorf("invalid algorithm %q", alg) } // DecodeSigningAlgorithm parses the signing algorithm name from a given string. -func DecodeSigningAlgorithm(raw SignatureAlgorithm) (signature.Algorithm, error) { +func DecodeSigningAlgorithm(raw plugin.SignatureAlgorithm) (signature.Algorithm, error) { switch raw { - case SignatureAlgorithmECDSA_SHA256: + case plugin.SignatureAlgorithmECDSA_SHA256: return signature.AlgorithmES256, nil - case SignatureAlgorithmECDSA_SHA384: + case plugin.SignatureAlgorithmECDSA_SHA384: return signature.AlgorithmES384, nil - case SignatureAlgorithmECDSA_SHA512: + case plugin.SignatureAlgorithmECDSA_SHA512: return signature.AlgorithmES512, nil - case SignatureAlgorithmRSASSA_PSS_SHA256: + case plugin.SignatureAlgorithmRSASSA_PSS_SHA256: return signature.AlgorithmPS256, nil - case SignatureAlgorithmRSASSA_PSS_SHA384: + case plugin.SignatureAlgorithmRSASSA_PSS_SHA384: return signature.AlgorithmPS384, nil - case SignatureAlgorithmRSASSA_PSS_SHA512: + case plugin.SignatureAlgorithmRSASSA_PSS_SHA512: return signature.AlgorithmPS512, nil } return 0, errors.New("unknown signing algorithm") diff --git a/plugin/proto/algorithm_test.go b/plugin/proto/algorithm_test.go index d60af053..95d2e9c0 100644 --- a/plugin/proto/algorithm_test.go +++ b/plugin/proto/algorithm_test.go @@ -17,13 +17,14 @@ import ( "testing" "github.com/notaryproject/notation-core-go/signature" + "github.com/notaryproject/notation-plugin-framework-go/plugin" ) func TestEncodeKeySpec(t *testing.T) { tests := []struct { name string keySpec signature.KeySpec - expected KeySpec + expected plugin.KeySpec }{ { name: "EC 256", @@ -31,7 +32,7 @@ func TestEncodeKeySpec(t *testing.T) { Type: signature.KeyTypeEC, Size: 256, }, - expected: KeySpecEC256, + expected: plugin.KeySpecEC256, }, { name: "EC 384", @@ -39,7 +40,7 @@ func TestEncodeKeySpec(t *testing.T) { Type: signature.KeyTypeEC, Size: 384, }, - expected: KeySpecEC384, + expected: plugin.KeySpecEC384, }, { name: "EC 521", @@ -47,7 +48,7 @@ func TestEncodeKeySpec(t *testing.T) { Type: signature.KeyTypeEC, Size: 521, }, - expected: KeySpecEC521, + expected: plugin.KeySpecEC521, }, { name: "RSA 2048", @@ -55,7 +56,7 @@ func TestEncodeKeySpec(t *testing.T) { Type: signature.KeyTypeRSA, Size: 2048, }, - expected: KeySpecRSA2048, + expected: plugin.KeySpecRSA2048, }, { name: "RSA 3072", @@ -63,7 +64,7 @@ func TestEncodeKeySpec(t *testing.T) { Type: signature.KeyTypeRSA, Size: 3072, }, - expected: KeySpecRSA3072, + expected: plugin.KeySpecRSA3072, }, { name: "RSA 4096", @@ -71,7 +72,7 @@ func TestEncodeKeySpec(t *testing.T) { Type: signature.KeyTypeRSA, Size: 4096, }, - expected: KeySpecRSA4096, + expected: plugin.KeySpecRSA4096, }, { name: "Unsupported key spec", @@ -96,7 +97,7 @@ func TestHashAlgorithmFromKeySpec(t *testing.T) { tests := []struct { name string keySpec signature.KeySpec - expected HashAlgorithm + expected plugin.HashAlgorithm }{ { name: "EC 256", @@ -104,7 +105,7 @@ func TestHashAlgorithmFromKeySpec(t *testing.T) { Type: signature.KeyTypeEC, Size: 256, }, - expected: HashAlgorithmSHA256, + expected: plugin.HashAlgorithmSHA256, }, { name: "EC 384", @@ -112,7 +113,7 @@ func TestHashAlgorithmFromKeySpec(t *testing.T) { Type: signature.KeyTypeEC, Size: 384, }, - expected: HashAlgorithmSHA384, + expected: plugin.HashAlgorithmSHA384, }, { name: "EC 521", @@ -120,7 +121,7 @@ func TestHashAlgorithmFromKeySpec(t *testing.T) { Type: signature.KeyTypeEC, Size: 521, }, - expected: HashAlgorithmSHA512, + expected: plugin.HashAlgorithmSHA512, }, { name: "RSA 2048", @@ -128,7 +129,7 @@ func TestHashAlgorithmFromKeySpec(t *testing.T) { Type: signature.KeyTypeRSA, Size: 2048, }, - expected: HashAlgorithmSHA256, + expected: plugin.HashAlgorithmSHA256, }, { name: "RSA 3072", @@ -136,7 +137,7 @@ func TestHashAlgorithmFromKeySpec(t *testing.T) { Type: signature.KeyTypeRSA, Size: 3072, }, - expected: HashAlgorithmSHA384, + expected: plugin.HashAlgorithmSHA384, }, { name: "RSA 4096", @@ -144,7 +145,7 @@ func TestHashAlgorithmFromKeySpec(t *testing.T) { Type: signature.KeyTypeRSA, Size: 4096, }, - expected: HashAlgorithmSHA512, + expected: plugin.HashAlgorithmSHA512, }, { name: "Unsupported key spec", @@ -168,13 +169,13 @@ func TestHashAlgorithmFromKeySpec(t *testing.T) { func TestDecodeKeySpec(t *testing.T) { tests := []struct { name string - raw KeySpec + raw plugin.KeySpec expected signature.KeySpec expectErr bool }{ { name: "EC 256", - raw: KeySpecEC256, + raw: plugin.KeySpecEC256, expected: signature.KeySpec{ Type: signature.KeyTypeEC, Size: 256, @@ -183,7 +184,7 @@ func TestDecodeKeySpec(t *testing.T) { }, { name: "EC 384", - raw: KeySpecEC384, + raw: plugin.KeySpecEC384, expected: signature.KeySpec{ Type: signature.KeyTypeEC, Size: 384, @@ -192,7 +193,7 @@ func TestDecodeKeySpec(t *testing.T) { }, { name: "EC 521", - raw: KeySpecEC521, + raw: plugin.KeySpecEC521, expected: signature.KeySpec{ Type: signature.KeyTypeEC, Size: 521, @@ -201,7 +202,7 @@ func TestDecodeKeySpec(t *testing.T) { }, { name: "RSA 2048", - raw: KeySpecRSA2048, + raw: plugin.KeySpecRSA2048, expected: signature.KeySpec{ Type: signature.KeyTypeRSA, Size: 2048, @@ -210,7 +211,7 @@ func TestDecodeKeySpec(t *testing.T) { }, { name: "RSA 3072", - raw: KeySpecRSA3072, + raw: plugin.KeySpecRSA3072, expected: signature.KeySpec{ Type: signature.KeyTypeRSA, Size: 3072, @@ -219,7 +220,7 @@ func TestDecodeKeySpec(t *testing.T) { }, { name: "RSA 4096", - raw: KeySpecRSA4096, + raw: plugin.KeySpecRSA4096, expected: signature.KeySpec{ Type: signature.KeyTypeRSA, Size: 4096, @@ -251,37 +252,37 @@ func TestEncodeSigningAlgorithm(t *testing.T) { tests := []struct { name string alg signature.Algorithm - expected SignatureAlgorithm + expected plugin.SignatureAlgorithm }{ { name: "RSASSA-PSS with SHA-256", alg: signature.AlgorithmPS256, - expected: SignatureAlgorithmRSASSA_PSS_SHA256, + expected: plugin.SignatureAlgorithmRSASSA_PSS_SHA256, }, { name: "RSASSA-PSS with SHA-384", alg: signature.AlgorithmPS384, - expected: SignatureAlgorithmRSASSA_PSS_SHA384, + expected: plugin.SignatureAlgorithmRSASSA_PSS_SHA384, }, { name: "RSASSA-PSS with SHA-512", alg: signature.AlgorithmPS512, - expected: SignatureAlgorithmRSASSA_PSS_SHA512, + expected: plugin.SignatureAlgorithmRSASSA_PSS_SHA512, }, { name: "ECDSA on secp256r1 with SHA-256", alg: signature.AlgorithmES256, - expected: SignatureAlgorithmECDSA_SHA256, + expected: plugin.SignatureAlgorithmECDSA_SHA256, }, { name: "ECDSA on secp384r1 with SHA-384", alg: signature.AlgorithmES384, - expected: SignatureAlgorithmECDSA_SHA384, + expected: plugin.SignatureAlgorithmECDSA_SHA384, }, { name: "ECDSA on secp521r1 with SHA-512", alg: signature.AlgorithmES512, - expected: SignatureAlgorithmECDSA_SHA512, + expected: plugin.SignatureAlgorithmECDSA_SHA512, }, { name: "unsupported algorithm", @@ -301,43 +302,43 @@ func TestEncodeSigningAlgorithm(t *testing.T) { func TestParseSigningAlgorithm(t *testing.T) { tests := []struct { name string - raw SignatureAlgorithm + raw plugin.SignatureAlgorithm expected signature.Algorithm expectErr bool }{ { name: "RSASSA-PSS with SHA-256", - raw: SignatureAlgorithmRSASSA_PSS_SHA256, + raw: plugin.SignatureAlgorithmRSASSA_PSS_SHA256, expected: signature.AlgorithmPS256, expectErr: false, }, { name: "RSASSA-PSS with SHA-384", - raw: SignatureAlgorithmRSASSA_PSS_SHA384, + raw: plugin.SignatureAlgorithmRSASSA_PSS_SHA384, expected: signature.AlgorithmPS384, expectErr: false, }, { name: "RSASSA-PSS with SHA-512", - raw: SignatureAlgorithmRSASSA_PSS_SHA512, + raw: plugin.SignatureAlgorithmRSASSA_PSS_SHA512, expected: signature.AlgorithmPS512, expectErr: false, }, { name: "ECDSA on secp256r1 with SHA-256", - raw: SignatureAlgorithmECDSA_SHA256, + raw: plugin.SignatureAlgorithmECDSA_SHA256, expected: signature.AlgorithmES256, expectErr: false, }, { name: "ECDSA on secp384r1 with SHA-384", - raw: SignatureAlgorithmECDSA_SHA384, + raw: plugin.SignatureAlgorithmECDSA_SHA384, expected: signature.AlgorithmES384, expectErr: false, }, { name: "ECDSA on secp521r1 with SHA-512", - raw: SignatureAlgorithmECDSA_SHA512, + raw: plugin.SignatureAlgorithmECDSA_SHA512, expected: signature.AlgorithmES512, expectErr: false, }, diff --git a/plugin/proto/errors.go b/plugin/proto/errors.go index 439cd845..592370d5 100644 --- a/plugin/proto/errors.go +++ b/plugin/proto/errors.go @@ -17,42 +17,13 @@ import ( "encoding/json" "errors" "fmt" -) - -type ErrorCode string - -const ( - // Any of the required request fields was empty, - // or a value was malformed/invalid. - ErrorCodeValidation ErrorCode = "VALIDATION_ERROR" - - // The contract version used in the request is unsupported. - ErrorCodeUnsupportedContractVersion ErrorCode = "UNSUPPORTED_CONTRACT_VERSION" - - // Authentication/authorization error to use given key. - ErrorCodeAccessDenied ErrorCode = "ACCESS_DENIED" - // The operation to generate signature timed out - // and can be retried by Notation. - ErrorCodeTimeout ErrorCode = "TIMEOUT" - - // The operation to generate signature was throttles - // and can be retried by Notation. - ErrorCodeThrottled ErrorCode = "THROTTLED" - - // Any general error that does not fall into any categories. - ErrorCodeGeneric ErrorCode = "ERROR" + "github.com/notaryproject/notation-plugin-framework-go/plugin" ) -type jsonErr struct { - Code ErrorCode `json:"errorCode"` - Message string `json:"errorMessage,omitempty"` - Metadata map[string]string `json:"errorMetadata,omitempty"` -} - // RequestError is the common error response for any request. type RequestError struct { - Code ErrorCode + Code plugin.ErrorCode Err error Metadata map[string]string } @@ -83,19 +54,19 @@ func (e RequestError) MarshalJSON() ([]byte, error) { if e.Err != nil { msg = e.Err.Error() } - return json.Marshal(jsonErr{e.Code, msg, e.Metadata}) + return json.Marshal(plugin.Error{ErrCode: e.Code, Message: msg, Metadata: e.Metadata}) } func (e *RequestError) UnmarshalJSON(data []byte) error { - var tmp jsonErr + var tmp plugin.Error err := json.Unmarshal(data, &tmp) if err != nil { return err } - if tmp.Code == "" && tmp.Message == "" && tmp.Metadata == nil { + if tmp.ErrCode == "" && tmp.Message == "" && tmp.Metadata == nil { return errors.New("incomplete json") } - *e = RequestError{Code: tmp.Code, Metadata: tmp.Metadata} + *e = RequestError{Code: tmp.ErrCode, Metadata: tmp.Metadata} if tmp.Message != "" { e.Err = errors.New(tmp.Message) } diff --git a/plugin/proto/errors_test.go b/plugin/proto/errors_test.go index 3a73dba3..c7a161e7 100644 --- a/plugin/proto/errors_test.go +++ b/plugin/proto/errors_test.go @@ -18,11 +18,13 @@ import ( "errors" "reflect" "testing" + + "github.com/notaryproject/notation-plugin-framework-go/plugin" ) func TestRequestError_Error(t *testing.T) { - err := RequestError{Code: ErrorCodeAccessDenied, Err: errors.New("an error")} - want := string(ErrorCodeAccessDenied) + ": an error" + err := RequestError{Code: plugin.ErrorCodeAccessDenied, Err: errors.New("an error")} + want := string(plugin.ErrorCodeAccessDenied) + ": an error" if got := err.Error(); got != want { t.Errorf("RequestError.Error() = %v, want %v", got, want) } @@ -30,7 +32,7 @@ func TestRequestError_Error(t *testing.T) { func TestRequestError_Unwrap(t *testing.T) { want := errors.New("an error") - got := RequestError{Code: ErrorCodeAccessDenied, Err: want}.Unwrap() + got := RequestError{Code: plugin.ErrorCodeAccessDenied, Err: want}.Unwrap() if got != want { t.Errorf("RequestError.Unwrap() = %v, want %v", got, want) } @@ -43,11 +45,11 @@ func TestRequestError_MarshalJSON(t *testing.T) { want []byte }{ {"empty", RequestError{}, []byte("{\"errorCode\":\"\"}")}, - {"with code", RequestError{Code: ErrorCodeAccessDenied}, []byte("{\"errorCode\":\"ACCESS_DENIED\"}")}, - {"with message", RequestError{Code: ErrorCodeAccessDenied, Err: errors.New("failed")}, []byte("{\"errorCode\":\"ACCESS_DENIED\",\"errorMessage\":\"failed\"}")}, + {"with code", RequestError{Code: plugin.ErrorCodeAccessDenied}, []byte("{\"errorCode\":\"ACCESS_DENIED\"}")}, + {"with message", RequestError{Code: plugin.ErrorCodeAccessDenied, Err: errors.New("failed")}, []byte("{\"errorCode\":\"ACCESS_DENIED\",\"errorMessage\":\"failed\"}")}, { "with metadata", - RequestError{Code: ErrorCodeAccessDenied, Err: errors.New("failed"), Metadata: map[string]string{"a": "b"}}, + RequestError{Code: plugin.ErrorCodeAccessDenied, Err: errors.New("failed"), Metadata: map[string]string{"a": "b"}}, []byte("{\"errorCode\":\"ACCESS_DENIED\",\"errorMessage\":\"failed\",\"errorMetadata\":{\"a\":\"b\"}}"), }, } @@ -87,7 +89,7 @@ func TestRequestError_UnmarshalJSON(t *testing.T) { }{ {"invalid", args{[]byte("")}, RequestError{}, true}, {"empty", args{[]byte("{}")}, RequestError{}, true}, - {"with code", args{[]byte("{\"errorCode\":\"ACCESS_DENIED\"}")}, RequestError{Code: ErrorCodeAccessDenied}, false}, + {"with code", args{[]byte("{\"errorCode\":\"ACCESS_DENIED\"}")}, RequestError{Code: plugin.ErrorCodeAccessDenied}, false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -114,10 +116,10 @@ func TestRequestError_Is(t *testing.T) { }{ {"nil", RequestError{}, args{nil}, false}, {"not same type", RequestError{Err: errors.New("foo")}, args{errors.New("foo")}, false}, - {"only same code", RequestError{Code: ErrorCodeGeneric, Err: errors.New("foo")}, args{RequestError{Code: ErrorCodeGeneric, Err: errors.New("bar")}}, false}, - {"only same message", RequestError{Code: ErrorCodeTimeout, Err: errors.New("foo")}, args{RequestError{Code: ErrorCodeGeneric, Err: errors.New("foo")}}, false}, - {"same with nil message", RequestError{Code: ErrorCodeGeneric}, args{RequestError{Code: ErrorCodeGeneric}}, true}, - {"same", RequestError{Code: ErrorCodeGeneric, Err: errors.New("foo")}, args{RequestError{Code: ErrorCodeGeneric, Err: errors.New("foo")}}, true}, + {"only same code", RequestError{Code: plugin.ErrorCodeGeneric, Err: errors.New("foo")}, args{RequestError{Code: plugin.ErrorCodeGeneric, Err: errors.New("bar")}}, false}, + {"only same message", RequestError{Code: plugin.ErrorCodeTimeout, Err: errors.New("foo")}, args{RequestError{Code: plugin.ErrorCodeGeneric, Err: errors.New("foo")}}, false}, + {"same with nil message", RequestError{Code: plugin.ErrorCodeGeneric}, args{RequestError{Code: plugin.ErrorCodeGeneric}}, true}, + {"same", RequestError{Code: plugin.ErrorCodeGeneric, Err: errors.New("foo")}, args{RequestError{Code: plugin.ErrorCodeGeneric, Err: errors.New("foo")}}, true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/plugin/proto/metadata.go b/plugin/proto/metadata.go index 495506cb..8035ba42 100644 --- a/plugin/proto/metadata.go +++ b/plugin/proto/metadata.go @@ -13,30 +13,12 @@ package proto -// GetMetadataRequest contains the parameters passed in a get-plugin-metadata -// request. -type GetMetadataRequest struct { - PluginConfig map[string]string `json:"pluginConfig,omitempty"` -} - -func (GetMetadataRequest) Command() Command { - return CommandGetMetadata -} - -// GetMetadataResponse provided by the plugin. -type GetMetadataResponse struct { - Name string `json:"name"` - Description string `json:"description"` - Version string `json:"version"` - URL string `json:"url"` - SupportedContractVersions []string `json:"supportedContractVersions"` - Capabilities []Capability `json:"capabilities"` -} +import "github.com/notaryproject/notation-plugin-framework-go/plugin" // HasCapability return true if the metadata states that the // capability is supported. // Returns true if capability is empty. -func (resp *GetMetadataResponse) HasCapability(capability Capability) bool { +func HasCapability(resp *plugin.GetMetadataResponse, capability plugin.Capability) bool { if capability == "" { return true } diff --git a/plugin/proto/metadata_test.go b/plugin/proto/metadata_test.go index 85d75134..ca6e85d9 100644 --- a/plugin/proto/metadata_test.go +++ b/plugin/proto/metadata_test.go @@ -15,26 +15,28 @@ package proto import ( "testing" + + "github.com/notaryproject/notation-plugin-framework-go/plugin" ) func TestGetMetadataResponse_HasCapability(t *testing.T) { type args struct { - capability Capability + capability plugin.Capability } tests := []struct { name string - m *GetMetadataResponse + m *plugin.GetMetadataResponse args args want bool }{ - {"empty capabilities", &GetMetadataResponse{}, args{"cap"}, false}, - {"other capabilities", &GetMetadataResponse{Capabilities: []Capability{"foo", "baz"}}, args{"cap"}, false}, - {"empty target capability", &GetMetadataResponse{Capabilities: []Capability{"foo", "baz"}}, args{""}, true}, - {"found", &GetMetadataResponse{Capabilities: []Capability{"foo", "baz"}}, args{"baz"}, true}, + {"empty capabilities", &plugin.GetMetadataResponse{}, args{"cap"}, false}, + {"other capabilities", &plugin.GetMetadataResponse{Capabilities: []plugin.Capability{"foo", "baz"}}, args{"cap"}, false}, + {"empty target capability", &plugin.GetMetadataResponse{Capabilities: []plugin.Capability{"foo", "baz"}}, args{""}, true}, + {"found", &plugin.GetMetadataResponse{Capabilities: []plugin.Capability{"foo", "baz"}}, args{"baz"}, true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if got := tt.m.HasCapability(tt.args.capability); got != tt.want { + if got := HasCapability(tt.m, tt.args.capability); got != tt.want { t.Errorf("GetMetadataResponse.HasCapability() = %v, want %v", got, tt.want) } }) diff --git a/plugin/proto/proto.go b/plugin/proto/proto.go index d550105e..b2e14919 100644 --- a/plugin/proto/proto.go +++ b/plugin/proto/proto.go @@ -20,59 +20,3 @@ const Prefix = "notation-" // ContractVersion is the . version of the plugin contract. const ContractVersion = "1.0" - -// Command is a CLI command available in the plugin contract. -type Command string - -// Request defines a plugin request, which is always associated to a command. -type Request interface { - Command() Command -} - -const ( - // CommandGetMetadata is the name of the plugin command - // which must be supported by every plugin and returns the - // plugin metadata. - CommandGetMetadata Command = "get-plugin-metadata" - - // CommandDescribeKey is the name of the plugin command - // which must be supported by every plugin that has the - // SIGNATURE_GENERATOR.RAW capability. - CommandDescribeKey Command = "describe-key" - - // CommandGenerateSignature is the name of the plugin command - // which must be supported by every plugin that has the - // SIGNATURE_GENERATOR.RAW capability. - CommandGenerateSignature Command = "generate-signature" - - // CommandGenerateEnvelope is the name of the plugin command - // which must be supported by every plugin that has the - // SIGNATURE_GENERATOR.ENVELOPE capability. - CommandGenerateEnvelope Command = "generate-envelope" - - // CommandVerifySignature is the name of the plugin command - // which must be supported by every plugin that has - // any SIGNATURE_VERIFIER.* capability - CommandVerifySignature Command = "verify-signature" -) - -// Capability is a feature available in the plugin contract. -type Capability string - -const ( - // CapabilitySignatureGenerator is the name of the capability - // for a plugin to support generating raw signatures. - CapabilitySignatureGenerator Capability = "SIGNATURE_GENERATOR.RAW" - - // CapabilityEnvelopeGenerator is the name of the capability - // for a plugin to support generating envelope signatures. - CapabilityEnvelopeGenerator Capability = "SIGNATURE_GENERATOR.ENVELOPE" - - // CapabilityTrustedIdentityVerifier is the name of the - // capability for a plugin to support verifying trusted identities. - CapabilityTrustedIdentityVerifier Capability = "SIGNATURE_VERIFIER.TRUSTED_IDENTITY" - - // CapabilityRevocationCheckVerifier is the name of the - // capability for a plugin to support verifying revocation checks. - CapabilityRevocationCheckVerifier Capability = "SIGNATURE_VERIFIER.REVOCATION_CHECK" -) diff --git a/plugin/proto/sign.go b/plugin/proto/sign.go deleted file mode 100644 index aea6ef80..00000000 --- a/plugin/proto/sign.go +++ /dev/null @@ -1,84 +0,0 @@ -// 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 proto - -// DescribeKeyRequest contains the parameters passed in a describe-key request. -type DescribeKeyRequest struct { - ContractVersion string `json:"contractVersion"` - KeyID string `json:"keyId"` - PluginConfig map[string]string `json:"pluginConfig,omitempty"` -} - -func (DescribeKeyRequest) Command() Command { - return CommandDescribeKey -} - -// DescribeKeyResponse is the response of a describe-key request. -type DescribeKeyResponse struct { - // The same key id as passed in the request. - KeyID string `json:"keyId"` - - // One of following supported key types: - // https://github.com/notaryproject/notaryproject/blob/main/specs/signature-specification.md#algorithm-selection - KeySpec KeySpec `json:"keySpec"` -} - -// GenerateSignatureRequest contains the parameters passed in a -// generate-signature request. -type GenerateSignatureRequest struct { - ContractVersion string `json:"contractVersion"` - KeyID string `json:"keyId"` - KeySpec KeySpec `json:"keySpec"` - Hash HashAlgorithm `json:"hashAlgorithm"` - Payload []byte `json:"payload"` - PluginConfig map[string]string `json:"pluginConfig,omitempty"` -} - -func (GenerateSignatureRequest) Command() Command { - return CommandGenerateSignature -} - -// GenerateSignatureResponse is the response of a generate-signature request. -type GenerateSignatureResponse struct { - KeyID string `json:"keyId"` - Signature []byte `json:"signature"` - SigningAlgorithm string `json:"signingAlgorithm"` - - // Ordered list of certificates starting with leaf certificate - // and ending with root certificate. - CertificateChain [][]byte `json:"certificateChain"` -} - -// GenerateEnvelopeRequest contains the parameters passed in a generate-envelope -// request. -type GenerateEnvelopeRequest struct { - ContractVersion string `json:"contractVersion"` - KeyID string `json:"keyId"` - PayloadType string `json:"payloadType"` - SignatureEnvelopeType string `json:"signatureEnvelopeType"` - Payload []byte `json:"payload"` - ExpiryDurationInSeconds uint64 `json:"expiryDurationInSeconds,omitempty"` - PluginConfig map[string]string `json:"pluginConfig,omitempty"` -} - -func (GenerateEnvelopeRequest) Command() Command { - return CommandGenerateEnvelope -} - -// GenerateEnvelopeResponse is the response of a generate-envelope request. -type GenerateEnvelopeResponse struct { - SignatureEnvelope []byte `json:"signatureEnvelope"` - SignatureEnvelopeType string `json:"signatureEnvelopeType"` - Annotations map[string]string `json:"annotations,omitempty"` -} diff --git a/plugin/proto/verify.go b/plugin/proto/verify.go deleted file mode 100644 index 5cec2f7f..00000000 --- a/plugin/proto/verify.go +++ /dev/null @@ -1,64 +0,0 @@ -// 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 proto - -import "time" - -// VerifySignatureRequest contains the parameters passed in a verify-signature -// request. -type VerifySignatureRequest struct { - ContractVersion string `json:"contractVersion"` - Signature Signature `json:"signature"` - TrustPolicy TrustPolicy `json:"trustPolicy"` - PluginConfig map[string]string `json:"pluginConfig,omitempty"` -} - -func (VerifySignatureRequest) Command() Command { - return CommandVerifySignature -} - -// Signature represents a signature pulled from the envelope -type Signature struct { - CriticalAttributes CriticalAttributes `json:"criticalAttributes"` - UnprocessedAttributes []string `json:"unprocessedAttributes"` - CertificateChain [][]byte `json:"certificateChain"` -} - -// CriticalAttributes contains all Notary Project defined critical -// attributes and their values in the signature envelope -type CriticalAttributes struct { - ContentType string `json:"contentType"` - SigningScheme string `json:"signingScheme"` - Expiry *time.Time `json:"expiry,omitempty"` - AuthenticSigningTime *time.Time `json:"authenticSigningTime,omitempty"` - ExtendedAttributes map[string]interface{} `json:"extendedAttributes,omitempty"` -} - -// TrustPolicy represents trusted identities that sign the artifacts -type TrustPolicy struct { - TrustedIdentities []string `json:"trustedIdentities"` - SignatureVerification []Capability `json:"signatureVerification"` -} - -// VerifySignatureResponse is the response of a verify-signature request. -type VerifySignatureResponse struct { - VerificationResults map[Capability]*VerificationResult `json:"verificationResults"` - ProcessedAttributes []interface{} `json:"processedAttributes"` -} - -// VerificationResult is the result of a verification performed by the plugin -type VerificationResult struct { - Success bool `json:"success"` - Reason string `json:"reason,omitempty"` -} diff --git a/plugin/testdata/plugins/foo/notation-foo b/plugin/testdata/plugins/foo/notation-foo old mode 100644 new mode 100755 diff --git a/signer/plugin.go b/signer/plugin.go index 139f354e..9925a96d 100644 --- a/signer/plugin.go +++ b/signer/plugin.go @@ -21,20 +21,21 @@ import ( "fmt" "time" + "oras.land/oras-go/v2/content" + "github.com/notaryproject/notation-core-go/signature" "github.com/notaryproject/notation-go" "github.com/notaryproject/notation-go/internal/envelope" "github.com/notaryproject/notation-go/log" - "github.com/notaryproject/notation-go/plugin" "github.com/notaryproject/notation-go/plugin/proto" + pluginframework "github.com/notaryproject/notation-plugin-framework-go/plugin" ocispec "github.com/opencontainers/image-spec/specs-go/v1" - "oras.land/oras-go/v2/content" ) // pluginSigner signs artifacts and generates signatures. // It implements notation.Signer type pluginSigner struct { - plugin plugin.SignPlugin + plugin pluginframework.SignPlugin keyID string pluginConfig map[string]string manifestAnnotations map[string]string @@ -43,7 +44,7 @@ type pluginSigner struct { // NewFromPlugin creates a notation.Signer that signs artifacts and generates // signatures by delegating the one or more operations to the named plugin, // as defined in https://github.com/notaryproject/notaryproject/blob/main/specs/plugin-extensibility.md#signing-interfaces. -func NewFromPlugin(plugin plugin.SignPlugin, keyID string, pluginConfig map[string]string) (notation.Signer, error) { +func NewFromPlugin(plugin pluginframework.SignPlugin, keyID string, pluginConfig map[string]string) (notation.Signer, error) { if plugin == nil { return nil, errors.New("nil plugin") } @@ -68,7 +69,7 @@ func (s *pluginSigner) PluginAnnotations() map[string]string { func (s *pluginSigner) Sign(ctx context.Context, desc ocispec.Descriptor, opts notation.SignerSignOptions) ([]byte, *signature.SignerInfo, error) { logger := log.GetLogger(ctx) logger.Debug("Invoking plugin's get-plugin-metadata command") - req := &proto.GetMetadataRequest{ + req := &pluginframework.GetMetadataRequest{ PluginConfig: s.mergeConfig(opts.PluginConfig), } metadata, err := s.plugin.GetMetadata(ctx, req) @@ -77,15 +78,15 @@ func (s *pluginSigner) Sign(ctx context.Context, desc ocispec.Descriptor, opts n } logger.Debugf("Using plugin %v with capabilities %v to sign artifact %v in signature media type %v", metadata.Name, metadata.Capabilities, desc.Digest, opts.SignatureMediaType) - if metadata.HasCapability(proto.CapabilitySignatureGenerator) { + if proto.HasCapability(metadata, pluginframework.CapabilitySignatureGenerator) { return s.generateSignature(ctx, desc, opts, metadata) - } else if metadata.HasCapability(proto.CapabilityEnvelopeGenerator) { + } else if proto.HasCapability(metadata, pluginframework.CapabilityEnvelopeGenerator) { return s.generateSignatureEnvelope(ctx, desc, opts) } return nil, nil, fmt.Errorf("plugin does not have signing capabilities") } -func (s *pluginSigner) generateSignature(ctx context.Context, desc ocispec.Descriptor, opts notation.SignerSignOptions, metadata *proto.GetMetadataResponse) ([]byte, *signature.SignerInfo, error) { +func (s *pluginSigner) generateSignature(ctx context.Context, desc ocispec.Descriptor, opts notation.SignerSignOptions, metadata *pluginframework.GetMetadataResponse) ([]byte, *signature.SignerInfo, error) { logger := log.GetLogger(ctx) logger.Debug("Generating signature by plugin") config := s.mergeConfig(opts.PluginConfig) @@ -127,7 +128,7 @@ func (s *pluginSigner) generateSignatureEnvelope(ctx context.Context, desc ocisp return nil, nil, fmt.Errorf("envelope payload can't be marshalled: %w", err) } // Execute plugin sign command. - req := &proto.GenerateEnvelopeRequest{ + req := &pluginframework.GenerateEnvelopeRequest{ KeyID: s.keyID, Payload: payloadBytes, SignatureEnvelopeType: opts.SignatureMediaType, @@ -193,8 +194,8 @@ func (s *pluginSigner) mergeConfig(config map[string]string) map[string]string { return c } -func (s *pluginSigner) describeKey(ctx context.Context, config map[string]string) (*proto.DescribeKeyResponse, error) { - req := &proto.DescribeKeyRequest{ +func (s *pluginSigner) describeKey(ctx context.Context, config map[string]string) (*pluginframework.DescribeKeyResponse, error) { + req := &pluginframework.DescribeKeyRequest{ KeyID: s.keyID, PluginConfig: config, } @@ -272,7 +273,7 @@ func parseCertChain(certChain [][]byte) ([]*x509.Certificate, error) { // pluginPrimitiveSigner implements signature.Signer type pluginPrimitiveSigner struct { ctx context.Context - plugin plugin.SignPlugin + plugin pluginframework.SignPlugin keyID string pluginConfig map[string]string keySpec signature.KeySpec @@ -291,7 +292,7 @@ func (s *pluginPrimitiveSigner) Sign(payload []byte) ([]byte, []*x509.Certificat return nil, nil, err } - req := &proto.GenerateSignatureRequest{ + req := &pluginframework.GenerateSignatureRequest{ KeyID: s.keyID, KeySpec: keySpec, Hash: keySpecHash, diff --git a/signer/plugin_test.go b/signer/plugin_test.go index 3e0460a9..fd9bb96c 100644 --- a/signer/plugin_test.go +++ b/signer/plugin_test.go @@ -32,16 +32,17 @@ import ( "github.com/notaryproject/notation-go/internal/envelope" "github.com/notaryproject/notation-go/plugin" "github.com/notaryproject/notation-go/plugin/proto" + pluginframework "github.com/notaryproject/notation-plugin-framework-go/plugin" ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) var ( - validMetadata = proto.GetMetadataResponse{ + validMetadata = pluginframework.GetMetadataResponse{ Name: "testPlugin", Description: "plugin for test", Version: "1.0", URL: "test.com", - SupportedContractVersions: []string{proto.ContractVersion}, - Capabilities: []proto.Capability{proto.CapabilitySignatureGenerator}, + SupportedContractVersions: []string{pluginframework.ContractVersion}, + Capabilities: []pluginframework.Capability{pluginframework.CapabilitySignatureGenerator}, } validSignDescriptor, validSignOpts = generateSigningContent() invalidSignatureEnvelope = []byte("invalid") @@ -78,33 +79,33 @@ func newMockPlugin(key crypto.PrivateKey, certs []*x509.Certificate, keySpec sig } } -func (p *mockPlugin) GetMetadata(ctx context.Context, req *proto.GetMetadataRequest) (*proto.GetMetadataResponse, error) { +func (p *mockPlugin) GetMetadata(_ context.Context, _ *pluginframework.GetMetadataRequest) (*pluginframework.GetMetadataResponse, error) { if p.wantEnvelope { - return &proto.GetMetadataResponse{ + return &pluginframework.GetMetadataResponse{ Name: "testPlugin", Version: "1.0", - SupportedContractVersions: []string{proto.ContractVersion}, - Capabilities: []proto.Capability{proto.CapabilityEnvelopeGenerator}, + SupportedContractVersions: []string{pluginframework.ContractVersion}, + Capabilities: []pluginframework.Capability{pluginframework.CapabilityEnvelopeGenerator}, }, nil } - return &proto.GetMetadataResponse{ + return &pluginframework.GetMetadataResponse{ Name: "testPlugin", Version: "1.0", - SupportedContractVersions: []string{proto.ContractVersion}, - Capabilities: []proto.Capability{proto.CapabilitySignatureGenerator}, + SupportedContractVersions: []string{pluginframework.ContractVersion}, + Capabilities: []pluginframework.Capability{pluginframework.CapabilitySignatureGenerator}, }, nil } // DescribeKey returns the KeySpec of a key. -func (p *mockPlugin) DescribeKey(ctx context.Context, req *proto.DescribeKeyRequest) (*proto.DescribeKeyResponse, error) { +func (p *mockPlugin) DescribeKey(_ context.Context, _ *pluginframework.DescribeKeyRequest) (*pluginframework.DescribeKeyResponse, error) { ks, _ := proto.EncodeKeySpec(p.keySpec) - return &proto.DescribeKeyResponse{ + return &pluginframework.DescribeKeyResponse{ KeySpec: ks, }, nil } // GenerateSignature generates the raw signature based on the request. -func (p *mockPlugin) GenerateSignature(ctx context.Context, req *proto.GenerateSignatureRequest) (*proto.GenerateSignatureResponse, error) { +func (p *mockPlugin) GenerateSignature(_ context.Context, req *pluginframework.GenerateSignatureRequest) (*pluginframework.GenerateSignatureResponse, error) { sig, err := localSign(req.Payload, p.keySpec.SignatureAlgorithm().Hash(), p.key) var certChain [][]byte for _, cert := range p.certs { @@ -112,22 +113,22 @@ func (p *mockPlugin) GenerateSignature(ctx context.Context, req *proto.GenerateS } sigAlg, _ := proto.EncodeSigningAlgorithm(p.keySpec.SignatureAlgorithm()) if p.invalidSig { - return &proto.GenerateSignatureResponse{ + return &pluginframework.GenerateSignatureResponse{ KeyID: req.KeyID, Signature: invalidSignatureEnvelope, - SigningAlgorithm: string(sigAlg), + SigningAlgorithm: pluginframework.SignatureAlgorithm(string(sigAlg)), CertificateChain: certChain, }, err } if p.invalidCertChain { - return &proto.GenerateSignatureResponse{ + return &pluginframework.GenerateSignatureResponse{ KeyID: req.KeyID, Signature: sig, CertificateChain: [][]byte{{}, {}}, }, err } - return &proto.GenerateSignatureResponse{ + return &pluginframework.GenerateSignatureResponse{ KeyID: req.KeyID, Signature: sig, CertificateChain: certChain, @@ -135,7 +136,7 @@ func (p *mockPlugin) GenerateSignature(ctx context.Context, req *proto.GenerateS } // GenerateEnvelope generates the Envelope with signature based on the request. -func (p *mockPlugin) GenerateEnvelope(ctx context.Context, req *proto.GenerateEnvelopeRequest) (*proto.GenerateEnvelopeResponse, error) { +func (p *mockPlugin) GenerateEnvelope(ctx context.Context, req *pluginframework.GenerateEnvelopeRequest) (*pluginframework.GenerateEnvelopeResponse, error) { internalPluginSigner := pluginSigner{ plugin: newMockPlugin(p.key, p.certs, p.keySpec), } @@ -181,7 +182,7 @@ func (p *mockPlugin) GenerateEnvelope(ctx context.Context, req *proto.GenerateEn } sig, err := sigEnv.Sign(signReq) - return &proto.GenerateEnvelopeResponse{ + return &pluginframework.GenerateEnvelopeResponse{ SignatureEnvelope: sig, SignatureEnvelopeType: req.SignatureEnvelopeType, }, err @@ -196,13 +197,13 @@ func (p *mockPlugin) GenerateEnvelope(ctx context.Context, req *proto.GenerateEn if err != nil { return nil, err } - return &proto.GenerateEnvelopeResponse{ + return &pluginframework.GenerateEnvelopeResponse{ SignatureEnvelope: data, SignatureEnvelopeType: req.SignatureEnvelopeType, Annotations: p.annotations, }, nil } - return &proto.GenerateEnvelopeResponse{}, nil + return &pluginframework.GenerateEnvelopeResponse{}, nil } func TestNewFromPluginFailed(t *testing.T) { @@ -294,7 +295,7 @@ func TestPluginSigner_Sign_Valid(t *testing.T) { for _, envelopeType := range signature.RegisteredEnvelopeTypes() { for _, keyCert := range keyCertPairCollections { t.Run(fmt.Sprintf("external plugin,envelopeType=%v_keySpec=%v", envelopeType, keyCert.keySpecName), func(t *testing.T) { - keySpec, _ := proto.DecodeKeySpec(proto.KeySpec(keyCert.keySpecName)) + keySpec, _ := proto.DecodeKeySpec(pluginframework.KeySpec(keyCert.keySpecName)) pluginSigner := pluginSigner{ plugin: newMockPlugin(keyCert.key, keyCert.certs, keySpec), } @@ -323,7 +324,7 @@ func TestPluginSigner_SignEnvelope_Valid(t *testing.T) { for _, envelopeType := range signature.RegisteredEnvelopeTypes() { for _, keyCert := range keyCertPairCollections { t.Run(fmt.Sprintf("envelopeType=%v, keySpec: %v", envelopeType, keyCert.keySpecName), func(t *testing.T) { - keySpec, _ := proto.DecodeKeySpec(proto.KeySpec(keyCert.keySpecName)) + keySpec, _ := proto.DecodeKeySpec(pluginframework.KeySpec(keyCert.keySpecName)) mockPlugin := newMockPlugin(keyCert.key, keyCert.certs, keySpec) mockPlugin.wantEnvelope = true pluginSigner := pluginSigner{ @@ -339,7 +340,7 @@ func TestPluginSigner_SignWithAnnotations_Valid(t *testing.T) { for _, envelopeType := range signature.RegisteredEnvelopeTypes() { for _, keyCert := range keyCertPairCollections { t.Run(fmt.Sprintf("external plugin,envelopeType=%v_keySpec=%v", envelopeType, keyCert.keySpecName), func(t *testing.T) { - keySpec, _ := proto.DecodeKeySpec(proto.KeySpec(keyCert.keySpecName)) + keySpec, _ := proto.DecodeKeySpec(pluginframework.KeySpec(keyCert.keySpecName)) annts := map[string]string{"key": "value"} pluginSigner := pluginSigner{ plugin: &mockPlugin{ @@ -368,7 +369,7 @@ func testSignerError(t *testing.T, signer pluginSigner, wantEr string, opts nota } } -func basicSignTest(t *testing.T, pluginSigner *pluginSigner, envelopeType string, metadata *proto.GetMetadataResponse) { +func basicSignTest(t *testing.T, pluginSigner *pluginSigner, envelopeType string, metadata *pluginframework.GetMetadataResponse) { validSignOpts.SignatureMediaType = envelopeType data, signerInfo, err := pluginSigner.Sign(context.Background(), validSignDescriptor, validSignOpts) if err != nil { diff --git a/signer/signer_test.go b/signer/signer_test.go index c8d0ae38..8da4a562 100644 --- a/signer/signer_test.go +++ b/signer/signer_test.go @@ -37,6 +37,7 @@ import ( "github.com/notaryproject/notation-go" "github.com/notaryproject/notation-go/internal/envelope" "github.com/notaryproject/notation-go/plugin/proto" + pluginframework "github.com/notaryproject/notation-plugin-framework-go/plugin" "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) @@ -117,7 +118,7 @@ func generateKeyBytes(key crypto.PrivateKey) (keyBytes []byte, err error) { return keyBytes, nil } -func prepareTestKeyCertFile(keyCert *keyCertPair, envelopeType, dir string) (string, string, error) { +func prepareTestKeyCertFile(keyCert *keyCertPair, dir string) (string, string, error) { keyPath, certPath := filepath.Join(dir, keyCert.keySpecName+".key"), filepath.Join(dir, keyCert.keySpecName+".cert") keyBytes, err := generateKeyBytes(keyCert.key) if err != nil { @@ -138,7 +139,7 @@ func prepareTestKeyCertFile(keyCert *keyCertPair, envelopeType, dir string) (str } func testSignerFromFile(t *testing.T, keyCert *keyCertPair, envelopeType, dir string) { - keyPath, certPath, err := prepareTestKeyCertFile(keyCert, envelopeType, dir) + keyPath, certPath, err := prepareTestKeyCertFile(keyCert, dir) if err != nil { t.Fatalf("prepareTestKeyCertFile() failed: %v", err) } @@ -209,7 +210,7 @@ func signRSA(digest []byte, hash crypto.Hash, pk *rsa.PrivateKey) ([]byte, error return rsa.SignPSS(rand.Reader, pk, hash, digest, &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash}) } -func signECDSA(digest []byte, hash crypto.Hash, pk *ecdsa.PrivateKey) ([]byte, error) { +func signECDSA(digest []byte, pk *ecdsa.PrivateKey) ([]byte, error) { r, s, err := ecdsa.Sign(rand.Reader, pk, digest) if err != nil { return nil, err @@ -229,7 +230,7 @@ func localSign(payload []byte, hash crypto.Hash, pk crypto.PrivateKey) ([]byte, case *rsa.PrivateKey: return signRSA(digest, hash, key) case *ecdsa.PrivateKey: - return signECDSA(digest, hash, key) + return signECDSA(digest, key) default: return nil, errors.New("signing private key not supported") } @@ -252,7 +253,7 @@ func generateSigningContent() (ocispec.Descriptor, notation.SignerSignOptions) { return desc, sOpts } -func basicVerification(t *testing.T, sig []byte, envelopeType string, trust *x509.Certificate, metadata *proto.GetMetadataResponse) { +func basicVerification(t *testing.T, sig []byte, envelopeType string, trust *x509.Certificate, metadata *pluginframework.GetMetadataResponse) { // basic verification sigEnv, err := signature.ParseEnvelope(envelopeType, sig) if err != nil { @@ -276,7 +277,7 @@ func basicVerification(t *testing.T, sig []byte, envelopeType string, trust *x50 verifySigningAgent(t, envContent.SignerInfo.UnsignedAttributes.SigningAgent, metadata) } -func verifySigningAgent(t *testing.T, signingAgentId string, metadata *proto.GetMetadataResponse) { +func verifySigningAgent(t *testing.T, signingAgentId string, metadata *pluginframework.GetMetadataResponse) { signingAgentRegex := regexp.MustCompile("^(?P.*) (?P.*)/(?P.*)$") match := signingAgentRegex.FindStringSubmatch(signingAgentId) diff --git a/verifier/verifier.go b/verifier/verifier.go index c340f8e9..2be4731a 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -25,6 +25,9 @@ import ( "strings" "time" + "golang.org/x/mod/semver" + "oras.land/oras-go/v2/content" + "github.com/notaryproject/notation-core-go/revocation" revocationresult "github.com/notaryproject/notation-core-go/revocation/result" "github.com/notaryproject/notation-core-go/signature" @@ -37,12 +40,11 @@ import ( trustpolicyInternal "github.com/notaryproject/notation-go/internal/trustpolicy" "github.com/notaryproject/notation-go/log" "github.com/notaryproject/notation-go/plugin" - "github.com/notaryproject/notation-go/plugin/proto" "github.com/notaryproject/notation-go/verifier/trustpolicy" "github.com/notaryproject/notation-go/verifier/truststore" + fplugin "github.com/notaryproject/notation-plugin-framework-go/plugin" + pluginframework "github.com/notaryproject/notation-plugin-framework-go/plugin" ocispec "github.com/opencontainers/image-spec/specs-go/v1" - "golang.org/x/mod/semver" - "oras.land/oras-go/v2/content" ) // verifier implements notation.Verifier and notation.verifySkipper @@ -199,14 +201,14 @@ func (v *verifier) processSignature(ctx context.Context, sigBlob []byte, envelop } // check if we need to verify using a plugin - var pluginCapabilities []proto.Capability + var pluginCapabilities []fplugin.Capability verificationPluginName, err := getVerificationPlugin(&outcome.EnvelopeContent.SignerInfo) // use plugin, but getPluginName returns an error if err != nil && err != errExtendedAttributeNotExist { return err } - var installedPlugin plugin.VerifyPlugin + var installedPlugin fplugin.VerifyPlugin if verificationPluginName != "" { logger.Debugf("Finding verification plugin %s", verificationPluginName) verificationPluginMinVersion, err := getVerificationPluginMinVersion(&outcome.EnvelopeContent.SignerInfo) @@ -224,7 +226,7 @@ func (v *verifier) processSignature(ctx context.Context, sigBlob []byte, envelop // filter the "verification" capabilities supported by the installed // plugin - metadata, err := installedPlugin.GetMetadata(ctx, &proto.GetMetadataRequest{PluginConfig: pluginConfig}) + metadata, err := installedPlugin.GetMetadata(ctx, &pluginframework.GetMetadataRequest{PluginConfig: pluginConfig}) if err != nil { return err } @@ -241,13 +243,13 @@ func (v *verifier) processSignature(ctx context.Context, sigBlob []byte, envelop } for _, capability := range metadata.Capabilities { - if capability == proto.CapabilityRevocationCheckVerifier || capability == proto.CapabilityTrustedIdentityVerifier { + if capability == pluginframework.CapabilityRevocationCheckVerifier || capability == pluginframework.CapabilityTrustedIdentityVerifier { pluginCapabilities = append(pluginCapabilities, capability) } } if len(pluginCapabilities) == 0 { - return notation.ErrorVerificationInconclusive{Msg: fmt.Sprintf("digital signature requires plugin %q with signature verification capabilities (%q and/or %q) installed", verificationPluginName, proto.CapabilityTrustedIdentityVerifier, proto.CapabilityRevocationCheckVerifier)} + return notation.ErrorVerificationInconclusive{Msg: fmt.Sprintf("digital signature requires plugin %q with signature verification capabilities (%q and/or %q) installed", verificationPluginName, pluginframework.CapabilityTrustedIdentityVerifier, pluginframework.CapabilityRevocationCheckVerifier)} } } @@ -262,7 +264,7 @@ func (v *verifier) processSignature(ctx context.Context, sigBlob []byte, envelop // verify x509 trusted identity based authenticity (only if notation needs // to perform this verification rather than a plugin) - if !slices.Contains(pluginCapabilities, proto.CapabilityTrustedIdentityVerifier) { + if !slices.Contains(pluginCapabilities, pluginframework.CapabilityTrustedIdentityVerifier) { logger.Debug("Validating trust identity") err = verifyX509TrustedIdentities(outcome.EnvelopeContent.SignerInfo.CertificateChain, trustPolicy) if err != nil { @@ -296,7 +298,7 @@ func (v *verifier) processSignature(ctx context.Context, sigBlob []byte, envelop // check if we need to bypass the revocation check, since revocation can be // skipped using a trust policy or a plugin may override the check if outcome.VerificationLevel.Enforcement[trustpolicy.TypeRevocation] != trustpolicy.ActionSkip && - !slices.Contains(pluginCapabilities, proto.CapabilityRevocationCheckVerifier) { + !slices.Contains(pluginCapabilities, pluginframework.CapabilityRevocationCheckVerifier) { logger.Debug("Validating revocation") revocationResult := verifyRevocation(outcome, v.revocationClient, logger) @@ -309,11 +311,11 @@ func (v *verifier) processSignature(ctx context.Context, sigBlob []byte, envelop // perform extended verification using verification plugin if present if installedPlugin != nil { - var capabilitiesToVerify []proto.Capability + var capabilitiesToVerify []pluginframework.Capability for _, pc := range pluginCapabilities { // skip the revocation capability if the trust policy is configured // to skip it - if outcome.VerificationLevel.Enforcement[trustpolicy.TypeRevocation] == trustpolicy.ActionSkip && pc == proto.CapabilityRevocationCheckVerifier { + if outcome.VerificationLevel.Enforcement[trustpolicy.TypeRevocation] == trustpolicy.ActionSkip && pc == pluginframework.CapabilityRevocationCheckVerifier { logger.Debugf("Skipping the %v validation", pc) continue } @@ -333,7 +335,7 @@ func (v *verifier) processSignature(ctx context.Context, sigBlob []byte, envelop return nil } -func processPluginResponse(logger log.Logger, capabilitiesToVerify []proto.Capability, response *proto.VerifySignatureResponse, outcome *notation.VerificationOutcome) error { +func processPluginResponse(logger log.Logger, capabilitiesToVerify []pluginframework.Capability, response *pluginframework.VerifySignatureResponse, outcome *notation.VerificationOutcome) error { verificationPluginName, err := getVerificationPlugin(&outcome.EnvelopeContent.SignerInfo) if err != nil { return err @@ -353,7 +355,7 @@ func processPluginResponse(logger log.Logger, capabilitiesToVerify []proto.Capab return notation.ErrorVerificationInconclusive{Msg: fmt.Sprintf("verification plugin %q failed to verify %q", verificationPluginName, capability)} } switch capability { - case proto.CapabilityTrustedIdentityVerifier: + case pluginframework.CapabilityTrustedIdentityVerifier: if !pluginResult.Success { // find the Authenticity VerificationResult that we already // created during x509 trust store verification @@ -371,7 +373,7 @@ func processPluginResponse(logger log.Logger, capabilitiesToVerify []proto.Capab return authenticityResult.Error } } - case proto.CapabilityRevocationCheckVerifier: + case pluginframework.CapabilityRevocationCheckVerifier: var revocationResult *notation.ValidationResult if !pluginResult.Success { revocationResult = ¬ation.ValidationResult{ @@ -634,7 +636,7 @@ func verifyRevocation(outcome *notation.VerificationOutcome, r revocation.Revoca return result } -func executePlugin(ctx context.Context, installedPlugin plugin.VerifyPlugin, trustPolicy *trustpolicy.TrustPolicy, capabilitiesToVerify []proto.Capability, envelopeContent *signature.EnvelopeContent, pluginConfig map[string]string) (*proto.VerifySignatureResponse, error) { +func executePlugin(ctx context.Context, installedPlugin fplugin.VerifyPlugin, trustPolicy *trustpolicy.TrustPolicy, capabilitiesToVerify []pluginframework.Capability, envelopeContent *signature.EnvelopeContent, pluginConfig map[string]string) (*pluginframework.VerifySignatureResponse, error) { logger := log.GetLogger(ctx) // sanity check if installedPlugin == nil { @@ -662,8 +664,8 @@ func executePlugin(ctx context.Context, installedPlugin plugin.VerifyPlugin, tru // https://github.com/notaryproject/notation-core-go/issues/38 } - signature := proto.Signature{ - CriticalAttributes: proto.CriticalAttributes{ + signature := pluginframework.Signature{ + CriticalAttributes: pluginframework.CriticalAttributes{ ContentType: payloadInfo.ContentType, SigningScheme: string(signerInfo.SignedAttributes.SigningScheme), Expiry: &signerInfo.SignedAttributes.Expiry, @@ -674,12 +676,12 @@ func executePlugin(ctx context.Context, installedPlugin plugin.VerifyPlugin, tru CertificateChain: certChain, } - policy := proto.TrustPolicy{ + policy := pluginframework.TrustPolicy{ TrustedIdentities: trustPolicy.TrustedIdentities, SignatureVerification: capabilitiesToVerify, } - req := &proto.VerifySignatureRequest{ + req := &pluginframework.VerifySignatureRequest{ Signature: signature, TrustPolicy: policy, PluginConfig: pluginConfig, diff --git a/verifier/verifier_test.go b/verifier/verifier_test.go index ae9943d2..a9eddc25 100644 --- a/verifier/verifier_test.go +++ b/verifier/verifier_test.go @@ -25,6 +25,8 @@ import ( "testing" "time" + "golang.org/x/crypto/ocsp" + "github.com/notaryproject/notation-core-go/revocation" "github.com/notaryproject/notation-core-go/signature" "github.com/notaryproject/notation-core-go/testhelper" @@ -34,12 +36,11 @@ import ( "github.com/notaryproject/notation-go/internal/envelope" "github.com/notaryproject/notation-go/internal/mock" "github.com/notaryproject/notation-go/log" - "github.com/notaryproject/notation-go/plugin/proto" "github.com/notaryproject/notation-go/signer" "github.com/notaryproject/notation-go/verifier/trustpolicy" "github.com/notaryproject/notation-go/verifier/truststore" + pluginframework "github.com/notaryproject/notation-plugin-framework-go/plugin" ocispec "github.com/opencontainers/image-spec/specs-go/v1" - "golang.org/x/crypto/ocsp" _ "github.com/notaryproject/notation-core-go/signature/cose" _ "github.com/notaryproject/notation-core-go/signature/jws" @@ -797,7 +798,7 @@ func assertPluginVerification(scheme signature.SigningScheme, t *testing.T) { // plugin is installed but without verification capabilities pluginManager = mock.PluginManager{} - pluginManager.PluginCapabilities = []proto.Capability{proto.CapabilitySignatureGenerator} + pluginManager.PluginCapabilities = []pluginframework.Capability{pluginframework.CapabilitySignatureGenerator} v = verifier{ trustPolicyDoc: &policyDocument, @@ -813,10 +814,10 @@ func assertPluginVerification(scheme signature.SigningScheme, t *testing.T) { // plugin interactions with trusted identity verification success pluginManager = mock.PluginManager{} - pluginManager.PluginCapabilities = []proto.Capability{proto.CapabilityTrustedIdentityVerifier} - pluginManager.PluginRunnerExecuteResponse = &proto.VerifySignatureResponse{ - VerificationResults: map[proto.Capability]*proto.VerificationResult{ - proto.CapabilityTrustedIdentityVerifier: { + pluginManager.PluginCapabilities = []pluginframework.Capability{pluginframework.CapabilityTrustedIdentityVerifier} + pluginManager.PluginRunnerExecuteResponse = &pluginframework.VerifySignatureResponse{ + VerificationResults: map[pluginframework.Capability]*pluginframework.VerificationResult{ + pluginframework.CapabilityTrustedIdentityVerifier: { Success: true, }, }, @@ -837,10 +838,10 @@ func assertPluginVerification(scheme signature.SigningScheme, t *testing.T) { // plugin interactions with trusted identity verification failure pluginManager = mock.PluginManager{} - pluginManager.PluginCapabilities = []proto.Capability{proto.CapabilityTrustedIdentityVerifier} - pluginManager.PluginRunnerExecuteResponse = &proto.VerifySignatureResponse{ - VerificationResults: map[proto.Capability]*proto.VerificationResult{ - proto.CapabilityTrustedIdentityVerifier: { + pluginManager.PluginCapabilities = []pluginframework.Capability{pluginframework.CapabilityTrustedIdentityVerifier} + pluginManager.PluginRunnerExecuteResponse = &pluginframework.VerifySignatureResponse{ + VerificationResults: map[pluginframework.Capability]*pluginframework.VerificationResult{ + pluginframework.CapabilityTrustedIdentityVerifier: { Success: false, Reason: "i feel like failing today", }, @@ -862,10 +863,10 @@ func assertPluginVerification(scheme signature.SigningScheme, t *testing.T) { // plugin interactions with revocation verification success pluginManager = mock.PluginManager{} - pluginManager.PluginCapabilities = []proto.Capability{proto.CapabilityRevocationCheckVerifier} - pluginManager.PluginRunnerExecuteResponse = &proto.VerifySignatureResponse{ - VerificationResults: map[proto.Capability]*proto.VerificationResult{ - proto.CapabilityRevocationCheckVerifier: { + pluginManager.PluginCapabilities = []pluginframework.Capability{pluginframework.CapabilityRevocationCheckVerifier} + pluginManager.PluginRunnerExecuteResponse = &pluginframework.VerifySignatureResponse{ + VerificationResults: map[pluginframework.Capability]*pluginframework.VerificationResult{ + pluginframework.CapabilityRevocationCheckVerifier: { Success: true, }, }, @@ -886,10 +887,10 @@ func assertPluginVerification(scheme signature.SigningScheme, t *testing.T) { // plugin interactions with trusted revocation failure pluginManager = mock.PluginManager{} - pluginManager.PluginCapabilities = []proto.Capability{proto.CapabilityRevocationCheckVerifier} - pluginManager.PluginRunnerExecuteResponse = &proto.VerifySignatureResponse{ - VerificationResults: map[proto.Capability]*proto.VerificationResult{ - proto.CapabilityRevocationCheckVerifier: { + pluginManager.PluginCapabilities = []pluginframework.Capability{pluginframework.CapabilityRevocationCheckVerifier} + pluginManager.PluginRunnerExecuteResponse = &pluginframework.VerifySignatureResponse{ + VerificationResults: map[pluginframework.Capability]*pluginframework.VerificationResult{ + pluginframework.CapabilityRevocationCheckVerifier: { Success: false, Reason: "i feel like failing today", }, @@ -911,13 +912,13 @@ func assertPluginVerification(scheme signature.SigningScheme, t *testing.T) { // plugin interactions with both trusted identity & revocation verification pluginManager = mock.PluginManager{} - pluginManager.PluginCapabilities = []proto.Capability{proto.CapabilityRevocationCheckVerifier, proto.CapabilityTrustedIdentityVerifier} - pluginManager.PluginRunnerExecuteResponse = &proto.VerifySignatureResponse{ - VerificationResults: map[proto.Capability]*proto.VerificationResult{ - proto.CapabilityRevocationCheckVerifier: { + pluginManager.PluginCapabilities = []pluginframework.Capability{pluginframework.CapabilityRevocationCheckVerifier, pluginframework.CapabilityTrustedIdentityVerifier} + pluginManager.PluginRunnerExecuteResponse = &pluginframework.VerifySignatureResponse{ + VerificationResults: map[pluginframework.Capability]*pluginframework.VerificationResult{ + pluginframework.CapabilityRevocationCheckVerifier: { Success: true, }, - proto.CapabilityTrustedIdentityVerifier: { + pluginframework.CapabilityTrustedIdentityVerifier: { Success: true, }, }, @@ -939,7 +940,7 @@ func assertPluginVerification(scheme signature.SigningScheme, t *testing.T) { // plugin interactions with skipped revocation policyDocument.TrustPolicies[0].SignatureVerification.Override = map[trustpolicy.ValidationType]trustpolicy.ValidationAction{trustpolicy.TypeRevocation: trustpolicy.ActionSkip} pluginManager = mock.PluginManager{} - pluginManager.PluginCapabilities = []proto.Capability{proto.CapabilityRevocationCheckVerifier} + pluginManager.PluginCapabilities = []pluginframework.Capability{pluginframework.CapabilityRevocationCheckVerifier} pluginManager.PluginRunnerExecuteError = errors.New("revocation plugin should not be invoked when the trust policy skips revocation check") v = verifier{ @@ -965,7 +966,7 @@ func assertPluginVerification(scheme signature.SigningScheme, t *testing.T) { // plugin unexpected response pluginManager = mock.PluginManager{} - pluginManager.PluginCapabilities = []proto.Capability{proto.CapabilityTrustedIdentityVerifier} + pluginManager.PluginCapabilities = []pluginframework.Capability{pluginframework.CapabilityTrustedIdentityVerifier} pluginManager.PluginRunnerExecuteResponse = "invalid plugin response" pluginManager.PluginRunnerExecuteError = errors.New("invalid plugin response") @@ -992,10 +993,10 @@ func assertPluginVerification(scheme signature.SigningScheme, t *testing.T) { // plugin did not process all extended critical attributes pluginManager = mock.PluginManager{} - pluginManager.PluginCapabilities = []proto.Capability{proto.CapabilityTrustedIdentityVerifier} - pluginManager.PluginRunnerExecuteResponse = &proto.VerifySignatureResponse{ - VerificationResults: map[proto.Capability]*proto.VerificationResult{ - proto.CapabilityTrustedIdentityVerifier: { + pluginManager.PluginCapabilities = []pluginframework.Capability{pluginframework.CapabilityTrustedIdentityVerifier} + pluginManager.PluginRunnerExecuteResponse = &pluginframework.VerifySignatureResponse{ + VerificationResults: map[pluginframework.Capability]*pluginframework.VerificationResult{ + pluginframework.CapabilityTrustedIdentityVerifier: { Success: true, }, }, @@ -1016,9 +1017,9 @@ func assertPluginVerification(scheme signature.SigningScheme, t *testing.T) { // plugin returned empty result for a capability pluginManager = mock.PluginManager{} - pluginManager.PluginCapabilities = []proto.Capability{proto.CapabilityTrustedIdentityVerifier} - pluginManager.PluginRunnerExecuteResponse = &proto.VerifySignatureResponse{ - VerificationResults: map[proto.Capability]*proto.VerificationResult{}, + pluginManager.PluginCapabilities = []pluginframework.Capability{pluginframework.CapabilityTrustedIdentityVerifier} + pluginManager.PluginRunnerExecuteResponse = &pluginframework.VerifySignatureResponse{ + VerificationResults: map[pluginframework.Capability]*pluginframework.VerificationResult{}, ProcessedAttributes: []interface{}{mock.PluginExtendedCriticalAttribute.Key}, } @@ -1139,10 +1140,10 @@ func TestPluginVersionCompatibility(t *testing.T) { }, } pluginManager := mock.PluginManager{} - pluginManager.PluginCapabilities = []proto.Capability{proto.CapabilityTrustedIdentityVerifier} - pluginManager.PluginRunnerExecuteResponse = &proto.VerifySignatureResponse{ - VerificationResults: map[proto.Capability]*proto.VerificationResult{ - proto.CapabilityTrustedIdentityVerifier: { + pluginManager.PluginCapabilities = []pluginframework.Capability{pluginframework.CapabilityTrustedIdentityVerifier} + pluginManager.PluginRunnerExecuteResponse = &pluginframework.VerifySignatureResponse{ + VerificationResults: map[pluginframework.Capability]*pluginframework.VerificationResult{ + pluginframework.CapabilityTrustedIdentityVerifier: { Success: true, }, }, From 65c15ce58f7d8965eb27f4953359f7f60f06c5ea Mon Sep 17 00:00:00 2001 From: Pritesh Bandi Date: Wed, 3 Jan 2024 09:35:40 -0800 Subject: [PATCH 2/5] feedback 1 Signed-off-by: Pritesh Bandi --- go.mod | 6 ++---- go.sum | 2 ++ internal/testdata/oci-layout/index.json | 20 +++++++++++++++++++- plugin/testdata/plugins/foo/libfoo | 0 plugin/testdata/plugins/foo/notation-foo | 0 5 files changed, 23 insertions(+), 5 deletions(-) delete mode 100644 plugin/testdata/plugins/foo/libfoo delete mode 100755 plugin/testdata/plugins/foo/notation-foo diff --git a/go.mod b/go.mod index ce9c0600..a778f6d8 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.20 require ( github.com/go-ldap/ldap/v3 v3.4.6 github.com/notaryproject/notation-core-go v1.0.1 - github.com/notaryproject/notation-plugin-framework-go v0.0.0-20231222132521-c8c68d2fe13b + github.com/notaryproject/notation-plugin-framework-go v0.0.0-20240103032027-c077edacd1ef github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.1.0-rc5 github.com/veraison/go-cose v1.1.0 @@ -22,6 +22,4 @@ require ( github.com/google/uuid v1.3.1 // indirect github.com/x448/float16 v0.8.4 // indirect golang.org/x/sync v0.4.0 // indirect -) - -replace github.com/notaryproject/notation-plugin-framework-go => /Volumes/workplace/notaryproject/notation-plugin-framework-go +) \ No newline at end of file diff --git a/go.sum b/go.sum index dcb02c30..4b344285 100644 --- a/go.sum +++ b/go.sum @@ -19,6 +19,8 @@ github.com/notaryproject/notation-core-go v1.0.1 h1:01doxjDERbd0vocLQrlJdusKrRLN github.com/notaryproject/notation-core-go v1.0.1/go.mod h1:rayl8WlKgS4YxOZgDO0iGGB4Ef515ZFZUFaZDmsPXgE= github.com/notaryproject/notation-plugin-framework-go v0.0.0-20231222132521-c8c68d2fe13b h1:HA7UI2hTamsehj2820fyVU4hECtyv9yx9LvFeErErDg= github.com/notaryproject/notation-plugin-framework-go v0.0.0-20231222132521-c8c68d2fe13b/go.mod h1:RqWSrTOtEASCrGOEffq0n8pSg2KOgKYiWqFWczRSics= +github.com/notaryproject/notation-plugin-framework-go v0.0.0-20240103032027-c077edacd1ef h1:49DEBh9FgHTQDcezSJShAw4r3KBa05EE/vY8pjw5HlU= +github.com/notaryproject/notation-plugin-framework-go v0.0.0-20240103032027-c077edacd1ef/go.mod h1:RqWSrTOtEASCrGOEffq0n8pSg2KOgKYiWqFWczRSics= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI= diff --git a/internal/testdata/oci-layout/index.json b/internal/testdata/oci-layout/index.json index 73321250..f784248d 100644 --- a/internal/testdata/oci-layout/index.json +++ b/internal/testdata/oci-layout/index.json @@ -1 +1,19 @@ -{"schemaVersion":2,"manifests":[{"mediaType":"application/vnd.oci.image.manifest.v1+json","digest":"sha256:19dbd2e48e921426ee8ace4dc892edfb2ecdc1d1a72d5416c83670c30acecef0","size":481,"annotations":{"io.containerd.image.name":"docker.io/library/alpine:v2","org.opencontainers.image.created":"2023-03-13T02:31:43Z","org.opencontainers.image.ref.name":"v2"},"platform":{"architecture":"amd64","os":"linux"}},{"mediaType":"application/vnd.oci.image.manifest.v1+json","digest":"sha256:1a0a67c6f7cfea22d50a18f48d857ed36cf8806e6542db1372675100db62d09b","size":723,"annotations":{"io.cncf.notary.x509chain.thumbprint#S256":"[\"9f5f5aecee24b5cfdc7a91f6d5ac5c3a5348feb17c934d403f59ac251549ea0d\"]","org.opencontainers.image.created":"2023-03-14T04:45:22Z"}},{"mediaType":"application/vnd.oci.image.manifest.v1+json","digest":"sha256:baeaea44f55c94499b7e082bd3c98ad5ec40fdf23ef89cdf4e5db6b83e4f18f5","size":728,"annotations":{"io.cncf.notary.x509chain.thumbprint#S256":"[\"9f5f5aecee24b5cfdc7a91f6d5ac5c3a5348feb17c934d403f59ac251549ea0d\"]","org.opencontainers.image.created":"2023-03-14T08:10:02Z"}}]} \ No newline at end of file +{ + "schemaVersion": 2, + "manifests": [ + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:19dbd2e48e921426ee8ace4dc892edfb2ecdc1d1a72d5416c83670c30acecef0", + "size": 481, + "annotations": { + "io.containerd.image.name": "docker.io/library/alpine:v2", + "org.opencontainers.image.created": "2023-03-13T02:31:43Z", + "org.opencontainers.image.ref.name": "v2" + }, + "platform": { + "architecture": "amd64", + "os": "linux" + } + } + ] +} \ No newline at end of file diff --git a/plugin/testdata/plugins/foo/libfoo b/plugin/testdata/plugins/foo/libfoo deleted file mode 100644 index e69de29b..00000000 diff --git a/plugin/testdata/plugins/foo/notation-foo b/plugin/testdata/plugins/foo/notation-foo deleted file mode 100755 index e69de29b..00000000 From 87f79e2589effbd2dce387cdc0f092b7abdd1dba Mon Sep 17 00:00:00 2001 From: Pritesh Bandi Date: Wed, 3 Jan 2024 09:36:56 -0800 Subject: [PATCH 3/5] feedback 1 Signed-off-by: Pritesh Bandi --- plugin/testdata/plugins/foo/libfoo | 0 plugin/testdata/plugins/foo/notation-foo | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 plugin/testdata/plugins/foo/libfoo create mode 100644 plugin/testdata/plugins/foo/notation-foo diff --git a/plugin/testdata/plugins/foo/libfoo b/plugin/testdata/plugins/foo/libfoo new file mode 100644 index 00000000..e69de29b diff --git a/plugin/testdata/plugins/foo/notation-foo b/plugin/testdata/plugins/foo/notation-foo new file mode 100644 index 00000000..e69de29b From a10d4b23441910718b45967bc1390e12d0f46d00 Mon Sep 17 00:00:00 2001 From: Pritesh Bandi Date: Wed, 3 Jan 2024 09:42:06 -0800 Subject: [PATCH 4/5] feedback 1.1 Signed-off-by: Pritesh Bandi --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 50c6a0b6..0a59aaf3 100644 --- a/go.mod +++ b/go.mod @@ -22,4 +22,4 @@ require ( github.com/google/uuid v1.3.1 // indirect github.com/x448/float16 v0.8.4 // indirect golang.org/x/sync v0.4.0 // indirect -) \ No newline at end of file +) From 94ef0bafd39712d7c8fd92c8c4eb53f632cb4195 Mon Sep 17 00:00:00 2001 From: Pritesh Bandi Date: Wed, 3 Jan 2024 09:43:43 -0800 Subject: [PATCH 5/5] feedback 1.1 Signed-off-by: Pritesh Bandi --- go.sum | 2 -- 1 file changed, 2 deletions(-) diff --git a/go.sum b/go.sum index c9deeca2..8ac00d9c 100644 --- a/go.sum +++ b/go.sum @@ -17,8 +17,6 @@ github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/notaryproject/notation-core-go v1.0.1 h1:01doxjDERbd0vocLQrlJdusKrRLNNn50OJzp0c5I4Cw= github.com/notaryproject/notation-core-go v1.0.1/go.mod h1:rayl8WlKgS4YxOZgDO0iGGB4Ef515ZFZUFaZDmsPXgE= -github.com/notaryproject/notation-plugin-framework-go v0.0.0-20231222132521-c8c68d2fe13b h1:HA7UI2hTamsehj2820fyVU4hECtyv9yx9LvFeErErDg= -github.com/notaryproject/notation-plugin-framework-go v0.0.0-20231222132521-c8c68d2fe13b/go.mod h1:RqWSrTOtEASCrGOEffq0n8pSg2KOgKYiWqFWczRSics= github.com/notaryproject/notation-plugin-framework-go v0.0.0-20240103032027-c077edacd1ef h1:49DEBh9FgHTQDcezSJShAw4r3KBa05EE/vY8pjw5HlU= github.com/notaryproject/notation-plugin-framework-go v0.0.0-20240103032027-c077edacd1ef/go.mod h1:RqWSrTOtEASCrGOEffq0n8pSg2KOgKYiWqFWczRSics= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=