From 7213fed17448ae8bcffaaeeae3d422668674d340 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Oct 2024 05:48:05 +0000 Subject: [PATCH 01/62] chore: Bump golang from `b274ff1` to `0ca97f4` in /httpserver (#1876) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- httpserver/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httpserver/Dockerfile b/httpserver/Dockerfile index 39ee6444c..33e3ccc0b 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:b274ff14d8eb9309b61b1a45333bf0559a554ebcf6732fa2012dbed9b01ea56f as builder +FROM --platform=$BUILDPLATFORM golang:1.22@sha256:0ca97f4ab335f4b284a5b8190980c7cdc21d320d529f2b643e8a8733a69bfb6b as builder ARG TARGETPLATFORM ARG TARGETOS From c8e8e00e4a89310c88884c0f0cdbaf8e542809eb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Oct 2024 06:24:54 +0000 Subject: [PATCH 02/62] chore: Bump github.com/prometheus/client_golang from 1.20.4 to 1.20.5 (#1877) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 49cfc2ea3..928608310 100644 --- a/go.mod +++ b/go.mod @@ -202,7 +202,7 @@ require ( github.com/pelletier/go-toml/v2 v2.1.0 // indirect github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/prometheus/client_golang v1.20.4 + github.com/prometheus/client_golang v1.20.5 github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.55.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect diff --git a/go.sum b/go.sum index e99841334..56f1d4edc 100644 --- a/go.sum +++ b/go.sum @@ -575,8 +575,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.20.4 h1:Tgh3Yr67PaOv/uTqloMsCEdeuFTatm5zIq5+qNN23vI= -github.com/prometheus/client_golang v1.20.4/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= +github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y= +github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= From a9ee77699c374f8d6bb4b59e52969a7f8f730daf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Oct 2024 06:51:50 +0000 Subject: [PATCH 03/62] chore: Bump vscode/devcontainers/go from `bdecb4c` to `46f85d1` in /.devcontainer (#1879) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .devcontainer/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 3b534a9b0..c5db92a0b 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -14,7 +14,7 @@ # See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.245.2/containers/go/.devcontainer/base.Dockerfile # [Choice] Go version (use -bullseye variants on local arm64/Apple Silicon): 1.22-bullseye, 1.21-bullseye, 1, 1.19, 1.18, 1-bullseye, 1.19-bullseye, 1.18-bullseye, 1-buster, 1.19-buster, 1.18-buster -FROM mcr.microsoft.com/vscode/devcontainers/go:1.22-bullseye@sha256:bdecb4ca0d168e7bd73b01e475d017aac0888ee22c7d4998a09858ab95157669 +FROM mcr.microsoft.com/vscode/devcontainers/go:1.22-bullseye@sha256:46f85d17eff2b121269b4ed547eb366c2499b5f549d8eaa16fbe6e38f04dfb93 # [Choice] Node.js version: none, lts/*, 18, 16, 14 ARG NODE_VERSION="none" From 9c40fba3f72d91bb63001c914b4f7277ff45975b Mon Sep 17 00:00:00 2001 From: Binbin Li Date: Tue, 22 Oct 2024 01:59:13 +0800 Subject: [PATCH 04/62] chore: bump up go version to 1.22.8 (#1880) Signed-off-by: Binbin Li Signed-off-by: Binbin Li --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 928608310..60bde1044 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/ratify-project/ratify -go 1.22.5 +go 1.22.8 // Accidentally published prior to 1.0.0 release retract ( From ea3cee574fde8f1335ec20783fd7b3a9ed4a8ab8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Oct 2024 19:21:13 +0000 Subject: [PATCH 05/62] chore: Bump github.com/sigstore/sigstore from 1.8.9 to 1.8.10 (#1878) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 12 ++++++------ go.sum | 24 ++++++++++++------------ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/go.mod b/go.mod index 60bde1044..27d1f11c1 100644 --- a/go.mod +++ b/go.mod @@ -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.9 + github.com/sigstore/sigstore v1.8.10 github.com/sirupsen/logrus v1.9.3 github.com/spdx/tools-golang v0.5.5 github.com/spf13/cobra v1.8.1 @@ -234,14 +234,14 @@ require ( go.uber.org/atomic v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect - golang.org/x/crypto v0.26.0 + golang.org/x/crypto v0.28.0 golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 // indirect golang.org/x/mod v0.20.0 // indirect golang.org/x/net v0.28.0 // indirect - golang.org/x/oauth2 v0.22.0 // indirect - golang.org/x/sys v0.23.0 // indirect - golang.org/x/term v0.23.0 // indirect - golang.org/x/text v0.17.0 // indirect + golang.org/x/oauth2 v0.23.0 // indirect + golang.org/x/sys v0.26.0 // indirect + golang.org/x/term v0.25.0 // indirect + golang.org/x/text v0.19.0 // indirect golang.org/x/time v0.6.0 // indirect gomodules.xyz/jsonpatch/v2 v2.3.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect diff --git a/go.sum b/go.sum index 56f1d4edc..d94ab83cf 100644 --- a/go.sum +++ b/go.sum @@ -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.9 h1:NiUZIVWywgYuVTxXmRoTT4O4QAGiTEKup4N1wdxFadk= -github.com/sigstore/sigstore v1.8.9/go.mod h1:d9ZAbNDs8JJfxJrYmulaTazU3Pwr8uLL9+mii4BNR3w= +github.com/sigstore/sigstore v1.8.10 h1:r4t+TYzJlG9JdFxMy+um9GZhZ2N1hBTyTex0AHEZxFs= +github.com/sigstore/sigstore v1.8.10/go.mod h1:BekjqxS5ZtHNJC4u3Q3Stvfx2eyisbW/lUZzmPU2u4A= 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= @@ -780,8 +780,8 @@ golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45 golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= -golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= -golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= +golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= +golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 h1:hNQpMuAJe5CtcUqCXaWga3FHu+kQvCqcsoVaQgSV60o= golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08= @@ -826,8 +826,8 @@ golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA= -golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= +golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -871,8 +871,8 @@ golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= -golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= @@ -883,8 +883,8 @@ golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo= golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= -golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= -golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= +golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24= +golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -897,8 +897,8 @@ golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= +golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= From 12b4446f1e9b7e117c601ecce6ed66f3a21ec400 Mon Sep 17 00:00:00 2001 From: Sushant Adhikari Date: Tue, 22 Oct 2024 11:25:41 +1100 Subject: [PATCH 06/62] docs: design proposal for tag and digest co-existing [ISSUE 1657] (#1793) --- docs/proposals/Tag-Digest-CoExist.md | 93 ++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 docs/proposals/Tag-Digest-CoExist.md diff --git a/docs/proposals/Tag-Digest-CoExist.md b/docs/proposals/Tag-Digest-CoExist.md new file mode 100644 index 000000000..1b8e6d5d7 --- /dev/null +++ b/docs/proposals/Tag-Digest-CoExist.md @@ -0,0 +1,93 @@ +# Ratify Mutation: mutual existence of tags and digest. + +## Problems + +Current User scenarios: +1. I want to see which version of my image is deployed but I can only see the digest in the pod image. + 1. This results in the engineer’s time being wasted on manually mapping between the image digest and the version from the image repository. + 1. All my observability dashboards rely on tags but now I need to manually know which tags belong to which digests and somehow also make my dashboards map between those. This is a big hassle. + +## Solution Overview + +The current solution has been chosen on the basis that Ratify is only meant to mutate from tags to digest as tags are mutable and digests are the ultimate source of truth. This solution is also prepared with the community recommendation of using digests instead of tags in mind with digests being the ultimate source of truth for artifact verification. + +However with the digest-only approach having altercations with broader software engineers NOT focused towards security, embedding digests alongside pre-existing tags in the K8s object spec during mutation as a debug-friendly and engineer friendly way forward seems feasible. As the end container orchestration framework such as `containerd` and ultimately `runc` still continue to rely on only the mutated digest to create containers, engineers on the other hand can rely on the pre-existing and untouched tag in the deployed object (Deployment, Pod, StatefulSet etc)’s image spec to know their source of truth for debugging purposes. + +As discussed in the corresponding [Github issue](https://github.com/ratify-project/ratify/issues/1657), having both tag & digest (`:@`) is NOT a recommended option but retains status for backward compatibility, new options with default configuration adhering to this shall be discussed in the design section. + +## Solution Design and Configurations / Proposed Changes + +This section discusses the various additions to the current Ratify Mutator and the corresponding Helm configuration that can help resolve this problem. We also discuss features that the mutator could incorporate to facilitate other additional problems but is a topic of further discussion and debate not within the realm and scope of the problem at hand. + +The solution proposes tweaks to the following sections to fix the problem at hand: +1. The helm chart shall be changed to add the corresponding new configs facilitating these new features for mutation. +1. The new configs shall be respectively passed to `/app/ratify serve` called through the `deployment.yaml` file to then handle the additional configs. +1. These configs then trickle down to the corresponding mutation code block to handle the mutations according to those config. + +### Configurations + +A new config block shall be added in the helm chart’s `values.yaml` which will be used respectively. + +This feature will be available through the new `provider.mutation` config block which will make the `provider.enableMutation` option obsolete. A new boolean sub-config of `provider.mutation.enable` will be added to facilitate this existing feature. + +A new sub config `mutationStyle` will be added to facilitate the type of mutation the user owuld want. +The following sub-options will be added to incorporate additional configuration during mutation. + +| `mutationStyle` | Implemented / Designed in the current solution? | Summary | Incoming Spec Condition | Upstream calls for Subject Descriptor? | Default Option | +| ----------- | ----------------------------------------------- | ------- | ----------------------- | -------------------------------------- | -------------- | +| `retain-mutated-tag` | Y | Retain the pre-existing tag during mutation / Do not strip the tag away if both tag & digest pre-exists |Contains Tag, Does not contain Digest / Contains Tag, Contains Digest | Y / N | false | +| `digest-only` | Y | Mutate tag to digest, stripping the tag away | Contains Tag, Does not contain Digest / Contains Tag, Contains Digest | Y / N | true | + +The options can work in conjunction to provide the required mutation output. +Here, + +`Latest` tag’s digest = `xxxx` + +`v1.2.4` tag’s digest = `yyyy` + + +| Config | Input | Output | +| ------ | ----- | ------ | +| `mutationStyle: "digest-only"` | docker.io/nginx | docker.io/nginx@sha256:xxxx | +| | docker.io/nginx:latest | docker.io/nginx@sha256:xxxx | +| | docker.io/nginx:v1.2.4 | docker.io/nginx@sha256:yyyy | +| | docker.io/nginx:latest@sha256:xxxx | docker.io/nginx@sha256:xxxx | +| | docker.io/nginx:v1.2.4@sha256:yyyy | docker.io/nginx@sha256:yyyy | +| | docker.io/nginx@sha256:xxxx | docker.io/nginx@sha256:xxxx | +| `mutationStyle: "retain-mutated-tag"` | docker.io/nginx | docker.io/nginx:latest@sha256:xxxx | +| | docker.io/nginx:v1.2.4 | docker.io/nginx:v1.2.4@sha256:yyyy | +| | docker.io/nginx:latest@sha256:xxxx | docker.io/nginx:latest@sha256:xxxx | +| | docker.io/nginx:v1.2.4@sha256:yyyy | docker.io/nginx:v1.2.4@sha256:yyyy | +| | docker.io/nginx@sha256:xxxx | docker.io/nginx@sha256:xxxx | + +An enum style config has been proposed so it does not overcrowd the `provider.mutation` block. Both, addition of new mutation styles as well as parsing on the code side will be easier with this approach. + +### Implementation + +The `mutationStyle` config will be implemented to retain the tag in the resulting spec image. The default option for this config will be `digest-only` to keep supporting the existing config parameter. + +Options of provider.mutation.enable and provider.mutation.retainMutatedTag shall be added into Helm. +Example: + +``` +provider: + tls: + crt: "" +... + mutation: + // enable: true + mutationStyle: "digest-only" // (default), other options are "retain-mutated-tag" + enableMutation: true // deprecated, enable and use mutation.enabled instead. If both are used, `mutation.enable` will be preferred +``` + +The `retain-mutated-tag` option will be available for anyone wanting to control if they want to completely remove tags (the default) or have both tags + digest in the resulting output. + +## Performance Impact +The solution should have very little performance impact considering addition of code will not have any network connectivity related feature. Addition of code mostly should adhere to if-else clauses and other small regex additions. + +## Security Considerations +As the change is purely beautification in nature, no security impact could be thought of. +As long as research suggests all major container orchestration frameworks (docker, podman, etc) support the `tag@digest`, however it’s not guaranteed that it’ll work with other smaller frameworks where this hasn’t yet been implemented. + +## Backward Compatibility +The added config won’t be backward compatible if mutation has been disabled, i.e `enableMutation:false` in the helm chart. This means that a new `provider.mutation.enable` will need to be added in the updated helm charts. From 5083cd4682e2b8c2359a3127e325afeee18f7202 Mon Sep 17 00:00:00 2001 From: Juncheng Zhu <74894646+junczhu@users.noreply.github.com> Date: Tue, 22 Oct 2024 08:27:00 +0800 Subject: [PATCH 07/62] docs: add CRL Design (#1789) Signed-off-by: Juncheng Zhu --- docs/design/Certificate Revocation Lists.md | 217 ++++++++++++++++++++ docs/img/CRL/CRL-workflow.png | Bin 0 -> 79472 bytes 2 files changed, 217 insertions(+) create mode 100644 docs/design/Certificate Revocation Lists.md create mode 100644 docs/img/CRL/CRL-workflow.png diff --git a/docs/design/Certificate Revocation Lists.md b/docs/design/Certificate Revocation Lists.md new file mode 100644 index 000000000..40433aa66 --- /dev/null +++ b/docs/design/Certificate Revocation Lists.md @@ -0,0 +1,217 @@ +# CRL and CRL Cache Design + +## Intro + +Certificate validation is an essential step during signature validation. Currently Ratify supports checking for revoked certificates through OCSP supported by notation-go library. However, OCSP validation requires internet connection for each validation while CRL could be cached for better performance. As notary-project is adding the CRL support for notation signature validation, Ratify could utilize it. + +OCSP URLs can be obtained from the certificate's authority information access (AIA) extension as defined in RFC 6960. If the certificate contains multiple OCSP URLs, then each URL is invoked in sequential order, until a 2xx response is received for any of the URL. For each OCSP URL, wait for a default threshold of 2 seconds to receive an OCSP response. The user may be able to configure this threshold. If OCSP response is not available within the timeout threshold the revocation result will be "revocation unavailable". + +If both OCSP URLs and CDP URLs are present, then OCSP is preferred over CRLs. If revocation status cannot be determined using OCSP because of any reason such as unavailability then fallback to using CRLs for revocation check. + +## Goals + +CRL support, including CRL downloading, validation, and revocation list checks. + +- Define a cache provider interface for CRL +- Implement default file-based cache implementation for both CLI and K8S +- Implement preload CRL when cert added from KMP +- Test plan for the CRL feature and performance test between CRL w/o cache. +- Update CRL and CRL caching related documentation + +## Design Points + +**How to Get CRL** + +With no extra configuration, CRL download location (URL) can be obtained from the certificate's CRL Distribution Point (CDP) extension. If the CRL cannot be downloaded within the timeout threshold the revocation result will be "revocation unavailable". More details are showing in the Download CRL section + +**Why Caching** + +Preload CRL can help improve the performance verifier from download CRLs when a single CRL can be up to 32MiB. Prefer ratify cache for reuse the cache provider [interface](https://github.com/ratify-project/ratify/blob/dev/pkg/cache/api.go). Reusing interfaces reduces redundant expressions, helps you easily maintain application objects. + +This design prefer file-based cache over memory-based one to ensure cache would still be available after service restarted. And in CLI scenario memory-based cache would not be applied. +Besides, by using memory-based cache, memory consumption and further cache expiring would increase the design complexity. + +**Why Refresh CRL Cache** + +A CRL is considered expired if the current date is after the `NextUpdate` field in the CRL. Verify that the CRL is valid (not expired) is necessary for revocation check. Monitoring and refreshing CRL on a regular basis can help avoid CRL download timetaken when doing verification by ensure the CRL is valid. + +## Proposed Design + +![image](../img/CRL/CRL-workflow.png) + + +**Ratify Verification Request Path**: + +Step 1: Apply the CRs including certs and CRL config + +Step 2: Load CRLs from cert provided URLs // Implement CanCacheCRL() with GetCertificates() which includes all scenarios that introduce a new cert: KMP, KMP refresher and Verifer Config + +Step 3: Trigger Refresh Monitor and set up refresh schedule // Refresher is based on build-in ticker + +Step 4: Start verify task // Revocation list check is handled by notation verifier. + +Step 5: Load trust policy // Get `Opt.Fetcher` + +Step 6: Load CRL cache + +**CRL Handler**: + +Step 1: Load cert URLs from `[]*x509.Certificate` + +Step 2: Download CRL + +Step 3: Trigger Refresh Monitor, refresh monitor is [`time`](https://pkg.go.dev/time#example-NewTicker) pkg based. + +### Cache Content Design + +Key: +- `uri` in type `string` + +Value: +- `*Bundle` + - `NextUpdate` // nextUpdate can be get from bundle.BaseCRL.NextUpdate + +Reference: [revocation/crl/bundle.go](https://github.com/notaryproject/notation-core-go/blob/main/revocation/crl/bundle.go) + +Check CRL Cache Validity +``` +// directly checks CRL validity +now := time.Now() +if !crl.NextUpdate.IsZero() && now.After(crl.NextUpdate) { + // perform refresh +} +``` + +### Load CRL Cache + +Load cache is triggerred after cert loaded from the either configurations. + +#### Download CRL + + +Download is implemented by CRL `fetcher`, which can be done in parallel via start tasks in seperate go routines. + +CRL download location (URL) can be obtained from the certificate's CRL Distribution Point (CDP) extension. +`notation-core-go` will download all CDP URLs because each CDP URL may belong to a different scope, and we cannot distinguish them. + +For each CDP location, Notary Project verification workflow will try to download the CRL for the default threshold of 5 seconds. Ratify is able to configure this threshold. If the CRL cannot be downloaded within the timeout threshold the revocation result will be "revocation unavailable". + +#### Save CRL to Cache + +``` +// Set stores the CRL bundle in the file system +// Check closest expired date and set to `CRLCacheProvider`. +// Save to temp file and avoid concurrency issue with atomic write operation +// `rename()` is atomic on UNIX-like platforms + + +// notation-go FScache + +type fileCacheContent struct { + // BaseCRL is the ASN.1 encoded base CRL + BaseCRL []byte `json:"baseCRL"` + + // DeltaCRL is the ASN.1 encoded delta CRL + DeltaCRL []byte `json:"deltaCRL,omitempty"` +} + +// This cache builds on top of the UNIX file system to leverage the file system's +// atomic operations. The `rename` and `remove` operations will unlink the old +// file but keep the inode and file descriptor for existing processes to access +// the file. The old inode will be dereferenced when all processes close the old +// file descriptor. Additionally, the operations are proven to be atomic on +// UNIX-like platforms, so there is no need to handle file locking. +// +// NOTE: For Windows, the `open`, `rename` and `remove` operations need file +// locking to ensure atomicity. The current implementation does not handle +// file locking, so the concurrent write from multiple processes may be failed. +// Please do not use this cache in a multi-process environment on Windows. +``` + +### Provide CRL Cache + +#### Get Cache from Provider + +``` +// Get retrieves the CRL bundle from the file system +// If the CRL is expired, return ErrCacheMiss + + +// Policy that uses custom verification level to relax the strict verification. +// It logs expiry and skips the revocation check. +"name": "use-expired-blobs", + "signatureVerification": { + "level" : "strict", + "override" : { + "expiry" : "log", + "revocation" : "skip" + } + }, + +``` +Reference: https://github.com/notaryproject/specifications/blob/main/specs/trust-store-trust-policy.md#signatureverification-details:~:text=Notary%20Project%20defines,scope%20(*). + +#### Refresh Cache + +Cache Data Structure: Store data along with expiration timestamps. + +Monitor Scheduler: Use a scheduler (e.g., time.Ticker) to check the cache at regular intervals. + +Concurrency: Use synchronization mechanisms like mutexes for thread-safe access to shared data. + +Expiration Handling: When setting cache, check closest expired date that set to `CRLCacheProvider`. Compare the current time with the cache item's expiration. If expired, trigger the fetch process to update the data. + +Error Handling and Retries: Implement error handling with retry logic in case of failed refresh operations. + +Use synchronization primitives like mutexes to ensure thread safety during cache updates. + +# Dev Work Items + +- Implement CRL Fetcher based on notation-go library (~ 1-2 weeks) +- Implement file-based CRL Cache Provider (~ 2-3 weeks) +- Support loading CRLs from cert provided URLs, engage PM discussion (~ 1-2 weeks) +- Verifier performance test and Cache r/w performance test (~ 2-3 weeks) +- New e2e tests for different scenarios (~ 1 week) + + +# More details + +**Brief Aside about CRL and CRL Cache** + +X.509 defines one method of certificate revocation. This method involves each CA periodically issuing a signed data structure called a certificate revocation list (CRL). + +A CRL is a time stamped list identifying revoked certificates which is signed by a CA or CRL issuer and made freely available in a public repository. Each revoked certificate is identified in a CRL by its certificate serial number. + +When a certificate-using system uses a certificate (e.g., for verifying a remote user's digital signature), that system not only checks the certificate signature and validity but also acquires a suitably-recent CRL and checks that the certificate serial number is not on that CRL. +The meaning of "suitably-recent" may vary with local policy, but it usually means the most recently-issued CRL. + +A new CRL is issued on a regular periodic basis (e.g., hourly, daily, or weekly). +An entry is added to the CRL as part of the next update following notification of revocation. An entry MUST NOT be removed from the CRL until it appears on one regularly scheduled CRL issued beyond the revoked certificate's validity period. + +Implementations of the Notary Project verification specification support only HTTP CRL URLs. + +**Revocation Checking with CRL** + +To check the revocation status of a certificate against CRL, the following steps must be performed: + +1. Verify the CRL signature. +1. Verify that the CRL is valid (not expired). + A CRL is considered expired if the current date is after the `NextUpdate` field in the CRL. +1. Look up the certificate’s serial number in the CRL. + 1. If the certificate’s serial number is listed in the CRL, look for `InvalidityDate`. + If CRL has an invalidity date and artifact signature is timestamped then compare the invalidity date with the timestamping date. + 1. If the invalidity date is before the timestamping date, the certificate is considered revoked. + 1. If the invalidity date is not present in CRL, the certificate is considered revoked. + 1. If the CRL is expired and the certificate is listed in the CRL for any reason other than `certificate hold`, the certificate is considered revoked. + 1. If the certificate is not listed in the CRL or the revocation reason is `certificate hold`, a new CRL is retrieved if the current time is past the time in the `NextPublish` field in the current CRL. + The new CRL is then checked to determine if the certificate is revoked. + If the original reason was `certificate hold`, the CRL is checked to determine if the certificate is unrevoked by looking for the `RemoveFromCRL` revocation code. + + +**rfc3280** + +REF: [Internet X.509 Public Key Infrastructure](https://www.rfc-editor.org/rfc/rfc3280#section-1) + +Q: Does the Notary Project trust policy support overriding of revocation endpoints to support signature verification in disconnected environments? + +A: TODO: Update after verification extensibility spec is ready. Not natively supported but a user can configure revocationValidations to skip and then use extended validations to check for revocation. \ No newline at end of file diff --git a/docs/img/CRL/CRL-workflow.png b/docs/img/CRL/CRL-workflow.png new file mode 100644 index 0000000000000000000000000000000000000000..b33faef398f97b79049cb0f17a76390ec9265b4f GIT binary patch literal 79472 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

h_YmvBs%}Xjd*L$;IVMw*w$f0j-NX za0uEcY&`YnW&UM;mUc~X^QgSv(3ZULoqQ%hBXbO7CiWhDgYNz{ghPn7jtNDEBCLTqygru7f88@iJw&#WobDd`^l%i->W}caz9gzc?f>oC7_xEWI4ILoV-g* zOO33p!F0Oxm08(0#0>7&pk6Wof!%o;pd{5^)4Br)cePw4o$qB9qz)o-0S)BqQdBxi z&LgIrb$ql9KzD)Qh}|D|E&&U_6j%au?Ay1?q-A9n*?~()*~)adQ>sDuJr%{p$o?1+ zSt7>S(8ar|n(|_krUr{={3y5PsoiOSZv^fJ9Oj?%{_P@9=%y?p_2LGllupX=EY?ed%uYu zr-;IaI;uT$_0U>qL$s3lY)VrpJ#uCaHu1t zd-xh!skylKH+_zPLN~nO(ifcH1&=+?{pTXv+f=8u+9=_X+UUFu+zXx7eyFOZb{Q

J&qk?I_5DRsx=8Yct|8_vx`TLX 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 literal 0 HcmV?d00001 From cc80ff81113bd860a64d3ef3c0bb9d820010aab7 Mon Sep 17 00:00:00 2001 From: Asaf Algawi <144888248+asafalgawi@users.noreply.github.com> Date: Tue, 22 Oct 2024 03:36:37 +0300 Subject: [PATCH 08/62] docs: Create proposal for verifying 'last-n' artifacts only. (#1797) Signed-off-by: Susan Shi --- docs/proposals/Verify-Latest-N-Artifacts.md | 103 ++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 docs/proposals/Verify-Latest-N-Artifacts.md diff --git a/docs/proposals/Verify-Latest-N-Artifacts.md b/docs/proposals/Verify-Latest-N-Artifacts.md new file mode 100644 index 000000000..efe7240eb --- /dev/null +++ b/docs/proposals/Verify-Latest-N-Artifacts.md @@ -0,0 +1,103 @@ +# Verify only the latest N artifacts + +## Problem/Motivation + +When configuring a verifier in Ratify, we set the artifact type the verifier should work on. In such case, Ratify will verify all referrers of a given subject that have a matching artifact type using the verifier. +In some cases, this could lead to a wrong behavior. For instance, Vulnerability Artifacts are outdated once a new artifact is written to the repository, as such there is no use for verifying both the new one and the old one. + +The issue with verifying all the matching artifacts could also lead to performance issues, each "verification" process hides within a request to pull the artifcat manifest, and the blobs containing the actual data. +In previous studies made by the ratify team, it was observed that opverloading the registry with requests could lead to errors and throtteling. (see: https://ratify.dev/docs/reference/performance) + +Given the performance study listed above, in order to provide the best experience for Ratify's users ratify would reduce the load it generates on an the registry, thus reducing the chance for throtteling. + +# Proposed Solution + +Ratify uses the Referrer API (see: https://github.com/opencontainers/distribution-spec/blob/main/spec.md#listing-referrers) in order to obtain the list of attached artifacts of a given subject artifact. The response body for this request is a generated OCI image index, that looks like this: + +```json +{ + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.index.v1+json", + "manifests": [ + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "size": 1234, + "digest": "sha256:a1a1a1...", + "artifactType": "application/vnd.example.sbom.v1", + "annotations": { + "org.opencontainers.image.created": "2022-01-01T14:42:55Z", + "org.example.sbom.format": "json" + } + }, + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "size": 1234, + "digest": "sha256:a2a2a2...", + "artifactType": "application/vnd.example.signature.v1", + "annotations": { + "org.opencontainers.image.created": "2022-01-01T07:21:33Z", + "org.example.signature.fingerprint": "abcd" + } + }, + { + "mediaType": "application/vnd.oci.image.index.v1+json", + "size": 1234, + "digest": "sha256:a3a3a3...", + "annotations": { + "org.opencontainers.image.created": "2023-01-01T07:21:33Z", + } + } + ] +} +``` + +The image index response is requried by API to include the image annotations, which gives Ratify to oprrotunity to perform some basic filtration before invoking the verifier on the listed artifacts. The exact mechanism for requiring the filtration should be specific to each verifier as the behavior and logic differs based on is actually being attested, as such, it will be part of the verifier configuration. + +## Latest N artifacts only verification + +Assuming artifacts are generated by ORAS, they all have a `org.opencontainers.image.created` annotation, that markes the creation date of the artifact. Based on it, Ratify could filter out stale artifacts and only evaluate the latest image. To achieve this, Ratify would have to read all the referrers, ordering them based on the artifact age, and only pass the latest one to the corresponding verifier. + +This kind of filtering strategy is best used on artifacts that are rapidly changing, for example Vulnerability Assessment artifacts that are immedietly oudated once a new artifact is pushed to the registry. + +* An artifact without the creation annotation is considered to be the oldest. +* The annotation value should be a date time string in RFC 3339 format, any other value will result is invalid, and should be treated as the oldest artifact. + +## User experiences + +This section describes the experience that users interact with Ratify using the proposed solution. In summary, the propsed solution suggest we should allow for filtering of artifact based on annotations, and as such the following section describes how the customer would configure the filtration. + +Seeing that filteration is unique to each verifier, it should be configured in the verifier itself, as such, in order to maintain backwards compatability, it is important to note that if no filteration is configured the default behavior would be to evaluate all artifacts. + +### Defining artifact age based filtering + +To support artifact age based filtering, we would add an additional field to the verifier configuration: + +```yaml +apiVersion: config.ratify.deislabs.io/v1beta1 +kind: Verifier # NamespacedVerifier has the same spec. +metadata: + name: test-verifier +spec: + name: # REQUIRED: [string], the unique type of the verifier (notation, cosign) + artifactType: # REQUIRED: [string], comma seperated list, artifact type this verifier handles + verifyLastNArtifacts: # Optional: [int], denote the number of attached artfacts that should be verified. only the Last n will be verified. if not defined, all artifacts will be verified. + address: # OPTIONAL: [string], Plugin path, defaults to value of env "RATIFY_CONFIG" or "~/.ratify/plugins" + version: # OPTIONAL: [string], Version of the external plugin, defaults to 1.0.0. On ratify initialization, the specified version will be validated against the supported plugin version. + source: + artifact: # OPTIONAL: [string], Source location to download the plugin binary, learn more at docs/reference/dynamic-plugins.md e.g. wabbitnetworks.azurecr.io/test sample-verifier-plugin:v1 + parameters: # OPTIONAL: [object] Parameters specific to this verifier +``` + +### Implementation Considerations +To implmenet "Last N" verification only, Ratify has to be aware of all the attached artifacts of a givan kind before handing them to the verifier that wishes to attest only the latest artifact. In order to implement such behavior some modification has to be made to the executor of Ratify and the verifier implementation. + +Below are two proposals which are currently being considered for implemetation. +| Approach | Pros | Cons| Notes | +| -------- | ---- | ----| ----- | +| 1. Obtain and store all the referrer list
2. Sort it in descending order.
3. Use the CanVerify method of the referrer to make sure a verifier
that only wants the latest artifact is invoked once. | Naive implementation.

Does not make a huge change in the executor, other than fetching the list before hand.

Transparent change for verifiers that do not wish to use verify the latest image only. | The referrer list can be of any arbitrary size, therefore fetching the entire list may cause Ratify to hit a hard memory limit and crash.
To implement the feature with this kind of behavior, Ratify would have to limit the number of attached artifacts it supports to some constant number which will be determined during the implementation.

Additional latency for sorting the artifacts. | A test index list, with ~1000 artifacts within and two annotations (created timestamp, and another text field) weighs around ~400K, default ratify installation has 512MB of ram, so we're well within the limits of 'normal' use. +| 1. Split verifiers into two groups, those which require only latest artifact, and those which operate on all artifacts.
2. For verifiers that work on all artifacts, no change will be made.
3. For verifiers that require only the last N artifacts, the executor will manage a map between the verifier and an artifact descriptor list that is the "current candidates" for being the latest.
4. As we iterate all the referrer, the cadndiate list is constantly being updated, if a new artifact is discovered.
Once the executor had finished iterating over the referrer list, it would execute all the verifiers that required the latest N artifact against the "current candidate" list for each verifier, which are promised to be latest artifacts. | Does not modify Ratify's current scalability.| Requires the executor to be aware of verifier type, possibly by an interface change on the verifier API

Requires changes in multiple places in the executor, performing the verifier loop another time for the second list of verifiers that only require latest artifact. | The benefit of not pulling all the referrers, from the standpoint of keeping the same 'memory footprint' is not clear. + +# References + +* [Ratify Performance at Scale Study](https://ratify.dev/docs/reference/performance) +* [Referrer API in Distribution Spec](https://github.com/opencontainers/distribution-spec/blob/main/spec.md#listing-referrers) \ No newline at end of file From f578982bb0ca6295566abdd54caf8ffa4d8402be Mon Sep 17 00:00:00 2001 From: Josh Duffney Date: Mon, 21 Oct 2024 19:40:55 -0500 Subject: [PATCH 09/62] docs: nVersionCount support for KMP design doc (#1831) Signed-off-by: Joshua Duffney --- docs/design/kmp-nversions.md | 106 +++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 docs/design/kmp-nversions.md diff --git a/docs/design/kmp-nversions.md b/docs/design/kmp-nversions.md new file mode 100644 index 000000000..afc2421db --- /dev/null +++ b/docs/design/kmp-nversions.md @@ -0,0 +1,106 @@ +# nVersionCount support for Key Management Provider + +Author: Josh Duffney (@duffney) + +Tracked issues in scope: + +- https://github.com/ratify-project/ratify/issues/1751 + +Proposal ref: + +- https://github.com/ratify-project/ratify/blob/dev/docs/proposals/Automated-Certificate-and-Key-Updates.md + +## Problem Statement + +In version 1.3.0 and earlier, Ratify does not support the nVersionCount parameter for Key Management Provider (KMP) resources. This means that when a certificate or key is rotated, Ratify updates the cache with the new version and removes the previous one, which may not suit all use cases. + +For instance, if a user needs to retain the last three versions of a certificate or key in the cache, Ratify cannot meet this requirement without manually adjusting the KMP resource for each new version. + +By supporting nVersionCount, Ratify would allow users to specify how many versions of a certificate or key should be kept in the cache, eliminating the need for manual updates to the KMP resource. + +## Proposed Solution + +To address this challenge, this proposal suggests adding support for the `versionHistory` parameter to the KMP resource in Ratify. This parameter will allow users to specify the number of versions of a certificate or key that should be retained in the cache. + +When a new version of a certificate or key is created, Ratify will check the `versionHistory` parameter to determine how many versions should be retained in the cache. If the number of versions exceeds the specified count, Ratify will remove the oldest version from the cache. + +If a version is disabled, Ratify will remove it from the cache. This ensures that disabled versions are not retained in the cache, reducing the risk of using compromised keys or certificates being passed to the verifiers. + +Example: AKV KMP resource with `versionHistory` parameter + +```yaml +apiVersion: config.ratify.deislabs.io/v1beta1 +kind: KeyManagementProvider +metadata: + name: keymanagementprovider-akv +spec: + type: azurekeyvault + refreshInterval: 1m + parameters: + vaultURI: https://yourkeyvault.vault.azure.net/ + certificates: + - name: yourCertName + versionHistory: 2 + tenantID: + clientID: +``` + +Example: AKV KMP resource status with multiple versions retained in the cache + +```yaml +Status: + Issuccess: true + Lastfetchedtime: 2024-10-02T14:58:54Z + Properties: + Certificates: + Last Refreshed: 2024-10-02T14:58:54Z + Name: yourCertName + Version: a1b2c3d4e5f67890abcdef1234567890 + Enabled: true + Last Refreshed: 2024-10-02T14:58:54Z + Name: yourCertName + Version: 0ff373a9259c4578a247cfd7861a8805 + Enabled: false +``` + +## Implementation Details + +- Modify the KMP data structure to include the status of the version. + ```go + type KMPMapKey struct { + Name string + Version string + Enabled string // true or false + Created time.Time // Time the version was created used for determining the oldest version + } + ``` +- Add the `versionHistory` parameter to the KMP resource in Ratify. + - ensure the value cannot be less than 0 or a negative number + - default to 2 if not specified by passing an empty value + - maximum value should be (TBD) + - specify the value at the object level within the parameters of the KMP resource. +- Changes to `azurekeyvault` provider: + - support for the `versionHistory` parameter. + - allowing retrieval of multiple versions of certificates or keys. + - remove the oldest version from the cache when the number of versions exceeds the `versionHistory` parameter. + - update disabled certs status in the cache & remove the certData from the cache. +- Log when the status of a version changes. +- Log when a conflict between the `versionHistory` and the number of specified certificate versions occurs. + +## Dev Work Items + +## Open Questions + +- If a version is disabled, should it be removed from the cache or retained based on the nVersionCount and marked as inactive\disabled? + - [x] Keep the disabled version in the cache and mark it as disabled. +- If a version is disabled, does that count towards the nVersionCount? For example, if nVersionCount is set to 3 and one of the versions is disabled, should Ratify retain the last three active versions or the last three versions, regardless of their status? + - [x] Yes, disabled versions should count towards the nVersionCount. The reason for this is that disabled versions may be re-enabled in the future, and it is important to retain them in the cache. +- Should the existing KMP data structure be changed to group versions by key or certificate name? + - [x] No, a flat list of versions is sufficient. At this time, there is no need to group versions by key or certificate name because the verifiers do not need to know the history of the versions. +- Should the KMP status return a flat list of versions? + - [x] Yes, the status should return a flat list of versions. + +## Future Considerations + +- What should the maximum value for nVersionCount be? + - [ ] TBD From 44abd8bb844ae104182559fd25415e23563b01c2 Mon Sep 17 00:00:00 2001 From: Binbin Li Date: Tue, 22 Oct 2024 09:01:13 +0800 Subject: [PATCH 10/62] ci: retry trivy db update upon failure (#1881) Signed-off-by: Binbin Li --- Makefile | 45 ++++++++++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/Makefile b/Makefile index 376a2d170..3d06df53b 100644 --- a/Makefile +++ b/Makefile @@ -160,7 +160,7 @@ test-e2e: generate-rotation-certs EXPIRING_CERT_DIR=.staging/rotation/expiring-certs CERT_DIR=.staging/rotation GATEKEEPER_VERSION=${GATEKEEPER_VERSION} bats -t ${BATS_PLUGIN_TESTS_FILE} .PHONY: test-e2e-cli -test-e2e-cli: e2e-dependencies e2e-create-local-registry e2e-notation-setup e2e-notation-leaf-cert-setup e2e-cosign-setup e2e-licensechecker-setup e2e-sbom-setup e2e-schemavalidator-setup e2e-vulnerabilityreport-setup +test-e2e-cli: e2e-dependencies e2e-create-local-registry e2e-notation-setup e2e-notation-leaf-cert-setup e2e-cosign-setup e2e-licensechecker-setup e2e-sbom-setup e2e-trivy-setup e2e-schemavalidator-setup e2e-vulnerabilityreport-setup rm ${GOCOVERDIR} -rf mkdir ${GOCOVERDIR} -p RATIFY_DIR=${INSTALL_DIR} TEST_REGISTRY=${TEST_REGISTRY} ${GITHUB_WORKSPACE}/bin/bats -t ${BATS_CLI_TESTS_FILE} @@ -459,14 +459,37 @@ e2e-sbom-setup: NOTATION_EXPERIMENTAL=1 .staging/notation/notation sign -u ${TEST_REGISTRY_USERNAME} -p ${TEST_REGISTRY_PASSWORD} ${TEST_REGISTRY}/sbom@`${GITHUB_WORKSPACE}/bin/oras discover --distribution-spec v1.1-referrers-api -o json --artifact-type application/spdx+json ${TEST_REGISTRY}/sbom:v0 | jq -r ".manifests[0].digest"` NOTATION_EXPERIMENTAL=1 .staging/notation/notation sign -u ${TEST_REGISTRY_USERNAME} -p ${TEST_REGISTRY_PASSWORD} ${TEST_REGISTRY}/all@`${GITHUB_WORKSPACE}/bin/oras discover --distribution-spec v1.1-referrers-api -o json --artifact-type application/spdx+json ${TEST_REGISTRY}/all:v0 | jq -r ".manifests[0].digest"` +e2e-trivy-setup: + rm -rf .staging/trivy + mkdir -p .staging/trivy + + # Install Trivy + curl -L https://github.com/aquasecurity/trivy/releases/download/v${TRIVY_VERSION}/trivy_${TRIVY_VERSION}_Linux-64bit.tar.gz --output .staging/trivy/trivy.tar.gz + tar -zxf .staging/trivy/trivy.tar.gz -C .staging/trivy + + # Download vulnerability database in retry mode + max_retries=3; \ + attempt=1; \ + wait_time=2; \ + while [ $$attempt -le $$max_retries ]; do \ + echo "Attempt $$attempt of $$max_retries..."; \ + if .staging/trivy/trivy image --download-db-only; then \ + break; \ + fi; \ + if [ $$attempt -eq $$max_retries ]; then \ + echo "Failed after $$max_retries attempts."; \ + exit 1; \ + fi; \ + echo "Failed. Retrying in $$wait_time seconds..."; \ + sleep $$wait_time; \ + wait_time=$$(( wait_time * 2 )); \ + attempt=$$(( attempt + 1 )); \ + done + e2e-schemavalidator-setup: rm -rf .staging/schemavalidator mkdir -p .staging/schemavalidator - # Install Trivy - curl -L https://github.com/aquasecurity/trivy/releases/download/v${TRIVY_VERSION}/trivy_${TRIVY_VERSION}_Linux-64bit.tar.gz --output .staging/schemavalidator/trivy.tar.gz - tar -zxf .staging/schemavalidator/trivy.tar.gz -C .staging/schemavalidator - # Build/Push Images printf 'FROM ${ALPINE_IMAGE}\nCMD ["echo", "schemavalidator image"]' > .staging/schemavalidator/Dockerfile docker buildx create --use @@ -475,7 +498,7 @@ e2e-schemavalidator-setup: rm .staging/schemavalidator/schemavalidator.tar # Create/Attach Scan Results - .staging/schemavalidator/trivy image --format sarif --output .staging/schemavalidator/trivy-scan.sarif ${TEST_REGISTRY}/schemavalidator:v0 + .staging/trivy/trivy image --skip-db-update --format sarif --output .staging/schemavalidator/trivy-scan.sarif ${TEST_REGISTRY}/schemavalidator:v0 ${GITHUB_WORKSPACE}/bin/oras attach \ --artifact-type application/vnd.aquasecurity.trivy.report.sarif.v1 \ --distribution-spec v1.1-referrers-api \ @@ -491,10 +514,6 @@ e2e-vulnerabilityreport-setup: rm -rf .staging/vulnerabilityreport mkdir -p .staging/vulnerabilityreport - # Install Trivy - curl -L https://github.com/aquasecurity/trivy/releases/download/v${TRIVY_VERSION}/trivy_${TRIVY_VERSION}_Linux-64bit.tar.gz --output .staging/vulnerabilityreport/trivy.tar.gz - tar -zxf .staging/vulnerabilityreport/trivy.tar.gz -C .staging/vulnerabilityreport - # Build/Push Image printf 'FROM ${ALPINE_IMAGE_VULNERABLE}\nCMD ["echo", "vulnerabilityreport image"]' > .staging/vulnerabilityreport/Dockerfile docker buildx create --use @@ -503,7 +522,7 @@ e2e-vulnerabilityreport-setup: rm .staging/vulnerabilityreport/vulnerabilityreport.tar # Create/Attach Scan Result - .staging/vulnerabilityreport/trivy image --format sarif --output .staging/vulnerabilityreport/trivy-sarif.json ${TEST_REGISTRY}/vulnerabilityreport:v0 + .staging/trivy/trivy image --skip-db-update --format sarif --output .staging/vulnerabilityreport/trivy-sarif.json ${TEST_REGISTRY}/vulnerabilityreport:v0 ${GITHUB_WORKSPACE}/bin/oras attach \ --artifact-type application/sarif+json \ --distribution-spec v1.1-referrers-api \ @@ -524,7 +543,7 @@ e2e-inlinecert-setup: .staging/notation/notation cert generate-test "alternate-cert" NOTATION_EXPERIMENTAL=1 .staging/notation/notation sign -u ${TEST_REGISTRY_USERNAME} -p ${TEST_REGISTRY_PASSWORD} --key "alternate-cert" ${TEST_REGISTRY}/notation@`${GITHUB_WORKSPACE}/bin/oras manifest fetch ${TEST_REGISTRY}/notation:signed-alternate --descriptor | jq .digest | xargs` -e2e-azure-setup: e2e-create-all-image e2e-notation-setup e2e-notation-leaf-cert-setup e2e-cosign-akv-setup e2e-licensechecker-setup e2e-sbom-setup e2e-schemavalidator-setup +e2e-azure-setup: e2e-create-all-image e2e-notation-setup e2e-notation-leaf-cert-setup e2e-cosign-akv-setup e2e-licensechecker-setup e2e-sbom-setup e2e-trivy-setup e2e-schemavalidator-setup e2e-deploy-gatekeeper: e2e-helm-install ./.staging/helm/linux-amd64/helm repo add gatekeeper https://open-policy-agent.github.io/gatekeeper/charts @@ -560,7 +579,7 @@ e2e-deploy-base-ratify: e2e-notation-setup e2e-notation-leaf-cert-setup e2e-cosi rm mount_config.json -e2e-deploy-ratify: e2e-notation-setup e2e-notation-leaf-cert-setup e2e-cosign-setup e2e-cosign-setup e2e-licensechecker-setup e2e-sbom-setup e2e-schemavalidator-setup e2e-vulnerabilityreport-setup e2e-inlinecert-setup e2e-build-crd-image load-build-crd-image e2e-build-local-ratify-image load-local-ratify-image e2e-helm-deploy-ratify +e2e-deploy-ratify: e2e-notation-setup e2e-notation-leaf-cert-setup e2e-cosign-setup e2e-cosign-setup e2e-licensechecker-setup e2e-sbom-setup e2e-trivy-setup e2e-schemavalidator-setup e2e-vulnerabilityreport-setup e2e-inlinecert-setup e2e-build-crd-image load-build-crd-image e2e-build-local-ratify-image load-local-ratify-image e2e-helm-deploy-ratify e2e-build-local-ratify-base-image: docker build --progress=plain --no-cache \ From 75ed5bad201c923b67117810801a9e07bf988958 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 22 Oct 2024 14:23:04 +0800 Subject: [PATCH 11/62] chore: Bump anchore/sbom-action from 0.17.4 to 0.17.5 (#1882) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3d95884f5..b550b2372 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -26,7 +26,7 @@ jobs: fetch-depth: 0 - name: Install Syft - uses: anchore/sbom-action/download-syft@8d0a6505bf28ced3e85154d13dc6af83299e13f1 # v0.17.4 + uses: anchore/sbom-action/download-syft@1ca97d9028b51809cf6d3c934c3e160716e1b605 # v0.17.5 - name: Set up Go uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 From df7fdffd5281e2ec6c9d2ad82841ceea53473d5b Mon Sep 17 00:00:00 2001 From: Binbin Li Date: Wed, 23 Oct 2024 09:05:59 +0800 Subject: [PATCH 12/62] ci: fix tagging in publish-ghcr workflow (#1884) Signed-off-by: Binbin Li --- .github/workflows/publish-package.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish-package.yml b/.github/workflows/publish-package.yml index 6a1499ecb..21bcf2815 100644 --- a/.github/workflows/publish-package.yml +++ b/.github/workflows/publish-package.yml @@ -64,7 +64,7 @@ jobs: --attest type=sbom \ --attest type=provenance,mode=max \ --platform linux/amd64,linux/arm64,linux/arm/v7 \ - --build-arg LDFLAGS="-X github.com/ratify-project/ratify/internal/version.Version=$(TAG)" \ + --build-arg LDFLAGS="-X github.com/ratify-project/ratify/internal/version.Version=$TAG" \ --label org.opencontainers.image.revision=${{ github.sha }} \ -t ${{ steps.prepare.outputs.baseref }} \ --push . @@ -79,7 +79,7 @@ jobs: --build-arg build_licensechecker=true \ --build-arg build_schemavalidator=true \ --build-arg build_vulnerabilityreport=true \ - --build-arg LDFLAGS="-X github.com/ratify-project/ratify/internal/version.Version=$(TAG)" \ + --build-arg LDFLAGS="-X github.com/ratify-project/ratify/internal/version.Version=$TAG" \ --label org.opencontainers.image.revision=${{ github.sha }} \ -t ${{ steps.prepare.outputs.ref }} \ --push . From c4adde7881d5b3d6c6e2ea1d3f8550a3ec41639c Mon Sep 17 00:00:00 2001 From: Binbin Li Date: Wed, 23 Oct 2024 10:16:23 +0800 Subject: [PATCH 13/62] ci: retry trivy download-db on failure (#1883) Signed-off-by: Binbin Li --- .github/workflows/scan-vulns.yaml | 76 ++++++++++++------------------- 1 file changed, 28 insertions(+), 48 deletions(-) diff --git a/.github/workflows/scan-vulns.yaml b/.github/workflows/scan-vulns.yaml index a4182aa7e..23208d9b1 100644 --- a/.github/workflows/scan-vulns.yaml +++ b/.github/workflows/scan-vulns.yaml @@ -38,7 +38,7 @@ jobs: runs-on: ubuntu-22.04 timeout-minutes: 15 env: - TRIVY_VERSION: v0.49.1 + TRIVY_VERSION: 0.49.1 steps: - name: Harden Runner uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 @@ -48,58 +48,38 @@ jobs: - name: Check out code into the Go module directory uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 - - name: Manual Trivy Setup - uses: aquasecurity/setup-trivy@eadb05c36f891dc855bba00f67174a1e61528cd4 # v0.2.1 + - name: Download trivy + run: | + pushd $(mktemp -d) + wget https://github.com/aquasecurity/trivy/releases/download/v${{ env.TRIVY_VERSION }}/trivy_${{ env.TRIVY_VERSION }}_Linux-64bit.tar.gz + tar zxvf trivy_${{ env.TRIVY_VERSION }}_Linux-64bit.tar.gz + echo "$(pwd)" >> $GITHUB_PATH + + - name: Download vulnerability database + uses: nick-fields/retry@7152eba30c6575329ac0576536151aca5a72780e # v3.0.0 with: - cache: true - version: ${{ env.TRIVY_VERSION }} + max_attempts: 3 + retry_on: error + timeout_seconds: 30 + retry_wait_seconds: 5 + command: | + trivy image --download-db-only - name: Run trivy on git repository - uses: aquasecurity/trivy-action@915b19bbe73b92a6cf82a1bc12b087c9a19a5fe2 # 0.28.0 - with: - scan-type: 'fs' - scan-ref: '.' - ignore-unfixed: true - scanners: 'vuln' - version: ${{ env.TRIVY_VERSION }} + run: | + trivy fs --skip-db-update --format table --ignore-unfixed --scanners vuln . - name: Build docker images run: | make e2e-build-local-ratify-image make e2e-build-crd-image - - - name: Run Trivy vulnerability scanner on localbuild:test - uses: aquasecurity/trivy-action@915b19bbe73b92a6cf82a1bc12b087c9a19a5fe2 # 0.28.0 - with: - scan-type: 'image' - image-ref: 'localbuild:test' - ignore-unfixed: true - version: ${{ env.TRIVY_VERSION }} - - - name: Run Trivy vulnerability scanner on localbuildcrd:test - uses: aquasecurity/trivy-action@915b19bbe73b92a6cf82a1bc12b087c9a19a5fe2 # 0.28.0 - with: - scan-type: 'image' - image-ref: 'localbuildcrd:test' - ignore-unfixed: true - version: ${{ env.TRIVY_VERSION }} - - - name: Run Trivy vulnerability scanner on localbuild:test and exit on HIGH severity - uses: aquasecurity/trivy-action@915b19bbe73b92a6cf82a1bc12b087c9a19a5fe2 # 0.28.0 - with: - scan-type: 'image' - image-ref: 'localbuild:test' - ignore-unfixed: true - severity: 'HIGH,CRITICAL' - exit-code: '1' - version: ${{ env.TRIVY_VERSION }} - - - name: Run Trivy vulnerability scanner on localbuildcrd:test and exit on HIGH severity - uses: aquasecurity/trivy-action@915b19bbe73b92a6cf82a1bc12b087c9a19a5fe2 # 0.28.0 - with: - scan-type: 'image' - image-ref: 'localbuildcrd:test' - ignore-unfixed: true - severity: 'HIGH,CRITICAL' - exit-code: '1' - version: ${{ env.TRIVY_VERSION }} \ No newline at end of file + - name: Run trivy on images for all severity + run: | + for img in "localbuild:test" "localbuildcrd:test"; do + trivy image --skip-db-update --ignore-unfixed --vuln-type="os,library" "${img}" + done + - name: Run trivy on images and exit on HIGH/CRITICAL severity + run: | + for img in "localbuild:test" "localbuildcrd:test"; do + trivy image --skip-db-update --ignore-unfixed --exit-code 1 --severity HIGH,CRITICAL --vuln-type="os,library" "${img}" + done \ No newline at end of file From 7c58a9ac1e260e8caa7e0c9f5194f6a4085d33e5 Mon Sep 17 00:00:00 2001 From: shahramk64 Date: Wed, 23 Oct 2024 15:14:31 +1000 Subject: [PATCH 14/62] chore: migrate azure-sdk-for-go/containerregistry to the latest release (#1829) Signed-off-by: Shahram Kalantari --- go.mod | 10 +- go.sum | 19 +- .../oras/authprovider/azure/azureidentity.go | 105 ++++-- .../authprovider/azure/azureidentity_test.go | 183 ++++++++++- .../azure/azureworkloadidentity.go | 94 ++++-- .../azure/azureworkloadidentity_test.go | 309 +++++++++++++++++- pkg/common/oras/authprovider/azure/helper.go | 84 +++++ .../oras/authprovider/azure/helper_test.go | 100 ++++++ 8 files changed, 834 insertions(+), 70 deletions(-) create mode 100644 pkg/common/oras/authprovider/azure/helper.go create mode 100644 pkg/common/oras/authprovider/azure/helper_test.go diff --git a/go.mod b/go.mod index 27d1f11c1..be3607472 100644 --- a/go.mod +++ b/go.mod @@ -10,8 +10,9 @@ retract ( require ( github.com/Azure/azure-sdk-for-go v68.0.0+incompatible - 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/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 + github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 + github.com/Azure/azure-sdk-for-go/sdk/containers/azcontainerregistry v0.2.2 github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 github.com/aws/aws-sdk-go-v2 v1.32.2 github.com/aws/aws-sdk-go-v2/config v1.27.43 @@ -118,6 +119,7 @@ require ( github.com/sigstore/timestamp-authority v1.2.2 // indirect github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect github.com/sourcegraph/conc v0.3.0 // indirect + github.com/stretchr/objx v0.5.2 // indirect github.com/tchap/go-patricia/v2 v2.3.1 // indirect github.com/thales-e-security/pool v0.0.2 // indirect github.com/tjfoc/gmsm v1.4.1 // indirect @@ -130,7 +132,7 @@ require ( ) require ( - github.com/Azure/azure-sdk-for-go/sdk/internal v1.8.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect github.com/Azure/go-autorest/autorest v0.11.29 github.com/Azure/go-autorest/autorest/adal v0.9.24 // indirect @@ -237,7 +239,7 @@ require ( golang.org/x/crypto v0.28.0 golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 // indirect golang.org/x/mod v0.20.0 // indirect - golang.org/x/net v0.28.0 // indirect + golang.org/x/net v0.29.0 // indirect golang.org/x/oauth2 v0.23.0 // indirect golang.org/x/sys v0.26.0 // indirect golang.org/x/term v0.25.0 // indirect diff --git a/go.sum b/go.sum index d94ab83cf..ecb26633c 100644 --- a/go.sum +++ b/go.sum @@ -18,12 +18,14 @@ github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/alibabacloudsdkgo github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/alibabacloudsdkgo/helper v0.2.0/go.mod h1:GgeIE+1be8Ivm7Sh4RgwI42aTtC9qrcj+Y9Y6CjJhJs= github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU= github.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1 h1:E+OJmp2tPvt1W+amx48v1eqbjDYsgN+RzP4q16yV5eM= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1/go.mod h1:a6xsAQUZg+VsS3TJ05SRp524Hs4pZ/AeFSr5ENf0Yjo= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.6.0 h1:U2rTu3Ef+7w9FHKIAXM6ZyqF3UOWJZ12zIm8zECAFfg= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.6.0/go.mod h1:9kIvujWAA58nmPmWB1m23fyWic1kYZMxD9CxaWn4Qpg= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.8.0 h1:jBQA3cKT4L2rWMpgE7Yt3Hwh2aUj8KXjIGLxjHeYNNo= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.8.0/go.mod h1:4OG6tQ9EOP/MT0NMjDlRzWoVFxfu9rN9B2X+tlSVktg= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 h1:nyQWyZvwGTvunIMxi1Y9uXkcyr+I7TeNrr/foo4Kpk8= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0/go.mod h1:l38EPgmsp71HHLq9j7De57JcKOWPyhrsW1Awm1JS6K0= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 h1:tfLQ34V6F7tVSwoTf/4lH5sE0o6eCJuNDTmH09nDpbc= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0/go.mod h1:9kIvujWAA58nmPmWB1m23fyWic1kYZMxD9CxaWn4Qpg= +github.com/Azure/azure-sdk-for-go/sdk/containers/azcontainerregistry v0.2.2 h1:wBx10efdJcl8FSewgc41kAW4AvHPgmJZmN7fpNxn8rc= +github.com/Azure/azure-sdk-for-go/sdk/containers/azcontainerregistry v0.2.2/go.mod h1:zzmu18cpAinSbhC86oWd47nmgbb91Fl+Yac2PE8NdYk= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.1.0 h1:DRiANoJTiW6obBQe3SqZizkuV1PEgfiiGivmVocDy64= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.1.0/go.mod h1:qLIye2hwb/ZouqhpSD9Zn3SJipvpEnz1Ywl3VUk9Y0s= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0 h1:D3occbWoio4EBLkbkevetNMAVX197GkzbUMtqjGWn80= @@ -657,6 +659,7 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -823,8 +826,8 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= +golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= diff --git a/pkg/common/oras/authprovider/azure/azureidentity.go b/pkg/common/oras/authprovider/azure/azureidentity.go index 0a5a00e5c..d0369c4dc 100644 --- a/pkg/common/oras/authprovider/azure/azureidentity.go +++ b/pkg/common/oras/authprovider/azure/azureidentity.go @@ -29,14 +29,44 @@ import ( "github.com/Azure/azure-sdk-for-go/sdk/azcore" "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" "github.com/Azure/azure-sdk-for-go/sdk/azidentity" - "github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/runtime/2019-08-15-preview/containerregistry" + "github.com/Azure/azure-sdk-for-go/sdk/containers/azcontainerregistry" ) +// ManagedIdentityTokenGetter defines an interface for getting a managed identity token. +type ManagedIdentityTokenGetter interface { + GetManagedIdentityToken(ctx context.Context, clientID string) (azcore.AccessToken, error) +} + +// defaultManagedIdentityTokenGetterImpl is the default implementation of getManagedIdentityToken. +type defaultManagedIdentityTokenGetterImpl struct{} + +func (g *defaultManagedIdentityTokenGetterImpl) GetManagedIdentityToken(ctx context.Context, clientID string) (azcore.AccessToken, error) { + return getManagedIdentityToken(ctx, clientID, azidentity.NewManagedIdentityCredential) +} + +func getManagedIdentityToken(ctx context.Context, clientID string, newCredentialFunc func(opts *azidentity.ManagedIdentityCredentialOptions) (*azidentity.ManagedIdentityCredential, error)) (azcore.AccessToken, error) { + id := azidentity.ClientID(clientID) + opts := azidentity.ManagedIdentityCredentialOptions{ID: id} + cred, err := newCredentialFunc(&opts) + if err != nil { + return azcore.AccessToken{}, err + } + scopes := []string{AADResource} + if cred != nil { + return cred.GetToken(ctx, policy.TokenRequestOptions{Scopes: scopes}) + } + return azcore.AccessToken{}, re.ErrorCodeConfigInvalid.WithComponentType(re.AuthProvider).WithDetail("config is nil pointer for GetServicePrincipalToken") +} + type azureManagedIdentityProviderFactory struct{} -type azureManagedIdentityAuthProvider struct { - identityToken azcore.AccessToken - clientID string - tenantID string + +type MIAuthProvider struct { + identityToken azcore.AccessToken + clientID string + tenantID string + authClientFactory AuthClientFactory + registryHostGetter RegistryHostGetter + getManagedIdentityToken ManagedIdentityTokenGetter } type azureManagedIdentityAuthProviderConf struct { @@ -53,7 +83,7 @@ func init() { provider.Register(azureManagedIdentityAuthProviderName, &azureManagedIdentityProviderFactory{}) } -// Create returns an azureManagedIdentityAuthProvider +// Create returns an MIAuthProvider func (s *azureManagedIdentityProviderFactory) Create(authProviderConfig provider.AuthProviderConfig) (provider.AuthProvider, error) { conf := azureManagedIdentityAuthProviderConf{} authProviderConfigBytes, err := json.Marshal(authProviderConfig) @@ -80,20 +110,22 @@ func (s *azureManagedIdentityProviderFactory) Create(authProviderConfig provider return nil, err } // retrieve an AAD Access token - token, err := getManagedIdentityToken(context.Background(), client) + token, err := getManagedIdentityToken(context.Background(), client, azidentity.NewManagedIdentityCredential) if err != nil { return nil, re.ErrorCodeAuthDenied.NewError(re.AuthProvider, "", re.AzureManagedIdentityLink, err, "", re.HideStackTrace) } - return &azureManagedIdentityAuthProvider{ - identityToken: token, - clientID: client, - tenantID: tenant, + return &MIAuthProvider{ + identityToken: token, + clientID: client, + tenantID: tenant, + authClientFactory: &defaultAuthClientFactoryImpl{}, // Concrete implementation + getManagedIdentityToken: &defaultManagedIdentityTokenGetterImpl{}, // Concrete implementation }, nil } // Enabled checks for non empty tenant ID and AAD access token -func (d *azureManagedIdentityAuthProvider) Enabled(_ context.Context) bool { +func (d *MIAuthProvider) Enabled(_ context.Context) bool { if d.clientID == "" { return false } @@ -112,57 +144,58 @@ func (d *azureManagedIdentityAuthProvider) Enabled(_ context.Context) bool { // Provide returns the credentials for a specified artifact. // Uses Managed Identity to retrieve an AAD access token which can be // exchanged for a valid ACR refresh token for login. -func (d *azureManagedIdentityAuthProvider) Provide(ctx context.Context, artifact string) (provider.AuthConfig, error) { +func (d *MIAuthProvider) Provide(ctx context.Context, artifact string) (provider.AuthConfig, error) { if !d.Enabled(ctx) { return provider.AuthConfig{}, fmt.Errorf("azure managed identity provider is not properly enabled") } + // parse the artifact reference string to extract the registry host name - artifactHostName, err := provider.GetRegistryHostName(artifact) + artifactHostName, err := d.registryHostGetter.GetRegistryHost(artifact) if err != nil { - return provider.AuthConfig{}, err + return provider.AuthConfig{}, re.ErrorCodeHostNameInvalid.WithComponentType(re.AuthProvider) } // need to refresh AAD token if it's expired if time.Now().Add(time.Minute * 5).After(d.identityToken.ExpiresOn) { - newToken, err := getManagedIdentityToken(ctx, d.clientID) + newToken, err := d.getManagedIdentityToken.GetManagedIdentityToken(ctx, d.clientID) if err != nil { return provider.AuthConfig{}, re.ErrorCodeAuthDenied.NewError(re.AuthProvider, "", re.AzureManagedIdentityLink, err, "could not refresh azure managed identity token", re.HideStackTrace) } d.identityToken = newToken logger.GetLogger(ctx, logOpt).Info("successfully refreshed azure managed identity token") } + // add protocol to generate complete URI serverURL := "https://" + artifactHostName - // create registry client and exchange AAD token for registry refresh token - refreshTokenClient := containerregistry.NewRefreshTokensClient(serverURL) - rt, err := refreshTokenClient.GetFromExchange(ctx, "access_token", artifactHostName, d.tenantID, "", d.identityToken.Token) + // TODO: Consider adding authentication client options for multicloud scenarios + var options *azcontainerregistry.AuthenticationClientOptions + client, err := d.authClientFactory.CreateAuthClient(serverURL, options) + if err != nil { + return provider.AuthConfig{}, re.ErrorCodeAuthDenied.WithError(err).WithDetail("failed to create authentication client for container registry by azure managed identity token") + } + + response, err := client.ExchangeAADAccessTokenForACRRefreshToken( + ctx, + azcontainerregistry.PostContentSchemaGrantType(GrantTypeAccessToken), + artifactHostName, + &azcontainerregistry.AuthenticationClientExchangeAADAccessTokenForACRRefreshTokenOptions{ + AccessToken: &d.identityToken.Token, + Tenant: &d.tenantID, + }, + ) if err != nil { return provider.AuthConfig{}, re.ErrorCodeAuthDenied.NewError(re.AuthProvider, "", re.AzureManagedIdentityLink, err, "failed to get refresh token for container registry by azure managed identity token", re.HideStackTrace) } + rt := response.ACRRefreshToken - expiresOn := getACRExpiryIfEarlier(d.identityToken.ExpiresOn) - + refreshTokenExpiry := getACRExpiryIfEarlier(d.identityToken.ExpiresOn) authConfig := provider.AuthConfig{ Username: dockerTokenLoginUsernameGUID, Password: *rt.RefreshToken, Provider: d, - ExpiresOn: expiresOn, + ExpiresOn: refreshTokenExpiry, } return authConfig, nil } - -func getManagedIdentityToken(ctx context.Context, clientID string) (azcore.AccessToken, error) { - id := azidentity.ClientID(clientID) - opts := azidentity.ManagedIdentityCredentialOptions{ID: id} - cred, err := azidentity.NewManagedIdentityCredential(&opts) - if err != nil { - return azcore.AccessToken{}, err - } - scopes := []string{AADResource} - if cred != nil { - return cred.GetToken(ctx, policy.TokenRequestOptions{Scopes: scopes}) - } - return azcore.AccessToken{}, re.ErrorCodeConfigInvalid.WithComponentType(re.AuthProvider).WithDetail("config is nil pointer for GetServicePrincipalToken") -} diff --git a/pkg/common/oras/authprovider/azure/azureidentity_test.go b/pkg/common/oras/authprovider/azure/azureidentity_test.go index 472e704b9..8d466d3d1 100644 --- a/pkg/common/oras/authprovider/azure/azureidentity_test.go +++ b/pkg/common/oras/authprovider/azure/azureidentity_test.go @@ -20,15 +20,31 @@ import ( "errors" "os" "testing" + "time" "github.com/Azure/azure-sdk-for-go/sdk/azcore" + "github.com/Azure/azure-sdk-for-go/sdk/azidentity" + azcontainerregistry "github.com/Azure/azure-sdk-for-go/sdk/containers/azcontainerregistry" ratifyerrors "github.com/ratify-project/ratify/errors" "github.com/ratify-project/ratify/pkg/common/oras/authprovider" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" ) +// Mock types for external dependencies +type MockManagedIdentityTokenGetter struct { + mock.Mock +} + +// Mock ManagedIdentityTokenGetter.GetManagedIdentityToken +func (m *MockManagedIdentityTokenGetter) GetManagedIdentityToken(ctx context.Context, clientID string) (azcore.AccessToken, error) { + args := m.Called(ctx, clientID) + return args.Get(0).(azcore.AccessToken), args.Error(1) +} + // Verifies that Enabled checks if tenantID is empty or AAD token is empty func TestAzureMSIEnabled_ExpectedResults(t *testing.T) { - azAuthProvider := azureManagedIdentityAuthProvider{ + azAuthProvider := MIAuthProvider{ tenantID: "test_tenant", clientID: "test_client", identityToken: azcore.AccessToken{ @@ -89,3 +105,168 @@ func TestAzureMSIValidation_EnvironmentVariables_ExpectedResults(t *testing.T) { t.Fatalf("create auth provider should have failed: expected err %s, but got err %s", expectedErr, err) } } + +// Test for invalid configuration when tenant ID is missing +func TestAzureManagedIdentityProviderFactory_Create_NoTenantID(t *testing.T) { + t.Setenv("AZURE_TENANT_ID", "") + + // Initialize factory + factory := &azureManagedIdentityProviderFactory{} + + // Attempt to create MIAuthProvider with empty configuration + _, err := factory.Create(map[string]interface{}{}) + + // Validate the error + assert.Error(t, err) + assert.Contains(t, err.Error(), "AZURE_TENANT_ID environment variable is empty") +} + +// Test for missing client ID +func TestAzureManagedIdentityProviderFactory_Create_NoClientID(t *testing.T) { + t.Setenv("AZURE_TENANT_ID", "tenantID") + t.Setenv("AZURE_CLIENT_ID", "") + + // Initialize factory + factory := &azureManagedIdentityProviderFactory{} + + // Attempt to create MIAuthProvider with empty client ID + _, err := factory.Create(map[string]interface{}{}) + + // Validate the error + assert.Error(t, err) + assert.Contains(t, err.Error(), "AZURE_CLIENT_ID environment variable is empty") +} + +// Test successful token refresh +func TestMIAuthProvider_Provide_TokenRefreshSuccess(t *testing.T) { + // Mock dependencies + mockAuthClientFactory := new(MockAuthClientFactory) + mockRegistryHostGetter := new(MockRegistryHostGetter) + mockManagedIdentityTokenGetter := new(MockManagedIdentityTokenGetter) + mockAuthClient := new(MockAuthClient) + + // Define token values + expiredToken := azcore.AccessToken{Token: "expired_token", ExpiresOn: time.Now().Add(-10 * time.Minute)} + newTokenString := "refreshed" + newAADToken := azcore.AccessToken{Token: "new_token", ExpiresOn: time.Now().Add(10 * time.Minute)} + refreshToken := azcontainerregistry.AuthenticationClientExchangeAADAccessTokenForACRRefreshTokenResponse{ + ACRRefreshToken: azcontainerregistry.ACRRefreshToken{RefreshToken: &newTokenString}, + } + + // Setup mock expectations + mockRegistryHostGetter.On("GetRegistryHost", "artifact_name").Return("example.azurecr.io", nil) + mockAuthClientFactory.On("CreateAuthClient", "https://example.azurecr.io", mock.Anything).Return(mockAuthClient, nil) + mockAuthClient.On("ExchangeAADAccessTokenForACRRefreshToken", mock.Anything, azcontainerregistry.PostContentSchemaGrantType(GrantTypeAccessToken), "example.azurecr.io", mock.Anything).Return(refreshToken, nil) + mockManagedIdentityTokenGetter.On("GetManagedIdentityToken", mock.Anything, "clientID").Return(newAADToken, nil) + + // Initialize provider with expired token + provider := MIAuthProvider{ + identityToken: expiredToken, + clientID: "clientID", + tenantID: "tenantID", + authClientFactory: mockAuthClientFactory, + registryHostGetter: mockRegistryHostGetter, + getManagedIdentityToken: mockManagedIdentityTokenGetter, + } + + // Call Provide method + ctx := context.Background() + authConfig, err := provider.Provide(ctx, "artifact_name") + + // Validate success and token refresh + assert.NoError(t, err) + assert.Equal(t, "refreshed", authConfig.Password) +} + +// Test failed token refresh +func TestMIAuthProvider_Provide_TokenRefreshFailure(t *testing.T) { + // Mock dependencies + mockAuthClientFactory := new(MockAuthClientFactory) + mockRegistryHostGetter := new(MockRegistryHostGetter) + mockManagedIdentityTokenGetter := new(MockManagedIdentityTokenGetter) + + // Define token values + expiredToken := azcore.AccessToken{Token: "expired_token", ExpiresOn: time.Now().Add(-10 * time.Minute)} + + // Setup mock expectations + mockRegistryHostGetter.On("GetRegistryHost", "artifact_name").Return("example.azurecr.io", nil) + mockManagedIdentityTokenGetter.On("GetManagedIdentityToken", mock.Anything, "clientID").Return(azcore.AccessToken{}, errors.New("token refresh failed")) + + // Initialize provider with expired token + provider := MIAuthProvider{ + identityToken: expiredToken, + clientID: "clientID", + tenantID: "tenantID", + authClientFactory: mockAuthClientFactory, + registryHostGetter: mockRegistryHostGetter, + getManagedIdentityToken: mockManagedIdentityTokenGetter, + } + + // Call Provide method + ctx := context.Background() + _, err := provider.Provide(ctx, "artifact_name") + + // Validate failure + assert.Error(t, err) + assert.Contains(t, err.Error(), "could not refresh azure managed identity token") +} + +// Test for invalid hostname retrieval +func TestMIAuthProvider_Provide_InvalidHostName(t *testing.T) { + // Mock dependencies + mockAuthClientFactory := new(MockAuthClientFactory) + mockRegistryHostGetter := new(MockRegistryHostGetter) + mockManagedIdentityTokenGetter := new(MockManagedIdentityTokenGetter) + + // Define valid token + validToken := azcore.AccessToken{Token: "valid_token", ExpiresOn: time.Now().Add(10 * time.Minute)} + + // Setup mock expectations for invalid hostname + mockRegistryHostGetter.On("GetRegistryHost", "artifact_name").Return("", errors.New("invalid hostname")) + + // Initialize provider with valid token + provider := MIAuthProvider{ + identityToken: validToken, + clientID: "clientID", + tenantID: "tenantID", + authClientFactory: mockAuthClientFactory, + registryHostGetter: mockRegistryHostGetter, + getManagedIdentityToken: mockManagedIdentityTokenGetter, + } + + // Call Provide method + ctx := context.Background() + _, err := provider.Provide(ctx, "artifact_name") + + // Validate failure + assert.Error(t, err) + assert.Contains(t, err.Error(), "HOST_NAME_INVALID") +} + +// Unit tests +func TestGetManagedIdentityToken(t *testing.T) { + ctx := context.Background() + clientID := "test-client-id" + expectedToken := azcore.AccessToken{Token: "test-token", ExpiresOn: time.Now().Add(time.Hour)} + + mockGetter := new(MockManagedIdentityTokenGetter) + mockGetter.On("GetManagedIdentityToken", ctx, clientID).Return(expectedToken, nil) + + token, err := mockGetter.GetManagedIdentityToken(ctx, clientID) + assert.Nil(t, err) + assert.Equal(t, expectedToken, token) +} + +func TestGetManagedIdentityToken_Error(t *testing.T) { + ctx := context.Background() + clientID := "test-client-id" + + // Mock the newCredentialFunc to return an error + mockNewCredentialFunc := func(_ *azidentity.ManagedIdentityCredentialOptions) (*azidentity.ManagedIdentityCredential, error) { + return nil, assert.AnError + } + + token, err := getManagedIdentityToken(ctx, clientID, mockNewCredentialFunc) + assert.NotNil(t, err) + assert.Equal(t, azcore.AccessToken{}, token) +} diff --git a/pkg/common/oras/authprovider/azure/azureworkloadidentity.go b/pkg/common/oras/authprovider/azure/azureworkloadidentity.go index a40ce4436..31f45127d 100644 --- a/pkg/common/oras/authprovider/azure/azureworkloadidentity.go +++ b/pkg/common/oras/authprovider/azure/azureworkloadidentity.go @@ -21,21 +21,57 @@ import ( "os" "time" + azcontainerregistry "github.com/Azure/azure-sdk-for-go/sdk/containers/azcontainerregistry" re "github.com/ratify-project/ratify/errors" "github.com/ratify-project/ratify/internal/logger" provider "github.com/ratify-project/ratify/pkg/common/oras/authprovider" - "github.com/ratify-project/ratify/pkg/metrics" "github.com/ratify-project/ratify/pkg/utils/azureauth" - "github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/runtime/2019-08-15-preview/containerregistry" "github.com/AzureAD/microsoft-authentication-library-for-go/apps/confidential" ) +// AADAccessTokenGetter defines an interface for getting an AAD access token. +type AADAccessTokenGetter interface { + GetAADAccessToken(ctx context.Context, tenantID, clientID, resource string) (confidential.AuthResult, error) +} + +// defaultAADAccessTokenGetterImpl is the default implementation of AADAccessTokenGetter. +type defaultAADAccessTokenGetterImpl struct{} + +func (g *defaultAADAccessTokenGetterImpl) GetAADAccessToken(ctx context.Context, tenantID, clientID, resource string) (confidential.AuthResult, error) { + return defaultGetAADAccessToken(ctx, tenantID, clientID, resource) +} + +func defaultGetAADAccessToken(ctx context.Context, tenantID, clientID, resource string) (confidential.AuthResult, error) { + return azureauth.GetAADAccessToken(ctx, tenantID, clientID, resource) +} + +// MetricsReporter defines an interface for reporting metrics. +type MetricsReporter interface { + ReportMetrics(ctx context.Context, duration int64, artifactHostName string) +} + +// defaultMetricsReporterImpl is the default implementation of MetricsReporter. +type defaultMetricsReporterImpl struct{} + +func (r *defaultMetricsReporterImpl) ReportMetrics(ctx context.Context, duration int64, artifactHostName string) { + defaultReportMetrics(ctx, duration, artifactHostName) +} + +func defaultReportMetrics(ctx context.Context, duration int64, artifactHostName string) { + logger.GetLogger(ctx, logOpt).Infof("Metrics Report: Duration=%dms, Host=%s", duration, artifactHostName) +} + type AzureWIProviderFactory struct{} //nolint:revive // ignore linter to have unique type name -type azureWIAuthProvider struct { - aadToken confidential.AuthResult - tenantID string - clientID string + +type WIAuthProvider struct { + aadToken confidential.AuthResult + tenantID string + clientID string + authClientFactory AuthClientFactory + registryHostGetter RegistryHostGetter + getAADAccessToken AADAccessTokenGetter + reportMetrics MetricsReporter } type azureWIAuthProviderConf struct { @@ -78,20 +114,24 @@ func (s *AzureWIProviderFactory) Create(authProviderConfig provider.AuthProvider } // retrieve an AAD Access token - token, err := azureauth.GetAADAccessToken(context.Background(), tenant, clientID, AADResource) + token, err := defaultGetAADAccessToken(context.Background(), tenant, clientID, AADResource) if err != nil { return nil, re.ErrorCodeAuthDenied.NewError(re.AuthProvider, "", re.AzureWorkloadIdentityLink, err, "", re.HideStackTrace) } - return &azureWIAuthProvider{ - aadToken: token, - tenantID: tenant, - clientID: clientID, + return &WIAuthProvider{ + aadToken: token, + tenantID: tenant, + clientID: clientID, + authClientFactory: &defaultAuthClientFactoryImpl{}, // Concrete implementation + registryHostGetter: &defaultRegistryHostGetterImpl{}, // Concrete implementation + getAADAccessToken: &defaultAADAccessTokenGetterImpl{}, // Concrete implementation + reportMetrics: &defaultMetricsReporterImpl{}, }, nil } // Enabled checks for non empty tenant ID and AAD access token -func (d *azureWIAuthProvider) Enabled(_ context.Context) bool { +func (d *WIAuthProvider) Enabled(_ context.Context) bool { if d.tenantID == "" || d.clientID == "" { return false } @@ -106,19 +146,20 @@ func (d *azureWIAuthProvider) Enabled(_ context.Context) bool { // Provide returns the credentials for a specified artifact. // Uses Azure Workload Identity to retrieve an AAD access token which can be // exchanged for a valid ACR refresh token for login. -func (d *azureWIAuthProvider) Provide(ctx context.Context, artifact string) (provider.AuthConfig, error) { +func (d *WIAuthProvider) Provide(ctx context.Context, artifact string) (provider.AuthConfig, error) { if !d.Enabled(ctx) { return provider.AuthConfig{}, re.ErrorCodeConfigInvalid.WithComponentType(re.AuthProvider).WithDetail("azure workload identity auth provider is not properly enabled") } + // parse the artifact reference string to extract the registry host name - artifactHostName, err := provider.GetRegistryHostName(artifact) + artifactHostName, err := d.registryHostGetter.GetRegistryHost(artifact) if err != nil { return provider.AuthConfig{}, re.ErrorCodeHostNameInvalid.WithComponentType(re.AuthProvider) } // need to refresh AAD token if it's expired if time.Now().Add(time.Minute * 5).After(d.aadToken.ExpiresOn) { - newToken, err := azureauth.GetAADAccessToken(ctx, d.tenantID, d.clientID, AADResource) + newToken, err := d.getAADAccessToken.GetAADAccessToken(ctx, d.tenantID, d.clientID, AADResource) if err != nil { return provider.AuthConfig{}, re.ErrorCodeAuthDenied.NewError(re.AuthProvider, "", re.AzureWorkloadIdentityLink, nil, "could not refresh AAD token", re.HideStackTrace) } @@ -129,14 +170,29 @@ func (d *azureWIAuthProvider) Provide(ctx context.Context, artifact string) (pro // add protocol to generate complete URI serverURL := "https://" + artifactHostName - // create registry client and exchange AAD token for registry refresh token - refreshTokenClient := containerregistry.NewRefreshTokensClient(serverURL) + // TODO: Consider adding authentication client options for multicloud scenarios + var options *azcontainerregistry.AuthenticationClientOptions + client, err := d.authClientFactory.CreateAuthClient(serverURL, options) + if err != nil { + return provider.AuthConfig{}, re.ErrorCodeAuthDenied.WithError(err).WithDetail("failed to create authentication client for container registry by azure managed identity token") + } + startTime := time.Now() - rt, err := refreshTokenClient.GetFromExchange(context.Background(), "access_token", artifactHostName, d.tenantID, "", d.aadToken.AccessToken) + response, err := client.ExchangeAADAccessTokenForACRRefreshToken( + ctx, + azcontainerregistry.PostContentSchemaGrantType(GrantTypeAccessToken), + artifactHostName, + &azcontainerregistry.AuthenticationClientExchangeAADAccessTokenForACRRefreshTokenOptions{ + AccessToken: &d.aadToken.AccessToken, + Tenant: &d.tenantID, + }, + ) if err != nil { return provider.AuthConfig{}, re.ErrorCodeAuthDenied.NewError(re.AuthProvider, "", re.AzureWorkloadIdentityLink, err, "failed to get refresh token for container registry", re.HideStackTrace) } - metrics.ReportACRExchangeDuration(ctx, time.Since(startTime).Milliseconds(), artifactHostName) + rt := response.ACRRefreshToken + + d.reportMetrics.ReportMetrics(ctx, time.Since(startTime).Milliseconds(), artifactHostName) refreshTokenExpiry := getACRExpiryIfEarlier(d.aadToken.ExpiresOn) authConfig := provider.AuthConfig{ diff --git a/pkg/common/oras/authprovider/azure/azureworkloadidentity_test.go b/pkg/common/oras/authprovider/azure/azureworkloadidentity_test.go index 3695ef65a..b2ffaa0cd 100644 --- a/pkg/common/oras/authprovider/azure/azureworkloadidentity_test.go +++ b/pkg/common/oras/authprovider/azure/azureworkloadidentity_test.go @@ -22,14 +22,319 @@ import ( "testing" "time" - "github.com/AzureAD/microsoft-authentication-library-for-go/apps/confidential" ratifyerrors "github.com/ratify-project/ratify/errors" "github.com/ratify-project/ratify/pkg/common/oras/authprovider" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + + azcontainerregistry "github.com/Azure/azure-sdk-for-go/sdk/containers/azcontainerregistry" + "github.com/AzureAD/microsoft-authentication-library-for-go/apps/confidential" ) +// MockAADAccessTokenGetter for retrieving AAD access token +type MockAADAccessTokenGetter struct { + mock.Mock +} + +func (m *MockAADAccessTokenGetter) GetAADAccessToken(ctx context.Context, tenantID, clientID, resource string) (confidential.AuthResult, error) { + args := m.Called(ctx, tenantID, clientID, resource) + return args.Get(0).(confidential.AuthResult), args.Error(1) +} + +// MockMetricsReporter for reporting metrics +type MockMetricsReporter struct { + mock.Mock +} + +func (m *MockMetricsReporter) ReportMetrics(ctx context.Context, duration int64, artifactHostName string) { + m.Called(ctx, duration, artifactHostName) +} + +// Test for successful Provide function +func TestWIAuthProvider_Provide_Success(t *testing.T) { + // Mock all dependencies + mockAuthClientFactory := new(MockAuthClientFactory) + mockRegistryHostGetter := new(MockRegistryHostGetter) + mockAADAccessTokenGetter := new(MockAADAccessTokenGetter) + mockMetricsReporter := new(MockMetricsReporter) + mockAuthClient := new(MockAuthClient) + + // Mock AAD token + initialToken := confidential.AuthResult{AccessToken: "initial_token", ExpiresOn: time.Now().Add(10 * time.Minute)} + refreshTokenString := "new_refresh_token" + refreshToken := azcontainerregistry.AuthenticationClientExchangeAADAccessTokenForACRRefreshTokenResponse{ + ACRRefreshToken: azcontainerregistry.ACRRefreshToken{RefreshToken: &refreshTokenString}, + } + + // Set expectations for mocked functions + mockRegistryHostGetter.On("GetRegistryHost", "artifact_name").Return("example.azurecr.io", nil) + mockAuthClientFactory.On("CreateAuthClient", "https://example.azurecr.io", mock.Anything).Return(mockAuthClient, nil) + mockAuthClient.On("ExchangeAADAccessTokenForACRRefreshToken", mock.Anything, azcontainerregistry.PostContentSchemaGrantType(GrantTypeAccessToken), "example.azurecr.io", mock.Anything).Return(refreshToken, nil) + mockAADAccessTokenGetter.On("GetAADAccessToken", mock.Anything, "tenantID", "clientID", mock.Anything).Return(initialToken, nil) + mockMetricsReporter.On("ReportMetrics", mock.Anything, mock.Anything, "example.azurecr.io").Return() + + // Create WIAuthProvider + provider := WIAuthProvider{ + aadToken: initialToken, + tenantID: "tenantID", + clientID: "clientID", + authClientFactory: mockAuthClientFactory, + registryHostGetter: mockRegistryHostGetter, + getAADAccessToken: mockAADAccessTokenGetter, + reportMetrics: mockMetricsReporter, + } + + // Call Provide method + ctx := context.Background() + authConfig, err := provider.Provide(ctx, "artifact_name") + + // Assertions + assert.NoError(t, err) + assert.Equal(t, "new_refresh_token", authConfig.Password) +} + +// Test for AAD token refresh logic +func TestWIAuthProvider_Provide_RefreshToken(t *testing.T) { + // Mock all dependencies + mockAuthClientFactory := new(MockAuthClientFactory) + mockRegistryHostGetter := new(MockRegistryHostGetter) + mockAADAccessTokenGetter := new(MockAADAccessTokenGetter) + mockMetricsReporter := new(MockMetricsReporter) + mockAuthClient := new(MockAuthClient) + + // Mock expired AAD token, and refreshed token + expiredToken := confidential.AuthResult{AccessToken: "expired_token", ExpiresOn: time.Now().Add(-10 * time.Minute)} + newToken := confidential.AuthResult{AccessToken: "new_token", ExpiresOn: time.Now().Add(10 * time.Minute)} + refreshTokenString := "refreshed_token" + refreshToken := azcontainerregistry.AuthenticationClientExchangeAADAccessTokenForACRRefreshTokenResponse{ + ACRRefreshToken: azcontainerregistry.ACRRefreshToken{RefreshToken: &refreshTokenString}, + } + + // Set expectations for mocked functions + mockRegistryHostGetter.On("GetRegistryHost", "artifact_name").Return("example.azurecr.io", nil) + mockAuthClientFactory.On("CreateAuthClient", "https://example.azurecr.io", mock.Anything).Return(mockAuthClient, nil) + mockAuthClient.On("ExchangeAADAccessTokenForACRRefreshToken", mock.Anything, azcontainerregistry.PostContentSchemaGrantType(GrantTypeAccessToken), "example.azurecr.io", mock.Anything).Return(refreshToken, nil) + mockAADAccessTokenGetter.On("GetAADAccessToken", mock.Anything, "tenantID", "clientID", mock.Anything).Return(newToken, nil) + mockMetricsReporter.On("ReportMetrics", mock.Anything, mock.Anything, "example.azurecr.io").Return() + + // Create WIAuthProvider with expired token + provider := WIAuthProvider{ + aadToken: expiredToken, + tenantID: "tenantID", + clientID: "clientID", + authClientFactory: mockAuthClientFactory, + registryHostGetter: mockRegistryHostGetter, + getAADAccessToken: mockAADAccessTokenGetter, + reportMetrics: mockMetricsReporter, + } + + // Call Provide method + ctx := context.Background() + authConfig, err := provider.Provide(ctx, "artifact_name") + + // Assertions + assert.NoError(t, err) + assert.Equal(t, "refreshed_token", authConfig.Password) +} + +// Test for failure when GetAADAccessToken fails +func TestWIAuthProvider_Provide_AADTokenFailure(t *testing.T) { + // Mock all dependencies + mockAuthClientFactory := new(MockAuthClientFactory) + mockRegistryHostGetter := new(MockRegistryHostGetter) + mockAADAccessTokenGetter := new(MockAADAccessTokenGetter) + mockMetricsReporter := new(MockMetricsReporter) + + // Mock expired AAD token, and failure to refresh + expiredToken := confidential.AuthResult{AccessToken: "expired_token", ExpiresOn: time.Now().Add(-10 * time.Minute)} + + // Set expectations for mocked functions + mockRegistryHostGetter.On("GetRegistryHost", "artifact_name").Return("example.azurecr.io", nil) + mockAADAccessTokenGetter.On("GetAADAccessToken", mock.Anything, "tenantID", "clientID", mock.Anything).Return(confidential.AuthResult{}, errors.New("token refresh failed")) + + // Create WIAuthProvider with expired token + provider := WIAuthProvider{ + aadToken: expiredToken, + tenantID: "tenantID", + clientID: "clientID", + authClientFactory: mockAuthClientFactory, + registryHostGetter: mockRegistryHostGetter, + getAADAccessToken: mockAADAccessTokenGetter, + reportMetrics: mockMetricsReporter, + } + + // Call Provide method + ctx := context.Background() + _, err := provider.Provide(ctx, "artifact_name") + + // Assertions + assert.Error(t, err) + assert.Contains(t, err.Error(), "could not refresh AAD token") +} + +// Test when tenant ID is missing from the environment +func TestAzureWIProviderFactory_Create_NoTenantID(t *testing.T) { + // Clear the tenant ID environment variable + t.Setenv("AZURE_TENANT_ID", "") + + // Initialize provider factory + factory := &AzureWIProviderFactory{} + + // Call Create with minimal configuration + _, err := factory.Create(map[string]interface{}{}) + + // Expect error related to missing tenant ID + assert.Error(t, err) + assert.Contains(t, err.Error(), "azure tenant id environment variable is empty") +} + +// Test when client ID is missing from the environment +func TestAzureWIProviderFactory_Create_NoClientID(t *testing.T) { + // Set tenant ID but leave client ID empty + t.Setenv("AZURE_TENANT_ID", "tenantID") + t.Setenv("AZURE_CLIENT_ID", "") + + // Initialize provider factory + factory := &AzureWIProviderFactory{} + + // Call Create with minimal configuration + _, err := factory.Create(map[string]interface{}{}) + + // Expect error related to missing client ID + assert.Error(t, err) + assert.Contains(t, err.Error(), "no client ID provided and AZURE_CLIENT_ID environment variable is empty") +} + +// Test for successful token refresh +func TestWIAuthProvider_Provide_TokenRefresh_Success(t *testing.T) { + // Mock dependencies + mockAuthClientFactory := new(MockAuthClientFactory) + mockRegistryHostGetter := new(MockRegistryHostGetter) + mockAADAccessTokenGetter := new(MockAADAccessTokenGetter) + mockMetricsReporter := new(MockMetricsReporter) + mockAuthClient := new(MockAuthClient) + + // Mock expired AAD token and refreshed token + expiredToken := confidential.AuthResult{AccessToken: "expired_token", ExpiresOn: time.Now().Add(-10 * time.Minute)} + refreshTokenString := "refreshed_token" + newToken := confidential.AuthResult{AccessToken: "new_token", ExpiresOn: time.Now().Add(10 * time.Minute)} + refreshToken := azcontainerregistry.AuthenticationClientExchangeAADAccessTokenForACRRefreshTokenResponse{ + ACRRefreshToken: azcontainerregistry.ACRRefreshToken{RefreshToken: &refreshTokenString}, + } + + // Set expectations + mockRegistryHostGetter.On("GetRegistryHost", "artifact_name").Return("example.azurecr.io", nil) + mockAuthClientFactory.On("CreateAuthClient", "https://example.azurecr.io", mock.Anything).Return(mockAuthClient, nil) + mockAuthClient.On("ExchangeAADAccessTokenForACRRefreshToken", mock.Anything, azcontainerregistry.PostContentSchemaGrantType(GrantTypeAccessToken), "example.azurecr.io", mock.Anything).Return(refreshToken, nil) + mockAADAccessTokenGetter.On("GetAADAccessToken", mock.Anything, "tenantID", "clientID", mock.Anything).Return(newToken, nil) + mockMetricsReporter.On("ReportMetrics", mock.Anything, mock.Anything, "example.azurecr.io").Return() + + // Create WIAuthProvider with expired token + provider := WIAuthProvider{ + aadToken: expiredToken, + tenantID: "tenantID", + clientID: "clientID", + authClientFactory: mockAuthClientFactory, + registryHostGetter: mockRegistryHostGetter, + getAADAccessToken: mockAADAccessTokenGetter, + reportMetrics: mockMetricsReporter, + } + + // Call Provide method + ctx := context.Background() + authConfig, err := provider.Provide(ctx, "artifact_name") + + // Assertions + assert.NoError(t, err) + assert.Equal(t, "refreshed_token", authConfig.Password) +} + +// Test when token refresh fails +func TestWIAuthProvider_Provide_TokenRefreshFailure(t *testing.T) { + // Mock dependencies + mockAuthClientFactory := new(MockAuthClientFactory) + mockRegistryHostGetter := new(MockRegistryHostGetter) + mockAADAccessTokenGetter := new(MockAADAccessTokenGetter) + mockMetricsReporter := new(MockMetricsReporter) + + // Mock expired AAD token and failure to refresh + expiredToken := confidential.AuthResult{AccessToken: "expired_token", ExpiresOn: time.Now().Add(-10 * time.Minute)} + + // Set expectations + mockRegistryHostGetter.On("GetRegistryHost", "artifact_name").Return("example.azurecr.io", nil) + mockAADAccessTokenGetter.On("GetAADAccessToken", mock.Anything, "tenantID", "clientID", mock.Anything).Return(confidential.AuthResult{}, errors.New("token refresh failed")) + + // Create WIAuthProvider with expired token + provider := WIAuthProvider{ + aadToken: expiredToken, + tenantID: "tenantID", + clientID: "clientID", + authClientFactory: mockAuthClientFactory, + registryHostGetter: mockRegistryHostGetter, + getAADAccessToken: mockAADAccessTokenGetter, + reportMetrics: mockMetricsReporter, + } + + // Call Provide method + ctx := context.Background() + _, err := provider.Provide(ctx, "artifact_name") + + // Assertions + assert.Error(t, err) + assert.Contains(t, err.Error(), "could not refresh AAD token") +} + +// Test for handling empty AccessToken +func TestWIAuthProvider_Enabled_NoAccessToken(t *testing.T) { + // Create a provider with no AccessToken + provider := WIAuthProvider{ + tenantID: "tenantID", + clientID: "clientID", + aadToken: confidential.AuthResult{AccessToken: ""}, + } + + // Assert that provider is not enabled + enabled := provider.Enabled(context.Background()) + assert.False(t, enabled) +} + +// Test for invalid hostname retrieval +func TestWIAuthProvider_Provide_InvalidHostName(t *testing.T) { + // Mock dependencies + mockAuthClientFactory := new(MockAuthClientFactory) + mockRegistryHostGetter := new(MockRegistryHostGetter) + mockAADAccessTokenGetter := new(MockAADAccessTokenGetter) + mockMetricsReporter := new(MockMetricsReporter) + + // Mock valid AAD token + validToken := confidential.AuthResult{AccessToken: "valid_token", ExpiresOn: time.Now().Add(10 * time.Minute)} + + // Set expectations for an invalid hostname + mockRegistryHostGetter.On("GetRegistryHost", "artifact_name").Return("", errors.New("invalid hostname")) + + // Create WIAuthProvider with valid token + provider := WIAuthProvider{ + aadToken: validToken, + tenantID: "tenantID", + clientID: "clientID", + authClientFactory: mockAuthClientFactory, + registryHostGetter: mockRegistryHostGetter, + getAADAccessToken: mockAADAccessTokenGetter, + reportMetrics: mockMetricsReporter, + } + + // Call Provide method + ctx := context.Background() + _, err := provider.Provide(ctx, "artifact_name") + + // Assertions + assert.Error(t, err) + assert.Contains(t, err.Error(), "HOST_NAME_INVALID") +} + // Verifies that Enabled checks if tenantID is empty or AAD token is empty func TestAzureWIEnabled_ExpectedResults(t *testing.T) { - azAuthProvider := azureWIAuthProvider{ + azAuthProvider := WIAuthProvider{ tenantID: "test_tenant", clientID: "test_client", aadToken: confidential.AuthResult{ diff --git a/pkg/common/oras/authprovider/azure/helper.go b/pkg/common/oras/authprovider/azure/helper.go new file mode 100644 index 000000000..beafa4db0 --- /dev/null +++ b/pkg/common/oras/authprovider/azure/helper.go @@ -0,0 +1,84 @@ +/* +Copyright The Ratify Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package azure + +import ( + "context" + + "github.com/Azure/azure-sdk-for-go/sdk/containers/azcontainerregistry" + provider "github.com/ratify-project/ratify/pkg/common/oras/authprovider" +) + +const GrantTypeAccessToken = "access_token" + +// AuthClientFactory defines an interface for creating an authentication client. +type AuthClientFactory interface { + CreateAuthClient(serverURL string, options *azcontainerregistry.AuthenticationClientOptions) (AuthClient, error) +} + +// defaultAuthClientFactoryImpl is the default implementation of AuthClientFactory. +type defaultAuthClientFactoryImpl struct{} + +// creates an AuthClient using the default factory implementation. +// Return an AuthClient and an error if the client creation fails. +func (f *defaultAuthClientFactoryImpl) CreateAuthClient(serverURL string, options *azcontainerregistry.AuthenticationClientOptions) (AuthClient, error) { + return defaultAuthClientFactory(serverURL, options) +} + +// Define a helper function that creates an instance of AuthenticationClientWrapper. +func defaultAuthClientFactory(serverURL string, options *azcontainerregistry.AuthenticationClientOptions) (AuthClient, error) { + client, err := azcontainerregistry.NewAuthenticationClient(serverURL, options) + if err != nil { + return nil, err + } + return &AuthenticationClientWrapper{client: client}, nil +} + +// Define the interface for azcontainerregistry.AuthenticationClient methods used +type AuthenticationClientInterface interface { + ExchangeAADAccessTokenForACRRefreshToken(ctx context.Context, grantType azcontainerregistry.PostContentSchemaGrantType, service string, options *azcontainerregistry.AuthenticationClientExchangeAADAccessTokenForACRRefreshTokenOptions) (azcontainerregistry.AuthenticationClientExchangeAADAccessTokenForACRRefreshTokenResponse, error) +} + +// Define the wrapper for AuthenticationClientInterface +type AuthenticationClientWrapper struct { + client AuthenticationClientInterface +} + +// A wrapper method that calls the underlying AuthenticationClientInterface's method. +// Exchanges an AAD access token for an ACR refresh token. +func (w *AuthenticationClientWrapper) ExchangeAADAccessTokenForACRRefreshToken(ctx context.Context, grantType azcontainerregistry.PostContentSchemaGrantType, service string, options *azcontainerregistry.AuthenticationClientExchangeAADAccessTokenForACRRefreshTokenOptions) (azcontainerregistry.AuthenticationClientExchangeAADAccessTokenForACRRefreshTokenResponse, error) { + return w.client.ExchangeAADAccessTokenForACRRefreshToken(ctx, grantType, service, options) +} + +// define the interface for authentication operations. +// It includes the method for exchanging an AAD access token for an ACR refresh token. +type AuthClient interface { + ExchangeAADAccessTokenForACRRefreshToken(ctx context.Context, grantType azcontainerregistry.PostContentSchemaGrantType, service string, options *azcontainerregistry.AuthenticationClientExchangeAADAccessTokenForACRRefreshTokenOptions) (azcontainerregistry.AuthenticationClientExchangeAADAccessTokenForACRRefreshTokenResponse, error) +} + +// RegistryHostGetter defines an interface for getting the registry host. +type RegistryHostGetter interface { + GetRegistryHost(artifact string) (string, error) +} + +// defaultRegistryHostGetterImpl is the default implementation of RegistryHostGetter. +type defaultRegistryHostGetterImpl struct{} + +// Retrieves the registry host name for a given artifact. +// It utilizes the provider's GetRegistryHostName function to perform the lookup. +func (g *defaultRegistryHostGetterImpl) GetRegistryHost(artifact string) (string, error) { + return provider.GetRegistryHostName(artifact) +} diff --git a/pkg/common/oras/authprovider/azure/helper_test.go b/pkg/common/oras/authprovider/azure/helper_test.go new file mode 100644 index 000000000..49c811f0f --- /dev/null +++ b/pkg/common/oras/authprovider/azure/helper_test.go @@ -0,0 +1,100 @@ +/* +Copyright The Ratify Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package azure + +import ( + "context" + "testing" + + "github.com/Azure/azure-sdk-for-go/sdk/containers/azcontainerregistry" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +// MockAuthClient is a mock implementation of AuthClient. +type MockAuthClient struct { + mock.Mock +} + +// Mock method for ExchangeAADAccessTokenForACRRefreshToken +func (m *MockAuthClient) ExchangeAADAccessTokenForACRRefreshToken(ctx context.Context, grantType azcontainerregistry.PostContentSchemaGrantType, service string, options *azcontainerregistry.AuthenticationClientExchangeAADAccessTokenForACRRefreshTokenOptions) (azcontainerregistry.AuthenticationClientExchangeAADAccessTokenForACRRefreshTokenResponse, error) { + args := m.Called(ctx, grantType, service, options) + return args.Get(0).(azcontainerregistry.AuthenticationClientExchangeAADAccessTokenForACRRefreshTokenResponse), args.Error(1) +} + +// MockAuthClientFactory is a mock implementation of AuthClientFactory. +type MockAuthClientFactory struct { + mock.Mock +} + +// Mock method for CreateAuthClient +func (m *MockAuthClientFactory) CreateAuthClient(serverURL string, options *azcontainerregistry.AuthenticationClientOptions) (AuthClient, error) { + args := m.Called(serverURL, options) + return args.Get(0).(AuthClient), args.Error(1) +} + +// MockRegistryHostGetter is a mock implementation of RegistryHostGetter. +type MockRegistryHostGetter struct { + mock.Mock +} + +// Mock method for GetRegistryHost +func (m *MockRegistryHostGetter) GetRegistryHost(artifact string) (string, error) { + args := m.Called(artifact) + return args.String(0), args.Error(1) +} + +func TestDefaultAuthClientFactoryImpl_CreateAuthClient(t *testing.T) { + factory := &defaultAuthClientFactoryImpl{} + serverURL := "https://example.com" + options := &azcontainerregistry.AuthenticationClientOptions{} + + client, err := factory.CreateAuthClient(serverURL, options) + assert.Nil(t, err) + assert.NotNil(t, client) +} + +func TestDefaultAuthClientFactory(t *testing.T) { + serverURL := "https://example.com" + options := &azcontainerregistry.AuthenticationClientOptions{} + + client, err := defaultAuthClientFactory(serverURL, options) + assert.Nil(t, err) + assert.NotNil(t, client) +} + +func TestDefaultRegistryHostGetterImpl_GetRegistryHost(t *testing.T) { + getter := &defaultRegistryHostGetterImpl{} + artifact := "example.azurecr.io/myArtifact" + + host, err := getter.GetRegistryHost(artifact) + assert.Nil(t, err) + assert.Equal(t, "example.azurecr.io", host) +} + +func TestAuthenticationClientWrapper_ExchangeAADAccessTokenForACRRefreshToken(t *testing.T) { + mockClient := new(MockAuthClient) + wrapper := &AuthenticationClientWrapper{client: mockClient} + ctx := context.Background() + grantType := azcontainerregistry.PostContentSchemaGrantType("grantType") + service := "service" + options := &azcontainerregistry.AuthenticationClientExchangeAADAccessTokenForACRRefreshTokenOptions{} + + mockClient.On("ExchangeAADAccessTokenForACRRefreshToken", ctx, grantType, service, options).Return(azcontainerregistry.AuthenticationClientExchangeAADAccessTokenForACRRefreshTokenResponse{}, nil) + + _, err := wrapper.ExchangeAADAccessTokenForACRRefreshToken(ctx, grantType, service, options) + assert.Nil(t, err) +} From 8ea916e783f44713d7fea9952c90d182621e192c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 23 Oct 2024 06:22:32 +0000 Subject: [PATCH 15/62] chore: Bump github/codeql-action from 3.26.13 to 3.27.0 (#1887) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/codeql.yml | 4 ++-- .github/workflows/scorecards.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 5a92c3ad1..0d45b7b64 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -37,7 +37,7 @@ jobs: with: go-version: "1.22" - name: Initialize CodeQL - uses: github/codeql-action/init@f779452ac5af1c261dce0346a8f964149f49322b # tag=v3.26.13 + uses: github/codeql-action/init@662472033e021d55d94146f66f6058822b0b39fd # tag=v3.27.0 with: languages: go - name: Run tidy @@ -45,4 +45,4 @@ jobs: - name: Build CLI run: make build - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@f779452ac5af1c261dce0346a8f964149f49322b # tag=v3.26.13 + uses: github/codeql-action/analyze@662472033e021d55d94146f66f6058822b0b39fd # tag=v3.27.0 diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index a45432923..022662659 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -55,6 +55,6 @@ jobs: retention-days: 5 - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@f779452ac5af1c261dce0346a8f964149f49322b # tag=v3.26.13 + uses: github/codeql-action/upload-sarif@662472033e021d55d94146f66f6058822b0b39fd # tag=v3.27.0 with: sarif_file: results.sarif From 6d7ce9e23569c3244add21b2422a6e0f95a41098 Mon Sep 17 00:00:00 2001 From: Juncheng Zhu Date: Wed, 23 Oct 2024 17:14:06 +0800 Subject: [PATCH 16/62] chore: update charts (#1892) Signed-off-by: Juncheng Zhu --- charts/ratify/Chart.yaml | 4 ++-- charts/ratify/values.yaml | 2 +- helmfile.yaml | 2 +- high-availability.helmfile.yaml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/charts/ratify/Chart.yaml b/charts/ratify/Chart.yaml index 945bb14a6..b51659435 100644 --- a/charts/ratify/Chart.yaml +++ b/charts/ratify/Chart.yaml @@ -1,7 +1,7 @@ apiVersion: v2 name: ratify description: A Helm chart for Ratify -version: 1.14.0 -appVersion: v1.3.0 +version: 1.14.1 +appVersion: v1.3.1 home: https://github.com/ratify-project/ratify icon: https://raw.githubusercontent.com/ratify-project/ratify/main/logo.svg diff --git a/charts/ratify/values.yaml b/charts/ratify/values.yaml index 348736e9b..2faf76a13 100644 --- a/charts/ratify/values.yaml +++ b/charts/ratify/values.yaml @@ -1,7 +1,7 @@ image: repository: ghcr.io/ratify-project/ratify crdRepository: ghcr.io/ratify-project/ratify-crds - tag: v1.3.0 + tag: v1.3.1 pullPolicy: IfNotPresent nameOverride: "" diff --git a/helmfile.yaml b/helmfile.yaml index e216de2ef..6e142d469 100644 --- a/helmfile.yaml +++ b/helmfile.yaml @@ -23,7 +23,7 @@ releases: - name: ratify namespace: gatekeeper-system chart: ratify/ratify - version: 1.14.0 # Make sure this matches Chart.yaml + version: 1.14.1 # Make sure this matches Chart.yaml wait: true needs: - gatekeeper diff --git a/high-availability.helmfile.yaml b/high-availability.helmfile.yaml index 5698e2281..e43ff3d0c 100644 --- a/high-availability.helmfile.yaml +++ b/high-availability.helmfile.yaml @@ -50,7 +50,7 @@ releases: - name: ratify namespace: gatekeeper-system chart: ratify/ratify - version: 1.14.0 # Make sure this matches Chart.yaml + version: 1.14.1 # Make sure this matches Chart.yaml wait: true needs: - dapr-system/dapr From 279632171642d05524d5b15901af34ae8d126ed5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 24 Oct 2024 16:23:09 +0800 Subject: [PATCH 17/62] chore: Bump actions/checkout from 4.2.1 to 4.2.2 (#1893) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build-pr.yml | 2 +- .github/workflows/codeql.yml | 2 +- .github/workflows/e2e-aks.yml | 2 +- .github/workflows/e2e-cli.yml | 8 ++++---- .github/workflows/e2e-k8s.yml | 2 +- .github/workflows/golangci-lint.yml | 2 +- .github/workflows/high-availability.yml | 2 +- .github/workflows/pr-to-main.yml | 2 +- .github/workflows/publish-charts.yml | 2 +- .github/workflows/publish-dev-assets.yml | 2 +- .github/workflows/publish-package.yml | 2 +- .github/workflows/quick-start.yml | 2 +- .github/workflows/release.yml | 2 +- .github/workflows/run-full-validation.yml | 2 +- .github/workflows/scan-vulns.yaml | 2 +- .github/workflows/scorecards.yml | 2 +- .github/workflows/sync-gh-pages.yml | 2 +- 17 files changed, 20 insertions(+), 20 deletions(-) diff --git a/.github/workflows/build-pr.yml b/.github/workflows/build-pr.yml index 3f5195ca9..8370d2648 100644 --- a/.github/workflows/build-pr.yml +++ b/.github/workflows/build-pr.yml @@ -75,7 +75,7 @@ jobs: egress-policy: audit - name: Check out code into the Go module directory - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Set up Go 1.22 uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 0d45b7b64..8b5f05e50 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -31,7 +31,7 @@ jobs: egress-policy: audit - name: Checkout repository - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # tag=3.0.2 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=3.0.2 - name: setup go environment uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: diff --git a/.github/workflows/e2e-aks.yml b/.github/workflows/e2e-aks.yml index 0ce8950a1..cba279530 100644 --- a/.github/workflows/e2e-aks.yml +++ b/.github/workflows/e2e-aks.yml @@ -33,7 +33,7 @@ jobs: egress-policy: audit - name: Check out code into the Go module directory - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Set up Go 1.22 uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: diff --git a/.github/workflows/e2e-cli.yml b/.github/workflows/e2e-cli.yml index 08a265249..798001995 100644 --- a/.github/workflows/e2e-cli.yml +++ b/.github/workflows/e2e-cli.yml @@ -19,7 +19,7 @@ jobs: egress-policy: audit - name: Checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - name: Check license header uses: apache/skywalking-eyes/header@cd7b195c51fd3d6ad52afceb760719ddc6b3ee91 with: @@ -39,7 +39,7 @@ jobs: egress-policy: audit - name: Checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - name: setup go environment uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: @@ -68,7 +68,7 @@ jobs: egress-policy: audit - name: Checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: setup go environment uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: @@ -96,7 +96,7 @@ jobs: egress-policy: audit - name: Checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: submodules: recursive - name: Run link check diff --git a/.github/workflows/e2e-k8s.yml b/.github/workflows/e2e-k8s.yml index be26f5362..93f03a7a9 100644 --- a/.github/workflows/e2e-k8s.yml +++ b/.github/workflows/e2e-k8s.yml @@ -31,7 +31,7 @@ jobs: egress-policy: audit - name: Check out code into the Go module directory - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Set up Go 1.22 uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index f6c1aba55..32f94c6f7 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -22,7 +22,7 @@ jobs: - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: go-version: "1.22" - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: golangci-lint uses: golangci/golangci-lint-action@971e284b6050e8a5849b72094c50ab08da042db8 # v6.1.1 with: diff --git a/.github/workflows/high-availability.yml b/.github/workflows/high-availability.yml index e9e576851..6720c99d2 100644 --- a/.github/workflows/high-availability.yml +++ b/.github/workflows/high-availability.yml @@ -35,7 +35,7 @@ jobs: egress-policy: audit - name: Check out code into the Go module directory - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Set up Go 1.22 uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: diff --git a/.github/workflows/pr-to-main.yml b/.github/workflows/pr-to-main.yml index fb7938dba..325158903 100644 --- a/.github/workflows/pr-to-main.yml +++ b/.github/workflows/pr-to-main.yml @@ -18,7 +18,7 @@ jobs: egress-policy: audit - name: git checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - name: Get current date id: date run: echo "::set-output name=date::$(date +'%Y-%m-%d')" diff --git a/.github/workflows/publish-charts.yml b/.github/workflows/publish-charts.yml index 45338d088..fd1d16a25 100644 --- a/.github/workflows/publish-charts.yml +++ b/.github/workflows/publish-charts.yml @@ -17,7 +17,7 @@ jobs: with: egress-policy: audit - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - name: Publish Helm charts uses: stefanprodan/helm-gh-pages@0ad2bb377311d61ac04ad9eb6f252fb68e207260 # v1.7.0 with: diff --git a/.github/workflows/publish-dev-assets.yml b/.github/workflows/publish-dev-assets.yml index 30b9b6c9e..0426b2bf7 100644 --- a/.github/workflows/publish-dev-assets.yml +++ b/.github/workflows/publish-dev-assets.yml @@ -21,7 +21,7 @@ jobs: with: egress-policy: audit - name: Checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - name: Install Notation uses: notaryproject/notation-action/setup@03242349f62aeddc995e12c6fbcea3b87697873f # v1.2.0 - name: Install cosign diff --git a/.github/workflows/publish-package.yml b/.github/workflows/publish-package.yml index 21bcf2815..11bee4cee 100644 --- a/.github/workflows/publish-package.yml +++ b/.github/workflows/publish-package.yml @@ -20,7 +20,7 @@ jobs: with: egress-policy: audit - name: Checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - name: prepare id: prepare run: | diff --git a/.github/workflows/quick-start.yml b/.github/workflows/quick-start.yml index 3d9b3aa6e..82eb211e0 100644 --- a/.github/workflows/quick-start.yml +++ b/.github/workflows/quick-start.yml @@ -35,7 +35,7 @@ jobs: egress-policy: audit - name: Checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: setup go environment uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b550b2372..81b2489b0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,7 +21,7 @@ jobs: egress-policy: audit - name: Checkout - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # tag=3.0.2 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=3.0.2 with: fetch-depth: 0 diff --git a/.github/workflows/run-full-validation.yml b/.github/workflows/run-full-validation.yml index 1584a2d3f..36ac8e649 100644 --- a/.github/workflows/run-full-validation.yml +++ b/.github/workflows/run-full-validation.yml @@ -63,7 +63,7 @@ jobs: egress-policy: audit - name: Check out code into the Go module directory - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Set up Go 1.22 uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: diff --git a/.github/workflows/scan-vulns.yaml b/.github/workflows/scan-vulns.yaml index 23208d9b1..b96841c85 100644 --- a/.github/workflows/scan-vulns.yaml +++ b/.github/workflows/scan-vulns.yaml @@ -46,7 +46,7 @@ jobs: egress-policy: audit - name: Check out code into the Go module directory - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - name: Download trivy run: | diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 022662659..ca1a7db65 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -35,7 +35,7 @@ jobs: egress-policy: audit - name: "Checkout code" - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # tag=3.0.2 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=3.0.2 with: persist-credentials: false diff --git a/.github/workflows/sync-gh-pages.yml b/.github/workflows/sync-gh-pages.yml index 0990fc29b..54a05e0cb 100644 --- a/.github/workflows/sync-gh-pages.yml +++ b/.github/workflows/sync-gh-pages.yml @@ -21,7 +21,7 @@ jobs: with: egress-policy: audit - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - uses: everlytic/branch-merge@c4a244dc23143f824ae6c022a10732566cb8e973 with: github_token: ${{ github.token }} From e9152c9a544a8ab7b63631188ff11eb99afae600 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 25 Oct 2024 05:49:09 +0000 Subject: [PATCH 18/62] chore: Bump actions/setup-go from 5.0.2 to 5.1.0 (#1894) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build-pr.yml | 2 +- .github/workflows/codeql.yml | 2 +- .github/workflows/e2e-aks.yml | 2 +- .github/workflows/e2e-cli.yml | 4 ++-- .github/workflows/e2e-k8s.yml | 2 +- .github/workflows/golangci-lint.yml | 2 +- .github/workflows/high-availability.yml | 2 +- .github/workflows/quick-start.yml | 2 +- .github/workflows/release.yml | 2 +- .github/workflows/run-full-validation.yml | 2 +- .github/workflows/scan-vulns.yaml | 2 +- 11 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/build-pr.yml b/.github/workflows/build-pr.yml index 8370d2648..272f4333e 100644 --- a/.github/workflows/build-pr.yml +++ b/.github/workflows/build-pr.yml @@ -77,7 +77,7 @@ jobs: - name: Check out code into the Go module directory uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Set up Go 1.22 - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 + uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 with: go-version: "1.22" diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 8b5f05e50..6e86bb638 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -33,7 +33,7 @@ jobs: - name: Checkout repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=3.0.2 - name: setup go environment - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 + uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 with: go-version: "1.22" - name: Initialize CodeQL diff --git a/.github/workflows/e2e-aks.yml b/.github/workflows/e2e-aks.yml index cba279530..8e28b48fa 100644 --- a/.github/workflows/e2e-aks.yml +++ b/.github/workflows/e2e-aks.yml @@ -35,7 +35,7 @@ jobs: - name: Check out code into the Go module directory uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Set up Go 1.22 - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 + uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 with: go-version: "1.22" - name: Az CLI login diff --git a/.github/workflows/e2e-cli.yml b/.github/workflows/e2e-cli.yml index 798001995..8d1027b6c 100644 --- a/.github/workflows/e2e-cli.yml +++ b/.github/workflows/e2e-cli.yml @@ -41,7 +41,7 @@ jobs: - name: Checkout uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - name: setup go environment - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 + uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 with: go-version: "1.22" - name: Run tidy @@ -70,7 +70,7 @@ jobs: - name: Checkout uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: setup go environment - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 + uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 with: go-version: "1.22" - name: Run tidy diff --git a/.github/workflows/e2e-k8s.yml b/.github/workflows/e2e-k8s.yml index 93f03a7a9..e80b65f5b 100644 --- a/.github/workflows/e2e-k8s.yml +++ b/.github/workflows/e2e-k8s.yml @@ -33,7 +33,7 @@ jobs: - name: Check out code into the Go module directory uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Set up Go 1.22 - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 + uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 with: go-version: "1.22" diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 32f94c6f7..f6eaa9331 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -19,7 +19,7 @@ jobs: with: egress-policy: audit - - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 + - uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 with: go-version: "1.22" - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 diff --git a/.github/workflows/high-availability.yml b/.github/workflows/high-availability.yml index 6720c99d2..be5281354 100644 --- a/.github/workflows/high-availability.yml +++ b/.github/workflows/high-availability.yml @@ -37,7 +37,7 @@ jobs: - name: Check out code into the Go module directory uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Set up Go 1.22 - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 + uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 with: go-version: "1.22" diff --git a/.github/workflows/quick-start.yml b/.github/workflows/quick-start.yml index 82eb211e0..1655d725f 100644 --- a/.github/workflows/quick-start.yml +++ b/.github/workflows/quick-start.yml @@ -37,7 +37,7 @@ jobs: - name: Checkout uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: setup go environment - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 + uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 with: go-version: "1.22" - name: Run tidy diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 81b2489b0..e7d12b22a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -29,7 +29,7 @@ jobs: uses: anchore/sbom-action/download-syft@1ca97d9028b51809cf6d3c934c3e160716e1b605 # v0.17.5 - name: Set up Go - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 + uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 with: go-version: "1.22" diff --git a/.github/workflows/run-full-validation.yml b/.github/workflows/run-full-validation.yml index 36ac8e649..4b2c13f19 100644 --- a/.github/workflows/run-full-validation.yml +++ b/.github/workflows/run-full-validation.yml @@ -65,7 +65,7 @@ jobs: - name: Check out code into the Go module directory uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Set up Go 1.22 - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 + uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 with: go-version: "1.22" diff --git a/.github/workflows/scan-vulns.yaml b/.github/workflows/scan-vulns.yaml index b96841c85..1a554a6e8 100644 --- a/.github/workflows/scan-vulns.yaml +++ b/.github/workflows/scan-vulns.yaml @@ -27,7 +27,7 @@ jobs: with: egress-policy: audit - - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 + - uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 with: go-version: "1.22" check-latest: true From 33064b0aa569cbb045f223b81dfcec31c4ae7521 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 29 Oct 2024 12:00:07 +1100 Subject: [PATCH 19/62] chore: Bump k8s.io/apimachinery from 0.28.14 to 0.28.15 (#1896) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index be3607472..70973697b 100644 --- a/go.mod +++ b/go.mod @@ -52,7 +52,7 @@ require ( google.golang.org/grpc v1.66.3 google.golang.org/protobuf v1.34.2 k8s.io/api v0.28.14 - k8s.io/apimachinery v0.28.14 + k8s.io/apimachinery v0.28.15 k8s.io/client-go v0.28.14 oras.land/oras-go/v2 v2.5.0 ) diff --git a/go.sum b/go.sum index ecb26633c..664e78b5f 100644 --- a/go.sum +++ b/go.sum @@ -986,8 +986,8 @@ k8s.io/api v0.28.14 h1:7DXeMrQq+BJI6H7WtSMC8l1gM4QZWtWN65UbN+qZ9Uc= k8s.io/api v0.28.14/go.mod h1:ROk/G6/7IZf14AL1WkpZdq//5khE1EtLNxkcEpSXNFM= k8s.io/apiextensions-apiserver v0.27.7 h1:YqIOwZAUokzxJIjunmUd4zS1v3JhK34EPXn+pP0/bsU= k8s.io/apiextensions-apiserver v0.27.7/go.mod h1:x0p+b5a955lfPz9gaDeBy43obM12s+N9dNHK6+dUL+g= -k8s.io/apimachinery v0.28.14 h1:n2l8jNNOmUUDXpa8ljHCEUSeIChby1BKyqoL0AtpmGw= -k8s.io/apimachinery v0.28.14/go.mod h1:zUG757HaKs6Dc3iGtKjzIpBfqTM4yiRsEe3/E7NX15o= +k8s.io/apimachinery v0.28.15 h1:Jg15ZoCcAgnhSRKVS6tQyUZaX9c3i08bl2qAz8XE3bI= +k8s.io/apimachinery v0.28.15/go.mod h1:zUG757HaKs6Dc3iGtKjzIpBfqTM4yiRsEe3/E7NX15o= k8s.io/client-go v0.28.14 h1:wfPRgz07MvLMxcHfN8kAc4Qcwduc4My25A3CBU7OqBQ= k8s.io/client-go v0.28.14/go.mod h1:HGfdb7BqkX4hRpNyVLHNQKWDU03W6a38LfIHD7QGJpI= k8s.io/component-base v0.27.7 h1:kngM58HR9W9Nqpv7e4rpdRyWnKl/ABpUhLAZ+HoliMs= From 4ffcf5ea7eadf99c1826db29d32818a5b6850762 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 29 Oct 2024 07:58:59 +0000 Subject: [PATCH 20/62] chore: Bump distroless/static from `26f9b99` to `3a03fc0` in /httpserver (#1899) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- httpserver/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httpserver/Dockerfile b/httpserver/Dockerfile index 33e3ccc0b..dcdee6b18 100644 --- a/httpserver/Dockerfile +++ b/httpserver/Dockerfile @@ -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:26f9b99f2463f55f20db19feb4d96eb88b056e0f1be7016bb9296a464a89d772 +FROM gcr.io/distroless/static:nonroot@sha256:3a03fc0826340c7deb82d4755ca391bef5adcedb8892e58412e1a6008199fa91 LABEL org.opencontainers.image.source https://github.com/ratify-project/ratify ARG RATIFY_FOLDER=$HOME/.ratify/ From 3e80c132625222b00783a6d408a5acd7c239cf50 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 29 Oct 2024 08:54:27 +0000 Subject: [PATCH 21/62] chore: Bump k8s.io/client-go from 0.28.14 to 0.28.15 (#1897) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 70973697b..0a25e89be 100644 --- a/go.mod +++ b/go.mod @@ -51,9 +51,9 @@ require ( golang.org/x/sync v0.8.0 google.golang.org/grpc v1.66.3 google.golang.org/protobuf v1.34.2 - k8s.io/api v0.28.14 + k8s.io/api v0.28.15 k8s.io/apimachinery v0.28.15 - k8s.io/client-go v0.28.14 + k8s.io/client-go v0.28.15 oras.land/oras-go/v2 v2.5.0 ) diff --git a/go.sum b/go.sum index 664e78b5f..e5e20addc 100644 --- a/go.sum +++ b/go.sum @@ -982,14 +982,14 @@ gotest.tools/v3 v3.1.0 h1:rVV8Tcg/8jHUkPUorwjaMTtemIMVXfIPKiOqnhEhakk= gotest.tools/v3 v3.1.0/go.mod h1:fHy7eyTmJFO5bQbUsEGQ1v4m2J3Jz9eWL54TP2/ZuYQ= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -k8s.io/api v0.28.14 h1:7DXeMrQq+BJI6H7WtSMC8l1gM4QZWtWN65UbN+qZ9Uc= -k8s.io/api v0.28.14/go.mod h1:ROk/G6/7IZf14AL1WkpZdq//5khE1EtLNxkcEpSXNFM= +k8s.io/api v0.28.15 h1:u+Sze8gI+DayQxndS0htiJf8yVooHyUx/H4jEehtmNs= +k8s.io/api v0.28.15/go.mod h1:SJuOJTphYG05iJC9UKnUTNkY84Mvveu1P7adCgWqjCg= k8s.io/apiextensions-apiserver v0.27.7 h1:YqIOwZAUokzxJIjunmUd4zS1v3JhK34EPXn+pP0/bsU= k8s.io/apiextensions-apiserver v0.27.7/go.mod h1:x0p+b5a955lfPz9gaDeBy43obM12s+N9dNHK6+dUL+g= k8s.io/apimachinery v0.28.15 h1:Jg15ZoCcAgnhSRKVS6tQyUZaX9c3i08bl2qAz8XE3bI= k8s.io/apimachinery v0.28.15/go.mod h1:zUG757HaKs6Dc3iGtKjzIpBfqTM4yiRsEe3/E7NX15o= -k8s.io/client-go v0.28.14 h1:wfPRgz07MvLMxcHfN8kAc4Qcwduc4My25A3CBU7OqBQ= -k8s.io/client-go v0.28.14/go.mod h1:HGfdb7BqkX4hRpNyVLHNQKWDU03W6a38LfIHD7QGJpI= +k8s.io/client-go v0.28.15 h1:+g6Ub+i6tacV3tYJaoyK6bizpinPkamcEwsiKyHcIxc= +k8s.io/client-go v0.28.15/go.mod h1:/4upIpTbhWQVSXKDqTznjcAegj2Bx73mW/i0aennJrY= k8s.io/component-base v0.27.7 h1:kngM58HR9W9Nqpv7e4rpdRyWnKl/ABpUhLAZ+HoliMs= k8s.io/component-base v0.27.7/go.mod h1:YGjlCVL1oeKvG3HSciyPHFh+LCjIEqsxz4BDR3cfHRs= k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= From 36a9b6e4d96b75cc41af046ad536f2a4687105c7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 30 Oct 2024 16:38:13 +0800 Subject: [PATCH 22/62] chore: Bump anchore/sbom-action from 0.17.5 to 0.17.6 (#1903) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e7d12b22a..ec43b4a9f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -26,7 +26,7 @@ jobs: fetch-depth: 0 - name: Install Syft - uses: anchore/sbom-action/download-syft@1ca97d9028b51809cf6d3c934c3e160716e1b605 # v0.17.5 + uses: anchore/sbom-action/download-syft@251a468eed47e5082b105c3ba6ee500c0e65a764 # v0.17.6 - name: Set up Go uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 From 10c431077a73760a8462e2a1918e56f6c678b2c3 Mon Sep 17 00:00:00 2001 From: Maneesh Singh Date: Sun, 3 Nov 2024 18:32:05 -0800 Subject: [PATCH 23/62] feat: allow service account annotations (#1907) Signed-off-by: Maneesh Singh --- charts/ratify/README.md | 1 + charts/ratify/templates/serviceaccount.yaml | 6 +++++- charts/ratify/values.yaml | 4 ++++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/charts/ratify/README.md b/charts/ratify/README.md index 571bfa141..7b79647bf 100644 --- a/charts/ratify/README.md +++ b/charts/ratify/README.md @@ -78,6 +78,7 @@ Values marked `# DEPRECATED` in the `values.yaml` as well as **DEPRECATED** in t | resources.requests.memory | Memory request of Ratify Deployment | `512Mi` | | serviceAccount.create | Create new dedicated Ratify service account | `true` | | serviceAccount.name | Name of Ratify service account to create | `ratify-admin` | +| serviceAccount.annotations | Annotations to add to the service account | `{}` | | gatekeeper.version | Determines the Gatekeeper CRD versioning | `3.17.0` | | gatekeeper.namespace | Namespace Gatekeeper is installed | `gatekeeper-system` | | instrumentation.metricsEnabled | Initializes the configured metrics provider | `true` | diff --git a/charts/ratify/templates/serviceaccount.yaml b/charts/ratify/templates/serviceaccount.yaml index 16713acff..68db5e8c5 100644 --- a/charts/ratify/templates/serviceaccount.yaml +++ b/charts/ratify/templates/serviceaccount.yaml @@ -7,5 +7,9 @@ metadata: {{- if .Values.azureWorkloadIdentity.clientId }} azure.workload.identity/use: "true" {{- end }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} name: {{ include "ratify.serviceAccountName" . }} -{{- end }} \ No newline at end of file +{{- end }} diff --git a/charts/ratify/values.yaml b/charts/ratify/values.yaml index 2faf76a13..c026ed4df 100644 --- a/charts/ratify/values.yaml +++ b/charts/ratify/values.yaml @@ -49,9 +49,13 @@ resources: requests: cpu: 600m memory: 512Mi + serviceAccount: create: true name: ratify-admin + # Annotations to add to the service account + annotations: {} + gatekeeper: version: "3.17.0" namespace: # default is gatekeeper-system From 31f63a575538f51de902f7741a970db9f8e33d18 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 09:31:49 -0800 Subject: [PATCH 24/62] chore: Bump github.com/aws/aws-sdk-go-v2 from 1.32.2 to 1.32.3 (#1912) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 0a25e89be..2e0fe3310 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 github.com/Azure/azure-sdk-for-go/sdk/containers/azcontainerregistry v0.2.2 github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 - github.com/aws/aws-sdk-go-v2 v1.32.2 + github.com/aws/aws-sdk-go-v2 v1.32.3 github.com/aws/aws-sdk-go-v2/config v1.27.43 github.com/aws/aws-sdk-go-v2/credentials v1.17.41 github.com/aws/aws-sdk-go-v2/service/ecr v1.28.6 diff --git a/go.sum b/go.sum index e5e20addc..05799a891 100644 --- a/go.sum +++ b/go.sum @@ -127,8 +127,8 @@ 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.32.2 h1:AkNLZEyYMLnx/Q/mSKkcMqwNFXMAvFto9bNsHqcTduI= -github.com/aws/aws-sdk-go-v2 v1.32.2/go.mod h1:2SK5n0a2karNTv5tbP1SjsX0uhttou00v/HpXKM1ZUo= +github.com/aws/aws-sdk-go-v2 v1.32.3 h1:T0dRlFBKcdaUPGNtkBSwHZxrtis8CQU17UpNBZYd0wk= +github.com/aws/aws-sdk-go-v2 v1.32.3/go.mod h1:2SK5n0a2karNTv5tbP1SjsX0uhttou00v/HpXKM1ZUo= github.com/aws/aws-sdk-go-v2/config v1.27.43 h1:p33fDDihFC390dhhuv8nOmX419wjOSDQRb+USt20RrU= github.com/aws/aws-sdk-go-v2/config v1.27.43/go.mod h1:pYhbtvg1siOOg8h5an77rXle9tVG8T+BWLWAo7cOukc= github.com/aws/aws-sdk-go-v2/credentials v1.17.41 h1:7gXo+Axmp+R4Z+AK8YFQO0ZV3L0gizGINCOWxSLY9W8= From 6edc911ca82aa1f469a8db79fdc832d72a547f6b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 18:00:17 +0000 Subject: [PATCH 25/62] chore: Bump github.com/aws/aws-sdk-go-v2/credentials from 1.17.41 to 1.17.42 (#1911) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 16 ++++++++-------- go.sum | 32 ++++++++++++++++---------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/go.mod b/go.mod index 2e0fe3310..eb1deeb91 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,7 @@ require ( github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 github.com/aws/aws-sdk-go-v2 v1.32.3 github.com/aws/aws-sdk-go-v2/config v1.27.43 - github.com/aws/aws-sdk-go-v2/credentials v1.17.41 + github.com/aws/aws-sdk-go-v2/credentials v1.17.42 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 @@ -141,14 +141,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.17 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.21 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.21 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.18 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.22 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.22 // 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.12.2 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.24.2 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.2 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.32.2 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.3 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.24.3 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.3 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.32.3 // indirect github.com/aws/smithy-go v1.22.0 // 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 05799a891..5d88273d1 100644 --- a/go.sum +++ b/go.sum @@ -131,14 +131,14 @@ github.com/aws/aws-sdk-go-v2 v1.32.3 h1:T0dRlFBKcdaUPGNtkBSwHZxrtis8CQU17UpNBZYd github.com/aws/aws-sdk-go-v2 v1.32.3/go.mod h1:2SK5n0a2karNTv5tbP1SjsX0uhttou00v/HpXKM1ZUo= github.com/aws/aws-sdk-go-v2/config v1.27.43 h1:p33fDDihFC390dhhuv8nOmX419wjOSDQRb+USt20RrU= github.com/aws/aws-sdk-go-v2/config v1.27.43/go.mod h1:pYhbtvg1siOOg8h5an77rXle9tVG8T+BWLWAo7cOukc= -github.com/aws/aws-sdk-go-v2/credentials v1.17.41 h1:7gXo+Axmp+R4Z+AK8YFQO0ZV3L0gizGINCOWxSLY9W8= -github.com/aws/aws-sdk-go-v2/credentials v1.17.41/go.mod h1:u4Eb8d3394YLubphT4jLEwN1rLNq2wFOlT6OuxFwPzU= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.17 h1:TMH3f/SCAWdNtXXVPPu5D6wrr4G5hI1rAxbcocKfC7Q= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.17/go.mod h1:1ZRXLdTpzdJb9fwTMXiLipENRxkGMTn1sfKexGllQCw= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.21 h1:UAsR3xA31QGf79WzpG/ixT9FZvQlh5HY1NRqSHBNOCk= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.21/go.mod h1:JNr43NFf5L9YaG3eKTm7HQzls9J+A9YYcGI5Quh1r2Y= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.21 h1:6jZVETqmYCadGFvrYEQfC5fAQmlo80CeL5psbno6r0s= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.21/go.mod h1:1SR0GbLlnN3QUmYaflZNiH1ql+1qrSiB2vwcJ+4UM60= +github.com/aws/aws-sdk-go-v2/credentials v1.17.42 h1:sBP0RPjBU4neGpIYyx8mkU2QqLPl5u9cmdTWVzIpHkM= +github.com/aws/aws-sdk-go-v2/credentials v1.17.42/go.mod h1:FwZBfU530dJ26rv9saAbxa9Ej3eF/AK0OAY86k13n4M= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.18 h1:68jFVtt3NulEzojFesM/WVarlFpCaXLKaBxDpzkQ9OQ= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.18/go.mod h1:Fjnn5jQVIo6VyedMc0/EhPpfNlPl7dHV916O6B+49aE= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.22 h1:Jw50LwEkVjuVzE1NzkhNKkBf9cRN7MtE1F/b2cOKTUM= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.22/go.mod h1:Y/SmAyPcOTmpeVaWSzSKiILfXTVJwrGmYZhcRbhWuEY= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.22 h1:981MHwBaRZM7+9QSR6XamDzF/o7ouUGxFzr+nVSIhrs= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.22/go.mod h1:1RA1+aBEfn+CAB/Mh0MB6LsdCYCnjZm7tKXtnk499ZQ= 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= @@ -147,16 +147,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.12.0 h1:TToQNkvGguu209puTojY/ozlqy2d/SFNcoLIqTFi42g= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0/go.mod h1:0jp+ltwkf+SwG2fm/PKo8t4y8pJSgOCO4D8Lz3k0aHQ= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.2 h1:s7NA1SOw8q/5c0wr8477yOPp0z+uBaXBnLE0XYb0POA= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.2/go.mod h1:fnjjWyAW/Pj5HYOxl9LJqWtEwS7W2qgcRLWP+uWbss0= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.3 h1:qcxX0JYlgWH3hpPUnd6U0ikcl6LLA9sLkXE2w1fpMvY= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.3/go.mod h1:cLSNEmI45soc+Ef8K/L+8sEA3A3pYFEYf5B5UI+6bH4= 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.24.2 h1:bSYXVyUzoTHoKalBmwaZxs97HU9DWWI3ehHSAMa7xOk= -github.com/aws/aws-sdk-go-v2/service/sso v1.24.2/go.mod h1:skMqY7JElusiOUjMJMOv1jJsP7YUg7DrhgqZZWuzu1U= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.2 h1:AhmO1fHINP9vFYUE0LHzCWg/LfUWUF+zFPEcY9QXb7o= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.2/go.mod h1:o8aQygT2+MVP0NaV6kbdE1YnnIM8RRVQzoeUH45GOdI= -github.com/aws/aws-sdk-go-v2/service/sts v1.32.2 h1:CiS7i0+FUe+/YY1GvIBLLrR/XNGZ4CtM1Ll0XavNuVo= -github.com/aws/aws-sdk-go-v2/service/sts v1.32.2/go.mod h1:HtaiBI8CjYoNVde8arShXb94UbQQi9L4EMr6D+xGBwo= +github.com/aws/aws-sdk-go-v2/service/sso v1.24.3 h1:UTpsIf0loCIWEbrqdLb+0RxnTXfWh2vhw4nQmFi4nPc= +github.com/aws/aws-sdk-go-v2/service/sso v1.24.3/go.mod h1:FZ9j3PFHHAR+w0BSEjK955w5YD2UwB/l/H0yAK3MJvI= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.3 h1:2YCmIXv3tmiItw0LlYf6v7gEHebLY45kBEnPezbUKyU= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.3/go.mod h1:u19stRyNPxGhj6dRm+Cdgu6N75qnbW7+QN0q0dsAk58= +github.com/aws/aws-sdk-go-v2/service/sts v1.32.3 h1:wVnQ6tigGsRqSWDEEyH6lSAJ9OyFUsSnbaUWChuSGzs= +github.com/aws/aws-sdk-go-v2/service/sts v1.32.3/go.mod h1:VZa9yTFyj4o10YGsmDO4gbQJUvvhY72fhumT8W4LqsE= github.com/aws/smithy-go v1.22.0 h1:uunKnWlcoL3zO7q+gG2Pk53joueEOsnNB28QdMsmiMM= github.com/aws/smithy-go v1.22.0/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= From b82b60db7e4e985debd7b1fff7e7a08dc05063a5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 10:38:32 -0800 Subject: [PATCH 26/62] chore: Bump github.com/AzureAD/microsoft-authentication-library-for-go from 1.2.2 to 1.2.3 (#1910) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index eb1deeb91..d503714c4 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 github.com/Azure/azure-sdk-for-go/sdk/containers/azcontainerregistry v0.2.2 - github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 + github.com/AzureAD/microsoft-authentication-library-for-go v1.2.3 github.com/aws/aws-sdk-go-v2 v1.32.3 github.com/aws/aws-sdk-go-v2/config v1.27.43 github.com/aws/aws-sdk-go-v2/credentials v1.17.42 diff --git a/go.sum b/go.sum index 5d88273d1..b9c4f32b7 100644 --- a/go.sum +++ b/go.sum @@ -59,8 +59,8 @@ github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUM github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= -github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU= -github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= +github.com/AzureAD/microsoft-authentication-library-for-go v1.2.3 h1:6LyjnnaLpcOKK0fbYisI+mb8CE7iNe7i89nMNQxFxs8= +github.com/AzureAD/microsoft-authentication-library-for-go v1.2.3/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= From 4f8dc7cf2fd2d798e9fa21681057096fa255a15a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 6 Nov 2024 16:20:59 +0800 Subject: [PATCH 27/62] chore: Bump anchore/sbom-action from 0.17.6 to 0.17.7 (#1915) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ec43b4a9f..0b637743a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -26,7 +26,7 @@ jobs: fetch-depth: 0 - name: Install Syft - uses: anchore/sbom-action/download-syft@251a468eed47e5082b105c3ba6ee500c0e65a764 # v0.17.6 + uses: anchore/sbom-action/download-syft@fc46e51fd3cb168ffb36c6d1915723c47db58abb # v0.17.7 - name: Set up Go uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 From 716fb8a490c56535179cba91055f2de35501327e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 6 Nov 2024 20:06:17 +0800 Subject: [PATCH 28/62] chore: Bump github.com/golang-jwt/jwt/v4 from 4.5.0 to 4.5.1 (#1916) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index d503714c4..f252a6706 100644 --- a/go.mod +++ b/go.mod @@ -173,7 +173,7 @@ require ( github.com/go-openapi/swag v0.23.0 // indirect github.com/go-openapi/validate v0.24.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang-jwt/jwt/v4 v4.5.0 // indirect + github.com/golang-jwt/jwt/v4 v4.5.1 // indirect github.com/golang/glog v1.2.1 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/snappy v0.0.4 // indirect diff --git a/go.sum b/go.sum index b9c4f32b7..47b4ca6a9 100644 --- a/go.sum +++ b/go.sum @@ -333,8 +333,9 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= -github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo= +github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= From 98f5581490edfceffa30adfe50d6a497ec79c72c Mon Sep 17 00:00:00 2001 From: Josh Duffney Date: Wed, 6 Nov 2024 14:52:24 -0600 Subject: [PATCH 29/62] feat: support enabled status for kmp keys/certs (#1874) Signed-off-by: Joshua Duffney --- .../keymanagementprovider_controller.go | 2 +- .../keymanagementprovider_controller.go | 2 +- pkg/controllers/utils/kmp.go | 7 +- pkg/controllers/utils/kmp_test.go | 13 +- .../azurekeyvault/provider.go | 109 ++++++-- .../azurekeyvault/provider_test.go | 261 +++++++++++++++--- .../azurekeyvault/types/types.go | 2 + .../keymanagementprovider.go | 25 ++ .../keymanagementprovider_test.go | 34 ++- pkg/keymanagementprovider/types/types.go | 1 + 10 files changed, 384 insertions(+), 72 deletions(-) diff --git a/pkg/controllers/clusterresource/keymanagementprovider_controller.go b/pkg/controllers/clusterresource/keymanagementprovider_controller.go index afb53a904..df454b3f2 100644 --- a/pkg/controllers/clusterresource/keymanagementprovider_controller.go +++ b/pkg/controllers/clusterresource/keymanagementprovider_controller.go @@ -80,7 +80,7 @@ func (r *KeyManagementProviderReconciler) ReconcileWithType(ctx context.Context, logger.Warn("Certificate Store already exists. Key management provider and certificate store should not be configured together. Please migrate to key management provider and delete certificate store.") } - provider, err := cutils.SpecToKeyManagementProvider(keyManagementProvider.Spec.Parameters.Raw, keyManagementProvider.Spec.Type) + provider, err := cutils.SpecToKeyManagementProvider(keyManagementProvider.Spec.Parameters.Raw, keyManagementProvider.Spec.Type, resource) if err != nil { kmpErr := re.ErrorCodeKeyManagementProviderFailure.WithError(err).WithDetail("Failed to create key management provider from CR") diff --git a/pkg/controllers/namespaceresource/keymanagementprovider_controller.go b/pkg/controllers/namespaceresource/keymanagementprovider_controller.go index 2bbdd0b29..dcba25711 100644 --- a/pkg/controllers/namespaceresource/keymanagementprovider_controller.go +++ b/pkg/controllers/namespaceresource/keymanagementprovider_controller.go @@ -79,7 +79,7 @@ func (r *KeyManagementProviderReconciler) ReconcileWithType(ctx context.Context, logger.Warn("Certificate Store already exists. Key management provider and certificate store should not be configured together. Please migrate to key management provider and delete certificate store.") } - provider, err := cutils.SpecToKeyManagementProvider(keyManagementProvider.Spec.Parameters.Raw, keyManagementProvider.Spec.Type) + provider, err := cutils.SpecToKeyManagementProvider(keyManagementProvider.Spec.Parameters.Raw, keyManagementProvider.Spec.Type, resource) if err != nil { kmpErr := re.ErrorCodeKeyManagementProviderFailure.WithError(err).WithDetail("Failed to create key management provider from CR") diff --git a/pkg/controllers/utils/kmp.go b/pkg/controllers/utils/kmp.go index a2085cfb5..8bda6a699 100644 --- a/pkg/controllers/utils/kmp.go +++ b/pkg/controllers/utils/kmp.go @@ -26,8 +26,8 @@ import ( ) // SpecToKeyManagementProvider creates KeyManagementProvider from KeyManagementProviderSpec config -func SpecToKeyManagementProvider(raw []byte, keyManagamentSystemName string) (kmp.KeyManagementProvider, error) { - kmProviderConfig, err := rawToKeyManagementProviderConfig(raw, keyManagamentSystemName) +func SpecToKeyManagementProvider(raw []byte, keyManagamentSystemName, resource string) (kmp.KeyManagementProvider, error) { + kmProviderConfig, err := rawToKeyManagementProviderConfig(raw, keyManagamentSystemName, resource) if err != nil { return nil, err } @@ -42,7 +42,7 @@ func SpecToKeyManagementProvider(raw []byte, keyManagamentSystemName string) (km } // rawToKeyManagementProviderConfig converts raw json to KeyManagementProviderConfig -func rawToKeyManagementProviderConfig(raw []byte, keyManagamentSystemName string) (config.KeyManagementProviderConfig, error) { +func rawToKeyManagementProviderConfig(raw []byte, keyManagamentSystemName, resource string) (config.KeyManagementProviderConfig, error) { pluginConfig := config.KeyManagementProviderConfig{} if string(raw) == "" { @@ -53,6 +53,7 @@ func rawToKeyManagementProviderConfig(raw []byte, keyManagamentSystemName string } pluginConfig[types.Type] = keyManagamentSystemName + pluginConfig[types.Resource] = resource return pluginConfig, nil } diff --git a/pkg/controllers/utils/kmp_test.go b/pkg/controllers/utils/kmp_test.go index e3223e481..bc3790f00 100644 --- a/pkg/controllers/utils/kmp_test.go +++ b/pkg/controllers/utils/kmp_test.go @@ -26,6 +26,7 @@ func TestSpecToKeyManagementProviderProvider(t *testing.T) { name string raw []byte kmpType string + resource string expectErr bool }{ { @@ -36,19 +37,21 @@ func TestSpecToKeyManagementProviderProvider(t *testing.T) { name: "missing inline provider required fields", raw: []byte("{\"type\": \"inline\"}"), kmpType: "inline", + resource: "test", expectErr: true, }, { name: "valid spec", raw: []byte(`{"type": "inline", "contentType": "certificate", "value": "-----BEGIN CERTIFICATE-----\nMIID2jCCAsKgAwIBAgIQXy2VqtlhSkiZKAGhsnkjbDANBgkqhkiG9w0BAQsFADBvMRswGQYDVQQD\nExJyYXRpZnkuZXhhbXBsZS5jb20xDzANBgNVBAsTBk15IE9yZzETMBEGA1UEChMKTXkgQ29tcGFu\neTEQMA4GA1UEBxMHUmVkbW9uZDELMAkGA1UECBMCV0ExCzAJBgNVBAYTAlVTMB4XDTIzMDIwMTIy\nNDUwMFoXDTI0MDIwMTIyNTUwMFowbzEbMBkGA1UEAxMScmF0aWZ5LmV4YW1wbGUuY29tMQ8wDQYD\nVQQLEwZNeSBPcmcxEzARBgNVBAoTCk15IENvbXBhbnkxEDAOBgNVBAcTB1JlZG1vbmQxCzAJBgNV\nBAgTAldBMQswCQYDVQQGEwJVUzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL10bM81\npPAyuraORABsOGS8M76Bi7Guwa3JlM1g2D8CuzSfSTaaT6apy9GsccxUvXd5cmiP1ffna5z+EFmc\nizFQh2aq9kWKWXDvKFXzpQuhyqD1HeVlRlF+V0AfZPvGt3VwUUjNycoUU44ctCWmcUQP/KShZev3\n6SOsJ9q7KLjxxQLsUc4mg55eZUThu8mGB8jugtjsnLUYvIWfHhyjVpGrGVrdkDMoMn+u33scOmrt\nsBljvq9WVo4T/VrTDuiOYlAJFMUae2Ptvo0go8XTN3OjLblKeiK4C+jMn9Dk33oGIT9pmX0vrDJV\nX56w/2SejC1AxCPchHaMuhlwMpftBGkCAwEAAaNyMHAwDgYDVR0PAQH/BAQDAgeAMAkGA1UdEwQC\nMAAwEwYDVR0lBAwwCgYIKwYBBQUHAwMwHwYDVR0jBBgwFoAU0eaKkZj+MS9jCp9Dg1zdv3v/aKww\nHQYDVR0OBBYEFNHmipGY/jEvYwqfQ4Nc3b97/2isMA0GCSqGSIb3DQEBCwUAA4IBAQBNDcmSBizF\nmpJlD8EgNcUCy5tz7W3+AAhEbA3vsHP4D/UyV3UgcESx+L+Nye5uDYtTVm3lQejs3erN2BjW+ds+\nXFnpU/pVimd0aYv6mJfOieRILBF4XFomjhrJOLI55oVwLN/AgX6kuC3CJY2NMyJKlTao9oZgpHhs\nLlxB/r0n9JnUoN0Gq93oc1+OLFjPI7gNuPXYOP1N46oKgEmAEmNkP1etFrEjFRgsdIFHksrmlOlD\nIed9RcQ087VLjmuymLgqMTFX34Q3j7XgN2ENwBSnkHotE9CcuGRW+NuiOeJalL8DBmFXXWwHTKLQ\nPp5g6m1yZXylLJaFLKz7tdMmO355\n-----END CERTIFICATE-----\n"}`), kmpType: "inline", + resource: "test", expectErr: false, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - _, err := SpecToKeyManagementProvider(tc.raw, tc.kmpType) + _, err := SpecToKeyManagementProvider(tc.raw, tc.kmpType, tc.resource) if tc.expectErr != (err != nil) { t.Fatalf("Expected error to be %t, got %t", tc.expectErr, err != nil) } @@ -60,6 +63,7 @@ func TestSpecToKeyManagementProviderProvider(t *testing.T) { func TestRawToKeyManagementProviderConfig(t *testing.T) { testCases := []struct { name string + resource string raw []byte expectErr bool expectConfig config.KeyManagementProviderConfig @@ -72,23 +76,26 @@ func TestRawToKeyManagementProviderConfig(t *testing.T) { }, { name: "unmarshal failure", + resource: "test", raw: []byte("invalid"), expectErr: true, expectConfig: config.KeyManagementProviderConfig{}, }, { name: "valid Raw", + resource: "test", raw: []byte("{\"type\": \"inline\"}"), expectErr: false, expectConfig: config.KeyManagementProviderConfig{ - "type": "inline", + "type": "inline", + "resource": "test", }, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - config, err := rawToKeyManagementProviderConfig(tc.raw, "inline") + config, err := rawToKeyManagementProviderConfig(tc.raw, "inline", "test") if tc.expectErr != (err != nil) { t.Fatalf("Expected error to be %t, got %t", tc.expectErr, err != nil) diff --git a/pkg/keymanagementprovider/azurekeyvault/provider.go b/pkg/keymanagementprovider/azurekeyvault/provider.go index da885af90..22c3fba6a 100644 --- a/pkg/keymanagementprovider/azurekeyvault/provider.go +++ b/pkg/keymanagementprovider/azurekeyvault/provider.go @@ -24,7 +24,9 @@ import ( "encoding/base64" "encoding/json" "encoding/pem" + "errors" "fmt" + "strconv" "strings" "time" @@ -40,6 +42,7 @@ import ( "golang.org/x/crypto/pkcs12" kv "github.com/Azure/azure-sdk-for-go/services/keyvault/v7.1/keyvault" + "github.com/Azure/go-autorest/autorest" "github.com/Azure/go-autorest/autorest/azure" ) @@ -59,6 +62,7 @@ type AKVKeyManagementProviderConfig struct { TenantID string `json:"tenantID"` ClientID string `json:"clientID"` CloudName string `json:"cloudName,omitempty"` + Resource string `json:"resource,omitempty"` Certificates []types.KeyVaultValue `json:"certificates,omitempty"` Keys []types.KeyVaultValue `json:"keys,omitempty"` } @@ -69,13 +73,44 @@ type akvKMProvider struct { tenantID string clientID string cloudName string + resource string certificates []types.KeyVaultValue keys []types.KeyVaultValue cloudEnv *azure.Environment - kvClient *kv.BaseClient + kvClient kvClient } + type akvKMProviderFactory struct{} +// kvClient is an interface to interact with the keyvault client used for mocking purposes +type kvClient interface { + // GetCertificate retrieves a certificate from the keyvault + GetCertificate(ctx context.Context, vaultBaseURL string, certificateName string, certificateVersion string) (kv.CertificateBundle, error) + // GetKey retrieves a key from the keyvault + GetKey(ctx context.Context, vaultBaseURL string, keyName string, keyVersion string) (kv.KeyBundle, error) + // GetSecret retrieves a secret from the keyvault + GetSecret(ctx context.Context, vaultBaseURL string, secretName string, secretVersion string) (kv.SecretBundle, error) +} + +type kvClientImpl struct { + kv.BaseClient +} + +// GetCertificate retrieves a certificate from the keyvault +func (c *kvClientImpl) GetCertificate(ctx context.Context, vaultBaseURL string, certificateName string, certificateVersion string) (kv.CertificateBundle, error) { + return c.BaseClient.GetCertificate(ctx, vaultBaseURL, certificateName, certificateVersion) +} + +// GetKey retrieves a key from the keyvault +func (c *kvClientImpl) GetKey(ctx context.Context, vaultBaseURL string, keyName string, keyVersion string) (kv.KeyBundle, error) { + return c.BaseClient.GetKey(ctx, vaultBaseURL, keyName, keyVersion) +} + +// GetSecret retrieves a secret from the keyvault +func (c *kvClientImpl) GetSecret(ctx context.Context, vaultBaseURL string, secretName string, secretVersion string) (kv.SecretBundle, error) { + return c.BaseClient.GetSecret(ctx, vaultBaseURL, secretName, secretVersion) +} + // initKVClient is a function to initialize the keyvault client // used for mocking purposes var initKVClient = initializeKvClient @@ -116,6 +151,7 @@ func (f *akvKMProviderFactory) Create(_ string, keyManagementProviderConfig conf certificates: conf.Certificates, keys: conf.Keys, cloudEnv: azureCloudEnv, + resource: conf.Resource, } if err := provider.validate(); err != nil { return nil, err @@ -127,7 +163,7 @@ func (f *akvKMProviderFactory) Create(_ string, keyManagementProviderConfig conf if err != nil { return nil, re.ErrorCodePluginInitFailure.NewError(re.KeyManagementProvider, ProviderName, re.AKVLink, err, "failed to create keyvault client", re.HideStackTrace) } - provider.kvClient = kvClient + provider.kvClient = &kvClientImpl{*kvClient} return provider, nil } @@ -140,25 +176,42 @@ func (s *akvKMProvider) GetCertificates(ctx context.Context) (map[keymanagementp for _, keyVaultCert := range s.certificates { logger.GetLogger(ctx, logOpt).Debugf("fetching secret from key vault, certName %v, keyvault %v", keyVaultCert.Name, s.vaultURI) - // fetch the object from Key Vault - // GetSecret is required so we can fetch the entire cert chain. See issue https://github.com/ratify-project/ratify/issues/695 for details startTime := time.Now() + + // GetSecret is required so we can fetch the entire cert chain. See issue https://github.com/ratify-project/ratify/issues/695 for details secretBundle, err := s.kvClient.GetSecret(ctx, s.vaultURI, keyVaultCert.Name, keyVaultCert.Version) if err != nil { + if isSecretDisabledError(err) { + // if secret is disabled, get the version of the certificate for status + certBundle, err := s.kvClient.GetCertificate(ctx, s.vaultURI, keyVaultCert.Name, keyVaultCert.Version) + if err != nil { + return nil, nil, fmt.Errorf("failed to get certificate objectName:%s, objectVersion:%s, error: %w", keyVaultCert.Name, keyVaultCert.Version, err) + } + keyVaultCert.Version = getObjectVersion(*certBundle.Kid) + isEnabled := *certBundle.Attributes.Enabled + lastRefreshed := startTime.Format(time.RFC3339) + certProperty := getStatusProperty(keyVaultCert.Name, keyVaultCert.Version, lastRefreshed, isEnabled) + certsStatus = append(certsStatus, certProperty) + mapKey := keymanagementprovider.KMPMapKey{Name: keyVaultCert.Name, Version: keyVaultCert.Version, Enabled: isEnabled} + keymanagementprovider.DeleteCertificateFromMap(s.resource, mapKey) + continue + } + return nil, nil, fmt.Errorf("failed to get secret objectName:%s, objectVersion:%s, error: %w", keyVaultCert.Name, keyVaultCert.Version, err) } - certResult, certProperty, err := getCertsFromSecretBundle(ctx, secretBundle, keyVaultCert.Name) + isEnabled := *secretBundle.Attributes.Enabled + + certResult, certProperty, err := getCertsFromSecretBundle(ctx, secretBundle, keyVaultCert.Name, isEnabled) if err != nil { return nil, nil, fmt.Errorf("failed to get certificates from secret bundle:%w", err) } metrics.ReportAKVCertificateDuration(ctx, time.Since(startTime).Milliseconds(), keyVaultCert.Name) certsStatus = append(certsStatus, certProperty...) - certMapKey := keymanagementprovider.KMPMapKey{Name: keyVaultCert.Name, Version: keyVaultCert.Version} + certMapKey := keymanagementprovider.KMPMapKey{Name: keyVaultCert.Name, Version: keyVaultCert.Version, Enabled: isEnabled} certsMap[certMapKey] = certResult } - return certsMap, getStatusMap(certsStatus, types.CertificatesStatus), nil } @@ -177,17 +230,27 @@ func (s *akvKMProvider) GetKeys(ctx context.Context) (map[keymanagementprovider. return nil, nil, fmt.Errorf("failed to get key objectName:%s, objectVersion:%s, error: %w", keyVaultKey.Name, keyVaultKey.Version, err) } - if keyBundle.Attributes != nil && keyBundle.Attributes.Enabled != nil && !*keyBundle.Attributes.Enabled { - return nil, nil, fmt.Errorf("key %s version %s is disabled. please re-enable in azure key vault or remove reference to this key", keyVaultKey.Name, keyVaultKey.Version) + isEnabled := *keyBundle.Attributes.Enabled + // if version is set as "" in the config, use the version from the key bundle + keyVaultKey.Version = getObjectVersion(*keyBundle.Key.Kid) + + if !isEnabled { + startTime := time.Now() + lastRefreshed := startTime.Format(time.RFC3339) + properties := getStatusProperty(keyVaultKey.Name, keyVaultKey.Version, lastRefreshed, isEnabled) + keysStatus = append(keysStatus, properties) + mapKey := keymanagementprovider.KMPMapKey{Name: keyVaultKey.Name, Version: keyVaultKey.Version, Enabled: isEnabled} + keymanagementprovider.DeleteKeyFromMap(s.resource, mapKey) + continue } publicKey, err := getKeyFromKeyBundle(keyBundle) if err != nil { return nil, nil, fmt.Errorf("failed to get key from key bundle:%w", err) } - keysMap[keymanagementprovider.KMPMapKey{Name: keyVaultKey.Name, Version: keyVaultKey.Version}] = publicKey + keysMap[keymanagementprovider.KMPMapKey{Name: keyVaultKey.Name, Version: keyVaultKey.Version, Enabled: isEnabled}] = publicKey metrics.ReportAKVCertificateDuration(ctx, time.Since(startTime).Milliseconds(), keyVaultKey.Name) - properties := getStatusProperty(keyVaultKey.Name, keyVaultKey.Version, time.Now().Format(time.RFC3339)) + properties := getStatusProperty(keyVaultKey.Name, keyVaultKey.Version, time.Now().Format(time.RFC3339), isEnabled) keysStatus = append(keysStatus, properties) } @@ -205,11 +268,12 @@ func getStatusMap(statusMap []map[string]string, contentType string) keymanageme return status } -// return a status object that consist of the cert/key name, version and last refreshed time -func getStatusProperty(name, version, lastRefreshed string) map[string]string { +// return a status object that consist of the cert/key name, version, enabled and last refreshed time +func getStatusProperty(name, version, lastRefreshed string, enabled bool) map[string]string { properties := map[string]string{} properties[types.StatusName] = name properties[types.StatusVersion] = version + properties[types.StatusEnabled] = strconv.FormatBool(enabled) properties[types.StatusLastRefreshed] = lastRefreshed return properties } @@ -230,7 +294,7 @@ func initializeKvClient(ctx context.Context, keyVaultEndpoint, tenantID, clientI kvClient := kv.New() kvEndpoint := strings.TrimSuffix(keyVaultEndpoint, "/") - err := kvClient.AddToUserAgent(userAgent) + err := kvClient.Client.AddToUserAgent(userAgent) if err != nil { return nil, re.ErrorCodeConfigInvalid.WithDetail("Failed to add user agent to keyvault client.").WithRemediation(re.AKVLink).WithError(err) } @@ -244,7 +308,7 @@ func initializeKvClient(ctx context.Context, keyVaultEndpoint, tenantID, clientI // Parse the secret bundle and return an array of certificates // In a certificate chain scenario, all certificates from root to leaf will be returned -func getCertsFromSecretBundle(ctx context.Context, secretBundle kv.SecretBundle, certName string) ([]*x509.Certificate, []map[string]string, error) { +func getCertsFromSecretBundle(ctx context.Context, secretBundle kv.SecretBundle, certName string, enabled bool) ([]*x509.Certificate, []map[string]string, error) { if secretBundle.ContentType == nil || secretBundle.Value == nil || secretBundle.ID == nil { return nil, nil, re.ErrorCodeCertInvalid.NewError(re.KeyManagementProvider, ProviderName, re.EmptyLink, nil, "found invalid secret bundle for certificate %s, contentType, value, and id must not be nil", re.HideStackTrace) } @@ -297,7 +361,7 @@ func getCertsFromSecretBundle(ctx context.Context, secretBundle kv.SecretBundle, } for _, cert := range decodedCerts { results = append(results, cert) - certProperty := getStatusProperty(certName, version, lastRefreshed) + certProperty := getStatusProperty(certName, version, lastRefreshed, enabled) certsStatus = append(certsStatus, certProperty) } default: @@ -352,6 +416,19 @@ func getObjectVersion(id string) string { return splitID[len(splitID)-1] } +func isSecretDisabledError(err error) bool { + var de autorest.DetailedError + if errors.As(err, &de) { + var re *azure.RequestError + if errors.As(de.Original, &re) { + if re.ServiceError.Code == "SecretDisabled" { + return true + } + } + } + return false +} + // validate checks vaultURI, tenantID, clientID are set and all certificates/keys have a name func (s *akvKMProvider) validate() error { if s.vaultURI == "" { diff --git a/pkg/keymanagementprovider/azurekeyvault/provider_test.go b/pkg/keymanagementprovider/azurekeyvault/provider_test.go index 676a43892..98effa5c4 100644 --- a/pkg/keymanagementprovider/azurekeyvault/provider_test.go +++ b/pkg/keymanagementprovider/azurekeyvault/provider_test.go @@ -20,12 +20,16 @@ package azurekeyvault import ( "context" "crypto" + "encoding/base64" + "errors" "strings" "testing" "time" kv "github.com/Azure/azure-sdk-for-go/services/keyvault/v7.1/keyvault" + "github.com/Azure/go-autorest/autorest" "github.com/Azure/go-autorest/autorest/azure" + "github.com/Azure/go-autorest/autorest/to" "github.com/ratify-project/ratify/internal/version" "github.com/ratify-project/ratify/pkg/keymanagementprovider/azurekeyvault/types" "github.com/ratify-project/ratify/pkg/keymanagementprovider/config" @@ -185,58 +189,238 @@ func TestCreate(t *testing.T) { } } +type MockKvClient struct { + GetCertificateFunc func(ctx context.Context, certificateName string, certificateVersion string, arg string) (kv.CertificateBundle, error) + GetSecretFunc func(ctx context.Context, secretName string, secretVersion string, arg string) (kv.SecretBundle, error) + GetKeyFunc func(ctx context.Context, keyName string, keyVersion string, arg string) (kv.KeyBundle, error) +} + +func (m *MockKvClient) GetCertificate(ctx context.Context, certificateName string, certificateVersion string, arg string) (kv.CertificateBundle, error) { + if m.GetCertificateFunc != nil { + return m.GetCertificateFunc(ctx, certificateName, certificateVersion, arg) + } + return kv.CertificateBundle{}, nil +} +func (m *MockKvClient) GetSecret(ctx context.Context, secretName string, secretVersion string, arg string) (kv.SecretBundle, error) { + if m.GetSecretFunc != nil { + return m.GetSecretFunc(ctx, secretName, secretVersion, arg) + } + return kv.SecretBundle{}, nil +} +func (m *MockKvClient) GetKey(ctx context.Context, keyName string, keyVersion string, arg string) (kv.KeyBundle, error) { + if m.GetKeyFunc != nil { + return m.GetKeyFunc(ctx, keyName, keyVersion, arg) + } + return kv.KeyBundle{}, nil +} + // TestGetCertificates tests the GetCertificates function func TestGetCertificates(t *testing.T) { - factory := &akvKMProviderFactory{} - config := config.KeyManagementProviderConfig{ - "vaultUri": "https://testkv.vault.azure.net/", - "tenantID": "tid", - "clientID": "clientid", - "certificates": []map[string]interface{}{ - { - "name": "cert1", - "version": "", + testCases := []struct { + name string + mockKvClient *MockKvClient + expectedErr bool + }{ + { + name: "GetSecret error", + mockKvClient: &MockKvClient{ + GetSecretFunc: func(_ context.Context, _ string, _ string, _ string) (kv.SecretBundle, error) { + return kv.SecretBundle{}, errors.New("error") + }, }, + expectedErr: true, + }, + { + name: "Certificate disabled", + mockKvClient: &MockKvClient{ + GetCertificateFunc: func(_ context.Context, _ string, _ string, _ string) (kv.CertificateBundle, error) { + return kv.CertificateBundle{ + ID: to.StringPtr("https://testkv.vault.azure.net/certificates/cert1"), + Kid: to.StringPtr("https://testkv.vault.azure.net/keys/key1"), + Attributes: &kv.CertificateAttributes{ + Enabled: to.BoolPtr(false), + }, + }, nil + }, + GetSecretFunc: func(_ context.Context, _ string, _ string, _ string) (kv.SecretBundle, error) { + err := autorest.DetailedError{ + Original: &azure.RequestError{ + ServiceError: &azure.ServiceError{Code: "SecretDisabled"}, + }, + } + return kv.SecretBundle{}, err + }, + }, + expectedErr: false, + }, + { + name: "Certificate disabled error", + mockKvClient: &MockKvClient{ + GetCertificateFunc: func(_ context.Context, _ string, _ string, _ string) (kv.CertificateBundle, error) { + return kv.CertificateBundle{}, errors.New("error") + }, + GetSecretFunc: func(_ context.Context, _ string, _ string, _ string) (kv.SecretBundle, error) { + err := autorest.DetailedError{ + Original: &azure.RequestError{ + ServiceError: &azure.ServiceError{Code: "SecretDisabled"}, + }, + } + return kv.SecretBundle{}, err + }, + }, + expectedErr: true, + }, + { + name: "Certificate enabled", + mockKvClient: &MockKvClient{ + GetCertificateFunc: func(_ context.Context, _ string, _ string, _ string) (kv.CertificateBundle, error) { + return kv.CertificateBundle{ + ID: to.StringPtr("https://testkv.vault.azure.net/certificates/cert1"), + Kid: to.StringPtr("https://testkv.vault.azure.net/keys/key1"), + Attributes: &kv.CertificateAttributes{ + Enabled: to.BoolPtr(true), + }, + }, nil + }, + GetSecretFunc: func(_ context.Context, _ string, _ string, _ string) (kv.SecretBundle, error) { + return kv.SecretBundle{ + ID: to.StringPtr("https://testkv.vault.azure.net/secrets/secret1"), + Kid: to.StringPtr("https://testkv.vault.azure.net/keys/key1"), + ContentType: to.StringPtr("application/x-pem-file"), + Attributes: &kv.SecretAttributes{ + Enabled: to.BoolPtr(true), + }, + Value: to.StringPtr("-----BEGIN CERTIFICATE-----\nMIIC8TCCAdmgAwIBAgIUaNrwbhs/I1ecqUYdzD2xuAVNdmowDQYJKoZIhvcNAQEL\nBQAwKjEPMA0GA1UECgwGUmF0aWZ5MRcwFQYDVQQDDA5SYXRpZnkgUm9vdCBDQTAe\nFw0yMzA2MjEwMTIyMzdaFw0yNDA2MjAwMTIyMzdaMBkxFzAVBgNVBAMMDnJhdGlm\neS5kZWZhdWx0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtskG1BUt\n4Fw2lbm53KbwZb1hnLmWdwRotZyznhhk/yrUDcq3uF6klwpk/E2IKfUKIo6doHSk\nXaEZXR68UtXygvA4wdg7xZ6kKpXy0gu+RxGE6CGtDHTyDDzITu+NBjo21ZSsyGpQ\nJeIKftUCHdwdygKf0CdJx8A29GBRpHGCmJadmt7tTzOnYjmbuPVLeqJo/Ex9qXcG\nZbxoxnxr5NCocFeKx+EbLo+k/KjdFB2PKnhgzxAaMMMP6eXPr8l5AlzkC83EmPvN\ntveuaBbamdlFkD+53TZeZlxt3GIdq93Iw/UpbQ/pvhbrztMT+UVEkm15sShfX8Xn\nL2st5A4n0V+66QIDAQABoyAwHjAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIH\ngDANBgkqhkiG9w0BAQsFAAOCAQEAGpOqozyfDSBjoTepsRroxxcZ4sq65gw45Bme\nm36BS6FG0WHIg3cMy6KIIBefTDSKrPkKNTtuF25AeGn9jM+26cnfDM78ZH0+Lnn7\n7hs0MA64WMPQaWs9/+89aM9NADV9vp2zdG4xMi6B7DruvKWyhJaNoRqK/qP6LdSQ\nw8M+21sAHvXgrRkQtJlVOzVhgwt36NOb1hzRlQiZB+nhv2Wbw7fbtAaADk3JAumf\nvM+YdPS1KfAFaYefm4yFd+9/C0KOkHico3LTbELO5hG0Mo/EYvtjM+Fljb42EweF\n3nAx1GSPe5Tn8p3h6RyJW5HIKozEKyfDuLS0ccB/nqT3oNjcTw==\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIDRTCCAi2gAwIBAgIUcC33VfaMhOnsl7avNTRVQozoVtUwDQYJKoZIhvcNAQEL\nBQAwKjEPMA0GA1UECgwGUmF0aWZ5MRcwFQYDVQQDDA5SYXRpZnkgUm9vdCBDQTAe\nFw0yMzA2MjEwMTIyMzZaFw0yMzA2MjIwMTIyMzZaMCoxDzANBgNVBAoMBlJhdGlm\neTEXMBUGA1UEAwwOUmF0aWZ5IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IB\nDwAwggEKAoIBAQDDFhDnyPrVDZaeRu6Tbg1a/iTwus+IuX+h8aKhKS1yHz4EF/Lz\nxCy7lNSQ9srGMMVumWuNom/ydIphff6PejZM1jFKPU6OQR/0JX5epcVIjbKa562T\nDguUxJ+h5V3EIyM4RqOWQ2g/xZo86x5TzyNJXiVdHHRvmDvUNwPpMeDjr/EHVAni\n5YQObxkJRiiZ7XOa5zz3YztVm8sSZAwPWroY1HIfvtP+KHpiNDIKSymmuJkH4SEr\nJn++iqN8na18a9DFBPTTrLPe3CxATGrMfosCMZ6LP3iFLLc/FaSpwcnugWdewsUK\nYs+sUY7jFWR7x7/1nyFWyRrQviM4f4TY+K7NAgMBAAGjYzBhMB0GA1UdDgQWBBQH\nYePW7QPP2p1utr3r6gqzEkKs+DAfBgNVHSMEGDAWgBQHYePW7QPP2p1utr3r6gqz\nEkKs+DAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwICBDANBgkqhkiG9w0B\nAQsFAAOCAQEAjKp4vx3bFaKVhAbQeTsDjWJgmXLK2vLgt74MiUwSF6t0wehlfszE\nIcJagGJsvs5wKFf91bnwiqwPjmpse/thPNBAxh1uEoh81tOklv0BN790vsVpq3t+\ncnUvWPiCZdRlAiGGFtRmKk3Keq4sM6UdiUki9s+wnxypHVb4wIpVxu5R271Lnp5I\n+rb2EQ48iblt4XZPczf/5QJdTgbItjBNbuO8WVPOqUIhCiFuAQziLtNUq3p81dHO\nQ2BPgmaitCpIUYHVYighLauBGCH8xOFzj4a4KbOxKdxyJTd0La/vRCKaUtJX67Lc\nfQYVR9HXQZ0YlmwPcmIG5v7wBfcW34NUvA==\n-----END CERTIFICATE-----\n"), + }, nil + }, + }, + }, + { + name: "getCertsFromSecretBundle error", + mockKvClient: &MockKvClient{ + GetSecretFunc: func(_ context.Context, _ string, _ string, _ string) (kv.SecretBundle, error) { + return kv.SecretBundle{ + ContentType: to.StringPtr("test"), + ID: to.StringPtr("https://testkv.vault.azure.net/secrets/secret1"), + Kid: to.StringPtr("https://testkv.vault.azure.net/keys/key1"), + Attributes: &kv.SecretAttributes{ + Enabled: to.BoolPtr(true), + }, + Value: to.StringPtr("-----BEGIN CERTIFICATE-----\nMIIC8TCCAdmgAwIBAgIUaNrwbhs/I1ecqUYdzD2xuAVNdmowDQYJKoZIhvcNAQEL\nBQAwKjEPMA0GA1UECgwGUmF0aWZ5MRcwFQYDVQQDDA5SYXRpZnkgUm9vdCBDQTAe\nFw0yMzA2MjEwMTIyMzdaFw0yNDA2MjAwMTIyMzdaMBkxFzAVBgNVBAMMDnJhdGlm\neS5kZWZhdWx0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtskG1BUt\n4Fw2lbm53KbwZb1hnLmWdwRotZyznhhk/yrUDcq3uF6klwpk/E2IKfUKIo6doHSk\nXaEZXR68UtXygvA4wdg7xZ6kKpXy0gu+RxGE6CGtDHTyDDzITu+NBjo21ZSsyGpQ\nJeIKftUCHdwdygKf0CdJx8A29GBRpHGCmJadmt7tTzOnYjmbuPVLeqJo/Ex9qXcG\nZbxoxnxr5NCocFeKx+EbLo+k/KjdFB2PKnhgzxAaMMMP6eXPr8l5AlzkC83EmPvN\ntveuaBbamdlFkD+53TZeZlxt3GIdq93Iw/UpbQ/pvhbrztMT+UVEkm15sShfX8Xn\nL2st5A4n0V+66QIDAQABoyAwHjAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIH\ngDANBgkqhkiG9w0BAQsFAAOCAQEAGpOqozyfDSBjoTepsRroxxcZ4sq65gw45Bme\nm36BS6FG0WHIg3cMy6KIIBefTDSKrPkKNTtuF25AeGn9jM+26cnfDM78ZH0+Lnn7\n7hs0MA64WMPQaWs9/+89aM9NADV9vp2zdG4xMi6B7DruvKWyhJaNoRqK/qP6LdSQ\nw8M+21sAHvXgrRkQtJlVOzVhgwt36NOb1hzRlQiZB+nhv2Wbw7fbtAaADk3JAumf\nvM+YdPS1KfAFaYefm4yFd+9/C0KOkHico3LTbELO5hG0Mo/EYvtjM+Fljb42EweF\n3nAx1GSPe5Tn8p3h6RyJW5HIKozEKyfDuLS0ccB/nqT3oNjcTw==\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIDRTCCAi2gAwIBAgIUcC33VfaMhOnsl7avNTRVQozoVtUwDQYJKoZIhvcNAQEL\nBQAwKjEPMA0GA1UECgwGUmF0aWZ5MRcwFQYDVQQDDA5SYXRpZnkgUm9vdCBDQTAe\nFw0yMzA2MjEwMTIyMzZaFw0yMzA2MjIwMTIyMzZaMCoxDzANBgNVBAoMBlJhdGlm\neTEXMBUGA1UEAwwOUmF0aWZ5IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IB\nDwAwggEKAoIBAQDDFhDnyPrVDZaeRu6Tbg1a/iTwus+IuX+h8aKhKS1yHz4EF/Lz\nxCy7lNSQ9srGMMVumWuNom/ydIphff6PejZM1jFKPU6OQR/0JX5epcVIjbKa562T\nDguUxJ+h5V3EIyM4RqOWQ2g/xZo86x5TzyNJXiVdHHRvmDvUNwPpMeDjr/EHVAni\n5YQObxkJRiiZ7XOa5zz3YztVm8sSZAwPWroY1HIfvtP+KHpiNDIKSymmuJkH4SEr\nJn++iqN8na18a9DFBPTTrLPe3CxATGrMfosCMZ6LP3iFLLc/FaSpwcnugWdewsUK\nYs+sUY7jFWR7x7/1nyFWyRrQviM4f4TY+K7NAgMBAAGjYzBhMB0GA1UdDgQWBBQH\nYePW7QPP2p1utr3r6gqzEkKs+DAfBgNVHSMEGDAWgBQHYePW7QPP2p1utr3r6gqz\nEkKs+DAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwICBDANBgkqhkiG9w0B\nAQsFAAOCAQEAjKp4vx3bFaKVhAbQeTsDjWJgmXLK2vLgt74MiUwSF6t0wehlfszE\nIcJagGJsvs5wKFf91bnwiqwPjmpse/thPNBAxh1uEoh81tOklv0BN790vsVpq3t+\ncnUvWPiCZdRlAiGGFtRmKk3Keq4sM6UdiUki9s+wnxypHVb4wIpVxu5R271Lnp5I\n+rb2EQ48iblt4XZPczf/5QJdTgbItjBNbuO8WVPOqUIhCiFuAQziLtNUq3p81dHO\nQ2BPgmaitCpIUYHVYighLauBGCH8xOFzj4a4KbOxKdxyJTd0La/vRCKaUtJX67Lc\nfQYVR9HXQZ0YlmwPcmIG5v7wBfcW34NUvA==\n-----END CERTIFICATE-----\n"), + }, nil + }, + }, + expectedErr: true, }, } - provider, err := factory.Create("v1", config, "") - if err != nil { - t.Fatalf("expected no err but got error = %v", err) - } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + provider := &akvKMProvider{ + certificates: []types.KeyVaultValue{ + { + Name: "cert1", + Version: "c1f03df1113d460491d970737dfdc35d", + }, + }, + kvClient: tc.mockKvClient, + } - certs, certStatus, err := provider.GetCertificates(context.Background()) - assert.NotNil(t, err) - assert.Nil(t, certs) - assert.Nil(t, certStatus) + _, _, err := provider.GetCertificates(context.Background()) + if tc.expectedErr != (err != nil) { + t.Fatalf("error = %v, expectedErr = %v", err, tc.expectedErr) + } + }) + } } // TestGetKeys tests the GetKeys function func TestGetKeys(t *testing.T) { - factory := &akvKMProviderFactory{} - config := config.KeyManagementProviderConfig{ - "vaultUri": "https://testkv.vault.azure.net/", - "tenantID": "tid", - "clientID": "clientid", - "keys": []map[string]interface{}{ - { - "name": "key1", + testCases := []struct { + name string + mockKvClient *MockKvClient + expectedErr bool + }{ + { + name: "GetKey error", + mockKvClient: &MockKvClient{ + GetKeyFunc: func(_ context.Context, _ string, _ string, _ string) (kv.KeyBundle, error) { + return kv.KeyBundle{}, errors.New("error") + }, }, + expectedErr: true, + }, + { + name: "Key disabled", + mockKvClient: &MockKvClient{ + GetKeyFunc: func(_ context.Context, _ string, _ string, _ string) (kv.KeyBundle, error) { + return kv.KeyBundle{ + Key: &kv.JSONWebKey{ + Kid: to.StringPtr("https://testkv.vault.azure.net/keys/key1"), + }, + Attributes: &kv.KeyAttributes{ + Enabled: to.BoolPtr(false), + }, + }, nil + }, + }, + expectedErr: false, + }, + { + name: "getKeyFromKeyBundle error", + mockKvClient: &MockKvClient{ + GetKeyFunc: func(_ context.Context, _ string, _ string, _ string) (kv.KeyBundle, error) { + return kv.KeyBundle{ + Key: &kv.JSONWebKey{ + Kid: to.StringPtr("https://testkv.vault.azure.net/keys/key1"), + }, + Attributes: &kv.KeyAttributes{ + Enabled: to.BoolPtr(true), + }, + }, nil + }, + }, + expectedErr: true, + }, + { + name: "Key enabled", + mockKvClient: &MockKvClient{ + GetKeyFunc: func(_ context.Context, _ string, _ string, _ string) (kv.KeyBundle, error) { + return kv.KeyBundle{ + Key: &kv.JSONWebKey{ + Kid: to.StringPtr("https://testkv.vault.azure.net/keys/key1"), + Kty: kv.RSA, + N: to.StringPtr(base64.StdEncoding.EncodeToString([]byte("n"))), + E: to.StringPtr(base64.StdEncoding.EncodeToString([]byte("e"))), + }, + Attributes: &kv.KeyAttributes{ + Enabled: to.BoolPtr(true), + }, + }, nil + }, + }, + expectedErr: false, }, } - initKVClient = func(_ context.Context, _, _, _, _ string) (*kv.BaseClient, error) { - return &kv.BaseClient{}, nil - } - provider, err := factory.Create("v1", config, "") - if err != nil { - t.Fatalf("expected no err but got error = %v", err) - } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + provider := &akvKMProvider{ + keys: []types.KeyVaultValue{ + { + Name: "key1", + Version: "c1f03df1113d460491d970737dfdc35d", + }, + }, + kvClient: tc.mockKvClient, + } - keys, keyStatus, err := provider.GetKeys(context.Background()) - assert.NotNil(t, err) - assert.Nil(t, keys) - assert.Nil(t, keyStatus) + _, _, err := provider.GetKeys(context.Background()) + if tc.expectedErr != (err != nil) { + t.Fatalf("error = %v, expectedErr = %v", err, tc.expectedErr) + } + }) + } } func TestIsRefreshable(t *testing.T) { @@ -288,8 +472,9 @@ func TestGetStatusProperty(t *testing.T) { timeNow := time.Now().String() certName := "certName" certVersion := "versionABC" + isEnabled := true - status := getStatusProperty(certName, certVersion, timeNow) + status := getStatusProperty(certName, certVersion, timeNow, isEnabled) assert.Equal(t, certName, status[types.StatusName]) assert.Equal(t, timeNow, status[types.StatusLastRefreshed]) assert.Equal(t, certVersion, status[types.StatusVersion]) @@ -349,7 +534,7 @@ func TestGetCertsFromSecretBundle(t *testing.T) { ContentType: &cases[i].contentType, } - certs, status, err := getCertsFromSecretBundle(context.Background(), testdata, "certName") + certs, status, err := getCertsFromSecretBundle(context.Background(), testdata, "certName", true) if tc.expectedErr { assert.NotNil(t, err) assert.Nil(t, certs) diff --git a/pkg/keymanagementprovider/azurekeyvault/types/types.go b/pkg/keymanagementprovider/azurekeyvault/types/types.go index 5cde59583..cae860773 100644 --- a/pkg/keymanagementprovider/azurekeyvault/types/types.go +++ b/pkg/keymanagementprovider/azurekeyvault/types/types.go @@ -25,6 +25,8 @@ const ( StatusName = "Name" // Certificate version string for the certificate status property StatusVersion = "Version" + // Enabled string for the certificate status property + StatusEnabled = "True" // Last refreshed string for the certificate status property StatusLastRefreshed = "LastRefreshed" ) diff --git a/pkg/keymanagementprovider/keymanagementprovider.go b/pkg/keymanagementprovider/keymanagementprovider.go index 584f50828..8a656b662 100644 --- a/pkg/keymanagementprovider/keymanagementprovider.go +++ b/pkg/keymanagementprovider/keymanagementprovider.go @@ -41,6 +41,7 @@ type KeyManagementProviderStatus map[string]interface{} type KMPMapKey struct { Name string Version string + Enabled bool } type PublicKey struct { @@ -156,6 +157,30 @@ func DeleteResourceFromMap(resource string) { keyErrMap.Delete(resource) } +// DeleteKeyFromMap deletes the keys from the map +func DeleteCertificateFromMap(resource string, certKey KMPMapKey) { + if certs, ok := certificatesMap.Load(resource); ok { + for k := range certs.(map[KMPMapKey][]*x509.Certificate) { + if k.Name == certKey.Name && k.Version == certKey.Version { + delete(certs.(map[KMPMapKey][]*x509.Certificate), k) + continue + } + } + } +} + +// DeleteKeyFromMap deletes the keys from the map +func DeleteKeyFromMap(resource string, key KMPMapKey) { + if keys, ok := keyMap.Load(resource); ok { + for k := range keys.(map[KMPMapKey]PublicKey) { + if k.Name == key.Name && k.Version == key.Version { + delete(keys.(map[KMPMapKey]PublicKey), k) + continue + } + } + } +} + // FlattenKMPMap flattens the map of certificates fetched for a single key management provider resource and returns a single array func FlattenKMPMap(certMap map[KMPMapKey][]*x509.Certificate) []*x509.Certificate { var items []*x509.Certificate diff --git a/pkg/keymanagementprovider/keymanagementprovider_test.go b/pkg/keymanagementprovider/keymanagementprovider_test.go index 044156220..57a2828ee 100644 --- a/pkg/keymanagementprovider/keymanagementprovider_test.go +++ b/pkg/keymanagementprovider/keymanagementprovider_test.go @@ -176,11 +176,19 @@ func TestGetCertificatesFromMap_ErrorFromReconcile(t *testing.T) { // TestDeleteCertificatesFromMap checks if certificates are deleted from the map func TestDeleteCertificatesFromMap(t *testing.T) { - certificatesMap.Delete("test") - setCertificatesInMap("test", map[KMPMapKey][]*x509.Certificate{{}: {{Raw: []byte("testcert")}}}) - DeleteResourceFromMap("test") - if _, ok := certificatesMap.Load("test"); ok { - t.Fatalf("certificatesMap should have been deleted for key") + resource := "test" + disabledCert := KMPMapKey{Name: "test", Version: "0", Enabled: false} + enabledCert := KMPMapKey{Name: "test", Version: "1", Enabled: true} + certsMap := map[KMPMapKey][]*x509.Certificate{} + certsMap[disabledCert] = []*x509.Certificate{{Raw: []byte("testcert")}} + certsMap[enabledCert] = []*x509.Certificate{{Raw: []byte("testcert")}} + setCertificatesInMap(resource, certsMap) + DeleteCertificateFromMap(resource, disabledCert) + + certs, _ := GetCertificatesFromMap(context.Background(), resource) + + if len(certs) != 1 { + t.Fatalf("certificates should have been deleted from the map") } } @@ -252,11 +260,17 @@ func TestGetKeysFromMap_AccessDifferentNamespace_ReturnsFalse(t *testing.T) { // TestDeleteKeysFromMap checks if key map entry is deleted from the map func TestDeleteKeysFromMap(t *testing.T) { - keyMap.Delete("test") - setKeysInMap("test", "", map[KMPMapKey]crypto.PublicKey{{}: &rsa.PublicKey{}}) - DeleteResourceFromMap("test") - if _, ok := keyMap.Load("test"); ok { - t.Fatalf("keysMap should have been deleted for key") + resource := "test" + keysMap := map[KMPMapKey]crypto.PublicKey{} + keyMapKey0 := KMPMapKey{Name: "test", Version: "0", Enabled: false} + keyMapKey1 := KMPMapKey{Name: "test", Version: "1", Enabled: true} + keysMap[keyMapKey0] = crypto.PublicKey(&rsa.PublicKey{}) + keysMap[keyMapKey1] = crypto.PublicKey(&rsa.PublicKey{}) + setKeysInMap(resource, "", keysMap) + DeleteKeyFromMap(resource, keyMapKey1) + keys, _ := GetKeysFromMap(context.Background(), resource) + if len(keys) != 1 { + t.Fatalf("keys should have been deleted from the map") } } diff --git a/pkg/keymanagementprovider/types/types.go b/pkg/keymanagementprovider/types/types.go index c15354dff..2e67b695e 100644 --- a/pkg/keymanagementprovider/types/types.go +++ b/pkg/keymanagementprovider/types/types.go @@ -19,5 +19,6 @@ const ( SpecVersion string = "0.1.0" Version string = "version" Type string = "type" + Resource string = "resource" Source string = "source" ) From 4ab047bf65f6f48f17a875292a5f0903747c0181 Mon Sep 17 00:00:00 2001 From: Binbin Li Date: Fri, 8 Nov 2024 10:32:31 +0800 Subject: [PATCH 30/62] ci: add cron job to cache trivy db (#1918) Signed-off-by: Binbin Li --- .../actions/restore_trivy_cache/action.yml | 20 +++++++++ .github/workflows/e2e-aks.yml | 3 ++ .github/workflows/e2e-cli.yml | 2 + .github/workflows/e2e-k8s.yml | 3 +- .github/workflows/scan-vulns.yaml | 11 +---- .github/workflows/update-trivy-cache.yml | 42 +++++++++++++++++++ Makefile | 19 --------- 7 files changed, 71 insertions(+), 29 deletions(-) create mode 100644 .github/actions/restore_trivy_cache/action.yml create mode 100644 .github/workflows/update-trivy-cache.yml diff --git a/.github/actions/restore_trivy_cache/action.yml b/.github/actions/restore_trivy_cache/action.yml new file mode 100644 index 000000000..fcc0e4a02 --- /dev/null +++ b/.github/actions/restore_trivy_cache/action.yml @@ -0,0 +1,20 @@ +name: "Steps to restore trivy cache" +description: "Steps to restore Trivy cache under ~/.cache/trivy" + +runs: + using: "composite" + steps: + - name: Get current date + id: date + run: echo "date=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT + shell: bash + - name: Restore trivy cache directory + uses: actions/cache/restore@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.1.2 + with: + path: ${{ github.workspace }}/.cache/trivy + key: cache-trivy-${{ steps.date.outputs.date }} + - name: Set up trivy cache directory + run: | + mkdir -p ~/.cache/trivy + cp -r ${{ github.workspace }}/.cache/trivy/db ~/.cache/trivy + shell: bash diff --git a/.github/workflows/e2e-aks.yml b/.github/workflows/e2e-aks.yml index 8e28b48fa..2cb7fbdf4 100644 --- a/.github/workflows/e2e-aks.yml +++ b/.github/workflows/e2e-aks.yml @@ -52,6 +52,9 @@ jobs: # Container Registry: az account get-access-token --scope https://containerregistry.azure.net/.default --output none + - name: Restore Trivy cache + uses: ./.github/actions/restore_trivy_cache + - name: Dependencies e2e run: | mkdir -p $GITHUB_WORKSPACE/bin diff --git a/.github/workflows/e2e-cli.yml b/.github/workflows/e2e-cli.yml index 8d1027b6c..5a2366f34 100644 --- a/.github/workflows/e2e-cli.yml +++ b/.github/workflows/e2e-cli.yml @@ -75,6 +75,8 @@ jobs: go-version: "1.22" - name: Run tidy run: go mod tidy + - name: Restore Trivy cache + uses: ./.github/actions/restore_trivy_cache - name: Build CLI run: make - name: Check build diff --git a/.github/workflows/e2e-k8s.yml b/.github/workflows/e2e-k8s.yml index e80b65f5b..2d911b56b 100644 --- a/.github/workflows/e2e-k8s.yml +++ b/.github/workflows/e2e-k8s.yml @@ -36,7 +36,8 @@ jobs: uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 with: go-version: "1.22" - + - name: Restore Trivy cache + uses: ./.github/actions/restore_trivy_cache - name: Bootstrap e2e run: | mkdir -p $GITHUB_WORKSPACE/bin diff --git a/.github/workflows/scan-vulns.yaml b/.github/workflows/scan-vulns.yaml index 1a554a6e8..fc9d9c9a9 100644 --- a/.github/workflows/scan-vulns.yaml +++ b/.github/workflows/scan-vulns.yaml @@ -55,15 +55,8 @@ jobs: tar zxvf trivy_${{ env.TRIVY_VERSION }}_Linux-64bit.tar.gz echo "$(pwd)" >> $GITHUB_PATH - - name: Download vulnerability database - uses: nick-fields/retry@7152eba30c6575329ac0576536151aca5a72780e # v3.0.0 - with: - max_attempts: 3 - retry_on: error - timeout_seconds: 30 - retry_wait_seconds: 5 - command: | - trivy image --download-db-only + - name: Restore Trivy cache + uses: ./.github/actions/restore_trivy_cache - name: Run trivy on git repository run: | diff --git a/.github/workflows/update-trivy-cache.yml b/.github/workflows/update-trivy-cache.yml new file mode 100644 index 000000000..dd39f3080 --- /dev/null +++ b/.github/workflows/update-trivy-cache.yml @@ -0,0 +1,42 @@ +name: Update Trivy Cache + +on: + schedule: + - cron: '0 0 * * *' # Run daily at midnight UTC + workflow_dispatch: + +permissions: read-all + +jobs: + update-trivy-db: + runs-on: ubuntu-latest + if: ${{ github.ref == github.event.repository.default_branch }} + steps: + - name: Setup oras + uses: oras-project/setup-oras@9c92598691bfef1424de2f8fae81941568f5889c # v1.2.1 + + - name: Get current date + id: date + run: echo "date=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT + + - name: Prepare DB directory + run: | + mkdir -p $GITHUB_WORKSPACE/.cache/trivy/db + + - name: Download vulnerability database + uses: nick-fields/retry@7152eba30c6575329ac0576536151aca5a72780e # v3.0.0 + with: + max_attempts: 60 + retry_on: error + timeout_seconds: 30 + retry_wait_seconds: 60 + command: | + oras pull ghcr.io/aquasecurity/trivy-db:2 + tar -xzf db.tar.gz -C $GITHUB_WORKSPACE/.cache/trivy/db + rm db.tar.gz + + - name: Cache DBs + uses: actions/cache/save@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.1.2 + with: + path: ${{ github.workspace }}/.cache/trivy + key: cache-trivy-${{ steps.date.outputs.date }} \ No newline at end of file diff --git a/Makefile b/Makefile index 3d06df53b..fde9cad09 100644 --- a/Makefile +++ b/Makefile @@ -467,25 +467,6 @@ e2e-trivy-setup: curl -L https://github.com/aquasecurity/trivy/releases/download/v${TRIVY_VERSION}/trivy_${TRIVY_VERSION}_Linux-64bit.tar.gz --output .staging/trivy/trivy.tar.gz tar -zxf .staging/trivy/trivy.tar.gz -C .staging/trivy - # Download vulnerability database in retry mode - max_retries=3; \ - attempt=1; \ - wait_time=2; \ - while [ $$attempt -le $$max_retries ]; do \ - echo "Attempt $$attempt of $$max_retries..."; \ - if .staging/trivy/trivy image --download-db-only; then \ - break; \ - fi; \ - if [ $$attempt -eq $$max_retries ]; then \ - echo "Failed after $$max_retries attempts."; \ - exit 1; \ - fi; \ - echo "Failed. Retrying in $$wait_time seconds..."; \ - sleep $$wait_time; \ - wait_time=$$(( wait_time * 2 )); \ - attempt=$$(( attempt + 1 )); \ - done - e2e-schemavalidator-setup: rm -rf .staging/schemavalidator mkdir -p .staging/schemavalidator From 18a88788febe674e2dd5092d48b53b419eea3366 Mon Sep 17 00:00:00 2001 From: Binbin Li Date: Fri, 8 Nov 2024 10:45:36 +0800 Subject: [PATCH 31/62] fix: fix the conditional check on update-trivy-cache job (#1919) Signed-off-by: Binbin Li --- .github/workflows/update-trivy-cache.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/update-trivy-cache.yml b/.github/workflows/update-trivy-cache.yml index dd39f3080..6d2fea0be 100644 --- a/.github/workflows/update-trivy-cache.yml +++ b/.github/workflows/update-trivy-cache.yml @@ -10,7 +10,7 @@ permissions: read-all jobs: update-trivy-db: runs-on: ubuntu-latest - if: ${{ github.ref == github.event.repository.default_branch }} + if: ${{ github.ref_name == github.event.repository.default_branch }} steps: - name: Setup oras uses: oras-project/setup-oras@9c92598691bfef1424de2f8fae81941568f5889c # v1.2.1 From 4510dd8645010f27276cde6b716f48f9ce041202 Mon Sep 17 00:00:00 2001 From: Juncheng Zhu Date: Fri, 8 Nov 2024 18:21:29 +0800 Subject: [PATCH 32/62] feat: add support for crl basic functionality with built-in cache (#1890) Signed-off-by: Juncheng Zhu Co-authored-by: Binbin Li --- go.mod | 6 +- go.sum | 12 +- pkg/verifier/notation/notation.go | 37 ++++++- pkg/verifier/notation/notation_test.go | 103 ++++++++++++++++++ .../notation/notationrevocationfactory.go | 63 +++++++++++ .../notationrevocationfactory_test.go | 103 ++++++++++++++++++ pkg/verifier/notation/revocationfactory.go | 27 +++++ 7 files changed, 338 insertions(+), 13 deletions(-) create mode 100644 pkg/verifier/notation/notationrevocationfactory.go create mode 100644 pkg/verifier/notation/notationrevocationfactory_test.go create mode 100644 pkg/verifier/notation/revocationfactory.go diff --git a/go.mod b/go.mod index f252a6706..32985ce77 100644 --- a/go.mod +++ b/go.mod @@ -29,8 +29,8 @@ require ( github.com/golang/protobuf v1.5.4 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.1 + github.com/notaryproject/notation-core-go v1.2.0-rc.1 + github.com/notaryproject/notation-go v1.3.0-rc.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 @@ -238,7 +238,7 @@ require ( go.uber.org/zap v1.27.0 // indirect golang.org/x/crypto v0.28.0 golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 // indirect - golang.org/x/mod v0.20.0 // indirect + golang.org/x/mod v0.21.0 // indirect golang.org/x/net v0.29.0 // indirect golang.org/x/oauth2 v0.23.0 // indirect golang.org/x/sys v0.26.0 // indirect diff --git a/go.sum b/go.sum index 47b4ca6a9..72451b682 100644 --- a/go.sum +++ b/go.sum @@ -519,10 +519,10 @@ github.com/mozillazg/docker-credential-acr-helper v0.3.0/go.mod h1:cZlu3tof523uj github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= 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.1 h1:fbCMBcvg1xttrisd5CyM60QDectGYYF701Us0M3cKN8= -github.com/notaryproject/notation-go v1.2.1/go.mod h1:re9V+TfuNRaUq5e3NuNcCJN53++sL2KbnJrjGyOUpgE= +github.com/notaryproject/notation-core-go v1.2.0-rc.1 h1:VMFlG+9a1JoNAQ3M96g8iqCq0cDRtE7XBaiTD8Ouvqw= +github.com/notaryproject/notation-core-go v1.2.0-rc.1/go.mod h1:b/70rA4OgOHlg0A7pb8zTWKJadFO6781zS3a37KHEJQ= +github.com/notaryproject/notation-go v1.3.0-rc.1 h1:pm9tdUy2tWYqlwyRDZyKXgLwAscDATPUYv0ul2RK/Iw= +github.com/notaryproject/notation-go v1.3.0-rc.1/go.mod h1:W4o45yolX4Q+3PKlcpGleLLXEKWHa3BshEqw/JX5c6I= 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= @@ -796,8 +796,8 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= -golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= +golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= diff --git a/pkg/verifier/notation/notation.go b/pkg/verifier/notation/notation.go index e825db11d..52fdcbda6 100644 --- a/pkg/verifier/notation/notation.go +++ b/pkg/verifier/notation/notation.go @@ -36,6 +36,8 @@ import ( "github.com/ratify-project/ratify/pkg/verifier/factory" "github.com/ratify-project/ratify/pkg/verifier/types" + "github.com/notaryproject/notation-core-go/revocation" + "github.com/notaryproject/notation-core-go/revocation/purpose" _ "github.com/notaryproject/notation-core-go/signature/cose" // register COSE signature _ "github.com/notaryproject/notation-core-go/signature/jws" // register JWS signature "github.com/notaryproject/notation-go" @@ -103,8 +105,7 @@ func (f *notationPluginVerifierFactory) Create(_ string, verifierConfig config.V if err != nil { return nil, re.ErrorCodePluginInitFailure.WithDetail("Failed to create the Notation Verifier").WithError(err) } - - verifyService, err := getVerifierService(conf, pluginDirectory) + verifyService, err := getVerifierService(conf, pluginDirectory, NewRevocationFactoryImpl()) if err != nil { return nil, re.ErrorCodePluginInitFailure.WithDetail("Failed to create the Notation Verifier").WithError(err) } @@ -176,12 +177,40 @@ func (v *notationPluginVerifier) Verify(ctx context.Context, return verifier.NewVerifierResult("", v.name, v.verifierType, "Notation signature verification success", true, nil, extensions), nil } -func getVerifierService(conf *NotationPluginVerifierConfig, pluginDirectory string) (notation.Verifier, error) { +func getVerifierService(conf *NotationPluginVerifierConfig, pluginDirectory string, revocationFactory RevocationFactory) (notation.Verifier, error) { store, err := newTrustStore(conf.VerificationCerts, conf.VerificationCertStores) if err != nil { return nil, err } - verifier, err := notationVerifier.New(&conf.TrustPolicyDoc, store, NewRatifyPluginManager(pluginDirectory)) + + // revocation check using corecrl from notation-core-go and crl from notation-go + // This is the implementation for revocation check from notation cli to support crl and cache configurations + // removed timeout + // Related PR: notaryproject/notation#1043 + // Related File: https://github.com/notaryproject/notation/commits/main/cmd/notation/verify.go5 + crlFetcher, err := revocationFactory.NewFetcher() + if err != nil { + return nil, err + } + revocationCodeSigningValidator, err := revocationFactory.NewValidator(revocation.Options{ + CRLFetcher: crlFetcher, + CertChainPurpose: purpose.CodeSigning, + }) + if err != nil { + return nil, err + } + revocationTimestampingValidator, err := revocationFactory.NewValidator(revocation.Options{ + CRLFetcher: crlFetcher, + CertChainPurpose: purpose.Timestamping, + }) + if err != nil { + return nil, err + } + + verifier, err := notationVerifier.NewWithOptions(&conf.TrustPolicyDoc, store, NewRatifyPluginManager(pluginDirectory), notationVerifier.VerifierOptions{ + RevocationCodeSigningValidator: revocationCodeSigningValidator, + RevocationTimestampingValidator: revocationTimestampingValidator, + }) if err != nil { return nil, re.ErrorCodePluginInitFailure.WithDetail("Failed to create the Notation Verifier").WithError(err) } diff --git a/pkg/verifier/notation/notation_test.go b/pkg/verifier/notation/notation_test.go index dc34a1f9d..bf2fa4abb 100644 --- a/pkg/verifier/notation/notation_test.go +++ b/pkg/verifier/notation/notation_test.go @@ -18,10 +18,14 @@ import ( "crypto/x509" "crypto/x509/pkix" "fmt" + "net/http" paths "path/filepath" "reflect" "testing" + "github.com/notaryproject/notation-core-go/revocation" + corecrl "github.com/notaryproject/notation-core-go/revocation/crl" + "github.com/notaryproject/notation-core-go/revocation/purpose" sig "github.com/notaryproject/notation-core-go/signature" "github.com/notaryproject/notation-go" "github.com/opencontainers/go-digest" @@ -558,3 +562,102 @@ func TestNormalizeLegacyCertStore(t *testing.T) { }) } } +func TestGetVerifierService(t *testing.T) { + tests := []struct { + name string + conf *NotationPluginVerifierConfig + pluginDir string + RevocationFactory RevocationFactory + expectErr bool + errContent error + }{ + { + name: "failed to create CRL fetcher", + conf: &NotationPluginVerifierConfig{ + VerificationCerts: []string{defaultCertDir}, + }, + pluginDir: "", + RevocationFactory: mockRevocationFactory{httpClient: &http.Client{}, failFetcher: true}, + expectErr: true, + errContent: nil, + }, + { + name: "failed to create file cache", + conf: &NotationPluginVerifierConfig{ + VerificationCerts: []string{defaultCertDir}, + }, + pluginDir: "", + RevocationFactory: mockRevocationFactory{httpClient: &http.Client{}, failFileCache: true}, + expectErr: true, + errContent: nil, + }, + { + name: "failed to create code signing validator", + conf: &NotationPluginVerifierConfig{ + VerificationCerts: []string{defaultCertDir}, + }, + pluginDir: "", + RevocationFactory: mockRevocationFactory{httpClient: &http.Client{}, failCodeSigningValidator: true}, + expectErr: true, + errContent: fmt.Errorf("failed to create code signing validator"), + }, + { + name: "failed to create timestamping validator", + conf: &NotationPluginVerifierConfig{ + VerificationCerts: []string{defaultCertDir}, + }, + pluginDir: "", + RevocationFactory: mockRevocationFactory{httpClient: &http.Client{}, failTimestampingValidator: true}, + expectErr: true, + errContent: fmt.Errorf("failed to create timestamping validator"), + }, + { + name: "failed to create verifier", + conf: &NotationPluginVerifierConfig{ + VerificationCerts: []string{defaultCertDir}, + }, + pluginDir: "", + RevocationFactory: mockRevocationFactory{httpClient: &http.Client{}, failVerifier: true}, + expectErr: true, + errContent: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + _, err := getVerifierService(tt.conf, tt.pluginDir, tt.RevocationFactory) + if (err != nil) != tt.expectErr { + t.Errorf("error = %v, expectErr = %v", err, tt.expectErr) + } + if tt.errContent != nil && err.Error() != tt.errContent.Error() { + t.Errorf("error = %v, expectErr = %v, content = %v", err, tt.expectErr, tt.errContent) + } + }) + } +} + +type mockRevocationFactory struct { + failFetcher bool + failFileCache bool + failCodeSigningValidator bool + failTimestampingValidator bool + failVerifier bool + httpClient *http.Client +} + +func (m mockRevocationFactory) NewFetcher() (corecrl.Fetcher, error) { + if m.failFetcher { + return nil, fmt.Errorf("failed to create fetcher") + } + return corecrl.NewHTTPFetcher(m.httpClient) +} + +func (m mockRevocationFactory) NewValidator(opts revocation.Options) (revocation.Validator, error) { + if m.failCodeSigningValidator && opts.CertChainPurpose == purpose.CodeSigning { + return nil, fmt.Errorf("failed to create code signing validator") + } + if m.failTimestampingValidator && opts.CertChainPurpose == purpose.Timestamping { + return nil, fmt.Errorf("failed to create timestamping validator") + } + return revocation.NewWithOptions(opts) +} diff --git a/pkg/verifier/notation/notationrevocationfactory.go b/pkg/verifier/notation/notationrevocationfactory.go new file mode 100644 index 000000000..47cc35606 --- /dev/null +++ b/pkg/verifier/notation/notationrevocationfactory.go @@ -0,0 +1,63 @@ +// Copyright The Ratify Authors. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package notation + +import ( + "net/http" + + "github.com/notaryproject/notation-core-go/revocation" + corecrl "github.com/notaryproject/notation-core-go/revocation/crl" + "github.com/notaryproject/notation-go/dir" + "github.com/notaryproject/notation-go/verifier/crl" +) + +type RevocationFactoryImpl struct { + cacheRoot string + httpClient *http.Client +} + +// NewRevocationFactoryImpl returns a new NewRevocationFactoryImpl instance +func NewRevocationFactoryImpl() RevocationFactory { + return &RevocationFactoryImpl{ + cacheRoot: dir.PathCRLCache, + httpClient: &http.Client{}, + } +} + +// NewFetcher returns a new fetcher instance +func (f *RevocationFactoryImpl) NewFetcher() (corecrl.Fetcher, error) { + crlFetcher, err := corecrl.NewHTTPFetcher(f.httpClient) + if err != nil { + return nil, err + } + crlFetcher.Cache, err = newFileCache(f.cacheRoot) + if err != nil { + return nil, err + } + return crlFetcher, nil +} + +// NewValidator returns a new validator instance +func (f *RevocationFactoryImpl) NewValidator(opts revocation.Options) (revocation.Validator, error) { + return revocation.NewWithOptions(opts) +} + +// newFileCache returns a new file cache instance +func newFileCache(root string) (*crl.FileCache, error) { + cacheRoot, err := dir.CacheFS().SysPath(root) + if err != nil { + return nil, err + } + return crl.NewFileCache(cacheRoot) +} diff --git a/pkg/verifier/notation/notationrevocationfactory_test.go b/pkg/verifier/notation/notationrevocationfactory_test.go new file mode 100644 index 000000000..b5355f83c --- /dev/null +++ b/pkg/verifier/notation/notationrevocationfactory_test.go @@ -0,0 +1,103 @@ +// Copyright The Ratify Authors. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package notation + +import ( + "net/http" + "runtime" + "testing" + + "github.com/notaryproject/notation-core-go/revocation" + "github.com/stretchr/testify/assert" +) + +func TestNewRevocationFactoryImpl(t *testing.T) { + factory := NewRevocationFactoryImpl() + assert.NotNil(t, factory) +} + +func TestNewFetcher(t *testing.T) { + tests := []struct { + name string + cacheRoot string + httpClient *http.Client + wantErr bool + }{ + { + name: "valid fetcher", + cacheRoot: "/valid/path", + httpClient: &http.Client{}, + wantErr: false, + }, + { + name: "invalid fetcher with nil httpClient", + cacheRoot: "/valid/path", + httpClient: nil, + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + factory := &RevocationFactoryImpl{ + cacheRoot: tt.cacheRoot, + httpClient: tt.httpClient, + } + + fetcher, err := factory.NewFetcher() + if tt.wantErr { + assert.Error(t, err) + assert.Nil(t, fetcher) + } + }) + } +} + +func TestNewValidator(t *testing.T) { + factory := &RevocationFactoryImpl{} + opts := revocation.Options{} + + validator, err := factory.NewValidator(opts) + assert.NoError(t, err) + assert.NotNil(t, validator) +} +func TestNewFileCache(t *testing.T) { + tests := []struct { + name string + cacheRoot string + wantErr bool + }{ + { + name: "valid cache root", + cacheRoot: "/valid/path", + wantErr: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("skipping test on Windows") + } + cache, err := newFileCache(tt.cacheRoot) + if tt.wantErr { + assert.Error(t, err) + assert.Nil(t, cache) + } else { + assert.NoError(t, err) + assert.NotNil(t, cache) + } + }) + } +} diff --git a/pkg/verifier/notation/revocationfactory.go b/pkg/verifier/notation/revocationfactory.go new file mode 100644 index 000000000..7860ec2a7 --- /dev/null +++ b/pkg/verifier/notation/revocationfactory.go @@ -0,0 +1,27 @@ +// Copyright The Ratify Authors. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package notation + +import ( + "github.com/notaryproject/notation-core-go/revocation" + corecrl "github.com/notaryproject/notation-core-go/revocation/crl" +) + +type RevocationFactory interface { + // NewFetcher returns a new fetcher instance + NewFetcher() (corecrl.Fetcher, error) + + // NewValidator returns a new validator instance + NewValidator(revocation.Options) (revocation.Validator, error) +} From 8647de290fa0b150ae9082f68ff03dd91f2bff7a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Nov 2024 02:41:07 +0000 Subject: [PATCH 33/62] chore: Bump goreleaser/goreleaser-action from 6.0.0 to 6.1.0 (#1920) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0b637743a..5479ad24c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -35,7 +35,7 @@ jobs: - name: Goreleaser id: goreleaser - uses: goreleaser/goreleaser-action@286f3b13b1b49da4ac219696163fb8c1c93e1200 # v6.0.0 + uses: goreleaser/goreleaser-action@9ed2f89a662bf1735a48bc8557fd212fa902bebf # v6.1.0 with: version: "2.0.1" args: release --clean From 511751f1ee538aaecfc4804447610f18b6ff4155 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Nov 2024 05:51:54 +0000 Subject: [PATCH 34/62] chore: Bump github/codeql-action from 3.27.0 to 3.27.1 (#1922) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/codeql.yml | 4 ++-- .github/workflows/scorecards.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 6e86bb638..5de96664f 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -37,7 +37,7 @@ jobs: with: go-version: "1.22" - name: Initialize CodeQL - uses: github/codeql-action/init@662472033e021d55d94146f66f6058822b0b39fd # tag=v3.27.0 + uses: github/codeql-action/init@4f3212b61783c3c68e8309a0f18a699764811cda # tag=v3.27.1 with: languages: go - name: Run tidy @@ -45,4 +45,4 @@ jobs: - name: Build CLI run: make build - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@662472033e021d55d94146f66f6058822b0b39fd # tag=v3.27.0 + uses: github/codeql-action/analyze@4f3212b61783c3c68e8309a0f18a699764811cda # tag=v3.27.1 diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index ca1a7db65..90785643a 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -55,6 +55,6 @@ jobs: retention-days: 5 - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@662472033e021d55d94146f66f6058822b0b39fd # tag=v3.27.0 + uses: github/codeql-action/upload-sarif@4f3212b61783c3c68e8309a0f18a699764811cda # tag=v3.27.1 with: sarif_file: results.sarif From b673586599e047c0a15820165f3d192e4c5917b8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Nov 2024 06:21:25 +0000 Subject: [PATCH 35/62] chore: Bump github.com/aws/aws-sdk-go-v2/credentials from 1.17.42 to 1.17.44 (#1923) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 20 ++++++++++---------- go.sum | 36 ++++++++++++++++++------------------ 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/go.mod b/go.mod index 32985ce77..396a408dc 100644 --- a/go.mod +++ b/go.mod @@ -13,10 +13,11 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 github.com/Azure/azure-sdk-for-go/sdk/containers/azcontainerregistry v0.2.2 + github.com/Azure/go-autorest/autorest/to v0.4.0 github.com/AzureAD/microsoft-authentication-library-for-go v1.2.3 - github.com/aws/aws-sdk-go-v2 v1.32.3 + github.com/aws/aws-sdk-go-v2 v1.32.4 github.com/aws/aws-sdk-go-v2/config v1.27.43 - github.com/aws/aws-sdk-go-v2/credentials v1.17.42 + github.com/aws/aws-sdk-go-v2/credentials v1.17.44 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 @@ -63,7 +64,6 @@ require ( github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/alibabacloudsdkgo/helper v0.2.0 // indirect github.com/Azure/go-autorest/autorest/azure/auth v0.5.12 // indirect github.com/Azure/go-autorest/autorest/azure/cli v0.4.6 // indirect - github.com/Azure/go-autorest/autorest/to v0.4.0 // indirect github.com/Azure/go-autorest/autorest/validation v0.3.1 // indirect github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect @@ -141,14 +141,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.18 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.22 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.22 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.19 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.23 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.23 // 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.12.3 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.24.3 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.3 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.32.3 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.4 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.24.5 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.4 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.32.4 // indirect github.com/aws/smithy-go v1.22.0 // 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 72451b682..a9f30e949 100644 --- a/go.sum +++ b/go.sum @@ -127,18 +127,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.32.3 h1:T0dRlFBKcdaUPGNtkBSwHZxrtis8CQU17UpNBZYd0wk= -github.com/aws/aws-sdk-go-v2 v1.32.3/go.mod h1:2SK5n0a2karNTv5tbP1SjsX0uhttou00v/HpXKM1ZUo= +github.com/aws/aws-sdk-go-v2 v1.32.4 h1:S13INUiTxgrPueTmrm5DZ+MiAo99zYzHEFh1UNkOxNE= +github.com/aws/aws-sdk-go-v2 v1.32.4/go.mod h1:2SK5n0a2karNTv5tbP1SjsX0uhttou00v/HpXKM1ZUo= github.com/aws/aws-sdk-go-v2/config v1.27.43 h1:p33fDDihFC390dhhuv8nOmX419wjOSDQRb+USt20RrU= github.com/aws/aws-sdk-go-v2/config v1.27.43/go.mod h1:pYhbtvg1siOOg8h5an77rXle9tVG8T+BWLWAo7cOukc= -github.com/aws/aws-sdk-go-v2/credentials v1.17.42 h1:sBP0RPjBU4neGpIYyx8mkU2QqLPl5u9cmdTWVzIpHkM= -github.com/aws/aws-sdk-go-v2/credentials v1.17.42/go.mod h1:FwZBfU530dJ26rv9saAbxa9Ej3eF/AK0OAY86k13n4M= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.18 h1:68jFVtt3NulEzojFesM/WVarlFpCaXLKaBxDpzkQ9OQ= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.18/go.mod h1:Fjnn5jQVIo6VyedMc0/EhPpfNlPl7dHV916O6B+49aE= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.22 h1:Jw50LwEkVjuVzE1NzkhNKkBf9cRN7MtE1F/b2cOKTUM= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.22/go.mod h1:Y/SmAyPcOTmpeVaWSzSKiILfXTVJwrGmYZhcRbhWuEY= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.22 h1:981MHwBaRZM7+9QSR6XamDzF/o7ouUGxFzr+nVSIhrs= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.22/go.mod h1:1RA1+aBEfn+CAB/Mh0MB6LsdCYCnjZm7tKXtnk499ZQ= +github.com/aws/aws-sdk-go-v2/credentials v1.17.44 h1:qqfs5kulLUHUEXlHEZXLJkgGoF3kkUeFUTVA585cFpU= +github.com/aws/aws-sdk-go-v2/credentials v1.17.44/go.mod h1:0Lm2YJ8etJdEdw23s+q/9wTpOeo2HhNE97XcRa7T8MA= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.19 h1:woXadbf0c7enQ2UGCi8gW/WuKmE0xIzxBF/eD94jMKQ= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.19/go.mod h1:zminj5ucw7w0r65bP6nhyOd3xL6veAUMc3ElGMoLVb4= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.23 h1:A2w6m6Tmr+BNXjDsr7M90zkWjsu4JXHwrzPg235STs4= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.23/go.mod h1:35EVp9wyeANdujZruvHiQUAo9E3vbhnIO1mTCAxMlY0= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.23 h1:pgYW9FCabt2M25MoHYCfMrVY2ghiiBKYWUVXfwZs+sU= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.23/go.mod h1:c48kLgzO19wAu3CPkDWC28JbaJ+hfQlsdl7I2+oqIbk= 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= @@ -147,16 +147,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.12.0 h1:TToQNkvGguu209puTojY/ozlqy2d/SFNcoLIqTFi42g= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0/go.mod h1:0jp+ltwkf+SwG2fm/PKo8t4y8pJSgOCO4D8Lz3k0aHQ= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.3 h1:qcxX0JYlgWH3hpPUnd6U0ikcl6LLA9sLkXE2w1fpMvY= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.3/go.mod h1:cLSNEmI45soc+Ef8K/L+8sEA3A3pYFEYf5B5UI+6bH4= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.4 h1:tHxQi/XHPK0ctd/wdOw0t7Xrc2OxcRCnVzv8lwWPu0c= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.4/go.mod h1:4GQbF1vJzG60poZqWatZlhP31y8PGCCVTvIGPdaaYJ0= 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.24.3 h1:UTpsIf0loCIWEbrqdLb+0RxnTXfWh2vhw4nQmFi4nPc= -github.com/aws/aws-sdk-go-v2/service/sso v1.24.3/go.mod h1:FZ9j3PFHHAR+w0BSEjK955w5YD2UwB/l/H0yAK3MJvI= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.3 h1:2YCmIXv3tmiItw0LlYf6v7gEHebLY45kBEnPezbUKyU= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.3/go.mod h1:u19stRyNPxGhj6dRm+Cdgu6N75qnbW7+QN0q0dsAk58= -github.com/aws/aws-sdk-go-v2/service/sts v1.32.3 h1:wVnQ6tigGsRqSWDEEyH6lSAJ9OyFUsSnbaUWChuSGzs= -github.com/aws/aws-sdk-go-v2/service/sts v1.32.3/go.mod h1:VZa9yTFyj4o10YGsmDO4gbQJUvvhY72fhumT8W4LqsE= +github.com/aws/aws-sdk-go-v2/service/sso v1.24.5 h1:HJwZwRt2Z2Tdec+m+fPjvdmkq2s9Ra+VR0hjF7V2o40= +github.com/aws/aws-sdk-go-v2/service/sso v1.24.5/go.mod h1:wrMCEwjFPms+V86TCQQeOxQF/If4vT44FGIOFiMC2ck= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.4 h1:zcx9LiGWZ6i6pjdcoE9oXAB6mUdeyC36Ia/QEiIvYdg= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.4/go.mod h1:Tp/ly1cTjRLGBBmNccFumbZ8oqpZlpdhFf80SrRh4is= +github.com/aws/aws-sdk-go-v2/service/sts v1.32.4 h1:yDxvkz3/uOKfxnv8YhzOi9m+2OGIxF+on3KOISbK5IU= +github.com/aws/aws-sdk-go-v2/service/sts v1.32.4/go.mod h1:9XEUty5v5UAsMiFOBJrNibZgwCeOma73jgGwwhgffa8= github.com/aws/smithy-go v1.22.0 h1:uunKnWlcoL3zO7q+gG2Pk53joueEOsnNB28QdMsmiMM= github.com/aws/smithy-go v1.22.0/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= From ddc3853ba424738c3d1611248630e297e44914cd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Nov 2024 07:05:43 +0000 Subject: [PATCH 36/62] chore: Bump golang from `0ca97f4` to `4cfe4a9` in /httpserver (#1925) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- httpserver/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httpserver/Dockerfile b/httpserver/Dockerfile index dcdee6b18..87cdeacec 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:0ca97f4ab335f4b284a5b8190980c7cdc21d320d529f2b643e8a8733a69bfb6b as builder +FROM --platform=$BUILDPLATFORM golang:1.22@sha256:4cfe4a9a7ff5817f93e70bcc016ea269401290ec9bd9509b4f0a2dd553640944 as builder ARG TARGETPLATFORM ARG TARGETOS From e73d4f5431ca60bead7d47085d80c2b3f6252ebc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 13 Nov 2024 08:22:08 +0000 Subject: [PATCH 37/62] chore: Bump github/codeql-action from 3.27.1 to 3.27.3 (#1926) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/codeql.yml | 4 ++-- .github/workflows/scorecards.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 5de96664f..edbb6eea1 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -37,7 +37,7 @@ jobs: with: go-version: "1.22" - name: Initialize CodeQL - uses: github/codeql-action/init@4f3212b61783c3c68e8309a0f18a699764811cda # tag=v3.27.1 + uses: github/codeql-action/init@396bb3e45325a47dd9ef434068033c6d5bb0d11a # tag=v3.27.3 with: languages: go - name: Run tidy @@ -45,4 +45,4 @@ jobs: - name: Build CLI run: make build - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@4f3212b61783c3c68e8309a0f18a699764811cda # tag=v3.27.1 + uses: github/codeql-action/analyze@396bb3e45325a47dd9ef434068033c6d5bb0d11a # tag=v3.27.3 diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 90785643a..261490912 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -55,6 +55,6 @@ jobs: retention-days: 5 - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@4f3212b61783c3c68e8309a0f18a699764811cda # tag=v3.27.1 + uses: github/codeql-action/upload-sarif@396bb3e45325a47dd9ef434068033c6d5bb0d11a # tag=v3.27.3 with: sarif_file: results.sarif From 0837c02e8325c20eeac8da9400d54207d330f898 Mon Sep 17 00:00:00 2001 From: DahuK Date: Thu, 14 Nov 2024 21:08:07 +0800 Subject: [PATCH 38/62] feat: support alibaba cloud rrsa store auth provider (#1909) Signed-off-by: dahu.kdh --- charts/ratify/README.md | 7 +- charts/ratify/templates/store.yaml | 7 + charts/ratify/values.yaml | 6 + errors/errors.go | 7 + go.mod | 11 +- go.sum | 45 +++- .../alibabacloud/alibabacloudacrbasic.go | 211 ++++++++++++++++++ .../alibabacloud/alibabacloudacrbasic_test.go | 205 +++++++++++++++++ .../oras/authprovider/alibabacloud/helper.go | 54 +++++ .../authprovider/alibabacloud/helper_test.go | 60 +++++ .../oras/authprovider/authproviderfactory.go | 1 - pkg/referrerstore/oras/oras.go | 17 +- 12 files changed, 612 insertions(+), 19 deletions(-) create mode 100644 pkg/common/oras/authprovider/alibabacloud/alibabacloudacrbasic.go create mode 100644 pkg/common/oras/authprovider/alibabacloud/alibabacloudacrbasic_test.go create mode 100644 pkg/common/oras/authprovider/alibabacloud/helper.go create mode 100644 pkg/common/oras/authprovider/alibabacloud/helper_test.go diff --git a/charts/ratify/README.md b/charts/ratify/README.md index 7b79647bf..7dc6ee02d 100644 --- a/charts/ratify/README.md +++ b/charts/ratify/README.md @@ -93,6 +93,7 @@ Values marked `# DEPRECATED` in the `values.yaml` as well as **DEPRECATED** in t | oras.authProviders.awsApiOverride.endpoint | Overrides ECR endpoint | `` | | oras.authProviders.awsApiOverride.partition | Overrides ECR partition in the endpoint URL | `aws` | | oras.authProviders.awsApiOverride.region | Overrides ECR region in the endpoint URL | `` | +| oras.authProviders.alibabacloudAcrBasicEnabled | Enables Alibaba Cloud ACR basic authentication provider | `false` | | oras.cache.enabled | Enables ORAS store cache for ListReferrers and GetSubjectDescriptor. TTL-based cache may cause inconsistency between cache and data source. Please disable it if strong consistency is required.operations | `true` | | oras.cache.ttl | Sets the ttl for ORAS store in seconds. cache | `10` | | provider.tls.crt | Ratify server's tls public certificate | `` | @@ -138,8 +139,10 @@ Values marked `# DEPRECATED` in the `values.yaml` as well as **DEPRECATED** in t | azurekeyvault.vaultURI | Vault URI for Azure Key Vault | `` | | azurekeyvault.tenantId | Tenant ID of the configured Azure Key Vault resource | `` | | azurekeyvault.certificates | An array of certificate objects identified by `name` and `version` (optional) stored in Azure Key Vault | `[]` | -| azurekeyvault.keys | An array of key objects identified by `name` and `version` (optional) stored in Azure Key Vault | `[]` | -| azurekeyvault.refreshInterval | time duration to refresh the certificates/keys. Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". Example: 1h, 30m, 1h30m. If it's not set, the refresh functionality will be disabled. | `` | +| azurekeyvault.keys | An array of key objects identified by `name` and `version` (optional) stored in Azure Key Vault | `[]` | +| azurekeyvault.refreshInterval | time duration to refresh the certificates/keys. Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". Example: 1h, 30m, 1h30m. If it's not set, the refresh functionality will be disabled. | `` | +| alibabacloudAcrConfig.defaultInstanceId | Default instance ID of the Alibaba Cloud Registry where the target artifacts stored | `` | +| alibabacloudAcrConfig.acrInstancesConfig | When images need to be pulled from multiple instances of Aliababa Cloud Registry, the instanceName and instanceId of the instances need to be defined separately in the list, e.g. acrInstancesConfig:
- instanceName: name1
instanceId: cri-xxx1
- instanceName: name2
instanceId: cri-xxx2
| `[]` | | notationCert | **DEPRECATED** Please switch to `notationCerts` to specify an array of verification certificates. Public certificate/certificate chain used to create inline certstore used by Notation verifier. | `` | | akvCertConfig.enabled | **DEPRECATED** Please use `azurekeyvault.enabled` instead. Enables/disables Azure Key Vault certificate store. If you are using a custom chart, certificate store should be referenced through a Verifier CR. References in ConfigMap will not be correctly resolved. | `false` | | akvCertConfig.vaultURI | **DEPRECATED** Please use `azurekeyvault.vaultURI` instead. Vault URI for AKV configured | `` | diff --git a/charts/ratify/templates/store.yaml b/charts/ratify/templates/store.yaml index 665a75c73..07ec36a9b 100644 --- a/charts/ratify/templates/store.yaml +++ b/charts/ratify/templates/store.yaml @@ -34,6 +34,13 @@ spec: authProvider: name: awsEcrBasic {{- end }} + {{- if .Values.oras.authProviders.alibabacloudAcrBasicEnabled }} + authProvider: + name: alibabacloudAcrBasic + defaultInstanceId: {{ .Values.alibabacloudAcrConfig.defaultInstanceId }} + acrInstancesConfig: + {{- toYaml .Values.alibabacloudAcrConfig.acrInstancesConfig | nindent 8 }} + {{- end }} {{- if .Values.oras.cache.enabled }} cacheEnabled: true ttl: {{ .Values.oras.cache.ttl }} diff --git a/charts/ratify/values.yaml b/charts/ratify/values.yaml index c026ed4df..1b9cc4ba4 100644 --- a/charts/ratify/values.yaml +++ b/charts/ratify/values.yaml @@ -82,6 +82,10 @@ azurekeyvault: keys: [] refreshInterval: +alibabacloudAcrConfig: + defaultInstanceId: + acrInstancesConfig: [] + oras: useHttp: false authProviders: @@ -94,6 +98,8 @@ oras: endpoint: "" partition: "" # defaults to aws region: "" + alibabacloudAcrBasicEnabled: false + cache: # Please tune your cache parameters to get better performance on the Oras Store performance. enabled: true # ttl-based cache may cause inconsistency between cache and data source, please disable it if strong consistency is required. diff --git a/errors/errors.go b/errors/errors.go index 9305f795c..8fe451e77 100644 --- a/errors/errors.go +++ b/errors/errors.go @@ -132,4 +132,11 @@ var ( Message: "operation forbidden", Description: "The requested operation is forbidden. Please verify the permission to the requested resource.", }) + + // ErrorCodeConfigInvalid is returned if provided alibabacloud image is invalid. + ErrorCodeAlibabaCloudImageInvalid = Register("errcode", ErrorDescriptor{ + Value: "ALIBABACLOUD_IMAGE_INVALID", + Message: "image invalid", + Description: `Invalid Alibaba Cloud Registry image format. Please verify your image configuration.`, + }) ) diff --git a/go.mod b/go.mod index 396a408dc..dbad99c35 100644 --- a/go.mod +++ b/go.mod @@ -15,6 +15,11 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/containers/azcontainerregistry v0.2.2 github.com/Azure/go-autorest/autorest/to v0.4.0 github.com/AzureAD/microsoft-authentication-library-for-go v1.2.3 + github.com/alibabacloud-go/cr-20181201/v2 v2.5.0 + github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.10 + github.com/alibabacloud-go/tea v1.2.2 + github.com/alibabacloud-go/tea-utils/v2 v2.0.7 + github.com/aliyun/credentials-go v1.3.10 github.com/aws/aws-sdk-go-v2 v1.32.4 github.com/aws/aws-sdk-go-v2/config v1.27.43 github.com/aws/aws-sdk-go-v2/credentials v1.17.44 @@ -70,17 +75,15 @@ require ( github.com/ProtonMail/go-crypto v0.0.0-20230923063757-afb1ddc0824c // indirect github.com/ThalesIgnite/crypto11 v1.2.5 // indirect github.com/agnivade/levenshtein v1.1.1 // indirect - github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4 // indirect + github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 // indirect github.com/alibabacloud-go/cr-20160607 v1.0.1 // indirect github.com/alibabacloud-go/cr-20181201 v1.0.10 // indirect github.com/alibabacloud-go/darabonba-openapi v0.2.1 // indirect - github.com/alibabacloud-go/debug v1.0.0 // indirect + github.com/alibabacloud-go/debug v1.0.1 // indirect github.com/alibabacloud-go/endpoint-util v1.1.1 // indirect github.com/alibabacloud-go/openapi-util v0.1.0 // indirect - github.com/alibabacloud-go/tea v1.2.1 // indirect github.com/alibabacloud-go/tea-utils v1.4.5 // indirect github.com/alibabacloud-go/tea-xml v1.1.3 // indirect - github.com/aliyun/credentials-go v1.3.1 // indirect github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092 // indirect github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.23.7 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0 // indirect diff --git a/go.sum b/go.sum index a9f30e949..c7be23e9a 100644 --- a/go.sum +++ b/go.sum @@ -76,21 +76,40 @@ github.com/alessio/shellescape v1.4.1 h1:V7yhSDDn8LP4lc4jS8pFkt0zCnzVJlG5JXy9BVK github.com/alessio/shellescape v1.4.1/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30= github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI= github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= +github.com/alibabacloud-go/alibabacloud-gateway-pop v0.0.6 h1:eIf+iGJxdU4U9ypaUfbtOWCsZSbTb8AUHvyPrxu6mAA= +github.com/alibabacloud-go/alibabacloud-gateway-pop v0.0.6/go.mod h1:4EUIoxs/do24zMOGGqYVWgw0s9NtiylnJglOeEB5UJo= github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.2/go.mod h1:sCavSAvdzOjul4cEqeVtvlSaSScfNsTQ+46HwlTL1hc= -github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4 h1:iC9YFYKDGEy3n/FtqJnOkZsene9olVspKmkX5A2YBEo= github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4/go.mod h1:sCavSAvdzOjul4cEqeVtvlSaSScfNsTQ+46HwlTL1hc= +github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 h1:zE8vH9C7JiZLNJJQ5OwjU9mSi4T9ef9u3BURT6LCLC8= +github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5/go.mod h1:tWnyE9AjF8J8qqLk645oUmVUnFybApTQWklQmi5tY6g= github.com/alibabacloud-go/cr-20160607 v1.0.1 h1:WEnP1iPFKJU74ryUKh/YDPHoxMZawqlPajOymyNAkts= github.com/alibabacloud-go/cr-20160607 v1.0.1/go.mod h1:QHeKZtZ3F3FOE+/uIXCBAp8POwnUYekpLwr1dtQa5r0= github.com/alibabacloud-go/cr-20181201 v1.0.10 h1:B60f6S1imsgn2fgC6X6FrVNrONDrbCT0NwYhsJ0C9/c= github.com/alibabacloud-go/cr-20181201 v1.0.10/go.mod h1:VN9orB/w5G20FjytoSpZROqu9ZqxwycASmGqYUJSoDc= +github.com/alibabacloud-go/cr-20181201/v2 v2.5.0 h1:dfhfzCsgpkC72pAwWyHUwVcjj88UIVaEcQn5dzo+heM= +github.com/alibabacloud-go/cr-20181201/v2 v2.5.0/go.mod h1:z5UYK7JxXtSqPASUscH9EZYYcEpEl7bvijlGO/OMNSI= +github.com/alibabacloud-go/darabonba-array v0.1.0 h1:vR8s7b1fWAQIjEjWnuF0JiKsCvclSRTfDzZHTYqfufY= +github.com/alibabacloud-go/darabonba-array v0.1.0/go.mod h1:BLKxr0brnggqOJPqT09DFJ8g3fsDshapUD3C3aOEFaI= +github.com/alibabacloud-go/darabonba-encode-util v0.0.2 h1:1uJGrbsGEVqWcWxrS9MyC2NG0Ax+GpOM5gtupki31XE= +github.com/alibabacloud-go/darabonba-encode-util v0.0.2/go.mod h1:JiW9higWHYXm7F4PKuMgEUETNZasrDM6vqVr/Can7H8= +github.com/alibabacloud-go/darabonba-map v0.0.2 h1:qvPnGB4+dJbJIxOOfawxzF3hzMnIpjmafa0qOTp6udc= +github.com/alibabacloud-go/darabonba-map v0.0.2/go.mod h1:28AJaX8FOE/ym8OUFWga+MtEzBunJwQGceGQlvaPGPc= github.com/alibabacloud-go/darabonba-openapi v0.1.12/go.mod h1:sTAjsFJmVsmcVeklL9d9uDBlFsgl43wZ6jhI6BHqHqU= github.com/alibabacloud-go/darabonba-openapi v0.1.14/go.mod h1:w4CosR7O/kapCtEEMBm3JsQqWBU/CnZ2o0pHorsTWDI= github.com/alibabacloud-go/darabonba-openapi v0.2.1 h1:WyzxxKvhdVDlwpAMOHgAiCJ+NXa6g5ZWPFEzaK/ewwY= github.com/alibabacloud-go/darabonba-openapi v0.2.1/go.mod h1:zXOqLbpIqq543oioL9IuuZYOQgHQ5B8/n5OPrnko8aY= +github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.6/go.mod h1:CzQnh+94WDnJOnKZH5YRyouL+OOcdBnXY5VWAf0McgI= +github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.10 h1:GEYkMApgpKEVDn6z12DcH1EGYpDYRB8JxsazM4Rywak= +github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.10/go.mod h1:26a14FGhZVELuz2cc2AolvW4RHmIO3/HRwsdHhaIPDE= +github.com/alibabacloud-go/darabonba-signature-util v0.0.7 h1:UzCnKvsjPFzApvODDNEYqBHMFt1w98wC7FOo0InLyxg= +github.com/alibabacloud-go/darabonba-signature-util v0.0.7/go.mod h1:oUzCYV2fcCH797xKdL6BDH8ADIHlzrtKVjeRtunBNTQ= github.com/alibabacloud-go/darabonba-string v1.0.0/go.mod h1:93cTfV3vuPhhEwGGpKKqhVW4jLe7tDpo3LUM0i0g6mA= +github.com/alibabacloud-go/darabonba-string v1.0.2 h1:E714wms5ibdzCqGeYJ9JCFywE5nDyvIXIIQbZVFkkqo= +github.com/alibabacloud-go/darabonba-string v1.0.2/go.mod h1:93cTfV3vuPhhEwGGpKKqhVW4jLe7tDpo3LUM0i0g6mA= github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68/go.mod h1:6pb/Qy8c+lqua8cFpEy7g39NRRqOWc3rOwAy8m5Y2BY= -github.com/alibabacloud-go/debug v1.0.0 h1:3eIEQWfay1fB24PQIEzXAswlVJtdQok8f3EVN5VrBnA= github.com/alibabacloud-go/debug v1.0.0/go.mod h1:8gfgZCCAC3+SCzjWtY053FrOcd4/qlH6IHTI4QyICOc= +github.com/alibabacloud-go/debug v1.0.1 h1:MsW9SmUtbb1Fnt3ieC6NNZi6aEwrXfDksD4QA6GSbPg= +github.com/alibabacloud-go/debug v1.0.1/go.mod h1:8gfgZCCAC3+SCzjWtY053FrOcd4/qlH6IHTI4QyICOc= github.com/alibabacloud-go/endpoint-util v1.1.0/go.mod h1:O5FuCALmCKs2Ff7JFJMudHs0I5EBgecXXxZRyswlEjE= github.com/alibabacloud-go/endpoint-util v1.1.1 h1:ZkBv2/jnghxtU0p+upSU0GGzW1VL9GQdZO3mcSUTUy8= github.com/alibabacloud-go/endpoint-util v1.1.1/go.mod h1:O5FuCALmCKs2Ff7JFJMudHs0I5EBgecXXxZRyswlEjE= @@ -105,19 +124,27 @@ github.com/alibabacloud-go/tea v1.1.8/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeG github.com/alibabacloud-go/tea v1.1.11/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4= github.com/alibabacloud-go/tea v1.1.17/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A= github.com/alibabacloud-go/tea v1.1.19/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A= -github.com/alibabacloud-go/tea v1.2.1 h1:rFF1LnrAdhaiPmKwH5xwYOKlMh66CqRwPUTzIK74ask= +github.com/alibabacloud-go/tea v1.1.20/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A= github.com/alibabacloud-go/tea v1.2.1/go.mod h1:qbzof29bM/IFhLMtJPrgTGK3eauV5J2wSyEUo4OEmnA= +github.com/alibabacloud-go/tea v1.2.2 h1:aTsR6Rl3ANWPfqeQugPglfurloyBJY85eFy7Gc1+8oU= +github.com/alibabacloud-go/tea v1.2.2/go.mod h1:CF3vOzEMAG+bR4WOql8gc2G9H3EkH3ZLAQdpmpXMgwk= github.com/alibabacloud-go/tea-utils v1.3.1/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE= github.com/alibabacloud-go/tea-utils v1.3.9/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE= github.com/alibabacloud-go/tea-utils v1.4.3/go.mod h1:KNcT0oXlZZxOXINnZBs6YvgOd5aYp9U67G+E3R8fcQw= github.com/alibabacloud-go/tea-utils v1.4.5 h1:h0/6Xd2f3bPE4XHTvkpjwxowIwRCJAJOqY6Eq8f3zfA= github.com/alibabacloud-go/tea-utils v1.4.5/go.mod h1:KNcT0oXlZZxOXINnZBs6YvgOd5aYp9U67G+E3R8fcQw= +github.com/alibabacloud-go/tea-utils/v2 v2.0.5/go.mod h1:dL6vbUT35E4F4bFTHL845eUloqaerYBYPsdWR2/jhe4= +github.com/alibabacloud-go/tea-utils/v2 v2.0.6/go.mod h1:qxn986l+q33J5VkialKMqT/TTs3E+U9MJpd001iWQ9I= +github.com/alibabacloud-go/tea-utils/v2 v2.0.7 h1:WDx5qW3Xa5ZgJ1c8NfqJkF6w+AU5wB8835UdhPr6Ax0= +github.com/alibabacloud-go/tea-utils/v2 v2.0.7/go.mod h1:qxn986l+q33J5VkialKMqT/TTs3E+U9MJpd001iWQ9I= github.com/alibabacloud-go/tea-xml v1.1.2/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8= github.com/alibabacloud-go/tea-xml v1.1.3 h1:7LYnm+JbOq2B+T/B0fHC4Ies4/FofC4zHzYtqw7dgt0= github.com/alibabacloud-go/tea-xml v1.1.3/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8= github.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw= -github.com/aliyun/credentials-go v1.3.1 h1:uq/0v7kWrxmoLGpqjx7vtQ/s03f0zR//0br/xWDTE28= github.com/aliyun/credentials-go v1.3.1/go.mod h1:8jKYhQuDawt8x2+fusqa1Y6mPxemTsBEN04dgcAcYz0= +github.com/aliyun/credentials-go v1.3.6/go.mod h1:1LxUuX7L5YrZUWzBrRyk0SwSdH4OmPrib8NVePL3fxM= +github.com/aliyun/credentials-go v1.3.10 h1:45Xxrae/evfzQL9V10zL3xX31eqgLWEaIdCoPipOEQA= +github.com/aliyun/credentials-go v1.3.10/go.mod h1:Jm6d+xIgwJVLVWT561vy67ZRP4lPTQxMbEYRuT2Ti1U= github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092 h1:aM1rlcoLz8y5B2r4tTLMiVTrMtpfY0O8EScKJxaSaEc= github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092/go.mod h1:rYqSE9HbjzpHTI74vwPvae4ZVYZd1lue2ta6xHPdblA= github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo= @@ -781,7 +808,9 @@ golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2Uz golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= @@ -825,8 +854,11 @@ golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -872,7 +904,9 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= @@ -884,7 +918,9 @@ golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= +golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24= @@ -900,6 +936,7 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= diff --git a/pkg/common/oras/authprovider/alibabacloud/alibabacloudacrbasic.go b/pkg/common/oras/authprovider/alibabacloud/alibabacloudacrbasic.go new file mode 100644 index 000000000..780f839c0 --- /dev/null +++ b/pkg/common/oras/authprovider/alibabacloud/alibabacloudacrbasic.go @@ -0,0 +1,211 @@ +/* +Copyright The Ratify Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package alibabacloud + +import ( + "context" + "encoding/json" + "fmt" + "os" + "time" + + cr20181201 "github.com/alibabacloud-go/cr-20181201/v2/client" + openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client" + util "github.com/alibabacloud-go/tea-utils/v2/service" + "github.com/alibabacloud-go/tea/tea" + "github.com/aliyun/credentials-go/credentials" + re "github.com/ratify-project/ratify/errors" + + "github.com/pkg/errors" + provider "github.com/ratify-project/ratify/pkg/common/oras/authprovider" + "github.com/sirupsen/logrus" +) + +const ( + EnvRoleArn = "ALIBABA_CLOUD_ROLE_ARN" + EnvOidcProviderArn = "ALIBABA_CLOUD_OIDC_PROVIDER_ARN" + EnvOidcTokenFile = "ALIBABA_CLOUD_OIDC_TOKEN_FILE" + AlibabaCloudACREndpoint = "cr.%s.aliyuncs.com" +) + +type AlibabaCloudAcrBasicProviderFactory struct{} //nolint:revive // ignore linter to have unique type name + +type acrInstancesConfig struct { + InstanceName string `json:"instanceName"` + InstanceID string `json:"instanceId"` +} + +type alibabacloudAcrBasicAuthProvider struct { + acrInstancesConfig map[string]string + providerName string + getAcrAuthToken AcrAuthTokenGetter +} + +type alibabacloudAcrBasicAuthProviderConf struct { + Name string `json:"name"` + DefaultInstanceID string `json:"defaultInstanceId"` + AcrInstancesConfig []acrInstancesConfig `json:"acrInstancesConfig,omitempty"` +} + +const ( + alibabacloudAcrAuthProviderName = "alibabacloudAcrBasic" +) + +// init calls Register for AlibabaCloud RRSA Basic Auth provider +func init() { + provider.Register(alibabacloudAcrAuthProviderName, &AlibabaCloudAcrBasicProviderFactory{}) +} + +// AcrAuthTokenGetter defines an interface for getting acr authentication token. +type AcrAuthTokenGetter interface { + GetAcrAuthToken(artifact string, acrInstanceConfig map[string]string) (*cr20181201.GetAuthorizationTokenResponseBody, error) +} + +// defaultAcrAuthTokenGetterImpl is the default implementation of getAcrAuthToken. +type defaultAcrAuthTokenGetterImpl struct{} + +func (g *defaultAcrAuthTokenGetterImpl) GetAcrAuthToken(artifact string, acrInstanceConfig map[string]string) (*cr20181201.GetAuthorizationTokenResponseBody, error) { + return getAcrAuthToken(artifact, acrInstanceConfig) +} + +// Get ACR auth token from RRSA config +func getAcrAuthToken(artifact string, acrInstanceConfig map[string]string) (*cr20181201.GetAuthorizationTokenResponseBody, error) { + // Verify RRSA ENV is present + + envRoleArn := os.Getenv(EnvRoleArn) + envOidcProviderArn := os.Getenv(EnvOidcProviderArn) + envOidcTokenFile := os.Getenv(EnvOidcTokenFile) + + if envRoleArn == "" || envOidcProviderArn == "" || envOidcTokenFile == "" { + return nil, fmt.Errorf("required environment variables not set, ALIBABA_CLOUD_ROLE_ARN: %s, ALIBABA_CLOUD_OIDC_PROVIDER_ARN: %s, ALIBABA_CLOUD_OIDC_TOKEN_FILE: %s", envRoleArn, envOidcProviderArn, envOidcTokenFile) + } + + // registry/region from image + registry, err := provider.GetRegistryHostName(artifact) + if err != nil { + return nil, fmt.Errorf("failed to get registry from image: %w", err) + } + registryMetaInfo, err := getRegionFromArtifact(registry) + if err != nil || registryMetaInfo.Region == "" { + return nil, err + } + region := registryMetaInfo.Region + instanceName := registryMetaInfo.InstanceName + logrus.Infof("Alibaba Cloud ACR basic artifact=%s, registry=%s, region=%s, instance=%s", artifact, registry, region, instanceName) + + cred, err := credentials.NewCredential(nil) + if err != nil { + return nil, fmt.Errorf("failed to init alibaba cloud sdk credential: %w", err) + } + config := &openapi.Config{ + Credential: cred, + } + instanceID := acrInstanceConfig[defaultInstance] + if insID, ok := acrInstanceConfig[instanceName]; ok { + instanceID = insID + } + if instanceID == "" { + return nil, fmt.Errorf("no instance id found for the given artifact") + } + // Endpoint refer to https://help.aliyun.com/zh/acr/developer-reference/api-cr-2018-12-01-endpoint + config.Endpoint = tea.String(fmt.Sprintf(AlibabaCloudACREndpoint, region)) + config.RegionId = tea.String(region) + crClient, err := cr20181201.NewClient(config) + if err != nil { + return nil, fmt.Errorf("failed to init alibaba cloud acr client: %w", err) + } + + getAuthorizationTokenRequest := &cr20181201.GetAuthorizationTokenRequest{} + getAuthorizationTokenRequest.InstanceId = tea.String(instanceID) + runtime := &util.RuntimeOptions{} + + tokenResponse, err := crClient.GetAuthorizationTokenWithOptions(getAuthorizationTokenRequest, runtime) + if err != nil || tokenResponse.Body == nil { + return nil, fmt.Errorf("failed to get acr authorization token: %w", err) + } + return tokenResponse.Body, nil +} + +// Create returns an Alibaba CloudAcrBasicProvider +func (d *AlibabaCloudAcrBasicProviderFactory) Create(authProviderConfig provider.AuthProviderConfig) (provider.AuthProvider, error) { + conf := alibabacloudAcrBasicAuthProviderConf{} + authProviderConfigBytes, err := json.Marshal(authProviderConfig) + if err != nil { + return nil, re.ErrorCodeConfigInvalid.WithError(err).WithComponentType(re.AuthProvider) + } + + if err = json.Unmarshal(authProviderConfigBytes, &conf); err != nil { + return nil, re.ErrorCodeConfigInvalid.NewError(re.AuthProvider, alibabacloudAcrAuthProviderName, re.AuthProviderLink, err, "failed to parse alibaba cloud auth provider configuration", re.HideStackTrace) + } + var acrInstancesConfig = make(map[string]string, 0) + if len(conf.AcrInstancesConfig) > 0 { + for _, ic := range conf.AcrInstancesConfig { + acrInstancesConfig[ic.InstanceName] = ic.InstanceID + } + } + //get ACR EE instance id + instanceID := conf.DefaultInstanceID + if instanceID == "" { + instanceID = os.Getenv("ALIBABA_CLOUD_ACR_INSTANCE_ID") + if instanceID == "" && len(acrInstancesConfig) == 0 { + return nil, re.ErrorCodeEnvNotSet.WithComponentType(re.AuthProvider).WithDetail("no instance ID provided and ALIBABA_CLOUD_ACR_INSTANCE_ID environment variable is empty") + } + } + acrInstancesConfig[defaultInstance] = instanceID + + return &alibabacloudAcrBasicAuthProvider{ + acrInstancesConfig: acrInstancesConfig, + providerName: alibabacloudAcrAuthProviderName, + getAcrAuthToken: &defaultAcrAuthTokenGetterImpl{}, + }, nil +} + +// Enabled checks for non-empty AlibabaCloud RAM creds +func (d *alibabacloudAcrBasicAuthProvider) Enabled(_ context.Context) bool { + if d.providerName == "" { + logrus.Error("basic Alibaba Cloud ACR providerName was empty") + return false + } + + return true +} + +// Provide returns the credentials for a specified artifact. +// Uses AlibabaCloud RRSA to retrieve creds from RRSA credential chain +func (d *alibabacloudAcrBasicAuthProvider) Provide(ctx context.Context, artifact string) (provider.AuthConfig, error) { + if !d.Enabled(ctx) { + return provider.AuthConfig{}, re.ErrorCodeConfigInvalid.WithComponentType(re.AuthProvider).WithDetail("Alibaba Cloud RRSA basic auth provider is not properly enabled") + } + + // need to first creat or refresh AlibabaCloud ACR credentials + authToken, err := d.getAcrAuthToken.GetAcrAuthToken(artifact, d.acrInstancesConfig) + if err != nil { + return provider.AuthConfig{}, errors.Wrapf(err, "could not get ACR auth token for %s", artifact) + } + logrus.Debugf("successfully refreshed ACR auth token for %s", artifact) + + // Get ACR basic auth creds from AuthData response + tmpUsr := tea.StringValue(authToken.TempUsername) + passwd := tea.StringValue(authToken.AuthorizationToken) + authConfig := provider.AuthConfig{ + Username: tmpUsr, + Password: passwd, + Provider: d, + ExpiresOn: time.UnixMilli(tea.Int64Value(authToken.ExpireTime)), + } + + return authConfig, nil +} diff --git a/pkg/common/oras/authprovider/alibabacloud/alibabacloudacrbasic_test.go b/pkg/common/oras/authprovider/alibabacloud/alibabacloudacrbasic_test.go new file mode 100644 index 000000000..fb4293b97 --- /dev/null +++ b/pkg/common/oras/authprovider/alibabacloud/alibabacloudacrbasic_test.go @@ -0,0 +1,205 @@ +/* +Copyright The Ratify Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package alibabacloud + +import ( + "context" + "os" + "testing" + + cr20181201 "github.com/alibabacloud-go/cr-20181201/v2/client" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +const ( + // #nosec G101 (Ref: https://github.com/securego/gosec/issues/295) + testPassword = "eyJwYXlsb2FkIjoiOThPNTFqemhaUmZWVG" + testUserMeta = `{"instanceId":"cri-xxxxxxx","time":"1730185474000","type":"user","userId":"123456"}` + testHost = "test-registry.cn-hangzhou.cr.aliyuncs.com" + testInvalidHost = "http://test-registry.cn-hangzhou.cr.aliyuncs.com" + testArtifact = testHost + "/foo:latest" + testArtifactWithoutRegion = "test-registry-vpc.cr.aliyuncs.com/foo/test:latest" + testInstanceID = "cri-testing" +) + +// Mock types for external dependencies +type MockAlibabaCloudAcrAuthTokenGetter struct { + mock.Mock +} + +// Mock AlibabaCloudAcrAuthTokenGetter.GetAcrAuthToken +func (m *MockAlibabaCloudAcrAuthTokenGetter) GetAcrAuthToken(artifact string, acrInstanceConfig map[string]string) (*cr20181201.GetAuthorizationTokenResponseBody, error) { + args := m.Called(artifact, acrInstanceConfig) + return args.Get(0).(*cr20181201.GetAuthorizationTokenResponseBody), args.Error(1) +} + +// Verifies that alibabacloudAcrBasicAuthProvider is properly constructed by mocking AcrAuthToken +func mockAuthProvider() alibabacloudAcrBasicAuthProvider { + // Setup + return alibabacloudAcrBasicAuthProvider{ + providerName: alibabacloudAcrAuthProviderName, + } +} + +func TestAlibabaCloudAcrBasicAuthProvider_Create(t *testing.T) { + authProviderConfig := map[string]interface{}{ + "name": "alibabacloudAcrBasic", + "defaultInstanceId": testInstanceID, + } + + factory := AlibabaCloudAcrBasicProviderFactory{} + _, err := factory.Create(authProviderConfig) + + if err != nil { + t.Fatalf("create failed %v", err) + } +} + +func TestAlibabaCloudAcrBasicAuthProvider_CreateWithoutInstanceId(t *testing.T) { + authProviderConfig := map[string]interface{}{ + "name": "alibabacloudAcrBasic", + } + factory := AlibabaCloudAcrBasicProviderFactory{} + _, err := factory.Create(authProviderConfig) + assert.Error(t, err) +} + +func TestAlibabaCloudAcrBasicAuthProvider_CreateWithInvalidProviderConfig(t *testing.T) { + authProviderConfig := map[string]interface{}{ + "name": 000, + "invalid": "test", + } + factory := AlibabaCloudAcrBasicProviderFactory{} + _, err := factory.Create(authProviderConfig) + assert.Error(t, err) +} + +func TestAlibabaCloudAcrBasicAuthProvider_CreateWithMultiProviderConfig(t *testing.T) { + ic1 := acrInstancesConfig{ + InstanceID: "cri-testing1", + InstanceName: "test-instance-1", + } + ic2 := acrInstancesConfig{ + InstanceID: "cri-testing2", + InstanceName: "test-instance-2", + } + authProviderConfig := map[string]interface{}{ + "name": "alibabacloudAcrBasic", + "acrInstancesConfig": []acrInstancesConfig{ic1, ic2}, + } + factory := AlibabaCloudAcrBasicProviderFactory{} + _, err := factory.Create(authProviderConfig) + assert.NoError(t, err) +} + +func TestAlibabaCloudAcrBasicAuthProvider_Enabled(t *testing.T) { + authProvider := mockAuthProvider() + + ctx := context.Background() + + if !authProvider.Enabled(ctx) { + t.Fatal("enabled should have returned true but returned false") + } + + authProvider.providerName = "" + if authProvider.Enabled(ctx) { + t.Fatal("enabled should have returned false but returned true") + } +} + +func TestAlibabaCloudAcrBasicAuthProvider_ProvidesNotEnabled(t *testing.T) { + authProvider := alibabacloudAcrBasicAuthProvider{ + providerName: "", + } + _, err := authProvider.Provide(context.TODO(), testInvalidHost) + assert.Error(t, err) +} + +func TestAlibabaCloudAcrBasicAuthProvider_GetAuthTokenWithoutRRSAEnv(t *testing.T) { + acrInstancesConfig := make(map[string]string, 0) + _, err := getAcrAuthToken(testArtifactWithoutRegion, acrInstancesConfig) + assert.Error(t, err) + + expectedMessage := "required environment variables not set, ALIBABA_CLOUD_ROLE_ARN: , ALIBABA_CLOUD_OIDC_PROVIDER_ARN: , ALIBABA_CLOUD_OIDC_TOKEN_FILE: " + if err.Error() != expectedMessage { + t.Fatalf("expected message: %s, instead got error: %s", expectedMessage, err.Error()) + } +} + +func TestAlibabaCloudAcrBasicAuthProvider_GetAuthTokenWithInvalidHost(t *testing.T) { + os.Setenv("ALIBABA_CLOUD_OIDC_PROVIDER_ARN", "placeholder") + os.Setenv("ALIBABA_CLOUD_ROLE_ARN", "placeholder") + os.Setenv("ALIBABA_CLOUD_OIDC_TOKEN_FILE", "placeholder") + acrInstancesConfig := map[string]string{ + "test": testInstanceID, + } + _, err := getAcrAuthToken(testInvalidHost, acrInstancesConfig) + assert.Error(t, err) +} + +func TestAlibabaCloudAcrBasicAuthProvider_GetAuthTokenWithoutRegion(t *testing.T) { + os.Setenv("ALIBABA_CLOUD_OIDC_PROVIDER_ARN", "placeholder") + os.Setenv("ALIBABA_CLOUD_ROLE_ARN", "placeholder") + os.Setenv("ALIBABA_CLOUD_OIDC_TOKEN_FILE", "placeholder") + acrInstancesConfig := make(map[string]string, 0) + _, err := getAcrAuthToken(testArtifactWithoutRegion, acrInstancesConfig) + assert.Error(t, err) + + expectedMessage := "ALIBABACLOUD_IMAGE_INVALID: Invalid Alibaba Cloud Registry image format" + if err.Error() != expectedMessage { + t.Fatalf("expected message: %s, instead got error: %s", expectedMessage, err.Error()) + } +} + +func TestAlibabaCloudAcrBasicAuthProvider_GetAuthTokenWithInvalidInstanceId(t *testing.T) { + os.Setenv("ALIBABA_CLOUD_OIDC_PROVIDER_ARN", "placeholder") + os.Setenv("ALIBABA_CLOUD_ROLE_ARN", "placeholder") + os.Setenv("ALIBABA_CLOUD_OIDC_TOKEN_FILE", "placeholder") + acrInstancesConfig := map[string]string{ + "testInvalid": testInstanceID, + } + _, err := getAcrAuthToken(testHost, acrInstancesConfig) + assert.Error(t, err) +} + +func TestAlibabaCloudAcrBasicAuthProvider_GetAuthTokenWithInvalidAcrClient(t *testing.T) { + os.Setenv("ALIBABA_CLOUD_OIDC_PROVIDER_ARN", "placeholder") + os.Setenv("ALIBABA_CLOUD_ROLE_ARN", "placeholder") + os.Setenv("ALIBABA_CLOUD_OIDC_TOKEN_FILE", "placeholder") + acrInstancesConfig := map[string]string{ + "test": testInstanceID, + } + _, err := getAcrAuthToken(testHost, acrInstancesConfig) + assert.Error(t, err) +} + +func TestAlibabaCloudAcrBasicAuthProvider_Provide_TokenRefreshSuccess(t *testing.T) { + mockAlibabaCloudAcrAuthTokenGetter := new(MockAlibabaCloudAcrAuthTokenGetter) + mockACRToken := cr20181201.GetAuthorizationTokenResponseBody{} + mockAlibabaCloudAcrAuthTokenGetter.On("GetAcrAuthToken", "mockartifact", mock.Anything).Return(&mockACRToken, nil) + + authProvider := alibabacloudAcrBasicAuthProvider{ + providerName: alibabacloudAcrAuthProviderName, + getAcrAuthToken: mockAlibabaCloudAcrAuthTokenGetter, + } + + ctx := context.Background() + _, err := authProvider.Provide(ctx, "mockartifact") + + // Validate success and token refresh + assert.NoError(t, err) +} diff --git a/pkg/common/oras/authprovider/alibabacloud/helper.go b/pkg/common/oras/authprovider/alibabacloud/helper.go new file mode 100644 index 000000000..acf225592 --- /dev/null +++ b/pkg/common/oras/authprovider/alibabacloud/helper.go @@ -0,0 +1,54 @@ +/* +Copyright The Ratify Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package alibabacloud + +import ( + "fmt" + "regexp" + "strings" + + re "github.com/ratify-project/ratify/errors" +) + +const ( + acrNameSuffix = ".aliyuncs.com" + defaultInstance = "defaultInstance" +) + +// examples of valid Alibaba Cloud Registry images: +// test-registry-vpc.cn-hangzhou.cr.aliyuncs.com +// test-registry.cn-hangzhou.cr.aliyuncs.com +var domainPattern = regexp.MustCompile( + `^(?:(?P[^.\s]+)-)?registry(?:-intl)?(?:-vpc)?(?:-internal)?(?:\.distributed)?\.(?P[^.]+\-[^.]+)\.(?:cr\.)?aliyuncs\.com`) + +type AcrMetaInfo struct { + InstanceName string + Region string +} + +func getRegionFromArtifact(artifact string) (*AcrMetaInfo, error) { + if !strings.HasSuffix(artifact, acrNameSuffix) { + return nil, re.ErrorCodeAlibabaCloudImageInvalid.WithComponentType(re.AuthProvider).WithDetail(fmt.Sprintf("Invalid Alibaba Cloud Registry image %s which does not end with `aliyuncs.com`", artifact)) + } + subItems := domainPattern.FindStringSubmatch(artifact) + if len(subItems) != 3 { + return nil, re.ErrorCodeAlibabaCloudImageInvalid.WithComponentType(re.AuthProvider).WithDetail("Invalid Alibaba Cloud Registry image format") + } + return &AcrMetaInfo{ + InstanceName: subItems[1], + Region: subItems[2], + }, nil +} diff --git a/pkg/common/oras/authprovider/alibabacloud/helper_test.go b/pkg/common/oras/authprovider/alibabacloud/helper_test.go new file mode 100644 index 000000000..fe6ef78f6 --- /dev/null +++ b/pkg/common/oras/authprovider/alibabacloud/helper_test.go @@ -0,0 +1,60 @@ +/* +Copyright The Ratify Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package alibabacloud + +import ( + "reflect" + "testing" +) + +func Test_getRegionFromArtifict(t *testing.T) { + type args struct { + artifact string + } + arg1 := "dahu-registry-vpc.cn-hangzhou.cr.aliyuncs.com" + arg2 := "registry-vpc.cn-beijing.aliyuncs.com" + arg3 := "test.bad" + arg4 := "registry-vpc.cr.aliyuncs.com" + + tests := []struct { + name string + args args + want *AcrMetaInfo + wantErr bool + }{ + {"mock-test-get-region-from-artifict-1", args{arg1}, &AcrMetaInfo{ + InstanceName: "dahu", + Region: "cn-hangzhou", + }, false}, + {"mock-test-get-region-from-artifict-2", args{arg2}, &AcrMetaInfo{ + Region: "cn-beijing", + }, false}, + {"mock-test-get-region-from-artifict-3", args{arg3}, nil, true}, + {"mock-test-get-region-from-artifict-4", args{arg4}, nil, true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := getRegionFromArtifact(tt.args.artifact) + if (err != nil) != tt.wantErr { + t.Errorf("getRegionFromArtifict() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("getRegionFromArtifict() got = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/pkg/common/oras/authprovider/authproviderfactory.go b/pkg/common/oras/authprovider/authproviderfactory.go index 08bde422c..d641bdae2 100644 --- a/pkg/common/oras/authprovider/authproviderfactory.go +++ b/pkg/common/oras/authprovider/authproviderfactory.go @@ -38,7 +38,6 @@ func Register(name string, factory AuthProviderFactory) { if registered { panic(fmt.Sprintf("auth provider factory named %s already registered", name)) } - builtInAuthProviders[name] = factory } diff --git a/pkg/referrerstore/oras/oras.go b/pkg/referrerstore/oras/oras.go index 64679dd0a..48f1dc061 100644 --- a/pkg/referrerstore/oras/oras.go +++ b/pkg/referrerstore/oras/oras.go @@ -45,8 +45,9 @@ import ( "github.com/ratify-project/ratify/pkg/cache" "github.com/ratify-project/ratify/pkg/common" "github.com/ratify-project/ratify/pkg/common/oras/authprovider" - _ "github.com/ratify-project/ratify/pkg/common/oras/authprovider/aws" // register aws auth provider - _ "github.com/ratify-project/ratify/pkg/common/oras/authprovider/azure" // register azure auth provider + _ "github.com/ratify-project/ratify/pkg/common/oras/authprovider/alibabacloud" // register alibabacloud auth provider + _ "github.com/ratify-project/ratify/pkg/common/oras/authprovider/aws" // register aws auth provider + _ "github.com/ratify-project/ratify/pkg/common/oras/authprovider/azure" // register azure auth provider commonutils "github.com/ratify-project/ratify/pkg/common/utils" "github.com/ratify-project/ratify/pkg/homedir" "github.com/ratify-project/ratify/pkg/metrics" @@ -57,12 +58,12 @@ import ( ) const ( - HTTPMaxIdleConns = 100 - HTTPMaxConnsPerHost = 100 - HTTPMaxIdleConnsPerHost = 100 - HTTPRetryMax = 5 - HTTPRetryDurationMinimum time.Duration = 200 * time.Millisecond - HTTPRetryDurationMax time.Duration = 1750 * time.Millisecond + HTTPMaxIdleConns = 100 + HTTPMaxConnsPerHost = 100 + HTTPMaxIdleConnsPerHost = 100 + HTTPRetryMax = 5 + HTTPRetryDurationMinimum = 200 * time.Millisecond + HTTPRetryDurationMax = 1750 * time.Millisecond ) const ( From 14f75c9b6fa1d4bd7d0575952014b2325a3cb59e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Nov 2024 09:31:34 +0800 Subject: [PATCH 39/62] chore: Bump github/codeql-action from 3.27.3 to 3.27.4 (#1929) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/codeql.yml | 4 ++-- .github/workflows/scorecards.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index edbb6eea1..1c826c942 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -37,7 +37,7 @@ jobs: with: go-version: "1.22" - name: Initialize CodeQL - uses: github/codeql-action/init@396bb3e45325a47dd9ef434068033c6d5bb0d11a # tag=v3.27.3 + uses: github/codeql-action/init@ea9e4e37992a54ee68a9622e985e60c8e8f12d9f # tag=v3.27.4 with: languages: go - name: Run tidy @@ -45,4 +45,4 @@ jobs: - name: Build CLI run: make build - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@396bb3e45325a47dd9ef434068033c6d5bb0d11a # tag=v3.27.3 + uses: github/codeql-action/analyze@ea9e4e37992a54ee68a9622e985e60c8e8f12d9f # tag=v3.27.4 diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 261490912..cbcc0e24b 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -55,6 +55,6 @@ jobs: retention-days: 5 - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@396bb3e45325a47dd9ef434068033c6d5bb0d11a # tag=v3.27.3 + uses: github/codeql-action/upload-sarif@ea9e4e37992a54ee68a9622e985e60c8e8f12d9f # tag=v3.27.4 with: sarif_file: results.sarif From 7e6e96c8b487cb8ea3190711bfdffa63ff85a131 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Nov 2024 15:39:33 +0800 Subject: [PATCH 40/62] chore: Bump alpine from `beefdbd` to `1e42bbe` (#1937) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- crd.Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crd.Dockerfile b/crd.Dockerfile index 6606aa0af..2854204e6 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:beefdbd8a1da6d2915566fde36db9db0b524eb737fc57cd1367effd16dc0d06d as builder +FROM alpine@sha256:1e42bbe2508154c9126d48c2b8a75420c3544343bf86fd041fb7527e017a4b4a as builder ARG TARGETOS ARG TARGETARCH From 2b789f3fd5215b12b133eabd02fc4b4d544557d5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Nov 2024 16:21:18 +0800 Subject: [PATCH 41/62] chore: Bump golang from `4cfe4a9` to `147f428` in /httpserver (#1936) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- httpserver/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httpserver/Dockerfile b/httpserver/Dockerfile index 87cdeacec..80603641e 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:4cfe4a9a7ff5817f93e70bcc016ea269401290ec9bd9509b4f0a2dd553640944 as builder +FROM --platform=$BUILDPLATFORM golang:1.22@sha256:147f428a24c6b80b8afbdaec7f245b9e7ac342601e3aeaffb321a103b7c6b3f4 as builder ARG TARGETPLATFORM ARG TARGETOS From d350f5c329072a9fbf5ea1afdc08846cd075076a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Nov 2024 08:48:41 +0000 Subject: [PATCH 42/62] chore: Bump distroless/static from `3a03fc0` to `d71f4b2` in /httpserver (#1935) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- httpserver/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httpserver/Dockerfile b/httpserver/Dockerfile index 80603641e..9cdc65df9 100644 --- a/httpserver/Dockerfile +++ b/httpserver/Dockerfile @@ -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:3a03fc0826340c7deb82d4755ca391bef5adcedb8892e58412e1a6008199fa91 +FROM gcr.io/distroless/static:nonroot@sha256:d71f4b239be2d412017b798a0a401c44c3049a3ca454838473a4c32ed076bfea LABEL org.opencontainers.image.source https://github.com/ratify-project/ratify ARG RATIFY_FOLDER=$HOME/.ratify/ From 0948848e4351199c0e50aeea21ca62f0b889245d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Nov 2024 22:47:24 +0800 Subject: [PATCH 43/62] chore: Bump github.com/aliyun/credentials-go from 1.3.10 to 1.3.11 (#1934) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index dbad99c35..28f7a64b8 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.10 github.com/alibabacloud-go/tea v1.2.2 github.com/alibabacloud-go/tea-utils/v2 v2.0.7 - github.com/aliyun/credentials-go v1.3.10 + github.com/aliyun/credentials-go v1.3.11 github.com/aws/aws-sdk-go-v2 v1.32.4 github.com/aws/aws-sdk-go-v2/config v1.27.43 github.com/aws/aws-sdk-go-v2/credentials v1.17.44 diff --git a/go.sum b/go.sum index c7be23e9a..d343ae30c 100644 --- a/go.sum +++ b/go.sum @@ -143,8 +143,9 @@ github.com/alibabacloud-go/tea-xml v1.1.3/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCE github.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw= github.com/aliyun/credentials-go v1.3.1/go.mod h1:8jKYhQuDawt8x2+fusqa1Y6mPxemTsBEN04dgcAcYz0= github.com/aliyun/credentials-go v1.3.6/go.mod h1:1LxUuX7L5YrZUWzBrRyk0SwSdH4OmPrib8NVePL3fxM= -github.com/aliyun/credentials-go v1.3.10 h1:45Xxrae/evfzQL9V10zL3xX31eqgLWEaIdCoPipOEQA= github.com/aliyun/credentials-go v1.3.10/go.mod h1:Jm6d+xIgwJVLVWT561vy67ZRP4lPTQxMbEYRuT2Ti1U= +github.com/aliyun/credentials-go v1.3.11 h1:8CjGRa0wAoNC0zGMar+PRushZkd1n4xdijpdV4vlCho= +github.com/aliyun/credentials-go v1.3.11/go.mod h1:Jm6d+xIgwJVLVWT561vy67ZRP4lPTQxMbEYRuT2Ti1U= github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092 h1:aM1rlcoLz8y5B2r4tTLMiVTrMtpfY0O8EScKJxaSaEc= github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092/go.mod h1:rYqSE9HbjzpHTI74vwPvae4ZVYZd1lue2ta6xHPdblA= github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo= From 4ae49e0b6b878b02fe20dbd841ac6991c6184fe3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Nov 2024 15:18:02 +0000 Subject: [PATCH 44/62] chore: Bump github.com/aws/aws-sdk-go-v2/credentials from 1.17.44 to 1.17.45 (#1933) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 28f7a64b8..8f0fa8b3a 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( github.com/aliyun/credentials-go v1.3.11 github.com/aws/aws-sdk-go-v2 v1.32.4 github.com/aws/aws-sdk-go-v2/config v1.27.43 - github.com/aws/aws-sdk-go-v2/credentials v1.17.44 + github.com/aws/aws-sdk-go-v2/credentials v1.17.45 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 @@ -151,7 +151,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.4 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.24.5 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.4 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.32.4 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.33.0 // indirect github.com/aws/smithy-go v1.22.0 // 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 d343ae30c..607a75b3f 100644 --- a/go.sum +++ b/go.sum @@ -159,8 +159,8 @@ github.com/aws/aws-sdk-go-v2 v1.32.4 h1:S13INUiTxgrPueTmrm5DZ+MiAo99zYzHEFh1UNkO github.com/aws/aws-sdk-go-v2 v1.32.4/go.mod h1:2SK5n0a2karNTv5tbP1SjsX0uhttou00v/HpXKM1ZUo= github.com/aws/aws-sdk-go-v2/config v1.27.43 h1:p33fDDihFC390dhhuv8nOmX419wjOSDQRb+USt20RrU= github.com/aws/aws-sdk-go-v2/config v1.27.43/go.mod h1:pYhbtvg1siOOg8h5an77rXle9tVG8T+BWLWAo7cOukc= -github.com/aws/aws-sdk-go-v2/credentials v1.17.44 h1:qqfs5kulLUHUEXlHEZXLJkgGoF3kkUeFUTVA585cFpU= -github.com/aws/aws-sdk-go-v2/credentials v1.17.44/go.mod h1:0Lm2YJ8etJdEdw23s+q/9wTpOeo2HhNE97XcRa7T8MA= +github.com/aws/aws-sdk-go-v2/credentials v1.17.45 h1:DUgm5lFso57E7150RBgu1JpVQoF8fAPretiDStIuVjg= +github.com/aws/aws-sdk-go-v2/credentials v1.17.45/go.mod h1:dnBpENcPC1ekZrGpSWspX+ZRGzhkvqngT2Qp5xBR1dY= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.19 h1:woXadbf0c7enQ2UGCi8gW/WuKmE0xIzxBF/eD94jMKQ= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.19/go.mod h1:zminj5ucw7w0r65bP6nhyOd3xL6veAUMc3ElGMoLVb4= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.23 h1:A2w6m6Tmr+BNXjDsr7M90zkWjsu4JXHwrzPg235STs4= @@ -183,8 +183,8 @@ github.com/aws/aws-sdk-go-v2/service/sso v1.24.5 h1:HJwZwRt2Z2Tdec+m+fPjvdmkq2s9 github.com/aws/aws-sdk-go-v2/service/sso v1.24.5/go.mod h1:wrMCEwjFPms+V86TCQQeOxQF/If4vT44FGIOFiMC2ck= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.4 h1:zcx9LiGWZ6i6pjdcoE9oXAB6mUdeyC36Ia/QEiIvYdg= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.4/go.mod h1:Tp/ly1cTjRLGBBmNccFumbZ8oqpZlpdhFf80SrRh4is= -github.com/aws/aws-sdk-go-v2/service/sts v1.32.4 h1:yDxvkz3/uOKfxnv8YhzOi9m+2OGIxF+on3KOISbK5IU= -github.com/aws/aws-sdk-go-v2/service/sts v1.32.4/go.mod h1:9XEUty5v5UAsMiFOBJrNibZgwCeOma73jgGwwhgffa8= +github.com/aws/aws-sdk-go-v2/service/sts v1.33.0 h1:s7LRgBqhwLaxcocnAniBJp7gaAB+4I4vHzqUqjH18yc= +github.com/aws/aws-sdk-go-v2/service/sts v1.33.0/go.mod h1:9XEUty5v5UAsMiFOBJrNibZgwCeOma73jgGwwhgffa8= github.com/aws/smithy-go v1.22.0 h1:uunKnWlcoL3zO7q+gG2Pk53joueEOsnNB28QdMsmiMM= github.com/aws/smithy-go v1.22.0/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= From a3b5d53531e12370c1490e19f568e3beb7039e69 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Nov 2024 02:15:51 +0000 Subject: [PATCH 45/62] chore: Bump codecov/codecov-action from 4.6.0 to 5.0.2 (#1932) Signed-off-by: dependabot[bot] --- .github/workflows/e2e-cli.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/e2e-cli.yml b/.github/workflows/e2e-cli.yml index 5a2366f34..658154bf4 100644 --- a/.github/workflows/e2e-cli.yml +++ b/.github/workflows/e2e-cli.yml @@ -51,7 +51,7 @@ jobs: - name: Check build run: bin/ratify version - name: Upload coverage to codecov.io - uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4.6.0 + uses: codecov/codecov-action@5c47607acb93fed5485fdbf7232e8a31425f672a # v5.0.2 with: token: ${{ secrets.CODECOV_TOKEN }} - name: Run helm lint @@ -86,7 +86,7 @@ jobs: make install ratify-config install-bats make test-e2e-cli GOCOVERDIR=${GITHUB_WORKSPACE}/test/e2e/.cover - name: Upload coverage to codecov.io - uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4.6.0 + uses: codecov/codecov-action@5c47607acb93fed5485fdbf7232e8a31425f672a # v5.0.2 with: token: ${{ secrets.CODECOV_TOKEN }} markdown-link-check: From 281ca40d9ab08236524b3c2b274e5a463a7a4148 Mon Sep 17 00:00:00 2001 From: Shahram Kalantari Date: Tue, 19 Nov 2024 12:44:37 +1000 Subject: [PATCH 46/62] chore: Replace deprecated autorest SDK with azidentity (#1904) Signed-off-by: Shahram Kalantari --- go.mod | 4 + go.sum | 8 + pkg/certificateprovider/azurekeyvault/auth.go | 44 -- .../azurekeyvault/provider.go | 62 +- .../azurekeyvault/provider_test.go | 156 ++-- .../azurekeyvault/auth.go | 44 -- .../azurekeyvault/provider.go | 213 +++--- .../azurekeyvault/provider_test.go | 673 +++++++++++++----- .../azurekeyvault/types/types.go | 2 +- 9 files changed, 779 insertions(+), 427 deletions(-) diff --git a/go.mod b/go.mod index 8f0fa8b3a..cadcd367c 100644 --- a/go.mod +++ b/go.mod @@ -21,6 +21,9 @@ require ( github.com/alibabacloud-go/tea-utils/v2 v2.0.7 github.com/aliyun/credentials-go v1.3.11 github.com/aws/aws-sdk-go-v2 v1.32.4 + github.com/Azure/azure-sdk-for-go/sdk/keyvault/azcertificates v0.9.0 + github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys v0.10.0 + github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.12.0 github.com/aws/aws-sdk-go-v2/config v1.27.43 github.com/aws/aws-sdk-go-v2/credentials v1.17.45 github.com/aws/aws-sdk-go-v2/service/ecr v1.28.6 @@ -67,6 +70,7 @@ require ( cloud.google.com/go/compute/metadata v0.3.0 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/alibabacloudsdkgo/helper v0.2.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.1 // indirect github.com/Azure/go-autorest/autorest/azure/auth v0.5.12 // indirect github.com/Azure/go-autorest/autorest/azure/cli v0.4.6 // indirect github.com/Azure/go-autorest/autorest/validation v0.3.1 // indirect diff --git a/go.sum b/go.sum index 607a75b3f..35a0ef1a9 100644 --- a/go.sum +++ b/go.sum @@ -26,6 +26,14 @@ github.com/Azure/azure-sdk-for-go/sdk/containers/azcontainerregistry v0.2.2 h1:w github.com/Azure/azure-sdk-for-go/sdk/containers/azcontainerregistry v0.2.2/go.mod h1:zzmu18cpAinSbhC86oWd47nmgbb91Fl+Yac2PE8NdYk= github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY= github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY= +github.com/Azure/azure-sdk-for-go/sdk/keyvault/azcertificates v0.9.0 h1:btEsytNrA4TG3edZnnUnzOz8W2MjOd6Bu3/7xyOXSOY= +github.com/Azure/azure-sdk-for-go/sdk/keyvault/azcertificates v0.9.0/go.mod h1:5SlTxxL1U4LLipEr7pAbnu6Ck5y3aIEu4L/tVbGmpsY= +github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys v0.10.0 h1:m/sWOGCREuSBqg2htVQTBY8nOZpyajYztF0vUvSZTuM= +github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys v0.10.0/go.mod h1:Pu5Zksi2KrU7LPbZbNINx6fuVrUp/ffvpxdDj+i8LeE= +github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.12.0 h1:xnO4sFyG8UH2fElBkcqLTOZsAajvKfnSlgBBW8dXYjw= +github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.12.0/go.mod h1:XD3DIOOVgBCO03OleB1fHjgktVRFxlT++KwKgIOewdM= +github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.1 h1:FbH3BbSb4bvGluTesZZ+ttN/MDsnMmQP36OSnDuSXqw= +github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.1/go.mod h1:9V2j0jn9jDEkCkv8w/bKTNppX/d0FVA1ud77xCIP4KA= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.1.0 h1:DRiANoJTiW6obBQe3SqZizkuV1PEgfiiGivmVocDy64= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.1.0/go.mod h1:qLIye2hwb/ZouqhpSD9Zn3SJipvpEnz1Ywl3VUk9Y0s= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0 h1:D3occbWoio4EBLkbkevetNMAVX197GkzbUMtqjGWn80= diff --git a/pkg/certificateprovider/azurekeyvault/auth.go b/pkg/certificateprovider/azurekeyvault/auth.go index b347000e7..9323f4607 100644 --- a/pkg/certificateprovider/azurekeyvault/auth.go +++ b/pkg/certificateprovider/azurekeyvault/auth.go @@ -18,16 +18,10 @@ package azurekeyvault // This class is based on implementation from azure secret store csi provider // Source: https://github.com/Azure/secrets-store-csi-driver-provider-azure/tree/release-1.4/pkg/auth import ( - "context" "encoding/json" "fmt" "strconv" - "strings" "time" - - "github.com/ratify-project/ratify/pkg/utils/azureauth" - - "github.com/Azure/go-autorest/autorest" ) const ( @@ -41,44 +35,6 @@ const ( DefaultTokenAudience = "api://AzureADTokenExchange" //nolint ) -// authResult contains the subset of results from token acquisition operation in ConfidentialClientApplication -// For details see https://aka.ms/msal-net-authenticationresult -type authResult struct { - accessToken string - expiresOn time.Time - grantedScopes []string - declinedScopes []string -} - -func getAuthorizerForWorkloadIdentity(ctx context.Context, tenantID, clientID, resource string) (autorest.Authorizer, error) { - scope := resource - // .default needs to be added to the scope - if !strings.Contains(resource, ".default") { - scope = fmt.Sprintf("%s/.default", resource) - } - - result, err := azureauth.GetAADAccessToken(ctx, tenantID, clientID, scope) - if err != nil { - return nil, fmt.Errorf("failed to acquire token: %w", err) - } - - if _, err = parseExpiresOn(result.ExpiresOn.UTC().Local().Format(expiresOnDateFormat)); err != nil { - return nil, fmt.Errorf("failed to parse expires_on: %w", err) - } - - return autorest.NewBearerAuthorizer(authResult{ - accessToken: result.AccessToken, - expiresOn: result.ExpiresOn, - grantedScopes: result.GrantedScopes, - declinedScopes: result.DeclinedScopes, - }), nil -} - -// OAuthToken implements the OAuthTokenProvider interface. It returns the current access token. -func (ar authResult) OAuthToken() string { - return ar.accessToken -} - // Vendored from https://github.com/Azure/go-autorest/blob/79575dd7ba2e88e7ce7ab84e167ec6653dcb70c1/autorest/adal/token.go // converts expires_on to the number of seconds func parseExpiresOn(s interface{}) (json.Number, error) { diff --git a/pkg/certificateprovider/azurekeyvault/provider.go b/pkg/certificateprovider/azurekeyvault/provider.go index 6565bca07..d93dccb6c 100644 --- a/pkg/certificateprovider/azurekeyvault/provider.go +++ b/pkg/certificateprovider/azurekeyvault/provider.go @@ -34,8 +34,9 @@ import ( "github.com/ratify-project/ratify/pkg/metrics" "golang.org/x/crypto/pkcs12" - kv "github.com/Azure/azure-sdk-for-go/services/keyvault/v7.1/keyvault" - "github.com/Azure/go-autorest/autorest/azure" + "github.com/Azure/azure-sdk-for-go/sdk/azcore" + "github.com/Azure/azure-sdk-for-go/sdk/azidentity" + "github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets" "gopkg.in/yaml.v2" ) @@ -65,7 +66,6 @@ func Create() certificateprovider.CertificateProvider { // get certificate retrieve the entire cert chain using getSecret API call func (s *akvCertProvider) GetCertificates(ctx context.Context, attrib map[string]string) ([]*x509.Certificate, certificateprovider.CertificatesStatus, error) { keyvaultURI := types.GetKeyVaultURI(attrib) - cloudName := types.GetCloudName(attrib) tenantID := types.GetTenantID(attrib) workloadIdentityClientID := types.GetClientID(attrib) @@ -79,11 +79,6 @@ func (s *akvCertProvider) GetCertificates(ctx context.Context, attrib map[string return nil, nil, re.ErrorCodeConfigInvalid.NewError(re.CertProvider, providerName, re.AKVLink, nil, "clientID is not set", re.HideStackTrace) } - azureCloudEnv, err := parseAzureEnvironment(cloudName) - if err != nil { - return nil, nil, re.ErrorCodeConfigInvalid.NewError(re.CertProvider, providerName, re.EmptyLink, nil, fmt.Sprintf("cloudName %s is not valid", cloudName), re.HideStackTrace) - } - keyVaultCerts, err := getKeyvaultRequestObj(ctx, attrib) if err != nil { return nil, nil, re.ErrorCodeConfigInvalid.NewError(re.CertProvider, providerName, re.AKVLink, err, "failed to get keyvault request object from provider attributes", re.HideStackTrace) @@ -93,9 +88,10 @@ func (s *akvCertProvider) GetCertificates(ctx context.Context, attrib map[string return nil, nil, re.ErrorCodeConfigInvalid.NewError(re.CertProvider, providerName, re.EmptyLink, nil, "no keyvault certificate configured", re.HideStackTrace) } - logger.GetLogger(ctx, logOpt).Debugf("vaultURI %s", keyvaultURI) - - kvClient, err := initializeKvClient(ctx, azureCloudEnv.KeyVaultEndpoint, tenantID, workloadIdentityClientID) + // credProvider is nil, so we will create a new workload identity credential inside the function + // For testing purposes, we can pass in a mock credential provider + var credProvider azcore.TokenCredential + secretKVClient, err := initializeKvClient(keyvaultURI, tenantID, workloadIdentityClientID, credProvider) if err != nil { return nil, nil, re.ErrorCodePluginInitFailure.NewError(re.CertProvider, providerName, re.AKVLink, err, "failed to get keyvault client", re.HideStackTrace) } @@ -108,11 +104,12 @@ func (s *akvCertProvider) GetCertificates(ctx context.Context, attrib map[string // fetch the object from Key Vault // GetSecret is required so we can fetch the entire cert chain. See issue https://github.com/ratify-project/ratify/issues/695 for details startTime := time.Now() - secretBundle, err := kvClient.GetSecret(ctx, keyvaultURI, keyVaultCert.CertificateName, keyVaultCert.CertificateVersion) + secretResponse, err := secretKVClient.GetSecret(ctx, keyVaultCert.CertificateName, keyVaultCert.CertificateVersion, nil) if err != nil { return nil, nil, fmt.Errorf("failed to get secret objectName:%s, objectVersion:%s, error: %w", keyVaultCert.CertificateName, keyVaultCert.CertificateVersion, err) } + secretBundle := secretResponse.SecretBundle certResult, certProperty, err := getCertsFromSecretBundle(ctx, secretBundle, keyVaultCert.CertificateName) @@ -195,42 +192,39 @@ func formatKeyVaultCertificate(object *types.KeyVaultCertificate) { } } -// parseAzureEnvironment returns azure environment by name -func parseAzureEnvironment(cloudName string) (*azure.Environment, error) { - var env azure.Environment - var err error - if cloudName == "" { - env = azure.PublicCloud - } else { - env, err = azure.EnvironmentFromName(cloudName) - } - return &env, err -} - -func initializeKvClient(ctx context.Context, keyVaultEndpoint, tenantID, clientID string) (*kv.BaseClient, error) { - kvClient := kv.New() +func initializeKvClient(keyVaultEndpoint, tenantID, clientID string, credProvider azcore.TokenCredential) (*azsecrets.Client, error) { + // Trim any trailing slash from the endpoint kvEndpoint := strings.TrimSuffix(keyVaultEndpoint, "/") - err := kvClient.AddToUserAgent("ratify") - if err != nil { - return nil, re.ErrorCodeConfigInvalid.NewError(re.CertProvider, providerName, re.AKVLink, err, "failed to add user agent to keyvault client", re.HideStackTrace) + // If credProvider is nil, create the default credential + if credProvider == nil { + var err error + credProvider, err = azidentity.NewWorkloadIdentityCredential(&azidentity.WorkloadIdentityCredentialOptions{ + ClientID: clientID, + TenantID: tenantID, + }) + if err != nil { + return nil, re.ErrorCodeAuthDenied.WithDetail("failed to create workload identity credential").WithError(err) + } } - kvClient.Authorizer, err = getAuthorizerForWorkloadIdentity(ctx, tenantID, clientID, kvEndpoint) + // create azsecrets client + secretKVClient, err := azsecrets.NewClient(kvEndpoint, credProvider, nil) if err != nil { - return nil, re.ErrorCodeAuthDenied.NewError(re.CertProvider, providerName, re.AKVLink, err, "failed to get authorizer for keyvault client", re.HideStackTrace) + return nil, re.ErrorCodeConfigInvalid.WithDetail("Failed to create Key Vault client").WithError(err) } - return &kvClient, nil + + return secretKVClient, nil } // Parse the secret bundle and return an array of certificates // In a certificate chain scenario, all certificates from root to leaf will be returned -func getCertsFromSecretBundle(ctx context.Context, secretBundle kv.SecretBundle, certName string) ([]*x509.Certificate, []map[string]string, error) { +func getCertsFromSecretBundle(ctx context.Context, secretBundle azsecrets.SecretBundle, certName string) ([]*x509.Certificate, []map[string]string, error) { if secretBundle.ContentType == nil || secretBundle.Value == nil || secretBundle.ID == nil { return nil, nil, re.ErrorCodeCertInvalid.NewError(re.CertProvider, providerName, re.EmptyLink, nil, "found invalid secret bundle for certificate %s, contentType, value, and id must not be nil", re.HideStackTrace) } - version := getObjectVersion(*secretBundle.ID) + version := getObjectVersion(string(*secretBundle.ID)) // This aligns with notation akv implementation // akv plugin supports both PKCS12 and PEM. https://github.com/Azure/notation-azure-kv/blob/558e7345ef8318783530de6a7a0a8420b9214ba8/Notation.Plugin.AzureKeyVault/KeyVault/KeyVaultClient.cs#L192 diff --git a/pkg/certificateprovider/azurekeyvault/provider_test.go b/pkg/certificateprovider/azurekeyvault/provider_test.go index f11f31eed..35b03c4bd 100644 --- a/pkg/certificateprovider/azurekeyvault/provider_test.go +++ b/pkg/certificateprovider/azurekeyvault/provider_test.go @@ -19,40 +19,19 @@ package azurekeyvault // Source: https://github.com/Azure/secrets-store-csi-driver-provider-azure/tree/release-1.4/pkg/provider import ( "context" + "errors" "reflect" - "strings" "testing" "time" - kv "github.com/Azure/azure-sdk-for-go/services/keyvault/v7.1/keyvault" - "github.com/Azure/go-autorest/autorest/azure" - "github.com/ratify-project/ratify/internal/version" + "github.com/Azure/azure-sdk-for-go/sdk/azidentity" + "github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets" "github.com/ratify-project/ratify/pkg/certificateprovider/azurekeyvault/types" "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" ) -func TestParseAzureEnvironment(t *testing.T) { - envNamesArray := []string{"AZURECHINACLOUD", "AZUREGERMANCLOUD", "AZUREPUBLICCLOUD", "AZUREUSGOVERNMENTCLOUD", ""} - for _, envName := range envNamesArray { - azureEnv, err := parseAzureEnvironment(envName) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - if strings.EqualFold(envName, "") && !strings.EqualFold(azureEnv.Name, "AZUREPUBLICCLOUD") { - t.Fatalf("string doesn't match, expected AZUREPUBLICCLOUD, got %s", azureEnv.Name) - } else if !strings.EqualFold(envName, "") && !strings.EqualFold(envName, azureEnv.Name) { - t.Fatalf("string doesn't match, expected %s, got %s", envName, azureEnv.Name) - } - } - - wrongEnvName := "AZUREWRONGCLOUD" - _, err := parseAzureEnvironment(wrongEnvName) - if err == nil { - t.Fatalf("expected error for wrong azure environment name") - } -} - func TestFormatKeyVaultCertificate(t *testing.T) { cases := []struct { desc string @@ -93,21 +72,110 @@ func TestFormatKeyVaultCertificate(t *testing.T) { } } -func SkipTestInitializeKVClient(t *testing.T) { - testEnvs := []azure.Environment{ - azure.PublicCloud, - azure.GermanCloud, - azure.ChinaCloud, - azure.USGovernmentCloud, +// Mock clients +type MockAzSecretsClient struct { + mock.Mock +} + +type MockWorkloadIdentityCredential struct { + mock.Mock +} + +// Mock functions +func (m *MockWorkloadIdentityCredential) NewWorkloadIdentityCredential(options *azidentity.WorkloadIdentityCredentialOptions) (*MockWorkloadIdentityCredential, error) { + args := m.Called(options) + return args.Get(0).(*MockWorkloadIdentityCredential), args.Error(1) +} + +func (m *MockAzSecretsClient) NewClient(endpoint string, credential *azidentity.WorkloadIdentityCredential, options *azsecrets.ClientOptions) (*azsecrets.Client, error) { + args := m.Called(endpoint, credential, options) + return args.Get(0).(*azsecrets.Client), args.Error(1) +} + +func TestInitializeKvClient(t *testing.T) { + mockCredential := new(MockWorkloadIdentityCredential) + mockSecretsClient := new(MockAzSecretsClient) + + tests := []struct { + name string + kvEndpoint string + userAgent string + tenantID string + clientID string + mockCredentialErr error + mockSecretsErr error + expectedErr bool + }{ + { + name: "Empty user agent", + kvEndpoint: "https://test.vault.azure.net", + userAgent: "", + expectedErr: true, + }, + { + name: "Auth failure", + kvEndpoint: "https://test.vault.azure.net", + tenantID: "testTenantID", + clientID: "testClientID", + expectedErr: true, + }, + { + name: "credential creation error", + kvEndpoint: "https://test-keyvault.vault.azure.net", + tenantID: "test-tenant-id", + clientID: "test-client-id", + mockCredentialErr: errors.New("failed to create workload identity credential"), + expectedErr: true, + }, + { + name: "azsecrets client creation error", + kvEndpoint: "https://test-keyvault.vault.azure.net", + tenantID: "test-tenant-id", + clientID: "test-client-id", + mockSecretsErr: errors.New("failed to create azsecrets client"), + expectedErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Set up mocks + mockCredential.On("NewWorkloadIdentityCredential", mock.Anything).Return(mockCredential, tt.mockCredentialErr) + mockSecretsClient.On("NewClient", tt.kvEndpoint, mockCredential, mock.Anything).Return(mockSecretsClient, tt.mockSecretsErr) + + // Call function under test + secretsClient, err := initializeKvClient(tt.kvEndpoint, tt.tenantID, tt.clientID, nil) + + // Validate expectations + if tt.expectedErr { + assert.Error(t, err) + assert.Nil(t, secretsClient) + } else { + assert.NoError(t, err) + assert.NotNil(t, secretsClient) + } + }) } +} + +func TestInitializeKvClient_Success(t *testing.T) { + // Mock the context and input parameters + keyVaultEndpoint := "https://myvault.vault.azure.net/" + tenantID := "tenant-id" + clientID := "client-id" - for i := range testEnvs { - kvBaseClient, err := initializeKvClient(context.TODO(), testEnvs[i].KeyVaultEndpoint, "", "") - assert.NoError(t, err) - assert.NotNil(t, kvBaseClient) - assert.NotNil(t, kvBaseClient.Authorizer) - assert.Contains(t, kvBaseClient.UserAgent, version.UserAgent) + // Create a mock credential provider + mockCredential, err := azidentity.NewClientSecretCredential(tenantID, clientID, "fake-secret", nil) + if err != nil { + t.Fatalf("Failed to create mock credential: %v", err) } + + // Run the function with the mock credential + kvClientSecrets, err := initializeKvClient(keyVaultEndpoint, tenantID, clientID, mockCredential) + + // Assert the function succeeds without errors and clients are created + assert.NotNil(t, kvClientSecrets) + assert.NoError(t, err) } func TestGetCertificates(t *testing.T) { @@ -137,15 +205,6 @@ func TestGetCertificates(t *testing.T) { }, expectedErr: true, }, - { - desc: "invalid cloud name", - parameters: map[string]string{ - "vaultUri": "https://testkv.vault.azure.net/", - "tenantID": "tid", - "cloudName": "AzureCloud", - }, - expectedErr: true, - }, { desc: "certificates array not set", parameters: map[string]string{ @@ -261,7 +320,6 @@ func TestGetKeyvaultRequestObj(t *testing.T) { attrib := map[string]string{} attrib["vaultURI"] = "https://testvault.vault.azure.net/" attrib["clientID"] = "TestClient" - attrib["cloudName"] = "TestCloud" attrib["tenantID"] = "TestIDABC" attrib["certificates"] = "array:\n- |\n certificateName: wabbit-networks-io \n certificateVersion: \"testversion\"\n" @@ -280,7 +338,7 @@ func Test(t *testing.T) { desc string value string contentType string - id string + id azsecrets.ID expectedErr bool }{ { @@ -322,7 +380,7 @@ func Test(t *testing.T) { for i, tc := range cases { t.Run(tc.desc, func(t *testing.T) { - testdata := kv.SecretBundle{ + testdata := azsecrets.SecretBundle{ Value: &cases[i].value, ID: &cases[i].id, ContentType: &cases[i].contentType, diff --git a/pkg/keymanagementprovider/azurekeyvault/auth.go b/pkg/keymanagementprovider/azurekeyvault/auth.go index cd4d248f7..1de94181a 100644 --- a/pkg/keymanagementprovider/azurekeyvault/auth.go +++ b/pkg/keymanagementprovider/azurekeyvault/auth.go @@ -18,16 +18,10 @@ package azurekeyvault // This class is based on implementation from azure secret store csi provider // Source: https://github.com/Azure/secrets-store-csi-driver-provider-azure/tree/release-1.4/pkg/auth import ( - "context" "encoding/json" "fmt" "strconv" - "strings" "time" - - "github.com/ratify-project/ratify/pkg/utils/azureauth" - - "github.com/Azure/go-autorest/autorest" ) const ( @@ -41,44 +35,6 @@ const ( DefaultTokenAudience = "api://AzureADTokenExchange" //nolint ) -// authResult contains the subset of results from token acquisition operation in ConfidentialClientApplication -// For details see https://aka.ms/msal-net-authenticationresult -type authResult struct { - accessToken string - expiresOn time.Time - grantedScopes []string - declinedScopes []string -} - -func getAuthorizerForWorkloadIdentity(ctx context.Context, tenantID, clientID, resource string) (autorest.Authorizer, error) { - scope := resource - // .default needs to be added to the scope - if !strings.Contains(resource, ".default") { - scope = fmt.Sprintf("%s/.default", resource) - } - - result, err := azureauth.GetAADAccessToken(ctx, tenantID, clientID, scope) - if err != nil { - return nil, fmt.Errorf("failed to acquire token: %w", err) - } - - if _, err = parseExpiresOn(result.ExpiresOn.UTC().Local().Format(expiresOnDateFormat)); err != nil { - return nil, fmt.Errorf("failed to parse expires_on: %w", err) - } - - return autorest.NewBearerAuthorizer(authResult{ - accessToken: result.AccessToken, - expiresOn: result.ExpiresOn, - grantedScopes: result.GrantedScopes, - declinedScopes: result.DeclinedScopes, - }), nil -} - -// OAuthToken implements the OAuthTokenProvider interface. It returns the current access token. -func (ar authResult) OAuthToken() string { - return ar.accessToken -} - // Vendored from https://github.com/Azure/go-autorest/blob/79575dd7ba2e88e7ce7ab84e167ec6653dcb70c1/autorest/adal/token.go // converts expires_on to the number of seconds func parseExpiresOn(s interface{}) (json.Number, error) { diff --git a/pkg/keymanagementprovider/azurekeyvault/provider.go b/pkg/keymanagementprovider/azurekeyvault/provider.go index 22c3fba6a..5a77692d5 100644 --- a/pkg/keymanagementprovider/azurekeyvault/provider.go +++ b/pkg/keymanagementprovider/azurekeyvault/provider.go @@ -26,6 +26,8 @@ import ( "encoding/pem" "errors" "fmt" + "io" + "net/http" "strconv" "strings" "time" @@ -33,7 +35,6 @@ import ( "github.com/go-jose/go-jose/v3" re "github.com/ratify-project/ratify/errors" "github.com/ratify-project/ratify/internal/logger" - "github.com/ratify-project/ratify/internal/version" "github.com/ratify-project/ratify/pkg/keymanagementprovider" "github.com/ratify-project/ratify/pkg/keymanagementprovider/azurekeyvault/types" "github.com/ratify-project/ratify/pkg/keymanagementprovider/config" @@ -41,9 +42,11 @@ import ( "github.com/ratify-project/ratify/pkg/metrics" "golang.org/x/crypto/pkcs12" - kv "github.com/Azure/azure-sdk-for-go/services/keyvault/v7.1/keyvault" - "github.com/Azure/go-autorest/autorest" - "github.com/Azure/go-autorest/autorest/azure" + "github.com/Azure/azure-sdk-for-go/sdk/azcore" + "github.com/Azure/azure-sdk-for-go/sdk/azidentity" + "github.com/Azure/azure-sdk-for-go/sdk/keyvault/azcertificates" + "github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys" + "github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets" ) const ( @@ -61,54 +64,63 @@ type AKVKeyManagementProviderConfig struct { VaultURI string `json:"vaultURI"` TenantID string `json:"tenantID"` ClientID string `json:"clientID"` - CloudName string `json:"cloudName,omitempty"` Resource string `json:"resource,omitempty"` Certificates []types.KeyVaultValue `json:"certificates,omitempty"` Keys []types.KeyVaultValue `json:"keys,omitempty"` } type akvKMProvider struct { - provider string - vaultURI string - tenantID string - clientID string - cloudName string - resource string - certificates []types.KeyVaultValue - keys []types.KeyVaultValue - cloudEnv *azure.Environment - kvClient kvClient + provider string + vaultURI string + tenantID string + clientID string + resource string + certificates []types.KeyVaultValue + keys []types.KeyVaultValue + keyKVClient keyKVClient + secretKVClient secretKVClient + certificateKVClient certificateKVClient } type akvKMProviderFactory struct{} // kvClient is an interface to interact with the keyvault client used for mocking purposes -type kvClient interface { - // GetCertificate retrieves a certificate from the keyvault - GetCertificate(ctx context.Context, vaultBaseURL string, certificateName string, certificateVersion string) (kv.CertificateBundle, error) +type keyKVClient interface { // GetKey retrieves a key from the keyvault - GetKey(ctx context.Context, vaultBaseURL string, keyName string, keyVersion string) (kv.KeyBundle, error) + GetKey(ctx context.Context, keyName string, keyVersion string) (azkeys.GetKeyResponse, error) +} +type secretKVClient interface { // GetSecret retrieves a secret from the keyvault - GetSecret(ctx context.Context, vaultBaseURL string, secretName string, secretVersion string) (kv.SecretBundle, error) + GetSecret(ctx context.Context, secretName string, secretVersion string) (azsecrets.GetSecretResponse, error) +} +type certificateKVClient interface { + // GetCertificate retrieves a certificate from the keyvault + GetCertificate(ctx context.Context, certificateName string, certificateVersion string) (azcertificates.GetCertificateResponse, error) } -type kvClientImpl struct { - kv.BaseClient +type keyKVClientImpl struct { + azkeys.Client +} +type secretKVClientImpl struct { + azsecrets.Client +} +type certificateKVClientImpl struct { + azcertificates.Client } // GetCertificate retrieves a certificate from the keyvault -func (c *kvClientImpl) GetCertificate(ctx context.Context, vaultBaseURL string, certificateName string, certificateVersion string) (kv.CertificateBundle, error) { - return c.BaseClient.GetCertificate(ctx, vaultBaseURL, certificateName, certificateVersion) +func (c *certificateKVClientImpl) GetCertificate(ctx context.Context, certificateName string, certificateVersion string) (azcertificates.GetCertificateResponse, error) { + return c.Client.GetCertificate(ctx, certificateName, certificateVersion, nil) } // GetKey retrieves a key from the keyvault -func (c *kvClientImpl) GetKey(ctx context.Context, vaultBaseURL string, keyName string, keyVersion string) (kv.KeyBundle, error) { - return c.BaseClient.GetKey(ctx, vaultBaseURL, keyName, keyVersion) +func (c *keyKVClientImpl) GetKey(ctx context.Context, keyName string, keyVersion string) (azkeys.GetKeyResponse, error) { + return c.Client.GetKey(ctx, keyName, keyVersion, nil) } // GetSecret retrieves a secret from the keyvault -func (c *kvClientImpl) GetSecret(ctx context.Context, vaultBaseURL string, secretName string, secretVersion string) (kv.SecretBundle, error) { - return c.BaseClient.GetSecret(ctx, vaultBaseURL, secretName, secretVersion) +func (c *secretKVClientImpl) GetSecret(ctx context.Context, secretName string, secretVersion string) (azsecrets.GetSecretResponse, error) { + return c.Client.GetSecret(ctx, secretName, secretVersion, nil) } // initKVClient is a function to initialize the keyvault client @@ -133,11 +145,6 @@ func (f *akvKMProviderFactory) Create(_ string, keyManagementProviderConfig conf return nil, re.ErrorCodeConfigInvalid.NewError(re.KeyManagementProvider, "", re.EmptyLink, err, "failed to parse AKV key management provider configuration", re.HideStackTrace) } - azureCloudEnv, err := parseAzureEnvironment(conf.CloudName) - if err != nil { - return nil, re.ErrorCodeConfigInvalid.NewError(re.KeyManagementProvider, ProviderName, re.EmptyLink, nil, fmt.Sprintf("cloudName %s is not valid", conf.CloudName), re.HideStackTrace) - } - if len(conf.Certificates) == 0 && len(conf.Keys) == 0 { return nil, re.ErrorCodeConfigInvalid.NewError(re.KeyManagementProvider, ProviderName, re.EmptyLink, nil, "no keyvault certificates or keys configured", re.HideStackTrace) } @@ -147,23 +154,25 @@ func (f *akvKMProviderFactory) Create(_ string, keyManagementProviderConfig conf vaultURI: strings.TrimSpace(conf.VaultURI), tenantID: strings.TrimSpace(conf.TenantID), clientID: strings.TrimSpace(conf.ClientID), - cloudName: strings.TrimSpace(conf.CloudName), certificates: conf.Certificates, keys: conf.Keys, - cloudEnv: azureCloudEnv, resource: conf.Resource, } if err := provider.validate(); err != nil { return nil, err } - logger.GetLogger(context.Background(), logOpt).Debugf("vaultURI %s", provider.vaultURI) - - kvClient, err := initKVClient(context.Background(), provider.cloudEnv.KeyVaultEndpoint, provider.tenantID, provider.clientID, version.UserAgent) + // credProvider is nil, so we will create a new workload identity credential inside the function + // For testing purposes, we can pass in a mock credential provider + var credProvider azcore.TokenCredential + keyKVClient, secretKVClient, certificateKVClient, err := initKVClient(provider.vaultURI, provider.tenantID, provider.clientID, credProvider) if err != nil { return nil, re.ErrorCodePluginInitFailure.NewError(re.KeyManagementProvider, ProviderName, re.AKVLink, err, "failed to create keyvault client", re.HideStackTrace) } - provider.kvClient = &kvClientImpl{*kvClient} + + provider.keyKVClient = &keyKVClientImpl{*keyKVClient} + provider.secretKVClient = &secretKVClientImpl{*secretKVClient} + provider.certificateKVClient = &certificateKVClientImpl{*certificateKVClient} return provider, nil } @@ -174,20 +183,19 @@ func (s *akvKMProvider) GetCertificates(ctx context.Context) (map[keymanagementp certsMap := map[keymanagementprovider.KMPMapKey][]*x509.Certificate{} certsStatus := []map[string]string{} for _, keyVaultCert := range s.certificates { - logger.GetLogger(ctx, logOpt).Debugf("fetching secret from key vault, certName %v, keyvault %v", keyVaultCert.Name, s.vaultURI) + logger.GetLogger(ctx, logOpt).Debugf("fetching secret from key vault, certName %v, certVersion %v, vaultURI: %v", keyVaultCert.Name, keyVaultCert.Version, s.vaultURI) startTime := time.Now() - - // GetSecret is required so we can fetch the entire cert chain. See issue https://github.com/ratify-project/ratify/issues/695 for details - secretBundle, err := s.kvClient.GetSecret(ctx, s.vaultURI, keyVaultCert.Name, keyVaultCert.Version) + secretResponse, err := s.secretKVClient.GetSecret(ctx, keyVaultCert.Name, keyVaultCert.Version) if err != nil { if isSecretDisabledError(err) { // if secret is disabled, get the version of the certificate for status - certBundle, err := s.kvClient.GetCertificate(ctx, s.vaultURI, keyVaultCert.Name, keyVaultCert.Version) + certResponse, err := s.certificateKVClient.GetCertificate(ctx, keyVaultCert.Name, keyVaultCert.Version) if err != nil { return nil, nil, fmt.Errorf("failed to get certificate objectName:%s, objectVersion:%s, error: %w", keyVaultCert.Name, keyVaultCert.Version, err) } - keyVaultCert.Version = getObjectVersion(*certBundle.Kid) + certBundle := certResponse.CertificateBundle + keyVaultCert.Version = getObjectVersion(*certBundle.KID) isEnabled := *certBundle.Attributes.Enabled lastRefreshed := startTime.Format(time.RFC3339) certProperty := getStatusProperty(keyVaultCert.Name, keyVaultCert.Version, lastRefreshed, isEnabled) @@ -196,10 +204,10 @@ func (s *akvKMProvider) GetCertificates(ctx context.Context) (map[keymanagementp keymanagementprovider.DeleteCertificateFromMap(s.resource, mapKey) continue } - return nil, nil, fmt.Errorf("failed to get secret objectName:%s, objectVersion:%s, error: %w", keyVaultCert.Name, keyVaultCert.Version, err) } + secretBundle := secretResponse.SecretBundle isEnabled := *secretBundle.Attributes.Enabled certResult, certProperty, err := getCertsFromSecretBundle(ctx, secretBundle, keyVaultCert.Name, isEnabled) @@ -225,14 +233,14 @@ func (s *akvKMProvider) GetKeys(ctx context.Context) (map[keymanagementprovider. // fetch the key object from Key Vault startTime := time.Now() - keyBundle, err := s.kvClient.GetKey(ctx, s.vaultURI, keyVaultKey.Name, keyVaultKey.Version) + keyResponse, err := s.keyKVClient.GetKey(ctx, keyVaultKey.Name, keyVaultKey.Version) if err != nil { return nil, nil, fmt.Errorf("failed to get key objectName:%s, objectVersion:%s, error: %w", keyVaultKey.Name, keyVaultKey.Version, err) } - + keyBundle := keyResponse.KeyBundle isEnabled := *keyBundle.Attributes.Enabled // if version is set as "" in the config, use the version from the key bundle - keyVaultKey.Version = getObjectVersion(*keyBundle.Key.Kid) + keyVaultKey.Version = getObjectVersion(string(*keyBundle.Key.KID)) if !isEnabled { startTime := time.Now() @@ -278,42 +286,53 @@ func getStatusProperty(name, version, lastRefreshed string, enabled bool) map[st return properties } -// parseAzureEnvironment returns azure environment by name -func parseAzureEnvironment(cloudName string) (*azure.Environment, error) { - var env azure.Environment - var err error - if cloudName == "" { - env = azure.PublicCloud - } else { - env, err = azure.EnvironmentFromName(cloudName) +// initializeKvClient creates a new keyvault client for keys, secrets and certificates +// TODO: credProvider in only added to params for testing purposes. Make sure it is handled properly in future +func initializeKvClient(keyVaultURI, tenantID, clientID string, credProvider azcore.TokenCredential) (*azkeys.Client, *azsecrets.Client, *azcertificates.Client, error) { + // Trim any trailing slash from the endpoint + kvEndpoint := strings.TrimSuffix(keyVaultURI, "/") + + // If credProvider is nil, create the default credential + if credProvider == nil { + var err error + credProvider, err = azidentity.NewWorkloadIdentityCredential(&azidentity.WorkloadIdentityCredentialOptions{ + ClientID: clientID, + TenantID: tenantID, + }) + if err != nil { + return nil, nil, nil, re.ErrorCodeAuthDenied.WithDetail("failed to create workload identity credential").WithError(err) + } } - return &env, err -} -func initializeKvClient(ctx context.Context, keyVaultEndpoint, tenantID, clientID, userAgent string) (*kv.BaseClient, error) { - kvClient := kv.New() - kvEndpoint := strings.TrimSuffix(keyVaultEndpoint, "/") + // create azkeys client + keyKVClient, err := azkeys.NewClient(kvEndpoint, credProvider, nil) + if err != nil { + return nil, nil, nil, re.ErrorCodeConfigInvalid.WithDetail("Failed to create keys Key Vault client").WithError(err) + } - err := kvClient.Client.AddToUserAgent(userAgent) + // create azsecrets client + secretKVClient, err := azsecrets.NewClient(kvEndpoint, credProvider, nil) if err != nil { - return nil, re.ErrorCodeConfigInvalid.WithDetail("Failed to add user agent to keyvault client.").WithRemediation(re.AKVLink).WithError(err) + return nil, nil, nil, re.ErrorCodeConfigInvalid.WithDetail("Failed to create secrets Key Vault client").WithError(err) } - kvClient.Authorizer, err = getAuthorizerForWorkloadIdentity(ctx, tenantID, clientID, kvEndpoint) + // create azcertificates client + certificateKVClient, err := azcertificates.NewClient(kvEndpoint, credProvider, nil) if err != nil { - return nil, re.ErrorCodeAuthDenied.WithDetail("failed to get authorizer for keyvault client").WithRemediation(re.AKVLink).WithError(err) + return nil, nil, nil, re.ErrorCodeConfigInvalid.WithDetail("Failed to create certificates Key Vault client").WithError(err) } - return &kvClient, nil + + return keyKVClient, secretKVClient, certificateKVClient, nil } // Parse the secret bundle and return an array of certificates // In a certificate chain scenario, all certificates from root to leaf will be returned -func getCertsFromSecretBundle(ctx context.Context, secretBundle kv.SecretBundle, certName string, enabled bool) ([]*x509.Certificate, []map[string]string, error) { +func getCertsFromSecretBundle(ctx context.Context, secretBundle azsecrets.SecretBundle, certName string, enabled bool) ([]*x509.Certificate, []map[string]string, error) { if secretBundle.ContentType == nil || secretBundle.Value == nil || secretBundle.ID == nil { return nil, nil, re.ErrorCodeCertInvalid.NewError(re.KeyManagementProvider, ProviderName, re.EmptyLink, nil, "found invalid secret bundle for certificate %s, contentType, value, and id must not be nil", re.HideStackTrace) } - version := getObjectVersion(*secretBundle.ID) + version := getObjectVersion(string(*secretBundle.ID)) // This aligns with notation akv implementation // akv plugin supports both PKCS12 and PEM. https://github.com/Azure/notation-azure-kv/blob/558e7345ef8318783530de6a7a0a8420b9214ba8/Notation.Plugin.AzureKeyVault/KeyVault/KeyVaultClient.cs#L192 @@ -378,18 +397,24 @@ func getCertsFromSecretBundle(ctx context.Context, secretBundle kv.SecretBundle, } // Based on https://github.com/sigstore/sigstore/blob/8b208f7d608b80a7982b2a66358b8333b1eec542/pkg/signature/kms/azure/client.go#L258 -func getKeyFromKeyBundle(keyBundle kv.KeyBundle) (crypto.PublicKey, error) { +func getKeyFromKeyBundle(keyBundle azkeys.KeyBundle) (crypto.PublicKey, error) { webKey := keyBundle.Key if webKey == nil { return nil, re.ErrorCodeKeyInvalid.NewError(re.KeyManagementProvider, ProviderName, re.EmptyLink, nil, "found invalid key bundle, key must not be nil", re.HideStackTrace) } - keyType := webKey.Kty + if webKey.Kty == nil { + return nil, re.ErrorCodeKeyInvalid.NewError(re.KeyManagementProvider, ProviderName, re.EmptyLink, nil, "found invalid key bundle, keytype must not be nil", re.HideStackTrace) + } + + keyType := *webKey.Kty switch keyType { - case kv.ECHSM: - webKey.Kty = kv.EC - case kv.RSAHSM: - webKey.Kty = kv.RSA + case azkeys.JSONWebKeyTypeECHSM: + ecType := azkeys.JSONWebKeyTypeEC + webKey.Kty = &ecType + case azkeys.JSONWebKeyTypeRSAHSM: + rsaType := azkeys.JSONWebKeyTypeRSA + webKey.Kty = &rsaType } keyBytes, err := json.Marshal(webKey) @@ -417,15 +442,39 @@ func getObjectVersion(id string) string { } func isSecretDisabledError(err error) bool { - var de autorest.DetailedError - if errors.As(err, &de) { - var re *azure.RequestError - if errors.As(de.Original, &re) { - if re.ServiceError.Code == "SecretDisabled" { - return true - } + // AzureError defines the structure of the error response from Azure Key Vault + // This structure is defined according to https://learn.microsoft.com/en-us/rest/api/keyvault/keys/get-keys/get-keys?view=rest-keyvault-keys-7.4&tabs=HTTP#error + type AzureError struct { + Error struct { + Code string `json:"code"` + Message string `json:"message"` + InnerError struct { + Code string `json:"code"` + } `json:"innererror"` + } `json:"error"` + } + + // Parse err and make sure it is a secretDisabled error and return true + const ErrorCodeForbidden = "Forbidden" + const SecretDisabledCode = "SecretDisabled" + var httpErr *azcore.ResponseError + if errors.As(err, &httpErr) { + if httpErr.StatusCode != http.StatusForbidden { + return false + } + + var azureError AzureError + errorResponseBody, readErr := io.ReadAll(httpErr.RawResponse.Body) + if readErr != nil { + return false + } + jsonErr := json.Unmarshal(errorResponseBody, &azureError) + if jsonErr == nil && azureError.Error.Code == ErrorCodeForbidden && azureError.Error.InnerError.Code == SecretDisabledCode { + return true } } + + // Return false if it's not a secretDisabled error return false } diff --git a/pkg/keymanagementprovider/azurekeyvault/provider_test.go b/pkg/keymanagementprovider/azurekeyvault/provider_test.go index 98effa5c4..9bb444ae6 100644 --- a/pkg/keymanagementprovider/azurekeyvault/provider_test.go +++ b/pkg/keymanagementprovider/azurekeyvault/provider_test.go @@ -20,61 +20,24 @@ package azurekeyvault import ( "context" "crypto" - "encoding/base64" "errors" + "io" + "net/http" "strings" "testing" "time" - kv "github.com/Azure/azure-sdk-for-go/services/keyvault/v7.1/keyvault" - "github.com/Azure/go-autorest/autorest" - "github.com/Azure/go-autorest/autorest/azure" - "github.com/Azure/go-autorest/autorest/to" - "github.com/ratify-project/ratify/internal/version" + "github.com/Azure/azure-sdk-for-go/sdk/azcore" + "github.com/Azure/azure-sdk-for-go/sdk/azidentity" + "github.com/Azure/azure-sdk-for-go/sdk/keyvault/azcertificates" + "github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys" + "github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets" "github.com/ratify-project/ratify/pkg/keymanagementprovider/azurekeyvault/types" "github.com/ratify-project/ratify/pkg/keymanagementprovider/config" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" ) -// TestParseAzureEnvironment tests the parseAzureEnvironment function -func TestParseAzureEnvironment(t *testing.T) { - envNamesArray := []string{"AZURECHINACLOUD", "AZUREGERMANCLOUD", "AZUREPUBLICCLOUD", "AZUREUSGOVERNMENTCLOUD", ""} - for _, envName := range envNamesArray { - azureEnv, err := parseAzureEnvironment(envName) - if err != nil { - t.Fatalf("expected no error, got %v", err) - } - if strings.EqualFold(envName, "") && !strings.EqualFold(azureEnv.Name, "AZUREPUBLICCLOUD") { - t.Fatalf("string doesn't match, expected AZUREPUBLICCLOUD, got %s", azureEnv.Name) - } else if !strings.EqualFold(envName, "") && !strings.EqualFold(envName, azureEnv.Name) { - t.Fatalf("string doesn't match, expected %s, got %s", envName, azureEnv.Name) - } - } - - wrongEnvName := "AZUREWRONGCLOUD" - _, err := parseAzureEnvironment(wrongEnvName) - if err == nil { - t.Fatalf("expected error for wrong azure environment name") - } -} - -func SkipTestInitializeKVClient(t *testing.T) { - testEnvs := []azure.Environment{ - azure.PublicCloud, - azure.GermanCloud, - azure.ChinaCloud, - azure.USGovernmentCloud, - } - - for i := range testEnvs { - kvBaseClient, err := initializeKvClient(context.TODO(), testEnvs[i].KeyVaultEndpoint, "", "", version.UserAgent) - assert.NoError(t, err) - assert.NotNil(t, kvBaseClient) - assert.NotNil(t, kvBaseClient.Authorizer) - assert.Contains(t, kvBaseClient.UserAgent, version.UserAgent) - } -} - // TestCreate tests the Create function func TestCreate(t *testing.T) { factory := &akvKMProviderFactory{} @@ -118,15 +81,6 @@ func TestCreate(t *testing.T) { }, expectErr: true, }, - { - name: "invalid cloud name", - config: config.KeyManagementProviderConfig{ - "vaultUri": "https://testkv.vault.azure.net/", - "tenantID": "tid", - "cloudName": "AzureCloud", - }, - expectErr: true, - }, { name: "certificates & keys array not set", config: config.KeyManagementProviderConfig{ @@ -178,8 +132,8 @@ func TestCreate(t *testing.T) { } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - initKVClient = func(_ context.Context, _, _, _, _ string) (*kv.BaseClient, error) { - return &kv.BaseClient{}, nil + initKVClient = func(_, _, _ string, _ azcore.TokenCredential) (*azkeys.Client, *azsecrets.Client, *azcertificates.Client, error) { + return &azkeys.Client{}, &azsecrets.Client{}, &azcertificates.Client{}, nil } _, err := factory.Create("v1", tc.config, "") if tc.expectErr != (err != nil) { @@ -189,124 +143,205 @@ func TestCreate(t *testing.T) { } } -type MockKvClient struct { - GetCertificateFunc func(ctx context.Context, certificateName string, certificateVersion string, arg string) (kv.CertificateBundle, error) - GetSecretFunc func(ctx context.Context, secretName string, secretVersion string, arg string) (kv.SecretBundle, error) - GetKeyFunc func(ctx context.Context, keyName string, keyVersion string, arg string) (kv.KeyBundle, error) +// TestGetCertificates tests the GetCertificates function +func TestGetCertificates_original(t *testing.T) { + factory := &akvKMProviderFactory{} + config := config.KeyManagementProviderConfig{ + "vaultUri": "https://testkv.vault.azure.net/", + "tenantID": "tid", + "clientID": "clientid", + "certificates": []map[string]interface{}{ + { + "name": "cert1", + "version": "", + }, + }, + } + + provider, err := factory.Create("v1", config, "") + if err != nil { + t.Fatalf("expected no err but got error = %v", err) + } + + certs, certStatus, err := provider.GetCertificates(context.Background()) + assert.NotNil(t, err) + assert.Nil(t, certs) + assert.Nil(t, certStatus) } -func (m *MockKvClient) GetCertificate(ctx context.Context, certificateName string, certificateVersion string, arg string) (kv.CertificateBundle, error) { - if m.GetCertificateFunc != nil { - return m.GetCertificateFunc(ctx, certificateName, certificateVersion, arg) +type MockKeyKVClient struct { + GetKeyFunc func(ctx context.Context, keyName string, keyVersion string) (azkeys.GetKeyResponse, error) +} +type MockSecretKVClient struct { + GetSecretFunc func(ctx context.Context, secretName string, secretVersion string) (azsecrets.GetSecretResponse, error) +} +type MockCertificateKVClient struct { + GetCertificateFunc func(ctx context.Context, certificateName string, certificateVersion string) (azcertificates.GetCertificateResponse, error) +} + +func (m *MockKeyKVClient) GetKey(ctx context.Context, keyName string, keyVersion string) (azkeys.GetKeyResponse, error) { + if m.GetKeyFunc != nil { + return m.GetKeyFunc(ctx, keyName, keyVersion) } - return kv.CertificateBundle{}, nil + return azkeys.GetKeyResponse{}, nil } -func (m *MockKvClient) GetSecret(ctx context.Context, secretName string, secretVersion string, arg string) (kv.SecretBundle, error) { +func (m *MockSecretKVClient) GetSecret(ctx context.Context, secretName string, secretVersion string) (azsecrets.GetSecretResponse, error) { if m.GetSecretFunc != nil { - return m.GetSecretFunc(ctx, secretName, secretVersion, arg) + return m.GetSecretFunc(ctx, secretName, secretVersion) } - return kv.SecretBundle{}, nil + return azsecrets.GetSecretResponse{}, nil } -func (m *MockKvClient) GetKey(ctx context.Context, keyName string, keyVersion string, arg string) (kv.KeyBundle, error) { - if m.GetKeyFunc != nil { - return m.GetKeyFunc(ctx, keyName, keyVersion, arg) +func (m *MockCertificateKVClient) GetCertificate(ctx context.Context, certificateName string, certificateVersion string) (azcertificates.GetCertificateResponse, error) { + if m.GetCertificateFunc != nil { + return m.GetCertificateFunc(ctx, certificateName, certificateVersion) } - return kv.KeyBundle{}, nil + return azcertificates.GetCertificateResponse{}, nil +} + +// stringPtr returns a pointer to the given string. +func stringPtr(s string) *string { + return &s +} + +// boolPtr returns a pointer to the given bool. +func boolPtr(b bool) *bool { + return &b } // TestGetCertificates tests the GetCertificates function func TestGetCertificates(t *testing.T) { + certID := azcertificates.ID("https://testkv.vault.azure.net/certificates/cert1") + secretID := azsecrets.ID("https://testkv.vault.azure.net/secrets/secret1") testCases := []struct { - name string - mockKvClient *MockKvClient - expectedErr bool + name string + mockKeyKVClient *MockKeyKVClient + mockSecretKVClient *MockSecretKVClient + mockCertificateKVClient *MockCertificateKVClient + expectedErr bool }{ { name: "GetSecret error", - mockKvClient: &MockKvClient{ - GetSecretFunc: func(_ context.Context, _ string, _ string, _ string) (kv.SecretBundle, error) { - return kv.SecretBundle{}, errors.New("error") + mockSecretKVClient: &MockSecretKVClient{ + GetSecretFunc: func(_ context.Context, _ string, _ string) (azsecrets.GetSecretResponse, error) { + return azsecrets.GetSecretResponse{}, errors.New("error") }, }, expectedErr: true, }, { name: "Certificate disabled", - mockKvClient: &MockKvClient{ - GetCertificateFunc: func(_ context.Context, _ string, _ string, _ string) (kv.CertificateBundle, error) { - return kv.CertificateBundle{ - ID: to.StringPtr("https://testkv.vault.azure.net/certificates/cert1"), - Kid: to.StringPtr("https://testkv.vault.azure.net/keys/key1"), - Attributes: &kv.CertificateAttributes{ - Enabled: to.BoolPtr(false), + mockCertificateKVClient: &MockCertificateKVClient{ + GetCertificateFunc: func(_ context.Context, _ string, _ string) (azcertificates.GetCertificateResponse, error) { + return azcertificates.GetCertificateResponse{ + CertificateBundle: azcertificates.CertificateBundle{ + ID: &certID, + KID: stringPtr("https://testkv.vault.azure.net/keys/key1"), + Attributes: &azcertificates.CertificateAttributes{ + Enabled: boolPtr(false), + }, }, }, nil }, - GetSecretFunc: func(_ context.Context, _ string, _ string, _ string) (kv.SecretBundle, error) { - err := autorest.DetailedError{ - Original: &azure.RequestError{ - ServiceError: &azure.ServiceError{Code: "SecretDisabled"}, + }, + mockSecretKVClient: &MockSecretKVClient{ + GetSecretFunc: func(_ context.Context, _ string, _ string) (azsecrets.GetSecretResponse, error) { + rawResponse := `{ + "error": { + "code": "Forbidden", + "message": "Operation get is not allowed on a disabled secret.", + "innererror": { + "code": "SecretDisabled" + } + } + }` + + httpErr := &azcore.ResponseError{ + StatusCode: http.StatusForbidden, + RawResponse: &http.Response{ + Body: io.NopCloser(strings.NewReader(rawResponse)), }, } - return kv.SecretBundle{}, err + return azsecrets.GetSecretResponse{}, httpErr }, }, expectedErr: false, }, { name: "Certificate disabled error", - mockKvClient: &MockKvClient{ - GetCertificateFunc: func(_ context.Context, _ string, _ string, _ string) (kv.CertificateBundle, error) { - return kv.CertificateBundle{}, errors.New("error") + mockCertificateKVClient: &MockCertificateKVClient{ + GetCertificateFunc: func(_ context.Context, _ string, _ string) (azcertificates.GetCertificateResponse, error) { + return azcertificates.GetCertificateResponse{}, errors.New("error") }, - GetSecretFunc: func(_ context.Context, _ string, _ string, _ string) (kv.SecretBundle, error) { - err := autorest.DetailedError{ - Original: &azure.RequestError{ - ServiceError: &azure.ServiceError{Code: "SecretDisabled"}, + }, + mockSecretKVClient: &MockSecretKVClient{ + GetSecretFunc: func(_ context.Context, _ string, _ string) (azsecrets.GetSecretResponse, error) { + rawResponse := `{ + "error": { + "code": "Forbidden", + "message": "Operation get is not allowed on a disabled secret.", + "innererror": { + "code": "SecretDisabled" + } + } + }` + + httpErr := &azcore.ResponseError{ + StatusCode: http.StatusForbidden, + RawResponse: &http.Response{ + Body: io.NopCloser(strings.NewReader(rawResponse)), }, } - return kv.SecretBundle{}, err + return azsecrets.GetSecretResponse{}, httpErr }, }, expectedErr: true, }, { name: "Certificate enabled", - mockKvClient: &MockKvClient{ - GetCertificateFunc: func(_ context.Context, _ string, _ string, _ string) (kv.CertificateBundle, error) { - return kv.CertificateBundle{ - ID: to.StringPtr("https://testkv.vault.azure.net/certificates/cert1"), - Kid: to.StringPtr("https://testkv.vault.azure.net/keys/key1"), - Attributes: &kv.CertificateAttributes{ - Enabled: to.BoolPtr(true), + mockCertificateKVClient: &MockCertificateKVClient{ + GetCertificateFunc: func(_ context.Context, _ string, _ string) (azcertificates.GetCertificateResponse, error) { + return azcertificates.GetCertificateResponse{ + CertificateBundle: azcertificates.CertificateBundle{ + ID: &certID, + KID: stringPtr("https://testkv.vault.azure.net/keys/key1"), + Attributes: &azcertificates.CertificateAttributes{ + Enabled: boolPtr(true), + }, }, }, nil }, - GetSecretFunc: func(_ context.Context, _ string, _ string, _ string) (kv.SecretBundle, error) { - return kv.SecretBundle{ - ID: to.StringPtr("https://testkv.vault.azure.net/secrets/secret1"), - Kid: to.StringPtr("https://testkv.vault.azure.net/keys/key1"), - ContentType: to.StringPtr("application/x-pem-file"), - Attributes: &kv.SecretAttributes{ - Enabled: to.BoolPtr(true), + }, + mockSecretKVClient: &MockSecretKVClient{ + GetSecretFunc: func(_ context.Context, _ string, _ string) (azsecrets.GetSecretResponse, error) { + return azsecrets.GetSecretResponse{ + SecretBundle: azsecrets.SecretBundle{ + ID: &secretID, + Kid: stringPtr("https://testkv.vault.azure.net/keys/key1"), + ContentType: stringPtr("application/x-pem-file"), + Attributes: &azsecrets.SecretAttributes{ + Enabled: boolPtr(true), + }, + Value: stringPtr("-----BEGIN CERTIFICATE-----\nMIIC8TCCAdmgAwIBAgIUaNrwbhs/I1ecqUYdzD2xuAVNdmowDQYJKoZIhvcNAQEL\nBQAwKjEPMA0GA1UECgwGUmF0aWZ5MRcwFQYDVQQDDA5SYXRpZnkgUm9vdCBDQTAe\nFw0yMzA2MjEwMTIyMzdaFw0yNDA2MjAwMTIyMzdaMBkxFzAVBgNVBAMMDnJhdGlm\neS5kZWZhdWx0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtskG1BUt\n4Fw2lbm53KbwZb1hnLmWdwRotZyznhhk/yrUDcq3uF6klwpk/E2IKfUKIo6doHSk\nXaEZXR68UtXygvA4wdg7xZ6kKpXy0gu+RxGE6CGtDHTyDDzITu+NBjo21ZSsyGpQ\nJeIKftUCHdwdygKf0CdJx8A29GBRpHGCmJadmt7tTzOnYjmbuPVLeqJo/Ex9qXcG\nZbxoxnxr5NCocFeKx+EbLo+k/KjdFB2PKnhgzxAaMMMP6eXPr8l5AlzkC83EmPvN\ntveuaBbamdlFkD+53TZeZlxt3GIdq93Iw/UpbQ/pvhbrztMT+UVEkm15sShfX8Xn\nL2st5A4n0V+66QIDAQABoyAwHjAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIH\ngDANBgkqhkiG9w0BAQsFAAOCAQEAGpOqozyfDSBjoTepsRroxxcZ4sq65gw45Bme\nm36BS6FG0WHIg3cMy6KIIBefTDSKrPkKNTtuF25AeGn9jM+26cnfDM78ZH0+Lnn7\n7hs0MA64WMPQaWs9/+89aM9NADV9vp2zdG4xMi6B7DruvKWyhJaNoRqK/qP6LdSQ\nw8M+21sAHvXgrRkQtJlVOzVhgwt36NOb1hzRlQiZB+nhv2Wbw7fbtAaADk3JAumf\nvM+YdPS1KfAFaYefm4yFd+9/C0KOkHico3LTbELO5hG0Mo/EYvtjM+Fljb42EweF\n3nAx1GSPe5Tn8p3h6RyJW5HIKozEKyfDuLS0ccB/nqT3oNjcTw==\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIDRTCCAi2gAwIBAgIUcC33VfaMhOnsl7avNTRVQozoVtUwDQYJKoZIhvcNAQEL\nBQAwKjEPMA0GA1UECgwGUmF0aWZ5MRcwFQYDVQQDDA5SYXRpZnkgUm9vdCBDQTAe\nFw0yMzA2MjEwMTIyMzZaFw0yMzA2MjIwMTIyMzZaMCoxDzANBgNVBAoMBlJhdGlm\neTEXMBUGA1UEAwwOUmF0aWZ5IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IB\nDwAwggEKAoIBAQDDFhDnyPrVDZaeRu6Tbg1a/iTwus+IuX+h8aKhKS1yHz4EF/Lz\nxCy7lNSQ9srGMMVumWuNom/ydIphff6PejZM1jFKPU6OQR/0JX5epcVIjbKa562T\nDguUxJ+h5V3EIyM4RqOWQ2g/xZo86x5TzyNJXiVdHHRvmDvUNwPpMeDjr/EHVAni\n5YQObxkJRiiZ7XOa5zz3YztVm8sSZAwPWroY1HIfvtP+KHpiNDIKSymmuJkH4SEr\nJn++iqN8na18a9DFBPTTrLPe3CxATGrMfosCMZ6LP3iFLLc/FaSpwcnugWdewsUK\nYs+sUY7jFWR7x7/1nyFWyRrQviM4f4TY+K7NAgMBAAGjYzBhMB0GA1UdDgQWBBQH\nYePW7QPP2p1utr3r6gqzEkKs+DAfBgNVHSMEGDAWgBQHYePW7QPP2p1utr3r6gqz\nEkKs+DAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwICBDANBgkqhkiG9w0B\nAQsFAAOCAQEAjKp4vx3bFaKVhAbQeTsDjWJgmXLK2vLgt74MiUwSF6t0wehlfszE\nIcJagGJsvs5wKFf91bnwiqwPjmpse/thPNBAxh1uEoh81tOklv0BN790vsVpq3t+\ncnUvWPiCZdRlAiGGFtRmKk3Keq4sM6UdiUki9s+wnxypHVb4wIpVxu5R271Lnp5I\n+rb2EQ48iblt4XZPczf/5QJdTgbItjBNbuO8WVPOqUIhCiFuAQziLtNUq3p81dHO\nQ2BPgmaitCpIUYHVYighLauBGCH8xOFzj4a4KbOxKdxyJTd0La/vRCKaUtJX67Lc\nfQYVR9HXQZ0YlmwPcmIG5v7wBfcW34NUvA==\n-----END CERTIFICATE-----\n"), }, - Value: to.StringPtr("-----BEGIN CERTIFICATE-----\nMIIC8TCCAdmgAwIBAgIUaNrwbhs/I1ecqUYdzD2xuAVNdmowDQYJKoZIhvcNAQEL\nBQAwKjEPMA0GA1UECgwGUmF0aWZ5MRcwFQYDVQQDDA5SYXRpZnkgUm9vdCBDQTAe\nFw0yMzA2MjEwMTIyMzdaFw0yNDA2MjAwMTIyMzdaMBkxFzAVBgNVBAMMDnJhdGlm\neS5kZWZhdWx0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtskG1BUt\n4Fw2lbm53KbwZb1hnLmWdwRotZyznhhk/yrUDcq3uF6klwpk/E2IKfUKIo6doHSk\nXaEZXR68UtXygvA4wdg7xZ6kKpXy0gu+RxGE6CGtDHTyDDzITu+NBjo21ZSsyGpQ\nJeIKftUCHdwdygKf0CdJx8A29GBRpHGCmJadmt7tTzOnYjmbuPVLeqJo/Ex9qXcG\nZbxoxnxr5NCocFeKx+EbLo+k/KjdFB2PKnhgzxAaMMMP6eXPr8l5AlzkC83EmPvN\ntveuaBbamdlFkD+53TZeZlxt3GIdq93Iw/UpbQ/pvhbrztMT+UVEkm15sShfX8Xn\nL2st5A4n0V+66QIDAQABoyAwHjAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIH\ngDANBgkqhkiG9w0BAQsFAAOCAQEAGpOqozyfDSBjoTepsRroxxcZ4sq65gw45Bme\nm36BS6FG0WHIg3cMy6KIIBefTDSKrPkKNTtuF25AeGn9jM+26cnfDM78ZH0+Lnn7\n7hs0MA64WMPQaWs9/+89aM9NADV9vp2zdG4xMi6B7DruvKWyhJaNoRqK/qP6LdSQ\nw8M+21sAHvXgrRkQtJlVOzVhgwt36NOb1hzRlQiZB+nhv2Wbw7fbtAaADk3JAumf\nvM+YdPS1KfAFaYefm4yFd+9/C0KOkHico3LTbELO5hG0Mo/EYvtjM+Fljb42EweF\n3nAx1GSPe5Tn8p3h6RyJW5HIKozEKyfDuLS0ccB/nqT3oNjcTw==\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIDRTCCAi2gAwIBAgIUcC33VfaMhOnsl7avNTRVQozoVtUwDQYJKoZIhvcNAQEL\nBQAwKjEPMA0GA1UECgwGUmF0aWZ5MRcwFQYDVQQDDA5SYXRpZnkgUm9vdCBDQTAe\nFw0yMzA2MjEwMTIyMzZaFw0yMzA2MjIwMTIyMzZaMCoxDzANBgNVBAoMBlJhdGlm\neTEXMBUGA1UEAwwOUmF0aWZ5IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IB\nDwAwggEKAoIBAQDDFhDnyPrVDZaeRu6Tbg1a/iTwus+IuX+h8aKhKS1yHz4EF/Lz\nxCy7lNSQ9srGMMVumWuNom/ydIphff6PejZM1jFKPU6OQR/0JX5epcVIjbKa562T\nDguUxJ+h5V3EIyM4RqOWQ2g/xZo86x5TzyNJXiVdHHRvmDvUNwPpMeDjr/EHVAni\n5YQObxkJRiiZ7XOa5zz3YztVm8sSZAwPWroY1HIfvtP+KHpiNDIKSymmuJkH4SEr\nJn++iqN8na18a9DFBPTTrLPe3CxATGrMfosCMZ6LP3iFLLc/FaSpwcnugWdewsUK\nYs+sUY7jFWR7x7/1nyFWyRrQviM4f4TY+K7NAgMBAAGjYzBhMB0GA1UdDgQWBBQH\nYePW7QPP2p1utr3r6gqzEkKs+DAfBgNVHSMEGDAWgBQHYePW7QPP2p1utr3r6gqz\nEkKs+DAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwICBDANBgkqhkiG9w0B\nAQsFAAOCAQEAjKp4vx3bFaKVhAbQeTsDjWJgmXLK2vLgt74MiUwSF6t0wehlfszE\nIcJagGJsvs5wKFf91bnwiqwPjmpse/thPNBAxh1uEoh81tOklv0BN790vsVpq3t+\ncnUvWPiCZdRlAiGGFtRmKk3Keq4sM6UdiUki9s+wnxypHVb4wIpVxu5R271Lnp5I\n+rb2EQ48iblt4XZPczf/5QJdTgbItjBNbuO8WVPOqUIhCiFuAQziLtNUq3p81dHO\nQ2BPgmaitCpIUYHVYighLauBGCH8xOFzj4a4KbOxKdxyJTd0La/vRCKaUtJX67Lc\nfQYVR9HXQZ0YlmwPcmIG5v7wBfcW34NUvA==\n-----END CERTIFICATE-----\n"), }, nil }, }, + expectedErr: false, }, { name: "getCertsFromSecretBundle error", - mockKvClient: &MockKvClient{ - GetSecretFunc: func(_ context.Context, _ string, _ string, _ string) (kv.SecretBundle, error) { - return kv.SecretBundle{ - ContentType: to.StringPtr("test"), - ID: to.StringPtr("https://testkv.vault.azure.net/secrets/secret1"), - Kid: to.StringPtr("https://testkv.vault.azure.net/keys/key1"), - Attributes: &kv.SecretAttributes{ - Enabled: to.BoolPtr(true), + mockSecretKVClient: &MockSecretKVClient{ + GetSecretFunc: func(_ context.Context, _ string, _ string) (azsecrets.GetSecretResponse, error) { + return azsecrets.GetSecretResponse{ + SecretBundle: azsecrets.SecretBundle{ + ContentType: stringPtr("test"), + ID: &secretID, + Kid: stringPtr("https://testkv.vault.azure.net/keys/key1"), + Attributes: &azsecrets.SecretAttributes{ + Enabled: boolPtr(true), + }, + Value: stringPtr("-----BEGIN CERTIFICATE-----\nMIIC8TCCAdmgAwIBAgIUaNrwbhs/I1ecqUYdzD2xuAVNdmowDQYJKoZIhvcNAQEL\nBQAwKjEPMA0GA1UECgwGUmF0aWZ5MRcwFQYDVQQDDA5SYXRpZnkgUm9vdCBDQTAe\nFw0yMzA2MjEwMTIyMzdaFw0yNDA2MjAwMTIyMzdaMBkxFzAVBgNVBAMMDnJhdGlm\neS5kZWZhdWx0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtskG1BUt\n4Fw2lbm53KbwZb1hnLmWdwRotZyznhhk/yrUDcq3uF6klwpk/E2IKfUKIo6doHSk\nXaEZXR68UtXygvA4wdg7xZ6kKpXy0gu+RxGE6CGtDHTyDDzITu+NBjo21ZSsyGpQ\nJeIKftUCHdwdygKf0CdJx8A29GBRpHGCmJadmt7tTzOnYjmbuPVLeqJo/Ex9qXcG\nZbxoxnxr5NCocFeKx+EbLo+k/KjdFB2PKnhgzxAaMMMP6eXPr8l5AlzkC83EmPvN\ntveuaBbamdlFkD+53TZeZlxt3GIdq93Iw/UpbQ/pvhbrztMT+UVEkm15sShfX8Xn\nL2st5A4n0V+66QIDAQABoyAwHjAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIH\ngDANBgkqhkiG9w0BAQsFAAOCAQEAGpOqozyfDSBjoTepsRroxxcZ4sq65gw45Bme\nm36BS6FG0WHIg3cMy6KIIBefTDSKrPkKNTtuF25AeGn9jM+26cnfDM78ZH0+Lnn7\n7hs0MA64WMPQaWs9/+89aM9NADV9vp2zdG4xMi6B7DruvKWyhJaNoRqK/qP6LdSQ\nw8M+21sAHvXgrRkQtJlVOzVhgwt36NOb1hzRlQiZB+nhv2Wbw7fbtAaADk3JAumf\nvM+YdPS1KfAFaYefm4yFd+9/C0KOkHico3LTbELO5hG0Mo/EYvtjM+Fljb42EweF\n3nAx1GSPe5Tn8p3h6RyJW5HIKozEKyfDuLS0ccB/nqT3oNjcTw==\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIDRTCCAi2gAwIBAgIUcC33VfaMhOnsl7avNTRVQozoVtUwDQYJKoZIhvcNAQEL\nBQAwKjEPMA0GA1UECgwGUmF0aWZ5MRcwFQYDVQQDDA5SYXRpZnkgUm9vdCBDQTAe\nFw0yMzA2MjEwMTIyMzZaFw0yMzA2MjIwMTIyMzZaMCoxDzANBgNVBAoMBlJhdGlm\neTEXMBUGA1UEAwwOUmF0aWZ5IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IB\nDwAwggEKAoIBAQDDFhDnyPrVDZaeRu6Tbg1a/iTwus+IuX+h8aKhKS1yHz4EF/Lz\nxCy7lNSQ9srGMMVumWuNom/ydIphff6PejZM1jFKPU6OQR/0JX5epcVIjbKa562T\nDguUxJ+h5V3EIyM4RqOWQ2g/xZo86x5TzyNJXiVdHHRvmDvUNwPpMeDjr/EHVAni\n5YQObxkJRiiZ7XOa5zz3YztVm8sSZAwPWroY1HIfvtP+KHpiNDIKSymmuJkH4SEr\nJn++iqN8na18a9DFBPTTrLPe3CxATGrMfosCMZ6LP3iFLLc/FaSpwcnugWdewsUK\nYs+sUY7jFWR7x7/1nyFWyRrQviM4f4TY+K7NAgMBAAGjYzBhMB0GA1UdDgQWBBQH\nYePW7QPP2p1utr3r6gqzEkKs+DAfBgNVHSMEGDAWgBQHYePW7QPP2p1utr3r6gqz\nEkKs+DAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwICBDANBgkqhkiG9w0B\nAQsFAAOCAQEAjKp4vx3bFaKVhAbQeTsDjWJgmXLK2vLgt74MiUwSF6t0wehlfszE\nIcJagGJsvs5wKFf91bnwiqwPjmpse/thPNBAxh1uEoh81tOklv0BN790vsVpq3t+\ncnUvWPiCZdRlAiGGFtRmKk3Keq4sM6UdiUki9s+wnxypHVb4wIpVxu5R271Lnp5I\n+rb2EQ48iblt4XZPczf/5QJdTgbItjBNbuO8WVPOqUIhCiFuAQziLtNUq3p81dHO\nQ2BPgmaitCpIUYHVYighLauBGCH8xOFzj4a4KbOxKdxyJTd0La/vRCKaUtJX67Lc\nfQYVR9HXQZ0YlmwPcmIG5v7wBfcW34NUvA==\n-----END CERTIFICATE-----\n"), }, - Value: to.StringPtr("-----BEGIN CERTIFICATE-----\nMIIC8TCCAdmgAwIBAgIUaNrwbhs/I1ecqUYdzD2xuAVNdmowDQYJKoZIhvcNAQEL\nBQAwKjEPMA0GA1UECgwGUmF0aWZ5MRcwFQYDVQQDDA5SYXRpZnkgUm9vdCBDQTAe\nFw0yMzA2MjEwMTIyMzdaFw0yNDA2MjAwMTIyMzdaMBkxFzAVBgNVBAMMDnJhdGlm\neS5kZWZhdWx0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtskG1BUt\n4Fw2lbm53KbwZb1hnLmWdwRotZyznhhk/yrUDcq3uF6klwpk/E2IKfUKIo6doHSk\nXaEZXR68UtXygvA4wdg7xZ6kKpXy0gu+RxGE6CGtDHTyDDzITu+NBjo21ZSsyGpQ\nJeIKftUCHdwdygKf0CdJx8A29GBRpHGCmJadmt7tTzOnYjmbuPVLeqJo/Ex9qXcG\nZbxoxnxr5NCocFeKx+EbLo+k/KjdFB2PKnhgzxAaMMMP6eXPr8l5AlzkC83EmPvN\ntveuaBbamdlFkD+53TZeZlxt3GIdq93Iw/UpbQ/pvhbrztMT+UVEkm15sShfX8Xn\nL2st5A4n0V+66QIDAQABoyAwHjAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIH\ngDANBgkqhkiG9w0BAQsFAAOCAQEAGpOqozyfDSBjoTepsRroxxcZ4sq65gw45Bme\nm36BS6FG0WHIg3cMy6KIIBefTDSKrPkKNTtuF25AeGn9jM+26cnfDM78ZH0+Lnn7\n7hs0MA64WMPQaWs9/+89aM9NADV9vp2zdG4xMi6B7DruvKWyhJaNoRqK/qP6LdSQ\nw8M+21sAHvXgrRkQtJlVOzVhgwt36NOb1hzRlQiZB+nhv2Wbw7fbtAaADk3JAumf\nvM+YdPS1KfAFaYefm4yFd+9/C0KOkHico3LTbELO5hG0Mo/EYvtjM+Fljb42EweF\n3nAx1GSPe5Tn8p3h6RyJW5HIKozEKyfDuLS0ccB/nqT3oNjcTw==\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIDRTCCAi2gAwIBAgIUcC33VfaMhOnsl7avNTRVQozoVtUwDQYJKoZIhvcNAQEL\nBQAwKjEPMA0GA1UECgwGUmF0aWZ5MRcwFQYDVQQDDA5SYXRpZnkgUm9vdCBDQTAe\nFw0yMzA2MjEwMTIyMzZaFw0yMzA2MjIwMTIyMzZaMCoxDzANBgNVBAoMBlJhdGlm\neTEXMBUGA1UEAwwOUmF0aWZ5IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IB\nDwAwggEKAoIBAQDDFhDnyPrVDZaeRu6Tbg1a/iTwus+IuX+h8aKhKS1yHz4EF/Lz\nxCy7lNSQ9srGMMVumWuNom/ydIphff6PejZM1jFKPU6OQR/0JX5epcVIjbKa562T\nDguUxJ+h5V3EIyM4RqOWQ2g/xZo86x5TzyNJXiVdHHRvmDvUNwPpMeDjr/EHVAni\n5YQObxkJRiiZ7XOa5zz3YztVm8sSZAwPWroY1HIfvtP+KHpiNDIKSymmuJkH4SEr\nJn++iqN8na18a9DFBPTTrLPe3CxATGrMfosCMZ6LP3iFLLc/FaSpwcnugWdewsUK\nYs+sUY7jFWR7x7/1nyFWyRrQviM4f4TY+K7NAgMBAAGjYzBhMB0GA1UdDgQWBBQH\nYePW7QPP2p1utr3r6gqzEkKs+DAfBgNVHSMEGDAWgBQHYePW7QPP2p1utr3r6gqz\nEkKs+DAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwICBDANBgkqhkiG9w0B\nAQsFAAOCAQEAjKp4vx3bFaKVhAbQeTsDjWJgmXLK2vLgt74MiUwSF6t0wehlfszE\nIcJagGJsvs5wKFf91bnwiqwPjmpse/thPNBAxh1uEoh81tOklv0BN790vsVpq3t+\ncnUvWPiCZdRlAiGGFtRmKk3Keq4sM6UdiUki9s+wnxypHVb4wIpVxu5R271Lnp5I\n+rb2EQ48iblt4XZPczf/5QJdTgbItjBNbuO8WVPOqUIhCiFuAQziLtNUq3p81dHO\nQ2BPgmaitCpIUYHVYighLauBGCH8xOFzj4a4KbOxKdxyJTd0La/vRCKaUtJX67Lc\nfQYVR9HXQZ0YlmwPcmIG5v7wBfcW34NUvA==\n-----END CERTIFICATE-----\n"), }, nil }, }, @@ -323,7 +358,9 @@ func TestGetCertificates(t *testing.T) { Version: "c1f03df1113d460491d970737dfdc35d", }, }, - kvClient: tc.mockKvClient, + keyKVClient: tc.mockKeyKVClient, + secretKVClient: tc.mockSecretKVClient, + certificateKVClient: tc.mockCertificateKVClient, } _, _, err := provider.GetCertificates(context.Background()) @@ -336,30 +373,34 @@ func TestGetCertificates(t *testing.T) { // TestGetKeys tests the GetKeys function func TestGetKeys(t *testing.T) { + keyID := azkeys.ID("https://testkv.vault.azure.net/keys/key1") + keyTY := azkeys.JSONWebKeyTypeRSA testCases := []struct { - name string - mockKvClient *MockKvClient - expectedErr bool + name string + mockKeyKVClient *MockKeyKVClient + expectedErr bool }{ { name: "GetKey error", - mockKvClient: &MockKvClient{ - GetKeyFunc: func(_ context.Context, _ string, _ string, _ string) (kv.KeyBundle, error) { - return kv.KeyBundle{}, errors.New("error") + mockKeyKVClient: &MockKeyKVClient{ + GetKeyFunc: func(_ context.Context, _ string, _ string) (azkeys.GetKeyResponse, error) { + return azkeys.GetKeyResponse{}, errors.New("error") }, }, expectedErr: true, }, { name: "Key disabled", - mockKvClient: &MockKvClient{ - GetKeyFunc: func(_ context.Context, _ string, _ string, _ string) (kv.KeyBundle, error) { - return kv.KeyBundle{ - Key: &kv.JSONWebKey{ - Kid: to.StringPtr("https://testkv.vault.azure.net/keys/key1"), - }, - Attributes: &kv.KeyAttributes{ - Enabled: to.BoolPtr(false), + mockKeyKVClient: &MockKeyKVClient{ + GetKeyFunc: func(_ context.Context, _ string, _ string) (azkeys.GetKeyResponse, error) { + return azkeys.GetKeyResponse{ + KeyBundle: azkeys.KeyBundle{ + Key: &azkeys.JSONWebKey{ + KID: &keyID, + }, + Attributes: &azkeys.KeyAttributes{ + Enabled: boolPtr(false), + }, }, }, nil }, @@ -368,14 +409,16 @@ func TestGetKeys(t *testing.T) { }, { name: "getKeyFromKeyBundle error", - mockKvClient: &MockKvClient{ - GetKeyFunc: func(_ context.Context, _ string, _ string, _ string) (kv.KeyBundle, error) { - return kv.KeyBundle{ - Key: &kv.JSONWebKey{ - Kid: to.StringPtr("https://testkv.vault.azure.net/keys/key1"), - }, - Attributes: &kv.KeyAttributes{ - Enabled: to.BoolPtr(true), + mockKeyKVClient: &MockKeyKVClient{ + GetKeyFunc: func(_ context.Context, _ string, _ string) (azkeys.GetKeyResponse, error) { + return azkeys.GetKeyResponse{ + KeyBundle: azkeys.KeyBundle{ + Key: &azkeys.JSONWebKey{ + KID: &keyID, + }, + Attributes: &azkeys.KeyAttributes{ + Enabled: boolPtr(true), + }, }, }, nil }, @@ -384,17 +427,19 @@ func TestGetKeys(t *testing.T) { }, { name: "Key enabled", - mockKvClient: &MockKvClient{ - GetKeyFunc: func(_ context.Context, _ string, _ string, _ string) (kv.KeyBundle, error) { - return kv.KeyBundle{ - Key: &kv.JSONWebKey{ - Kid: to.StringPtr("https://testkv.vault.azure.net/keys/key1"), - Kty: kv.RSA, - N: to.StringPtr(base64.StdEncoding.EncodeToString([]byte("n"))), - E: to.StringPtr(base64.StdEncoding.EncodeToString([]byte("e"))), - }, - Attributes: &kv.KeyAttributes{ - Enabled: to.BoolPtr(true), + mockKeyKVClient: &MockKeyKVClient{ + GetKeyFunc: func(_ context.Context, _ string, _ string) (azkeys.GetKeyResponse, error) { + return azkeys.GetKeyResponse{ + KeyBundle: azkeys.KeyBundle{ + Key: &azkeys.JSONWebKey{ + KID: &keyID, + Kty: &keyTY, + N: []byte("n"), + E: []byte("e"), + }, + Attributes: &azkeys.KeyAttributes{ + Enabled: boolPtr(true), + }, }, }, nil }, @@ -412,7 +457,7 @@ func TestGetKeys(t *testing.T) { Version: "c1f03df1113d460491d970737dfdc35d", }, }, - kvClient: tc.mockKvClient, + keyKVClient: tc.mockKeyKVClient, } _, _, err := provider.GetKeys(context.Background()) @@ -423,6 +468,34 @@ func TestGetKeys(t *testing.T) { } } +// TestGetKeys tests the GetKeys function +func TestGetKeys_original(t *testing.T) { + factory := &akvKMProviderFactory{} + config := config.KeyManagementProviderConfig{ + "vaultUri": "https://testkv.vault.azure.net/", + "tenantID": "tid", + "clientID": "clientid", + "keys": []map[string]interface{}{ + { + "name": "key1", + }, + }, + } + + initKVClient = func(_, _, _ string, _ azcore.TokenCredential) (*azkeys.Client, *azsecrets.Client, *azcertificates.Client, error) { + return &azkeys.Client{}, &azsecrets.Client{}, &azcertificates.Client{}, nil + } + provider, err := factory.Create("v1", config, "") + if err != nil { + t.Fatalf("expected no err but got error = %v", err) + } + + keys, keyStatus, err := provider.GetKeys(context.Background()) + assert.NotNil(t, err) + assert.Nil(t, keys) + assert.Nil(t, keyStatus) +} + func TestIsRefreshable(t *testing.T) { factory := &akvKMProviderFactory{} config := config.KeyManagementProviderConfig{ @@ -486,7 +559,7 @@ func TestGetCertsFromSecretBundle(t *testing.T) { desc string value string contentType string - id string + id azsecrets.ID expectedErr bool }{ { @@ -528,7 +601,7 @@ func TestGetCertsFromSecretBundle(t *testing.T) { for i, tc := range cases { t.Run(tc.desc, func(t *testing.T) { - testdata := kv.SecretBundle{ + testdata := azsecrets.SecretBundle{ Value: &cases[i].value, ID: &cases[i].id, ContentType: &cases[i].contentType, @@ -547,24 +620,37 @@ func TestGetCertsFromSecretBundle(t *testing.T) { } func TestGetKeyFromKeyBundle(t *testing.T) { + unsupportedType := azkeys.JSONWebKeyType("abc") cases := []struct { desc string - keyBundle kv.KeyBundle + keyBundle azkeys.KeyBundle expectedErr bool output crypto.PublicKey }{ { desc: "no key in key bundle", - keyBundle: kv.KeyBundle{ + keyBundle: azkeys.KeyBundle{ Key: nil, }, expectedErr: true, output: nil, }, { - desc: "invalid key in key bundle", - keyBundle: kv.KeyBundle{ - Key: &kv.JSONWebKey{}, + desc: "invalid key in key bundle with nil Kty", + keyBundle: azkeys.KeyBundle{ + Key: &azkeys.JSONWebKey{ + Kty: nil, + }, + }, + expectedErr: true, + output: nil, + }, + { + desc: "key with unsupported Kty value", + keyBundle: azkeys.KeyBundle{ + Key: &azkeys.JSONWebKey{ + Kty: &unsupportedType, // Unsupported key type + }, }, expectedErr: true, output: nil, @@ -693,14 +779,60 @@ func TestValidate(t *testing.T) { } } +// Mock clients +type MockAzKeysClient struct { + mock.Mock +} + +type MockAzSecretsClient struct { + mock.Mock +} + +type MockAzCertificatesClient struct { + mock.Mock +} + +type MockWorkloadIdentityCredential struct { + mock.Mock +} + +// Mock functions +func (m *MockWorkloadIdentityCredential) NewWorkloadIdentityCredential(options *azidentity.WorkloadIdentityCredentialOptions) (*MockWorkloadIdentityCredential, error) { + args := m.Called(options) + return args.Get(0).(*MockWorkloadIdentityCredential), args.Error(1) +} + +func (m *MockAzKeysClient) NewClient(endpoint string, credential *azidentity.WorkloadIdentityCredential, options *azkeys.ClientOptions) (*azkeys.Client, error) { + args := m.Called(endpoint, credential, options) + return args.Get(0).(*azkeys.Client), args.Error(1) +} + +func (m *MockAzSecretsClient) NewClient(endpoint string, credential *azidentity.WorkloadIdentityCredential, options *azsecrets.ClientOptions) (*azsecrets.Client, error) { + args := m.Called(endpoint, credential, options) + return args.Get(0).(*azsecrets.Client), args.Error(1) +} + +func (m *MockAzCertificatesClient) NewClient(endpoint string, credential *azidentity.WorkloadIdentityCredential, options *azcertificates.ClientOptions) (*azcertificates.Client, error) { + args := m.Called(endpoint, credential, options) + return args.Get(0).(*azcertificates.Client), args.Error(1) +} + func TestInitializeKvClient(t *testing.T) { + mockCredential := new(MockWorkloadIdentityCredential) + mockKeysClient := new(MockAzKeysClient) + mockSecretsClient := new(MockAzSecretsClient) + mockCertificatesClient := new(MockAzCertificatesClient) + tests := []struct { - name string - kvEndpoint string - userAgent string - tenantID string - clientID string - expectedErr bool + name string + kvEndpoint string + userAgent string + tenantID string + clientID string + mockCredentialErr error + mockKeysErr error + mockSecretsErr error + expectedErr bool }{ { name: "Empty user agent", @@ -711,19 +843,214 @@ func TestInitializeKvClient(t *testing.T) { { name: "Auth failure", kvEndpoint: "https://test.vault.azure.net", - userAgent: version.UserAgent, tenantID: "testTenantID", clientID: "testClientID", expectedErr: true, }, + { + name: "credential creation error", + kvEndpoint: "https://test-keyvault.vault.azure.net", + tenantID: "test-tenant-id", + clientID: "test-client-id", + mockCredentialErr: errors.New("failed to create workload identity credential"), + expectedErr: true, + }, + { + name: "azkeys client creation error", + kvEndpoint: "https://test-keyvault.vault.azure.net", + tenantID: "test-tenant-id", + clientID: "test-client-id", + mockKeysErr: errors.New("failed to create azkeys client"), + expectedErr: true, + }, + { + name: "azsecrets client creation error", + kvEndpoint: "https://test-keyvault.vault.azure.net", + tenantID: "test-tenant-id", + clientID: "test-client-id", + mockSecretsErr: errors.New("failed to create azsecrets client"), + expectedErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Set up mocks + mockCredential.On("NewWorkloadIdentityCredential", mock.Anything).Return(mockCredential, tt.mockCredentialErr) + mockKeysClient.On("NewClient", tt.kvEndpoint, mockCredential, mock.Anything).Return(mockKeysClient, tt.mockKeysErr) + mockSecretsClient.On("NewClient", tt.kvEndpoint, mockCredential, mock.Anything).Return(mockSecretsClient, tt.mockSecretsErr) + mockCertificatesClient.On("NewClient", tt.kvEndpoint, mockCredential, mock.Anything).Return(mockCertificatesClient, tt.mockSecretsErr) + + // Call function under test + keysKVClient, secretsKVClient, certificatesKVClient, err := initializeKvClient(tt.kvEndpoint, tt.tenantID, tt.clientID, nil) + + // Validate expectations + if tt.expectedErr { + assert.Error(t, err) + assert.Nil(t, keysKVClient) + assert.Nil(t, secretsKVClient) + assert.Nil(t, certificatesKVClient) + } else { + assert.NoError(t, err) + assert.NotNil(t, keysKVClient) + assert.NotNil(t, secretsKVClient) + assert.Nil(t, certificatesKVClient) + } + }) + } +} + +// Test cases for keyType switch case handling +func TestGetKeyFromKeyBundlex(t *testing.T) { + tests := []struct { + name string + keyType azkeys.JSONWebKeyType + expected azkeys.JSONWebKeyType + curve azkeys.JSONWebKeyCurveName + x []byte + y []byte + n []byte + e []byte + }{ + { + name: "Test ECHSM to EC", + keyType: azkeys.JSONWebKeyTypeECHSM, + expected: azkeys.JSONWebKeyTypeEC, + curve: azkeys.JSONWebKeyCurveNameP256, // Example curve name + x: []byte{0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c, 0x42, 0x47, 0xf8, 0xbc, 0xe6, 0xe5, 0x63, 0xa4, 0x40, 0xf2, 0x77, 0x03, 0x7d, 0x81, 0x2d, 0xeb, 0x33, 0xa0, 0xf4, 0xa1, 0x39, 0x45, 0xd8, 0x98, 0xc2, 0x96}, // Valid x-coordinate for P-256 + y: []byte{0x4f, 0xe3, 0x42, 0xe2, 0xfe, 0x1a, 0x7f, 0x9b, 0x8e, 0xe7, 0xeb, 0x4a, 0x7c, 0x0f, 0x9e, 0x16, 0x2b, 0xce, 0x33, 0x57, 0x6b, 0x31, 0x5e, 0xce, 0xcb, 0xb6, 0x40, 0x68, 0x37, 0xbf, 0x51, 0xf5}, // Valid y-coordinate for P-256 + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - _, err := initializeKvClient(context.Background(), tt.kvEndpoint, tt.tenantID, tt.clientID, tt.userAgent) - if tt.expectedErr != (err != nil) { - t.Fatalf("expected error: %v, got: %v", tt.expectedErr, err) + webKey := &azkeys.JSONWebKey{ + Kty: &tt.keyType, + } + if tt.keyType == azkeys.JSONWebKeyTypeECHSM { + webKey.Crv = &tt.curve + webKey.X = tt.x + webKey.Y = tt.y + } + keyBundle := azkeys.KeyBundle{ + Key: webKey, } + + _, err := getKeyFromKeyBundle(keyBundle) + assert.NoError(t, err) + assert.Equal(t, tt.expected, *webKey.Kty) + }) + } +} + +const tenantID = "tenant-id" +const clientID = "client-id" + +func TestInitializeKvClient_Success(t *testing.T) { + // Mock the context and input parameters + keyVaultEndpoint := "https://myvault.vault.azure.net/" + + // Create a mock credential provider + mockCredential, err := azidentity.NewClientSecretCredential(tenantID, clientID, "fake-secret", nil) + if err != nil { + t.Fatalf("Failed to create mock credential: %v", err) + } + + // Run the function with the mock credential + keysKVClient, secretsKVClient, certificatesKVClient, err := initializeKvClient(keyVaultEndpoint, tenantID, clientID, mockCredential) + + // Assert the function succeeds without errors and clients are created + assert.NotNil(t, keysKVClient) + assert.NotNil(t, secretsKVClient) + assert.NotNil(t, certificatesKVClient) + assert.NoError(t, err) +} + +func TestInitializeKvClient_FailureInAzKeysClient(t *testing.T) { + // Mock the context and input parameters + keyVaultEndpoint := "https://invalid-vault.vault.azure.net/" + + // Run the function + keysKVClient, secretsKVClient, certificatesKVClient, err := initializeKvClient(keyVaultEndpoint, tenantID, clientID, nil) + + // Assert that an error occurred and clients were not created + assert.Nil(t, keysKVClient) + assert.Nil(t, secretsKVClient) + assert.Nil(t, certificatesKVClient) + assert.Error(t, err) + assert.Contains(t, err.Error(), "failed to create workload identity credential") +} + +func TestInitializeKvClient_FailureInAzSecretsClient(t *testing.T) { + // Mock the context and input parameters + keyVaultEndpoint := "https://valid-vault.vault.azure.net/" + + // Modify the azsecrets.NewClient function to simulate failure + // Run the function + keysKVClient, secretsKVClient, certificatesKVClient, err := initializeKvClient(keyVaultEndpoint, tenantID, clientID, nil) + + // Assert that an error occurred and clients were not created + assert.Nil(t, keysKVClient) + assert.Nil(t, secretsKVClient) + assert.Nil(t, certificatesKVClient) + assert.Error(t, err) + assert.Contains(t, err.Error(), "failed to create workload identity credential") +} + +func TestInitializeKvClient_FailureInAzCertificatesClient(t *testing.T) { + // Mock the context and input parameters + keyVaultEndpoint := "https://valid-vault.vault.azure.net/" + + // Modify the azsecrets.NewClient function to simulate failure + // Run the function + keysKVClient, secretsKVClient, certificatesKVClient, err := initializeKvClient(keyVaultEndpoint, tenantID, clientID, nil) + + // Assert that an error occurred and clients were not created + assert.Nil(t, keysKVClient) + assert.Nil(t, secretsKVClient) + assert.Nil(t, certificatesKVClient) + assert.Error(t, err) + assert.Contains(t, err.Error(), "failed to create workload identity credential") +} +func TestIsSecretDisabledError(t *testing.T) { + rawResponse := `{ + "error": { + "code": "Forbidden", + "message": "Operation get is not allowed on a disabled secret.", + "innererror": { + "code": "SecretDisabled" + } + } + }` + + httpErr := &azcore.ResponseError{ + StatusCode: http.StatusForbidden, + RawResponse: &http.Response{ + Body: io.NopCloser(strings.NewReader(rawResponse)), + }, + } + + testCases := []struct { + name string + err error + expectedRes bool + }{ + { + name: "SecretDisabledError", + err: httpErr, + expectedRes: true, + }, + { + name: "NonSecretDisabledError", + err: errors.New("some other error"), + expectedRes: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + res := isSecretDisabledError(tc.err) + assert.Equal(t, tc.expectedRes, res) }) } } diff --git a/pkg/keymanagementprovider/azurekeyvault/types/types.go b/pkg/keymanagementprovider/azurekeyvault/types/types.go index cae860773..e51650dab 100644 --- a/pkg/keymanagementprovider/azurekeyvault/types/types.go +++ b/pkg/keymanagementprovider/azurekeyvault/types/types.go @@ -26,7 +26,7 @@ const ( // Certificate version string for the certificate status property StatusVersion = "Version" // Enabled string for the certificate status property - StatusEnabled = "True" + StatusEnabled = "Enabled" // Last refreshed string for the certificate status property StatusLastRefreshed = "LastRefreshed" ) From 9b5d31b810a2fdd979e297c17d2c80151c15f475 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Nov 2024 14:55:40 +0800 Subject: [PATCH 47/62] chore: Bump step-security/harden-runner from 2.10.1 to 2.10.2 (#1938) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build-pr.yml | 2 +- .github/workflows/cache-cleanup.yml | 2 +- .github/workflows/clean-dev-package.yml | 2 +- .github/workflows/codeql.yml | 2 +- .github/workflows/e2e-aks.yml | 2 +- .github/workflows/e2e-cli.yml | 8 ++++---- .github/workflows/e2e-k8s.yml | 2 +- .github/workflows/golangci-lint.yml | 2 +- .github/workflows/high-availability.yml | 2 +- .github/workflows/pr-to-main.yml | 2 +- .github/workflows/publish-charts.yml | 2 +- .github/workflows/publish-cosign-sample.yml | 2 +- .github/workflows/publish-dev-assets.yml | 2 +- .github/workflows/publish-package.yml | 2 +- .github/workflows/publish-sample.yml | 2 +- .github/workflows/quick-start.yml | 2 +- .github/workflows/release.yml | 2 +- .github/workflows/run-full-validation.yml | 2 +- .github/workflows/scan-vulns.yaml | 4 ++-- .github/workflows/scorecards.yml | 2 +- .github/workflows/sync-gh-pages.yml | 2 +- 21 files changed, 25 insertions(+), 25 deletions(-) diff --git a/.github/workflows/build-pr.yml b/.github/workflows/build-pr.yml index 272f4333e..830471faf 100644 --- a/.github/workflows/build-pr.yml +++ b/.github/workflows/build-pr.yml @@ -70,7 +70,7 @@ jobs: environment: azure-test steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit diff --git a/.github/workflows/cache-cleanup.yml b/.github/workflows/cache-cleanup.yml index 46042f7f1..af26b9253 100644 --- a/.github/workflows/cache-cleanup.yml +++ b/.github/workflows/cache-cleanup.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit diff --git a/.github/workflows/clean-dev-package.yml b/.github/workflows/clean-dev-package.yml index 0a53bd8d0..0cbdbb534 100644 --- a/.github/workflows/clean-dev-package.yml +++ b/.github/workflows/clean-dev-package.yml @@ -13,7 +13,7 @@ jobs: packages: write steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 1c826c942..2992d208e 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -26,7 +26,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit diff --git a/.github/workflows/e2e-aks.yml b/.github/workflows/e2e-aks.yml index 2cb7fbdf4..395d85471 100644 --- a/.github/workflows/e2e-aks.yml +++ b/.github/workflows/e2e-aks.yml @@ -28,7 +28,7 @@ jobs: contents: read steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit diff --git a/.github/workflows/e2e-cli.yml b/.github/workflows/e2e-cli.yml index 658154bf4..4899630bc 100644 --- a/.github/workflows/e2e-cli.yml +++ b/.github/workflows/e2e-cli.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit @@ -34,7 +34,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit @@ -63,7 +63,7 @@ jobs: contents: read steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit @@ -93,7 +93,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit diff --git a/.github/workflows/e2e-k8s.yml b/.github/workflows/e2e-k8s.yml index 2d911b56b..1b22314b4 100644 --- a/.github/workflows/e2e-k8s.yml +++ b/.github/workflows/e2e-k8s.yml @@ -26,7 +26,7 @@ jobs: contents: read steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index f6eaa9331..7d903f64d 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit diff --git a/.github/workflows/high-availability.yml b/.github/workflows/high-availability.yml index be5281354..e64c6923f 100644 --- a/.github/workflows/high-availability.yml +++ b/.github/workflows/high-availability.yml @@ -30,7 +30,7 @@ jobs: DAPR_VERSION: ["1.13.2"] steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit diff --git a/.github/workflows/pr-to-main.yml b/.github/workflows/pr-to-main.yml index 325158903..df966cf9e 100644 --- a/.github/workflows/pr-to-main.yml +++ b/.github/workflows/pr-to-main.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit diff --git a/.github/workflows/publish-charts.yml b/.github/workflows/publish-charts.yml index fd1d16a25..aa2069e47 100644 --- a/.github/workflows/publish-charts.yml +++ b/.github/workflows/publish-charts.yml @@ -13,7 +13,7 @@ jobs: contents: write steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit diff --git a/.github/workflows/publish-cosign-sample.yml b/.github/workflows/publish-cosign-sample.yml index 36f3a897c..e2064dbf9 100644 --- a/.github/workflows/publish-cosign-sample.yml +++ b/.github/workflows/publish-cosign-sample.yml @@ -20,7 +20,7 @@ jobs: id-token: write steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit diff --git a/.github/workflows/publish-dev-assets.yml b/.github/workflows/publish-dev-assets.yml index 0426b2bf7..520700d17 100644 --- a/.github/workflows/publish-dev-assets.yml +++ b/.github/workflows/publish-dev-assets.yml @@ -17,7 +17,7 @@ jobs: environment: azure-publish steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit - name: Checkout diff --git a/.github/workflows/publish-package.yml b/.github/workflows/publish-package.yml index 11bee4cee..f0c73dd60 100644 --- a/.github/workflows/publish-package.yml +++ b/.github/workflows/publish-package.yml @@ -16,7 +16,7 @@ jobs: contents: read steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit - name: Checkout diff --git a/.github/workflows/publish-sample.yml b/.github/workflows/publish-sample.yml index 52981797d..54a2157a2 100644 --- a/.github/workflows/publish-sample.yml +++ b/.github/workflows/publish-sample.yml @@ -19,7 +19,7 @@ jobs: packages: write steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit diff --git a/.github/workflows/quick-start.yml b/.github/workflows/quick-start.yml index 1655d725f..b35a5bf09 100644 --- a/.github/workflows/quick-start.yml +++ b/.github/workflows/quick-start.yml @@ -30,7 +30,7 @@ jobs: KUBERNETES_VERSION: ["1.29.2"] steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5479ad24c..6cccec5eb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -16,7 +16,7 @@ jobs: contents: write steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit diff --git a/.github/workflows/run-full-validation.yml b/.github/workflows/run-full-validation.yml index 4b2c13f19..fefb937ea 100644 --- a/.github/workflows/run-full-validation.yml +++ b/.github/workflows/run-full-validation.yml @@ -58,7 +58,7 @@ jobs: environment: azure-test steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit diff --git a/.github/workflows/scan-vulns.yaml b/.github/workflows/scan-vulns.yaml index fc9d9c9a9..3a9fbba85 100644 --- a/.github/workflows/scan-vulns.yaml +++ b/.github/workflows/scan-vulns.yaml @@ -23,7 +23,7 @@ jobs: timeout-minutes: 15 steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit @@ -41,7 +41,7 @@ jobs: TRIVY_VERSION: 0.49.1 steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index cbcc0e24b..4bd37abca 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -30,7 +30,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit diff --git a/.github/workflows/sync-gh-pages.yml b/.github/workflows/sync-gh-pages.yml index 54a05e0cb..55069d724 100644 --- a/.github/workflows/sync-gh-pages.yml +++ b/.github/workflows/sync-gh-pages.yml @@ -17,7 +17,7 @@ jobs: repository-projects: write steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit From 04d1de702582547c49a3f5313cfb923b642fd1df Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 20 Nov 2024 14:03:15 +0800 Subject: [PATCH 48/62] chore: Bump codecov/codecov-action from 5.0.2 to 5.0.4 (#1939) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/e2e-cli.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/e2e-cli.yml b/.github/workflows/e2e-cli.yml index 4899630bc..1370108e5 100644 --- a/.github/workflows/e2e-cli.yml +++ b/.github/workflows/e2e-cli.yml @@ -51,7 +51,7 @@ jobs: - name: Check build run: bin/ratify version - name: Upload coverage to codecov.io - uses: codecov/codecov-action@5c47607acb93fed5485fdbf7232e8a31425f672a # v5.0.2 + uses: codecov/codecov-action@985343d70564a82044c1b7fcb84c2fa05405c1a2 # v5.0.4 with: token: ${{ secrets.CODECOV_TOKEN }} - name: Run helm lint @@ -86,7 +86,7 @@ jobs: make install ratify-config install-bats make test-e2e-cli GOCOVERDIR=${GITHUB_WORKSPACE}/test/e2e/.cover - name: Upload coverage to codecov.io - uses: codecov/codecov-action@5c47607acb93fed5485fdbf7232e8a31425f672a # v5.0.2 + uses: codecov/codecov-action@985343d70564a82044c1b7fcb84c2fa05405c1a2 # v5.0.4 with: token: ${{ secrets.CODECOV_TOKEN }} markdown-link-check: From 675a5d6a1649e1484156be87fb4fe548634e9b98 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 14:16:13 +0800 Subject: [PATCH 49/62] chore: Bump codecov/codecov-action from 5.0.4 to 5.0.7 (#1946) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/e2e-cli.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/e2e-cli.yml b/.github/workflows/e2e-cli.yml index 1370108e5..bd12aab63 100644 --- a/.github/workflows/e2e-cli.yml +++ b/.github/workflows/e2e-cli.yml @@ -51,7 +51,7 @@ jobs: - name: Check build run: bin/ratify version - name: Upload coverage to codecov.io - uses: codecov/codecov-action@985343d70564a82044c1b7fcb84c2fa05405c1a2 # v5.0.4 + uses: codecov/codecov-action@015f24e6818733317a2da2edd6290ab26238649a # v5.0.7 with: token: ${{ secrets.CODECOV_TOKEN }} - name: Run helm lint @@ -86,7 +86,7 @@ jobs: make install ratify-config install-bats make test-e2e-cli GOCOVERDIR=${GITHUB_WORKSPACE}/test/e2e/.cover - name: Upload coverage to codecov.io - uses: codecov/codecov-action@985343d70564a82044c1b7fcb84c2fa05405c1a2 # v5.0.4 + uses: codecov/codecov-action@015f24e6818733317a2da2edd6290ab26238649a # v5.0.7 with: token: ${{ secrets.CODECOV_TOKEN }} markdown-link-check: From 6c5604bca401ae12a7e8522f88f67f704e262084 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 06:45:15 +0000 Subject: [PATCH 50/62] chore: Bump github/codeql-action from 3.27.4 to 3.27.5 (#1945) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/codeql.yml | 4 ++-- .github/workflows/scorecards.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 2992d208e..1d408b41e 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -37,7 +37,7 @@ jobs: with: go-version: "1.22" - name: Initialize CodeQL - uses: github/codeql-action/init@ea9e4e37992a54ee68a9622e985e60c8e8f12d9f # tag=v3.27.4 + uses: github/codeql-action/init@f09c1c0a94de965c15400f5634aa42fac8fb8f88 # tag=v3.27.5 with: languages: go - name: Run tidy @@ -45,4 +45,4 @@ jobs: - name: Build CLI run: make build - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@ea9e4e37992a54ee68a9622e985e60c8e8f12d9f # tag=v3.27.4 + uses: github/codeql-action/analyze@f09c1c0a94de965c15400f5634aa42fac8fb8f88 # tag=v3.27.5 diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 4bd37abca..db16e41f7 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -55,6 +55,6 @@ jobs: retention-days: 5 - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@ea9e4e37992a54ee68a9622e985e60c8e8f12d9f # tag=v3.27.4 + uses: github/codeql-action/upload-sarif@f09c1c0a94de965c15400f5634aa42fac8fb8f88 # tag=v3.27.5 with: sarif_file: results.sarif From b31e2509aa58eb5441a9277a4b5091e0e61b60c6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 22 Nov 2024 15:05:17 +0800 Subject: [PATCH 51/62] chore: Bump anchore/sbom-action from 0.17.7 to 0.17.8 (#1948) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6cccec5eb..b323cfe6f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -26,7 +26,7 @@ jobs: fetch-depth: 0 - name: Install Syft - uses: anchore/sbom-action/download-syft@fc46e51fd3cb168ffb36c6d1915723c47db58abb # v0.17.7 + uses: anchore/sbom-action/download-syft@55dc4ee22412511ee8c3142cbea40418e6cec693 # v0.17.8 - name: Set up Go uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 From 67cd411188cfba880257203eee0aff21fcf0db2e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Nov 2024 05:46:51 +0000 Subject: [PATCH 52/62] chore: Bump github.com/aws/aws-sdk-go-v2/credentials from 1.17.45 to 1.17.46 (#1953) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 34 ++++++++++++++++------------------ go.sum | 48 ++++++++++++++++++++++-------------------------- 2 files changed, 38 insertions(+), 44 deletions(-) diff --git a/go.mod b/go.mod index cadcd367c..36a15b0db 100644 --- a/go.mod +++ b/go.mod @@ -9,23 +9,21 @@ retract ( ) require ( - github.com/Azure/azure-sdk-for-go v68.0.0+incompatible github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 github.com/Azure/azure-sdk-for-go/sdk/containers/azcontainerregistry v0.2.2 - github.com/Azure/go-autorest/autorest/to v0.4.0 + github.com/Azure/azure-sdk-for-go/sdk/keyvault/azcertificates v0.9.0 + github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys v0.10.0 + github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.12.0 github.com/AzureAD/microsoft-authentication-library-for-go v1.2.3 github.com/alibabacloud-go/cr-20181201/v2 v2.5.0 github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.10 github.com/alibabacloud-go/tea v1.2.2 github.com/alibabacloud-go/tea-utils/v2 v2.0.7 github.com/aliyun/credentials-go v1.3.11 - github.com/aws/aws-sdk-go-v2 v1.32.4 - github.com/Azure/azure-sdk-for-go/sdk/keyvault/azcertificates v0.9.0 - github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys v0.10.0 - github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.12.0 + github.com/aws/aws-sdk-go-v2 v1.32.5 github.com/aws/aws-sdk-go-v2/config v1.27.43 - github.com/aws/aws-sdk-go-v2/credentials v1.17.45 + github.com/aws/aws-sdk-go-v2/credentials v1.17.46 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 @@ -70,10 +68,10 @@ require ( cloud.google.com/go/compute/metadata v0.3.0 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/alibabacloudsdkgo/helper v0.2.0 // indirect + github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.1 // indirect github.com/Azure/go-autorest/autorest/azure/auth v0.5.12 // indirect github.com/Azure/go-autorest/autorest/azure/cli v0.4.6 // indirect - github.com/Azure/go-autorest/autorest/validation v0.3.1 // indirect github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect github.com/ProtonMail/go-crypto v0.0.0-20230923063757-afb1ddc0824c // indirect @@ -90,7 +88,7 @@ require ( github.com/alibabacloud-go/tea-xml v1.1.3 // indirect github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092 // indirect github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.23.7 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 // indirect github.com/aws/aws-sdk-go-v2/service/kms v1.31.3 // indirect github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20231024185945-8841054dbdb8 // indirect github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb27589 // indirect @@ -141,22 +139,22 @@ require ( require ( github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect - github.com/Azure/go-autorest/autorest v0.11.29 + github.com/Azure/go-autorest/autorest v0.11.29 // indirect github.com/Azure/go-autorest/autorest/adal v0.9.24 // indirect github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect github.com/Azure/go-autorest/logger v0.2.1 // indirect 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.19 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.23 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.23 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.20 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.24 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.24 // 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.12.4 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.24.5 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.4 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.33.0 // indirect - github.com/aws/smithy-go v1.22.0 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.5 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.24.6 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.5 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.33.1 // indirect + github.com/aws/smithy-go v1.22.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver v3.5.1+incompatible // indirect github.com/bshuster-repo/logrus-logstash-hook v1.1.0 diff --git a/go.sum b/go.sum index 35a0ef1a9..0698a0046 100644 --- a/go.sum +++ b/go.sum @@ -57,10 +57,6 @@ github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSY github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= github.com/Azure/go-autorest/autorest/mocks v0.4.2 h1:PGN4EDXnuQbojHbU0UWoNvmu9AGVwYHG9/fkDYhtAfw= github.com/Azure/go-autorest/autorest/mocks v0.4.2/go.mod h1:Vy7OitM9Kei0i1Oj+LvyAWMXJHeKH1MVlzFugfVrmyU= -github.com/Azure/go-autorest/autorest/to v0.4.0 h1:oXVqrxakqqV1UZdSazDOPOLvOIz+XA683u8EctwboHk= -github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcPR4o9jEImooCeWJcYV/zLE= -github.com/Azure/go-autorest/autorest/validation v0.3.1 h1:AgyqjAd94fwNAoTjl/WQXg4VvFeRFpO+UhNyRXqF1ac= -github.com/Azure/go-autorest/autorest/validation v0.3.1/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E= github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg= github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= @@ -163,38 +159,38 @@ 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.32.4 h1:S13INUiTxgrPueTmrm5DZ+MiAo99zYzHEFh1UNkOxNE= -github.com/aws/aws-sdk-go-v2 v1.32.4/go.mod h1:2SK5n0a2karNTv5tbP1SjsX0uhttou00v/HpXKM1ZUo= +github.com/aws/aws-sdk-go-v2 v1.32.5 h1:U8vdWJuY7ruAkzaOdD7guwJjD06YSKmnKCJs7s3IkIo= +github.com/aws/aws-sdk-go-v2 v1.32.5/go.mod h1:P5WJBrYqqbWVaOxgH0X/FYYD47/nooaPOZPlQdmiN2U= github.com/aws/aws-sdk-go-v2/config v1.27.43 h1:p33fDDihFC390dhhuv8nOmX419wjOSDQRb+USt20RrU= github.com/aws/aws-sdk-go-v2/config v1.27.43/go.mod h1:pYhbtvg1siOOg8h5an77rXle9tVG8T+BWLWAo7cOukc= -github.com/aws/aws-sdk-go-v2/credentials v1.17.45 h1:DUgm5lFso57E7150RBgu1JpVQoF8fAPretiDStIuVjg= -github.com/aws/aws-sdk-go-v2/credentials v1.17.45/go.mod h1:dnBpENcPC1ekZrGpSWspX+ZRGzhkvqngT2Qp5xBR1dY= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.19 h1:woXadbf0c7enQ2UGCi8gW/WuKmE0xIzxBF/eD94jMKQ= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.19/go.mod h1:zminj5ucw7w0r65bP6nhyOd3xL6veAUMc3ElGMoLVb4= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.23 h1:A2w6m6Tmr+BNXjDsr7M90zkWjsu4JXHwrzPg235STs4= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.23/go.mod h1:35EVp9wyeANdujZruvHiQUAo9E3vbhnIO1mTCAxMlY0= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.23 h1:pgYW9FCabt2M25MoHYCfMrVY2ghiiBKYWUVXfwZs+sU= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.23/go.mod h1:c48kLgzO19wAu3CPkDWC28JbaJ+hfQlsdl7I2+oqIbk= +github.com/aws/aws-sdk-go-v2/credentials v1.17.46 h1:AU7RcriIo2lXjUfHFnFKYsLCwgbz1E7Mm95ieIRDNUg= +github.com/aws/aws-sdk-go-v2/credentials v1.17.46/go.mod h1:1FmYyLGL08KQXQ6mcTlifyFXfJVCNJTVGuQP4m0d/UA= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.20 h1:sDSXIrlsFSFJtWKLQS4PUWRvrT580rrnuLydJrCQ/yA= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.20/go.mod h1:WZ/c+w0ofps+/OUqMwWgnfrgzZH1DZO1RIkktICsqnY= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.24 h1:4usbeaes3yJnCFC7kfeyhkdkPtoRYPa/hTmCqMpKpLI= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.24/go.mod h1:5CI1JemjVwde8m2WG3cz23qHKPOxbpkq0HaoreEgLIY= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.24 h1:N1zsICrQglfzaBnrfM0Ys00860C+QFwu6u/5+LomP+o= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.24/go.mod h1:dCn9HbJ8+K31i8IQ8EWmWj0EiIk0+vKiHNMxTTYveAg= 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= github.com/aws/aws-sdk-go-v2/service/ecr v1.28.6/go.mod h1:1FKdZMR/Tfx40IKjdLDRlFz/UKlff8CKQuC7mhlTAMM= github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.23.7 h1:dsmihXaPkhFuUTiL+ygm9RtUYEmhOeIl7DXNIHCoKDg= 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.12.0 h1:TToQNkvGguu209puTojY/ozlqy2d/SFNcoLIqTFi42g= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0/go.mod h1:0jp+ltwkf+SwG2fm/PKo8t4y8pJSgOCO4D8Lz3k0aHQ= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.4 h1:tHxQi/XHPK0ctd/wdOw0t7Xrc2OxcRCnVzv8lwWPu0c= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.4/go.mod h1:4GQbF1vJzG60poZqWatZlhP31y8PGCCVTvIGPdaaYJ0= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 h1:iXtILhvDxB6kPvEXgsDhGaZCSC6LQET5ZHSdJozeI0Y= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1/go.mod h1:9nu0fVANtYiAePIBh2/pFUSwtJ402hLnp854CNoDOeE= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.5 h1:wtpJ4zcwrSbwhECWQoI/g6WM9zqCcSpHDJIWSbMLOu4= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.5/go.mod h1:qu/W9HXQbbQ4+1+JcZp0ZNPV31ym537ZJN+fiS7Ti8E= 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.24.5 h1:HJwZwRt2Z2Tdec+m+fPjvdmkq2s9Ra+VR0hjF7V2o40= -github.com/aws/aws-sdk-go-v2/service/sso v1.24.5/go.mod h1:wrMCEwjFPms+V86TCQQeOxQF/If4vT44FGIOFiMC2ck= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.4 h1:zcx9LiGWZ6i6pjdcoE9oXAB6mUdeyC36Ia/QEiIvYdg= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.4/go.mod h1:Tp/ly1cTjRLGBBmNccFumbZ8oqpZlpdhFf80SrRh4is= -github.com/aws/aws-sdk-go-v2/service/sts v1.33.0 h1:s7LRgBqhwLaxcocnAniBJp7gaAB+4I4vHzqUqjH18yc= -github.com/aws/aws-sdk-go-v2/service/sts v1.33.0/go.mod h1:9XEUty5v5UAsMiFOBJrNibZgwCeOma73jgGwwhgffa8= -github.com/aws/smithy-go v1.22.0 h1:uunKnWlcoL3zO7q+gG2Pk53joueEOsnNB28QdMsmiMM= -github.com/aws/smithy-go v1.22.0/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= +github.com/aws/aws-sdk-go-v2/service/sso v1.24.6 h1:3zu537oLmsPfDMyjnUS2g+F2vITgy5pB74tHI+JBNoM= +github.com/aws/aws-sdk-go-v2/service/sso v1.24.6/go.mod h1:WJSZH2ZvepM6t6jwu4w/Z45Eoi75lPN7DcydSRtJg6Y= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.5 h1:K0OQAsDywb0ltlFrZm0JHPY3yZp/S9OaoLU33S7vPS8= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.5/go.mod h1:ORITg+fyuMoeiQFiVGoqB3OydVTLkClw/ljbblMq6Cc= +github.com/aws/aws-sdk-go-v2/service/sts v1.33.1 h1:6SZUVRQNvExYlMLbHdlKB48x0fLbc2iVROyaNEwBHbU= +github.com/aws/aws-sdk-go-v2/service/sts v1.33.1/go.mod h1:GqWyYCwLXnlUB1lOAXQyNSPqPLQJvmo8J0DWBzp9mtg= +github.com/aws/smithy-go v1.22.1 h1:/HPHZQ0g7f4eUeK6HKglFz8uwVfZKgoI25rb/J+dnro= +github.com/aws/smithy-go v1.22.1/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= github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20231024185945-8841054dbdb8/go.mod h1:2JF49jcDOrLStIXN/j/K1EKRq8a8R2qRnlZA6/o/c7c= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= From aae1aa6ee59d59a516d17caf5728908f7d253c3b Mon Sep 17 00:00:00 2001 From: Akash Singhal Date: Mon, 25 Nov 2024 16:38:57 -0800 Subject: [PATCH 53/62] fix: add missing pod annotations and labels to deployment spec (#1949) Signed-off-by: akashsinghal --- charts/ratify/templates/_helpers.tpl | 8 +++++++- charts/ratify/templates/deployment.yaml | 2 ++ charts/ratify/templates/upgrade-crds-hook.yaml | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/charts/ratify/templates/_helpers.tpl b/charts/ratify/templates/_helpers.tpl index cc56acb9e..db0e4da18 100644 --- a/charts/ratify/templates/_helpers.tpl +++ b/charts/ratify/templates/_helpers.tpl @@ -8,7 +8,13 @@ Expand the name of the chart. {{- define "ratify.podLabels" -}} {{- if .Values.podLabels }} -{{- toYaml .Values.podLabels | nindent 8 }} +{{- toYaml .Values.podLabels }} +{{- end }} +{{- end }} + +{{- define "ratify.podAnnotations" -}} +{{- if .Values.podAnnotations }} +{{- toYaml .Values.podAnnotations }} {{- end }} {{- end }} diff --git a/charts/ratify/templates/deployment.yaml b/charts/ratify/templates/deployment.yaml index 46ed544ae..3c3a630ee 100644 --- a/charts/ratify/templates/deployment.yaml +++ b/charts/ratify/templates/deployment.yaml @@ -13,11 +13,13 @@ spec: template: metadata: labels: + {{- include "ratify.podLabels" . | nindent 8 }} {{- include "ratify.selectorLabels" . | nindent 8 }} {{- if ne .Values.azureWorkloadIdentity.clientId "" }} azure.workload.identity/use: "true" {{- end }} annotations: + {{- include "ratify.podAnnotations" . | nindent 8 }} {{- if eq .Values.instrumentation.metricsType "prometheus" }} prometheus.io/scrape: "true" prometheus.io/port: {{ .Values.instrumentation.metricsPort | quote }} diff --git a/charts/ratify/templates/upgrade-crds-hook.yaml b/charts/ratify/templates/upgrade-crds-hook.yaml index a843c66cc..48e21f020 100644 --- a/charts/ratify/templates/upgrade-crds-hook.yaml +++ b/charts/ratify/templates/upgrade-crds-hook.yaml @@ -78,7 +78,7 @@ spec: annotations: {{- toYaml .Values.podAnnotations | trim | nindent 8 }} labels: - {{- include "ratify.podLabels" . }} + {{- include "ratify.podLabels" . | nindent 8 }} app: '{{ template "ratify.name" . }}' chart: '{{ template "ratify.name" . }}' ratify.sh/system: "yes" From 6a719c9ec18909c16ae44664e945854c894b3474 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 29 Nov 2024 18:11:51 +0800 Subject: [PATCH 54/62] chore: Bump github.com/sigstore/rekor from 1.3.6 to 1.3.7 (#1952) Signed-off-by: dependabot[bot] Signed-off-by: Susan Shi Signed-off-by: Binbin Li Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 65 ++++++------ go.sum | 225 ++++++++++++++++++++++-------------------- httpserver/Dockerfile | 2 +- 3 files changed, 153 insertions(+), 139 deletions(-) diff --git a/go.mod b/go.mod index 36a15b0db..df833b0ce 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/ratify-project/ratify -go 1.22.8 +go 1.23.3 // Accidentally published prior to 1.0.0 release retract ( @@ -9,8 +9,8 @@ retract ( ) require ( - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 - github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0 + github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0 github.com/Azure/azure-sdk-for-go/sdk/containers/azcontainerregistry v0.2.2 github.com/Azure/azure-sdk-for-go/sdk/keyvault/azcertificates v0.9.0 github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys v0.10.0 @@ -22,7 +22,7 @@ require ( github.com/alibabacloud-go/tea-utils/v2 v2.0.7 github.com/aliyun/credentials-go v1.3.11 github.com/aws/aws-sdk-go-v2 v1.32.5 - github.com/aws/aws-sdk-go-v2/config v1.27.43 + github.com/aws/aws-sdk-go-v2/config v1.28.3 github.com/aws/aws-sdk-go-v2/credentials v1.17.46 github.com/aws/aws-sdk-go-v2/service/ecr v1.28.6 github.com/cespare/xxhash/v2 v2.3.0 @@ -53,11 +53,11 @@ require ( github.com/spf13/cobra v1.8.1 github.com/xlab/treeprint v1.1.0 go.opentelemetry.io/otel/exporters/prometheus v0.49.0 - go.opentelemetry.io/otel/metric v1.28.0 + go.opentelemetry.io/otel/metric v1.29.0 go.opentelemetry.io/otel/sdk/metric v1.27.0 - golang.org/x/sync v0.8.0 - google.golang.org/grpc v1.66.3 - google.golang.org/protobuf v1.34.2 + golang.org/x/sync v0.9.0 + google.golang.org/grpc v1.68.0 + google.golang.org/protobuf v1.35.2 k8s.io/api v0.28.15 k8s.io/apimachinery v0.28.15 k8s.io/client-go v0.28.15 @@ -65,7 +65,7 @@ require ( ) require ( - cloud.google.com/go/compute/metadata v0.3.0 // indirect + cloud.google.com/go/compute/metadata v0.5.2 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/alibabacloudsdkgo/helper v0.2.0 // indirect github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect @@ -89,7 +89,6 @@ require ( github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092 // indirect github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.23.7 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 // indirect - github.com/aws/aws-sdk-go-v2/service/kms v1.31.3 // indirect github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20231024185945-8841054dbdb8 // indirect github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb27589 // indirect github.com/clbanning/mxj/v2 v2.7.0 // indirect @@ -130,10 +129,10 @@ require ( github.com/tjfoc/gmsm v1.4.1 // indirect github.com/xanzy/go-gitlab v0.102.0 // indirect github.com/yashtewari/glob-intersection v0.2.0 // indirect - go.step.sm/crypto v0.44.2 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect + go.step.sm/crypto v0.54.2 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20241104194629-dd2ea8efbc28 // indirect gotest.tools/v3 v3.1.0 // indirect - sigs.k8s.io/release-utils v0.7.7 // indirect + sigs.k8s.io/release-utils v0.8.5 // indirect ) require ( @@ -179,7 +178,7 @@ require ( github.com/go-openapi/validate v0.24.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v4 v4.5.1 // indirect - github.com/golang/glog v1.2.1 // indirect + github.com/golang/glog v1.2.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/certificate-transparency-go v1.1.8 // indirect @@ -191,7 +190,7 @@ require ( github.com/in-toto/in-toto-golang v0.9.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267 // indirect - github.com/jmespath/go-jmespath v0.4.0 // indirect + github.com/jmespath/go-jmespath v0.4.1-0.20220621161143-b0104c826a24 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.17.9 // indirect @@ -206,7 +205,7 @@ require ( github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/oklog/ulid v1.3.1 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect - github.com/pelletier/go-toml/v2 v2.1.0 // indirect + github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_golang v1.20.5 @@ -217,11 +216,11 @@ require ( github.com/sassoftware/relic v7.2.1+incompatible // indirect github.com/secure-systems-lab/go-securesystemslib v0.8.0 // indirect github.com/shibumi/go-pathspec v1.3.0 // indirect - github.com/sigstore/rekor v1.3.6 + github.com/sigstore/rekor v1.3.7 github.com/spf13/afero v1.11.0 // indirect - github.com/spf13/cast v1.6.0 // indirect + github.com/spf13/cast v1.7.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/spf13/viper v1.18.2 // indirect + github.com/spf13/viper v1.19.0 // indirect github.com/stretchr/testify v1.9.0 github.com/subosito/gotenv v1.6.0 // indirect github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect @@ -229,27 +228,27 @@ require ( github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect github.com/transparency-dev/merkle v0.0.2 // indirect github.com/vbatts/tar-split v0.11.5 // indirect - github.com/veraison/go-cose v1.2.1 // indirect + github.com/veraison/go-cose v1.3.0 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonschema v1.2.0 go.mongodb.org/mongo-driver v1.14.0 // indirect - go.opentelemetry.io/otel v1.28.0 + go.opentelemetry.io/otel v1.29.0 go.opentelemetry.io/otel/sdk v1.28.0 - go.opentelemetry.io/otel/trace v1.28.0 // indirect + go.opentelemetry.io/otel/trace v1.29.0 // indirect go.uber.org/atomic v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect - golang.org/x/crypto v0.28.0 - golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 // indirect - golang.org/x/mod v0.21.0 // indirect - golang.org/x/net v0.29.0 // indirect - golang.org/x/oauth2 v0.23.0 // indirect - golang.org/x/sys v0.26.0 // indirect - golang.org/x/term v0.25.0 // indirect - golang.org/x/text v0.19.0 // indirect - golang.org/x/time v0.6.0 // indirect + golang.org/x/crypto v0.29.0 + golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 // indirect + golang.org/x/mod v0.22.0 // indirect + golang.org/x/net v0.31.0 // indirect + golang.org/x/oauth2 v0.24.0 // indirect + golang.org/x/sys v0.27.0 // indirect + golang.org/x/term v0.26.0 // indirect + golang.org/x/text v0.20.0 // indirect + golang.org/x/time v0.8.0 // indirect gomodules.xyz/jsonpatch/v2 v2.3.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect @@ -257,9 +256,9 @@ require ( gopkg.in/yaml.v3 v3.0.1 k8s.io/apiextensions-apiserver v0.27.7 // indirect k8s.io/component-base v0.27.7 // indirect - k8s.io/klog/v2 v2.120.1 // indirect + k8s.io/klog/v2 v2.130.1 // indirect k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect - k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect + k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0 // indirect sigs.k8s.io/controller-runtime v0.15.3 sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/structured-merge-diff/v4 v4.3.0 // indirect diff --git a/go.sum b/go.sum index 0698a0046..2c68c5a8d 100644 --- a/go.sum +++ b/go.sum @@ -1,11 +1,18 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.112.1 h1:uJSeirPke5UNZHIb4SxfZklVSiWWVqW4oXlETwZziwM= -cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= -cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= -cloud.google.com/go/iam v1.1.6 h1:bEa06k05IO4f4uJonbB5iAgKTPpABy1ayxaIZV/GHVc= -cloud.google.com/go/iam v1.1.6/go.mod h1:O0zxdPeGBoFdWW3HWmBxJsk0pfvNM/p/qa82rWOGTwI= -cloud.google.com/go/kms v1.15.8 h1:szIeDCowID8th2i8XE4uRev5PMxQFqW+JjwYxL9h6xs= -cloud.google.com/go/kms v1.15.8/go.mod h1:WoUHcDjD9pluCg7pNds131awnH429QGvRM3N/4MyoVs= +cloud.google.com/go v0.116.0 h1:B3fRrSDkLRt5qSHWe40ERJvhvnQwdZiHu0bJOpldweE= +cloud.google.com/go v0.116.0/go.mod h1:cEPSRWPzZEswwdr9BxE6ChEn01dWlTaF05LiC2Xs70U= +cloud.google.com/go/auth v0.10.2 h1:oKF7rgBfSHdp/kuhXtqU/tNDr0mZqhYbEh+6SiqzkKo= +cloud.google.com/go/auth v0.10.2/go.mod h1:xxA5AqpDrvS+Gkmo9RqrGGRh6WSNKKOXhY3zNOr38tI= +cloud.google.com/go/auth/oauth2adapt v0.2.5 h1:2p29+dePqsCHPP1bqDJcKj4qxRyYCcbzKpFyKGt3MTk= +cloud.google.com/go/auth/oauth2adapt v0.2.5/go.mod h1:AlmsELtlEBnaNTL7jCj8VQFLy6mbZv0s4Q7NGBeQ5E8= +cloud.google.com/go/compute/metadata v0.5.2 h1:UxK4uu/Tn+I3p2dYWTfiX4wva7aYlKixAHn3fyqngqo= +cloud.google.com/go/compute/metadata v0.5.2/go.mod h1:C66sj2AluDcIqakBq/M8lw8/ybHgOZqin2obFxa/E5k= +cloud.google.com/go/iam v1.2.2 h1:ozUSofHUGf/F4tCNy/mu9tHLTaxZFLOUiKzjcgWHGIA= +cloud.google.com/go/iam v1.2.2/go.mod h1:0Ys8ccaZHdI1dEUilwzqng/6ps2YB6vRsjIe00/+6JY= +cloud.google.com/go/kms v1.20.1 h1:og29Wv59uf2FVaZlesaiDAqHFzHaoUyHI3HYp9VUHVg= +cloud.google.com/go/kms v1.20.1/go.mod h1:LywpNiVCvzYNJWS9JUcGJSVTNSwPwi0vBAotzDqn2nc= +cloud.google.com/go/longrunning v0.6.2 h1:xjDfh1pQcWPEvnfjZmwjKQEcHnpz6lHjfy7Fo0MK+hc= +cloud.google.com/go/longrunning v0.6.2/go.mod h1:k/vIs83RN4bE3YCswdXC5PFfWVILjm3hpEUlSko4PiI= cuelabs.dev/go/oci/ociregistry v0.0.0-20240314152124-224736b49f2e h1:GwCVItFUPxwdsEYnlUcJ6PJxOjTeFFCKOh6QWg4oAzQ= cuelabs.dev/go/oci/ociregistry v0.0.0-20240314152124-224736b49f2e/go.mod h1:ApHceQLLwcOkCEXM1+DyCXTHEJhNGDpJ2kmV6axsx24= cuelang.org/go v0.8.1 h1:VFYsxIFSPY5KgSaH1jQ2GxHOrbu6Ga3kEI70yCZwnOg= @@ -18,10 +25,12 @@ github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/alibabacloudsdkgo github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/alibabacloudsdkgo/helper v0.2.0/go.mod h1:GgeIE+1be8Ivm7Sh4RgwI42aTtC9qrcj+Y9Y6CjJhJs= github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU= github.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 h1:nyQWyZvwGTvunIMxi1Y9uXkcyr+I7TeNrr/foo4Kpk8= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0/go.mod h1:l38EPgmsp71HHLq9j7De57JcKOWPyhrsW1Awm1JS6K0= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 h1:tfLQ34V6F7tVSwoTf/4lH5sE0o6eCJuNDTmH09nDpbc= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0/go.mod h1:9kIvujWAA58nmPmWB1m23fyWic1kYZMxD9CxaWn4Qpg= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0 h1:JZg6HRh6W6U4OLl6lk7BZ7BLisIzM9dG1R50zUk9C/M= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0/go.mod h1:YL1xnZ6QejvQHWJrX/AvhFl4WW4rqHVoKspWNVwFk0M= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0 h1:B/dfvscEQtew9dVuoxqxrUKKv8Ih2f55PydknDamU+g= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0/go.mod h1:fiPSssYvltE08HJchL04dOy+RD4hgrjph0cwGGMntdI= +github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.0 h1:+m0M/LFxN43KvULkDNfdXOgrjtg6UYJPFBJyuEcRCAw= +github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.0/go.mod h1:PwOyop78lveYMRs6oCxjiVyBdyCgIYH6XHIVZO9/SFQ= github.com/Azure/azure-sdk-for-go/sdk/containers/azcontainerregistry v0.2.2 h1:wBx10efdJcl8FSewgc41kAW4AvHPgmJZmN7fpNxn8rc= github.com/Azure/azure-sdk-for-go/sdk/containers/azcontainerregistry v0.2.2/go.mod h1:zzmu18cpAinSbhC86oWd47nmgbb91Fl+Yac2PE8NdYk= github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY= @@ -63,6 +72,8 @@ github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUM github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= +github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM= +github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE= github.com/AzureAD/microsoft-authentication-library-for-go v1.2.3 h1:6LyjnnaLpcOKK0fbYisI+mb8CE7iNe7i89nMNQxFxs8= github.com/AzureAD/microsoft-authentication-library-for-go v1.2.3/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= @@ -157,12 +168,12 @@ github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= 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 v1.55.5 h1:KKUZBfBoyqy5d3swXyiC7Q76ic40rYcbqH7qjh59kzU= +github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= github.com/aws/aws-sdk-go-v2 v1.32.5 h1:U8vdWJuY7ruAkzaOdD7guwJjD06YSKmnKCJs7s3IkIo= github.com/aws/aws-sdk-go-v2 v1.32.5/go.mod h1:P5WJBrYqqbWVaOxgH0X/FYYD47/nooaPOZPlQdmiN2U= -github.com/aws/aws-sdk-go-v2/config v1.27.43 h1:p33fDDihFC390dhhuv8nOmX419wjOSDQRb+USt20RrU= -github.com/aws/aws-sdk-go-v2/config v1.27.43/go.mod h1:pYhbtvg1siOOg8h5an77rXle9tVG8T+BWLWAo7cOukc= +github.com/aws/aws-sdk-go-v2/config v1.28.3 h1:kL5uAptPcPKaJ4q0sDUjUIdueO18Q7JDzl64GpVwdOM= +github.com/aws/aws-sdk-go-v2/config v1.28.3/go.mod h1:SPEn1KA8YbgQnwiJ/OISU4fz7+F6Fe309Jf0QTsRCl4= github.com/aws/aws-sdk-go-v2/credentials v1.17.46 h1:AU7RcriIo2lXjUfHFnFKYsLCwgbz1E7Mm95ieIRDNUg= github.com/aws/aws-sdk-go-v2/credentials v1.17.46/go.mod h1:1FmYyLGL08KQXQ6mcTlifyFXfJVCNJTVGuQP4m0d/UA= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.20 h1:sDSXIrlsFSFJtWKLQS4PUWRvrT580rrnuLydJrCQ/yA= @@ -181,8 +192,8 @@ github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 h1:iXtILhv github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1/go.mod h1:9nu0fVANtYiAePIBh2/pFUSwtJ402hLnp854CNoDOeE= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.5 h1:wtpJ4zcwrSbwhECWQoI/g6WM9zqCcSpHDJIWSbMLOu4= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.5/go.mod h1:qu/W9HXQbbQ4+1+JcZp0ZNPV31ym537ZJN+fiS7Ti8E= -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/kms v1.37.5 h1:5dQJ6Q5QrQOqZxXjSbRXukBqU8Pgu6Ro6Qqtyd8yiz4= +github.com/aws/aws-sdk-go-v2/service/kms v1.37.5/go.mod h1:A9vfQcNHVBCE7ZZN6H+UUJpXtbH26Vv6L7Zhk5nIJAY= github.com/aws/aws-sdk-go-v2/service/sso v1.24.6 h1:3zu537oLmsPfDMyjnUS2g+F2vITgy5pB74tHI+JBNoM= github.com/aws/aws-sdk-go-v2/service/sso v1.24.6/go.mod h1:WJSZH2ZvepM6t6jwu4w/Z45Eoi75lPN7DcydSRtJg6Y= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.5 h1:K0OQAsDywb0ltlFrZm0JHPY3yZp/S9OaoLU33S7vPS8= @@ -208,8 +219,6 @@ github.com/buildkite/interpolate v0.0.0-20200526001904-07f35b4ae251/go.mod h1:gb github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/bytecodealliance/wasmtime-go/v3 v3.0.2 h1:3uZCA/BLTIu+DqCfguByNMJa2HVHpXvjfy0Dy7g6fuA= github.com/bytecodealliance/wasmtime-go/v3 v3.0.2/go.mod h1:RnUjnIXxEJcL6BgCvNyzCCRzZcxCgsZCi+RNlvYor5Q= -github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M= -github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -261,6 +270,8 @@ github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkz github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48 h1:fRzb/w+pyskVMQ+UbP35JkH8yB7MYb4q/qhBarqZE6g= github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= github.com/digitorus/pkcs7 v0.0.0-20230713084857-e76b763bdc49/go.mod h1:SKVExuS+vpu2l9IoOc0RwqE7NYnb0JlcFHFnEJkVDzc= @@ -371,8 +382,8 @@ github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.2.1 h1:OptwRhECazUx5ix5TTWC3EZhsZEHWcYWY4FQHTIubm4= -github.com/golang/glog v1.2.1/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= +github.com/golang/glog v1.2.2 h1:1+mZ9upx1Dh6FmUTFR1naJ77miKiXgALjWOZ3NVFPmY= +github.com/golang/glog v1.2.2/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= @@ -418,20 +429,20 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/ github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20231023181126-ff6d637d2a7b h1:RMpPgZTSApbPf7xaVel+QkoGPRLFLrwFO89uDUHEGf0= -github.com/google/pprof v0.0.0-20231023181126-ff6d637d2a7b/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= -github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= -github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= +github.com/google/pprof v0.0.0-20240528025155-186aa0362fba h1:ql1qNgCyOB7iAEk8JTNM+zJrgIbnyCKX/wdlyPufP5g= +github.com/google/pprof v0.0.0-20240528025155-186aa0362fba/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= +github.com/google/s2a-go v0.1.8 h1:zZDs9gcbt9ZPLV0ndSyQk6Kacx2g/X+SKYovpnz3SMM= +github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA= github.com/google/tink/go v1.7.0 h1:6Eox8zONGebBFcCBqkVmt60LaWZa6xg1cl/DwAh/J1w= github.com/google/tink/go v1.7.0/go.mod h1:GAUOd+QE3pgj9q8VKIGTCP33c/B7eb4NhxLcgTJZStM= -github.com/google/trillian v1.6.0 h1:jMBeDBIkINFvS2n6oV5maDqfRlxREAc6CW9QYWQ0qT4= -github.com/google/trillian v1.6.0/go.mod h1:Yu3nIMITzNhhMJEHjAtp6xKiu+H/iHu2Oq5FjV2mCWI= +github.com/google/trillian v1.6.1 h1:jWU5BGz24GQ5IsHNr+qbmISLkt+73jLv8BOIPN8RtD4= +github.com/google/trillian v1.6.1/go.mod h1:TvwtNkJViJgWZ5VmAMXDwsTjzPBHaPjQO85Kt37JPmM= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= -github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= -github.com/googleapis/gax-go/v2 v2.12.3 h1:5/zPPDvw8Q1SuXjrqrZslrqT7dL/uJT2CQii/cLCKqA= -github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBHwWRvkNFJUQcS4= +github.com/googleapis/enterprise-certificate-proxy v0.3.4 h1:XYIDZApgAnrN1c855gTgghdIA6Stxb52D5RnLI1SLyw= +github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA= +github.com/googleapis/gax-go/v2 v2.14.0 h1:f+jMrjBPl+DL9nI4IQzLUxMq7XrAqFYB7hBPqMNIe8o= +github.com/googleapis/gax-go/v2 v2.14.0/go.mod h1:lhBCnjdLrWRaPvLWhmc8IS24m9mr07qSYnHncrgo+zk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= @@ -464,8 +475,8 @@ github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/C github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/hcl v1.0.1-vault-5 h1:kI3hhbbyzr4dldA8UdTb7ZlVVlI2DACdCfz31RPDgJM= github.com/hashicorp/hcl v1.0.1-vault-5/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM= -github.com/hashicorp/vault/api v1.12.2 h1:7YkCTE5Ni90TcmYHDBExdt4WGJxhpzaHqR6uGbQb/rE= -github.com/hashicorp/vault/api v1.12.2/go.mod h1:LSGf1NGT1BnvFFnKVtnvcaLBM2Lz+gJdpL6HUYed8KE= +github.com/hashicorp/vault/api v1.15.0 h1:O24FYQCWwhwKnF7CuSqP30S51rTV7vz1iACXE/pj5DA= +github.com/hashicorp/vault/api v1.15.0/go.mod h1:+5YTO09JGn0u+b6ySD/LLVf8WkJCPLAL2Vkmrn2+CM8= github.com/howeyc/gopass v0.0.0-20210920133722-c8aef6fb66ef h1:A9HsByNhogrvm9cWb28sjiS3i7tcKCkflWFEkHfuAgM= github.com/howeyc/gopass v0.0.0-20210920133722-c8aef6fb66ef/go.mod h1:lADxMC39cJJqL93Duh1xhAs4I2Zs8mKS89XWXFGp9cs= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= @@ -490,11 +501,11 @@ github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZ github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267 h1:TMtDYDHKYY15rFihtRfck/bfFqNfvcabqvXAFQfAUpY= github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267/go.mod h1:h1nSAbGFqGVzn6Jyl1R/iCcBUHN4g+gW1u9CoBTrb9E= -github.com/jellydator/ttlcache/v3 v3.2.0 h1:6lqVJ8X3ZaUwvzENqPAobDsXNExfUJd61u++uW8a3LE= -github.com/jellydator/ttlcache/v3 v3.2.0/go.mod h1:hi7MGFdMAwZna5n2tuvh63DvFLzVKySzCVW6+0gA2n4= +github.com/jellydator/ttlcache/v3 v3.3.0 h1:BdoC9cE81qXfrxeb9eoJi9dWrdhSuwXMAnHTbnBm4Wc= +github.com/jellydator/ttlcache/v3 v3.3.0/go.mod h1:bj2/e0l4jRnQdrnSTaGTsh4GSXvMjQcy41i7th0GVGw= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= -github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath v0.4.1-0.20220621161143-b0104c826a24 h1:liMMTbpW34dhU4az1GN0pTPADwNmvoRSeoZ6PItiqnY= +github.com/jmespath/go-jmespath v0.4.1-0.20220621161143-b0104c826a24/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/jmhodges/clock v1.2.0 h1:eq4kys+NI0PLngzaHEe7AmPT90XMGIEySD1JfV1PDIs= @@ -505,6 +516,8 @@ github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6 h1:IsMZxCuZqKuao2vNdfD82fjjgPLfyHLpR41Z88viRWs= +github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6/go.mod h1:3VeWNIJaW+O5xpRQbPp0Ybqu1vJd/pm7s2F473HRrkw= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= @@ -600,8 +613,8 @@ github.com/owenrumney/go-sarif/v2 v2.3.3 h1:ubWDJcF5i3L/EIOER+ZyQ03IfplbSU1BLOE2 github.com/owenrumney/go-sarif/v2 v2.3.3/go.mod h1:MSqMMx9WqlBSY7pXoOZWgEsVB4FDNfhcaXDA1j6Sr+w= github.com/pborman/uuid v1.2.1 h1:+ZZIw58t/ozdjRaXh/3awHfmWRbzYxJoAdNJxe/3pvw= github.com/pborman/uuid v1.2.1/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= -github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= -github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= +github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= +github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -623,6 +636,8 @@ github.com/protocolbuffers/txtpbfmt v0.0.0-20231025115547-084445ff1adf h1:014O62 github.com/protocolbuffers/txtpbfmt v0.0.0-20231025115547-084445ff1adf/go.mod h1:jgxiZysxFPM+iWKwQwPR+y+Jvo54ARd4EisXxKYpB5c= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/redis/go-redis/v9 v9.7.0 h1:HhLSs+B6O021gwzl+locl0zEDnyNkxMtf/Z3NNBMa9E= +github.com/redis/go-redis/v9 v9.7.0/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -646,18 +661,18 @@ github.com/sigstore/cosign/v2 v2.2.4 h1:iY4vtEacmu2hkNj1Fh+8EBqBwKs2DHM27/lbNWDF github.com/sigstore/cosign/v2 v2.2.4/go.mod h1:JZlRD2uaEjVAvZ1XJ3QkkZJhTqSDVtLaet+C/TMR81Y= 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/rekor v1.3.7 h1:Z5UW5TmqbTZnyOFkMRfi32q/CWcxK6VuzIkx+33mbq8= +github.com/sigstore/rekor v1.3.7/go.mod h1:TihqJscZ6L6398x68EHY82t0AOnGYfrQ0siXe3WgbR4= github.com/sigstore/sigstore v1.8.10 h1:r4t+TYzJlG9JdFxMy+um9GZhZ2N1hBTyTex0AHEZxFs= github.com/sigstore/sigstore v1.8.10/go.mod h1:BekjqxS5ZtHNJC4u3Q3Stvfx2eyisbW/lUZzmPU2u4A= -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= -github.com/sigstore/sigstore/pkg/signature/kms/azure v1.8.3/go.mod h1:G4+I83FILPX6MtnoaUdmv/bRGEVtR3JdLeJa/kXdk/0= -github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.8.3 h1:vDl2fqPT0h3D/k6NZPlqnKFd1tz3335wm39qjvpZNJc= -github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.8.3/go.mod h1:9uOJXbXEXj+M6QjMKH5PaL5WDMu43rHfbIMgXzA8eKI= -github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.8.3 h1:h9G8j+Ds21zqqulDbA/R/ft64oQQIyp8S7wJYABYSlg= -github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.8.3/go.mod h1:zgCeHOuqF6k7A7TTEvftcA9V3FRzB7mrPtHOhXAQBnc= +github.com/sigstore/sigstore/pkg/signature/kms/aws v1.8.10 h1:e5GfVngPjGap/N3ODefayt7vKIPS1/v3hWLZ9+4MrN4= +github.com/sigstore/sigstore/pkg/signature/kms/aws v1.8.10/go.mod h1:HOr3AdFPKdND2FNl/sUD5ZifPl1OMJvrbf9xIaaWcus= +github.com/sigstore/sigstore/pkg/signature/kms/azure v1.8.10 h1:9tZEpfIL/ewAG9G87AHe3aVoy8Ujos2F1qLfCckX6jQ= +github.com/sigstore/sigstore/pkg/signature/kms/azure v1.8.10/go.mod h1:VnIAcitund62R45ezK/dtUeEhuRtB3LsAgJ8m0H34zc= +github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.8.10 h1:Xre51HdjIIaVo5ox5zyL+6h0tkrx7Ke9Neh7fLmmZK0= +github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.8.10/go.mod h1:VNfdklQDbyGJog8S7apdxiEfmYmCkKyxrsCL9xprkTY= +github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.8.10 h1:HjfjL3x3dP2kaGqQHVog974cTcKfzFaGjfZyLQ9KXrg= +github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.8.10/go.mod h1:jaeEjkTW1p3gUyPjz9lTcT4TydCs208FoyAwIs6bIT4= github.com/sigstore/timestamp-authority v1.2.2 h1:X4qyutnCQqJ0apMewFyx+3t7Tws00JQ/JonBiu3QvLE= github.com/sigstore/timestamp-authority v1.2.2/go.mod h1:nEah4Eq4wpliDjlY342rXclGSO7Kb9hoRrl9tqLW13A= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= @@ -677,15 +692,15 @@ github.com/spdx/tools-golang v0.5.5 h1:61c0KLfAcNqAjlg6UNMdkwpMernhw3zVRwDZ2x9XO github.com/spdx/tools-golang v0.5.5/go.mod h1:MVIsXx8ZZzaRWNQpUDhC4Dud34edUYJYecciXgrw5vE= github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= -github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= -github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w= +github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ= -github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= +github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= +github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= github.com/spiffe/go-spiffe/v2 v2.2.0 h1:9Vf06UsvsDbLYK/zJ4sYsIsHmMFknUD+feA7IYoWMQY= github.com/spiffe/go-spiffe/v2 v2.2.0/go.mod h1:Urzb779b3+IwDJD2ZbN8fVl3Aa8G4N/PiUe6iXC0XxU= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -726,8 +741,8 @@ github.com/transparency-dev/merkle v0.0.2 h1:Q9nBoQcZcgPamMkGn7ghV8XiTZ/kRxn1yCG github.com/transparency-dev/merkle v0.0.2/go.mod h1:pqSy+OXefQ1EDUVmAJ8MUhHB9TXGuzVAT58PqBoHz1A= github.com/vbatts/tar-split v0.11.5 h1:3bHCTIheBm1qFTcgh9oPu+nNBtX+XJIupG/vacinCts= github.com/vbatts/tar-split v0.11.5/go.mod h1:yZbwRsSeGjusneWgA781EKej9HF8vme8okylkAeNKLk= -github.com/veraison/go-cose v1.2.1 h1:Gj4x20D0YP79J2+cK3anjGEMwIkg2xX+TKVVGUXwNAc= -github.com/veraison/go-cose v1.2.1/go.mod h1:t6V8WJzHm1PD5HNsuDjW3KLv577uWb6UTzbZGvdQHD8= +github.com/veraison/go-cose v1.3.0 h1:2/H5w8kdSpQJyVtIhx8gmwPJ2uSz1PkyWFx0idbd7rk= +github.com/veraison/go-cose v1.3.0/go.mod h1:df09OV91aHoQWLmy1KsDdYiagtXgyAwAl8vFeFn1gMc= github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4= github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= @@ -768,30 +783,30 @@ go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.52.0 h1:vS1Ao/R55RNV4O7TA2Qopok8yN+X0LIP6RVWLFkprck= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.52.0/go.mod h1:BMsdeOxN04K0L5FNUBfjFdvwWGNe/rkmSwH4Aelu/X0= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg= -go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= -go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 h1:r6I7RJCN86bpD/FQwedZ0vSixDpwuWREjW9oRMsmqDc= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0/go.mod h1:B9yO6b04uB80CzjedvewuqDhxJxi11s7/GtiGa8bAjI= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8= +go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw= +go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 h1:R3X6ZXmNPRR8ul6i3WgFURCHzaXjHdm0karRG/+dj3s= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0/go.mod h1:QWFXnDavXWwMx2EEcZsf3yxgEKAqsxQ+Syjp+seyInw= go.opentelemetry.io/otel/exporters/prometheus v0.49.0 h1:Er5I1g/YhfYv9Affk9nJLfH/+qCCVVg1f2R9AbJfqDQ= go.opentelemetry.io/otel/exporters/prometheus v0.49.0/go.mod h1:KfQ1wpjf3zsHjzP149P4LyAwWRupc6c7t1ZJ9eXpKQM= -go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= -go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= +go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc= +go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8= go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE= go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg= go.opentelemetry.io/otel/sdk/metric v1.27.0 h1:5uGNOlpXi+Hbo/DRoI31BSb1v+OGcpv2NemcCrOL8gI= go.opentelemetry.io/otel/sdk/metric v1.27.0/go.mod h1:we7jJVrYN2kh3mVBlswtPU22K0SA+769l93J6bsyvqw= -go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= -go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= +go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4= +go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ= go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= -go.step.sm/crypto v0.44.2 h1:t3p3uQ7raP2jp2ha9P6xkQF85TJZh+87xmjSLaib+jk= -go.step.sm/crypto v0.44.2/go.mod h1:x1439EnFhadzhkuaGX7sz03LEMQ+jV4gRamf5LCZJQQ= +go.step.sm/crypto v0.54.2 h1:3LSA5nYDQvcd484OSx7xsS3XDqQ7/WZjVqvq0+a0fWc= +go.step.sm/crypto v0.54.2/go.mod h1:1+OjUozd5aA3TkBJfr5Aobd6vNt9F70n1DagcoBh3Pc= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -818,11 +833,11 @@ golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= -golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= -golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= +golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= +golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 h1:hNQpMuAJe5CtcUqCXaWga3FHu+kQvCqcsoVaQgSV60o= -golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08= +golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 h1:aAcj0Da7eBAtrTp03QXWvm88pSyOt+UgdZw2BFZ+lEw= +golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -830,8 +845,8 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= -golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4= +golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -864,11 +879,11 @@ golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= -golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= -golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= +golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo= +golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= -golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE= +golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -877,8 +892,8 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= +golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -914,8 +929,8 @@ golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= -golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= +golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= @@ -928,8 +943,8 @@ golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= -golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24= -golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= +golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU= +golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -943,10 +958,10 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= -golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= -golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= -golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= +golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= +golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg= +golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -970,25 +985,25 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= gomodules.xyz/jsonpatch/v2 v2.3.0 h1:8NFhfS6gzxNqjLIYnZxg319wZ5Qjnx4m/CcX+Klzazc= gomodules.xyz/jsonpatch/v2 v2.3.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= -google.golang.org/api v0.172.0 h1:/1OcMZGPmW1rX2LCu2CmGUD1KXK1+pfzxotxyRUCCdk= -google.golang.org/api v0.172.0/go.mod h1:+fJZq6QXWfa9pXhnIzsjx4yI22d4aI9ZpLb58gvXjis= +google.golang.org/api v0.206.0 h1:A27GClesCSheW5P2BymVHjpEeQ2XHH8DI8Srs2HI2L8= +google.golang.org/api v0.206.0/go.mod h1:BtB8bfjTYIrai3d8UyvPmV9REGgox7coh+ZRwm0b+W8= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20240311173647-c811ad7063a7 h1:ImUcDPHjTrAqNhlOkSocDLfG9rrNHH7w7uoKWPaWZ8s= -google.golang.org/genproto v0.0.0-20240311173647-c811ad7063a7/go.mod h1:/3XmxOjePkvmKrHuBy4zNFw7IzxJXtAgdpXi8Ll990U= -google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 h1:0+ozOGcrp+Y8Aq8TLNN2Aliibms5LEzsq99ZZmAGYm0= -google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094/go.mod h1:fJ/e3If/Q67Mj99hin0hMhiNyCRmt6BQ2aWIJshUSJw= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= +google.golang.org/genproto v0.0.0-20241104194629-dd2ea8efbc28 h1:KJjNNclfpIkVqrZlTWcgOOaVQ00LdBnoEaRfkUx760s= +google.golang.org/genproto v0.0.0-20241104194629-dd2ea8efbc28/go.mod h1:mt9/MofW7AWQ+Gy179ChOnvmJatV8YHUmrcedo9CIFI= +google.golang.org/genproto/googleapis/api v0.0.0-20241104194629-dd2ea8efbc28 h1:M0KvPgPmDZHPlbRbaNU1APr28TvwvvdUPlSv7PUvy8g= +google.golang.org/genproto/googleapis/api v0.0.0-20241104194629-dd2ea8efbc28/go.mod h1:dguCy7UOdZhTvLzDyt15+rOrawrpM4q7DD9dQ1P11P4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241104194629-dd2ea8efbc28 h1:XVhgTWWV3kGQlwJHR3upFWZeTsei6Oks1apkZSeonIE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241104194629-dd2ea8efbc28/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.66.3 h1:TWlsh8Mv0QI/1sIbs1W36lqRclxrmF+eFJ4DbI0fuhA= -google.golang.org/grpc v1.66.3/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= +google.golang.org/grpc v1.68.0 h1:aHQeeJbo8zAkAa3pRzrVjZlbz6uSfeOXlJNQM0RAbz0= +google.golang.org/grpc v1.68.0/go.mod h1:fmSPC5AsjSBCK54MyHRx48kpOti1/jRfOlwEWywNjWA= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -997,8 +1012,8 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io= +google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -1035,22 +1050,22 @@ k8s.io/client-go v0.28.15 h1:+g6Ub+i6tacV3tYJaoyK6bizpinPkamcEwsiKyHcIxc= k8s.io/client-go v0.28.15/go.mod h1:/4upIpTbhWQVSXKDqTznjcAegj2Bx73mW/i0aennJrY= k8s.io/component-base v0.27.7 h1:kngM58HR9W9Nqpv7e4rpdRyWnKl/ABpUhLAZ+HoliMs= k8s.io/component-base v0.27.7/go.mod h1:YGjlCVL1oeKvG3HSciyPHFh+LCjIEqsxz4BDR3cfHRs= -k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= -k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= +k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/kube-aggregator v0.27.2 h1:jfHoPip+qN/fn3OcrYs8/xMuVYvkJHKo0H0DYciqdns= k8s.io/kube-aggregator v0.27.2/go.mod h1:mwrTt4ESjQ7A6847biwohgZWn8P/KzSFHegEScbSGY4= k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780= k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA= -k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= -k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0 h1:jgGTlFYnhF1PM1Ax/lAlxUPE+KfCIXHaathvJg1C3ak= +k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= oras.land/oras-go/v2 v2.5.0 h1:o8Me9kLY74Vp5uw07QXPiitjsw7qNXi8Twd+19Zf02c= oras.land/oras-go/v2 v2.5.0/go.mod h1:z4eisnLP530vwIOUOJeBIj0aGI0L1C3d53atvCBqZHg= sigs.k8s.io/controller-runtime v0.15.3 h1:L+t5heIaI3zeejoIyyvLQs5vTVu/67IU2FfisVzFlBc= sigs.k8s.io/controller-runtime v0.15.3/go.mod h1:kp4jckA4vTx281S/0Yk2LFEEQe67mjg+ev/yknv47Ds= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= -sigs.k8s.io/release-utils v0.7.7 h1:JKDOvhCk6zW8ipEOkpTGDH/mW3TI+XqtPp16aaQ79FU= -sigs.k8s.io/release-utils v0.7.7/go.mod h1:iU7DGVNi3umZJ8q6aHyUFzsDUIaYwNnNKGHo3YE5E3s= +sigs.k8s.io/release-utils v0.8.5 h1:FUtFqEAN621gSXv0L7kHyWruBeS7TUU9aWf76olX7uQ= +sigs.k8s.io/release-utils v0.8.5/go.mod h1:qsm5bdxdgoHkD8HsXpgme2/c3mdsNaiV53Sz2HmKeJA= sigs.k8s.io/structured-merge-diff/v4 v4.3.0 h1:UZbZAZfX0wV2zr7YZorDz6GXROfDFj6LvqCRm4VUVKk= sigs.k8s.io/structured-merge-diff/v4 v4.3.0/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= diff --git a/httpserver/Dockerfile b/httpserver/Dockerfile index 9cdc65df9..71403565c 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:147f428a24c6b80b8afbdaec7f245b9e7ac342601e3aeaffb321a103b7c6b3f4 as builder +FROM --platform=$BUILDPLATFORM golang:1.23@sha256:73f06be4578c9987ce560087e2e2ea6485fb605e3910542cadd8fa09fc5f3e31 as builder ARG TARGETPLATFORM ARG TARGETOS From d8dfa6050cb35f666df1fd0fa68ac2e00e411345 Mon Sep 17 00:00:00 2001 From: Binbin Li Date: Tue, 3 Dec 2024 08:29:32 +0800 Subject: [PATCH 55/62] chore: bump up golangci-lint version (#1961) Signed-off-by: Binbin Li --- .github/workflows/golangci-lint.yml | 2 +- cmd/ratify/cmd/serve.go | 2 +- pkg/certificateprovider/certificate_provider_test.go | 2 +- pkg/controllers/logging.go | 2 +- pkg/keymanagementprovider/keymanagementprovider_test.go | 2 +- pkg/manager/manager.go | 2 +- pkg/verifier/notation/truststore_test.go | 2 +- pkg/verifier/result_test.go | 7 ++++--- pkg/verifier/types/types_test.go | 7 ++++--- 9 files changed, 15 insertions(+), 13 deletions(-) diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 7d903f64d..54319e002 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -26,5 +26,5 @@ jobs: - name: golangci-lint uses: golangci/golangci-lint-action@971e284b6050e8a5849b72094c50ab08da042db8 # v6.1.1 with: - version: v1.59.1 + version: v1.62.2 args: --timeout=10m diff --git a/cmd/ratify/cmd/serve.go b/cmd/ratify/cmd/serve.go index ab0f872f0..373ad12ef 100644 --- a/cmd/ratify/cmd/serve.go +++ b/cmd/ratify/cmd/serve.go @@ -118,7 +118,7 @@ func serve(opts serveCmdOptions) error { if err != nil { return err } - logrus.Infof("starting server at" + opts.httpServerAddress) + logrus.Infof("starting server at %s", opts.httpServerAddress) if err := server.Run(nil); err != nil { return err } diff --git a/pkg/certificateprovider/certificate_provider_test.go b/pkg/certificateprovider/certificate_provider_test.go index 78d70c439..2b6309be4 100644 --- a/pkg/certificateprovider/certificate_provider_test.go +++ b/pkg/certificateprovider/certificate_provider_test.go @@ -78,7 +78,7 @@ func TestDecodeCertificates_ByteArrayToCertificates(t *testing.T) { r, err := DecodeCertificates(c1) if err != nil { - t.Fatalf(err.Error()) + t.Fatal(err.Error()) } expectedLen := 1 diff --git a/pkg/controllers/logging.go b/pkg/controllers/logging.go index 7ad3429f6..90abce740 100644 --- a/pkg/controllers/logging.go +++ b/pkg/controllers/logging.go @@ -122,7 +122,7 @@ func (sink *LogrusSink) createEntry(keysAndValues ...interface{}) *logrus.Entry } func (sink *LogrusSink) formatMessage(msg string) string { - if sink.names == nil || len(sink.names) == 0 { + if len(sink.names) == 0 { return msg } diff --git a/pkg/keymanagementprovider/keymanagementprovider_test.go b/pkg/keymanagementprovider/keymanagementprovider_test.go index 57a2828ee..c4ac13866 100644 --- a/pkg/keymanagementprovider/keymanagementprovider_test.go +++ b/pkg/keymanagementprovider/keymanagementprovider_test.go @@ -85,7 +85,7 @@ func TestDecodeCertificates_ByteArrayToCertificates(t *testing.T) { r, err := DecodeCertificates(c1) if err != nil { - t.Fatalf(err.Error()) + t.Fatal(err.Error()) } expectedLen := 1 diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go index f284ceaea..6726f39cd 100644 --- a/pkg/manager/manager.go +++ b/pkg/manager/manager.go @@ -105,7 +105,7 @@ func StartServer(httpServerAddress, configFilePath, certDirectory, caCertFile st logrus.Errorf("initialize server failed with error %v, exiting..", err) os.Exit(1) } - logrus.Infof("starting server at" + httpServerAddress) + logrus.Infof("starting server at %s", httpServerAddress) if err := server.Run(certRotatorReady); err != nil { logrus.Errorf("starting server failed with error %v, exiting..", err) os.Exit(1) diff --git a/pkg/verifier/notation/truststore_test.go b/pkg/verifier/notation/truststore_test.go index eb64c042d..964f97cb6 100644 --- a/pkg/verifier/notation/truststore_test.go +++ b/pkg/verifier/notation/truststore_test.go @@ -133,7 +133,7 @@ func TestGetCertificates_ErrorFromKMPReconcile(t *testing.T) { } store, err := newTrustStore(nil, certStore) if err != nil { - t.Fatalf("failed to parse verificationCertStores: " + err.Error()) + t.Fatalf("failed to parse verificationCertStores: %s", err.Error()) } controllers.NamespacedCertStores = &mockCertStores{ diff --git a/pkg/verifier/result_test.go b/pkg/verifier/result_test.go index 64efd2c52..67ceec690 100644 --- a/pkg/verifier/result_test.go +++ b/pkg/verifier/result_test.go @@ -16,9 +16,10 @@ limitations under the License. package verifier import ( - "fmt" "testing" + e "errors" + "github.com/ratify-project/ratify/errors" ) @@ -47,7 +48,7 @@ func TestNewVerifierResult(t *testing.T) { { name: "error without detail", message: testMsg1, - err: errors.ErrorCodeUnknown.WithError(fmt.Errorf(testErrReason)).WithRemediation(testRemediation), + err: errors.ErrorCodeUnknown.WithError(e.New(testErrReason)).WithRemediation(testRemediation), expectedMsg: testMsg1, expectedErrReason: testErrReason, expectedRemediation: testRemediation, @@ -55,7 +56,7 @@ func TestNewVerifierResult(t *testing.T) { { name: "error with detail", message: testMsg1, - err: errors.ErrorCodeUnknown.WithError(fmt.Errorf(testErrReason)).WithRemediation(testRemediation).WithDetail(testMsg2), + err: errors.ErrorCodeUnknown.WithError(e.New(testErrReason)).WithRemediation(testRemediation).WithDetail(testMsg2), expectedMsg: testMsg2, expectedErrReason: testErrReason, expectedRemediation: testRemediation, diff --git a/pkg/verifier/types/types_test.go b/pkg/verifier/types/types_test.go index ce1cd39f6..c2d097a33 100644 --- a/pkg/verifier/types/types_test.go +++ b/pkg/verifier/types/types_test.go @@ -16,9 +16,10 @@ limitations under the License. package types import ( - "fmt" "testing" + e "errors" + "github.com/ratify-project/ratify/errors" ) @@ -47,7 +48,7 @@ func TestCreateVerifierResult(t *testing.T) { { name: "error without detail", message: testMsg1, - err: errors.ErrorCodeUnknown.WithError(fmt.Errorf(testErrReason)).WithRemediation(testRemediation), + err: errors.ErrorCodeUnknown.WithError(e.New(testErrReason)).WithRemediation(testRemediation), expectedMsg: testMsg1, expectedErrReason: testErrReason, expectedRemediation: testRemediation, @@ -55,7 +56,7 @@ func TestCreateVerifierResult(t *testing.T) { { name: "error with detail", message: testMsg1, - err: errors.ErrorCodeUnknown.WithError(fmt.Errorf(testErrReason)).WithRemediation(testRemediation).WithDetail(testMsg2), + err: errors.ErrorCodeUnknown.WithError(e.New(testErrReason)).WithRemediation(testRemediation).WithDetail(testMsg2), expectedMsg: testMsg2, expectedErrReason: testErrReason, expectedRemediation: testRemediation, From 666849aa12016da032228e478751e8ab15f614a6 Mon Sep 17 00:00:00 2001 From: Jordan Langue <55289214+JoupainMD@users.noreply.github.com> Date: Tue, 3 Dec 2024 01:57:46 +0100 Subject: [PATCH 56/62] fix(tls): allowing TLS when crd-manager disabled (#1954) Signed-off-by: Jordan Langue --- httpserver/server.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/httpserver/server.go b/httpserver/server.go index 782e3c83d..10fcb87ee 100644 --- a/httpserver/server.go +++ b/httpserver/server.go @@ -140,7 +140,9 @@ func (server *Server) Run(certRotatorReady chan struct{}) error { } if server.CertDirectory != "" { - <-certRotatorReady + if certRotatorReady != nil { + <-certRotatorReady + } certFile := filepath.Join(server.CertDirectory, certName) keyFile := filepath.Join(server.CertDirectory, keyName) From 527004bf9a7a29e4ebb04829b6106dd82d060946 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 Dec 2024 05:23:16 +0000 Subject: [PATCH 57/62] chore: Bump github.com/aws/aws-sdk-go-v2/config from 1.28.3 to 1.28.6 (#1957) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 20 ++++++++++---------- go.sum | 40 ++++++++++++++++++++-------------------- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/go.mod b/go.mod index df833b0ce..38a48896b 100644 --- a/go.mod +++ b/go.mod @@ -21,9 +21,9 @@ require ( github.com/alibabacloud-go/tea v1.2.2 github.com/alibabacloud-go/tea-utils/v2 v2.0.7 github.com/aliyun/credentials-go v1.3.11 - github.com/aws/aws-sdk-go-v2 v1.32.5 - github.com/aws/aws-sdk-go-v2/config v1.28.3 - github.com/aws/aws-sdk-go-v2/credentials v1.17.46 + github.com/aws/aws-sdk-go-v2 v1.32.6 + github.com/aws/aws-sdk-go-v2/config v1.28.6 + github.com/aws/aws-sdk-go-v2/credentials v1.17.47 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 @@ -145,14 +145,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.20 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.24 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.24 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.21 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.25 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.25 // 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.12.5 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.24.6 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.5 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.33.1 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.6 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.24.7 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.6 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.33.2 // indirect github.com/aws/smithy-go v1.22.1 // 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 2c68c5a8d..118a71986 100644 --- a/go.sum +++ b/go.sum @@ -170,18 +170,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.55.5 h1:KKUZBfBoyqy5d3swXyiC7Q76ic40rYcbqH7qjh59kzU= github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= -github.com/aws/aws-sdk-go-v2 v1.32.5 h1:U8vdWJuY7ruAkzaOdD7guwJjD06YSKmnKCJs7s3IkIo= -github.com/aws/aws-sdk-go-v2 v1.32.5/go.mod h1:P5WJBrYqqbWVaOxgH0X/FYYD47/nooaPOZPlQdmiN2U= -github.com/aws/aws-sdk-go-v2/config v1.28.3 h1:kL5uAptPcPKaJ4q0sDUjUIdueO18Q7JDzl64GpVwdOM= -github.com/aws/aws-sdk-go-v2/config v1.28.3/go.mod h1:SPEn1KA8YbgQnwiJ/OISU4fz7+F6Fe309Jf0QTsRCl4= -github.com/aws/aws-sdk-go-v2/credentials v1.17.46 h1:AU7RcriIo2lXjUfHFnFKYsLCwgbz1E7Mm95ieIRDNUg= -github.com/aws/aws-sdk-go-v2/credentials v1.17.46/go.mod h1:1FmYyLGL08KQXQ6mcTlifyFXfJVCNJTVGuQP4m0d/UA= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.20 h1:sDSXIrlsFSFJtWKLQS4PUWRvrT580rrnuLydJrCQ/yA= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.20/go.mod h1:WZ/c+w0ofps+/OUqMwWgnfrgzZH1DZO1RIkktICsqnY= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.24 h1:4usbeaes3yJnCFC7kfeyhkdkPtoRYPa/hTmCqMpKpLI= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.24/go.mod h1:5CI1JemjVwde8m2WG3cz23qHKPOxbpkq0HaoreEgLIY= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.24 h1:N1zsICrQglfzaBnrfM0Ys00860C+QFwu6u/5+LomP+o= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.24/go.mod h1:dCn9HbJ8+K31i8IQ8EWmWj0EiIk0+vKiHNMxTTYveAg= +github.com/aws/aws-sdk-go-v2 v1.32.6 h1:7BokKRgRPuGmKkFMhEg/jSul+tB9VvXhcViILtfG8b4= +github.com/aws/aws-sdk-go-v2 v1.32.6/go.mod h1:P5WJBrYqqbWVaOxgH0X/FYYD47/nooaPOZPlQdmiN2U= +github.com/aws/aws-sdk-go-v2/config v1.28.6 h1:D89IKtGrs/I3QXOLNTH93NJYtDhm8SYa9Q5CsPShmyo= +github.com/aws/aws-sdk-go-v2/config v1.28.6/go.mod h1:GDzxJ5wyyFSCoLkS+UhGB0dArhb9mI+Co4dHtoTxbko= +github.com/aws/aws-sdk-go-v2/credentials v1.17.47 h1:48bA+3/fCdi2yAwVt+3COvmatZ6jUDNkDTIsqDiMUdw= +github.com/aws/aws-sdk-go-v2/credentials v1.17.47/go.mod h1:+KdckOejLW3Ks3b0E3b5rHsr2f9yuORBum0WPnE5o5w= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.21 h1:AmoU1pziydclFT/xRV+xXE/Vb8fttJCLRPv8oAkprc0= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.21/go.mod h1:AjUdLYe4Tgs6kpH4Bv7uMZo7pottoyHMn4eTcIcneaY= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.25 h1:s/fF4+yDQDoElYhfIVvSNyeCydfbuTKzhxSXDXCPasU= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.25/go.mod h1:IgPfDv5jqFIzQSNbUEMoitNooSMXjRSDkhXv8jiROvU= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.25 h1:ZntTCl5EsYnhN/IygQEUugpdwbhdkom9uHcbCftiGgA= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.25/go.mod h1:DBdPrgeocww+CSl1C8cEV8PN1mHMBhuCDLpXezyvWkE= 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= @@ -190,16 +190,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.12.1 h1:iXtILhvDxB6kPvEXgsDhGaZCSC6LQET5ZHSdJozeI0Y= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1/go.mod h1:9nu0fVANtYiAePIBh2/pFUSwtJ402hLnp854CNoDOeE= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.5 h1:wtpJ4zcwrSbwhECWQoI/g6WM9zqCcSpHDJIWSbMLOu4= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.5/go.mod h1:qu/W9HXQbbQ4+1+JcZp0ZNPV31ym537ZJN+fiS7Ti8E= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.6 h1:50+XsN70RS7dwJ2CkVNXzj7U2L1HKP8nqTd3XWEXBN4= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.6/go.mod h1:WqgLmwY7so32kG01zD8CPTJWVWM+TzJoOVHwTg4aPug= github.com/aws/aws-sdk-go-v2/service/kms v1.37.5 h1:5dQJ6Q5QrQOqZxXjSbRXukBqU8Pgu6Ro6Qqtyd8yiz4= github.com/aws/aws-sdk-go-v2/service/kms v1.37.5/go.mod h1:A9vfQcNHVBCE7ZZN6H+UUJpXtbH26Vv6L7Zhk5nIJAY= -github.com/aws/aws-sdk-go-v2/service/sso v1.24.6 h1:3zu537oLmsPfDMyjnUS2g+F2vITgy5pB74tHI+JBNoM= -github.com/aws/aws-sdk-go-v2/service/sso v1.24.6/go.mod h1:WJSZH2ZvepM6t6jwu4w/Z45Eoi75lPN7DcydSRtJg6Y= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.5 h1:K0OQAsDywb0ltlFrZm0JHPY3yZp/S9OaoLU33S7vPS8= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.5/go.mod h1:ORITg+fyuMoeiQFiVGoqB3OydVTLkClw/ljbblMq6Cc= -github.com/aws/aws-sdk-go-v2/service/sts v1.33.1 h1:6SZUVRQNvExYlMLbHdlKB48x0fLbc2iVROyaNEwBHbU= -github.com/aws/aws-sdk-go-v2/service/sts v1.33.1/go.mod h1:GqWyYCwLXnlUB1lOAXQyNSPqPLQJvmo8J0DWBzp9mtg= +github.com/aws/aws-sdk-go-v2/service/sso v1.24.7 h1:rLnYAfXQ3YAccocshIH5mzNNwZBkBo+bP6EhIxak6Hw= +github.com/aws/aws-sdk-go-v2/service/sso v1.24.7/go.mod h1:ZHtuQJ6t9A/+YDuxOLnbryAmITtr8UysSny3qcyvJTc= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.6 h1:JnhTZR3PiYDNKlXy50/pNeix9aGMo6lLpXwJ1mw8MD4= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.6/go.mod h1:URronUEGfXZN1VpdktPSD1EkAL9mfrV+2F4sjH38qOY= +github.com/aws/aws-sdk-go-v2/service/sts v1.33.2 h1:s4074ZO1Hk8qv65GqNXqDjmkf4HSQqJukaLuuW0TpDA= +github.com/aws/aws-sdk-go-v2/service/sts v1.33.2/go.mod h1:mVggCnIWoM09jP71Wh+ea7+5gAp53q+49wDFs1SW5z8= github.com/aws/smithy-go v1.22.1 h1:/HPHZQ0g7f4eUeK6HKglFz8uwVfZKgoI25rb/J+dnro= github.com/aws/smithy-go v1.22.1/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= From ca88b6259272e59fba78974734fa66caf78c44b7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 Dec 2024 06:36:48 +0000 Subject: [PATCH 58/62] chore: Bump distroless/static from `d71f4b2` to `6cd937e` in /httpserver (#1960) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- httpserver/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httpserver/Dockerfile b/httpserver/Dockerfile index 71403565c..c022f6e80 100644 --- a/httpserver/Dockerfile +++ b/httpserver/Dockerfile @@ -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:d71f4b239be2d412017b798a0a401c44c3049a3ca454838473a4c32ed076bfea +FROM gcr.io/distroless/static:nonroot@sha256:6cd937e9155bdfd805d1b94e037f9d6a899603306030936a3b11680af0c2ed58 LABEL org.opencontainers.image.source https://github.com/ratify-project/ratify ARG RATIFY_FOLDER=$HOME/.ratify/ From fa9be71614fc5b29a611a8759c561ccaf7e43ae0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 5 Dec 2024 14:55:33 +0800 Subject: [PATCH 59/62] chore: Bump github/codeql-action from 3.27.5 to 3.27.6 (#1963) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/codeql.yml | 4 ++-- .github/workflows/scorecards.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 1d408b41e..e88b04fc7 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -37,7 +37,7 @@ jobs: with: go-version: "1.22" - name: Initialize CodeQL - uses: github/codeql-action/init@f09c1c0a94de965c15400f5634aa42fac8fb8f88 # tag=v3.27.5 + uses: github/codeql-action/init@aa578102511db1f4524ed59b8cc2bae4f6e88195 # tag=v3.27.6 with: languages: go - name: Run tidy @@ -45,4 +45,4 @@ jobs: - name: Build CLI run: make build - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@f09c1c0a94de965c15400f5634aa42fac8fb8f88 # tag=v3.27.5 + uses: github/codeql-action/analyze@aa578102511db1f4524ed59b8cc2bae4f6e88195 # tag=v3.27.6 diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index db16e41f7..b18a16885 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -55,6 +55,6 @@ jobs: retention-days: 5 - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@f09c1c0a94de965c15400f5634aa42fac8fb8f88 # tag=v3.27.5 + uses: github/codeql-action/upload-sarif@aa578102511db1f4524ed59b8cc2bae4f6e88195 # tag=v3.27.6 with: sarif_file: results.sarif From a2efeb728c334de4df0bd84515f6507ab292ab41 Mon Sep 17 00:00:00 2001 From: Akash Singhal Date: Thu, 5 Dec 2024 17:20:32 -0800 Subject: [PATCH 60/62] build: add image signing for all release images (#1947) Signed-off-by: Akash Singhal --- .github/workflows/publish-dev-assets.yml | 42 ++++++++++++++ .github/workflows/publish-package.yml | 64 +++++++++++++++++++++ .well-known/pki-validation/trustpolicy.json | 24 ++++++++ 3 files changed, 130 insertions(+) create mode 100644 .well-known/pki-validation/trustpolicy.json diff --git a/.github/workflows/publish-dev-assets.yml b/.github/workflows/publish-dev-assets.yml index 520700d17..9fa349232 100644 --- a/.github/workflows/publish-dev-assets.yml +++ b/.github/workflows/publish-dev-assets.yml @@ -37,6 +37,10 @@ jobs: az version # Key Vault: az account get-access-token --scope https://vault.azure.net/.default --output none + - name: Prepare notation certificate + run: | + mkdir -p truststore/x509/ca/ratify-verify + cp ./.well-known/pki-validation/ratify-verification.crt truststore/x509/ca/ratify-verify - name: prepare id: prepare run: | @@ -138,6 +142,44 @@ jobs: cosign sign --yes ${{ steps.prepare.outputs.ref }}:${{ steps.prepare.outputs.version }} cosign sign --yes ${{ steps.prepare.outputs.chartrepo }}/ratify:${{ steps.prepare.outputs.semversionrolling }} cosign sign --yes ${{ steps.prepare.outputs.chartrepo }}/ratify:${{ steps.prepare.outputs.semversion }} + - name: Verify with Notation + uses: notaryproject/notation-action/verify@03242349f62aeddc995e12c6fbcea3b87697873f # v1.2.0 + with: + target_artifact_reference: |- + ${{ steps.prepare.outputs.crdref }}:${{ steps.prepare.outputs.version }} + ${{ steps.prepare.outputs.baseref }}:${{ steps.prepare.outputs.version }} + ${{ steps.prepare.outputs.ref }}:${{ steps.prepare.outputs.version }} + ${{ steps.prepare.outputs.chartrepo }}/ratify:${{ steps.prepare.outputs.semversionrolling }} + ${{ steps.prepare.outputs.chartrepo }}/ratify:${{ steps.prepare.outputs.semversion }} + trust_policy: ./.well-known/pki-validation/trustpolicy.json + trust_store: truststore + - name: Verify with Cosign + run: | + cosign verify \ + --certificate-identity-regexp "https://github.com/ratify-project/ratify/.github/workflows/publish-dev-assets.yml@*" \ + --certificate-oidc-issuer https://token.actions.githubusercontent.com \ + --certificate-github-workflow-repository ratify-project/ratify \ + ${{ steps.prepare.outputs.crdref }}:${{ steps.prepare.outputs.version }} + cosign verify \ + --certificate-identity-regexp "https://github.com/ratify-project/ratify/.github/workflows/publish-dev-assets.yml@*" \ + --certificate-oidc-issuer https://token.actions.githubusercontent.com \ + --certificate-github-workflow-repository ratify-project/ratify \ + ${{ steps.prepare.outputs.baseref }}:${{ steps.prepare.outputs.version }} + cosign verify \ + --certificate-identity-regexp "https://github.com/ratify-project/ratify/.github/workflows/publish-dev-assets.yml@*" \ + --certificate-oidc-issuer https://token.actions.githubusercontent.com \ + --certificate-github-workflow-repository ratify-project/ratify \ + ${{ steps.prepare.outputs.ref }}:${{ steps.prepare.outputs.version }} + cosign verify \ + --certificate-identity-regexp "https://github.com/ratify-project/ratify/.github/workflows/publish-dev-assets.yml@*" \ + --certificate-oidc-issuer https://token.actions.githubusercontent.com \ + --certificate-github-workflow-repository ratify-project/ratify \ + ${{ steps.prepare.outputs.chartrepo }}/ratify:${{ steps.prepare.outputs.semversionrolling }} + cosign verify \ + --certificate-identity-regexp "https://github.com/ratify-project/ratify/.github/workflows/publish-dev-assets.yml@*" \ + --certificate-oidc-issuer https://token.actions.githubusercontent.com \ + --certificate-github-workflow-repository ratify-project/ratify \ + ${{ steps.prepare.outputs.chartrepo }}/ratify:${{ steps.prepare.outputs.semversion }} - name: clear if: always() run: | diff --git a/.github/workflows/publish-package.yml b/.github/workflows/publish-package.yml index f0c73dd60..76efddfbb 100644 --- a/.github/workflows/publish-package.yml +++ b/.github/workflows/publish-package.yml @@ -14,6 +14,8 @@ jobs: permissions: packages: write contents: read + id-token: write + environment: azure-publish steps: - name: Harden Runner uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 @@ -21,6 +23,25 @@ jobs: egress-policy: audit - name: Checkout uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + - name: Install Notation + uses: notaryproject/notation-action/setup@03242349f62aeddc995e12c6fbcea3b87697873f # v1.2.0 + - name: Install cosign + uses: sigstore/cosign-installer@dc72c7d5c4d10cd6bcb8cf6e3fd625a9e5e537da # v3.7.0 + - name: Az CLI login + uses: azure/login@a65d910e8af852a8061c627c456678983e180302 # v2.2.0 + with: + client-id: ${{ secrets.AZURE_CLIENT_ID }} + tenant-id: ${{ secrets.AZURE_TENANT_ID }} + subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + - name: Cache AAD tokens + run: | + az version + # Key Vault: + az account get-access-token --scope https://vault.azure.net/.default --output none + - name: Prepare notation certificate + run: | + mkdir -p truststore/x509/ca/ratify-verify + cp ./.well-known/pki-validation/ratify-verification.crt truststore/x509/ca/ratify-verify - name: prepare id: prepare run: | @@ -83,6 +104,49 @@ jobs: --label org.opencontainers.image.revision=${{ github.sha }} \ -t ${{ steps.prepare.outputs.ref }} \ --push . + - name: Sign with Notation + uses: notaryproject/notation-action/sign@03242349f62aeddc995e12c6fbcea3b87697873f # v1.2.0 + with: + plugin_name: azure-kv + plugin_url: ${{ vars.AZURE_KV_PLUGIN_URL }} + plugin_checksum: ${{ vars.AZURE_KV_CHECKSUM }} + key_id: ${{ secrets.AZURE_KV_KEY_ID }} + target_artifact_reference: |- + ${{ steps.prepare.outputs.crdref }} + ${{ steps.prepare.outputs.baseref }} + ${{ steps.prepare.outputs.ref }} + signature_format: cose + - name: Sign with Cosign + run: | + cosign sign --yes ${{ steps.prepare.outputs.crdref }} + cosign sign --yes ${{ steps.prepare.outputs.baseref }} + cosign sign --yes ${{ steps.prepare.outputs.ref }} + - name: Verify with Notation + uses: notaryproject/notation-action/verify@03242349f62aeddc995e12c6fbcea3b87697873f # v1.2.0 + with: + target_artifact_reference: |- + ${{ steps.prepare.outputs.crdref }} + ${{ steps.prepare.outputs.baseref }} + ${{ steps.prepare.outputs.ref }} + trust_policy: ./.well-known/pki-validation/trustpolicy.json + trust_store: truststore + - name: Verify with Cosign + run: | + cosign verify \ + --certificate-identity-regexp "https://github.com/ratify-project/ratify/.github/workflows/publish-package.yml@*" \ + --certificate-oidc-issuer https://token.actions.githubusercontent.com \ + --certificate-github-workflow-repository ratify-project/ratify \ + ${{ steps.prepare.outputs.crdref }} + cosign verify \ + --certificate-identity-regexp "https://github.com/ratify-project/ratify/.github/workflows/publish-package.yml@*" \ + --certificate-oidc-issuer https://token.actions.githubusercontent.com \ + --certificate-github-workflow-repository ratify-project/ratify \ + ${{ steps.prepare.outputs.baseref }} + cosign verify \ + --certificate-identity-regexp "https://github.com/ratify-project/ratify/.github/workflows/publish-package.yml@*" \ + --certificate-oidc-issuer https://token.actions.githubusercontent.com \ + --certificate-github-workflow-repository ratify-project/ratify \ + ${{ steps.prepare.outputs.ref }} - name: clear if: always() run: | diff --git a/.well-known/pki-validation/trustpolicy.json b/.well-known/pki-validation/trustpolicy.json new file mode 100644 index 000000000..779f096a5 --- /dev/null +++ b/.well-known/pki-validation/trustpolicy.json @@ -0,0 +1,24 @@ +{ + "version": "1.0", + "trustPolicies": [ + { + "name": "ratify-images", + "registryScopes": [ + "ghcr.io/ratify-project/ratify", + "ghcr.io/ratify-project/ratify-base", + "ghcr.io/ratify-project/ratify-crds", + "ghcr.io/ratify-project/ratify-dev", + "ghcr.io/ratify-project/ratify-base-dev", + "ghcr.io/ratify-project/ratify-crds-dev", + "ghcr.io/ratify-project/ratify-chart-dev/ratify" + ], + "signatureVerification": { + "level" : "strict" + }, + "trustStores": [ "ca:ratify-verify" ], + "trustedIdentities": [ + "x509.subject: CN=ratify.dev,O=ratify-project,L=Seattle,ST=WA,C=US" + ] + } + ] +} \ No newline at end of file From 78b2ebae76b1698da2b4323dd97267734939197a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Dec 2024 21:57:15 +0800 Subject: [PATCH 61/62] chore: Bump golang from `73f06be` to `574185e` in /httpserver (#1973) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- httpserver/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httpserver/Dockerfile b/httpserver/Dockerfile index c022f6e80..c02233f82 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.23@sha256:73f06be4578c9987ce560087e2e2ea6485fb605e3910542cadd8fa09fc5f3e31 as builder +FROM --platform=$BUILDPLATFORM golang:1.23@sha256:574185e5c6b9d09873f455a7c205ea0514bfd99738c5dc7750196403a44ed4b7 as builder ARG TARGETPLATFORM ARG TARGETOS From d176ea0ba6901a6e8c015af9086cda0930e06414 Mon Sep 17 00:00:00 2001 From: Akash Singhal Date: Mon, 9 Dec 2024 17:58:01 -0800 Subject: [PATCH 62/62] docs: update dev image release guidance (#1974) Signed-off-by: Akash Singhal --- RELEASES.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 1069f3f1f..28d6754ac 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -92,13 +92,13 @@ After a successful release, please prepare a [PR](https://github.com/ratify-proj * Contributors MUST select the `Helm Chart Change` option under the `Type of Change` section if there is ANY update to the helm chart that is required for proposed changes in PR. * Maintainers MUST manually trigger the "Publish Package" workflow after merging any PR that indicates `Helm Chart Change` * Go to the `Actions` tab for the Ratify repository - * Select `publish-ghcr` option from list of workflows on left pane + * Select `publish-dev-assets` option from list of workflows on left pane * Select the `Run workflow` drop down on the right side above the list of action runs - * Choose `Branch: main` + * Choose `Branch: dev` * Select `Run workflow` * Process to Request an off-schedule dev build be published * Submit a new feature request issue prefixed with `[Dev Build Request]` - * In the the `What this PR does / why we need it` section, briefly explain why an off schedule build is needed + * In the the `What would you like to be added?` section, briefly explain why an off schedule build is needed * Once issue is created, post in the `#ratify` slack channel and tag the maintainers * Maintainers should acknowledge request by approving/denying request as a follow up comment