From 957207b9312c49dc499495cba519ae700c8adacf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 15 Oct 2024 14:57:04 +0800 Subject: [PATCH 01/18] chore: Bump github/codeql-action from 3.26.12 to 3.26.13 (#1869) 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 cda4a9af4..5a92c3ad1 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@c36620d31ac7c881962c3d9dd939c40ec9434f2b # tag=v3.26.12 + uses: github/codeql-action/init@f779452ac5af1c261dce0346a8f964149f49322b # tag=v3.26.13 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@c36620d31ac7c881962c3d9dd939c40ec9434f2b # tag=v3.26.12 + uses: github/codeql-action/analyze@f779452ac5af1c261dce0346a8f964149f49322b # tag=v3.26.13 diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index d0e8bc59a..a1b98ce7c 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@c36620d31ac7c881962c3d9dd939c40ec9434f2b # tag=v3.26.12 + uses: github/codeql-action/upload-sarif@f779452ac5af1c261dce0346a8f964149f49322b # tag=v3.26.13 with: sarif_file: results.sarif From 6f96ebce4e0cb6e758455f4e8fa7d80d24485f26 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 15 Oct 2024 07:24:45 +0000 Subject: [PATCH 02/18] chore: Bump golang from `628529a` to `b274ff1` in /httpserver (#1865) 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 1748ecbe6..39ee6444c 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:628529a29f130a8ab336b994be99d134ce98cd23b8f2052d8995678681e97ca2 as builder +FROM --platform=$BUILDPLATFORM golang:1.22@sha256:b274ff14d8eb9309b61b1a45333bf0559a554ebcf6732fa2012dbed9b01ea56f as builder ARG TARGETPLATFORM ARG TARGETOS From 4ed4425934e2e9f88665f56ea63c2692d04213df Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 15 Oct 2024 08:18:43 +0000 Subject: [PATCH 03/18] chore: Bump actions/upload-artifact from 4.4.1 to 4.4.3 (#1859) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/e2e-aks.yml | 2 +- .github/workflows/e2e-k8s.yml | 2 +- .github/workflows/high-availability.yml | 2 +- .github/workflows/quick-start.yml | 2 +- .github/workflows/release.yml | 2 +- .github/workflows/scorecards.yml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/e2e-aks.yml b/.github/workflows/e2e-aks.yml index 85a3b81d5..0ce8950a1 100644 --- a/.github/workflows/e2e-aks.yml +++ b/.github/workflows/e2e-aks.yml @@ -64,7 +64,7 @@ jobs: make e2e-aks KUBERNETES_VERSION=${{ inputs.k8s_version }} GATEKEEPER_VERSION=${{ inputs.gatekeeper_version }} TENANT_ID=${{ secrets.AZURE_TENANT_ID }} AZURE_SP_OBJECT_ID=${{ secrets.AZURE_SP_OBJECT_ID }} - name: Upload artifacts - uses: actions/upload-artifact@604373da6381bf24206979c74d06a550515601b9 # v4.4.1 + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 if: ${{ always() }} with: name: e2e-logs-aks-${{ inputs.k8s_version }}-${{ inputs.gatekeeper_version }} diff --git a/.github/workflows/e2e-k8s.yml b/.github/workflows/e2e-k8s.yml index 9fae3941e..be26f5362 100644 --- a/.github/workflows/e2e-k8s.yml +++ b/.github/workflows/e2e-k8s.yml @@ -65,7 +65,7 @@ jobs: kubectl logs -n gatekeeper-system -l app=ratify --tail=-1 > logs-ratify-preinstall-${{ matrix.KUBERNETES_VERSION }}-${{ matrix.GATEKEEPER_VERSION }}-rego-policy.json kubectl logs -n gatekeeper-system -l app.kubernetes.io/name=ratify --tail=-1 > logs-ratify-${{ matrix.KUBERNETES_VERSION }}-${{ matrix.GATEKEEPER_VERSION }}-rego-policy.json - name: Upload artifacts - uses: actions/upload-artifact@604373da6381bf24206979c74d06a550515601b9 # v4.4.1 + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 if: ${{ always() }} with: name: e2e-logs-${{ inputs.k8s_version }}-${{ inputs.gatekeeper_version }} diff --git a/.github/workflows/high-availability.yml b/.github/workflows/high-availability.yml index 9cd72b8d7..e9e576851 100644 --- a/.github/workflows/high-availability.yml +++ b/.github/workflows/high-availability.yml @@ -60,7 +60,7 @@ jobs: kubectl logs -n gatekeeper-system -l app=ratify --tail=-1 > logs-ratify-preinstall-${{ matrix.DAPR_VERSION }}.json kubectl logs -n gatekeeper-system -l app.kubernetes.io/name=ratify --tail=-1 > logs-ratify-${{ matrix.DAPR_VERSION }}.json - name: Upload artifacts - uses: actions/upload-artifact@604373da6381bf24206979c74d06a550515601b9 # v4.4.1 + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 if: ${{ always() }} with: name: e2e-logs-${{ matrix.DAPR_VERSION }} diff --git a/.github/workflows/quick-start.yml b/.github/workflows/quick-start.yml index 82c6444d1..3d9b3aa6e 100644 --- a/.github/workflows/quick-start.yml +++ b/.github/workflows/quick-start.yml @@ -59,7 +59,7 @@ jobs: kubectl logs -n gatekeeper-system -l app=ratify --tail=-1 > logs-ratify-preinstall-${{ matrix.KUBERNETES_VERSION }}-config-policy.json kubectl logs -n gatekeeper-system -l app.kubernetes.io/name=ratify --tail=-1 > logs-ratify-${{ matrix.KUBERNETES_VERSION }}-config-policy.json - name: Upload artifacts - uses: actions/upload-artifact@604373da6381bf24206979c74d06a550515601b9 # v4.4.1 + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 if: ${{ always() }} with: name: e2e-logs-${{ matrix.KUBERNETES_VERSION }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ab9e8c0f6..0b692df82 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -49,7 +49,7 @@ jobs: $RUNNER_TEMP/sbom-tool generate -b . -bc . -pn ratify -pv $GITHUB_REF_NAME -ps Microsoft -nsb https://microsoft.com -V Verbose - name: Upload a Build Artifact - uses: actions/upload-artifact@604373da6381bf24206979c74d06a550515601b9 # tag=v4.4.1 + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # tag=v4.4.3 with: name: SBOM SPDX files path: _manifest/spdx_2.2/** diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index a1b98ce7c..a45432923 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -48,7 +48,7 @@ jobs: publish_results: true - name: "Upload artifact" - uses: actions/upload-artifact@604373da6381bf24206979c74d06a550515601b9 # tag=v4.4.1 + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # tag=v4.4.3 with: name: SARIF file path: results.sarif From 85781ccba706e460c8f33109f4a95f8fbe4b9f3d Mon Sep 17 00:00:00 2001 From: Maneesh Singh Date: Tue, 15 Oct 2024 21:38:42 -0700 Subject: [PATCH 04/18] feat: additional env vars for ratify container via helm chart (#1854) Signed-off-by: Maneesh Singh --- charts/ratify/README.md | 1 + charts/ratify/templates/deployment.yaml | 3 +++ charts/ratify/values.yaml | 7 ++++++- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/charts/ratify/README.md b/charts/ratify/README.md index af3600209..571bfa141 100644 --- a/charts/ratify/README.md +++ b/charts/ratify/README.md @@ -47,6 +47,7 @@ Values marked `# DEPRECATED` in the `values.yaml` as well as **DEPRECATED** in t | replicaCount | The number of Ratify replicas in deployment | 1 | | affinity | Pod affinity for the Ratify deployment | `{}` | | tolerations | Pod tolerations for the Ratify deployment | `[]` | +| env | Environment variables for Ratify container | `[]` | | notationCerts | An array of public certificate/certificate chain used to create inline certstore used by Notation verifier | `` | | cosignKeys | An array of public keys used to create inline key management providers used by Cosign verifier | `[]` | | notation.enabled | Enables/disables the built-in notation verifier. MUST be set to true for notation verification. | `true` | diff --git a/charts/ratify/templates/deployment.yaml b/charts/ratify/templates/deployment.yaml index 7a979ca43..46ed544ae 100644 --- a/charts/ratify/templates/deployment.yaml +++ b/charts/ratify/templates/deployment.yaml @@ -110,6 +110,9 @@ spec: readOnly: true {{- end }} env: + {{- with .Values.env }} + {{- toYaml . | nindent 12 }} + {{- end }} {{- if .Values.logger.level }} - name: RATIFY_LOG_LEVEL value: {{ .Values.logger.level }} diff --git a/charts/ratify/values.yaml b/charts/ratify/values.yaml index ee7c82d41..348736e9b 100644 --- a/charts/ratify/values.yaml +++ b/charts/ratify/values.yaml @@ -169,4 +169,9 @@ akvCertConfig: # DEPRECATED: Use azurekeyvault instead cert2Name: # DEPRECATED: Use azurekeyvault.certificates instead cert2Version: # DEPRECATED: Use azurekeyvault.certificates instead certificates: # DEPRECATED: Use azurekeyvault.certificates instead - tenantId: # DEPRECATED: Use azurekeyvault.tenantId instead \ No newline at end of file + tenantId: # DEPRECATED: Use azurekeyvault.tenantId instead + +# env: environment variables for ratify container +env: [] +# - name: https_proxy +# value: http://proxy-server:80 From 6376762bd4b58ac0278e655ca66bfdfca74adf1c Mon Sep 17 00:00:00 2001 From: Binbin Li Date: Wed, 16 Oct 2024 13:05:56 +0800 Subject: [PATCH 05/18] ci: replace trivy with trivy-action (#1871) Signed-off-by: Binbin Li --- .github/workflows/scan-vulns.yaml | 70 ++++++++++++++++++++++--------- 1 file changed, 50 insertions(+), 20 deletions(-) diff --git a/.github/workflows/scan-vulns.yaml b/.github/workflows/scan-vulns.yaml index b2ead2507..ad2d2fb54 100644 --- a/.github/workflows/scan-vulns.yaml +++ b/.github/workflows/scan-vulns.yaml @@ -37,6 +37,8 @@ jobs: name: "[Trivy] Scan for vulnerabilities" runs-on: ubuntu-22.04 timeout-minutes: 15 + env: + TRIVY_VERSION: v0.49.1 steps: - name: Harden Runner uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 @@ -46,30 +48,58 @@ jobs: - name: Check out code into the Go module directory uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 - - 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 - env: - TRIVY_VERSION: "0.46.0" + - name: Manual Trivy Setup + uses: aquasecurity/setup-trivy@eadb05c36f891dc855bba00f67174a1e61528cd4 # v0.2.1 + with: + cache: true + version: ${{ env.TRIVY_VERSION }} - name: Run trivy on git repository - run: | - trivy fs --format table --ignore-unfixed --scanners vuln . + uses: aquasecurity/trivy-action@5681af892cd0f4997658e2bacc62bd0a894cf564 # 0.27.0 + with: + scan-type: 'fs' + scan-ref: '.' + ignore-unfixed: true + scanners: 'vuln' + version: ${{ env.TRIVY_VERSION }} - name: Build docker images run: | make e2e-build-local-ratify-image make e2e-build-crd-image - - name: Run trivy on images for all severity - run: | - for img in "localbuild:test" "localbuildcrd:test"; do - trivy image --ignore-unfixed --vuln-type="os,library" "${img}" - done - - name: Run trivy on images and exit on HIGH severity - run: | - for img in "localbuild:test" "localbuildcrd:test"; do - trivy image --ignore-unfixed --exit-code 1 --severity HIGH --vuln-type="os,library" "${img}" - done + + - name: Run Trivy vulnerability scanner on localbuild:test + uses: aquasecurity/trivy-action@5681af892cd0f4997658e2bacc62bd0a894cf564 # 0.27.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@5681af892cd0f4997658e2bacc62bd0a894cf564 # 0.27.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@5681af892cd0f4997658e2bacc62bd0a894cf564 # 0.27.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@5681af892cd0f4997658e2bacc62bd0a894cf564 # 0.27.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 From 130194feca08fe937e69111caee0aebb40d65775 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 16 Oct 2024 13:55:55 +0800 Subject: [PATCH 06/18] chore: Bump anchore/sbom-action from 0.17.2 to 0.17.4 (#1872) 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 0b692df82..3d95884f5 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@61119d458adab75f756bc0b9e4bde25725f86a7a # v0.17.2 + uses: anchore/sbom-action/download-syft@8d0a6505bf28ced3e85154d13dc6af83299e13f1 # v0.17.4 - name: Set up Go uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 From 1757d2a2b249e507cb9082959c9f0b35a34d9b5a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 16 Oct 2024 15:24:45 +0800 Subject: [PATCH 07/18] chore: Bump aquasecurity/trivy-action from 0.27.0 to 0.28.0 (#1873) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/scan-vulns.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/scan-vulns.yaml b/.github/workflows/scan-vulns.yaml index ad2d2fb54..a4182aa7e 100644 --- a/.github/workflows/scan-vulns.yaml +++ b/.github/workflows/scan-vulns.yaml @@ -55,7 +55,7 @@ jobs: version: ${{ env.TRIVY_VERSION }} - name: Run trivy on git repository - uses: aquasecurity/trivy-action@5681af892cd0f4997658e2bacc62bd0a894cf564 # 0.27.0 + uses: aquasecurity/trivy-action@915b19bbe73b92a6cf82a1bc12b087c9a19a5fe2 # 0.28.0 with: scan-type: 'fs' scan-ref: '.' @@ -69,7 +69,7 @@ jobs: make e2e-build-crd-image - name: Run Trivy vulnerability scanner on localbuild:test - uses: aquasecurity/trivy-action@5681af892cd0f4997658e2bacc62bd0a894cf564 # 0.27.0 + uses: aquasecurity/trivy-action@915b19bbe73b92a6cf82a1bc12b087c9a19a5fe2 # 0.28.0 with: scan-type: 'image' image-ref: 'localbuild:test' @@ -77,7 +77,7 @@ jobs: version: ${{ env.TRIVY_VERSION }} - name: Run Trivy vulnerability scanner on localbuildcrd:test - uses: aquasecurity/trivy-action@5681af892cd0f4997658e2bacc62bd0a894cf564 # 0.27.0 + uses: aquasecurity/trivy-action@915b19bbe73b92a6cf82a1bc12b087c9a19a5fe2 # 0.28.0 with: scan-type: 'image' image-ref: 'localbuildcrd:test' @@ -85,7 +85,7 @@ jobs: version: ${{ env.TRIVY_VERSION }} - name: Run Trivy vulnerability scanner on localbuild:test and exit on HIGH severity - uses: aquasecurity/trivy-action@5681af892cd0f4997658e2bacc62bd0a894cf564 # 0.27.0 + uses: aquasecurity/trivy-action@915b19bbe73b92a6cf82a1bc12b087c9a19a5fe2 # 0.28.0 with: scan-type: 'image' image-ref: 'localbuild:test' @@ -95,7 +95,7 @@ jobs: version: ${{ env.TRIVY_VERSION }} - name: Run Trivy vulnerability scanner on localbuildcrd:test and exit on HIGH severity - uses: aquasecurity/trivy-action@5681af892cd0f4997658e2bacc62bd0a894cf564 # 0.27.0 + uses: aquasecurity/trivy-action@915b19bbe73b92a6cf82a1bc12b087c9a19a5fe2 # 0.28.0 with: scan-type: 'image' image-ref: 'localbuildcrd:test' From deafb4aaa456c2ef4c535d0d1463ff6c95f6ce8c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 16 Oct 2024 07:52:24 +0000 Subject: [PATCH 08/18] chore: Bump github.com/aws/aws-sdk-go-v2/config from 1.27.41 to 1.27.43 (#1861) 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 47064879b..49cfc2ea3 100644 --- a/go.mod +++ b/go.mod @@ -13,9 +13,9 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1 github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.6.0 github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 - github.com/aws/aws-sdk-go-v2 v1.32.0 - github.com/aws/aws-sdk-go-v2/config v1.27.41 - github.com/aws/aws-sdk-go-v2/credentials v1.17.39 + github.com/aws/aws-sdk-go-v2 v1.32.2 + 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 github.com/cespare/xxhash/v2 v2.3.0 github.com/dapr/go-sdk v1.8.0 @@ -139,14 +139,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.15 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.19 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.19 // 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/internal/ini v1.8.1 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.0 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.24.0 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.0 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.32.0 // 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/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 cbf0082b8..e99841334 100644 --- a/go.sum +++ b/go.sum @@ -125,18 +125,18 @@ github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3d github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/aws/aws-sdk-go v1.51.6 h1:Ld36dn9r7P9IjU8WZSaswQ8Y/XUCRpewim5980DwYiU= github.com/aws/aws-sdk-go v1.51.6/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= -github.com/aws/aws-sdk-go-v2 v1.32.0 h1:GuHp7GvMN74PXD5C97KT5D87UhIy4bQPkflQKbfkndg= -github.com/aws/aws-sdk-go-v2 v1.32.0/go.mod h1:2SK5n0a2karNTv5tbP1SjsX0uhttou00v/HpXKM1ZUo= -github.com/aws/aws-sdk-go-v2/config v1.27.41 h1:esG3WpmEuNJ6F4kVFLumN8nCfA5VBav1KKb3JPx83O4= -github.com/aws/aws-sdk-go-v2/config v1.27.41/go.mod h1:haUg09ebP+ClvPjU3EB/xe0HF9PguO19PD2fdjM2X14= -github.com/aws/aws-sdk-go-v2/credentials v1.17.39 h1:tmVexAhoGqJxNE2oc4/SJqL+Jz1x1iCPt5ts9XcqZCU= -github.com/aws/aws-sdk-go-v2/credentials v1.17.39/go.mod h1:zgOdbDI9epE608PdboJ87CYvPIejAgFevazeJW6iauQ= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.15 h1:kGjlNc2IXXcxPDcfMyCshNCjVgxUhC/vTJv7NvC9wKk= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.15/go.mod h1:rk/HmqPo+dX0Uv0Q1+4w3QKFdICEGSsTYz1hRWvH8UI= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.19 h1:Q/k5wCeJkSWs+62kDfOillkNIJ5NqmE3iOfm48g/W8c= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.19/go.mod h1:Wns1C66VvtA2Bv/cUBuKZKQKdjo7EVMhp90aAa+8oTI= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.19 h1:AYLE0lUfKvN6icFTR/p+NmD1amYKTbqHQ1Nm+jwE6BM= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.19/go.mod h1:1giLakj64GjuH1NBzF/DXqly5DWHtMTaOzRZ53nFX0I= +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/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/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= github.com/aws/aws-sdk-go-v2/service/ecr v1.28.6 h1:CnQNpQv+WGl5aECyAXrJ4w+Qccz2aC/uXg2OjxiPl30= @@ -145,16 +145,16 @@ github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.23.7 h1:dsmihXaPkhFuUTiL+ygm9R github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.23.7/go.mod h1:g7If3uXj+mKcmIuxh08qh8I9ju6f/aOSWMyc6hEEi58= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.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.0 h1:AdbiDUgQZmM28rDIZbiSwFxz8+3B94aOXxzs6oH+EA0= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.0/go.mod h1:uV476Bd80tiDTX4X2redMtagQUg65aU/gzPojSJ4kSI= +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/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.0 h1:71FvP6XFj53NK+YiAEGVzeiccLVeFnHOCvMig0zOHsE= -github.com/aws/aws-sdk-go-v2/service/sso v1.24.0/go.mod h1:UVJqtKXSd9YppRKgdBIkyv7qgbSGv5DchM3yX0BN2mU= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.0 h1:Uco4o19bi3AmBapImNzuMk+rfzlui52BDyVK1UfJeRA= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.0/go.mod h1:+HLFhCpnG08hBee8bUdfd1mBK+rFKPt4O5igR9lXDfk= -github.com/aws/aws-sdk-go-v2/service/sts v1.32.0 h1:GiQUjZM2KUZX68o/LpZ1xqxYMuvoxpRrOwYARYog3vc= -github.com/aws/aws-sdk-go-v2/service/sts v1.32.0/go.mod h1:dKnu7M4MAS2SDlng1ytxd03H+y0LoUfEQ5E2VaaSw/4= +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/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 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 09/18] 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 10/18] 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 11/18] 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 12/18] 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 13/18] 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 14/18] 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 15/18] 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 16/18] 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 17/18] 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 18/18] 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 \