diff --git a/errors.go b/errors.go new file mode 100644 index 00000000..733b0cae --- /dev/null +++ b/errors.go @@ -0,0 +1,49 @@ +package notation + +// ErrorVerificationInconclusive is used when signature verification fails due to a runtime error (e.g. a network error) +type ErrorVerificationInconclusive struct { + Msg string +} + +func (e ErrorVerificationInconclusive) Error() string { + if e.Msg != "" { + return e.Msg + } + return "signature verification was inclusive due to an unexpected error" +} + +// ErrorNoApplicableTrustPolicy is used when there is no trust policy that applies to the given artifact +type ErrorNoApplicableTrustPolicy struct { + Msg string +} + +func (e ErrorNoApplicableTrustPolicy) Error() string { + if e.Msg != "" { + return e.Msg + } + return "there is no applicable trust policy for the given artifact" +} + +// ErrorSignatureRetrievalFailed is used when notation is unable to retrieve the digital signature/s for the given artifact +type ErrorSignatureRetrievalFailed struct { + Msg string +} + +func (e ErrorSignatureRetrievalFailed) Error() string { + if e.Msg != "" { + return e.Msg + } + return "unable to retrieve the digital signature from the registry" +} + +// ErrorVerificationFailed is used when it is determined that the digital signature/s is not valid for the given artifact +type ErrorVerificationFailed struct { + Msg string +} + +func (e ErrorVerificationFailed) Error() string { + if e.Msg != "" { + return e.Msg + } + return "signature verification failed" +} diff --git a/go.mod b/go.mod index 9f2db601..56822548 100644 --- a/go.mod +++ b/go.mod @@ -19,5 +19,5 @@ require ( github.com/golang-jwt/jwt/v4 v4.4.2 // indirect github.com/x448/float16 v0.8.4 // indirect golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d // indirect - golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect + golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f // indirect ) diff --git a/go.sum b/go.sum index 38b7b6f6..57355e89 100644 --- a/go.sum +++ b/go.sum @@ -30,8 +30,8 @@ github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcY golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8= +golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/internal/mock/mocks.go b/internal/mock/mocks.go index f72141c3..a6a146d5 100644 --- a/internal/mock/mocks.go +++ b/internal/mock/mocks.go @@ -5,11 +5,10 @@ import ( _ "embed" "github.com/notaryproject/notation-core-go/signature" - "github.com/notaryproject/notation-go" "github.com/notaryproject/notation-go/internal/plugin" "github.com/notaryproject/notation-go/internal/plugin/manager" - "github.com/notaryproject/notation-go/internal/registry" "github.com/opencontainers/go-digest" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) //go:embed testdata/ca_valid_sig_env.json @@ -40,13 +39,19 @@ var ( SampleArtifactUri = "registry.acme-rockets.io/software/net-monitor@sha256:60043cf45eaebc4c0867fea485a039b598f52fd09fd5b07b0b2d2f88fad9d74e" SampleDigest = digest.Digest("sha256:60043cf45eaebc4c0867fea485a039b598f52fd09fd5b07b0b2d2f88fad9d74e") Annotations = map[string]string{"key": "value"} - ImageDescriptor = notation.Descriptor{ + ImageDescriptor = ocispec.Descriptor{ MediaType: "application/vnd.docker.distribution.manifest.v2+json", Digest: SampleDigest, Size: 528, Annotations: nil, } - JwsSigEnvDescriptor = notation.Descriptor{ + SigManfiestDescriptor = ocispec.Descriptor{ + MediaType: "application/vnd.cncf.oras.artifact.manifest.v1+json", + Digest: SampleDigest, + Size: 300, + Annotations: Annotations, + } + JwsSigEnvDescriptor = ocispec.Descriptor{ MediaType: "application/jose+json", Digest: SampleDigest, Size: 100, @@ -60,39 +65,40 @@ var ( ) type Repository struct { - ResolveResponse notation.Descriptor - ResolveError error - ListSignatureManifestsResponse []registry.SignatureManifest - ListSignatureManifestsError error - GetResponse []byte - GetError error + ResolveResponse ocispec.Descriptor + ResolveError error + ListSignaturesResponse []ocispec.Descriptor + ListSignaturesError error + FetchSignatureBlobResponse []byte + FetchSignatureBlobError error } func NewRepository() Repository { return Repository{ - ResolveResponse: ImageDescriptor, - ListSignatureManifestsResponse: []registry.SignatureManifest{{ - Blob: JwsSigEnvDescriptor, - Annotations: Annotations, - }}, - GetResponse: MockCaValidSigEnv, + ResolveResponse: ImageDescriptor, + ListSignaturesResponse: []ocispec.Descriptor{SigManfiestDescriptor}, + FetchSignatureBlobResponse: MockCaValidSigEnv, } } -func (t Repository) Resolve(ctx context.Context, reference string) (notation.Descriptor, error) { +func (t Repository) Resolve(ctx context.Context, reference string) (ocispec.Descriptor, error) { return t.ResolveResponse, t.ResolveError } -func (t Repository) ListSignatureManifests(ctx context.Context, manifestDigest digest.Digest) ([]registry.SignatureManifest, error) { - return t.ListSignatureManifestsResponse, t.ListSignatureManifestsError +func (t Repository) ListSignatures(ctx context.Context, desc ocispec.Descriptor, fn func(signatureManifests []ocispec.Descriptor) error) error { + err := fn(t.ListSignaturesResponse) + if err != nil { + return err + } + return t.ListSignaturesError } -func (t Repository) GetBlob(ctx context.Context, digest digest.Digest) ([]byte, error) { - return t.GetResponse, t.GetError +func (t Repository) FetchSignatureBlob(ctx context.Context, desc ocispec.Descriptor) ([]byte, ocispec.Descriptor, error) { + return t.FetchSignatureBlobResponse, JwsSigEnvDescriptor, t.FetchSignatureBlobError } -func (t Repository) PutSignatureManifest(ctx context.Context, signature []byte, signatureMediaType string, manifest notation.Descriptor, annotaions map[string]string) (notation.Descriptor, registry.SignatureManifest, error) { - return notation.Descriptor{}, registry.SignatureManifest{}, nil +func (t Repository) PushSignature(ctx context.Context, mediaType string, blob []byte, subject ocispec.Descriptor, annotations map[string]string) (blobDesc, manifestDesc ocispec.Descriptor, err error) { + return ocispec.Descriptor{}, ocispec.Descriptor{}, nil } type PluginManager struct { diff --git a/internal/mock_origin/mocks.go b/internal/mock_origin/mocks.go new file mode 100644 index 00000000..43d5485c --- /dev/null +++ b/internal/mock_origin/mocks.go @@ -0,0 +1,134 @@ +package mock + +import ( + "context" + _ "embed" + + "github.com/notaryproject/notation-core-go/signature" + notation "github.com/notaryproject/notation-go/internal" + "github.com/notaryproject/notation-go/internal/plugin" + "github.com/notaryproject/notation-go/internal/plugin/manager" + "github.com/notaryproject/notation-go/internal/registry" + "github.com/opencontainers/go-digest" +) + +//go:embed testdata/ca_valid_sig_env.json +var MockCaValidSigEnv []byte + +//go:embed testdata/ca_invalid_sig_env.json +var MockCaInvalidSigEnv []byte + +//go:embed testdata/sa_valid_sig_env.json +var MockSaValidSigEnv []byte + +//go:embed testdata/ca_plugin_sig_env.json +var MockCaPluginSigEnv []byte // extended attributes are "SomeKey":"SomeValue", "io.cncf.notary.verificationPlugin":"plugin-name" + +//go:embed testdata/sa_invalid_sig_env.json +var MockSaInvalidSigEnv []byte + +//go:embed testdata/ca_expired_sig_env.json +var MockCaExpiredSigEnv []byte + +//go:embed testdata/sa_expired_sig_env.json +var MockSaExpiredSigEnv []byte + +//go:embed testdata/sa_plugin_sig_env.json +var MockSaPluginSigEnv []byte // extended attributes are "SomeKey":"SomeValue", "io.cncf.notary.verificationPlugin":"plugin-name" + +var ( + SampleArtifactUri = "registry.acme-rockets.io/software/net-monitor@sha256:60043cf45eaebc4c0867fea485a039b598f52fd09fd5b07b0b2d2f88fad9d74e" + SampleDigest = digest.Digest("sha256:60043cf45eaebc4c0867fea485a039b598f52fd09fd5b07b0b2d2f88fad9d74e") + Annotations = map[string]string{"key": "value"} + ImageDescriptor = notation.Descriptor{ + MediaType: "application/vnd.docker.distribution.manifest.v2+json", + Digest: SampleDigest, + Size: 528, + Annotations: nil, + } + JwsSigEnvDescriptor = notation.Descriptor{ + MediaType: "application/jose+json", + Digest: SampleDigest, + Size: 100, + Annotations: Annotations, + } + PluginExtendedCriticalAttribute = signature.Attribute{ + Key: "SomeKey", + Critical: true, + Value: "SomeValue", + } +) + +type Repository struct { + ResolveResponse notation.Descriptor + ResolveError error + ListSignatureManifestsResponse []registry.SignatureManifest + ListSignatureManifestsError error + GetResponse []byte + GetError error +} + +func NewRepository() Repository { + return Repository{ + ResolveResponse: ImageDescriptor, + ListSignatureManifestsResponse: []registry.SignatureManifest{{ + Blob: JwsSigEnvDescriptor, + Annotations: Annotations, + }}, + GetResponse: MockCaValidSigEnv, + } +} + +func (t Repository) Resolve(ctx context.Context, reference string) (notation.Descriptor, error) { + return t.ResolveResponse, t.ResolveError +} + +func (t Repository) ListSignatureManifests(ctx context.Context, manifestDigest digest.Digest) ([]registry.SignatureManifest, error) { + return t.ListSignatureManifestsResponse, t.ListSignatureManifestsError +} + +func (t Repository) GetBlob(ctx context.Context, digest digest.Digest) ([]byte, error) { + return t.GetResponse, t.GetError +} + +func (t Repository) PutSignatureManifest(ctx context.Context, signature []byte, signatureMediaType string, manifest notation.Descriptor, annotaions map[string]string) (notation.Descriptor, registry.SignatureManifest, error) { + return notation.Descriptor{}, registry.SignatureManifest{}, nil +} + +type PluginManager struct { + PluginCapabilities []plugin.Capability + GetPluginError error + PluginRunnerLoadError error + PluginRunnerExecuteResponse interface{} + PluginRunnerExecuteError error +} + +type PluginRunner struct { + Response interface{} + Error error +} + +func (pr PluginRunner) Run(ctx context.Context, req plugin.Request) (interface{}, error) { + return pr.Response, pr.Error +} + +func (pm PluginManager) Get(ctx context.Context, name string) (*manager.Plugin, error) { + return &manager.Plugin{ + Metadata: plugin.Metadata{ + Name: "plugin-name", + Description: "for mocking in unit tests", + Version: "1.0.0", + URL: ".", + SupportedContractVersions: []string{"1.0"}, + Capabilities: pm.PluginCapabilities, + }, + Path: ".", + Err: nil, + }, pm.GetPluginError +} +func (pm PluginManager) Runner(name string) (plugin.Runner, error) { + return PluginRunner{ + Response: pm.PluginRunnerExecuteResponse, + Error: pm.PluginRunnerExecuteError, + }, pm.PluginRunnerLoadError +} diff --git a/internal/mock_origin/testdata/ca_expired_sig_env.json b/internal/mock_origin/testdata/ca_expired_sig_env.json new file mode 100644 index 00000000..9d629269 --- /dev/null +++ b/internal/mock_origin/testdata/ca_expired_sig_env.json @@ -0,0 +1,12 @@ +{ + "payload": "eyJ0YXJnZXRBcnRpZmFjdCI6eyJtZWRpYVR5cGUiOiJhcHBsaWNhdGlvbi92bmQuZG9ja2VyLmRpc3RyaWJ1dGlvbi5tYW5pZmVzdC52Mitqc29uIiwiZGlnZXN0Ijoic2hhMjU2OjYwMDQzY2Y0NWVhZWJjNGMwODY3ZmVhNDg1YTAzOWI1OThmNTJmZDA5ZmQ1YjA3YjBiMmQyZjg4ZmFkOWQ3NGUiLCJzaXplIjo1Mjh9fQ", + "protected": "eyJhbGciOiJQUzM4NCIsImNyaXQiOlsiaW8uY25jZi5ub3Rhcnkuc2lnbmluZ1NjaGVtZSIsImlvLmNuY2Yubm90YXJ5LmV4cGlyeSJdLCJjdHkiOiJhcHBsaWNhdGlvbi92bmQuY25jZi5ub3RhcnkucGF5bG9hZC52MStqc29uIiwiaW8uY25jZi5ub3RhcnkuZXhwaXJ5IjoiMjAyMi0wNy0yOVQyMzo1OTowMFoiLCJpby5jbmNmLm5vdGFyeS5zaWduaW5nU2NoZW1lIjoibm90YXJ5Lng1MDkiLCJpby5jbmNmLm5vdGFyeS5zaWduaW5nVGltZSI6IjIwMjItMDctMjlUMDA6MDA6MDBaIn0", + "header": { + "x5c": [ + "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" + ], + "io.cncf.notary.SigningAgent": "Notation/1.0.0" + }, + "signature": "RZtqCD4KGh5_CD8wjG69TJIzzB4Cr-cxQhKTvZJYsRVIJyl3s5D0215GhBrggomVk9-LGD2FdWd2VfuaLd4bmhW3rSV3ltmAext7DNQFg2xtMeYSeCL2U_ygN2j4bc80RDaX8w_zOTVOmuhW6i2jgwRjWXdDaJeYTbZA2syA5R38tYYewVcZJ6U057Wsflt5yPWJCdxZLuTago5CkbLASL8HHnmlUkDvKKB1Y9SNDOQ3AmGP4-XJykcX_MfPo5RGRvZE-zHUJOEKj3ryfC0UTUT7V1ISTagqOt7zOa1BEzgQ-1GQk1MbaPPZWkiOZX4RqMXMV3hVqtDuZxlpT25KzZPm1USwWwJkycv7YB69fc2aoHJAPo-39uEV9fdAz_03whnrQSpfJbmHHTXMJkWKrZ5ozU-8zlEttWyL5D85zAouSMVXWm22zMrDW-XxST9QoeV4b1_BedW1PwJDbeU6P1hhobnQh3jHmSueVl_WZ5_g8_iVepSmSBcR1e4WpoPi" +} \ No newline at end of file diff --git a/internal/mock_origin/testdata/ca_invalid_sig_env.json b/internal/mock_origin/testdata/ca_invalid_sig_env.json new file mode 100644 index 00000000..255eb32e --- /dev/null +++ b/internal/mock_origin/testdata/ca_invalid_sig_env.json @@ -0,0 +1,12 @@ +{ + "payload": "eyJ0YXJnZXRBcnRpZmFjdCI6eyJtZWRpYVR5cGUiOiJhcHBsaWNhdGlvbi92bmQuZG9ja2VyLmRpc3RyaWJ1dGlvbi5tYW5pZmVzdC52Mitqc29uIiwiZGlnZXN0Ijoic2hhMjU2OjYwMDQzY2Y0NWVhZWJjNGMwODY3ZmVhNDg1YTAzOWI1OThmNTJmZDA5ZmQ1YjA3YjBiMmQyZjg4ZmFkOWQ3NGUiLCJzaXplIjo1Mjh9fQ=", + "protected": "eyJhbGciOiJQUzM4NCIsImNyaXQiOlsiaW8uY25jZi5ub3Rhcnkuc2lnbmluZ1NjaGVtZSIsImlvLmNuY2Yubm90YXJ5LmV4cGlyeSJdLCJjdHkiOiJhcHBsaWNhdGlvbi92bmQuY25jZi5ub3RhcnkucGF5bG9hZC52MStqc29uIiwiaW8uY25jZi5ub3RhcnkuZXhwaXJ5IjoiMjEyMC0xMS0wOVQwNzowMDowMFoiLCJpby5jbmNmLm5vdGFyeS5zaWduaW5nU2NoZW1lIjoibm90YXJ5Lng1MDkiLCJpby5jbmNmLm5vdGFyeS5zaWduaW5nVGltZSI6IjIwMjAtMTEtMDlUMDc6MDA6MDBaIn0", + "header": { + "x5c": [ + "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" + ], + "io.cncf.notary.SigningAgent": "Notation/1.0.0" + }, + "signature": "ZvsxyaSqDzS7mY_jKpnq2XtBcmyWmSE461BHL6q2pAx_-Rxr8Fvs2oIfZdSG2o3qugPDjzZDMhKdYdnrW1AIEkVIG_QUmeyGj28PVXxsC5NKpXwrPUMOzrXSFLHIvBNZ2q87wRYInsgCPtv5ZPv0IgA2sAW6y7NlVM2D0vJax55ITsJO5aEaEUlAdi_H7-TCD48DHuFpnJdNkVB_hZkwYfxuqIKU2C__Z2hLLHxaS2LzuzhqOnYlbqn4e225uZt9odXq3qmZ_44Vx3DYL_-ZuV0S9jEk7NW8-dO0T0MeQn6VXDyfT1rjc6IVPnLxAnELFyLn121GYulYC8V2D1_MLcv8sDHY23rHb3-R-WCLMDSfaIvReY89vQfxcfpdCRC0F3N2CcnrgsrUC6Fplm5Uy45Gn9--b7x5cdSzOzQsefCH1GpixW7YyNs1xZQ17WqdYyWD2EBrB5vqVFzkzDYnQ4H-p9G3AzM4HTrjWqHX-0cYHlpmTS4AjVxn0UV80Jn9" +} \ No newline at end of file diff --git a/internal/mock_origin/testdata/ca_plugin_sig_env.json b/internal/mock_origin/testdata/ca_plugin_sig_env.json new file mode 100644 index 00000000..8b14bef8 --- /dev/null +++ b/internal/mock_origin/testdata/ca_plugin_sig_env.json @@ -0,0 +1,12 @@ +{ + "payload": "eyJ0YXJnZXRBcnRpZmFjdCI6eyJtZWRpYVR5cGUiOiJhcHBsaWNhdGlvbi92bmQuZG9ja2VyLmRpc3RyaWJ1dGlvbi5tYW5pZmVzdC52Mitqc29uIiwiZGlnZXN0Ijoic2hhMjU2OjYwMDQzY2Y0NWVhZWJjNGMwODY3ZmVhNDg1YTAzOWI1OThmNTJmZDA5ZmQ1YjA3YjBiMmQyZjg4ZmFkOWQ3NGUiLCJzaXplIjo1Mjh9fQ", + "protected": "eyJTb21lS2V5IjoiU29tZVZhbHVlIiwiYWxnIjoiUFMzODQiLCJjcml0IjpbImlvLmNuY2Yubm90YXJ5LnNpZ25pbmdTY2hlbWUiLCJTb21lS2V5IiwiaW8uY25jZi5ub3RhcnkuZXhwaXJ5IiwiaW8uY25jZi5ub3RhcnkudmVyaWZpY2F0aW9uUGx1Z2luIl0sImN0eSI6ImFwcGxpY2F0aW9uL3ZuZC5jbmNmLm5vdGFyeS5wYXlsb2FkLnYxK2pzb24iLCJpby5jbmNmLm5vdGFyeS5leHBpcnkiOiIyMTIwLTExLTA5VDA3OjAwOjAwWiIsImlvLmNuY2Yubm90YXJ5LnNpZ25pbmdTY2hlbWUiOiJub3RhcnkueDUwOSIsImlvLmNuY2Yubm90YXJ5LnNpZ25pbmdUaW1lIjoiMjAyMC0xMS0wOVQwNzowMDowMFoiLCJpby5jbmNmLm5vdGFyeS52ZXJpZmljYXRpb25QbHVnaW4iOiJwbHVnaW4tbmFtZSJ9", + "header": { + "x5c": [ + "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" + ], + "io.cncf.notary.SigningAgent": "Notation/1.0.0" + }, + "signature": "cyB34qtMss9N1E_2XAQ_71c6j1fOcamenm7YrYsXn562XOhFgJKUjmDYWkz9mmdLN-GqQNKA8MhAfKt2ipXxsWldrb3a-6AZ-y4jIkY5XIY_s7Sndz58DPtez0X4kAehvKiyUtDVPbqIJQ5Hwgj8tC_f0Yva6pdrSD7xwenxwiCZmxM6N_LV9d1oYSDQi9890XRrFK4M1YRlOZquJ19HrhADLVJXS-ZfqcTE_tceoU2Hq82pqd2MnazAtJiWZm0cxwt-OsGlgGrkvHoNcMYS8K6BSBvL-vVtOuSpca89QrLsTCnKnmvUlw3wrWTDf83qhPyfw-2ASrE2V57vunpxSNyoA_70fNgOuhWUZZUTi9eXxutp0GCcGTem7MzZRBJVOVdw9OgR3pClGiRxP3BE2Atn3EUXs2HgQHEiE1KZvVHFeObB6asMqfbAMMNDgZCsZi7Yah7NaYg1NH9YwrJgAtNFW0p2trxiQ6uqICD2m54yGtRmvw_O9kt5HnUaBQJX" +} \ No newline at end of file diff --git a/internal/mock_origin/testdata/ca_valid_sig_env.json b/internal/mock_origin/testdata/ca_valid_sig_env.json new file mode 100644 index 00000000..e547a13f --- /dev/null +++ b/internal/mock_origin/testdata/ca_valid_sig_env.json @@ -0,0 +1,12 @@ +{ + "payload": "eyJ0YXJnZXRBcnRpZmFjdCI6eyJtZWRpYVR5cGUiOiJhcHBsaWNhdGlvbi92bmQuZG9ja2VyLmRpc3RyaWJ1dGlvbi5tYW5pZmVzdC52Mitqc29uIiwiZGlnZXN0Ijoic2hhMjU2OjYwMDQzY2Y0NWVhZWJjNGMwODY3ZmVhNDg1YTAzOWI1OThmNTJmZDA5ZmQ1YjA3YjBiMmQyZjg4ZmFkOWQ3NGUiLCJzaXplIjo1Mjh9fQ", + "protected": "eyJhbGciOiJQUzM4NCIsImNyaXQiOlsiaW8uY25jZi5ub3Rhcnkuc2lnbmluZ1NjaGVtZSIsImlvLmNuY2Yubm90YXJ5LmV4cGlyeSJdLCJjdHkiOiJhcHBsaWNhdGlvbi92bmQuY25jZi5ub3RhcnkucGF5bG9hZC52MStqc29uIiwiaW8uY25jZi5ub3RhcnkuZXhwaXJ5IjoiMjEyMC0xMS0wOVQwNzowMDowMFoiLCJpby5jbmNmLm5vdGFyeS5zaWduaW5nU2NoZW1lIjoibm90YXJ5Lng1MDkiLCJpby5jbmNmLm5vdGFyeS5zaWduaW5nVGltZSI6IjIwMjAtMTEtMDlUMDc6MDA6MDBaIn0", + "header": { + "x5c": [ + "MIIEWDCCAsCgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJVUzELMAkGA1UECBMCV0ExEDAOBgNVBAcTB1NlYXR0bGUxDzANBgNVBAoTBk5vdGFyeTEbMBkGA1UEAxMSTm90YXRpb24gVGVzdCBSb290MCAXDTIwMTAwOTA3MDAwMFoYDzIxMjIwODA2MjAzODQ1WjBaMQswCQYDVQQGEwJVUzELMAkGA1UECBMCV0ExEDAOBgNVBAcTB1NlYXR0bGUxDzANBgNVBAoTBk5vdGFyeTEbMBkGA1UEAxMSTm90YXRpb24gVGVzdCBSb290MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAwE8YkFUAA0R7aUkRYxHKYoVbFPx9xhuNovLKDy72/7X0+j4XdGP4C0aAX2KLfgy9OR1RIUwtpMyI7k7ZFRd+ljcMW/FgbirfhkY/8axjamOYMBO0Qg+w93oaI6HA1gvZ/WZem4PHu68LlZhLQ2BrQwCz/F/3Ft0IZ2S1aF6N6vajx2le8xTI5hQS+UZFPQGrBUqrjcYc6GkL8XqL+rLGZaKGfh3c7bF9cEbA1H2Tm6MDFnfoFemerbP3v19JoUH+EtOnvYmNZWEU51RaLsNGkC3E/unXAnIfXrNxHDcbehyfa5y3AT10Shiron6O4Bc9S0MvwtXyLT6qein3Nh0VKBFUMSdthu5ZrSR28T9wDWHMXngpa115VjHOQDY3gDPwfzZ0xitN3NpMnivxculGUCkEQpst957tqQNJpS/zipI5Mtej0YOAhVKGQMjDIJekZ2DXDNd1X3xfahrR5VEQF0gnRFhA3vhycDqFj4E6Hoc5y3SxnFqrhX3w2wyFt/xRAgMBAAGjJzAlMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzANBgkqhkiG9w0BAQsFAAOCAYEAAdONCAJxdB7H0uFDw6H+8Z5MtoRdJe6ZhlM2O5WMzkC1DLSyrF7arPnUMTeSyNS2Fx1BU38n5R1wvdgSfWtjm7o2ZyR8JQ+AngPklUCTNeL18kxNNXpmjDuMvsRlfHcr5hherjiQ49jWlpFqGRrNtZQWiVEI0r9Qz8DtZTw3GYF4MSuotA6wuUjolI1V2oMn/gdt8FFo0XUTDyiA12qpZzkUHY1rg3zJxKq3pIk04E7k6rFakHyZL91ipV2UeSbNq9vwLL7cglfPJ8+J+9AKvIPDstDF5k0ivUCYH5fIFZBGoceLiNfHSMcqA/qWfErqLBWAkACRUNyCWpAEv3DfDRbTHId0n6QQwOXj5d9YnDrmOLvQcn/sa+ZBfFMK7RdG9uVwMRyo+sRUnxo+v2lcvYwWymL7ONQqVWZbTJCxuG90Unxa3cQHZiKB5mgKweMft+vp6C3IQFhFfP8j1kvRTJq8ZqSEBADppUuBZJ1KWalwauK0AE4jpHlE0KsYDXiP", + "MIIEizCCAvOgAwIBAgIBATANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJVUzELMAkGA1UECBMCV0ExEDAOBgNVBAcTB1NlYXR0bGUxDzANBgNVBAoTBk5vdGFyeTEbMBkGA1UEAxMSTm90YXRpb24gVGVzdCBSb290MCAXDTIwMDkwOTA3MDAwMFoYDzIxMjIwOTA1MjAzODQ1WjBaMQswCQYDVQQGEwJVUzELMAkGA1UECBMCV0ExEDAOBgNVBAcTB1NlYXR0bGUxDzANBgNVBAoTBk5vdGFyeTEbMBkGA1UEAxMSTm90YXRpb24gVGVzdCBSb290MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAxxAZ8VZegqBUctz3BkwhObZKnW+KsN5/N1/u2vPLmEzHDj6xgd8Hn0JoughDaxeQCV66NC2obqPnPp4+68G/qZnxkXVXdFyqVodu4FgPUjiqcJjft7bh45BVgLFpOqSqDQ3ko30B7gdGfIIkoBj/8gz3tHnmIvl3MywtOhDeGnlLNzBY52wVmhPIdKOaW/7WkMrXKFCkLkNICGnIpWuyBtC+7RfM8hG6eRW1KCm5xrkRmn5ptonjxix/JTGj4me/NMkwdVkz6wcCSAJnqTgHi2oqk73qqNu0LHsEMFBF8IGqmVkn2MOHkFamPBokzQ6HXXfvR4nbcWQZCUgRinPTVg9CF0B6XSCEMCSH5kveZxTQtAFRB6NosbzuU5jDmJgpbDfauev7Eg/6bZzphcugRkVuwulymzsake5Jbvs9Kyw3CNPYH2G3Kli1FNhfc46ugXHbIfXgNQcou3xabcu+r6cFRqqK6NmV9ouMQRj8Ri95Gp2BUlpTEFhcvMb9d4nXAgMBAAGjWjBYMA4GA1UdDwEB/wQEAwICBDATBgNVHSUEDDAKBggrBgEFBQcDAzASBgNVHRMBAf8ECDAGAQH/AgEBMB0GA1UdDgQWBBS5FZjt9UsEPkcKrStrnjSpTq4kDTANBgkqhkiG9w0BAQsFAAOCAYEAKtxfv12LzM85bxOMp5++pIDa6eMcBaurYbAM2yC9B6LuHf0JGeFdNqt4Fw38Ajooj2vWMWBrARVEZRVqTC5+ZSN2meGBXBXlT4n8FdEdmv+05iwVYdmDFp8FKeoOZZZF23u+r2OrazJo1ufWmoSI2P0lEfZQQFQElltWu3QH+OLOWXJmB7KbLKyheelGK5XhtAYYapRdW4sKJ398ybpv5C1oALCcTwoSmvH8wW5J4/gjmhKICYh2goMauf0lesdxj+0His7E8blOWrUmfOB5dp73XawLKcd/UxHN8zAPC08LDL9NMcihn3ZHKi7/dtkiV2iSaDPD1ChSGdqfXIysYqOhYoktgAfBZ43CWnqQhgB8NezRKdOStYC3P2AGJW18irxxTRp2CO+gnXEcyhyr+cvyf0j8MkRSaHLXzjIrECu8BUitB6sKughdN13fs5t5SIiO6foeFdvIpZFFKO8s+4oTOSDCos2WFoC+8TZS6r583OtFLmywl1HRgQkobGgw" + ], + "io.cncf.notary.SigningAgent": "Notation/1.0.0" + }, + "signature": "ZvsxyaSqDzS7mY_jKpnq2XtBcmyWmSE461BHL6q2pAx_-Rxr8Fvs2oIfZdSG2o3qugPDjzZDMhKdYdnrW1AIEkVIG_QUmeyGj28PVXxsC5NKpXwrPUMOzrXSFLHIvBNZ2q87wRYInsgCPtv5ZPv0IgA2sAW6y7NlVM2D0vJax55ITsJO5aEaEUlAdi_H7-TCD48DHuFpnJdNkVB_hZkwYfxuqIKU2C__Z2hLLHxaS2LzuzhqOnYlbqn4e225uZt9odXq3qmZ_44Vx3DYL_-ZuV0S9jEk7NW8-dO0T0MeQn6VXDyfT1rjc6IVPnLxAnELFyLn121GYulYC8V2D1_MLcv8sDHY23rHb3-R-WCLMDSfaIvReY89vQfxcfpdCRC0F3N2CcnrgsrUC6Fplm5Uy45Gn9--b7x5cdSzOzQsefCH1GpixW7YyNs1xZQ17WqdYyWD2EBrB5vqVFzkzDYnQ4H-p9G3AzM4HTrjWqHX-0cYHlpmTS4AjVxn0UV80Jn9" +} \ No newline at end of file diff --git a/internal/mock_origin/testdata/sa_expired_sig_env.json b/internal/mock_origin/testdata/sa_expired_sig_env.json new file mode 100644 index 00000000..19a316c0 --- /dev/null +++ b/internal/mock_origin/testdata/sa_expired_sig_env.json @@ -0,0 +1,12 @@ +{ + "payload": "eyJ0YXJnZXRBcnRpZmFjdCI6eyJtZWRpYVR5cGUiOiJhcHBsaWNhdGlvbi92bmQuZG9ja2VyLmRpc3RyaWJ1dGlvbi5tYW5pZmVzdC52Mitqc29uIiwiZGlnZXN0Ijoic2hhMjU2OjYwMDQzY2Y0NWVhZWJjNGMwODY3ZmVhNDg1YTAzOWI1OThmNTJmZDA5ZmQ1YjA3YjBiMmQyZjg4ZmFkOWQ3NGUiLCJzaXplIjo1Mjh9fQ", + "protected": "eyJhbGciOiJQUzM4NCIsImNyaXQiOlsiaW8uY25jZi5ub3Rhcnkuc2lnbmluZ1NjaGVtZSIsImlvLmNuY2Yubm90YXJ5LmF1dGhlbnRpY1NpZ25pbmdUaW1lIiwiaW8uY25jZi5ub3RhcnkuZXhwaXJ5Il0sImN0eSI6ImFwcGxpY2F0aW9uL3ZuZC5jbmNmLm5vdGFyeS5wYXlsb2FkLnYxK2pzb24iLCJpby5jbmNmLm5vdGFyeS5hdXRoZW50aWNTaWduaW5nVGltZSI6IjIwMjItMDctMjlUMDA6MDA6MDBaIiwiaW8uY25jZi5ub3RhcnkuZXhwaXJ5IjoiMjAyMi0wNy0yOVQyMzo1OTowMFoiLCJpby5jbmNmLm5vdGFyeS5zaWduaW5nU2NoZW1lIjoibm90YXJ5Lng1MDkuc2lnbmluZ0F1dGhvcml0eSJ9", + "header": { + "x5c": [ + "MIIEWDCCAsCgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJVUzELMAkGA1UECBMCV0ExEDAOBgNVBAcTB1NlYXR0bGUxDzANBgNVBAoTBk5vdGFyeTEbMBkGA1UEAxMSTm90YXRpb24gVGVzdCBSb290MCAXDTIwMTAwOTA3MDAwMFoYDzIxMjIwODA2MjAzODQ1WjBaMQswCQYDVQQGEwJVUzELMAkGA1UECBMCV0ExEDAOBgNVBAcTB1NlYXR0bGUxDzANBgNVBAoTBk5vdGFyeTEbMBkGA1UEAxMSTm90YXRpb24gVGVzdCBSb290MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAwE8YkFUAA0R7aUkRYxHKYoVbFPx9xhuNovLKDy72/7X0+j4XdGP4C0aAX2KLfgy9OR1RIUwtpMyI7k7ZFRd+ljcMW/FgbirfhkY/8axjamOYMBO0Qg+w93oaI6HA1gvZ/WZem4PHu68LlZhLQ2BrQwCz/F/3Ft0IZ2S1aF6N6vajx2le8xTI5hQS+UZFPQGrBUqrjcYc6GkL8XqL+rLGZaKGfh3c7bF9cEbA1H2Tm6MDFnfoFemerbP3v19JoUH+EtOnvYmNZWEU51RaLsNGkC3E/unXAnIfXrNxHDcbehyfa5y3AT10Shiron6O4Bc9S0MvwtXyLT6qein3Nh0VKBFUMSdthu5ZrSR28T9wDWHMXngpa115VjHOQDY3gDPwfzZ0xitN3NpMnivxculGUCkEQpst957tqQNJpS/zipI5Mtej0YOAhVKGQMjDIJekZ2DXDNd1X3xfahrR5VEQF0gnRFhA3vhycDqFj4E6Hoc5y3SxnFqrhX3w2wyFt/xRAgMBAAGjJzAlMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzANBgkqhkiG9w0BAQsFAAOCAYEAAdONCAJxdB7H0uFDw6H+8Z5MtoRdJe6ZhlM2O5WMzkC1DLSyrF7arPnUMTeSyNS2Fx1BU38n5R1wvdgSfWtjm7o2ZyR8JQ+AngPklUCTNeL18kxNNXpmjDuMvsRlfHcr5hherjiQ49jWlpFqGRrNtZQWiVEI0r9Qz8DtZTw3GYF4MSuotA6wuUjolI1V2oMn/gdt8FFo0XUTDyiA12qpZzkUHY1rg3zJxKq3pIk04E7k6rFakHyZL91ipV2UeSbNq9vwLL7cglfPJ8+J+9AKvIPDstDF5k0ivUCYH5fIFZBGoceLiNfHSMcqA/qWfErqLBWAkACRUNyCWpAEv3DfDRbTHId0n6QQwOXj5d9YnDrmOLvQcn/sa+ZBfFMK7RdG9uVwMRyo+sRUnxo+v2lcvYwWymL7ONQqVWZbTJCxuG90Unxa3cQHZiKB5mgKweMft+vp6C3IQFhFfP8j1kvRTJq8ZqSEBADppUuBZJ1KWalwauK0AE4jpHlE0KsYDXiP", + "MIIEizCCAvOgAwIBAgIBATANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJVUzELMAkGA1UECBMCV0ExEDAOBgNVBAcTB1NlYXR0bGUxDzANBgNVBAoTBk5vdGFyeTEbMBkGA1UEAxMSTm90YXRpb24gVGVzdCBSb290MCAXDTIwMDkwOTA3MDAwMFoYDzIxMjIwOTA1MjAzODQ1WjBaMQswCQYDVQQGEwJVUzELMAkGA1UECBMCV0ExEDAOBgNVBAcTB1NlYXR0bGUxDzANBgNVBAoTBk5vdGFyeTEbMBkGA1UEAxMSTm90YXRpb24gVGVzdCBSb290MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAxxAZ8VZegqBUctz3BkwhObZKnW+KsN5/N1/u2vPLmEzHDj6xgd8Hn0JoughDaxeQCV66NC2obqPnPp4+68G/qZnxkXVXdFyqVodu4FgPUjiqcJjft7bh45BVgLFpOqSqDQ3ko30B7gdGfIIkoBj/8gz3tHnmIvl3MywtOhDeGnlLNzBY52wVmhPIdKOaW/7WkMrXKFCkLkNICGnIpWuyBtC+7RfM8hG6eRW1KCm5xrkRmn5ptonjxix/JTGj4me/NMkwdVkz6wcCSAJnqTgHi2oqk73qqNu0LHsEMFBF8IGqmVkn2MOHkFamPBokzQ6HXXfvR4nbcWQZCUgRinPTVg9CF0B6XSCEMCSH5kveZxTQtAFRB6NosbzuU5jDmJgpbDfauev7Eg/6bZzphcugRkVuwulymzsake5Jbvs9Kyw3CNPYH2G3Kli1FNhfc46ugXHbIfXgNQcou3xabcu+r6cFRqqK6NmV9ouMQRj8Ri95Gp2BUlpTEFhcvMb9d4nXAgMBAAGjWjBYMA4GA1UdDwEB/wQEAwICBDATBgNVHSUEDDAKBggrBgEFBQcDAzASBgNVHRMBAf8ECDAGAQH/AgEBMB0GA1UdDgQWBBS5FZjt9UsEPkcKrStrnjSpTq4kDTANBgkqhkiG9w0BAQsFAAOCAYEAKtxfv12LzM85bxOMp5++pIDa6eMcBaurYbAM2yC9B6LuHf0JGeFdNqt4Fw38Ajooj2vWMWBrARVEZRVqTC5+ZSN2meGBXBXlT4n8FdEdmv+05iwVYdmDFp8FKeoOZZZF23u+r2OrazJo1ufWmoSI2P0lEfZQQFQElltWu3QH+OLOWXJmB7KbLKyheelGK5XhtAYYapRdW4sKJ398ybpv5C1oALCcTwoSmvH8wW5J4/gjmhKICYh2goMauf0lesdxj+0His7E8blOWrUmfOB5dp73XawLKcd/UxHN8zAPC08LDL9NMcihn3ZHKi7/dtkiV2iSaDPD1ChSGdqfXIysYqOhYoktgAfBZ43CWnqQhgB8NezRKdOStYC3P2AGJW18irxxTRp2CO+gnXEcyhyr+cvyf0j8MkRSaHLXzjIrECu8BUitB6sKughdN13fs5t5SIiO6foeFdvIpZFFKO8s+4oTOSDCos2WFoC+8TZS6r583OtFLmywl1HRgQkobGgw" + ], + "io.cncf.notary.SigningAgent": "Notation/1.0.0" + }, + "signature": "nDpYiwd536V2krjmxH2FCk6QgUTRyA6AFL9D5sDBJ3JwS9q9znsefSIg9rz6PMskVO9GUzUSG0ZIna5izrVR9pctLw4yQrWIZz3fp-lc3orK4w1nmHG_pCdpasH4FxpvXa0-4dllJmX2Yc3GrdeFaxJhcgtr2iiArabKnOFh5DbfOpeyMGDEa2XVRnrcS4VRgc5UdewFkq2NslMw1Y9loQwrNr3JGTQQpvZHOR4yBtnfCWFJ7G8AYDUb4H1Us8iaIlyp-jSIVSOT9HQzizDzZgn-Gtv90pq9xqAEtrW4thkPUOOJP_P0-_huAH3475UEPi-Yc7ekyt7PH6PazyI9yuTsJlkM_eWDsNLDARRfgygzr9DJHPkYQG3S8MRfNGqskob6Lcfl8nPaXnTfAhLNl-JiWvzMpwq1af2sWek-NVcGf5-81hRF9GTCE1IAtjQ0ITR86zq_G8pEj4JfI-H0c0yXTDUilUHzwzXV_7zE0gEB8UFHHg9VHGflYRdbWuS9" +} \ No newline at end of file diff --git a/internal/mock_origin/testdata/sa_invalid_sig_env.json b/internal/mock_origin/testdata/sa_invalid_sig_env.json new file mode 100644 index 00000000..ec86ab8a --- /dev/null +++ b/internal/mock_origin/testdata/sa_invalid_sig_env.json @@ -0,0 +1,12 @@ +{ + "payload": "eyJ0YXJnZXRBcnRpZmFjdCI6eyJtZWRpYVR5cGUiOiJhcHBsaWNhdGlvbi92bmQuZG9ja2VyLmRpc3RyaWJ1dGlvbi5tYW5pZmVzdC52Mitqc29uIiwiZGlnZXN0Ijoic2hhMjU2OjYwMDQzY2Y0NWVhZWJjNGMwODY3ZmVhNDg1YTAzOWI1OThmNTJmZDA5ZmQ1YjA3YjBiMmQyZjg4ZmFkOWQ3NGUiLCJzaXplIjo1Mjh9fQ=", + "protected": "eyJhbGciOiJQUzM4NCIsImNyaXQiOlsiaW8uY25jZi5ub3Rhcnkuc2lnbmluZ1NjaGVtZSIsImlvLmNuY2Yubm90YXJ5LmF1dGhlbnRpY1NpZ25pbmdUaW1lIiwiaW8uY25jZi5ub3RhcnkuZXhwaXJ5Il0sImN0eSI6ImFwcGxpY2F0aW9uL3ZuZC5jbmNmLm5vdGFyeS5wYXlsb2FkLnYxK2pzb24iLCJpby5jbmNmLm5vdGFyeS5hdXRoZW50aWNTaWduaW5nVGltZSI6IjIwMjAtMTEtMDlUMDc6MDA6MDBaIiwiaW8uY25jZi5ub3RhcnkuZXhwaXJ5IjoiMjEyMC0xMS0wOVQwNzowMDowMFoiLCJpby5jbmNmLm5vdGFyeS5zaWduaW5nU2NoZW1lIjoibm90YXJ5Lng1MDkuc2lnbmluZ0F1dGhvcml0eSJ9", + "header": { + "x5c": [ + "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" + ], + "io.cncf.notary.SigningAgent": "Notation/1.0.0" + }, + "signature": "kqt4plYZgCdPkoVmC-1_JfH7dPUjIQOMaONP6pEucnKC1QiTa7peN83Ka8_0kAvAT3BIZ8CFjVuazioZpjHw-ydRlL3-pgagnENS8Fz2Vfwj9nKJF7mmFGi3R0t6fFFyx_Tw9rtxi4Nsv8y4k-2XLFLeSm1_EEDThHPVMbWE6XJpOIdvr2w3Iq1PsEOVo9QqVOd3FYcGLQAbiAAi_jREYpEKImFqQeY8noUCDOtULPwxbslrglOOBtKouI4OUT0ZtG3tDCBdoZUOAfNgKSlHQutlA0-G6GdBuytCz0ku45DTnGAPS11WwsuPBJfouYlusJuZHmqJTodwEnu2B2AZpLu5wxRUwWOpSyc8ftnSBkiHJWIT3bwatPjlaHoIgwcEsGPRwvFCq7V7yH2yW2uHI1FsiMUHYuWx-hDpLf4Nzag5oc-PyaV3lzsvZZHwy43ilFO-WJOZeDQCWjIZ_U1f4hGsoDkqvoRn-aFZ-pE7Nn99buVRHDjQ6-8-jfJncJaB" +} diff --git a/internal/mock_origin/testdata/sa_plugin_sig_env.json b/internal/mock_origin/testdata/sa_plugin_sig_env.json new file mode 100644 index 00000000..966082a8 --- /dev/null +++ b/internal/mock_origin/testdata/sa_plugin_sig_env.json @@ -0,0 +1,12 @@ +{ + "payload": "eyJ0YXJnZXRBcnRpZmFjdCI6eyJtZWRpYVR5cGUiOiJhcHBsaWNhdGlvbi92bmQuZG9ja2VyLmRpc3RyaWJ1dGlvbi5tYW5pZmVzdC52Mitqc29uIiwiZGlnZXN0Ijoic2hhMjU2OjYwMDQzY2Y0NWVhZWJjNGMwODY3ZmVhNDg1YTAzOWI1OThmNTJmZDA5ZmQ1YjA3YjBiMmQyZjg4ZmFkOWQ3NGUiLCJzaXplIjo1Mjh9fQ", + "protected": "eyJTb21lS2V5IjoiU29tZVZhbHVlIiwiYWxnIjoiUFMzODQiLCJjcml0IjpbImlvLmNuY2Yubm90YXJ5LnNpZ25pbmdTY2hlbWUiLCJTb21lS2V5IiwiaW8uY25jZi5ub3RhcnkuYXV0aGVudGljU2lnbmluZ1RpbWUiLCJpby5jbmNmLm5vdGFyeS5leHBpcnkiLCJpby5jbmNmLm5vdGFyeS52ZXJpZmljYXRpb25QbHVnaW4iXSwiY3R5IjoiYXBwbGljYXRpb24vdm5kLmNuY2Yubm90YXJ5LnBheWxvYWQudjEranNvbiIsImlvLmNuY2Yubm90YXJ5LmF1dGhlbnRpY1NpZ25pbmdUaW1lIjoiMjAyMC0xMS0wOVQwNzowMDowMFoiLCJpby5jbmNmLm5vdGFyeS5leHBpcnkiOiIyMTIwLTExLTA5VDA3OjAwOjAwWiIsImlvLmNuY2Yubm90YXJ5LnNpZ25pbmdTY2hlbWUiOiJub3RhcnkueDUwOS5zaWduaW5nQXV0aG9yaXR5IiwiaW8uY25jZi5ub3RhcnkudmVyaWZpY2F0aW9uUGx1Z2luIjoicGx1Z2luLW5hbWUifQ", + "header": { + "x5c": [ + "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" + ], + "io.cncf.notary.SigningAgent": "Notation/1.0.0" + }, + "signature": "DwrGzND2JgpkeFASatpp-kBKpgrlt1Io3fbetSB3VUnRb0zWkj3vreKzAFpNBI6MN0lTuIWA3_igTqkYcFq8VFW2VSvWGidARJnzd4WDrCFp7n-Qp9TQPqbkLknZUxT2pFsTw1EF_plyAdJmRwbJikwvc2RkxW1Bz6fAcagJEul4lm6j2Yq4iTE8xThjn1ih7_9XMQ9I1f79CK3CTdu9jCrlQbyC1wEI9btyx-91OJ2V1oeGVtasNvRhA1ttVS3h7EQvzcJ9eKdEHPCVK6j5X7xvbjz40Z2kouZAb3ve9jsYZquMx6krrwAh4JPwUDJGT2x6ujdIIU6QioJgbOqRLdyYYERHqhO3P3FAsIJqIwtupMkcSJZJrMlzdi_nuHPHvy9ToQTW5z98LSQHqHtmWf4JdfVGq5iOWwrwLO4QINi716wcqiVp8srd2VdpoxvA5nnT2zzukzSXXVFj3V7XcqWutQoM3ihfw-aWDLU_OBo7aaSLaZUXhYkLsB3pHX1G" +} diff --git a/internal/mock_origin/testdata/sa_valid_sig_env.json b/internal/mock_origin/testdata/sa_valid_sig_env.json new file mode 100644 index 00000000..e1d49a6c --- /dev/null +++ b/internal/mock_origin/testdata/sa_valid_sig_env.json @@ -0,0 +1,12 @@ +{ + "payload": "eyJ0YXJnZXRBcnRpZmFjdCI6eyJtZWRpYVR5cGUiOiJhcHBsaWNhdGlvbi92bmQuZG9ja2VyLmRpc3RyaWJ1dGlvbi5tYW5pZmVzdC52Mitqc29uIiwiZGlnZXN0Ijoic2hhMjU2OjYwMDQzY2Y0NWVhZWJjNGMwODY3ZmVhNDg1YTAzOWI1OThmNTJmZDA5ZmQ1YjA3YjBiMmQyZjg4ZmFkOWQ3NGUiLCJzaXplIjo1Mjh9fQ", + "protected": "eyJhbGciOiJQUzM4NCIsImNyaXQiOlsiaW8uY25jZi5ub3Rhcnkuc2lnbmluZ1NjaGVtZSIsImlvLmNuY2Yubm90YXJ5LmF1dGhlbnRpY1NpZ25pbmdUaW1lIiwiaW8uY25jZi5ub3RhcnkuZXhwaXJ5Il0sImN0eSI6ImFwcGxpY2F0aW9uL3ZuZC5jbmNmLm5vdGFyeS5wYXlsb2FkLnYxK2pzb24iLCJpby5jbmNmLm5vdGFyeS5hdXRoZW50aWNTaWduaW5nVGltZSI6IjIwMjAtMTEtMDlUMDc6MDA6MDBaIiwiaW8uY25jZi5ub3RhcnkuZXhwaXJ5IjoiMjEyMC0xMS0wOVQwNzowMDowMFoiLCJpby5jbmNmLm5vdGFyeS5zaWduaW5nU2NoZW1lIjoibm90YXJ5Lng1MDkuc2lnbmluZ0F1dGhvcml0eSJ9", + "header": { + "x5c": [ + "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" + ], + "io.cncf.notary.SigningAgent": "Notation/1.0.0" + }, + "signature": "kqt4plYZgCdPkoVmC-1_JfH7dPUjIQOMaONP6pEucnKC1QiTa7peN83Ka8_0kAvAT3BIZ8CFjVuazioZpjHw-ydRlL3-pgagnENS8Fz2Vfwj9nKJF7mmFGi3R0t6fFFyx_Tw9rtxi4Nsv8y4k-2XLFLeSm1_EEDThHPVMbWE6XJpOIdvr2w3Iq1PsEOVo9QqVOd3FYcGLQAbiAAi_jREYpEKImFqQeY8noUCDOtULPwxbslrglOOBtKouI4OUT0ZtG3tDCBdoZUOAfNgKSlHQutlA0-G6GdBuytCz0ku45DTnGAPS11WwsuPBJfouYlusJuZHmqJTodwEnu2B2AZpLu5wxRUwWOpSyc8ftnSBkiHJWIT3bwatPjlaHoIgwcEsGPRwvFCq7V7yH2yW2uHI1FsiMUHYuWx-hDpLf4Nzag5oc-PyaV3lzsvZZHwy43ilFO-WJOZeDQCWjIZ_U1f4hGsoDkqvoRn-aFZ-pE7Nn99buVRHDjQ6-8-jfJncJaB" +} diff --git a/internal/notation.go b/internal/notation.go new file mode 100644 index 00000000..18665f1b --- /dev/null +++ b/internal/notation.go @@ -0,0 +1,93 @@ +package notation + +import ( + "context" + "crypto/x509" + "time" + + "github.com/notaryproject/notation-core-go/timestamp" + "github.com/opencontainers/go-digest" +) + +// MediaTypePayloadV1 is the supported content type for signature's payload. +const MediaTypePayloadV1 = "application/vnd.cncf.notary.payload.v1+json" + +// SigningAgent is the unprotected header field used by signature. +var SigningAgent = "Notation/1.0.0" + +// Descriptor describes the artifact that needs to be signed. +type Descriptor struct { + // The media type of the targeted content. + MediaType string `json:"mediaType"` + + // The digest of the targeted content. + Digest digest.Digest `json:"digest"` + + // Specifies the size in bytes of the blob. + Size int64 `json:"size"` + + // Contains optional user defined attributes. + Annotations map[string]string `json:"annotations,omitempty"` +} + +// Equal reports whether d and t points to the same content. +func (d Descriptor) Equal(t Descriptor) bool { + return d.MediaType == t.MediaType && d.Digest == t.Digest && d.Size == t.Size +} + +// Payload describes the content that gets signed. +type Payload struct { + TargetArtifact Descriptor `json:"targetArtifact"` +} + +// SignOptions contains parameters for Signer.Sign. +type SignOptions struct { + // Expiry identifies the expiration time of the resulted signature. + Expiry time.Time + + // TSA is the TimeStamp Authority to timestamp the resulted signature if present. + TSA timestamp.Timestamper + + // TSAVerifyOptions is the verify option to verify the fetched timestamp signature. + // The `Intermediates` in the verify options will be ignored and re-contrusted using + // the certificates in the fetched timestamp signature. + // An empty list of `KeyUsages` in the verify options implies ExtKeyUsageTimeStamping. + TSAVerifyOptions x509.VerifyOptions + + // Sets or overrides the plugin configuration. + PluginConfig map[string]string +} + +// Signer is a generic interface for signing an artifact. +// The interface allows signing with local or remote keys, +// and packing in various signature formats. +type Signer interface { + // Sign signs the artifact described by its descriptor, + // and returns the signature. + Sign(ctx context.Context, desc Descriptor, opts SignOptions) ([]byte, error) +} + +// VerifyOptions contains parameters for Verifier.Verify. +type VerifyOptions struct { + // SignatureMediaType is the envelope type of the signature. + // Currently both `application/jose+json` and `application/cose` are supported. + SignatureMediaType string +} + +// Validate does basic validation on VerifyOptions. +func (opts VerifyOptions) Validate() error { + return nil +} + +// Verifier is a generic interface for verifying an artifact. +type Verifier interface { + // Verify verifies the signature and returns the verified descriptor and + // metadata of the signed artifact. + Verify(ctx context.Context, signature []byte, opts VerifyOptions) (Descriptor, error) +} + +// Service combines the signing and verification services. +type Service interface { + Signer + Verifier +} diff --git a/internal/registry/interface.go b/internal/registry/interface.go index e8e621bc..6d683146 100644 --- a/internal/registry/interface.go +++ b/internal/registry/interface.go @@ -3,7 +3,7 @@ package registry import ( "context" - "github.com/notaryproject/notation-go" + notation "github.com/notaryproject/notation-go/internal" "github.com/opencontainers/go-digest" ) diff --git a/internal/registry/repository.go b/internal/registry/repository.go index 7efb4f5a..1ae51c68 100644 --- a/internal/registry/repository.go +++ b/internal/registry/repository.go @@ -6,7 +6,7 @@ import ( "encoding/json" "fmt" - "github.com/notaryproject/notation-go" + notation "github.com/notaryproject/notation-go/internal" "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" artifactspec "github.com/oras-project/artifacts-spec/specs-go/v1" diff --git a/notation.go b/notation.go index 18665f1b..43637179 100644 --- a/notation.go +++ b/notation.go @@ -2,57 +2,39 @@ package notation import ( "context" - "crypto/x509" + "crypto/sha256" + "encoding/hex" + "encoding/json" + "errors" + "fmt" + "reflect" "time" - "github.com/notaryproject/notation-core-go/timestamp" - "github.com/opencontainers/go-digest" + "github.com/notaryproject/notation-core-go/signature" + "github.com/notaryproject/notation-go/registry" + "github.com/notaryproject/notation-go/verification/trustpolicy" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "oras.land/oras-go/v2/content" ) -// MediaTypePayloadV1 is the supported content type for signature's payload. -const MediaTypePayloadV1 = "application/vnd.cncf.notary.payload.v1+json" +const annotationX509ChainThumbprint = "io.cncf.notary.x509chain.thumbprint#S256" -// SigningAgent is the unprotected header field used by signature. -var SigningAgent = "Notation/1.0.0" +const maxVerificationLimitDefault = 50 -// Descriptor describes the artifact that needs to be signed. -type Descriptor struct { - // The media type of the targeted content. - MediaType string `json:"mediaType"` - - // The digest of the targeted content. - Digest digest.Digest `json:"digest"` - - // Specifies the size in bytes of the blob. - Size int64 `json:"size"` - - // Contains optional user defined attributes. - Annotations map[string]string `json:"annotations,omitempty"` -} - -// Equal reports whether d and t points to the same content. -func (d Descriptor) Equal(t Descriptor) bool { - return d.MediaType == t.MediaType && d.Digest == t.Digest && d.Size == t.Size -} - -// Payload describes the content that gets signed. -type Payload struct { - TargetArtifact Descriptor `json:"targetArtifact"` -} +var errDoneVerification = errors.New("done verification") // SignOptions contains parameters for Signer.Sign. type SignOptions struct { - // Expiry identifies the expiration time of the resulted signature. - Expiry time.Time + // Reference of the artifact that needs to be signed. + ArtifactReference string - // TSA is the TimeStamp Authority to timestamp the resulted signature if present. - TSA timestamp.Timestamper + // SignatureMediaType is the envelope type of the signature. + // Currently both `application/jose+json` and `application/cose` are + // supported. + SignatureMediaType string - // TSAVerifyOptions is the verify option to verify the fetched timestamp signature. - // The `Intermediates` in the verify options will be ignored and re-contrusted using - // the certificates in the fetched timestamp signature. - // An empty list of `KeyUsages` in the verify options implies ExtKeyUsageTimeStamping. - TSAVerifyOptions x509.VerifyOptions + // Expiry identifies the expiration time of the resulted signature. + Expiry time.Time // Sets or overrides the plugin configuration. PluginConfig map[string]string @@ -63,31 +45,207 @@ type SignOptions struct { // and packing in various signature formats. type Signer interface { // Sign signs the artifact described by its descriptor, - // and returns the signature. - Sign(ctx context.Context, desc Descriptor, opts SignOptions) ([]byte, error) + // and returns the signature and SignerInfo. + Sign(ctx context.Context, desc ocispec.Descriptor, envelopeMediaType string, opts SignOptions) ([]byte, *signature.SignerInfo, error) +} + +// Sign signs the artifact in the remote registry and push the signature to the +// remote. +// The descriptor of the sign content is returned upon sucessful signing. +func Sign(ctx context.Context, signer Signer, repo registry.Repository, opts SignOptions) (ocispec.Descriptor, error) { + targetDesc, err := repo.Resolve(ctx, opts.ArtifactReference) + if err != nil { + return ocispec.Descriptor{}, err + } + sig, signerInfo, err := signer.Sign(ctx, targetDesc, opts.SignatureMediaType, opts) + if err != nil { + return ocispec.Descriptor{}, err + } + annotations, err := generateAnnotations(signerInfo) + if err != nil { + return ocispec.Descriptor{}, err + } + _, _, err = repo.PushSignature(ctx, opts.SignatureMediaType, sig, targetDesc, annotations) + if err != nil { + return ocispec.Descriptor{}, err + } + + return targetDesc, nil } // VerifyOptions contains parameters for Verifier.Verify. type VerifyOptions struct { + // ArtifactReference is the reference of the artifact that is been + // verified against to. + ArtifactReference string + // SignatureMediaType is the envelope type of the signature. - // Currently both `application/jose+json` and `application/cose` are supported. + // Currently both `application/jose+json` and `application/cose` are + // supported. SignatureMediaType string + + // PluginConfig is a map of plugin configs. + PluginConfig map[string]string + + // MaxSignatureAttempts is the maximum number of signature envelopes that + // can be associated with the target artifact. If set to less than or equals + // to zero, value defaults to 50. + // Note: this option is scoped to notation.Verify(). verifier.Verify() is + // for signle signature verification, and therefore, does not use it. + MaxSignatureAttempts int } -// Validate does basic validation on VerifyOptions. -func (opts VerifyOptions) Validate() error { - return nil +// ValidationResult encapsulates the verification result (passed or failed) +// for a verification type, including the desired verification action as +// specified in the trust policy +type ValidationResult struct { + // Type of verification that is performed + Type trustpolicy.ValidationType + + // Action is the intended action for the given verification type as defined + // in the trust policy + Action trustpolicy.ValidationAction + + // Error is set if there are any errors during the verification process + Error error +} + +// VerificationOutcome encapsulates a signature blob's descriptor, its content, +// the verification level and results for each verification type that was +// performed. +type VerificationOutcome struct { + // RawSignature is the signature envelope blob + RawSignature []byte + + // EnvelopeContent contains the details of the digital signature and + // associated metadata + EnvelopeContent *signature.EnvelopeContent + + // VerificationLevel describes what verification level was used for + // performing signature verification + VerificationLevel *trustpolicy.VerificationLevel + + // VerificationResults contains the verifications performed on the signature + // and their results + VerificationResults []*ValidationResult + + // Error that caused the verification to fail (if it fails) + Error error } // Verifier is a generic interface for verifying an artifact. type Verifier interface { - // Verify verifies the signature and returns the verified descriptor and - // metadata of the signed artifact. - Verify(ctx context.Context, signature []byte, opts VerifyOptions) (Descriptor, error) + // Verify verifies the signature blob and returns the artifact + // descriptor upon successful verification. + // If nil signature is present and the verification level is not 'skip', + // an error will be returned. + Verify(ctx context.Context, signature []byte, opts VerifyOptions) (ocispec.Descriptor, *VerificationOutcome, error) +} + +// Verify performs signature verification on each of the notation supported +// verification types (like integrity, authenticity, etc.) and return the +// verification outcomes. +// For more details on signature verification, see +// https://github.com/notaryproject/notaryproject/blob/main/specs/trust-store-trust-policy.md#signature-verification +func Verify(ctx context.Context, verifier Verifier, repo registry.Repository, opts VerifyOptions) (ocispec.Descriptor, []*VerificationOutcome, error) { + // passing nil signature to check 'skip' + _, outcome, err := verifier.Verify(ctx, nil, opts) + if err != nil { + if outcome == nil { + return ocispec.Descriptor{}, nil, err + } + } else if reflect.DeepEqual(outcome.VerificationLevel, trustpolicy.LevelSkip) { + return ocispec.Descriptor{}, []*VerificationOutcome{outcome}, nil + } + // get signature manifests + artifactRef := opts.ArtifactReference + artifactDescriptor, err := repo.Resolve(ctx, artifactRef) + if err != nil { + return ocispec.Descriptor{}, nil, ErrorSignatureRetrievalFailed{Msg: err.Error()} + } + + var verificationOutcomes []*VerificationOutcome + var targetArtifactDesc ocispec.Descriptor + if opts.MaxSignatureAttempts <= 0 { + // Set MaxVerificationLimit to 50 as default + opts.MaxSignatureAttempts = maxVerificationLimitDefault + } + errExceededMaxVerificationLimit := ErrorVerificationFailed{Msg: fmt.Sprintf("total number of signatures associated with an artifact should be less than: %d", opts.MaxSignatureAttempts)} + count := 0 + err = repo.ListSignatures(ctx, artifactDescriptor, func(signatureManifests []ocispec.Descriptor) error { + // process signatures + for _, sigManifestDesc := range signatureManifests { + if count >= opts.MaxSignatureAttempts { + break + } + count++ + // get signature envelope + sigBlob, _, err := repo.FetchSignatureBlob(ctx, sigManifestDesc) + if err != nil { + return ErrorSignatureRetrievalFailed{Msg: fmt.Sprintf("unable to retrieve digital signature with digest %q associated with %q from the registry, error : %v", sigManifestDesc.Digest, artifactRef, err.Error())} + } + payloadArtifactDescriptor, outcome, err := verifier.Verify(ctx, sigBlob, opts) + if err != nil { + if outcome == nil { + // TODO: log fatal error + return err + } + verificationOutcomes = append(verificationOutcomes, outcome) + continue + } + if !content.Equal(payloadArtifactDescriptor, artifactDescriptor) { + outcome.Error = errors.New("content descriptor mismatch") + verificationOutcomes = append(verificationOutcomes, outcome) + continue + } + + // At this point, we've found a signature verified successfully + verificationOutcomes = append(verificationOutcomes, outcome) + // Descriptor of the signature blob that gets verified successfully + targetArtifactDesc = payloadArtifactDescriptor + + return errDoneVerification + } + + if count >= opts.MaxSignatureAttempts { + return errExceededMaxVerificationLimit + } + + return nil + }) + + if err != nil && !errors.Is(err, errDoneVerification) { + if errors.Is(err, errExceededMaxVerificationLimit) { + return ocispec.Descriptor{}, verificationOutcomes, err + } + return ocispec.Descriptor{}, nil, err + } + + // If there's no signature associated with the reference + if len(verificationOutcomes) == 0 { + return ocispec.Descriptor{}, nil, ErrorSignatureRetrievalFailed{Msg: fmt.Sprintf("no signature is associated with %q, make sure the image was signed successfully", artifactRef)} + } + + // check whether verification was successful or not + if verificationOutcomes[len(verificationOutcomes)-1].Error != nil { + return ocispec.Descriptor{}, verificationOutcomes, ErrorVerificationFailed{} + } + + return targetArtifactDesc, verificationOutcomes, nil } -// Service combines the signing and verification services. -type Service interface { - Signer - Verifier +func generateAnnotations(signerInfo *signature.SignerInfo) (map[string]string, error) { + var thumbprints []string + for _, cert := range signerInfo.CertificateChain { + checkSum := sha256.Sum256(cert.Raw) + thumbprints = append(thumbprints, hex.EncodeToString(checkSum[:])) + } + val, err := json.Marshal(thumbprints) + if err != nil { + return nil, err + } + + return map[string]string{ + annotationX509ChainThumbprint: string(val), + }, nil } diff --git a/notation_test.go b/notation_test.go new file mode 100644 index 00000000..ddedfed5 --- /dev/null +++ b/notation_test.go @@ -0,0 +1,126 @@ +package notation + +import ( + "context" + "errors" + "fmt" + "testing" + + "github.com/notaryproject/notation-go/internal/mock" + "github.com/notaryproject/notation-go/internal/plugin" + "github.com/notaryproject/notation-go/internal/plugin/manager" + "github.com/notaryproject/notation-go/verification/trustpolicy" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" +) + +func TestRegistryResolveError(t *testing.T) { + policyDocument := dummyPolicyDocument() + repo := mock.NewRepository() + verifier := dummyVerifier{&policyDocument, mock.PluginManager{}, false, *trustpolicy.LevelStrict} + + errorMessage := "network error" + expectedErr := ErrorSignatureRetrievalFailed{Msg: errorMessage} + + // mock the repository + repo.ResolveError = errors.New(errorMessage) + opts := VerifyOptions{ArtifactReference: mock.SampleArtifactUri} + _, _, err := Verify(context.Background(), &verifier, repo, opts) + + if err == nil || !errors.Is(err, expectedErr) { + t.Fatalf("RegistryResolve expected: %v got: %v", expectedErr, err) + } +} + +func TestSkippedSignatureVerification(t *testing.T) { + policyDocument := dummyPolicyDocument() + repo := mock.NewRepository() + verifier := dummyVerifier{&policyDocument, mock.PluginManager{}, false, *trustpolicy.LevelSkip} + + opts := VerifyOptions{ArtifactReference: mock.SampleArtifactUri} + _, outcomes, err := Verify(context.Background(), &verifier, repo, opts) + + if err != nil || outcomes[0].VerificationLevel.Name != trustpolicy.LevelSkip.Name { + t.Fatalf("\"skip\" verification level must pass overall signature verification") + } +} + +func TestRegistryNoSignatureManifests(t *testing.T) { + policyDocument := dummyPolicyDocument() + repo := mock.NewRepository() + verifier := dummyVerifier{&policyDocument, mock.PluginManager{}, false, *trustpolicy.LevelStrict} + errorMessage := fmt.Sprintf("no signature is associated with %q, make sure the image was signed successfully", mock.SampleArtifactUri) + expectedErr := ErrorSignatureRetrievalFailed{Msg: errorMessage} + + // mock the repository + repo.ListSignaturesResponse = []ocispec.Descriptor{} + opts := VerifyOptions{ArtifactReference: mock.SampleArtifactUri} + _, _, err := Verify(context.Background(), &verifier, repo, opts) + + if err == nil || !errors.Is(err, expectedErr) { + t.Fatalf("RegistryNoSignatureManifests expected: %v got: %v", expectedErr, err) + } +} + +func TestRegistryFetchSignatureBlobError(t *testing.T) { + policyDocument := dummyPolicyDocument() + repo := mock.NewRepository() + verifier := dummyVerifier{&policyDocument, mock.PluginManager{}, false, *trustpolicy.LevelStrict} + errorMessage := fmt.Sprintf("unable to retrieve digital signature with digest %q associated with %q from the registry, error : network error", mock.SampleDigest, mock.SampleArtifactUri) + expectedErr := ErrorSignatureRetrievalFailed{Msg: errorMessage} + + // mock the repository + repo.FetchSignatureBlobError = errors.New("network error") + opts := VerifyOptions{ArtifactReference: mock.SampleArtifactUri} + _, _, err := Verify(context.Background(), &verifier, repo, opts) + + if err == nil || !errors.Is(err, expectedErr) { + t.Fatalf("RegistryGetBlob expected: %v got: %v", expectedErr, err) + } +} + +func dummyPolicyDocument() (policyDoc trustpolicy.Document) { + policyDoc = trustpolicy.Document{ + Version: "1.0", + TrustPolicies: []trustpolicy.TrustPolicy{dummyPolicyStatement()}, + } + return +} + +func dummyPolicyStatement() (policyStatement trustpolicy.TrustPolicy) { + policyStatement = trustpolicy.TrustPolicy{ + Name: "test-statement-name", + RegistryScopes: []string{"registry.acme-rockets.io/software/net-monitor"}, + SignatureVerification: trustpolicy.SignatureVerification{VerificationLevel: "strict"}, + TrustStores: []string{"ca:valid-trust-store", "signingAuthority:valid-trust-store"}, + TrustedIdentities: []string{"x509.subject:CN=Notation Test Root,O=Notary,L=Seattle,ST=WA,C=US"}, + } + return +} + +type dummyVerifier struct { + TrustPolicyDoc *trustpolicy.Document + PluginManager pluginManager + FailVerify bool + VerificationLevel trustpolicy.VerificationLevel +} + +func (v *dummyVerifier) Verify(ctx context.Context, signature []byte, opts VerifyOptions) (ocispec.Descriptor, *VerificationOutcome, error) { + if v.FailVerify { + return ocispec.Descriptor{}, nil, errors.New("failed verify") + } + outcome := &VerificationOutcome{ + VerificationResults: []*ValidationResult{}, + VerificationLevel: &v.VerificationLevel, + } + return ocispec.Descriptor{}, outcome, nil +} + +func (v *dummyVerifier) TrustPolicyDocument() (*trustpolicy.Document, error) { + return v.TrustPolicyDoc, nil +} + +// pluginManager is for mocking in unit tests +type pluginManager interface { + Get(ctx context.Context, name string) (*manager.Plugin, error) + Runner(name string) (plugin.Runner, error) +} diff --git a/registry/interface.go b/registry/interface.go index 9fb4452d..b185d5df 100644 --- a/registry/interface.go +++ b/registry/interface.go @@ -23,5 +23,5 @@ type Repository interface { // PushSignature creates and uploads an signature manifest along with its // linked signature envelope blob. - PushSignature(ctx context.Context, blob []byte, mediaType string, subject ocispec.Descriptor, annotations map[string]string) (blobDesc, manifestDesc ocispec.Descriptor, err error) + PushSignature(ctx context.Context, mediaType string, blob []byte, subject ocispec.Descriptor, annotations map[string]string) (blobDesc, manifestDesc ocispec.Descriptor, err error) } diff --git a/registry/repository.go b/registry/repository.go index a153060b..b39e8c7d 100644 --- a/registry/repository.go +++ b/registry/repository.go @@ -70,7 +70,7 @@ func (c *repositoryClient) FetchSignatureBlob(ctx context.Context, desc ocispec. // PushSignature creates and uploads an signature manifest along with its // linked signature envelope blob. Upon successful, PushSignature returns // signature envelope blob and manifest descriptors. -func (c *repositoryClient) PushSignature(ctx context.Context, blob []byte, mediaType string, subject ocispec.Descriptor, annotations map[string]string) (blobDesc, manifestDesc ocispec.Descriptor, err error) { +func (c *repositoryClient) PushSignature(ctx context.Context, mediaType string, blob []byte, subject ocispec.Descriptor, annotations map[string]string) (blobDesc, manifestDesc ocispec.Descriptor, err error) { blobDesc, err = oras.PushBytes(ctx, c.Repository.Blobs(), mediaType, blob) if err != nil { return ocispec.Descriptor{}, ocispec.Descriptor{}, err diff --git a/registry/repository_test.go b/registry/repository_test.go index 71100909..71062bb7 100644 --- a/registry/repository_test.go +++ b/registry/repository_test.go @@ -461,7 +461,7 @@ func TestPushSignature(t *testing.T) { ref, _ := registry.ParseReference(args.reference) client := newRepositoryClient(args.remoteClient, ref, args.plainHttp) - des, _, err := client.PushSignature(args.ctx, args.signature, args.signatureMediaType, args.subjectManifest, args.annotations) + des, _, err := client.PushSignature(args.ctx, args.signatureMediaType, args.signature, args.subjectManifest, args.annotations) if (err != nil) != tt.expectErr { t.Errorf("error = %v, expectErr = %v", err, tt.expectErr) } diff --git a/signature/envelope.go b/signature/envelope.go index 88fa9914..ba3e9dfe 100644 --- a/signature/envelope.go +++ b/signature/envelope.go @@ -5,7 +5,7 @@ import ( "fmt" "github.com/notaryproject/notation-core-go/signature" - "github.com/notaryproject/notation-go" + notation "github.com/notaryproject/notation-go/internal" ) // ValidateEnvelopeMediaType validetes envelope media type is supported by notation-core-go. diff --git a/signature/envelope_test.go b/signature/envelope_test.go index 2bf672b1..488f4ab2 100644 --- a/signature/envelope_test.go +++ b/signature/envelope_test.go @@ -7,7 +7,7 @@ import ( "github.com/notaryproject/notation-core-go/signature" "github.com/notaryproject/notation-core-go/signature/cose" "github.com/notaryproject/notation-core-go/signature/jws" - "github.com/notaryproject/notation-go" + notation "github.com/notaryproject/notation-go/internal" gcose "github.com/veraison/go-cose" ) diff --git a/signature/plugin.go b/signature/plugin.go index f0dca93d..bcf83a84 100644 --- a/signature/plugin.go +++ b/signature/plugin.go @@ -9,7 +9,7 @@ import ( "time" "github.com/notaryproject/notation-core-go/signature" - "github.com/notaryproject/notation-go" + notation "github.com/notaryproject/notation-go/internal" "github.com/notaryproject/notation-go/internal/plugin" ) diff --git a/signature/plugin_test.go b/signature/plugin_test.go index dbbfe588..c8c70e2c 100644 --- a/signature/plugin_test.go +++ b/signature/plugin_test.go @@ -15,7 +15,7 @@ import ( "github.com/notaryproject/notation-core-go/signature" "github.com/notaryproject/notation-core-go/signature/cose" "github.com/notaryproject/notation-core-go/signature/jws" - "github.com/notaryproject/notation-go" + notation "github.com/notaryproject/notation-go/internal" "github.com/notaryproject/notation-go/internal/plugin" gcose "github.com/veraison/go-cose" ) diff --git a/signature/signer.go b/signature/signer.go index 9fa2ce7e..40537c2d 100644 --- a/signature/signer.go +++ b/signature/signer.go @@ -7,7 +7,7 @@ import ( "errors" "fmt" - "github.com/notaryproject/notation-go" + notation "github.com/notaryproject/notation-go/internal" ) // NewSignerFromFiles creates a signer from key, certificate files diff --git a/signature/signer_test.go b/signature/signer_test.go index 81fb916e..13b635ff 100644 --- a/signature/signer_test.go +++ b/signature/signer_test.go @@ -19,7 +19,7 @@ import ( "github.com/notaryproject/notation-core-go/signature" "github.com/notaryproject/notation-core-go/testhelper" "github.com/notaryproject/notation-core-go/timestamp/timestamptest" - "github.com/notaryproject/notation-go" + notation "github.com/notaryproject/notation-go/internal" "github.com/notaryproject/notation-go/internal/plugin" "github.com/opencontainers/go-digest" ) diff --git a/verification/verifier.go b/verification/verifier.go index dd0c99c9..df9ca4c9 100644 --- a/verification/verifier.go +++ b/verification/verifier.go @@ -5,8 +5,8 @@ import ( "encoding/json" "fmt" - "github.com/notaryproject/notation-go" "github.com/notaryproject/notation-go/dir" + notation "github.com/notaryproject/notation-go/internal" "github.com/notaryproject/notation-go/internal/plugin" "github.com/notaryproject/notation-go/internal/plugin/manager" "github.com/notaryproject/notation-go/internal/registry" diff --git a/verification/verifier_test.go b/verification/verifier_test.go index 83cf4a55..7228e73d 100644 --- a/verification/verifier_test.go +++ b/verification/verifier_test.go @@ -8,9 +8,9 @@ import ( "testing" "github.com/notaryproject/notation-core-go/signature" - "github.com/notaryproject/notation-go" "github.com/notaryproject/notation-go/dir" - "github.com/notaryproject/notation-go/internal/mock" + notation "github.com/notaryproject/notation-go/internal" + mock "github.com/notaryproject/notation-go/internal/mock_origin" "github.com/notaryproject/notation-go/internal/plugin" "github.com/notaryproject/notation-go/internal/plugin/manager" "github.com/notaryproject/notation-go/internal/registry"