diff --git a/README.md b/README.md index 3a5b438cd..93cce5145 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ Is a verification engine as a binary executable and on Kubernetes which enables [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/ratify-project/ratify/badge)](https://api.securityscorecards.dev/projects/github.com/ratify-project/ratify) [![OpenSSF Best Practices](https://www.bestpractices.dev/projects/9334/badge)](https://www.bestpractices.dev/projects/9334) [![Go Reference](https://pkg.go.dev/badge/github.com/deislabs/ratify.svg)](https://pkg.go.dev/github.com/deislabs/ratify) +[![codecov](https://codecov.io/gh/ratify-project/ratify/graph/badge.svg?token=3X0BIPI4VD)](https://codecov.io/gh/ratify-project/ratify) ## Table of Contents diff --git a/charts/ratify/README.md b/charts/ratify/README.md index 135f3ed0e..10ec62582 100644 --- a/charts/ratify/README.md +++ b/charts/ratify/README.md @@ -49,6 +49,7 @@ Values marked `# DEPRECATED` in the `values.yaml` as well as **DEPRECATED** in t | tolerations | Pod tolerations for the Ratify deployment | `[]` | | notationCerts | An array of public certificate/certificate chain used to create inline certstore used by Notation verifier | `` | | cosignKeys | An array of public keys used to create inline key management providers used by Cosign verifier | `[]` | +| notation.enabled | Enables/disables the built-in notation verifier. MUST be set to true for notation verification. | `true` | | cosign.enabled | Enables/disables cosign tag-based signature lookup in ORAS store. MUST be set to true for cosign verification. | `true` | | cosign.scopes | An array of scopes relevant to the single trust policy configured in Cosign verifier. A scope of '*' is a global wildcard character to represent all images apply. | `["*"]` | | cosign.rekorURL | URL string reference to remote rekor server. If not specified, implementation will default to use Rekor public good instance `https://rekor.sigstore.dev`. | `` | diff --git a/cmd/ratify/cmd/cmd_test.go b/cmd/ratify/cmd/cmd_test.go index 9016198ab..f2f1b2850 100644 --- a/cmd/ratify/cmd/cmd_test.go +++ b/cmd/ratify/cmd/cmd_test.go @@ -36,8 +36,8 @@ func TestVerify(t *testing.T) { // TODO: make ratify cli more unit testable // unit test should not have dependency for real image - if !strings.Contains(err.Error(), "plugin not found") { - t.Errorf("error expected") + if !strings.Contains(err.Error(), "PLUGIN_NOT_FOUND") { + t.Fatalf("expected containing: %s, but got: %s", "PLUGIN_NOT_FOUND", err.Error()) } } diff --git a/config/samples/clustered/verifier/config_v1beta1_verifier_notation.yaml b/config/samples/clustered/verifier/config_v1beta1_verifier_notation.yaml index 8da1278ba..4da8453a7 100644 --- a/config/samples/clustered/verifier/config_v1beta1_verifier_notation.yaml +++ b/config/samples/clustered/verifier/config_v1beta1_verifier_notation.yaml @@ -6,10 +6,11 @@ spec: name: notation artifactTypes: application/vnd.cncf.notary.signature parameters: - verificationCertStores: - certs: - - ratify-notation-inline-cert-0 - trustPolicyDoc: + verificationCertStores: + ca: + ca-certs: + - ratify-notation-inline-cert-0 + trustPolicyDoc: version: "1.0" trustPolicies: - name: default @@ -18,6 +19,6 @@ spec: signatureVerification: level: strict trustStores: - - ca:certs + - ca:ca-certs trustedIdentities: - "*" diff --git a/config/samples/clustered/verifier/config_v1beta1_verifier_notation_kmprovider.yaml b/config/samples/clustered/verifier/config_v1beta1_verifier_notation_kmprovider.yaml index 36caa15c3..ea2d24c8e 100644 --- a/config/samples/clustered/verifier/config_v1beta1_verifier_notation_kmprovider.yaml +++ b/config/samples/clustered/verifier/config_v1beta1_verifier_notation_kmprovider.yaml @@ -7,10 +7,9 @@ spec: artifactTypes: application/vnd.cncf.notary.signature parameters: verificationCertStores: - certs: - - kmprovider-akv - certs1: - - kmprovider-akv1 + ca: + ca-certs: + - kmprovider-akv trustPolicyDoc: version: "1.0" trustPolicies: @@ -20,6 +19,6 @@ spec: signatureVerification: level: strict trustStores: - - ca:certs + - ca:ca-certs trustedIdentities: - "*" diff --git a/config/samples/clustered/verifier/config_v1beta1_verifier_notation_specificnskmprovider.yaml b/config/samples/clustered/verifier/config_v1beta1_verifier_notation_specificnskmprovider.yaml index 1920a14fe..8584b9938 100644 --- a/config/samples/clustered/verifier/config_v1beta1_verifier_notation_specificnskmprovider.yaml +++ b/config/samples/clustered/verifier/config_v1beta1_verifier_notation_specificnskmprovider.yaml @@ -6,10 +6,11 @@ spec: name: notation artifactTypes: application/vnd.cncf.notary.signature parameters: - verificationCertStores: - certs: - - default/ratify-notation-inline-cert-0 - trustPolicyDoc: + verificationCertStores: + ca: + ca-certs: + - default/ratify-notation-inline-cert-0 + trustPolicyDoc: version: "1.0" trustPolicies: - name: default @@ -18,6 +19,6 @@ spec: signatureVerification: level: strict trustStores: - - ca:certs + - ca:ca-certs trustedIdentities: - "*" diff --git a/config/samples/namespaced/verifier/config_v1beta1_verifier_notation.yaml b/config/samples/namespaced/verifier/config_v1beta1_verifier_notation.yaml index b3c46c3f1..83f0d72e6 100644 --- a/config/samples/namespaced/verifier/config_v1beta1_verifier_notation.yaml +++ b/config/samples/namespaced/verifier/config_v1beta1_verifier_notation.yaml @@ -6,10 +6,11 @@ spec: name: notation artifactTypes: application/vnd.cncf.notary.signature parameters: - verificationCertStores: - certs: - - default/ratify-notation-inline-cert-0 - trustPolicyDoc: + verificationCertStores: + ca: + ca-certs: + - default/ratify-notation-inline-cert-0 + trustPolicyDoc: version: "1.0" trustPolicies: - name: default @@ -18,6 +19,6 @@ spec: signatureVerification: level: strict trustStores: - - ca:certs + - ca:ca-certs trustedIdentities: - "*" diff --git a/config/samples/namespaced/verifier/config_v1beta1_verifier_notation_kmprovider.yaml b/config/samples/namespaced/verifier/config_v1beta1_verifier_notation_kmprovider.yaml index 447f959c9..e076c6c98 100644 --- a/config/samples/namespaced/verifier/config_v1beta1_verifier_notation_kmprovider.yaml +++ b/config/samples/namespaced/verifier/config_v1beta1_verifier_notation_kmprovider.yaml @@ -7,10 +7,9 @@ spec: artifactTypes: application/vnd.cncf.notary.signature parameters: verificationCertStores: - certs: - - kmprovider-akv - certs1: - - kmprovider-akv1 + ca: + ca-certs: + - kmprovider-akv trustPolicyDoc: version: "1.0" trustPolicies: @@ -20,6 +19,6 @@ spec: signatureVerification: level: strict trustStores: - - ca:certs + - ca:ca-certs trustedIdentities: - "*" diff --git a/config/samples/namespaced/verifier/config_v1beta1_verifier_notation_specificnskmprovider.yaml b/config/samples/namespaced/verifier/config_v1beta1_verifier_notation_specificnskmprovider.yaml index b3c46c3f1..83f0d72e6 100644 --- a/config/samples/namespaced/verifier/config_v1beta1_verifier_notation_specificnskmprovider.yaml +++ b/config/samples/namespaced/verifier/config_v1beta1_verifier_notation_specificnskmprovider.yaml @@ -6,10 +6,11 @@ spec: name: notation artifactTypes: application/vnd.cncf.notary.signature parameters: - verificationCertStores: - certs: - - default/ratify-notation-inline-cert-0 - trustPolicyDoc: + verificationCertStores: + ca: + ca-certs: + - default/ratify-notation-inline-cert-0 + trustPolicyDoc: version: "1.0" trustPolicies: - name: default @@ -18,6 +19,6 @@ spec: signatureVerification: level: strict trustStores: - - ca:certs + - ca:ca-certs trustedIdentities: - "*" diff --git a/crd.Dockerfile b/crd.Dockerfile index 92482cd1b..6606aa0af 100644 --- a/crd.Dockerfile +++ b/crd.Dockerfile @@ -11,7 +11,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -FROM alpine@sha256:0a4eaa0eecf5f8c050e5bba433f58c052be7587ee8af3e8b3910ef9ab5fbe9f5 as builder +FROM alpine@sha256:beefdbd8a1da6d2915566fde36db9db0b524eb737fc57cd1367effd16dc0d06d as builder ARG TARGETOS ARG TARGETARCH diff --git a/go.mod b/go.mod index b483bd80d..5225b06dd 100644 --- a/go.mod +++ b/go.mod @@ -13,9 +13,9 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1 github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.6.0 github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 - github.com/aws/aws-sdk-go-v2 v1.30.4 - github.com/aws/aws-sdk-go-v2/config v1.27.31 - github.com/aws/aws-sdk-go-v2/credentials v1.17.30 + github.com/aws/aws-sdk-go-v2 v1.30.5 + github.com/aws/aws-sdk-go-v2/config v1.27.33 + github.com/aws/aws-sdk-go-v2/credentials v1.17.32 github.com/aws/aws-sdk-go-v2/service/ecr v1.28.6 github.com/cespare/xxhash/v2 v2.3.0 github.com/dapr/go-sdk v1.8.0 @@ -29,7 +29,7 @@ require ( github.com/google/go-containerregistry v0.20.2 github.com/gorilla/mux v1.8.1 github.com/notaryproject/notation-core-go v1.1.0 - github.com/notaryproject/notation-go v1.2.0 + github.com/notaryproject/notation-go v1.2.1 github.com/notaryproject/notation-plugin-framework-go v1.0.0 github.com/open-policy-agent/cert-controller v0.8.0 github.com/open-policy-agent/frameworks/constraint v0.0.0-20230411224310-3f237e2710fa @@ -39,7 +39,7 @@ require ( github.com/owenrumney/go-sarif/v2 v2.3.3 github.com/pkg/errors v0.9.1 github.com/sigstore/cosign/v2 v2.2.4 - github.com/sigstore/sigstore v1.8.8 + github.com/sigstore/sigstore v1.8.9 github.com/sirupsen/logrus v1.9.3 github.com/spdx/tools-golang v0.5.5 github.com/spf13/cobra v1.8.1 @@ -138,14 +138,14 @@ require ( github.com/Azure/go-autorest/tracing v0.6.0 // indirect github.com/OneOfOne/xxhash v1.2.8 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.12 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.16 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.16 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.13 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.17 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.17 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.18 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.22.5 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.5 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.30.5 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.19 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.22.7 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.7 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.30.7 // indirect github.com/aws/smithy-go v1.20.4 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver v3.5.1+incompatible // indirect diff --git a/go.sum b/go.sum index 63d25297a..857713089 100644 --- a/go.sum +++ b/go.sum @@ -125,18 +125,18 @@ github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3d github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/aws/aws-sdk-go v1.51.6 h1:Ld36dn9r7P9IjU8WZSaswQ8Y/XUCRpewim5980DwYiU= github.com/aws/aws-sdk-go v1.51.6/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= -github.com/aws/aws-sdk-go-v2 v1.30.4 h1:frhcagrVNrzmT95RJImMHgabt99vkXGslubDaDagTk8= -github.com/aws/aws-sdk-go-v2 v1.30.4/go.mod h1:CT+ZPWXbYrci8chcARI3OmI/qgd+f6WtuLOoaIA8PR0= -github.com/aws/aws-sdk-go-v2/config v1.27.31 h1:kxBoRsjhT3pq0cKthgj6RU6bXTm/2SgdoUMyrVw0rAI= -github.com/aws/aws-sdk-go-v2/config v1.27.31/go.mod h1:z04nZdSWFPaDwK3DdJOG2r+scLQzMYuJeW0CujEm9FM= -github.com/aws/aws-sdk-go-v2/credentials v1.17.30 h1:aau/oYFtibVovr2rDt8FHlU17BTicFEMAi29V1U+L5Q= -github.com/aws/aws-sdk-go-v2/credentials v1.17.30/go.mod h1:BPJ/yXV92ZVq6G8uYvbU0gSl8q94UB63nMT5ctNO38g= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.12 h1:yjwoSyDZF8Jth+mUk5lSPJCkMC0lMy6FaCD51jm6ayE= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.12/go.mod h1:fuR57fAgMk7ot3WcNQfb6rSEn+SUffl7ri+aa8uKysI= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.16 h1:TNyt/+X43KJ9IJJMjKfa3bNTiZbUP7DeCxfbTROESwY= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.16/go.mod h1:2DwJF39FlNAUiX5pAc0UNeiz16lK2t7IaFcm0LFHEgc= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.16 h1:jYfy8UPmd+6kJW5YhY0L1/KftReOGxI/4NtVSTh9O/I= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.16/go.mod h1:7ZfEPZxkW42Afq4uQB8H2E2e6ebh6mXTueEpYzjCzcs= +github.com/aws/aws-sdk-go-v2 v1.30.5 h1:mWSRTwQAb0aLE17dSzztCVJWI9+cRMgqebndjwDyK0g= +github.com/aws/aws-sdk-go-v2 v1.30.5/go.mod h1:CT+ZPWXbYrci8chcARI3OmI/qgd+f6WtuLOoaIA8PR0= +github.com/aws/aws-sdk-go-v2/config v1.27.33 h1:Nof9o/MsmH4oa0s2q9a0k7tMz5x/Yj5k06lDODWz3BU= +github.com/aws/aws-sdk-go-v2/config v1.27.33/go.mod h1:kEqdYzRb8dd8Sy2pOdEbExTTF5v7ozEXX0McgPE7xks= +github.com/aws/aws-sdk-go-v2/credentials v1.17.32 h1:7Cxhp/BnT2RcGy4VisJ9miUPecY+lyE9I8JvcZofn9I= +github.com/aws/aws-sdk-go-v2/credentials v1.17.32/go.mod h1:P5/QMF3/DCHbXGEGkdbilXHsyTBX5D3HSwcrSc9p20I= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.13 h1:pfQ2sqNpMVK6xz2RbqLEL0GH87JOwSxPV2rzm8Zsb74= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.13/go.mod h1:NG7RXPUlqfsCLLFfi0+IpKN4sCB9D9fw/qTaSB+xRoU= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.17 h1:pI7Bzt0BJtYA0N/JEC6B8fJ4RBrEMi1LBrkMdFYNSnQ= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.17/go.mod h1:Dh5zzJYMtxfIjYW+/evjQ8uj2OyR/ve2KROHGHlSFqE= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.17 h1:Mqr/V5gvrhA2gvgnF42Zh5iMiQNcOYthFYwCyrnuWlc= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.17/go.mod h1:aLJpZlCmjE+V+KtN1q1uyZkfnUWpQGpbsn89XPKyzfU= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= github.com/aws/aws-sdk-go-v2/service/ecr v1.28.6 h1:CnQNpQv+WGl5aECyAXrJ4w+Qccz2aC/uXg2OjxiPl30= @@ -145,16 +145,16 @@ github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.23.7 h1:dsmihXaPkhFuUTiL+ygm9R github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.23.7/go.mod h1:g7If3uXj+mKcmIuxh08qh8I9ju6f/aOSWMyc6hEEi58= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.4 h1:KypMCbLPPHEmf9DgMGw51jMj77VfGPAN2Kv4cfhlfgI= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.4/go.mod h1:Vz1JQXliGcQktFTN/LN6uGppAIRoLBR2bMvIMP0gOjc= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.18 h1:tJ5RnkHCiSH0jyd6gROjlJtNwov0eGYNz8s8nFcR0jQ= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.18/go.mod h1:++NHzT+nAF7ZPrHPsA+ENvsXkOO8wEu+C6RXltAG4/c= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.19 h1:rfprUlsdzgl7ZL2KlXiUAoJnI/VxfHCvDFr2QDFj6u4= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.19/go.mod h1:SCWkEdRq8/7EK60NcvvQ6NXKuTcchAD4ROAsC37VEZE= github.com/aws/aws-sdk-go-v2/service/kms v1.31.3 h1:wLBgq6nDNYdd0A5CvscVAKV5SVlHKOHVPedpgtigATg= github.com/aws/aws-sdk-go-v2/service/kms v1.31.3/go.mod h1:8lETO9lelSG2B6KMXFh2OwPPqGV6WQM3RqLAEjP1xaU= -github.com/aws/aws-sdk-go-v2/service/sso v1.22.5 h1:zCsFCKvbj25i7p1u94imVoO447I/sFv8qq+lGJhRN0c= -github.com/aws/aws-sdk-go-v2/service/sso v1.22.5/go.mod h1:ZeDX1SnKsVlejeuz41GiajjZpRSWR7/42q/EyA/QEiM= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.5 h1:SKvPgvdvmiTWoi0GAJ7AsJfOz3ngVkD/ERbs5pUnHNI= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.5/go.mod h1:20sz31hv/WsPa3HhU3hfrIet2kxM4Pe0r20eBZ20Tac= -github.com/aws/aws-sdk-go-v2/service/sts v1.30.5 h1:OMsEmCyz2i89XwRwPouAJvhj81wINh+4UK+k/0Yo/q8= -github.com/aws/aws-sdk-go-v2/service/sts v1.30.5/go.mod h1:vmSqFK+BVIwVpDAGZB3CoCXHzurt4qBE8lf+I/kRTh0= +github.com/aws/aws-sdk-go-v2/service/sso v1.22.7 h1:pIaGg+08llrP7Q5aiz9ICWbY8cqhTkyy+0SHvfzQpTc= +github.com/aws/aws-sdk-go-v2/service/sso v1.22.7/go.mod h1:eEygMHnTKH/3kNp9Jr1n3PdejuSNcgwLe1dWgQtO0VQ= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.7 h1:/Cfdu0XV3mONYKaOt1Gr0k1KvQzkzPyiKUdlWJqy+J4= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.7/go.mod h1:bCbAxKDqNvkHxRaIMnyVPXPo+OaPRwvmgzMxbz1VKSA= +github.com/aws/aws-sdk-go-v2/service/sts v1.30.7 h1:NKTa1eqZYw8tiHSRGpP0VtTdub/8KNk8sDkNPFaOKDE= +github.com/aws/aws-sdk-go-v2/service/sts v1.30.7/go.mod h1:NXi1dIAGteSaRLqYgarlhP/Ij0cFT+qmCwiJqWh/U5o= github.com/aws/smithy-go v1.20.4 h1:2HK1zBdPgRbjFOHlfeQZfpC4r72MOb9bZkiFwggKO+4= github.com/aws/smithy-go v1.20.4/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20231024185945-8841054dbdb8 h1:SoFYaT9UyGkR0+nogNyD/Lj+bsixB+SNuAS4ABlEs6M= @@ -518,8 +518,8 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8m github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/notaryproject/notation-core-go v1.1.0 h1:xCybcONOKcCyPNihJUSa+jRNsyQFNkrk0eJVVs1kWeg= github.com/notaryproject/notation-core-go v1.1.0/go.mod h1:+6AOh41JPrnVLbW/19SJqdhVHwKgIINBO/np0e7nXJA= -github.com/notaryproject/notation-go v1.2.0 h1:Muq/S+Vyyerq/hefD1SUaIqFbNrhV/zgXi/M9sL4bpg= -github.com/notaryproject/notation-go v1.2.0/go.mod h1:re9V+TfuNRaUq5e3NuNcCJN53++sL2KbnJrjGyOUpgE= +github.com/notaryproject/notation-go v1.2.1 h1:fbCMBcvg1xttrisd5CyM60QDectGYYF701Us0M3cKN8= +github.com/notaryproject/notation-go v1.2.1/go.mod h1:re9V+TfuNRaUq5e3NuNcCJN53++sL2KbnJrjGyOUpgE= github.com/notaryproject/notation-plugin-framework-go v1.0.0 h1:6Qzr7DGXoCgXEQN+1gTZWuJAZvxh3p8Lryjn5FaLzi4= github.com/notaryproject/notation-plugin-framework-go v1.0.0/go.mod h1:RqWSrTOtEASCrGOEffq0n8pSg2KOgKYiWqFWczRSics= github.com/notaryproject/tspclient-go v0.2.0 h1:g/KpQGmyk/h7j60irIRG1mfWnibNOzJ8WhLqAzuiQAQ= @@ -613,8 +613,8 @@ github.com/sigstore/fulcio v1.4.5 h1:WWNnrOknD0DbruuZWCbN+86WRROpEl3Xts+WT2Ek1yc github.com/sigstore/fulcio v1.4.5/go.mod h1:oz3Qwlma8dWcSS/IENR/6SjbW4ipN0cxpRVfgdsjMU8= github.com/sigstore/rekor v1.3.6 h1:QvpMMJVWAp69a3CHzdrLelqEqpTM3ByQRt5B5Kspbi8= github.com/sigstore/rekor v1.3.6/go.mod h1:JDTSNNMdQ/PxdsS49DJkJ+pRJCO/83nbR5p3aZQteXc= -github.com/sigstore/sigstore v1.8.8 h1:B6ZQPBKK7Z7tO3bjLNnlCMG+H66tO4E/+qAphX8T/hg= -github.com/sigstore/sigstore v1.8.8/go.mod h1:GW0GgJSCTBJY3fUOuGDHeFWcD++c4G8Y9K015pwcpDI= +github.com/sigstore/sigstore v1.8.9 h1:NiUZIVWywgYuVTxXmRoTT4O4QAGiTEKup4N1wdxFadk= +github.com/sigstore/sigstore v1.8.9/go.mod h1:d9ZAbNDs8JJfxJrYmulaTazU3Pwr8uLL9+mii4BNR3w= github.com/sigstore/sigstore/pkg/signature/kms/aws v1.8.3 h1:LTfPadUAo+PDRUbbdqbeSl2OuoFQwUFTnJ4stu+nwWw= github.com/sigstore/sigstore/pkg/signature/kms/aws v1.8.3/go.mod h1:QV/Lxlxm0POyhfyBtIbTWxNeF18clMlkkyL9mu45y18= github.com/sigstore/sigstore/pkg/signature/kms/azure v1.8.3 h1:xgbPRCr2npmmsuVVteJqi/ERw9+I13Wou7kq0Yk4D8g= diff --git a/httpserver/Dockerfile b/httpserver/Dockerfile index 85b6256ad..6483cb687 100644 --- a/httpserver/Dockerfile +++ b/httpserver/Dockerfile @@ -11,7 +11,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -FROM --platform=$BUILDPLATFORM golang:1.22@sha256:367bb5295d3103981a86a572651d8297d6973f2ec8b62f716b007860e22cbc25 as builder +FROM --platform=$BUILDPLATFORM golang:1.22@sha256:192683db8982323952988c7b86c098ee7ecc6cbeb202bf7c113ff9be5358367c as builder ARG TARGETPLATFORM ARG TARGETOS @@ -41,7 +41,7 @@ RUN if [ "$build_licensechecker" = "true" ]; then go build -o /app/out/plugins/ RUN if [ "$build_schemavalidator" = "true" ]; then go build -o /app/out/plugins/ /app/plugins/verifier/schemavalidator; fi RUN if [ "$build_vulnerabilityreport" = "true" ]; then go build -o /app/out/plugins/ /app/plugins/verifier/vulnerabilityreport; fi -FROM gcr.io/distroless/static:nonroot@sha256:8dd8d3ca2cf283383304fd45a5c9c74d5f2cd9da8d3b077d720e264880077c65 +FROM gcr.io/distroless/static:nonroot@sha256:42d15c647a762d3ce3a67eab394220f5268915d6ddba9006871e16e4698c3a24 LABEL org.opencontainers.image.source https://github.com/ratify-project/ratify ARG RATIFY_FOLDER=$HOME/.ratify/ diff --git a/pkg/controllers/clusterresource/verifier_controller.go b/pkg/controllers/clusterresource/verifier_controller.go index ff889e1bb..f752fa154 100644 --- a/pkg/controllers/clusterresource/verifier_controller.go +++ b/pkg/controllers/clusterresource/verifier_controller.go @@ -17,6 +17,7 @@ package clusterresource import ( "context" + "fmt" configv1beta1 "github.com/ratify-project/ratify/api/v1beta1" re "github.com/ratify-project/ratify/errors" @@ -82,12 +83,13 @@ func (r *VerifierReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c return ctrl.Result{}, nil } -// creates a verifier reference from CRD spec and add store to map +// creates a verifier reference from CR spec and add verifier to map func verifierAddOrReplace(spec configv1beta1.VerifierSpec, objectName string) error { verifierConfig, err := cutils.SpecToVerifierConfig(spec.Parameters.Raw, objectName, cutils.GetVerifierType(spec), spec.ArtifactTypes, spec.Source) if err != nil { - logrus.Error(err) - return err + errMsg := fmt.Sprintf("Unable to apply cluster-wide resource %s of Verifier kind", objectName) + logrus.Error(err, errMsg) + return re.ErrorCodeConfigInvalid.WithDetail(errMsg).WithError(err) } return cutils.UpsertVerifier(spec.Version, spec.Address, constants.EmptyNamespace, objectName, verifierConfig) diff --git a/pkg/controllers/clusterresource/verifier_controller_test.go b/pkg/controllers/clusterresource/verifier_controller_test.go index 850a1fb69..96cfb5956 100644 --- a/pkg/controllers/clusterresource/verifier_controller_test.go +++ b/pkg/controllers/clusterresource/verifier_controller_test.go @@ -19,7 +19,6 @@ import ( "context" "errors" "os" - "strings" "testing" configv1beta1 "github.com/ratify-project/ratify/api/v1beta1" @@ -124,12 +123,12 @@ func TestVerifierAdd_WithParameters(t *testing.T) { func TestVerifierAddOrReplace_PluginNotFound(t *testing.T) { resetVerifierMap() - var resource = "invalidplugin" - expectedMsg := "plugin not found" + resource := "invalidplugin" + expectedMsg := "PLUGIN_NOT_FOUND: Verifier plugin pluginnotfound not found: failed to find plugin \"pluginnotfound\" in paths [test/path]: Please ensure that the correct type is specified for the built-in Verifier configuration or the custom Verifier plugin is configured." var testVerifierSpec = getInvalidVerifierSpec() err := verifierAddOrReplace(testVerifierSpec, resource) - if !strings.Contains(err.Error(), expectedMsg) { + if err.Error() != expectedMsg { t.Fatalf("TestVerifierAddOrReplace_PluginNotFound expected msg: '%v', actual %v", expectedMsg, err.Error()) } } diff --git a/pkg/controllers/namespaceresource/verifier_controller.go b/pkg/controllers/namespaceresource/verifier_controller.go index 67eddd33c..a2926efe9 100644 --- a/pkg/controllers/namespaceresource/verifier_controller.go +++ b/pkg/controllers/namespaceresource/verifier_controller.go @@ -17,6 +17,7 @@ package namespaceresource import ( "context" + "fmt" configv1beta1 "github.com/ratify-project/ratify/api/v1beta1" "github.com/ratify-project/ratify/internal/constants" @@ -85,8 +86,9 @@ func (r *VerifierReconciler) Reconcile(ctx context.Context, req ctrl.Request) (c func verifierAddOrReplace(spec configv1beta1.NamespacedVerifierSpec, objectName string, namespace string) error { verifierConfig, err := cutils.SpecToVerifierConfig(spec.Parameters.Raw, objectName, cutils.GetVerifierType(spec), spec.ArtifactTypes, spec.Source) if err != nil { - logrus.Error(err) - return err + errMsg := fmt.Sprintf("Unable to apply the resource %s of NamespacedVerifier kind in the namespace %s", objectName, namespace) + logrus.Error(err, errMsg) + return re.ErrorCodeConfigInvalid.WithDetail(errMsg).WithError(err) } return cutils.UpsertVerifier(spec.Version, spec.Address, namespace, objectName, verifierConfig) diff --git a/pkg/controllers/namespaceresource/verifier_controller_test.go b/pkg/controllers/namespaceresource/verifier_controller_test.go index ac433a53c..5c65f1645 100644 --- a/pkg/controllers/namespaceresource/verifier_controller_test.go +++ b/pkg/controllers/namespaceresource/verifier_controller_test.go @@ -19,7 +19,6 @@ import ( "context" "errors" "os" - "strings" "testing" configv1beta1 "github.com/ratify-project/ratify/api/v1beta1" @@ -142,12 +141,12 @@ func TestVerifierAdd_WithParameters(t *testing.T) { func TestVerifierAddOrReplace_PluginNotFound(t *testing.T) { resetVerifierMap() - var resource = "invalidplugin" - expectedMsg := "plugin not found" + resource := "invalidplugin" + expectedMsg := "PLUGIN_NOT_FOUND: Verifier plugin pluginnotfound not found: failed to find plugin \"pluginnotfound\" in paths [test/path]: Please ensure that the correct type is specified for the built-in Verifier configuration or the custom Verifier plugin is configured." var testVerifierSpec = getInvalidVerifierSpec() err := verifierAddOrReplace(testVerifierSpec, resource, testNamespace) - if !strings.Contains(err.Error(), expectedMsg) { + if err.Error() != expectedMsg { t.Fatalf("TestVerifierAddOrReplace_PluginNotFound expected msg: '%v', actual %v", expectedMsg, err.Error()) } } diff --git a/pkg/controllers/utils/verifier.go b/pkg/controllers/utils/verifier.go index c569388a3..43a9e858d 100644 --- a/pkg/controllers/utils/verifier.go +++ b/pkg/controllers/utils/verifier.go @@ -15,8 +15,10 @@ package utils import ( "encoding/json" + "fmt" configv1beta1 "github.com/ratify-project/ratify/api/v1beta1" + re "github.com/ratify-project/ratify/errors" vc "github.com/ratify-project/ratify/pkg/verifier/config" vf "github.com/ratify-project/ratify/pkg/verifier/factory" "github.com/ratify-project/ratify/pkg/verifier/types" @@ -56,8 +58,9 @@ func SpecToVerifierConfig(raw []byte, verifierName, verifierType, artifactTypes if string(raw) != "" { if err := json.Unmarshal(raw, &verifierConfig); err != nil { - logrus.Error(err, "unable to decode verifier parameters", "Parameters.Raw", raw) - return vc.VerifierConfig{}, err + errMsg := fmt.Sprintf("Unable to recognize the parameters of the Verifier resource %s", string(raw)) + logrus.Error(err, errMsg) + return vc.VerifierConfig{}, re.ErrorCodeConfigInvalid.WithError(err).WithDetail(errMsg).WithRemediation("Please update the Verifier parameters and try again. Refer to the Verifier configuration guide: https://ratify.dev/docs/reference/custom%20resources/verifiers") } } verifierConfig[types.Name] = verifierName diff --git a/pkg/executor/core/executor.go b/pkg/executor/core/executor.go index e5d8ec299..b364bee30 100644 --- a/pkg/executor/core/executor.go +++ b/pkg/executor/core/executor.go @@ -61,7 +61,7 @@ type Executor struct { // VerifySubject verifies the subject and returns results. func (executor Executor) VerifySubject(ctx context.Context, verifyParameters e.VerifyParameters) (types.VerifyResult, error) { if executor.PolicyEnforcer == nil { - return types.VerifyResult{}, errors.ErrorCodePolicyProviderNotFound.WithComponentType(errors.Executor) + return types.VerifyResult{}, errors.ErrorCodePolicyProviderNotFound.WithDetail("Policy configuration not found") } result, err := executor.verifySubjectInternal(ctx, verifyParameters) if err != nil { @@ -83,7 +83,7 @@ func (executor Executor) verifySubjectInternal(ctx context.Context, verifyParame } if executor.PolicyEnforcer.GetPolicyType(ctx) == pt.ConfigPolicy { if len(verifierReports) == 0 { - return types.VerifyResult{}, errors.ErrorCodeNoVerifierReport.WithComponentType(errors.Executor).WithDescription() + return types.VerifyResult{}, errors.ErrorCodeNoVerifierReport.WithDetail(fmt.Sprintf("No verification results for the artifact %s. Ensure verifiers are properly configured and that artifact metadata is attached", verifyParameters.Subject)) } } // If it requires embedded Rego Policy Engine make the decision, execute @@ -176,7 +176,7 @@ func (executor Executor) verifyReferenceForJSONPolicy(ctx context.Context, subje verifierStartTime := time.Now() verifyResult, err := verifier.Verify(ctx, subjectRef, referenceDesc, referrerStore) if err != nil { - verifierErr := errors.ErrorCodeVerifyReferenceFailure.NewError(errors.Verifier, verifier.Name(), errors.EmptyLink, err, nil, errors.HideStackTrace) + verifierErr := errors.ErrorCodeVerifyReferenceFailure.WithError(err) verifyResult = vr.NewVerifierResult("", verifier.Name(), verifier.Type(), "", false, &verifierErr, nil) } @@ -224,7 +224,7 @@ func (executor Executor) verifyReferenceForRegoPolicy(ctx context.Context, subje verifierStartTime := time.Now() verifierResult, err := verifier.Verify(errCtx, subjectRef, referenceDesc, referrerStore) if err != nil { - verifierErr := errors.ErrorCodeVerifyReferenceFailure.NewError(errors.Verifier, verifier.Name(), errors.EmptyLink, err, nil, errors.HideStackTrace) + verifierErr := errors.ErrorCodeVerifyReferenceFailure.WithError(err) verifierReport = vt.CreateVerifierResult(verifier.Name(), verifier.Type(), "", false, &verifierErr) } else { verifierReport = vt.NewVerifierResult(verifierResult) @@ -288,7 +288,7 @@ func (executor Executor) addNestedReports(ctx context.Context, referenceDes ocis for _, report := range reports.VerifierReports { nestedReport, err := types.NewNestedVerifierReport(report) if err != nil { - return errors.ErrorCodeExecutorFailure.WithError(err).WithComponentType(errors.Executor) + return errors.ErrorCodeExecutorFailure.WithError(err) } nestedReports = append(nestedReports, nestedReport) } diff --git a/pkg/keymanagementprovider/keymanagementprovider.go b/pkg/keymanagementprovider/keymanagementprovider.go index bf77c2cd5..584f50828 100644 --- a/pkg/keymanagementprovider/keymanagementprovider.go +++ b/pkg/keymanagementprovider/keymanagementprovider.go @@ -136,7 +136,7 @@ func setCertificatesInMap(resource string, certs map[KMPMapKey][]*x509.Certifica // GetCertificatesFromMap gets the certificates from the map and returns an empty map of certificate arrays if not found or an error happened. func GetCertificatesFromMap(ctx context.Context, resource string) (map[KMPMapKey][]*x509.Certificate, error) { if !hasAccessToProvider(ctx, resource) { - return map[KMPMapKey][]*x509.Certificate{}, errors.ErrorCodeForbidden.WithDetail(fmt.Sprintf("namespace: [%s] does not have access to key management provider: %s", ctxUtils.GetNamespace(ctx), resource)).WithRemediation(fmt.Sprintf("Ensure the key management provider: %s is created under namespace: [%s] or as a cluster-wide resource.", resource, ctxUtils.GetNamespace(ctx))) + return map[KMPMapKey][]*x509.Certificate{}, errors.ErrorCodeForbidden.WithDetail(fmt.Sprintf("Resources in namespace [%s] do not have access to key management provider [%s]", ctxUtils.GetNamespace(ctx), resource)).WithRemediation(fmt.Sprintf("Make sure the key management provider: %s is created in the namespace: [%s] or as a cluster-wide resource.", resource, ctxUtils.GetNamespace(ctx))) } if err, ok := certificateErrMap.Load(resource); ok && err != nil { return map[KMPMapKey][]*x509.Certificate{}, err.(error) @@ -144,7 +144,7 @@ func GetCertificatesFromMap(ctx context.Context, resource string) (map[KMPMapKey if certs, ok := certificatesMap.Load(resource); ok { return certs.(map[KMPMapKey][]*x509.Certificate), nil } - return map[KMPMapKey][]*x509.Certificate{}, errors.ErrorCodeNotFound.WithDetail(fmt.Sprintf("failed to access non-existent key management provider: %s", resource)) + return map[KMPMapKey][]*x509.Certificate{}, errors.ErrorCodeNotFound.WithDetail(fmt.Sprintf("The key management provider [%s] does not exist", resource)).WithRemediation(fmt.Sprintf("Make sure the key management provider: %s is created in the namespace: [%s] or as a cluster-wide resource.", resource, ctxUtils.GetNamespace(ctx))) } // DeleteResourceFromMap deletes the certificates, keys and errors from the map @@ -186,7 +186,7 @@ func GetKeysFromMap(ctx context.Context, resource string) (map[KMPMapKey]PublicK // A cluster-wide operation can access cluster-wide provider // A namespaced operation can only fetch the provider in the same namespace or cluster-wide provider. if !hasAccessToProvider(ctx, resource) { - return map[KMPMapKey]PublicKey{}, fmt.Errorf("namespace: [%s] does not have access to key management provider: %s", ctxUtils.GetNamespace(ctx), resource) + return map[KMPMapKey]PublicKey{}, errors.ErrorCodeForbidden.WithDetail(fmt.Sprintf("The resources in namespace [%s] do not have access to key management provider [%s]", ctxUtils.GetNamespace(ctx), resource)).WithRemediation(fmt.Sprintf("Make sure the key management provider [%s] is created in the namespace [%s] or as a cluster-wide resource.", resource, ctxUtils.GetNamespace(ctx))) } if err, ok := keyErrMap.Load(resource); ok && err != nil { return map[KMPMapKey]PublicKey{}, err.(error) @@ -194,7 +194,7 @@ func GetKeysFromMap(ctx context.Context, resource string) (map[KMPMapKey]PublicK if keys, ok := keyMap.Load(resource); ok { return keys.(map[KMPMapKey]PublicKey), nil } - return map[KMPMapKey]PublicKey{}, fmt.Errorf("failed to access non-existent key management provider: %s", resource) + return map[KMPMapKey]PublicKey{}, errors.ErrorCodeNotFound.WithDetail(fmt.Sprintf("The key management provider [%s] does not exist", resource)).WithRemediation(fmt.Sprintf("Make sure the key management provider: %s is created in the namespace: [%s] or as a cluster-wide resource.", resource, ctxUtils.GetNamespace(ctx))) } // SetCertificateError sets the error while fetching certificates from key management provider. diff --git a/pkg/referrerstore/oras/cosign.go b/pkg/referrerstore/oras/cosign.go index a60f458ae..3db4b23bb 100644 --- a/pkg/referrerstore/oras/cosign.go +++ b/pkg/referrerstore/oras/cosign.go @@ -46,7 +46,7 @@ func getCosignReferences(ctx context.Context, subjectReference common.Reference, return nil, nil } evictOnError(ctx, err, subjectReference.Original) - return nil, re.ErrorCodeRepositoryOperationFailure.WithError(err).WithComponentType(re.ReferrerStore) + return nil, re.ErrorCodeRepositoryOperationFailure.WithDetail(fmt.Sprintf("Failed to validate the signature of the artifact: %+v", subjectReference)).WithError(err) } references = append(references, ocispecs.ReferenceDescriptor{ @@ -64,7 +64,7 @@ func getCosignReferences(ctx context.Context, subjectReference common.Reference, func attachedImageTag(subjectReference common.Reference, tagSuffix string) (string, error) { // sha256:d34db33f -> sha256-d34db33f.suffix if subjectReference.Digest.String() == "" { - return "", re.ErrorCodeReferenceInvalid.WithComponentType(re.ReferrerStore).WithDetail("Cosign subject digest is empty") + return "", re.ErrorCodeReferenceInvalid.WithDetail("The digest of the artifact is empty") } tagStr := strings.ReplaceAll(subjectReference.Digest.String(), ":", "-") + tagSuffix return fmt.Sprintf("%s:%s", subjectReference.Path, tagStr), nil diff --git a/pkg/referrerstore/oras/oras.go b/pkg/referrerstore/oras/oras.go index 0a8f146e5..64679dd0a 100644 --- a/pkg/referrerstore/oras/oras.go +++ b/pkg/referrerstore/oras/oras.go @@ -208,7 +208,7 @@ func (store *orasStore) GetConfig() *config.StoreConfig { func (store *orasStore) ListReferrers(ctx context.Context, subjectReference common.Reference, _ []string, _ string, subjectDesc *ocispecs.SubjectDescriptor) (referrerstore.ListReferrersResult, error) { repository, err := store.createRepository(ctx, store, subjectReference) if err != nil { - return referrerstore.ListReferrersResult{}, re.ErrorCodeCreateRepositoryFailure.WithError(err).WithComponentType(re.ReferrerStore) + return referrerstore.ListReferrersResult{}, re.ErrorCodeRepositoryOperationFailure.WithDetail("Failed to connect to the remote registry").WithError(err) } // resolve subject descriptor if not provided @@ -260,7 +260,7 @@ func (store *orasStore) GetBlobContent(ctx context.Context, subjectReference com repository, err := store.createRepository(ctx, store, subjectReference) if err != nil { - return nil, err + return nil, re.ErrorCodeGetBlobContentFailure.WithDetail("Failed to connect to the remote registry").WithError(err) } // create a dummy Descriptor to check the local store cache @@ -292,10 +292,10 @@ func (store *orasStore) GetBlobContent(ctx context.Context, subjectReference com blobDesc, rc, err := repository.Blobs().FetchReference(ctx, ref) if err != nil { evictOnError(ctx, err, subjectReference.Original) - return nil, err + return nil, re.ErrorCodeRepositoryOperationFailure.WithDetail("Failed to fetch the artifact metadata from the registry").WithError(err) } if blobContent, err = io.ReadAll(rc); err != nil { - return nil, re.ErrorCodeGetBlobContentFailure.WithError(err) + return nil, re.ErrorCodeRepositoryOperationFailure.WithDetail("Failed to parse the artifact metadata").WithError(err) } // push fetched content to local ORAS cache @@ -313,7 +313,7 @@ func (store *orasStore) GetBlobContent(ctx context.Context, subjectReference com func (store *orasStore) GetReferenceManifest(ctx context.Context, subjectReference common.Reference, referenceDesc ocispecs.ReferenceDescriptor) (ocispecs.ReferenceManifest, error) { repository, err := store.createRepository(ctx, store, subjectReference) if err != nil { - return ocispecs.ReferenceManifest{}, re.ErrorCodeCreateRepositoryFailure.NewError(re.ReferrerStore, storeName, re.EmptyLink, err, nil, re.HideStackTrace) + return ocispecs.ReferenceManifest{}, re.ErrorCodeRepositoryOperationFailure.WithDetail("Failed to connect to the remote registry").WithError(err) } var manifestBytes []byte // check if manifest exists in local ORAS cache @@ -336,12 +336,12 @@ func (store *orasStore) GetReferenceManifest(ctx context.Context, subjectReferen manifestReader, err := repository.Fetch(ctx, referenceDesc.Descriptor) if err != nil { evictOnError(ctx, err, subjectReference.Original) - return ocispecs.ReferenceManifest{}, re.ErrorCodeRepositoryOperationFailure.NewError(re.ReferrerStore, storeName, re.EmptyLink, err, nil, re.HideStackTrace) + return ocispecs.ReferenceManifest{}, re.ErrorCodeRepositoryOperationFailure.WithDetail("Failed to fetch the artifact metadata from the registry").WithError(err) } manifestBytes, err = io.ReadAll(manifestReader) if err != nil { - return ocispecs.ReferenceManifest{}, re.ErrorCodeManifestInvalid.WithError(err).WithPluginName(storeName).WithComponentType(re.ReferrerStore) + return ocispecs.ReferenceManifest{}, re.ErrorCodeManifestInvalid.WithDetail("Failed to parse the artifact metadata").WithError(err) } // push fetched manifest to local ORAS cache @@ -360,15 +360,15 @@ func (store *orasStore) GetReferenceManifest(ctx context.Context, subjectReferen if referenceDesc.Descriptor.MediaType == oci.MediaTypeImageManifest { var imageManifest oci.Manifest if err := json.Unmarshal(manifestBytes, &imageManifest); err != nil { - return ocispecs.ReferenceManifest{}, re.ErrorCodeDataDecodingFailure.WithError(err).WithComponentType(re.ReferrerStore) + return ocispecs.ReferenceManifest{}, re.ErrorCodeDataDecodingFailure.WithDetail("Failed to parse artifact metadata of mediatype `application/vnd.oci.image.manifest.v1+json`").WithError(err).WithRemediation("Please check if the artifact metadata was created correctly.") } referenceManifest = commonutils.OciManifestToReferenceManifest(imageManifest) } else if referenceDesc.Descriptor.MediaType == ocispecs.MediaTypeArtifactManifest { if err := json.Unmarshal(manifestBytes, &referenceManifest); err != nil { - return ocispecs.ReferenceManifest{}, re.ErrorCodeDataDecodingFailure.WithError(err).WithComponentType(re.ReferrerStore) + return ocispecs.ReferenceManifest{}, re.ErrorCodeDataDecodingFailure.WithDetail("Failed to parse artifact metadata of mediatype `application/vnd.oci.artifact.manifest.v1+json`").WithError(err).WithRemediation("Please check if the artifact metadata was created correctly.") } } else { - return ocispecs.ReferenceManifest{}, fmt.Errorf("unsupported manifest media type: %s", referenceDesc.Descriptor.MediaType) + return ocispecs.ReferenceManifest{}, re.ErrorCodeGetReferenceManifestFailure.WithDetail(fmt.Sprintf("Unsupported artifact metadata of media type %s", referenceDesc.Descriptor.MediaType)).WithRemediation("Please check if the artifact metadata was created correctly.") } return referenceManifest, nil @@ -377,13 +377,13 @@ func (store *orasStore) GetReferenceManifest(ctx context.Context, subjectReferen func (store *orasStore) GetSubjectDescriptor(ctx context.Context, subjectReference common.Reference) (*ocispecs.SubjectDescriptor, error) { repository, err := store.createRepository(ctx, store, subjectReference) if err != nil { - return nil, re.ErrorCodeCreateRepositoryFailure.WithError(err).WithComponentType(re.ReferrerStore).WithPluginName(storeName) + return nil, re.ErrorCodeRepositoryOperationFailure.WithDetail("Failed to connect to remote registry").WithError(err) } desc, err := repository.Resolve(ctx, subjectReference.Original) if err != nil { evictOnError(ctx, err, subjectReference.Original) - return nil, re.ErrorCodeRepositoryOperationFailure.WithError(err).WithPluginName(storeName) + return nil, re.ErrorCodeRepositoryOperationFailure.WithDetail(fmt.Sprintf("Unable to resolve the reference: %s", subjectReference.Original)).WithError(err) } return &ocispecs.SubjectDescriptor{Descriptor: desc}, nil diff --git a/pkg/verifier/cosign/cosign.go b/pkg/verifier/cosign/cosign.go index fb3efd714..cba6a1e9a 100644 --- a/pkg/verifier/cosign/cosign.go +++ b/pkg/verifier/cosign/cosign.go @@ -143,17 +143,17 @@ func (f *cosignVerifierFactory) Create(_ string, verifierConfig config.VerifierC logger.GetLogger(context.Background(), logOpt).Debugf("creating cosign verifier with config %v, namespace '%v'", verifierConfig, namespace) verifierName, hasName := verifierConfig[types.Name].(string) if !hasName { - return nil, re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithPluginName(verifierName).WithDetail("missing name in verifier config") + return nil, re.ErrorCodeConfigInvalid.WithDetail("The name field is required in the Cosign Verifier configuration") } config, err := parseVerifierConfig(verifierConfig) if err != nil { - return nil, re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithPluginName(verifierName) + return nil, re.ErrorCodeConfigInvalid.WithDetail("Failed to create the Cosign Verifier").WithError(err) } // if key or rekorURL is provided, trustPolicies should not be provided if (config.KeyRef != "" || config.RekorURL != "") && len(config.TrustPolicies) > 0 { - return nil, re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithPluginName(verifierName).WithDetail("'key' and 'rekorURL' are part of cosign legacy configuration and cannot be used with `trustPolicies`") + return nil, re.ErrorCodeConfigInvalid.WithDetail("'key' and 'rekorURL' are part of Cosign legacy configuration and cannot be used with `trustPolicies` parameter") } var trustPolicies *TrustPolicies @@ -163,7 +163,7 @@ func (f *cosignVerifierFactory) Create(_ string, verifierConfig config.VerifierC logger.GetLogger(context.Background(), logOpt).Debugf("legacy cosign verifier configuration not found, creating trust policies") trustPolicies, err = CreateTrustPolicies(config.TrustPolicies, verifierName) if err != nil { - return nil, err + return nil, re.ErrorCodePluginInitFailure.WithDetail("Failed to create the Cosign Verifier").WithError(err) } legacy = false } @@ -224,18 +224,18 @@ func (v *cosignVerifier) verifyInternal(ctx context.Context, subjectReference co // get the reference manifest (cosign oci image) referenceManifest, err := referrerStore.GetReferenceManifest(ctx, subjectReference, referenceDescriptor) if err != nil { - return errorToVerifyResult(v.name, v.verifierType, fmt.Errorf("failed to get reference manifest: %w", err)), nil + return errorToVerifyResult(v.name, v.verifierType, re.ErrorCodeVerifyPluginFailure.WithDetail(fmt.Sprintf("Failed to get artifact metadata for %s", referenceDescriptor.Digest)).WithError(err)), nil } // manifest must be an OCI Image if referenceManifest.MediaType != imgspec.MediaTypeImageManifest { - return errorToVerifyResult(v.name, v.verifierType, fmt.Errorf("reference manifest is not an image")), nil + return errorToVerifyResult(v.name, v.verifierType, re.ErrorCodeVerifyPluginFailure.WithDetail("The artifact metadata is not an OCI image")), nil } // get the subject image descriptor subjectDesc, err := referrerStore.GetSubjectDescriptor(ctx, subjectReference) if err != nil { - return errorToVerifyResult(v.name, v.verifierType, fmt.Errorf("failed to create subject hash: %w", err)), nil + return errorToVerifyResult(v.name, v.verifierType, re.ErrorCodeVerifyReferenceFailure.WithDetail(fmt.Sprintf("Failed to validate the Cosign signature of the artifact: %+v", subjectReference)).WithError(err)), nil } // create the hash of the subject image descriptor (used as the hashed payload) @@ -255,23 +255,23 @@ func (v *cosignVerifier) verifyInternal(ctx context.Context, subjectReference co // fetch the blob content of the signature from the referrer store blobBytes, err := referrerStore.GetBlobContent(ctx, subjectReference, blob.Digest) if err != nil { - return errorToVerifyResult(v.name, v.verifierType, fmt.Errorf("failed to get blob content: %w", err)), nil + return errorToVerifyResult(v.name, v.verifierType, re.ErrorCodeGetBlobContentFailure.WithDetail(fmt.Sprintf("Failed to get Cosign signature with digest %s", blob.Digest)).WithError(err)), nil } // convert the blob to a static signature staticOpts, err := staticLayerOpts(blob) if err != nil { - return errorToVerifyResult(v.name, v.verifierType, fmt.Errorf("failed to parse static signature opts: %w", err)), nil + return errorToVerifyResult(v.name, v.verifierType, re.ErrorCodeVerifyPluginFailure.WithDetail(fmt.Sprintf("Failed to parse Cosign signature with digest %s", blob.Digest)).WithError(err)), nil } sig, err := static.NewSignature(blobBytes, blob.Annotations[static.SignatureAnnotationKey], staticOpts...) if err != nil { - return errorToVerifyResult(v.name, v.verifierType, fmt.Errorf("failed to generate static signature: %w", err)), nil + return errorToVerifyResult(v.name, v.verifierType, re.ErrorCodeVerifyPluginFailure.WithDetail("Failed to validate the Cosign signature").WithError(err)), nil } if len(keysMap) > 0 { // if keys are found, perform verification with keys var verifications []cosignExtension verifications, hasValidSignature, err = verifyWithKeys(ctx, keysMap, sig, blob.Annotations[static.SignatureAnnotationKey], blobBytes, staticOpts, &cosignOpts, subjectDescHash) if err != nil { - return errorToVerifyResult(v.name, v.verifierType, fmt.Errorf("failed to verify with keys: %w", err)), nil + return errorToVerifyResult(v.name, v.verifierType, re.ErrorCodeVerifyPluginFailure.WithDetail("Failed to validate the Cosign signature with keys").WithError(err)), nil } extensionListEntry.Verifications = append(extensionListEntry.Verifications, verifications...) } else { @@ -295,7 +295,7 @@ func (v *cosignVerifier) verifyInternal(ctx context.Context, subjectReference co ), nil } - errorResult := errorToVerifyResult(v.name, v.verifierType, fmt.Errorf("no valid signatures found")) + errorResult := errorToVerifyResult(v.name, v.verifierType, fmt.Errorf("no valid Cosign signatures found")) errorResult.Extensions = Extension{SignatureExtension: sigExtensions, TrustPolicy: trustPolicy.GetName()} return errorResult, nil } @@ -485,7 +485,7 @@ func staticLayerOpts(desc imgspec.Descriptor) ([]static.Option, error) { // ErrorToVerifyResult returns a verifier result with the error message and isSuccess set to false func errorToVerifyResult(name string, verifierType string, err error) verifier.VerifierResult { - verifierErr := re.ErrorCodeVerifyReferenceFailure.WithDetail("Verification failed").WithError(err) + verifierErr := re.ErrorCodeVerifyReferenceFailure.WithDetail("Failed to validate the Cosign signature").WithError(err) return verifier.NewVerifierResult( "", name, @@ -540,14 +540,14 @@ func verifyWithKeys(ctx context.Context, keysMap map[PKKey]keymanagementprovider if pubKey.ProviderType == azurekeyvault.ProviderName { hashType, sig, err = processAKVSignature(sigEncoded, sig, pubKey.Key, payload, staticOpts) if err != nil { - return verifications, false, fmt.Errorf("failed to process AKV signature: %w", err) + return verifications, false, re.ErrorCodeVerifyPluginFailure.WithDetail("Failed to validate the Cosign signature generated by AKV").WithError(err) } } // return the correct verifier based on public key type and bytes verifier, err := signature.LoadVerifier(pubKey.Key, hashType) if err != nil { - return verifications, false, fmt.Errorf("failed to load public key from provider [%s] name [%s] version [%s]: %w", mapKey.Provider, mapKey.Name, mapKey.Version, err) + return verifications, false, re.ErrorCodeVerifyPluginFailure.WithDetail(fmt.Sprintf("Failed to load public key from provider [%s] name [%s] version [%s]", mapKey.Provider, mapKey.Name, mapKey.Version)).WithError(err) } cosignOpts.SigVerifier = verifier // verify signature with cosign options + perform bundle verification @@ -627,17 +627,17 @@ func processAKVSignature(sigEncoded string, staticSig oci.Signature, publicKey c // EC verifiers in cosign have built in ASN.1 decoding, but RSA verifiers do not base64DecodedBytes, err := base64.StdEncoding.DecodeString(sigEncoded) if err != nil { - return crypto.SHA256, nil, fmt.Errorf("RSA key check: failed to decode base64 signature: %w", err) + return crypto.SHA256, nil, re.ErrorCodeVerifyPluginFailure.WithDetail("RSA key check: failed to decode base64 signature").WithError(err) } // decode ASN.1 signature to raw signature if it is ASN.1 encoded decodedSigBytes, err := decodeASN1Signature(base64DecodedBytes) if err != nil { - return crypto.SHA256, nil, fmt.Errorf("RSA key check: failed to decode ASN.1 signature: %w", err) + return crypto.SHA256, nil, re.ErrorCodeVerifyPluginFailure.WithDetail("RSA key check: failed to decode ASN.1 signature").WithError(err) } encodedBase64SigBytes := base64.StdEncoding.EncodeToString(decodedSigBytes) staticSig, err = static.NewSignature(payloadBytes, encodedBase64SigBytes, staticOpts...) if err != nil { - return crypto.SHA256, nil, fmt.Errorf("RSA key check: failed to generate static signature: %w", err) + return crypto.SHA256, nil, re.ErrorCodeVerifyPluginFailure.WithDetail("RSA key check: failed to generate static signature").WithError(err) } case *ecdsa.PublicKey: switch keyType.Curve { @@ -648,10 +648,10 @@ func processAKVSignature(sigEncoded string, staticSig oci.Signature, publicKey c case elliptic.P521(): hashType = crypto.SHA512 default: - return crypto.SHA256, nil, fmt.Errorf("ECDSA key check: unsupported key curve: %s", keyType.Params().Name) + return crypto.SHA256, nil, fmt.Errorf("ECDSA key check: unsupported key curve [%s]", keyType.Params().Name) } default: - return crypto.SHA256, nil, fmt.Errorf("unsupported public key type: %T", publicKey) + return crypto.SHA256, nil, fmt.Errorf("unsupported public key type [%T]", publicKey) } return hashType, staticSig, nil } diff --git a/pkg/verifier/cosign/cosign_test.go b/pkg/verifier/cosign/cosign_test.go index b4e368617..aea1cf5a7 100644 --- a/pkg/verifier/cosign/cosign_test.go +++ b/pkg/verifier/cosign/cosign_test.go @@ -23,6 +23,7 @@ import ( "crypto/elliptic" "crypto/rand" "crypto/rsa" + "encoding/base64" "fmt" "io" "slices" @@ -114,6 +115,26 @@ func TestCreate(t *testing.T) { }, wantErr: false, }, + { + name: "duplicate trust policies in config", + config: config.VerifierConfig{ + "name": "test", + "artifactTypes": "testtype", + "trustPolicies": []TrustPolicyConfig{ + { + Name: "test", + Keyless: KeylessConfig{CertificateIdentity: testIdentity, CertificateOIDCIssuer: testIssuer}, + Scopes: []string{"*"}, + }, + { + Name: "test", + Keyless: KeylessConfig{CertificateIdentity: testIdentity, CertificateOIDCIssuer: testIssuer}, + Scopes: []string{"*"}, + }, + }, + }, + wantErr: true, + }, { name: "invalid config with legacy and trust policies", config: config.VerifierConfig{ @@ -407,8 +428,8 @@ func TestErrorToVerifyResult(t *testing.T) { if verifierResult.Type != "cosign" { t.Errorf("errorToVerifyResult() = %v, want %v", verifierResult.Type, "cosign") } - if verifierResult.Message != "Verification failed" { - t.Errorf("errorToVerifyResult() = %v, want %v", verifierResult.Message, "Verification failed") + if verifierResult.Message != "Failed to validate the Cosign signature" { + t.Errorf("errorToVerifyResult() = %v, want %v", verifierResult.Message, "Failed to validate the Cosign signature") } if verifierResult.ErrorReason != "test error" { t.Errorf("errorToVerifyResult() = %v, want %v", verifierResult.ErrorReason, "test error") @@ -573,7 +594,7 @@ mmBwUAwwW0Uc+Nt3bDOCiB1nUsICv1ry keys: map[PKKey]keymanagementprovider.PublicKey{}, getKeysError: true, store: &mocks.MemoryTestStore{}, - expectedResultMessagePrefix: "Verification failed", + expectedResultMessagePrefix: "Failed to validate the Cosign signature", expectedErrorReason: "error", }, { @@ -581,8 +602,8 @@ mmBwUAwwW0Uc+Nt3bDOCiB1nUsICv1ry keys: map[PKKey]keymanagementprovider.PublicKey{}, getKeysError: false, store: &mocks.MemoryTestStore{}, - expectedResultMessagePrefix: "Verification failed", - expectedErrorReason: "failed to get reference manifest: manifest not found", + expectedResultMessagePrefix: "Failed to validate the Cosign signature", + expectedErrorReason: "manifest not found", }, { name: "incorrect reference manifest media type error", @@ -595,8 +616,8 @@ mmBwUAwwW0Uc+Nt3bDOCiB1nUsICv1ry }, }, }, - expectedResultMessagePrefix: "Verification failed", - expectedErrorReason: "reference manifest is not an image", + expectedResultMessagePrefix: "Failed to validate the Cosign signature", + expectedErrorReason: "The artifact metadata is not an OCI image", }, { name: "failed subject descriptor fetch", @@ -609,8 +630,8 @@ mmBwUAwwW0Uc+Nt3bDOCiB1nUsICv1ry }, }, }, - expectedResultMessagePrefix: "Verification failed", - expectedErrorReason: "failed to create subject hash: subject not found for sha256:5678", + expectedResultMessagePrefix: "Failed to validate the Cosign signature", + expectedErrorReason: "subject not found for sha256:5678", }, { name: "failed to fetch blob", @@ -636,8 +657,8 @@ mmBwUAwwW0Uc+Nt3bDOCiB1nUsICv1ry }, }, }, - expectedResultMessagePrefix: "Verification failed", - expectedErrorReason: "failed to get blob content: blob not found", + expectedResultMessagePrefix: "Failed to validate the Cosign signature", + expectedErrorReason: "blob not found", }, { name: "invalid key type for AKV", @@ -668,8 +689,8 @@ mmBwUAwwW0Uc+Nt3bDOCiB1nUsICv1ry blobDigest: validSignatureBlob, }, }, - expectedResultMessagePrefix: "Verification failed", - expectedErrorReason: "failed to verify with keys: failed to process AKV signature: unsupported public key type: *ecdh.PublicKey", + expectedResultMessagePrefix: "Failed to validate the Cosign signature", + expectedErrorReason: "unsupported public key type [*ecdh.PublicKey]", }, { name: "invalid RSA key size for AKV", @@ -700,8 +721,8 @@ mmBwUAwwW0Uc+Nt3bDOCiB1nUsICv1ry blobDigest: validSignatureBlob, }, }, - expectedResultMessagePrefix: "Verification failed", - expectedErrorReason: "failed to verify with keys: failed to process AKV signature: RSA key check: unsupported key size: 128", + expectedResultMessagePrefix: "Failed to validate the Cosign signature", + expectedErrorReason: "RSA key check: unsupported key size: 128", }, { name: "invalid ECDSA curve type for AKV", @@ -732,8 +753,8 @@ mmBwUAwwW0Uc+Nt3bDOCiB1nUsICv1ry blobDigest: validSignatureBlob, }, }, - expectedResultMessagePrefix: "Verification failed", - expectedErrorReason: "failed to verify with keys: failed to process AKV signature: ECDSA key check: unsupported key curve: P-224", + expectedResultMessagePrefix: "Failed to validate the Cosign signature", + expectedErrorReason: "ECDSA key check: unsupported key curve [P-224]", }, { name: "valid hash: 256 keysize: 2048 RSA key AKV", @@ -965,8 +986,8 @@ mmBwUAwwW0Uc+Nt3bDOCiB1nUsICv1ry "sha256:d1226e36bc8502978324cb2cb2116c6aa48edb2ea8f15b1c6f6f256ed43388f6": []byte(`{"critical":{"identity":{"docker-reference":"wabbitnetworks.azurecr.io/test/cosign-image"},"image":{"docker-manifest-digest":"sha256:623621b56649b5e0c2c7cf3ffd987932f8f9a5a01036e00d6f3ae9480087621c"},"type":"cosign container image signature"},"optional":null}`), }, }, - expectedResultMessagePrefix: "Verification failed", - expectedErrorReason: "failed to parse static signature opts: failed to unmarshal bundle from blob payload: illegal base64 data at input byte 91", + expectedResultMessagePrefix: "Failed to validate the Cosign signature:", + expectedErrorReason: "failed to unmarshal bundle from blob payload: illegal base64 data at input byte 91", }, } @@ -1051,3 +1072,81 @@ func TestVerificationMessage(t *testing.T) { }) } } + +func TestProcessAKVSignature_RSAKey(t *testing.T) { + tests := []struct { + name string + keySize int + encodedSig string + expectedErr bool + expectedHashType crypto.Hash + expectedSigOut bool + }{ + { + name: "RSA 2048 bits", + keySize: 256, + expectedErr: false, + expectedHashType: crypto.SHA256, + expectedSigOut: true, + }, + { + name: "RSA 3072 bits", + keySize: 384, + expectedErr: false, + expectedHashType: crypto.SHA384, + expectedSigOut: true, + }, + { + name: "RSA 4096 bits", + keySize: 512, + expectedErr: false, + expectedHashType: crypto.SHA512, + expectedSigOut: true, + }, + { + name: "Unsupported key size", + keySize: 128, + expectedErr: true, + }, + { + name: "Invalid base64 encoded signature", + keySize: 256, + encodedSig: "ThisIsNot@ValidBase64%String!", + expectedErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Create a mock RSA public key + privateKey, err := rsa.GenerateKey(rand.Reader, tt.keySize*8) + if err != nil { + t.Fatalf("Failed to generate RSA key: %v", err) + } + rsaPublicKey := &privateKey.PublicKey + + // Mock the signature as base64 encoded string + sig := "dummy_signature" + encodedSig := base64.StdEncoding.EncodeToString([]byte(sig)) + if tt.encodedSig != "" { + encodedSig = tt.encodedSig + } + + // Process the signature + hashType, sigOut, err := processAKVSignature(encodedSig, nil, rsaPublicKey, []byte("test payload"), []static.Option{}) + + if tt.expectedErr { + if err == nil { + t.Fatalf("Expected error but got nil") + } + } else { + if hashType != tt.expectedHashType { + t.Fatalf("Expected hash type %v but got %v", tt.expectedHashType, hashType) + } + if tt.expectedSigOut != (sigOut != nil) { + t.Fatalf("Expected signature output to be %v but got %v", tt.expectedSigOut, sigOut) + } + } + }) + } +} diff --git a/pkg/verifier/cosign/trustpolicies.go b/pkg/verifier/cosign/trustpolicies.go index 4858cfd47..6ba5521ed 100644 --- a/pkg/verifier/cosign/trustpolicies.go +++ b/pkg/verifier/cosign/trustpolicies.go @@ -35,14 +35,14 @@ var validScopeRegex = regexp.MustCompile(`^[a-z0-9\.\-:@\/]*\*?$`) // CreateTrustPolicies creates a set of trust policies from the given configuration func CreateTrustPolicies(configs []TrustPolicyConfig, verifierName string) (*TrustPolicies, error) { if len(configs) == 0 { - return nil, re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithPluginName(verifierName).WithDetail("failed to create trust policies: no policies found") + return nil, re.ErrorCodeConfigInvalid.WithDetail("Failed to create trust policies: policy configuration not found").WithRemediation("Ensure that the trust policy configuration is correct.") } policies := make([]TrustPolicy, 0, len(configs)) names := make(map[string]struct{}) for _, policyConfig := range configs { if _, ok := names[policyConfig.Name]; ok { - return nil, re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithPluginName(verifierName).WithDetail(fmt.Sprintf("failed to create trust policies: duplicate policy name %s", policyConfig.Name)) + return nil, re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("Failed to create trust policies: duplicate policy name %s", policyConfig.Name)).WithRemediation("Ensure that trust policy names are unique.") } names[policyConfig.Name] = struct{}{} policy, err := CreateTrustPolicy(policyConfig, verifierName) @@ -86,7 +86,7 @@ func (tps *TrustPolicies) GetScopedPolicy(reference string) (TrustPolicy, error) if globalPolicy != nil { return globalPolicy, nil } - return nil, re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithDetail(fmt.Sprintf("failed to get trust policy: no policy found for reference %s", reference)) + return nil, re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("No policy found for the artifact %s", reference)) } // validateScopes validates the scopes in the trust policies @@ -97,16 +97,16 @@ func validateScopes(policies []TrustPolicy) error { policyName := policy.GetName() scopes := policy.GetScopes() if len(scopes) == 0 { - return re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithDetail(fmt.Sprintf("failed to create trust policies: no scopes defined for trust policy %s", policyName)) + return re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("Failed to create trust policies: scope parameter is required for trust policy %s", policyName)) } // check for global wildcard character along with other scopes in the same policy if len(scopes) > 1 && slices.Contains(scopes, string(GlobalWildcardCharacter)) { - return re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithDetail(fmt.Sprintf("failed to create trust policies: global wildcard character %c cannot be used with other scopes within the same trust policy %s", GlobalWildcardCharacter, policyName)) + return re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("Failed to create trust policies: global wildcard character %c cannot be used with other scopes within the same trust policy %s", GlobalWildcardCharacter, policyName)) } // check for duplicate global wildcard characters across policies if slices.Contains(scopes, string(GlobalWildcardCharacter)) { if hasGlobalWildcard { - return re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithDetail(fmt.Sprintf("failed to create trust policies: global wildcard character %c can only be used once", GlobalWildcardCharacter)) + return re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("Failed to create trust policies: global wildcard character %c can only be used once", GlobalWildcardCharacter)) } hasGlobalWildcard = true continue @@ -114,15 +114,15 @@ func validateScopes(policies []TrustPolicy) error { for _, scope := range scopes { // check for empty scope if scope == "" { - return re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithDetail(fmt.Sprintf("failed to create trust policies: scope defined is empty for trust policy %s", policyName)) + return re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("Failed to create trust policies: scope value cannot be empty in trust policy %s", policyName)) } // check scope is formatted correctly if !validScopeRegex.MatchString(scope) { - return re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithDetail(fmt.Sprintf("failed to create trust policies: invalid scope %s for trust policy %s", scope, policyName)) + return re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("Failed to create trust policies: invalid scope %s for trust policy %s", scope, policyName)) } // check for duplicate scopes if _, ok := scopesMap[scope]; ok { - return re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithDetail(fmt.Sprintf("failed to create trust policies: duplicate scope %s for trust policy %s", scope, policyName)) + return re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("Failed to create trust policies: duplicate scope %s for trust policy %s", scope, policyName)) } // check wildcard overlaps for existingScope := range scopesMap { @@ -144,7 +144,7 @@ func validateScopes(policies []TrustPolicy) error { isConflict = strings.HasPrefix(existingScope, trimmedScope) } if isConflict { - return re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithDetail(fmt.Sprintf("failed to create trust policies: overlapping scopes %s and %s for trust policy %s", scope, existingScope, policyName)) + return re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("Failed to create trust policies: overlapping scopes %s and %s for trust policy %s", scope, existingScope, policyName)) } } scopesMap[scope] = struct{}{} diff --git a/pkg/verifier/cosign/trustpolicy.go b/pkg/verifier/cosign/trustpolicy.go index c49b86aa8..8d20a7320 100644 --- a/pkg/verifier/cosign/trustpolicy.go +++ b/pkg/verifier/cosign/trustpolicy.go @@ -97,7 +97,7 @@ func CreateTrustPolicy(config TrustPolicyConfig, verifierName string) (TrustPoli config.Version = DefaultTrustPolicyConfigVersion } - if err := validate(config, verifierName); err != nil { + if err := validate(config); err != nil { return nil, err } @@ -107,7 +107,7 @@ func CreateTrustPolicy(config TrustPolicyConfig, verifierName string) (TrustPoli if keyConfig.File != "" { pubKey, err := loadKeyFromPath(keyConfig.File) if err != nil { - return nil, re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithPluginName(verifierName).WithDetail(fmt.Sprintf("trust policy %s failed: failed to load key from file %s", config.Name, keyConfig.File)).WithError(err) + return nil, re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("Invalid trust policy [%s]: failed to load the key from file %s", config.Name, keyConfig.File)).WithError(err).WithRemediation("Ensure that the key file path is correct and public key is correctly saved.") } keyMap[PKKey{Provider: fileProviderName, Name: keyConfig.File}] = keymanagementprovider.PublicKey{Key: pubKey, ProviderType: fileProviderName} } @@ -155,13 +155,13 @@ func (tp *trustPolicy) GetKeys(ctx context.Context, _ string) (map[PKKey]keymana // get the key management provider resource which contains a map of keys kmpResource, kmpErr := keymanagementprovider.GetKeysFromMap(ctx, keyConfig.Provider) if kmpErr != nil { - return nil, re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithPluginName(tp.verifierName).WithDetail(fmt.Sprintf("trust policy [%s] failed to access key management provider %s, err: %s", tp.config.Name, keyConfig.Provider, kmpErr.Error())) + return nil, re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("Invalid trust policy [%s]: failed to access key management provider %s", tp.config.Name, keyConfig.Provider)).WithError(kmpErr) } // get a specific key from the key management provider resource if keyConfig.Name != "" { pubKey, exists := kmpResource[keymanagementprovider.KMPMapKey{Name: keyConfig.Name, Version: keyConfig.Version}] if !exists { - return nil, re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithPluginName(tp.verifierName).WithDetail(fmt.Sprintf("trust policy %s failed: key %s with version %s not found in key management provider %s", tp.config.Name, keyConfig.Name, keyConfig.Version, keyConfig.Provider)) + return nil, re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("Invalid trust policy [%s]: key %s with version %s not found in key management provider %s", tp.config.Name, keyConfig.Name, keyConfig.Version, keyConfig.Provider)) } keyMap[PKKey{Provider: keyConfig.Provider, Name: keyConfig.Name, Version: keyConfig.Version}] = pubKey } else { @@ -188,12 +188,12 @@ func (tp *trustPolicy) GetCosignOpts(ctx context.Context) (cosign.CheckOpts, err // create the rekor client cosignOpts.RekorClient, err = rekor.NewClient(tp.config.RekorURL) if err != nil { - return cosignOpts, fmt.Errorf("failed to create Rekor client from URL %s: %w", tp.config.RekorURL, err) + return cosignOpts, re.ErrorCodeConfigInvalid.WithDetail(fmt.Errorf("Failed to create Rekor client from URL %s", tp.config.RekorURL)).WithRemediation("Ensure that the Rekor URL is valid.").WithError(err) } // Fetches the Rekor public keys from the Rekor server cosignOpts.RekorPubKeys, err = cosign.GetRekorPubs(ctx) if err != nil { - return cosignOpts, fmt.Errorf("failed to fetch Rekor public keys: %w", err) + return cosignOpts, re.ErrorCodeVerifyPluginFailure.WithDetail("Failed to fetch Rekor public keys").WithRemediation(fmt.Sprintf("Please check if the Rekor server %s is available", tp.config.RekorURL)).WithError(err) } } else { cosignOpts.IgnoreTlog = true @@ -203,20 +203,20 @@ func (tp *trustPolicy) GetCosignOpts(ctx context.Context) (cosign.CheckOpts, err if tp.isKeyless { roots, err := fulcio.GetRoots() if err != nil || roots == nil { - return cosignOpts, fmt.Errorf("failed to get fulcio roots: %w", err) + return cosignOpts, re.ErrorCodeVerifyPluginFailure.WithDetail("Failed to get fulcio root").WithError(err).WithRemediation("Please check if Fulcio is available") } cosignOpts.RootCerts = roots if tp.config.Keyless.CTLogVerify != nil && *tp.config.Keyless.CTLogVerify { cosignOpts.CTLogPubKeys, err = cosign.GetCTLogPubs(ctx) if err != nil { - return cosignOpts, fmt.Errorf("failed to fetch certificate transparency log public keys: %w", err) + return cosignOpts, re.ErrorCodeVerifyPluginFailure.WithDetail("Failed to fetch certificate transparency log public keys").WithError(err).WithRemediation("Please check if TUF root is available") } } else { cosignOpts.IgnoreSCT = true } cosignOpts.IntermediateCerts, err = fulcio.GetIntermediates() if err != nil { - return cosignOpts, fmt.Errorf("failed to get fulcio intermediate certificates: %w", err) + return cosignOpts, re.ErrorCodeVerifyPluginFailure.WithDetail("Failed to get fulcio intermediate certificates").WithError(err).WithRemediation("Please check if Fulcio is available") } // Set the certificate identity and issuer for keyless verification cosignOpts.Identities = []cosign.Identity{ @@ -234,42 +234,42 @@ func (tp *trustPolicy) GetCosignOpts(ctx context.Context) (cosign.CheckOpts, err // validate checks if the trust policy configuration is valid // returns an error if the configuration is invalid -func validate(config TrustPolicyConfig, verifierName string) error { +func validate(config TrustPolicyConfig) error { // check if the trust policy version is supported if !slices.Contains(SupportedTrustPolicyConfigVersions, config.Version) { - return re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithPluginName(verifierName).WithDetail(fmt.Sprintf("trust policy %s failed: unsupported version %s", config.Name, config.Version)) + return re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("Invalid trust policy %s: unsupported version %s", config.Name, config.Version)).WithRemediation(fmt.Sprintf("Supported versions are: %v", SupportedTrustPolicyConfigVersions)) } if config.Name == "" { - return re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithPluginName(verifierName).WithDetail("missing trust policy name") + return re.ErrorCodeConfigInvalid.WithDetail("name parameter is required in trust policy configuration").WithRemediation("Please provide a name for the trust policy.") } if len(config.Scopes) == 0 { - return re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithPluginName(verifierName).WithDetail(fmt.Sprintf("trust policy %s failed: no scopes defined", config.Name)) + return re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("scopes parameter is required in trust policy configuration %s", config.Name)).WithRemediation("Please provide at least one scope for the trust policy.") } // keys or keyless must be defined if len(config.Keys) == 0 && config.Keyless == (KeylessConfig{}) { - return re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithPluginName(verifierName).WithDetail(fmt.Sprintf("trust policy %s failed: no keys defined and keyless section not configured", config.Name)) + return re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("keys or keyless parameter is required in trust policy configuration %s", config.Name)) } // only one of keys or keyless can be defined if len(config.Keys) > 0 && config.Keyless != (KeylessConfig{}) { - return re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithPluginName(verifierName).WithDetail(fmt.Sprintf("trust policy %s failed: both keys and keyless sections are defined", config.Name)) + return re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("Only one of keys or keyless parameter is required in trust policy configuration %s", config.Name)) } for _, keyConfig := range config.Keys { // check if the key is defined by file path or by key management provider if keyConfig.File == "" && keyConfig.Provider == "" { - return re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithPluginName(verifierName).WithDetail(fmt.Sprintf("trust policy %s failed: key management provider name is required when not using file path", config.Name)) + return re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("Invalid trust policy %s: key management provider name is required when not using file path", config.Name)) } // both file path and key management provider cannot be defined together if keyConfig.File != "" && keyConfig.Provider != "" { - return re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithPluginName(verifierName).WithDetail(fmt.Sprintf("trust policy %s failed: 'name' and 'file' cannot be configured together", config.Name)) + return re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("Invalid trust policy %s: 'name' and 'file' cannot be configured together", config.Name)) } // key name is required when key version is defined if keyConfig.Version != "" && keyConfig.Name == "" { - return re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithPluginName(verifierName).WithDetail(fmt.Sprintf("trust policy %s failed: key name is required when key version is defined", config.Name)) + return re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("Invalid trust policy %s: key name is required when key version is defined", config.Name)) } } @@ -277,19 +277,19 @@ func validate(config TrustPolicyConfig, verifierName string) error { if config.Keyless != (KeylessConfig{}) { // validate certificate identity specified if config.Keyless.CertificateIdentity == "" && config.Keyless.CertificateIdentityRegExp == "" { - return re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithPluginName(verifierName).WithDetail(fmt.Sprintf("trust policy %s failed: certificate identity or identity regex pattern is required", config.Name)) + return re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("Invalid trust policy %s: certificate identity or identity regex pattern is required", config.Name)) } // validate certificate OIDC issuer specified if config.Keyless.CertificateOIDCIssuer == "" && config.Keyless.CertificateOIDCIssuerRegExp == "" { - return re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithPluginName(verifierName).WithDetail(fmt.Sprintf("trust policy %s failed: certificate OIDC issuer or issuer regex pattern is required", config.Name)) + return re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("Invalid trust policy %s: certificate OIDC issuer or issuer regex pattern is required", config.Name)) } // validate only expression or value is specified for certificate identity if config.Keyless.CertificateIdentity != "" && config.Keyless.CertificateIdentityRegExp != "" { - return re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithPluginName(verifierName).WithDetail(fmt.Sprintf("trust policy %s failed: only one of certificate identity or identity regex pattern should be specified", config.Name)) + return re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("Invalid trust policy %s: only one of certificate identity or identity regex pattern should be specified", config.Name)) } // validate only expression or value is specified for certificate OIDC issuer if config.Keyless.CertificateOIDCIssuer != "" && config.Keyless.CertificateOIDCIssuerRegExp != "" { - return re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithPluginName(verifierName).WithDetail(fmt.Sprintf("trust policy %s failed: only one of certificate OIDC issuer or issuer regex pattern should be specified", config.Name)) + return re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("Invalid trust policy %s: only one of certificate OIDC issuer or issuer regex pattern should be specified", config.Name)) } } diff --git a/pkg/verifier/cosign/trustpolicy_test.go b/pkg/verifier/cosign/trustpolicy_test.go index ea720c50e..65dcb84da 100644 --- a/pkg/verifier/cosign/trustpolicy_test.go +++ b/pkg/verifier/cosign/trustpolicy_test.go @@ -21,6 +21,7 @@ import ( "crypto/ecdsa" "crypto/x509" "fmt" + "os" "testing" ctxUtils "github.com/ratify-project/ratify/internal/context" @@ -204,6 +205,20 @@ func TestGetKeys(t *testing.T) { }, wantErr: true, }, + { + name: "access nonexistent key from KMP", + cfg: TrustPolicyConfig{ + Name: "test", + Scopes: []string{"*"}, + Keys: []KeyConfig{ + { + Provider: "ns/kmp", + Name: "nonexistent", + }, + }, + }, + wantErr: true, + }, { name: "valid KMP", cfg: TrustPolicyConfig{ @@ -423,7 +438,7 @@ func TestValidate(t *testing.T) { for _, tt := range tc { t.Run(tt.name, func(t *testing.T) { - actual := validate(tt.policyConfig, "test-verifier") + actual := validate(tt.policyConfig) if (actual != nil) != tt.wantErr { t.Fatalf("expected %v, got %v", tt.wantErr, actual) } @@ -447,3 +462,76 @@ func TestLoadKeyFromPath(t *testing.T) { t.Fatalf("expected ecdsa.PublicKey, got %v", keyType) } } + +func TestGetCosignOpts(t *testing.T) { + testCases := []struct { + name string + tlogVerify bool + rekorURL string + rekorPubKeyEnv string + isKeyless bool + CTLogVerify bool + CTLogPubKeyEnv string + expectedErr bool + }{ + { + name: "invalid rekor url", + tlogVerify: true, + rekorURL: string([]byte{0x7f}), + expectedErr: true, + }, + { + name: "failed to get rekor public key", + tlogVerify: true, + rekorURL: "https://rekor.sigstore.dev", + rekorPubKeyEnv: "invalid", + expectedErr: true, + }, + { + name: "failed to get CT log public key", + tlogVerify: false, + isKeyless: true, + CTLogVerify: true, + CTLogPubKeyEnv: "invalid", + expectedErr: true, + }, + } + + for _, tc := range testCases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + if tc.rekorPubKeyEnv != "" { + val := os.Getenv("SIGSTORE_REKOR_PUBLIC_KEY") + os.Setenv("SIGSTORE_REKOR_PUBLIC_KEY", tc.rekorPubKeyEnv) + t.Cleanup(func() { + os.Setenv("SIGSTORE_REKOR_PUBLIC_KEY", val) + }) + } + + if tc.CTLogPubKeyEnv != "" { + val := os.Getenv("SIGSTORE_CT_LOG_PUBLIC_KEY_FILE") + os.Setenv("SIGSTORE_CT_LOG_PUBLIC_KEY_FILE", tc.CTLogPubKeyEnv) + t.Cleanup(func() { + os.Setenv("SIGSTORE_CT_LOG_PUBLIC_KEY_FILE", val) + }) + } + + tp := trustPolicy{ + config: TrustPolicyConfig{ + TLogVerify: &tc.tlogVerify, + RekorURL: tc.rekorURL, + Keyless: KeylessConfig{ + CTLogVerify: &tc.CTLogVerify, + }, + }, + isKeyless: tc.isKeyless, + } + _, err := tp.GetCosignOpts(context.Background()) + if tc.expectedErr { + if err == nil { + t.Fatalf("expected error, got nil") + } + } + }) + } +} diff --git a/pkg/verifier/factory/factory.go b/pkg/verifier/factory/factory.go index a23bdcfde..fdc6e57a8 100644 --- a/pkg/verifier/factory/factory.go +++ b/pkg/verifier/factory/factory.go @@ -53,12 +53,12 @@ func Register(name string, factory VerifierFactory) { // namespace is only applicable in K8s environment, namespace is appended to the certstore of the truststore so it is uniquely identifiable in a cluster env // the first element of pluginBinDir will be used as the plugin directory func CreateVerifierFromConfig(verifierConfig config.VerifierConfig, configVersion string, pluginBinDir []string, namespace string) (verifier.ReferenceVerifier, error) { - // in cli mode both `type` and `name`` are read from config, if `type` is not specified, `name` is used as `type` + // in cli mode both `type` and `name` are read from config, if `type` is not specified, `name` is used as `type` var verifierTypeStr string if value, ok := verifierConfig[types.Name]; ok { verifierTypeStr = value.(string) } else { - return nil, re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithDetail(fmt.Sprintf("failed to find verifier name in the verifier config with key %s", "name")) + return nil, re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("The name field is required in the Verifier configuration: %+v", verifierConfig)) } if value, ok := verifierConfig[types.Type]; ok { @@ -66,7 +66,7 @@ func CreateVerifierFromConfig(verifierConfig config.VerifierConfig, configVersio } if strings.ContainsRune(verifierTypeStr, os.PathSeparator) { - return nil, re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithDetail(fmt.Sprintf("invalid plugin name for a verifier: %s", verifierTypeStr)) + return nil, re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("Invalid name [%s] in the Verifier configuration, [%v] is disallowed", verifierTypeStr, os.PathSeparator)) } // if source is specified, download the plugin @@ -74,13 +74,13 @@ func CreateVerifierFromConfig(verifierConfig config.VerifierConfig, configVersio if featureflag.DynamicPlugins.Enabled { source, err := pluginCommon.ParsePluginSource(source) if err != nil { - return nil, re.ErrorCodeConfigInvalid.NewError(re.Verifier, "", re.EmptyLink, err, "failed to parse plugin source", re.HideStackTrace) + return nil, re.ErrorCodeConfigInvalid.WithDetail("Failed to parse the plugin source").WithError(err) } targetPath := path.Join(pluginBinDir[0], verifierTypeStr) err = pluginCommon.DownloadPlugin(source, targetPath) if err != nil { - return nil, re.ErrorCodeDownloadPluginFailure.NewError(re.Verifier, "", re.EmptyLink, err, "failed to download plugin", re.HideStackTrace) + return nil, re.ErrorCodeDownloadPluginFailure.WithDetail("Failed to download the plugin from the source").WithError(err) } logrus.Infof("downloaded verifier plugin %s from %s to %s", verifierTypeStr, source.Artifact, targetPath) } else { @@ -94,7 +94,7 @@ func CreateVerifierFromConfig(verifierConfig config.VerifierConfig, configVersio } if _, err := pluginCommon.FindInPaths(verifierTypeStr, pluginBinDir); err != nil { - return nil, re.ErrorCodePluginNotFound.NewError(re.Verifier, "", re.EmptyLink, err, "plugin not found", re.HideStackTrace) + return nil, re.ErrorCodePluginNotFound.WithDetail(fmt.Sprintf("Verifier plugin %s not found", verifierTypeStr)).WithError(err).WithRemediation("Please ensure that the correct type is specified for the built-in Verifier configuration or the custom Verifier plugin is configured.") } pluginVersion := configVersion @@ -113,11 +113,11 @@ func CreateVerifiersFromConfig(verifiersConfig config.VerifiersConfig, defaultPl err := validateVerifiersConfig(&verifiersConfig) if err != nil { - return nil, re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithError(err) + return nil, re.ErrorCodeConfigInvalid.WithError(err) } if len(verifiersConfig.Verifiers) == 0 { - return nil, re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithDetail("verifiers config should have at least one verifier") + return nil, re.ErrorCodeConfigInvalid.WithDetail("The configuration for verifier.plugins must include at least one plugin") } verifiers := make([]verifier.ReferenceVerifier, 0) @@ -131,7 +131,7 @@ func CreateVerifiersFromConfig(verifiersConfig config.VerifiersConfig, defaultPl for _, verifierConfig := range verifiersConfig.Verifiers { verifier, err := CreateVerifierFromConfig(verifierConfig, verifiersConfig.Version, verifiersConfig.PluginBinDirs, namespace) if err != nil { - return nil, re.ErrorCodePluginInitFailure.WithComponentType(re.Verifier).WithError(err) + return nil, re.ErrorCodePluginInitFailure.WithError(err) } verifiers = append(verifiers, verifier) } diff --git a/pkg/verifier/factory/factory_test.go b/pkg/verifier/factory/factory_test.go index 273e76b00..7b839e0e5 100644 --- a/pkg/verifier/factory/factory_test.go +++ b/pkg/verifier/factory/factory_test.go @@ -22,6 +22,7 @@ import ( "github.com/ratify-project/ratify/internal/constants" "github.com/ratify-project/ratify/pkg/common" + "github.com/ratify-project/ratify/pkg/featureflag" "github.com/ratify-project/ratify/pkg/ocispecs" "github.com/ratify-project/ratify/pkg/referrerstore" @@ -103,6 +104,21 @@ func TestCreateVerifiersFromConfig_BuiltInVerifiers_ReturnsExpected(t *testing.T } } +func TestCreateVerifiersFromConfig_InvalidConfig_ReturnsErr(t *testing.T) { + verifierConfig := map[string]interface{}{ + "name": "test-verifier-0", + } + verifiersConfig := config.VerifiersConfig{ + Verifiers: []config.VerifierConfig{verifierConfig}, + } + + _, err := CreateVerifiersFromConfig(verifiersConfig, "test/dir", constants.EmptyNamespace) + + if err == nil { + t.Fatalf("expected to have an error") + } +} + func TestCreateVerifiersFromConfig_PluginVerifiers_ReturnsExpected(t *testing.T) { dirPath, err := utils.CreatePlugin("sample") if err != nil { @@ -137,3 +153,83 @@ func TestCreateVerifiersFromConfig_PluginVerifiers_ReturnsExpected(t *testing.T) t.Fatalf("type assertion failed expected a plugin in verifier") } } + +func TestCreateVerifiersFromConfig_EmptyVerifiers_ReturnsErr(t *testing.T) { + verifiersConfig := config.VerifiersConfig{} + + _, err := CreateVerifiersFromConfig(verifiersConfig, "test/dir", "") + + if err == nil { + t.Fatalf("expected to have an error") + } +} + +func TestCreateVerifierFromConfig(t *testing.T) { + tests := []struct { + name string + verifierConfig config.VerifierConfig + configVersion string + pluginBinDir []string + namespace string + dynamicPluginEnabled bool + expectedErr bool + }{ + { + name: "missing name", + verifierConfig: config.VerifierConfig{}, + expectedErr: true, + }, + { + name: "verifier type contains path separator", + verifierConfig: config.VerifierConfig{ + "name": "test/verifier", + }, + expectedErr: true, + }, + { + name: "external verifier plugin not found", + verifierConfig: config.VerifierConfig{ + "name": "not-found", + }, + pluginBinDir: []string{"test/path"}, + expectedErr: true, + }, + { + name: "parse plugin source failed", + verifierConfig: config.VerifierConfig{ + "name": "test-verifier", + "source": "invalid", + }, + dynamicPluginEnabled: true, + expectedErr: true, + }, + { + name: "download plugin failed", + verifierConfig: config.VerifierConfig{ + "name": "test-verifier", + "source": map[string]interface{}{ + "artifact": "invalid", + }, + }, + pluginBinDir: []string{"test/path"}, + dynamicPluginEnabled: true, + expectedErr: true, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + if tt.dynamicPluginEnabled { + dynamicVal := featureflag.DynamicPlugins.Enabled + t.Cleanup(func() { featureflag.DynamicPlugins.Enabled = dynamicVal }) + featureflag.DynamicPlugins.Enabled = true + } + + _, err := CreateVerifierFromConfig(tt.verifierConfig, tt.configVersion, tt.pluginBinDir, tt.namespace) + if tt.expectedErr != (err != nil) { + t.Fatalf("expected error %v, actual %v", tt.expectedErr, err) + } + }) + } +} diff --git a/pkg/verifier/notation/certstoresbytype.go b/pkg/verifier/notation/certstoresbytype.go index a2ab8454e..a5a9228bf 100644 --- a/pkg/verifier/notation/certstoresbytype.go +++ b/pkg/verifier/notation/certstoresbytype.go @@ -73,18 +73,18 @@ func newCertStoreByType(confInNewFormat verificationCertStores) (certStores, err s[certStoreType(certstoretype)] = make(map[string][]string) parsedStoreData, ok := storeData.(map[string]interface{}) if !ok { - return nil, fmt.Errorf("certStores: %s assertion to type verificationCertStores failed", storeData) + return nil, fmt.Errorf("the verificationCertStores configuration is invalid: %+v", confInNewFormat) } for storeName, certProviderList := range parsedStoreData { var certProviderNames []string parsedCertProviders, ok := certProviderList.([]interface{}) if !ok { - return nil, fmt.Errorf("certProviderList: %s assertion to type []interface{} failed", certProviderList) + return nil, fmt.Errorf("the verificationCertStores configuration is invalid: %+v", confInNewFormat) } for _, certProvider := range parsedCertProviders { certProviderName, ok := certProvider.(string) if !ok { - return nil, fmt.Errorf("certProvider: %s assertion to type string failed", certProvider) + return nil, fmt.Errorf("the verificationCertStores configuration is invalid: %+v", confInNewFormat) } certProviderNames = append(certProviderNames, certProviderName) } diff --git a/pkg/verifier/notation/notation.go b/pkg/verifier/notation/notation.go index 9bca58342..f25b21c10 100644 --- a/pkg/verifier/notation/notation.go +++ b/pkg/verifier/notation/notation.go @@ -93,7 +93,7 @@ func init() { } func (f *notationPluginVerifierFactory) Create(_ string, verifierConfig config.VerifierConfig, pluginDirectory string, namespace string) (verifier.ReferenceVerifier, error) { - logger.GetLogger(context.Background(), logOpt).Debugf("creating notation with config %v, namespace '%v'", verifierConfig, namespace) + logger.GetLogger(context.Background(), logOpt).Debugf("creating Notation verifier with config %v, namespace '%v'", verifierConfig, namespace) verifierName := fmt.Sprintf("%s", verifierConfig[types.Name]) verifierTypeStr := "" if _, ok := verifierConfig[types.Type]; ok { @@ -101,12 +101,12 @@ func (f *notationPluginVerifierFactory) Create(_ string, verifierConfig config.V } conf, err := parseVerifierConfig(verifierConfig, namespace) if err != nil { - return nil, re.ErrorCodeConfigInvalid.WithComponentType(re.Verifier).WithPluginName(verifierName) + return nil, re.ErrorCodePluginInitFailure.WithDetail("Failed to create the Notation Verifier").WithError(err) } verifyService, err := getVerifierService(conf, pluginDirectory) if err != nil { - return nil, re.ErrorCodePluginInitFailure.WithComponentType(re.Verifier).WithPluginName(verifierName).WithError(err) + return nil, re.ErrorCodePluginInitFailure.WithDetail("Failed to create the Notation Verifier").WithError(err) } artifactTypes := strings.Split(conf.ArtifactTypes, ",") @@ -143,22 +143,21 @@ func (v *notationPluginVerifier) Verify(ctx context.Context, subjectDesc, err := store.GetSubjectDescriptor(ctx, subjectReference) if err != nil { - return verifier.VerifierResult{IsSuccess: false}, re.ErrorCodeGetSubjectDescriptorFailure.NewError(re.ReferrerStore, store.Name(), re.EmptyLink, err, fmt.Sprintf("failed to resolve subject: %+v", subjectReference), re.HideStackTrace) + return verifier.VerifierResult{IsSuccess: false}, re.ErrorCodeVerifyReferenceFailure.WithDetail(fmt.Sprintf("Failed to validate the Notation signature of the artifact: %+v", subjectReference)).WithError(err) } referenceManifest, err := store.GetReferenceManifest(ctx, subjectReference, referenceDescriptor) if err != nil { - return verifier.VerifierResult{IsSuccess: false}, re.ErrorCodeGetReferenceManifestFailure.NewError(re.ReferrerStore, store.Name(), re.EmptyLink, err, fmt.Sprintf("failed to resolve reference manifest: %+v", referenceDescriptor), re.HideStackTrace) + return verifier.VerifierResult{IsSuccess: false}, re.ErrorCodeVerifyReferenceFailure.WithDetail(fmt.Sprintf("Failed to validate the Notation signature: %+v", referenceDescriptor)).WithError(err) } if len(referenceManifest.Blobs) != 1 { - return verifier.VerifierResult{IsSuccess: false}, re.ErrorCodeVerifyPluginFailure.WithDetail(fmt.Sprintf("Notation signature manifest requires exactly one signature envelope blob, got %d", len(referenceManifest.Blobs))).WithRemediation(fmt.Sprintf("Please inspect the artifact [%s@%s] is correctly signed by Notation signer", subjectReference.Path, referenceDescriptor.Digest.String())) + return verifier.VerifierResult{IsSuccess: false}, re.ErrorCodeVerifyReferenceFailure.WithDetail(fmt.Sprintf("Notation signature manifest requires exactly one signature envelope blob, got %d", len(referenceManifest.Blobs))).WithRemediation(fmt.Sprintf("Please inspect the artifact [%s@%s] is correctly signed by Notation signer", subjectReference.Path, referenceDescriptor.Digest.String())) } - blobDesc := referenceManifest.Blobs[0] refBlob, err := store.GetBlobContent(ctx, subjectReference, blobDesc.Digest) if err != nil { - return verifier.VerifierResult{IsSuccess: false}, re.ErrorCodeGetBlobContentFailure.NewError(re.ReferrerStore, store.Name(), re.EmptyLink, err, fmt.Sprintf("failed to get blob content of digest: %s", blobDesc.Digest), re.HideStackTrace) + return verifier.VerifierResult{IsSuccess: false}, re.ErrorCodeVerifyReferenceFailure.WithDetail(fmt.Sprintf("Failed to validate the Notation signature of the artifact: %+v", subjectReference)).WithError(err) } // TODO: notation verify API only accepts digested reference now. @@ -166,7 +165,7 @@ func (v *notationPluginVerifier) Verify(ctx context.Context, subjectRef := fmt.Sprintf("%s@%s", subjectReference.Path, subjectReference.Digest.String()) outcome, err := v.verifySignature(ctx, subjectRef, blobDesc.MediaType, subjectDesc.Descriptor, refBlob) if err != nil { - return verifier.VerifierResult{IsSuccess: false, Extensions: extensions}, re.ErrorCodeVerifyPluginFailure.NewError(re.Verifier, v.name, re.NotationTsgLink, err, "failed to verify signature of digest", re.HideStackTrace) + return verifier.VerifierResult{IsSuccess: false, Extensions: extensions}, re.ErrorCodeVerifyReferenceFailure.WithDetail(fmt.Sprintf("Failed to validate the Notation signature: %+v", referenceDescriptor)).WithError(err) } // Note: notation verifier already validates certificate chain is not empty. @@ -174,7 +173,7 @@ func (v *notationPluginVerifier) Verify(ctx context.Context, extensions["Issuer"] = cert.Issuer.String() extensions["SN"] = cert.Subject.String() - return verifier.NewVerifierResult("", v.name, v.verifierType, "Signature verification success", true, nil, extensions), nil + return verifier.NewVerifierResult("", v.name, v.verifierType, "Notation signature verification success", true, nil, extensions), nil } func getVerifierService(conf *NotationPluginVerifierConfig, pluginDirectory string) (notation.Verifier, error) { @@ -182,7 +181,11 @@ func getVerifierService(conf *NotationPluginVerifierConfig, pluginDirectory stri if err != nil { return nil, err } - return notationVerifier.New(&conf.TrustPolicyDoc, store, NewRatifyPluginManager(pluginDirectory)) + verifier, err := notationVerifier.New(&conf.TrustPolicyDoc, store, NewRatifyPluginManager(pluginDirectory)) + if err != nil { + return nil, re.ErrorCodePluginInitFailure.WithDetail("Failed to create the Notation Verifier").WithError(err) + } + return verifier, nil } func (v *notationPluginVerifier) verifySignature(ctx context.Context, subjectRef, mediaType string, subjectDesc oci.Descriptor, refBlob []byte) (*notation.VerificationOutcome, error) { @@ -196,16 +199,15 @@ func (v *notationPluginVerifier) verifySignature(ctx context.Context, subjectRef } func parseVerifierConfig(verifierConfig config.VerifierConfig, _ string) (*NotationPluginVerifierConfig, error) { - verifierName := verifierConfig[types.Name].(string) conf := &NotationPluginVerifierConfig{} verifierConfigBytes, err := json.Marshal(verifierConfig) if err != nil { - return nil, re.ErrorCodeConfigInvalid.NewError(re.Verifier, verifierName, re.EmptyLink, err, nil, re.HideStackTrace) + return nil, re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("Failed to parse the Notation Verifier configuration: %+v", verifierConfig)).WithError(err) } if err := json.Unmarshal(verifierConfigBytes, &conf); err != nil { - return nil, re.ErrorCodeConfigInvalid.NewError(re.Verifier, verifierName, re.EmptyLink, err, fmt.Sprintf("failed to unmarshal to notationPluginVerifierConfig from: %+v.", verifierConfig), re.HideStackTrace) + return nil, re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("Failed to parse the Notation Verifier configuration: %+v", verifierConfig)).WithError(err) } defaultCertsDir := paths.Join(homedir.Get(), ratifyconfig.ConfigFileDir, defaultCertPath) @@ -235,7 +237,7 @@ func normalizeVerificationCertsStores(conf *NotationPluginVerifierConfig) error } } if isCertStoresByType && isLegacyCertStore { - return re.ErrorCodeConfigInvalid.NewError(re.Verifier, conf.Name, re.EmptyLink, nil, "both old VerificationCertStores and new VerificationCertStores are provided, please provide only one", re.HideStackTrace) + return re.ErrorCodeConfigInvalid.WithDetail("The verificationCertStores is misconfigured with both legacy and new formats").WithRemediation("Please provide only one format for the VerificationCertStores. Refer to the Notation Verifier configuration guide: https://ratify.dev/docs/plugins/verifier/notation#configuration") } else if !isCertStoresByType && isLegacyCertStore { legacyCertStore, err := normalizeLegacyCertStore(conf) if err != nil { @@ -254,11 +256,11 @@ func normalizeVerificationCertsStores(conf *NotationPluginVerifierConfig) error func normalizeLegacyCertStore(conf *NotationPluginVerifierConfig) (map[string]interface{}, error) { legacyCertStoreBytes, err := json.Marshal(conf.VerificationCertStores) if err != nil { - return nil, re.ErrorCodeConfigInvalid.NewError(re.Verifier, conf.Name, re.EmptyLink, err, nil, re.HideStackTrace) + return nil, re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("Failed to recognize `verificationCertStores` value of Notation Verifier configuration: %+v", conf.VerificationCertStores)).WithError(err) } var legacyCertStore map[string]interface{} if err := json.Unmarshal(legacyCertStoreBytes, &legacyCertStore); err != nil { - return nil, re.ErrorCodeConfigInvalid.NewError(re.Verifier, conf.Name, re.EmptyLink, err, fmt.Sprintf("failed to unmarshal to legacyCertStore from: %+v.", legacyCertStoreBytes), re.HideStackTrace) + return nil, re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("Failed to recognize `verificationCertStores` value of Notation Verifier configuration: %+v", conf.VerificationCertStores)).WithError(err) } return legacyCertStore, nil } diff --git a/pkg/verifier/notation/truststore.go b/pkg/verifier/notation/truststore.go index c7bceb443..e9490cb71 100644 --- a/pkg/verifier/notation/truststore.go +++ b/pkg/verifier/notation/truststore.go @@ -41,7 +41,7 @@ type trustStore struct { func newTrustStore(certPaths []string, verificationCertStores verificationCertStores) (*trustStore, error) { certStores, err := newCertStoreByType(verificationCertStores) if err != nil { - return nil, err + return nil, re.ErrorCodeConfigInvalid.WithDetail(fmt.Sprintf("Failed to create the trust store from the verificationCertStores parameter in Notation Verifier configuration: %+v", verificationCertStores)).WithError(err).WithRemediation("Please check the value of the verificationCertStores parameter according to the Notation Verifier configuration guide: https://ratify.dev/docs/plugins/verifier/notation#configuration") } store := &trustStore{ certPaths: certPaths, diff --git a/scripts/azure-ci-test.sh b/scripts/azure-ci-test.sh index 1589adec2..c5c7be9c5 100755 --- a/scripts/azure-ci-test.sh +++ b/scripts/azure-ci-test.sh @@ -142,7 +142,7 @@ trap cleanup EXIT main() { ./scripts/create-azure-resources.sh create_key_akv - + local ACR_USER_NAME="00000000-0000-0000-0000-000000000000" local ACR_PASSWORD=$(az acr login --name ${ACR_NAME} --expose-token --output tsv --query accessToken) make e2e-azure-setup TEST_REGISTRY=$REGISTRY TEST_REGISTRY_USERNAME=${ACR_USER_NAME} TEST_REGISTRY_PASSWORD=${ACR_PASSWORD} KEYVAULT_KEY_NAME=${KEYVAULT_KEY_NAME} KEYVAULT_NAME=${KEYVAULT_NAME} @@ -152,7 +152,9 @@ main() { deploy_gatekeeper deploy_ratify - TEST_REGISTRY=$REGISTRY bats -t ./test/bats/azure-test.bats + local IDENTITY_CLIENT_ID=$(az identity show --name ${USER_ASSIGNED_IDENTITY_NAME} --resource-group ${GROUP_NAME} --query 'clientId' -o tsv) + local VAULT_URI=$(az keyvault show --name ${KEYVAULT_NAME} --resource-group ${GROUP_NAME} --query "properties.vaultUri" -otsv) + TEST_REGISTRY=$REGISTRY IDENTITY_CLIENT_ID=$IDENTITY_CLIENT_ID VAULT_URI=$VAULT_URI bats -t ./test/bats/azure-test.bats } main diff --git a/test/bats/azure-test.bats b/test/bats/azure-test.bats index a30556dd7..d37a8f5c7 100644 --- a/test/bats/azure-test.bats +++ b/test/bats/azure-test.bats @@ -70,7 +70,7 @@ SLEEP_TIME=1 sed -i '10,$d' ./test/bats/tests/config/config_v1beta1_keymanagementprovider_inline.yaml # configure the notation verifier to use the inline key management provider - run kubectl apply -f ./test/bats/tests/config/config_v1beta1_verifier_notation_kmprovider.yaml + run kubectl replace -f ./test/bats/tests/config/config_v1beta1_verifier_notation_kmprovider.yaml assert_success # wait for the httpserver cache to be invalidated @@ -318,3 +318,80 @@ SLEEP_TIME=1 result=$(kubectl get pod mutate-demo --namespace default -o json | jq -r ".spec.containers[0].image" | grep @sha) assert_mutate_success } + +@test "validate refresher reconcile count" { + teardown() { + echo "cleaning up" + wait_for_process ${WAIT_TIME} ${SLEEP_TIME} 'kubectl delete keymanagementprovider kmp-akv-refresh --ignore-not-found=true' + rm test.yaml + } + sed -e "s/keymanagementprovider-akv/kmp-akv-refresh/" \ + -e "s/1m/1s/" \ + -e "s/yourCertName/${NOTATION_PEM_NAME}/" \ + -e '/version: yourCertVersion/d' \ + -e "s|https://yourkeyvault.vault.azure.net/|${VAULT_URI}|" \ + -e "s/tenantID:/tenantID: ${TENANT_ID}/" \ + -e "s/clientID:/clientID: ${IDENTITY_CLIENT_ID}/" \ + ./config/samples/clustered/kmp/config_v1beta1_keymanagementprovider_akv_refresh_enabled.yaml >test.yaml + run kubectl apply -f test.yaml + assert_success + sleep 10 + count=$(kubectl logs deployment/ratify -n gatekeeper-system | grep "Reconciled KeyManagementProvider" | wc -l) + [ $count -ge 4 ] +} + +@test "validate refresher updates kmp with latest certificate version" { + teardown() { + echo "cleaning up" + wait_for_process ${WAIT_TIME} ${SLEEP_TIME} 'kubectl delete keymanagementprovider kmp-akv-refresh --ignore-not-found=true' + rm test.yaml + rm policy.json + } + sed -e "s/keymanagementprovider-akv/kmp-akv-refresh/" \ + -e "s/1m/5s/" \ + -e "s/yourCertName/${NOTATION_PEM_NAME}/" \ + -e '/version: yourCertVersion/d' \ + -e "s|https://yourkeyvault.vault.azure.net/|${VAULT_URI}|" \ + -e "s/tenantID:/tenantID: ${TENANT_ID}/" \ + -e "s/clientID:/clientID: ${IDENTITY_CLIENT_ID}/" \ + ./config/samples/clustered/kmp/config_v1beta1_keymanagementprovider_akv_refresh_enabled.yaml >test.yaml + run kubectl apply -f test.yaml + assert_success + sleep 5 + result=$(kubectl get keymanagementprovider kmp-akv-refresh -o jsonpath='{.status.properties.Certificates[0].Version}') + az keyvault certificate get-default-policy -o json >>policy.json + wait_for_process 20 10 "az keyvault certificate create --vault-name $KEYVAULT_NAME --name $NOTATION_PEM_NAME --policy @policy.json" + sleep 30 + refreshResult=$(kubectl get keymanagementprovider kmp-akv-refresh -o jsonpath='{.status.properties.Certificates[0].Version}') + [ "$result" != "$refreshResult" ] +} + +@test "validate certificate specified version" { + teardown() { + echo "cleaning up" + wait_for_process ${WAIT_TIME} ${SLEEP_TIME} 'kubectl delete keymanagementprovider kmp-akv-refresh --ignore-not-found=true' + rm policy.json + rm test.yaml + } + sed -e "s/keymanagementprovider-akv/kmp-akv-refresh/" \ + -e "s/1m/1s/" \ + -e "s/yourCertName/${NOTATION_PEM_NAME}/" \ + -e '/version: yourCertVersion/d' \ + -e "s|https://yourkeyvault.vault.azure.net/|${VAULT_URI}|" \ + -e "s/tenantID:/tenantID: ${TENANT_ID}/" \ + -e "s/clientID:/clientID: ${IDENTITY_CLIENT_ID}/" \ + ./config/samples/clustered/kmp/config_v1beta1_keymanagementprovider_akv_refresh_enabled.yaml >test.yaml + version=$(az keyvault certificate show --vault-name $KEYVAULT_NAME --name $NOTATION_PEM_NAME --query 'sid' -o tsv | rev | cut -d'/' -f1 | rev) + sed -i \ + -e "/name: ${NOTATION_PEM_NAME}/a \ \ \ \ \ \ \ \ version: ${version}" \ + test.yaml + run kubectl apply -f test.yaml + assert_success + sleep 10 + result=$(kubectl get keymanagementprovider kmp-akv-refresh -o jsonpath='{.status.properties.Certificates[0].Version}') + az keyvault certificate get-default-policy -o json >>policy.json + wait_for_process 20 10 "az keyvault certificate create --vault-name $KEYVAULT_NAME --name $NOTATION_PEM_NAME --policy @policy.json" + sleep 30 + refreshResult=$(kubectl get keymanagementprovider kmp-akv-refresh -o jsonpath='{.status.properties.Certificates[0].Version}') + [ "$result" = "$refreshResult" ] +} diff --git a/test/bats/tests/config/config_v1beta1_verifier_notation.yaml b/test/bats/tests/config/config_v1beta1_verifier_notation.yaml index fb6595d85..bb1564a44 100644 --- a/test/bats/tests/config/config_v1beta1_verifier_notation.yaml +++ b/test/bats/tests/config/config_v1beta1_verifier_notation.yaml @@ -7,7 +7,8 @@ spec: artifactTypes: application/vnd.cncf.notary.signature parameters: verificationCertStores: - certs: + ca: + ca-certs: - certstore-inline trustPolicyDoc: version: "1.0" @@ -18,6 +19,6 @@ spec: signatureVerification: level: strict trustStores: - - ca:certs + - ca:ca-certs trustedIdentities: - "*" diff --git a/test/bats/tests/config/config_v1beta1_verifier_notation_akv.yaml b/test/bats/tests/config/config_v1beta1_verifier_notation_akv.yaml index 031180229..ea2d24c8e 100644 --- a/test/bats/tests/config/config_v1beta1_verifier_notation_akv.yaml +++ b/test/bats/tests/config/config_v1beta1_verifier_notation_akv.yaml @@ -7,8 +7,9 @@ spec: artifactTypes: application/vnd.cncf.notary.signature parameters: verificationCertStores: - certs: - - kmprovider-akv + ca: + ca-certs: + - kmprovider-akv trustPolicyDoc: version: "1.0" trustPolicies: @@ -18,6 +19,6 @@ spec: signatureVerification: level: strict trustStores: - - ca:certs + - ca:ca-certs trustedIdentities: - "*" diff --git a/test/bats/tests/config/config_v1beta1_verifier_notation_kmprovider.yaml b/test/bats/tests/config/config_v1beta1_verifier_notation_kmprovider.yaml index c90ccc5fd..04304c3f1 100644 --- a/test/bats/tests/config/config_v1beta1_verifier_notation_kmprovider.yaml +++ b/test/bats/tests/config/config_v1beta1_verifier_notation_kmprovider.yaml @@ -7,8 +7,9 @@ spec: artifactTypes: application/vnd.cncf.notary.signature parameters: verificationCertStores: - certs: - - keymanagementprovider-inline + ca: + ca-certs: + - keymanagementprovider-inline trustPolicyDoc: version: "1.0" trustPolicies: @@ -18,6 +19,6 @@ spec: signatureVerification: level: strict trustStores: - - ca:certs + - ca:ca-certs trustedIdentities: - "*"