diff --git a/.github/dependabot.yml b/.github/dependabot.yml index b39c03108ed..5c17c1be8f6 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -35,3 +35,13 @@ updates: update-types: - "minor" - "patch" + + - package-ecosystem: "docker" + directory: "/" + schedule: + interval: "weekly" + groups: + all: + update-types: + - "minor" + - "patch" diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 71b9de6c8c7..da86591a6c1 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -44,22 +44,26 @@ jobs: packages: write steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: persist-credentials: false - - uses: sigstore/cosign-installer@d58896d6a1865668819e1d91763c7751a165e159 # v3.9.2 + - uses: sigstore/cosign-installer@faadad0cce49287aee09b3a48701e75088a2c6ad # v4.0.0 - - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 + - name: Extract version of Go to use + run: echo "GOVERSION=$(awk -F'[:@]' '/FROM golang/{print $2; exit}' Dockerfile)" >> $GITHUB_ENV + + - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: - go-version-file: 'go.mod' + go-version: '${{ env.GOVERSION }}' check-latest: true + cache: false # will use the latest release available for ko - uses: ko-build/setup-ko@d006021bd0c28d1ce33a07e7943d48b079944c8d # v0.9 - name: Set up Cloud SDK - uses: google-github-actions/auth@140bb5113ffb6b65a7e9b937a81fa96cf5064462 # v2.1.11 + uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3.0.0 with: workload_identity_provider: 'projects/498091336538/locations/global/workloadIdentityPools/githubactions/providers/sigstore-cosign' service_account: 'github-actions@projectsigstore.iam.gserviceaccount.com' @@ -68,7 +72,7 @@ jobs: run: gcloud auth configure-docker --quiet - name: Login to GitHub Container Registry - uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 + uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0 with: registry: ghcr.io username: ${{ github.actor }} diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index b9ec879d307..9903e6d564c 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -51,12 +51,12 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: persist-credentials: false - name: Utilize Go Module Cache - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: | ~/go/pkg/mod @@ -65,11 +65,14 @@ jobs: restore-keys: | ${{ runner.os }}-go- - - name: Set correct version of Golang to use during CodeQL run - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 + - name: Extract version of Go to use + run: echo "GOVERSION=$(awk -F'[:@]' '/FROM golang/{print $2; exit}' Dockerfile)" >> $GITHUB_ENV + + - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: - go-version-file: 'go.mod' + go-version: '${{ env.GOVERSION }}' check-latest: true + cache: false # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.github/workflows/conformance-nightly.yml b/.github/workflows/conformance-nightly.yml index 29b8590970a..4d24caaf7ce 100644 --- a/.github/workflows/conformance-nightly.yml +++ b/.github/workflows/conformance-nightly.yml @@ -27,13 +27,18 @@ jobs: conformance: runs-on: ubuntu-latest steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: persist-credentials: false - - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 + + - name: Extract version of Go to use + run: echo "GOVERSION=$(awk -F'[:@]' '/FROM golang/{print $2; exit}' Dockerfile)" >> $GITHUB_ENV + + - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: - go-version-file: 'go.mod' + go-version: '${{ env.GOVERSION }}' check-latest: true + cache: false - run: make cosign conformance @@ -43,7 +48,7 @@ jobs: - name: Create Issue on Failure if: failure() - uses: actions/github-script@v7 + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | diff --git a/.github/workflows/conformance.yml b/.github/workflows/conformance.yml index d64220099de..579fba4027a 100644 --- a/.github/workflows/conformance.yml +++ b/.github/workflows/conformance.yml @@ -29,16 +29,21 @@ jobs: conformance: runs-on: ubuntu-latest steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: persist-credentials: false - - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 + + - name: Extract version of Go to use + run: echo "GOVERSION=$(awk -F'[:@]' '/FROM golang/{print $2; exit}' Dockerfile)" >> $GITHUB_ENV + + - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: - go-version-file: 'go.mod' + go-version: '${{ env.GOVERSION }}' check-latest: true + cache: false - run: make cosign conformance - - uses: sigstore/sigstore-conformance@fd90e6b0f3046f2276a6659481de6df495dea3b9 # v0.0.18 + - uses: sigstore/sigstore-conformance@b7856cfca56fe3f957d4cefdc2c359cc36a84e14 # v0.0.24 with: entrypoint: ${{ github.workspace }}/conformance diff --git a/.github/workflows/donotsubmit.yaml b/.github/workflows/donotsubmit.yaml index 43cdb3a4975..d471c1444fe 100644 --- a/.github/workflows/donotsubmit.yaml +++ b/.github/workflows/donotsubmit.yaml @@ -35,9 +35,9 @@ jobs: steps: - name: Check out code - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v2.4.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 #v2.4.0 with: persist-credentials: false - name: Do Not Submit - uses: chainguard-dev/actions/donotsubmit@708219d4822f33611ac1a2653815cc10e1ab54a6 # v1.4.7 + uses: chainguard-dev/actions/donotsubmit@3e8a2a226fad9e1ecbf2d359b8a7697554a4ac6d # v1.5.10 diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index b8ceccc4247..d1d671bfcd6 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -39,13 +39,18 @@ jobs: runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: persist-credentials: false - - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 + + - name: Extract version of Go to use + run: echo "GOVERSION=$(awk -F'[:@]' '/FROM golang/{print $2; exit}' Dockerfile)" >> $GITHUB_ENV + + - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: - go-version-file: 'go.mod' + go-version: '${{ env.GOVERSION }}' check-latest: true + cache: false - name: Run cross platform e2e tests run: go test -tags=e2e,cross -v ./test/... @@ -54,13 +59,18 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: persist-credentials: false - - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 + + - name: Extract version of Go to use + run: echo "GOVERSION=$(awk -F'[:@]' '/FROM golang/{print $2; exit}' Dockerfile)" >> $GITHUB_ENV + + - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: - go-version-file: 'go.mod' + go-version: '${{ env.GOVERSION }}' check-latest: true + cache: false - name: Run pkcs11 end-to-end tests shell: bash @@ -89,17 +99,21 @@ jobs: SCAFFOLDING_RELEASE_VERSION: "v0.7.24" steps: - name: Checkout - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: persist-credentials: false - name: setup vault - uses: cpanato/vault-installer@e7c1d664fa15219e89e43739e39a9df11ba00849 # v1.2.0 + uses: cpanato/vault-installer@f7e2ad9737b49f351f233eba2df1bdfede939a21 # v1.3.0 - - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 + - name: Extract version of Go to use + run: echo "GOVERSION=$(awk -F'[:@]' '/FROM golang/{print $2; exit}' Dockerfile)" >> $GITHUB_ENV + + - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: - go-version-file: 'go.mod' + go-version: '${{ env.GOVERSION }}' check-latest: true + cache: false - uses: imjasonh/setup-crane@31b88efe9de28ae0ffa220711af4b60be9435f6e # v0.4 @@ -121,16 +135,21 @@ jobs: SCAFFOLDING_RELEASE_VERSION: "v0.7.24" steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: persist-credentials: false - - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 + + - name: Extract version of Go to use + run: echo "GOVERSION=$(awk -F'[:@]' '/FROM golang/{print $2; exit}' Dockerfile)" >> $GITHUB_ENV + + - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: - go-version-file: 'go.mod' + go-version: '${{ env.GOVERSION }}' check-latest: true + cache: false - name: Setup mirror - uses: chainguard-dev/actions/setup-mirror@main + uses: chainguard-dev/actions/setup-mirror@3e8a2a226fad9e1ecbf2d359b8a7697554a4ac6d # v1.5.10 with: mirror: mirror.gcr.io @@ -167,6 +186,7 @@ jobs: run: go test -tags=e2e,registry -v ./test/... env: COSIGN_TEST_REPO: insecure-registry.notlocal:5001 + TUF_ROOT_JSON: ${{ github.workspace }}/root.json - name: Setup local insecure OCI 1.1 registry run: | @@ -217,7 +237,24 @@ jobs: env: OCI11: yes COSIGN_TEST_REPO: insecure-oci-registry.notlocal:5002 + TUF_ROOT_JSON: ${{ github.workspace }}/root.json + + - name: Set up local HTTP registry + run: | + docker run -d --restart=always \ + --name $HTTP_REGISTRY_NAME \ + -p $HTTP_REGISTRY_PORT:5000 registry:2.8.1 + sudo echo "127.0.0.1 $HTTP_REGISTRY_NAME" | sudo tee -a /etc/hosts + env: + HTTP_REGISTRY_NAME: http-registry.notlocal + HTTP_REGISTRY_PORT: 5003 + + - name: Run HTTP registry tests + run: go test -tags=e2e,registry -v ./test/... + env: + COSIGN_TEST_REPO: http-registry.notlocal:5003 + TUF_ROOT_JSON: ${{ github.workspace }}/root.json - name: Collect diagnostics if: ${{ failure() }} - uses: chainguard-dev/actions/kind-diag@708219d4822f33611ac1a2653815cc10e1ab54a6 # v1.4.7 + uses: chainguard-dev/actions/kind-diag@3e8a2a226fad9e1ecbf2d359b8a7697554a4ac6d # v1.5.10 diff --git a/.github/workflows/e2e-with-binary.yml b/.github/workflows/e2e-with-binary.yml index ccb4ae7cc4f..eb0251640e7 100644 --- a/.github/workflows/e2e-with-binary.yml +++ b/.github/workflows/e2e-with-binary.yml @@ -48,35 +48,26 @@ jobs: COSIGN_YES: "true" steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: persist-credentials: false - - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 + + - name: Extract version of Go to use + shell: bash # To use awk on Windows + run: echo "GOVERSION=$(awk -F'[:@]' '/FROM golang/{print $2; exit}' Dockerfile)" >> $GITHUB_ENV + + - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: - go-version-file: 'go.mod' + go-version: '${{ env.GOVERSION }}' check-latest: true + cache: false + - name: build cosign and check sign-blob and verify-blob shell: bash run: | set -e make cosign - ./cosign sign-blob --output-certificate certificate.pem --output-signature README.md.sig README.md - - if [ -s certificate.pem ] - then - echo "all good for key.pem" - else - echo "file does not exist, or is empty" - exit 1 - fi - - if [ -s README.md.sig ] - then - exit 0 - else - echo "file does not exist, or is empty" - exit 1 - fi + ./cosign sign-blob --bundle sigstore.json --yes README.md # Verify with sign-blob - ./cosign verify-blob README.md --certificate certificate.pem --signature README.md.sig + ./cosign verify-blob --bundle sigstore.json --certificate-identity-regexp ".*" --certificate-oidc-issuer-regexp ".*" README.md diff --git a/.github/workflows/github-oidc.yaml b/.github/workflows/github-oidc.yaml index e9a837fa96c..4cbdaa80190 100644 --- a/.github/workflows/github-oidc.yaml +++ b/.github/workflows/github-oidc.yaml @@ -48,14 +48,18 @@ jobs: KO_PREFIX: ghcr.io/${{ github.repository }} steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: persist-credentials: false - - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 + + - name: Extract version of Go to use + run: echo "GOVERSION=$(awk -F'[:@]' '/FROM golang/{print $2; exit}' Dockerfile)" >> $GITHUB_ENV + + - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: - go-version-file: 'go.mod' + go-version: '${{ env.GOVERSION }}' check-latest: true - cache: true + cache: false # Install tools. - uses: ko-build/setup-ko@d006021bd0c28d1ce33a07e7943d48b079944c8d # v0.9 diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index e78b11219bc..85aa9c569e8 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -31,17 +31,23 @@ jobs: contents: read steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: persist-credentials: false - - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 + + - name: Extract version of Go to use + run: echo "GOVERSION=$(awk -F'[:@]' '/FROM golang/{print $2; exit}' Dockerfile)" >> $GITHUB_ENV + + - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: - go-version-file: 'go.mod' + go-version: '${{ env.GOVERSION }}' check-latest: true + cache: false + - name: golangci-lint - uses: golangci/golangci-lint-action@4afd733a84b1f43292c63897423277bb7f4313a9 # v8.0.0 + uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0 with: - version: v2.2 + version: v2.5 golangci-test-e2e: name: lint-test-e2e @@ -51,15 +57,21 @@ jobs: contents: read steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: persist-credentials: false - - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 + + - name: Extract version of Go to use + run: echo "GOVERSION=$(awk -F'[:@]' '/FROM golang/{print $2; exit}' Dockerfile)" >> $GITHUB_ENV + + - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: - go-version-file: 'go.mod' + go-version: '${{ env.GOVERSION }}' check-latest: true + cache: false + - name: golangci-lint - uses: golangci/golangci-lint-action@4afd733a84b1f43292c63897423277bb7f4313a9 # v8.0.0 + uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0 with: - version: v2.2 + version: v2.4 args: --build-tags e2e ./test diff --git a/.github/workflows/kind-verify-attestation.yaml b/.github/workflows/kind-verify-attestation.yaml index cddb4c31444..365a0111060 100644 --- a/.github/workflows/kind-verify-attestation.yaml +++ b/.github/workflows/kind-verify-attestation.yaml @@ -53,19 +53,24 @@ jobs: COSIGN_YES: "true" steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: persist-credentials: false - - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 + + - name: Extract version of Go to use + run: echo "GOVERSION=$(awk -F'[:@]' '/FROM golang/{print $2; exit}' Dockerfile)" >> $GITHUB_ENV + + - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: - go-version-file: 'go.mod' + go-version: '${{ env.GOVERSION }}' check-latest: true + cache: false # will use the latest release available for ko - uses: ko-build/setup-ko@d006021bd0c28d1ce33a07e7943d48b079944c8d # v0.9 - name: Install yq - uses: mikefarah/yq@f03c9dc599c37bfcaf533427211d05e51e6fee64 # v4.47.1 + uses: mikefarah/yq@7ccaf8e700ce99eb3f0f6cef7f5930a0b3c827cd # v4.49.2 - name: build cosign run: | @@ -100,38 +105,58 @@ jobs: TUF_MIRROR=$(kubectl -n tuf-system get ksvc tuf -ojsonpath='{.status.url}') ./cosign initialize --mirror $TUF_MIRROR --root ./root.json - - name: Initialize with custom TUF root pointing to local filesystem - if: ${{ matrix.tuf-root == 'air-gap' }} + - name: Get copy of TUF repository run: | # Grab the compressed repository for airgap testing. kubectl -n tuf-system get secrets tuf-root -ojsonpath='{.data.repository}' | base64 -d > ./repository.tar.gz tar -zxvf ./repository.tar.gz + + - name: Initialize with custom TUF root pointing to local filesystem + if: ${{ matrix.tuf-root == 'air-gap' }} + run: | + # Grab the compressed repository for airgap testing. PWD=$(pwd) ROOT=${PWD}/repository/1.root.json REPOSITORY=${PWD}/repository ./cosign initialize --root ${ROOT} --mirror file://${REPOSITORY} + - name: Set TrustedRoot + run: | + trustedroot=$(find ./repository/targets -name "*.trusted_root.json") + echo "trustedroot=$trustedroot" >> $GITHUB_ENV + + - name: Create SigningConfig + run: | + ./cosign signing-config create \ + --fulcio="url=${FULCIO_URL},api-version=1,start-time=2024-01-01T00:00:00Z,operator=sigstore.dev" \ + --rekor="url=${REKOR_URL},api-version=1,start-time=2024-01-01T00:00:00Z,operator=sigstore.dev" \ + --rekor-config="ANY" \ + --tsa="url=${TSA_URL}/api/v1/timestamp,api-version=1,start-time=2024-01-01T00:00:00Z,operator=sigstore.dev" \ + --tsa-config="EXACT:1" \ + --out signingconfig.json + echo "signingconfig=signingconfig.json" >> $GITHUB_ENV + - name: Sign demoimage with cosign run: | - ./cosign sign --rekor-url ${REKOR_URL} --fulcio-url ${FULCIO_URL} --yes --allow-insecure-registry ${demoimage} --identity-token ${OIDC_TOKEN} + ./cosign sign --signing-config=${signingconfig} --trusted-root=${trustedroot} --yes --allow-insecure-registry ${demoimage} --identity-token ${OIDC_TOKEN} - name: Create attestation for it run: | echo -n 'foobar e2e test' > ./predicate-file - ./cosign attest --predicate ./predicate-file --fulcio-url ${FULCIO_URL} --rekor-url ${REKOR_URL} --allow-insecure-registry --yes ${demoimage} --identity-token ${OIDC_TOKEN} + ./cosign attest --predicate ./predicate-file --signing-config=${signingconfig} --trusted-root=${trustedroot} --allow-insecure-registry --yes ${demoimage} --identity-token ${OIDC_TOKEN} - name: Sign a blob run: | - ./cosign sign-blob README.md --fulcio-url ${FULCIO_URL} --rekor-url ${REKOR_URL} --output-certificate cert.pem --output-signature sig --yes --identity-token ${OIDC_TOKEN} + ./cosign sign-blob README.md --signing-config=${signingconfig} --trusted-root=${trustedroot} --bundle blob.sigstore.json --yes --identity-token ${OIDC_TOKEN} - name: Verify with cosign run: | - ./cosign verify --rekor-url ${REKOR_URL} --allow-insecure-registry ${demoimage} --certificate-identity https://kubernetes.io/namespaces/default/serviceaccounts/default --certificate-oidc-issuer "https://kubernetes.default.svc.cluster.local" + ./cosign verify --trusted-root=${trustedroot} --allow-insecure-registry ${demoimage} --certificate-identity https://kubernetes.io/namespaces/default/serviceaccounts/default --certificate-oidc-issuer "https://kubernetes.default.svc.cluster.local" - name: Verify custom attestation with cosign, works run: | echo '::group:: test custom verify-attestation success' - if ! ./cosign verify-attestation --certificate-identity https://kubernetes.io/namespaces/default/serviceaccounts/default --certificate-oidc-issuer "https://kubernetes.default.svc.cluster.local" --policy ./test/testdata/policies/cue-works.cue --rekor-url ${REKOR_URL} --allow-insecure-registry ${demoimage} ; then + if ! ./cosign verify-attestation --trusted-root=${trustedroot} --certificate-identity https://kubernetes.io/namespaces/default/serviceaccounts/default --certificate-oidc-issuer "https://kubernetes.default.svc.cluster.local" --policy ./test/testdata/policies/cue-works.cue --allow-insecure-registry ${demoimage} ; then echo Failed to verify attestation with a valid policy exit 1 else @@ -142,7 +167,7 @@ jobs: - name: Verify custom attestation with cosign, fails run: | echo '::group:: test custom verify-attestation success' - if ./cosign verify-attestation --policy ./test/testdata/policies/cue-fails.cue --rekor-url ${REKOR_URL} --allow-insecure-registry ${demoimage} --certificate-identity https://kubernetes.io/namespaces/default/serviceaccounts/default --certificate-oidc-issuer "https://kubernetes.default.svc.cluster.local" ; then + if ./cosign verify-attestation --trusted-root=${trustedroot} --policy ./test/testdata/policies/cue-fails.cue --allow-insecure-registry ${demoimage} --certificate-identity https://kubernetes.io/namespaces/default/serviceaccounts/default --certificate-oidc-issuer "https://kubernetes.default.svc.cluster.local" ; then echo custom verify-attestation succeeded with cue policy that should not work exit 1 else @@ -152,20 +177,20 @@ jobs: - name: Verify a blob run: | - ./cosign verify-blob README.md --rekor-url ${REKOR_URL} --certificate ./cert.pem --signature sig --certificate-identity https://kubernetes.io/namespaces/default/serviceaccounts/default --certificate-oidc-issuer "https://kubernetes.default.svc.cluster.local" + ./cosign verify-blob README.md --trusted-root=${trustedroot} --bundle blob.sigstore.json --certificate-identity https://kubernetes.io/namespaces/default/serviceaccounts/default --certificate-oidc-issuer "https://kubernetes.default.svc.cluster.local" - name: Collect diagnostics if: ${{ failure() }} - uses: chainguard-dev/actions/kind-diag@708219d4822f33611ac1a2653815cc10e1ab54a6 # v1.4.7 + uses: chainguard-dev/actions/kind-diag@3e8a2a226fad9e1ecbf2d359b8a7697554a4ac6d # v1.5.10 - name: Create vuln attestation for it run: | - ./cosign attest --predicate ./test/testdata/attestations/vuln-predicate.json --type vuln --fulcio-url ${FULCIO_URL} --rekor-url ${REKOR_URL} --allow-insecure-registry --yes ${demoimage} --identity-token ${OIDC_TOKEN} + ./cosign attest --predicate ./test/testdata/attestations/vuln-predicate.json --type vuln --signing-config=${signingconfig} --trusted-root=${trustedroot} --allow-insecure-registry --yes ${demoimage} --identity-token ${OIDC_TOKEN} - name: Verify vuln attestation with cosign, works run: | echo '::group:: test vuln verify-attestation success' - if ! ./cosign verify-attestation --type vuln --policy ./test/testdata/policies/cue-vuln-works.cue --rekor-url ${REKOR_URL} --allow-insecure-registry ${demoimage} --certificate-identity https://kubernetes.io/namespaces/default/serviceaccounts/default --certificate-oidc-issuer "https://kubernetes.default.svc.cluster.local" ; then + if ! ./cosign verify-attestation --trusted-root=${trustedroot} --type vuln --policy ./test/testdata/policies/cue-vuln-works.cue --allow-insecure-registry ${demoimage} --certificate-identity https://kubernetes.io/namespaces/default/serviceaccounts/default --certificate-oidc-issuer "https://kubernetes.default.svc.cluster.local" ; then echo Failed to verify attestation with a valid policy exit 1 else @@ -176,7 +201,7 @@ jobs: - name: Verify vuln attestation with cosign, fails run: | echo '::group:: test vuln verify-attestation success' - if ./cosign verify-attestation --type vuln --policy ./test/testdata/policies/cue-vuln-fails.cue --rekor-url ${REKOR_URL} --allow-insecure-registry ${demoimage} --certificate-identity https://kubernetes.io/namespaces/default/serviceaccounts/default --certificate-oidc-issuer "https://kubernetes.default.svc.cluster.local" ; then + if ./cosign verify-attestation --trusted-root=${trustedroot} --type vuln --policy ./test/testdata/policies/cue-vuln-fails.cue --allow-insecure-registry ${demoimage} --certificate-identity https://kubernetes.io/namespaces/default/serviceaccounts/default --certificate-oidc-issuer "https://kubernetes.default.svc.cluster.local" ; then echo verify-attestation succeeded with cue policy that should not work exit 1 else diff --git a/.github/workflows/scorecard-action.yml b/.github/workflows/scorecard-action.yml index 3083085cf82..8f62afaf766 100644 --- a/.github/workflows/scorecard-action.yml +++ b/.github/workflows/scorecard-action.yml @@ -40,12 +40,12 @@ jobs: steps: - name: "Checkout code" - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: persist-credentials: false - name: "Run analysis" - uses: ossf/scorecard-action@05b42c624433fc40578a4040d5cf5e36ddca8cde # v2.4.2 + uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3 with: results_file: results.sarif results_format: sarif @@ -61,7 +61,7 @@ jobs: # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF # format to the repository Actions tab. - name: "Upload artifact" - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 with: name: SARIF file path: results.sarif diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index d87b0bfd58b..dca93c7e35f 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -41,11 +41,12 @@ jobs: OS: ${{ matrix.os }} steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: persist-credentials: false + # https://github.com/mvdan/github-actions-golang#how-do-i-set-up-caching-between-builds - - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: # In order: # * Module download cache @@ -60,16 +61,25 @@ jobs: key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} restore-keys: | ${{ runner.os }}-go- - - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 + + - name: Extract version of Go to use + shell: bash # To use awk on Windows + run: echo "GOVERSION=$(awk -F'[:@]' '/FROM golang/{print $2; exit}' Dockerfile)" >> $GITHUB_ENV + + - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: - go-version-file: 'go.mod' + go-version: '${{ env.GOVERSION }}' check-latest: true + cache: false + - name: Run Go tests run: go test -covermode atomic -coverprofile coverage.txt $(go list ./... | grep -v third_party/) + - name: Upload Coverage Report - uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24 # v5.4.3 + uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1 with: env_vars: OS + - name: Run Go tests w/ `-race` if: ${{ runner.os == 'Linux' }} run: go test -race $(go list ./... | grep -v third_party/) @@ -81,7 +91,7 @@ jobs: contents: read steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: persist-credentials: false # Related to https://github.com/sigstore/cosign/issues/3149 @@ -138,7 +148,7 @@ jobs: - name: check disk space run: df -h # https://github.com/mvdan/github-actions-golang#how-do-i-set-up-caching-between-builds - - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: # In order: # * Module download cache @@ -153,10 +163,16 @@ jobs: key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} restore-keys: | ${{ runner.os }}-go- - - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 + + - name: Extract version of Go to use + run: echo "GOVERSION=$(awk -F'[:@]' '/FROM golang/{print $2; exit}' Dockerfile)" >> $GITHUB_ENV + + - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: - go-version-file: 'go.mod' + go-version: '${{ env.GOVERSION }}' check-latest: true + cache: false + - uses: ko-build/setup-ko@d006021bd0c28d1ce33a07e7943d48b079944c8d # v0.9 - name: setup kind cluster run: | @@ -169,7 +185,7 @@ jobs: - name: Collect diagnostics if: ${{ failure() }} - uses: chainguard-dev/actions/kind-diag@708219d4822f33611ac1a2653815cc10e1ab54a6 # v1.4.7 + uses: chainguard-dev/actions/kind-diag@3e8a2a226fad9e1ecbf2d359b8a7697554a4ac6d # v1.5.10 e2e-windows-powershell-tests: name: Run PowerShell E2E tests @@ -177,16 +193,22 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: persist-credentials: false - - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 + + - name: Extract version of Go to use + shell: bash # To use awk on Windows + run: echo "GOVERSION=$(awk -F'[:@]' '/FROM golang/{print $2; exit}' Dockerfile)" >> $GITHUB_ENV + + - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: - go-version-file: 'go.mod' + go-version: '${{ env.GOVERSION }}' check-latest: true + cache: false # https://github.com/mvdan/github-actions-golang#how-do-i-set-up-caching-between-builds - - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: # In order: # * Module download cache @@ -207,15 +229,22 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: persist-credentials: false - - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 + + - name: Extract version of Go to use + run: echo "GOVERSION=$(awk -F'[:@]' '/FROM golang/{print $2; exit}' Dockerfile)" >> $GITHUB_ENV + + - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: - go-version-file: 'go.mod' + go-version: '${{ env.GOVERSION }}' check-latest: true + cache: false + - name: Install addlicense run: go install github.com/google/addlicense@latest + - name: Check license headers run: | set -e diff --git a/.github/workflows/validate-release.yml b/.github/workflows/validate-release.yml index 7def77f8458..ef0493d005c 100644 --- a/.github/workflows/validate-release.yml +++ b/.github/workflows/validate-release.yml @@ -26,14 +26,14 @@ jobs: check-signature: runs-on: ubuntu-latest container: - image: ghcr.io/sigstore/cosign/cosign:v2.5.2-dev@sha256:14a20131240190350e18f002bdd61345d2803eff370913737392281e834ee22a + image: ghcr.io/sigstore/cosign/cosign:v3.0.2-dev@sha256:322c53c5f3e4516351bd8cb793ff46ad3809eed48a53daf0da1bae8f4d550e18 steps: - name: Check Signature run: | - cosign verify ghcr.io/gythialy/golang-cross:v1.24.5-0@sha256:492c51e60ed27ff597511b0a24e6c5acb6e3e2e97bb68d7bd35f81a7e3dfa4d0 \ + cosign verify ghcr.io/gythialy/golang-cross:v1.25.5-0@sha256:3a7d463d9e3438513b6bd597c79f7d5db756023e04718259cc25aabd5d00fc17 \ --certificate-oidc-issuer https://token.actions.githubusercontent.com \ - --certificate-identity "https://github.com/gythialy/golang-cross/.github/workflows/release-golang-cross.yml@refs/tags/v1.24.5-0" + --certificate-identity "https://github.com/gythialy/golang-cross/.github/workflows/release-golang-cross.yml@refs/tags/v1.25.5-0" env: TUF_ROOT: /tmp @@ -43,7 +43,7 @@ jobs: - check-signature container: - image: ghcr.io/gythialy/golang-cross:v1.24.5-0@sha256:492c51e60ed27ff597511b0a24e6c5acb6e3e2e97bb68d7bd35f81a7e3dfa4d0 + image: ghcr.io/gythialy/golang-cross:v1.25.5-0@sha256:3a7d463d9e3438513b6bd597c79f7d5db756023e04718259cc25aabd5d00fc17 volumes: - /usr:/host_usr - /opt:/host_opt @@ -51,7 +51,7 @@ jobs: permissions: {} steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: persist-credentials: false diff --git a/.github/workflows/verify-docgen.yaml b/.github/workflows/verify-docgen.yaml index 79d81f15d87..d1d826027b4 100644 --- a/.github/workflows/verify-docgen.yaml +++ b/.github/workflows/verify-docgen.yaml @@ -36,11 +36,18 @@ jobs: steps: - name: deps run: sudo apt-get update && sudo apt-get install -yq libpcsclite-dev - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: persist-credentials: false - - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0 + + - name: Extract version of Go to use + run: echo "GOVERSION=$(awk -F'[:@]' '/FROM golang/{print $2; exit}' Dockerfile)" >> $GITHUB_ENV + + - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: - go-version-file: 'go.mod' + go-version: '${{ env.GOVERSION }}' check-latest: true + cache: false + - run: ./cmd/help/verify.sh diff --git a/.github/workflows/whitespace.yaml b/.github/workflows/whitespace.yaml index 525a9d3b776..20c46369d03 100644 --- a/.github/workflows/whitespace.yaml +++ b/.github/workflows/whitespace.yaml @@ -34,12 +34,12 @@ jobs: steps: - name: Check out code - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: persist-credentials: false - - uses: chainguard-dev/actions/trailing-space@708219d4822f33611ac1a2653815cc10e1ab54a6 # v1.4.7 + - uses: chainguard-dev/actions/trailing-space@3e8a2a226fad9e1ecbf2d359b8a7697554a4ac6d # v1.5.10 if: ${{ always() }} - - uses: chainguard-dev/actions/eof-newline@708219d4822f33611ac1a2653815cc10e1ab54a6 # v1.4.7 + - uses: chainguard-dev/actions/eof-newline@3e8a2a226fad9e1ecbf2d359b8a7697554a4ac6d # v1.5.10 if: ${{ always() }} diff --git a/.gitignore b/.gitignore index 473584dc6fa..4c5ee9a79ea 100644 --- a/.gitignore +++ b/.gitignore @@ -27,7 +27,7 @@ bin* dist/ cosignImagerefs -bundle +/bundle signature certificate sigstore-conformance diff --git a/.golangci.yml b/.golangci.yml index 5dacb8d3224..8d91818665a 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -51,8 +51,8 @@ linters: settings: printf: funcs: - - github.com/sigstore/cosign/v2/internal/ui.Infof - - github.com/sigstore/cosign/v2/internal/ui.Warnf + - github.com/sigstore/cosign/v3/internal/ui.Infof + - github.com/sigstore/cosign/v3/internal/ui.Warnf exclusions: generated: lax presets: @@ -78,6 +78,11 @@ linters: path: pkg/cosign/verify.go # NewEntry used for Rekor v1, will update to NewTlogEntry for Rekor v2 support text: SA1019 + - linters: + - staticcheck + path: pkg/cosign/verify_bundle_test.go + # NewEntry used for Rekor v1, will update to NewTlogEntry for Rekor v2 support + text: SA1019 paths: - third_party$ - builtin$ diff --git a/.goreleaser.yml b/.goreleaser.yml index f9ad566f9d4..5c4f276f5b1 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -153,28 +153,25 @@ builds: signs: - id: cosign - signature: "${artifact}.sig" cmd: ./dist/cosign-linux-amd64 - args: ["sign-blob", "--output-signature", "${artifact}.sig", "--key", "gcpkms://projects/{{ .Env.PROJECT_ID }}/locations/{{ .Env.KEY_LOCATION }}/keyRings/{{ .Env.KEY_RING }}/cryptoKeys/{{ .Env.KEY_NAME }}/versions/{{ .Env.KEY_VERSION }}", "${artifact}"] + args: ["sign-blob", "--bundle", "${signature}", "--key", "gcpkms://projects/{{ .Env.PROJECT_ID }}/locations/{{ .Env.KEY_LOCATION }}/keyRings/{{ .Env.KEY_RING }}/cryptoKeys/{{ .Env.KEY_NAME }}/versions/{{ .Env.KEY_VERSION }}", "${artifact}"] + signature: "${artifact}-kms.sigstore.json" artifacts: binary # Keyless - id: cosign-keyless - signature: "${artifact}-keyless.sig" - certificate: "${artifact}-keyless.pem" cmd: ./dist/cosign-linux-amd64 - args: ["sign-blob", "--output-signature", "${artifact}-keyless.sig", "--output-certificate", "${artifact}-keyless.pem", "${artifact}"] + args: ["sign-blob", "--bundle", "${signature}", "${artifact}"] + signature: "${artifact}.sigstore.json" artifacts: binary - id: checksum-keyless - signature: "${artifact}-keyless.sig" - certificate: "${artifact}-keyless.pem" cmd: ./dist/cosign-linux-amd64 - args: ["sign-blob", "--output-signature", "${artifact}-keyless.sig", "--output-certificate", "${artifact}-keyless.pem", "${artifact}"] + args: ["sign-blob", "--bundle", "${signature}", "${artifact}"] + signature: "${artifact}.sigstore.json" artifacts: checksum - id: packages-keyless - signature: "${artifact}-keyless.sig" - certificate: "${artifact}-keyless.pem" cmd: ./dist/cosign-linux-amd64 - args: ["sign-blob", "--output-signature", "${artifact}-keyless.sig", "--output-certificate", "${artifact}-keyless.pem", "${artifact}"] + args: ["sign-blob", "--bundle", "${signature}", "${artifact}"] + signature: "${artifact}.sigstore.json" artifacts: package nfpms: diff --git a/CHANGELOG.md b/CHANGELOG.md index f4000a587d6..b68bea7d74b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,145 @@ +# v3.0.3 + +Thank you for all of your feedback on Cosign v3! v3.0.3 fixes a number of bugs reported by +the community along with adding compatibility for the new bundle format and attestation +storage in OCI to additional commands. We're continuing to work on compatibility with +the remaining commands and will have a new release shortly. If you run into any problems, +please [file an issue](https://github.com/sigstore/cosign/issues) + +## Changes + +* 4554: Closes 4554 - Add warning when --output* is used (#4556) +* Protobuf bundle support for subcommand `clean` (#4539) +* Add staging flag to initialize with staging TUF metadata +* Updating sign-blob to also support signing with a certificate (#4547) +* Protobuf bundle support for subcommands `save` and `load` (#4538) +* Fix cert attachment for new bundle with signing config +* Fix OCI verification with local cert - old bundle +* Deprecate tlog-upload flag (#4458) +* fix: Use signal context for `sign` cli package. +* update offline verification directions (#4526) +* Fix signing/verifying annotations for new bundle +* Add support to download and attach for protobuf bundles (#4477) +* Add --signing-algorithm flag (#3497) +* Refactor signcommon bundle helpers +* Add --bundle and fix --upload for new bundle +* Pass insecure registry flags through to referrers +* Add protobuf bundle support for tree subcommand (#4491) +* Remove stale embed import (#4492) +* Support multiple container identities +* Fix segfault when no attestations are found (#4472) +* Use overridden repository for new bundle format (#4473) +* Remove --out flag from `cosign initialize` (#4462) +* Deprecate offline flag (#4457) +* Deduplicate code in sign/attest* and verify* commands (#4449) +* Cache signing config when calling initialize (#4456) + +# v3.0.2 + +v3.0.2 is a functionally equivalent release to v3.0.0 and v3.0.1, with a fix for CI to publish signed releases in the new bundle format. + +* Note that the `--bundle` flag specifying an output file to write the Sigstore bundle (which contains all relevant verification material) has moved from optional to required in v3. + +## Changes + +* choose different signature filename for KMS-signed release signatures (#4448) +* Update rekor-tiles version path (#4450) + +# v3.0.1 + +v3.0.1 is an equivalent release to v3.0.0, which was never published due to a failure in our CI workflows. + +* Note that the `--bundle` flag specifying an output file to write the Sigstore bundle (which contains all relevant verification material) has moved from optional to required in v3. + +## Changes + +* update goreleaser config for v3.0.0 release (#4446) + +# v3.0.0 + +Announcing the next major release of Cosign! + +Cosign v3 is a minor change from Cosign v2.6.x, with all of the new capabilities of recent +releases **on by default**, but will still allow you to disable them if you need the older functionality. +These new features include support for the standardized bundle format (`--new-bundle-fomat`), providing roots +of trust for verification and service URLs for signing via one file (`--trusted-root`, `--signing-config`), +and container signatures stored as an OCI Image 1.1 referring artifact. + +Learn more on our [v3 announcement blog post](https://blog.sigstore.dev/cosign-3-0-available/)! See +the changelogs for [v2.6.0](#v260), [v2.5.0](#v250), and [v2.4.0](#v240) for more information on recent +changes. + +If you have any feedback, please reach out on Slack or file an issue on GitHub. + +## Changes + +* Default to using the new protobuf format (#4318) +* Fetch service URLs from the TUF PGI signing config by default (#4428) +* Bump module version to v3 for Cosign v3.0 (#4427) + +# v2.6.1 + +## Bug Fixes + +* Partially populate the output of cosign verify when working with new bundles (#4416) +* Bump sigstore-go, move conformance back to tagged release (#4426) + +# v2.6.0 + +v2.6.0 introduces a number of new features, including: + +* Signing an in-toto statement rather than Cosign constructing one from a predicate, along with verifying a statement's subject using a digest and digest algorithm rather than providing a file reference (#4306) +* Uploading a signature and its verification material (a ["bundle"](https://github.com/sigstore/protobuf-specs/blob/main/protos/sigstore_bundle.proto)) as an OCI Image 1.1 referring artifact, completing [#3927](https://github.com/sigstore/cosign/issues/3927) (#4316) +* Providing service URLs for signing and attesting using a [SigningConfig](https://github.com/sigstore/protobuf-specs/blob/4df5baadcdb582a70c2bc032e042c0a218eb3841/protos/sigstore_trustroot.proto#L185). Note that this is required when using a [Rekor v2](https://github.com/sigstore/rekor-tiles) instance (#4319) + +Example generation and verification of a signed in-toto statement: + +``` +cosign attest-blob --new-bundle-format=true --bundle="digest-key-test.sigstore.json" --key="cosign.key" --statement="../sigstore-go/examples/sigstore-go-signing/intoto.txt" +cosign verify-blob-attestation --bundle="digest-key-test.sigstore.json" --key=cosign.pub --type=unused --digest="b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9" --digestAlg="sha256" +``` + +Example container signing and verification using the new bundle format and referring artifacts: + +``` +cosign sign --new-bundle-format=true ghcr.io/user/alpine@sha256:a19367999603840546b8612572e338ec076c6d1f2fec61760a9e11410f546733 +cosign verify --new-bundle-format=true ghcr.io/user/alpine@sha256:a19367999603840546b8612572e338ec076c6d1f2fec61760a9e11410f546733 +``` + +Example usage of a signing config provided by the public good instance's TUF repository: + +``` +cosign sign-blob --use-signing-config --bundle sigstore.json README.md +cosign verify-blob --new-bundle-format --bundle sigstore.json --certificate-identity $EMAIL --certificate-oidc-issuer $ISSUER --use-signed-timestamps README.md +``` + +v2.6.0 leverages sigstore-go's signing and verification APIs gated behind these new flags. In an upcoming major release, we will be +updating Cosign to default to producing and consuming bundles to align with all other Sigstore SDKs. + +## Features + +* Add to `attest-blob` the ability to supply a complete in-toto statement, and add to `verify-blob-attestation` the ability to verify with just a digest (#4306) +* Have cosign sign support bundle format (#4316) +* Add support for SigningConfig for sign-blob/attest-blob, support Rekor v2 (#4319) +* Add support for SigningConfig in sign/attest (#4371) +* Support self-managed keys when signing with sigstore-go (#4368) +* Don't require timestamps when verifying with a key (#4337) +* Don't load content from TUF if trusted root path is specified (#4347) +* Add a terminal spinner while signing with sigstore-go (#4402) +* Require exclusively a SigningConfig or service URLs when signing (#4403) +* Remove SHA256 assumption in sign-blob/verify-blob (#4050) +* Bump sigstore-go, support alternative hash algorithms with keys (#4386) + +## Breaking API Changes + +* `sign.SignerFromKeyOpts` no longer generates a key. Instead, it returns whether or not the client needs to generate a key, and if so, clients +should call `sign.KeylessSigner`. This allows clients to more easily manage key generation. + +## Bug Fixes + +* Verify subject with bundle only when checking claims (#4320) +* Fixes to cosign sign / verify for the new bundle format (#4346) + # v2.5.3 ## Features diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000000..947427698ee --- /dev/null +++ b/Dockerfile @@ -0,0 +1,18 @@ +# +# Copyright 2025 The Sigstore 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. + +# This is used to we scrap the go version and use in CI to get the latest go version +# and we use dependabot to keep the go version up to date +FROM golang:1.25.5 diff --git a/Makefile b/Makefile index 92b2171e3b9..53ded438b33 100644 --- a/Makefile +++ b/Makefile @@ -171,7 +171,7 @@ ko-cosign: KOCACHE=$(KOCACHE_PATH) ko build --base-import-paths \ --platform=all --tags $(GIT_VERSION) --tags $(GIT_HASH)$(LATEST_TAG) \ $(ARTIFACT_HUB_LABELS) --image-refs cosignImagerefs \ - github.com/sigstore/cosign/v2/cmd/cosign + github.com/sigstore/cosign/v3/cmd/cosign .PHONY: ko-cosign-dev ko-cosign-dev: @@ -180,7 +180,7 @@ ko-cosign-dev: KOCACHE=$(KOCACHE_PATH) KO_DEFAULTBASEIMAGE=gcr.io/distroless/static-debian12:debug-nonroot ko build --base-import-paths \ --platform=all --tags $(GIT_VERSION)-dev --tags $(GIT_HASH)-dev$(LATEST_TAG)-dev \ $(ARTIFACT_HUB_LABELS) --image-refs cosignDevImagerefs \ - github.com/sigstore/cosign/v2/cmd/cosign + github.com/sigstore/cosign/v3/cmd/cosign .PHONY: ko-local ko-local: @@ -189,7 +189,7 @@ ko-local: KOCACHE=$(KOCACHE_PATH) ko build --base-import-paths \ --tags $(GIT_VERSION) --tags $(GIT_HASH) \ $(ARTIFACT_HUB_LABELS) \ - github.com/sigstore/cosign/v2/cmd/cosign + github.com/sigstore/cosign/v3/cmd/cosign .PHONY: ko-local-dev ko-local-dev: @@ -198,7 +198,7 @@ ko-local-dev: KOCACHE=$(KOCACHE_PATH) KO_DEFAULTBASEIMAGE=gcr.io/distroless/static-debian12:debug-nonroot ko build --base-import-paths \ --tags $(GIT_VERSION) --tags $(GIT_HASH) \ $(ARTIFACT_HUB_LABELS) \ - github.com/sigstore/cosign/v2/cmd/cosign + github.com/sigstore/cosign/v3/cmd/cosign ################## # help diff --git a/README.md b/README.md index 7083fd71df4..cecd6c0ccb5 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ Cosign supports: `Cosign` is developed as part of the [`sigstore`](https://sigstore.dev) project. We also use a [slack channel](https://sigstore.slack.com)! -Click [here](https://join.slack.com/t/sigstore/shared_invite/zt-mhs55zh0-XmY3bcfWn4XEyMqUUutbUQ) for the invite link. +Click [here](https://join.slack.com/t/sigstore/shared_invite/zt-2ub0ztl5z-PkWb_Ldwef5d6nb~oryaTA) for the invite link. ## Installation @@ -141,6 +141,14 @@ The following checks were performed on these signatures: ### Verify a container in an air-gapped environment +**Note:** This section is out of date. + +**Note:** Most verification workflows require periodically requesting service keys from a TUF repository. +For airgapped verification of signatures using the public-good instance, you will need to retrieve the +[trusted root](https://github.com/sigstore/root-signing/blob/main/targets/trusted_root.json) file from the production +TUF repository. The contents of this file will change without notification. By not using TUF, you will need +to build your own mechanism to keep your airgapped copy of this file up-to-date. + Cosign can do completely offline verification by verifying a [bundle](./specs/SIGNATURE_SPEC.md#properties) which is typically distributed as an annotation on the image manifest. As long as this annotation is present, then offline verification can be done. This bundle annotation is always included by default for keyless signing, so the default `cosign sign` functionality will include all materials needed for offline verification. @@ -156,8 +164,14 @@ cosign save $IMAGE_NAME --dir ./path/to/dir Now, in an air-gapped environment, this local image can be verified: -``` -cosign verify --certificate-identity $CERT_IDENTITY --certificate-oidc-issuer $CERT_OIDC_ISSUER --offline --local-image ./path/to/dir +```shell +cosign verify \ + --certificate-identity $CERT_IDENTITY \ + --certificate-oidc-issuer $CERT_OIDC_ISSUER \ + --offline=true \ + --new-bundle-format=false \ # for artifacts signed without the new protobuf bundle format + --trusted-root ~/.sigstore/root/tuf-repo-cdn.sigstore.dev/targets/trusted_root.json \ # default location of trusted root + --local-image ./path/to/dir ``` You'll need to pass in expected values for `$CERT_IDENTITY` and `$CERT_OIDC_ISSUER` to correctly verify this image. @@ -761,8 +775,6 @@ will be released when there are breaking features. Should you discover any security issues, please refer to sigstore's [security process](https://github.com/sigstore/.github/blob/main/SECURITY.md) -## PEM files in GitHub Release Assets - -The GitHub release assets for cosign contain a PEM file produced by [GoReleaser](https://github.com/sigstore/cosign/blob/ac999344eb381ae91455b0a9c5c267e747608d76/.goreleaser.yml#L166) while signing the cosign blob that is used to verify the integrity of the release binaries. This file is not used by cosign itself, but is provided for users who wish to verify the integrity of the release binaries. +## Bundle files in GitHub Release Assets -By default, cosign output these PEM files in [base64 encoded format](https://github.com/sigstore/cosign/blob/main/doc/cosign_sign-blob.md#options), this approach might be good for air-gapped environments where the PEM file is stored in a file system. So, you should decode these PEM files before using them to verify the blobs. +The GitHub release assets for `cosign` contain Sigstore bundle files produced by [GoReleaser](https://github.com/sigstore/cosign/blob/ac999344eb381ae91455b0a9c5c267e747608d76/.goreleaser.yml#L166) while signing the cosign blob that is used to verify the integrity of the release binaries. This file is not used by cosign itself, but is provided for users who wish to [verify the integrity of the release binaries](https://docs.sigstore.dev/cosign/system_config/installation/#verifying-cosign-with-artifact-key). diff --git a/cmd/conformance/main.go b/cmd/conformance/main.go index d4916df6df6..6415341135d 100644 --- a/cmd/conformance/main.go +++ b/cmd/conformance/main.go @@ -30,10 +30,11 @@ var certOIDC *string var certSAN *string var identityToken *string var trustedRootPath *string +var signingConfigPath *string func usage() { fmt.Println("Usage:") - fmt.Printf("\t%s sign-bundle --identity-token TOKEN --bundle FILE FILE\n", os.Args[0]) + fmt.Printf("\t%s sign-bundle --identity-token TOKEN [--signing-config FILE] [--trusted-root FILE] --bundle FILE FILE\n", os.Args[0]) fmt.Printf("\t%s verify-bundle --bundle FILE --certificate-identity IDENTITY --certificate-oidc-issuer URL [--trusted-root FILE] FILE\n", os.Args[0]) } @@ -61,6 +62,9 @@ func parseArgs() { case "--trusted-root": trustedRootPath = &os.Args[i+1] i += 2 + case "--signing-config": + signingConfigPath = &os.Args[i+1] + i += 2 default: i++ } @@ -121,6 +125,9 @@ func main() { if trustedRootPath != nil { args = append(args, "--trusted-root", *trustedRootPath) } + if signingConfigPath != nil { + args = append(args, "--signing-config", *signingConfigPath) + } args = append(args, os.Args[len(os.Args)-1]) dir := filepath.Dir(os.Args[0]) diff --git a/cmd/cosign/cli/attach.go b/cmd/cosign/cli/attach.go index f8c384f97ac..e2c56239276 100644 --- a/cmd/cosign/cli/attach.go +++ b/cmd/cosign/cli/attach.go @@ -19,8 +19,8 @@ import ( "fmt" "os" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/attach" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/attach" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" "github.com/spf13/cobra" ) diff --git a/cmd/cosign/cli/attach/attach.go b/cmd/cosign/cli/attach/attach.go index 76bb5078c8f..15440379cb9 100644 --- a/cmd/cosign/cli/attach/attach.go +++ b/cmd/cosign/cli/attach/attach.go @@ -22,12 +22,13 @@ import ( "github.com/google/go-containerregistry/pkg/name" ssldsse "github.com/secure-systems-lab/go-securesystemslib/dsse" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/internal/ui" - "github.com/sigstore/cosign/v2/pkg/oci/mutate" - ociremote "github.com/sigstore/cosign/v2/pkg/oci/remote" - "github.com/sigstore/cosign/v2/pkg/oci/static" - "github.com/sigstore/cosign/v2/pkg/types" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/internal/ui" + "github.com/sigstore/cosign/v3/pkg/oci/mutate" + ociremote "github.com/sigstore/cosign/v3/pkg/oci/remote" + "github.com/sigstore/cosign/v3/pkg/oci/static" + "github.com/sigstore/cosign/v3/pkg/types" + "github.com/sigstore/sigstore-go/pkg/bundle" ) func AttestationCmd(ctx context.Context, regOpts options.RegistryOptions, signedPayloads []string, imageRef string) error { @@ -37,7 +38,28 @@ func AttestationCmd(ctx context.Context, regOpts options.RegistryOptions, signed } for _, payload := range signedPayloads { - if err := attachAttestation(ctx, ociremoteOpts, payload, imageRef, regOpts.NameOptions()); err != nil { + fmt.Fprintf(os.Stderr, "Using payload from: %s", payload) + + ref, err := name.ParseReference(imageRef, regOpts.NameOptions()...) + if err != nil { + return err + } + if _, ok := ref.(name.Digest); !ok { + ui.Warnf(ctx, ui.TagReferenceMessage, imageRef) + } + + digest, err := ociremote.ResolveDigest(ref, ociremoteOpts...) + if err != nil { + return err + } + + // Detect if we are using new bundle format + b, err := bundle.LoadJSONFromPath(payload) + if err == nil { + return attachAttestationNewBundle(ociremoteOpts, b, digest) + } + + if err := attachAttestation(ociremoteOpts, payload, digest); err != nil { return fmt.Errorf("attaching payload from %s: %w", payload, err) } } @@ -45,8 +67,29 @@ func AttestationCmd(ctx context.Context, regOpts options.RegistryOptions, signed return nil } -func attachAttestation(ctx context.Context, remoteOpts []ociremote.Option, signedPayload, imageRef string, nameOpts []name.Option) error { - fmt.Fprintf(os.Stderr, "Using payload from: %s", signedPayload) +func attachAttestationNewBundle(remoteOpts []ociremote.Option, b *bundle.Bundle, digest name.Digest) error { + envelope, err := b.Envelope() + if err != nil { + return err + } + if envelope == nil { + return fmt.Errorf("bundle does not have DSSE envelope") + } + statement, err := envelope.Statement() + if err != nil { + return err + } + if statement == nil { + return fmt.Errorf("unable to understand bundle envelope statement") + } + bundleBytes, err := b.MarshalJSON() + if err != nil { + return err + } + return ociremote.WriteAttestationNewBundleFormat(digest, bundleBytes, statement.PredicateType, remoteOpts...) +} + +func attachAttestation(remoteOpts []ociremote.Option, signedPayload string, digest name.Digest) error { attestationFile, err := os.Open(signedPayload) if err != nil { return err @@ -73,22 +116,6 @@ func attachAttestation(ctx context.Context, remoteOpts []ociremote.Option, signe return fmt.Errorf("could not attach attestation without having signatures") } - ref, err := name.ParseReference(imageRef, nameOpts...) - if err != nil { - return err - } - if _, ok := ref.(name.Digest); !ok { - ui.Warnf(ctx, ui.TagReferenceMessage, imageRef) - } - digest, err := ociremote.ResolveDigest(ref, remoteOpts...) - if err != nil { - return err - } - // Overwrite "ref" with a digest to avoid a race where we use a tag - // multiple times, and it potentially points to different things at - // each access. - ref = digest // nolint - opts := []static.Option{static.WithLayerMediaType(types.DssePayloadType)} att, err := static.NewAttestation(payload, opts...) if err != nil { diff --git a/cmd/cosign/cli/attach/sbom.go b/cmd/cosign/cli/attach/sbom.go index df651197f63..a7a4f84dd78 100644 --- a/cmd/cosign/cli/attach/sbom.go +++ b/cmd/cosign/cli/attach/sbom.go @@ -33,11 +33,11 @@ import ( "github.com/google/go-containerregistry/pkg/v1/remote/transport" ocistatic "github.com/google/go-containerregistry/pkg/v1/static" ocitypes "github.com/google/go-containerregistry/pkg/v1/types" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - ociexperimental "github.com/sigstore/cosign/v2/internal/pkg/oci/remote" - "github.com/sigstore/cosign/v2/internal/ui" - ociremote "github.com/sigstore/cosign/v2/pkg/oci/remote" - "github.com/sigstore/cosign/v2/pkg/oci/static" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + ociexperimental "github.com/sigstore/cosign/v3/internal/pkg/oci/remote" + "github.com/sigstore/cosign/v3/internal/ui" + ociremote "github.com/sigstore/cosign/v3/pkg/oci/remote" + "github.com/sigstore/cosign/v3/pkg/oci/static" ) func SBOMCmd(ctx context.Context, regOpts options.RegistryOptions, regExpOpts options.RegistryExperimentalOptions, sbomRef string, sbomType ocitypes.MediaType, imageRef string) error { diff --git a/cmd/cosign/cli/attach/sig.go b/cmd/cosign/cli/attach/sig.go index 812c5cc87a6..c09fe03df3e 100644 --- a/cmd/cosign/cli/attach/sig.go +++ b/cmd/cosign/cli/attach/sig.go @@ -24,22 +24,16 @@ import ( "path/filepath" "github.com/google/go-containerregistry/pkg/name" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/pkg/cosign" - "github.com/sigstore/cosign/v2/pkg/cosign/bundle" - "github.com/sigstore/cosign/v2/pkg/oci/mutate" - ociremote "github.com/sigstore/cosign/v2/pkg/oci/remote" - "github.com/sigstore/cosign/v2/pkg/oci/static" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/pkg/cosign" + "github.com/sigstore/cosign/v3/pkg/cosign/bundle" + "github.com/sigstore/cosign/v3/pkg/oci/mutate" + ociremote "github.com/sigstore/cosign/v3/pkg/oci/remote" + "github.com/sigstore/cosign/v3/pkg/oci/static" + sgbundle "github.com/sigstore/sigstore-go/pkg/bundle" ) func SignatureCmd(ctx context.Context, regOpts options.RegistryOptions, sigRef, payloadRef, certRef, certChainRef, timeStampedSigRef, rekorBundleRef, imageRef string) error { - b64SigBytes, err := signatureBytes(sigRef) - if err != nil { - return err - } else if len(b64SigBytes) == 0 { - return errors.New("empty signature") - } - ref, err := name.ParseReference(imageRef, regOpts.NameOptions()...) if err != nil { return err @@ -52,10 +46,12 @@ func SignatureCmd(ctx context.Context, regOpts options.RegistryOptions, sigRef, if err != nil { return err } - // Overwrite "ref" with a digest to avoid a race where we use a tag - // multiple times, and it potentially points to different things at - // each access. - ref = digest // nolint + + // Detect if we are using new bundle format + b, err := sgbundle.LoadJSONFromPath(payloadRef) + if err == nil { + return attachAttestationNewBundle(ociremoteOpts, b, digest) + } var payload []byte if payloadRef == "" { @@ -67,6 +63,13 @@ func SignatureCmd(ctx context.Context, regOpts options.RegistryOptions, sigRef, return err } + b64SigBytes, err := signatureBytes(sigRef) + if err != nil { + return err + } else if len(b64SigBytes) == 0 { + return errors.New("empty signature") + } + sig, err := static.NewSignature(payload, string(b64SigBytes)) if err != nil { return err diff --git a/cmd/cosign/cli/attest.go b/cmd/cosign/cli/attest.go index f9ac6a85c55..d63557f6939 100644 --- a/cmd/cosign/cli/attest.go +++ b/cmd/cosign/cli/attest.go @@ -16,15 +16,12 @@ package cli import ( - "context" "fmt" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/attest" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/generate" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/internal/ui" - "github.com/sigstore/cosign/v2/pkg/cosign" - "github.com/sigstore/cosign/v2/pkg/cosign/env" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/attest" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/generate" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/signcommon" "github.com/spf13/cobra" ) @@ -78,35 +75,37 @@ func Attest() *cobra.Command { } ko := options.KeyOpts{ - KeyRef: o.Key, - PassFunc: generate.GetPass, - Sk: o.SecurityKey.Use, - Slot: o.SecurityKey.Slot, - FulcioURL: o.Fulcio.URL, - IDToken: o.Fulcio.IdentityToken, - FulcioAuthFlow: o.Fulcio.AuthFlow, - InsecureSkipFulcioVerify: o.Fulcio.InsecureSkipFulcioVerify, - RekorURL: o.Rekor.URL, - OIDCIssuer: o.OIDC.Issuer, - OIDCClientID: o.OIDC.ClientID, - OIDCClientSecret: oidcClientSecret, - OIDCRedirectURL: o.OIDC.RedirectURL, - OIDCProvider: o.OIDC.Provider, - SkipConfirmation: o.SkipConfirmation, - TSAClientCACert: o.TSAClientCACert, - TSAClientKey: o.TSAClientKey, - TSAClientCert: o.TSAClientCert, - TSAServerName: o.TSAServerName, - TSAServerURL: o.TSAServerURL, - NewBundleFormat: o.NewBundleFormat, + KeyRef: o.Key, + PassFunc: generate.GetPass, + Sk: o.SecurityKey.Use, + Slot: o.SecurityKey.Slot, + FulcioURL: o.Fulcio.URL, + IDToken: o.Fulcio.IdentityToken, + FulcioAuthFlow: o.Fulcio.AuthFlow, + InsecureSkipFulcioVerify: o.Fulcio.InsecureSkipFulcioVerify, + RekorURL: o.Rekor.URL, + OIDCIssuer: o.OIDC.Issuer, + OIDCClientID: o.OIDC.ClientID, + OIDCClientSecret: oidcClientSecret, + OIDCRedirectURL: o.OIDC.RedirectURL, + OIDCProvider: o.OIDC.Provider, + SkipConfirmation: o.SkipConfirmation, + TSAClientCACert: o.TSAClientCACert, + TSAClientKey: o.TSAClientKey, + TSAClientCert: o.TSAClientCert, + TSAServerName: o.TSAServerName, + TSAServerURL: o.TSAServerURL, + IssueCertificateForExistingKey: o.IssueCertificate, + BundlePath: o.BundlePath, + NewBundleFormat: o.NewBundleFormat, } - if o.Key == "" && env.Getenv(env.VariableSigstoreCTLogPublicKeyFile) == "" { // Get the trusted root if using fulcio for signing - trustedMaterial, err := cosign.TrustedRoot() - if err != nil { - ui.Warnf(context.Background(), "Could not fetch trusted_root.json from the TUF repository. Continuing with individual targets. Error from TUF: %v", err) - } - ko.TrustedMaterial = trustedMaterial + if err := signcommon.LoadTrustedMaterialAndSigningConfig(cmd.Context(), &ko, o.UseSigningConfig, o.SigningConfigPath, + o.Rekor.URL, o.Fulcio.URL, o.OIDC.Issuer, o.TSAServerURL, o.TrustedRootPath, o.TlogUpload, + o.NewBundleFormat, "", o.Key, o.IssueCertificate, + "", "", "", "", ""); err != nil { + return err } + attestCommand := attest.AttestCommand{ KeyOpts: ko, RegistryOptions: o.Registry, diff --git a/cmd/cosign/cli/attest/attest.go b/cmd/cosign/cli/attest/attest.go index 6a8443726e8..861a2b7716c 100644 --- a/cmd/cosign/cli/attest/attest.go +++ b/cmd/cosign/cli/attest/attest.go @@ -16,57 +16,26 @@ package attest import ( - "bytes" "context" _ "crypto/sha256" // for `crypto.SHA256` "encoding/json" "fmt" - "os" "time" "github.com/google/go-containerregistry/pkg/name" v1 "github.com/google/go-containerregistry/pkg/v1" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/rekor" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/sign" - "github.com/sigstore/cosign/v2/internal/pkg/cosign/tsa" - tsaclient "github.com/sigstore/cosign/v2/internal/pkg/cosign/tsa/client" - "github.com/sigstore/cosign/v2/internal/ui" - "github.com/sigstore/cosign/v2/pkg/cosign" - "github.com/sigstore/cosign/v2/pkg/cosign/attestation" - cbundle "github.com/sigstore/cosign/v2/pkg/cosign/bundle" - cremote "github.com/sigstore/cosign/v2/pkg/cosign/remote" - "github.com/sigstore/cosign/v2/pkg/oci/mutate" - ociremote "github.com/sigstore/cosign/v2/pkg/oci/remote" - "github.com/sigstore/cosign/v2/pkg/oci/static" - "github.com/sigstore/cosign/v2/pkg/types" - "github.com/sigstore/rekor/pkg/generated/client" - "github.com/sigstore/rekor/pkg/generated/models" - "github.com/sigstore/sigstore/pkg/signature/dsse" - signatureoptions "github.com/sigstore/sigstore/pkg/signature/options" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/signcommon" + "github.com/sigstore/cosign/v3/pkg/cosign/attestation" + cbundle "github.com/sigstore/cosign/v3/pkg/cosign/bundle" + cremote "github.com/sigstore/cosign/v3/pkg/cosign/remote" + "github.com/sigstore/cosign/v3/pkg/oci/mutate" + ociremote "github.com/sigstore/cosign/v3/pkg/oci/remote" + "github.com/sigstore/cosign/v3/pkg/oci/static" + "github.com/sigstore/cosign/v3/pkg/types" ) -type tlogUploadFn func(*client.Rekor, []byte) (*models.LogEntryAnon, error) - -func uploadToTlog(ctx context.Context, sv *sign.SignerVerifier, rekorURL string, upload tlogUploadFn) (*models.LogEntryAnon, error) { - rekorBytes, err := sv.Bytes(ctx) - if err != nil { - return nil, err - } - - rekorClient, err := rekor.NewClient(rekorURL) - if err != nil { - return nil, err - } - entry, err := upload(rekorClient, rekorBytes) - if err != nil { - return nil, err - } - fmt.Fprintln(os.Stderr, "tlog entry created with index:", *entry.LogIndex) - return entry, nil -} - // nolint type AttestCommand struct { options.KeyOpts @@ -103,14 +72,10 @@ func (c *AttestCommand) Exec(ctx context.Context, imageRef string) error { if err != nil { return err } - ref, err := name.ParseReference(imageRef, c.NameOptions()...) + ref, err := signcommon.ParseOCIReference(ctx, imageRef, c.NameOptions()...) if err != nil { return fmt.Errorf("parsing reference: %w", err) } - if _, ok := ref.(name.Digest); !ok { - msg := fmt.Sprintf(ui.TagReferenceMessage, imageRef) - ui.Warnf(ctx, msg) - } if c.Timeout != 0 { var cancelFn context.CancelFunc @@ -122,6 +87,9 @@ func (c *AttestCommand) Exec(ctx context.Context, imageRef string) error { if err != nil { return err } + if c.RegistryOptions.AllowHTTPRegistry || c.RegistryOptions.AllowInsecure { + ociremoteOpts = append(ociremoteOpts, ociremote.WithNameOptions(name.Insecure)) + } digest, err := ociremote.ResolveDigest(ref, ociremoteOpts...) if err != nil { return err @@ -132,14 +100,6 @@ func (c *AttestCommand) Exec(ctx context.Context, imageRef string) error { // each access. ref = digest // nolint - sv, err := sign.SignerFromKeyOpts(ctx, c.CertPath, c.CertChainPath, c.KeyOpts) - if err != nil { - return fmt.Errorf("getting signer: %w", err) - } - defer sv.Close() - wrapped := dsse.WrapSigner(sv, types.IntotoPayloadType) - dd := cremote.NewDupeDetector(sv) - predicate, err := predicateReader(c.PredicatePath) if err != nil { return fmt.Errorf("getting predicate reader: %w", err) @@ -160,13 +120,30 @@ func (c *AttestCommand) Exec(ctx context.Context, imageRef string) error { if err != nil { return err } - signedPayload, err := wrapped.SignMessage(bytes.NewReader(payload), signatureoptions.WithContext(ctx)) + + bundleOpts := signcommon.CommonBundleOpts{ + Payload: payload, + Digest: digest, + PredicateType: types.CosignSignPredicateType, + BundlePath: c.BundlePath, + Upload: !c.NoUpload, + OCIRemoteOpts: ociremoteOpts, + } + + if c.SigningConfig != nil { + return signcommon.WriteNewBundleWithSigningConfig(ctx, c.KeyOpts, c.CertPath, c.CertChainPath, bundleOpts, c.SigningConfig, c.TrustedMaterial) + } + + bundleComponents, closeSV, err := signcommon.GetBundleComponents(ctx, c.CertPath, c.CertChainPath, c.KeyOpts, c.NoUpload, c.TlogUpload, payload, digest, c.RekorEntryType) if err != nil { - return fmt.Errorf("signing: %w", err) + return fmt.Errorf("getting bundle components: %w", err) } + defer closeSV() - if c.NoUpload { - fmt.Println(string(signedPayload)) + sv := bundleComponents.SV + + if c.NoUpload && c.BundlePath == "" { + fmt.Println(string(bundleComponents.SignedPayload)) return nil } @@ -174,39 +151,9 @@ func (c *AttestCommand) Exec(ctx context.Context, imageRef string) error { if sv.Cert != nil { opts = append(opts, static.WithCertChain(sv.Cert, sv.Chain)) } - var timestampBytes []byte - var tsaPayload []byte - if c.KeyOpts.TSAServerURL != "" { - // We need to decide what signature to send to the timestamp authority. - // - // Historically, cosign sent `signedPayload`, which is the entire JSON DSSE - // Envelope. However, when sigstore clients are verifying a bundle they - // will use the DSSE Sig field, so we choose what signature to send to - // the timestamp authority based on our output format. - if c.KeyOpts.NewBundleFormat { - tsaPayload, err = getEnvelopeSigBytes(signedPayload) - if err != nil { - return err - } - } else { - tsaPayload = signedPayload - } - tc := tsaclient.NewTSAClient(c.KeyOpts.TSAServerURL) - if c.KeyOpts.TSAClientCert != "" { - tc = tsaclient.NewTSAClientMTLS(c.KeyOpts.TSAServerURL, - c.KeyOpts.TSAClientCACert, - c.KeyOpts.TSAClientCert, - c.KeyOpts.TSAClientKey, - c.KeyOpts.TSAServerName, - ) - } - timestampBytes, err = tsa.GetTimestampedSignature(tsaPayload, tc) - if err != nil { - return err - } - bundle := cbundle.TimestampToRFC3161Timestamp(timestampBytes) - - opts = append(opts, static.WithRFC3161Timestamp(bundle)) + + if bundleComponents.RFC3161Timestamp != nil { + opts = append(opts, static.WithRFC3161Timestamp(bundleComponents.RFC3161Timestamp)) } predicateType, err := options.ParsePredicateType(c.PredicateType) @@ -214,54 +161,27 @@ func (c *AttestCommand) Exec(ctx context.Context, imageRef string) error { return err } + bundleOpts.PredicateType = predicateType + predicateTypeAnnotation := map[string]string{ "predicateType": predicateType, } // Add predicateType as manifest annotation opts = append(opts, static.WithAnnotations(predicateTypeAnnotation)) - // Check whether we should be uploading to the transparency log - shouldUpload, err := sign.ShouldUploadToTlog(ctx, c.KeyOpts, digest, c.TlogUpload) - if err != nil { - return fmt.Errorf("should upload to tlog: %w", err) - } - var rekorEntry *models.LogEntryAnon - if shouldUpload { - rekorEntry, err = uploadToTlog(ctx, sv, c.RekorURL, func(r *client.Rekor, b []byte) (*models.LogEntryAnon, error) { - if c.RekorEntryType == "intoto" { - return cosign.TLogUploadInTotoAttestation(ctx, r, signedPayload, b) - } else { - return cosign.TLogUploadDSSEEnvelope(ctx, r, signedPayload, b) - } - - }) - if err != nil { - return err - } - opts = append(opts, static.WithBundle(cbundle.EntryToBundle(rekorEntry))) - } - - sig, err := static.NewAttestation(signedPayload, opts...) - if err != nil { - return err + if bundleComponents.RekorEntry != nil { + opts = append(opts, static.WithBundle(cbundle.EntryToBundle(bundleComponents.RekorEntry))) } if c.KeyOpts.NewBundleFormat { - signerBytes, err := sv.Bytes(ctx) - if err != nil { - return err - } - bundleBytes, err := makeNewBundle(sv, rekorEntry, payload, signedPayload, signerBytes, timestampBytes) - if err != nil { - return err - } - return ociremote.WriteAttestationNewBundleFormat(digest, bundleBytes, predicateType, ociremoteOpts...) + return signcommon.WriteBundle(ctx, sv, bundleComponents.RekorEntry, bundleOpts, bundleComponents.SignedPayload, bundleComponents.SignerBytes, bundleComponents.TimestampBytes) } // We don't actually need to access the remote entity to attach things to it // so we use a placeholder here. se := ociremote.SignedUnknown(digest, ociremoteOpts...) + dd := cremote.NewDupeDetector(sv) signOpts := []mutate.SignOption{ mutate.WithDupeDetector(dd), mutate.WithRecordCreationTimestamp(c.RecordCreationTimestamp), @@ -272,6 +192,11 @@ func (c *AttestCommand) Exec(ctx context.Context, imageRef string) error { signOpts = append(signOpts, mutate.WithReplaceOp(ro)) } + sig, err := static.NewAttestation(bundleComponents.SignedPayload, opts...) + if err != nil { + return err + } + // Attach the attestation to the entity. newSE, err := mutate.AttachAttestationToEntity(se, sig, signOpts...) if err != nil { diff --git a/cmd/cosign/cli/attest/attest_blob.go b/cmd/cosign/cli/attest/attest_blob.go index b899e3e9606..9e611f663aa 100644 --- a/cmd/cosign/cli/attest/attest_blob.go +++ b/cmd/cosign/cli/attest/attest_blob.go @@ -18,12 +18,9 @@ import ( "bytes" "context" "crypto" - "crypto/sha256" - "crypto/x509" "encoding/base64" "encoding/hex" "encoding/json" - "errors" "fmt" "io" "os" @@ -33,24 +30,13 @@ import ( "time" intotov1 "github.com/in-toto/attestation/go/v1" - "github.com/secure-systems-lab/go-securesystemslib/dsse" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/rekor" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/sign" - "github.com/sigstore/cosign/v2/internal/pkg/cosign/tsa" - tsaclient "github.com/sigstore/cosign/v2/internal/pkg/cosign/tsa/client" - "github.com/sigstore/cosign/v2/pkg/cosign" - "github.com/sigstore/cosign/v2/pkg/cosign/attestation" - cbundle "github.com/sigstore/cosign/v2/pkg/cosign/bundle" - "github.com/sigstore/cosign/v2/pkg/types" - protobundle "github.com/sigstore/protobuf-specs/gen/pb-go/bundle/v1" - protodsse "github.com/sigstore/protobuf-specs/gen/pb-go/dsse" - "github.com/sigstore/rekor/pkg/generated/models" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/signcommon" + "github.com/sigstore/cosign/v3/pkg/cosign" + "github.com/sigstore/cosign/v3/pkg/cosign/attestation" + cbundle "github.com/sigstore/cosign/v3/pkg/cosign/bundle" "github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/sigstore/sigstore/pkg/signature" - sigstoredsse "github.com/sigstore/sigstore/pkg/signature/dsse" - signatureoptions "github.com/sigstore/sigstore/pkg/signature/options" - "google.golang.org/protobuf/encoding/protojson" ) // nolint @@ -96,20 +82,10 @@ func (c *AttestBlobCommand) Exec(ctx context.Context, artifactPath string) error defer cancelFn() } - if c.TSAServerURL != "" && c.RFC3161TimestampPath == "" && !c.NewBundleFormat { - return errors.New("expected either new bundle or an rfc3161-timestamp path when using a TSA server") - } - - sv, err := sign.SignerFromKeyOpts(ctx, c.CertPath, c.CertChainPath, c.KeyOpts) - if err != nil { - return fmt.Errorf("getting signer: %w", err) - } - defer sv.Close() - wrapped := sigstoredsse.WrapSigner(sv, types.IntotoPayloadType) - base := path.Base(artifactPath) var payload []byte + var err error if c.StatementPath != "" { fmt.Fprintln(os.Stderr, "Using statement from:", c.StatementPath) @@ -165,100 +141,44 @@ func (c *AttestBlobCommand) Exec(ctx context.Context, artifactPath string) error } } - sig, err := wrapped.SignMessage(bytes.NewReader(payload), signatureoptions.WithContext(ctx)) - if err != nil { - return fmt.Errorf("signing: %w", err) + bundleOpts := signcommon.CommonBundleOpts{ + Payload: payload, + BundlePath: c.BundlePath, } - var rfc3161Timestamp *cbundle.RFC3161Timestamp - var timestampBytes []byte - var tsaPayload []byte - var rekorEntry *models.LogEntryAnon - - if c.KeyOpts.TSAServerURL != "" { - tc := tsaclient.NewTSAClient(c.KeyOpts.TSAServerURL) - if c.TSAClientCert != "" { - tc = tsaclient.NewTSAClientMTLS(c.KeyOpts.TSAServerURL, - c.KeyOpts.TSAClientCACert, - c.KeyOpts.TSAClientCert, - c.KeyOpts.TSAClientKey, - c.KeyOpts.TSAServerName, - ) - } - // We need to decide what signature to send to the timestamp authority. - // - // Historically, cosign sent `sig`, which is the entire JSON DSSE - // Envelope. However, when sigstore clients are verifying a bundle they - // will use the DSSE Sig field, so we choose what signature to send to - // the timestamp authority based on our output format. - if c.NewBundleFormat { - tsaPayload, err = getEnvelopeSigBytes(sig) - if err != nil { - return err - } - } else { - tsaPayload = sig - } - timestampBytes, err = tsa.GetTimestampedSignature(tsaPayload, tc) - if err != nil { - return err - } - rfc3161Timestamp = cbundle.TimestampToRFC3161Timestamp(timestampBytes) - // TODO: Consider uploading RFC3161 TS to Rekor - - if rfc3161Timestamp == nil { - return fmt.Errorf("rfc3161 timestamp is nil") - } - - if c.RFC3161TimestampPath != "" { - ts, err := json.Marshal(rfc3161Timestamp) - if err != nil { - return err - } - if err := os.WriteFile(c.RFC3161TimestampPath, ts, 0600); err != nil { - return fmt.Errorf("create RFC3161 timestamp file: %w", err) - } - fmt.Fprintln(os.Stderr, "RFC3161 timestamp bundle written to file ", c.RFC3161TimestampPath) - } + if c.SigningConfig != nil { + return signcommon.WriteNewBundleWithSigningConfig(ctx, c.KeyOpts, c.CertPath, c.CertChainPath, bundleOpts, c.SigningConfig, c.TrustedMaterial) } - signer, err := sv.Bytes(ctx) - if err != nil { - return err - } - shouldUpload, err := sign.ShouldUploadToTlog(ctx, c.KeyOpts, nil, c.TlogUpload) + bundleComponents, closeSV, err := signcommon.GetBundleComponents(ctx, c.CertPath, c.CertChainPath, c.KeyOpts, false, c.TlogUpload, payload, nil, c.RekorEntryType) if err != nil { - return fmt.Errorf("upload to tlog: %w", err) + return fmt.Errorf("getting bundle components: %w", err) } + defer closeSV() + + sv := bundleComponents.SV + signedPayload := cosign.LocalSignedPayload{} - if shouldUpload { - rekorClient, err := rekor.NewClient(c.RekorURL) - if err != nil { - return err - } - if c.RekorEntryType == "intoto" { - rekorEntry, err = cosign.TLogUploadInTotoAttestation(ctx, rekorClient, sig, signer) - } else { - rekorEntry, err = cosign.TLogUploadDSSEEnvelope(ctx, rekorClient, sig, signer) - } - if err != nil { - return err - } - fmt.Fprintln(os.Stderr, "tlog entry created with index:", *rekorEntry.LogIndex) - signedPayload.Bundle = cbundle.EntryToBundle(rekorEntry) + if bundleComponents.RekorEntry != nil { + signedPayload.Bundle = cbundle.EntryToBundle(bundleComponents.RekorEntry) } if c.BundlePath != "" { var contents []byte if c.NewBundleFormat { - contents, err = makeNewBundle(sv, rekorEntry, payload, sig, signer, timestampBytes) + pubKey, err := sv.PublicKey() + if err != nil { + return err + } + + contents, err = cbundle.MakeNewBundle(pubKey, bundleComponents.RekorEntry, payload, bundleComponents.SignedPayload, bundleComponents.SignerBytes, bundleComponents.TimestampBytes) if err != nil { return err } } else { - signedPayload.Base64Signature = base64.StdEncoding.EncodeToString(sig) - signedPayload.Cert = base64.StdEncoding.EncodeToString(signer) + signedPayload.Base64Signature = base64.StdEncoding.EncodeToString(bundleComponents.SignedPayload) + signedPayload.Cert = base64.StdEncoding.EncodeToString(bundleComponents.SignerBytes) contents, err = json.Marshal(signedPayload) if err != nil { @@ -273,12 +193,12 @@ func (c *AttestBlobCommand) Exec(ctx context.Context, artifactPath string) error } if c.OutputSignature != "" { - if err := os.WriteFile(c.OutputSignature, sig, 0600); err != nil { + if err := os.WriteFile(c.OutputSignature, bundleComponents.SignedPayload, 0600); err != nil { return fmt.Errorf("create signature file: %w", err) } fmt.Fprintf(os.Stderr, "Signature written in %s\n", c.OutputSignature) } else { - fmt.Fprintln(os.Stdout, string(sig)) + fmt.Fprintln(os.Stdout, string(bundleComponents.SignedPayload)) } if c.OutputAttestation != "" { @@ -289,11 +209,7 @@ func (c *AttestBlobCommand) Exec(ctx context.Context, artifactPath string) error } if c.OutputCertificate != "" { - signer, err := sv.Bytes(ctx) - if err != nil { - return fmt.Errorf("error getting signer: %w", err) - } - cert, err := cryptoutils.UnmarshalCertificatesFromPEM(signer) + cert, err := cryptoutils.UnmarshalCertificatesFromPEM(bundleComponents.SignerBytes) // signer is a certificate if err != nil { fmt.Fprintln(os.Stderr, "Could not output signer certificate. Was a certificate used? ", err) @@ -304,7 +220,7 @@ func (c *AttestBlobCommand) Exec(ctx context.Context, artifactPath string) error fmt.Fprintln(os.Stderr, "Could not output signer certificate. Expected a single certificate") return nil } - bts := signer + bts := bundleComponents.SignerBytes if err := os.WriteFile(c.OutputCertificate, bts, 0600); err != nil { return fmt.Errorf("create certificate file: %w", err) } @@ -314,67 +230,6 @@ func (c *AttestBlobCommand) Exec(ctx context.Context, artifactPath string) error return nil } -func makeNewBundle(sv *sign.SignerVerifier, rekorEntry *models.LogEntryAnon, payload, sig, signer, timestampBytes []byte) ([]byte, error) { - // Determine if signature is certificate or not - var hint string - var rawCert []byte - - cert, err := cryptoutils.UnmarshalCertificatesFromPEM(signer) - if err != nil || len(cert) == 0 { - pubKey, err := sv.PublicKey() - if err != nil { - return nil, err - } - pkixPubKey, err := x509.MarshalPKIXPublicKey(pubKey) - if err != nil { - return nil, err - } - hashedBytes := sha256.Sum256(pkixPubKey) - hint = base64.StdEncoding.EncodeToString(hashedBytes[:]) - } else { - rawCert = cert[0].Raw - } - - bundle, err := cbundle.MakeProtobufBundle(hint, rawCert, rekorEntry, timestampBytes) - if err != nil { - return nil, err - } - - var envelope dsse.Envelope - err = json.Unmarshal(sig, &envelope) - if err != nil { - return nil, err - } - - if len(envelope.Signatures) == 0 { - return nil, fmt.Errorf("no signature in DSSE envelope") - } - - sigBytes, err := base64.StdEncoding.DecodeString(envelope.Signatures[0].Sig) - if err != nil { - return nil, err - } - - bundle.Content = &protobundle.Bundle_DsseEnvelope{ - DsseEnvelope: &protodsse.Envelope{ - Payload: payload, - PayloadType: envelope.PayloadType, - Signatures: []*protodsse.Signature{ - { - Sig: sigBytes, - }, - }, - }, - } - - contents, err := protojson.Marshal(bundle) - if err != nil { - return nil, err - } - - return contents, nil -} - func validateStatement(payload []byte) (string, error) { var statement *intotov1.Statement if err := json.Unmarshal(payload, &statement); err != nil { diff --git a/cmd/cosign/cli/attest/attest_blob_test.go b/cmd/cosign/cli/attest/attest_blob_test.go index 806de15d058..cf0a8c566b5 100644 --- a/cmd/cosign/cli/attest/attest_blob_test.go +++ b/cmd/cosign/cli/attest/attest_blob_test.go @@ -33,10 +33,10 @@ import ( "github.com/in-toto/in-toto-golang/in_toto" ssldsse "github.com/secure-systems-lab/go-securesystemslib/dsse" "github.com/secure-systems-lab/go-securesystemslib/encrypted" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/generate" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/pkg/cosign" - "github.com/sigstore/cosign/v2/test" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/generate" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/internal/test" + "github.com/sigstore/cosign/v3/pkg/cosign" "github.com/sigstore/sigstore/pkg/signature" "github.com/sigstore/sigstore/pkg/signature/dsse" "github.com/stretchr/testify/assert" diff --git a/cmd/cosign/cli/attest/common.go b/cmd/cosign/cli/attest/common.go index e5f4589a343..b9bb6dcebcc 100644 --- a/cmd/cosign/cli/attest/common.go +++ b/cmd/cosign/cli/attest/common.go @@ -15,13 +15,9 @@ package attest import ( - "encoding/base64" - "encoding/json" "fmt" "io" "os" - - "github.com/secure-systems-lab/go-securesystemslib/dsse" ) func predicateReader(predicatePath string) (io.ReadCloser, error) { @@ -37,15 +33,3 @@ func predicateReader(predicatePath string) (io.ReadCloser, error) { } return f, nil } - -func getEnvelopeSigBytes(envelopeBytes []byte) ([]byte, error) { - var envelope dsse.Envelope - err := json.Unmarshal(envelopeBytes, &envelope) - if err != nil { - return nil, err - } - if len(envelope.Signatures) == 0 { - return nil, fmt.Errorf("envelope has no signatures") - } - return base64.StdEncoding.DecodeString(envelope.Signatures[0].Sig) -} diff --git a/cmd/cosign/cli/attest_blob.go b/cmd/cosign/cli/attest_blob.go index 022bd095e7f..3a953fdd28c 100644 --- a/cmd/cosign/cli/attest_blob.go +++ b/cmd/cosign/cli/attest_blob.go @@ -15,14 +15,10 @@ package cli import ( - "context" - - "github.com/sigstore/cosign/v2/cmd/cosign/cli/attest" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/generate" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/internal/ui" - "github.com/sigstore/cosign/v2/pkg/cosign" - "github.com/sigstore/cosign/v2/pkg/cosign/env" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/attest" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/generate" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/signcommon" "github.com/spf13/cobra" ) @@ -63,37 +59,38 @@ func AttestBlob() *cobra.Command { } ko := options.KeyOpts{ - KeyRef: o.Key, - PassFunc: generate.GetPass, - Sk: o.SecurityKey.Use, - Slot: o.SecurityKey.Slot, - FulcioURL: o.Fulcio.URL, - IDToken: o.Fulcio.IdentityToken, - FulcioAuthFlow: o.Fulcio.AuthFlow, - InsecureSkipFulcioVerify: o.Fulcio.InsecureSkipFulcioVerify, - RekorURL: o.Rekor.URL, - OIDCIssuer: o.OIDC.Issuer, - OIDCClientID: o.OIDC.ClientID, - OIDCClientSecret: oidcClientSecret, - OIDCRedirectURL: o.OIDC.RedirectURL, - OIDCProvider: o.OIDC.Provider, - SkipConfirmation: o.SkipConfirmation, - TSAClientCACert: o.TSAClientCACert, - TSAClientKey: o.TSAClientKey, - TSAClientCert: o.TSAClientCert, - TSAServerName: o.TSAServerName, - TSAServerURL: o.TSAServerURL, - RFC3161TimestampPath: o.RFC3161TimestampPath, - BundlePath: o.BundlePath, - NewBundleFormat: o.NewBundleFormat, + KeyRef: o.Key, + PassFunc: generate.GetPass, + Sk: o.SecurityKey.Use, + Slot: o.SecurityKey.Slot, + FulcioURL: o.Fulcio.URL, + IDToken: o.Fulcio.IdentityToken, + FulcioAuthFlow: o.Fulcio.AuthFlow, + InsecureSkipFulcioVerify: o.Fulcio.InsecureSkipFulcioVerify, + RekorURL: o.Rekor.URL, + OIDCIssuer: o.OIDC.Issuer, + OIDCClientID: o.OIDC.ClientID, + OIDCClientSecret: oidcClientSecret, + OIDCRedirectURL: o.OIDC.RedirectURL, + OIDCProvider: o.OIDC.Provider, + SkipConfirmation: o.SkipConfirmation, + TSAClientCACert: o.TSAClientCACert, + TSAClientKey: o.TSAClientKey, + TSAClientCert: o.TSAClientCert, + TSAServerName: o.TSAServerName, + TSAServerURL: o.TSAServerURL, + RFC3161TimestampPath: o.RFC3161TimestampPath, + IssueCertificateForExistingKey: o.IssueCertificate, + BundlePath: o.BundlePath, + NewBundleFormat: o.NewBundleFormat, } - if o.Key == "" && env.Getenv(env.VariableSigstoreCTLogPublicKeyFile) == "" { // Get the trusted root if using fulcio for signing - trustedMaterial, err := cosign.TrustedRoot() - if err != nil { - ui.Warnf(context.Background(), "Could not fetch trusted_root.json from the TUF repository. Continuing with individual targets. Error from TUF: %v", err) - } - ko.TrustedMaterial = trustedMaterial + if err := signcommon.LoadTrustedMaterialAndSigningConfig(cmd.Context(), &ko, o.UseSigningConfig, o.SigningConfigPath, + o.Rekor.URL, o.Fulcio.URL, o.OIDC.Issuer, o.TSAServerURL, o.TrustedRootPath, o.TlogUpload, + o.NewBundleFormat, o.BundlePath, o.Key, o.IssueCertificate, + "", o.OutputAttestation, o.OutputCertificate, "", o.OutputSignature); err != nil { + return err } + v := attest.AttestBlobCommand{ KeyOpts: ko, CertPath: o.Cert, diff --git a/cmd/cosign/cli/bundle.go b/cmd/cosign/cli/bundle.go index ba08d6b6545..25e1a24509d 100644 --- a/cmd/cosign/cli/bundle.go +++ b/cmd/cosign/cli/bundle.go @@ -18,8 +18,8 @@ package cli import ( "context" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/bundle" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/bundle" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" "github.com/spf13/cobra" ) diff --git a/cmd/cosign/cli/bundle/bundle.go b/cmd/cosign/cli/bundle/bundle.go index 54778e45e99..8fe426ed9dd 100644 --- a/cmd/cosign/cli/bundle/bundle.go +++ b/cmd/cosign/cli/bundle/bundle.go @@ -29,14 +29,14 @@ import ( "github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/sigstore/sigstore/pkg/signature" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/rekor" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/verify" - "github.com/sigstore/cosign/v2/pkg/cosign" - "github.com/sigstore/cosign/v2/pkg/cosign/bundle" - "github.com/sigstore/cosign/v2/pkg/cosign/pivkey" - "github.com/sigstore/cosign/v2/pkg/cosign/pkcs11key" - sigs "github.com/sigstore/cosign/v2/pkg/signature" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/rekor" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/verify" + "github.com/sigstore/cosign/v3/pkg/cosign" + "github.com/sigstore/cosign/v3/pkg/cosign/bundle" + "github.com/sigstore/cosign/v3/pkg/cosign/pivkey" + "github.com/sigstore/cosign/v3/pkg/cosign/pkcs11key" + sigs "github.com/sigstore/cosign/v3/pkg/signature" ) type CreateCmd struct { diff --git a/cmd/cosign/cli/bundle/bundle_test.go b/cmd/cosign/cli/bundle/bundle_test.go index 279d59bf86b..71c24355cd8 100644 --- a/cmd/cosign/cli/bundle/bundle_test.go +++ b/cmd/cosign/cli/bundle/bundle_test.go @@ -30,8 +30,8 @@ import ( "path/filepath" "testing" - "github.com/sigstore/cosign/v2/pkg/cosign" - "github.com/sigstore/cosign/v2/test" + "github.com/sigstore/cosign/v3/internal/test" + "github.com/sigstore/cosign/v3/pkg/cosign" sgBundle "github.com/sigstore/sigstore-go/pkg/bundle" "github.com/sigstore/sigstore/pkg/cryptoutils" ) diff --git a/cmd/cosign/cli/clean.go b/cmd/cosign/cli/clean.go index 32b68385700..a771d9aaf36 100644 --- a/cmd/cosign/cli/clean.go +++ b/cmd/cosign/cli/clean.go @@ -25,9 +25,10 @@ import ( "github.com/google/go-containerregistry/pkg/name" "github.com/google/go-containerregistry/pkg/v1/remote" "github.com/google/go-containerregistry/pkg/v1/remote/transport" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/internal/ui" - ociremote "github.com/sigstore/cosign/v2/pkg/oci/remote" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/internal/ui" + "github.com/sigstore/cosign/v3/pkg/cosign/bundle" + ociremote "github.com/sigstore/cosign/v3/pkg/oci/remote" "github.com/spf13/cobra" ) @@ -62,34 +63,98 @@ func CleanCmd(ctx context.Context, regOpts options.RegistryOptions, cleanType op } remoteOpts := regOpts.GetRegistryClientOpts(ctx) + ociRemoteOpts := ociremote.WithRemoteOptions(remoteOpts...) - sigRef, err := ociremote.SignatureTag(ref, ociremote.WithRemoteOptions(remoteOpts...)) + sigRef, err := ociremote.SignatureTag(ref, ociRemoteOpts) if err != nil { return err } - attRef, err := ociremote.AttestationTag(ref, ociremote.WithRemoteOptions(remoteOpts...)) + attRef, err := ociremote.AttestationTag(ref, ociRemoteOpts) if err != nil { return err } - sbomRef, err := ociremote.SBOMTag(ref, ociremote.WithRemoteOptions(remoteOpts...)) + sbomRef, err := ociremote.SBOMTag(ref, ociRemoteOpts) if err != nil { return err } - var cleanTags []name.Tag + referrerRefs := []name.Reference{} + digest, ok := ref.(name.Digest) + if !ok { + var err error + digest, err = ociremote.ResolveDigest(ref, ociRemoteOpts) + if err != nil { + return fmt.Errorf("resolving digest: %w", err) + } + } + idx, err := remote.Referrers(digest, remoteOpts...) + if err != nil { + return err + } + if idx != nil { + // Delete manifest + imgDigest, err := idx.Digest() + if err != nil { + return err + } + referrerDigestStr := fmt.Sprintf("%s@%s", ref.Context().Name(), imgDigest.String()) + referrerDigest, err := name.NewDigest(referrerDigestStr) + if err != nil { + return err + } + referrerRefs = append(referrerRefs, referrerDigest) + + // Delete layers in the manifest + idxManifest, err := idx.IndexManifest() + if err != nil { + return err + } + if idxManifest != nil { + for _, manifest := range idxManifest.Manifests { + layerDigestStr := fmt.Sprintf("%s@%s", ref.Context().Name(), manifest.Digest.String()) + layerDigest, err := name.NewDigest(layerDigestStr) + if err != nil { + return err + } + layerImage, err := remote.Image(layerDigest, remoteOpts...) + if err != nil { + return err + } + layerManifest, err := layerImage.Manifest() + if err != nil { + return err + } + if layerManifest != nil { + if layerManifest.Config.ArtifactType == bundle.BundleV03MediaType { + referrerRefs = append(referrerRefs, layerDigest) + } + } + } + } + } + + var cleanTags []name.Reference switch cleanType { case options.CleanTypeSignature: - cleanTags = []name.Tag{sigRef} + cleanTags = []name.Reference{sigRef} + if len(referrerRefs) > 0 { + ui.Warnf(ctx, "image has referrers, consider using --referrer") + } case options.CleanTypeSbom: - cleanTags = []name.Tag{sbomRef} + cleanTags = []name.Reference{sbomRef} case options.CleanTypeAttestation: - cleanTags = []name.Tag{attRef} + cleanTags = []name.Reference{attRef} + if len(referrerRefs) > 0 { + ui.Warnf(ctx, "image has referrers, consider using --referrer") + } + case options.CleanTypeReferrer: + cleanTags = referrerRefs case options.CleanTypeAll: - cleanTags = []name.Tag{sigRef, attRef, sbomRef} + cleanTags = append([]name.Reference{sigRef, attRef, sbomRef}, referrerRefs...) default: - panic("invalid CleanType value") + return errors.New("invalid CleanType value") } for _, t := range cleanTags { @@ -103,13 +168,16 @@ func CleanCmd(ctx context.Context, regOpts options.RegistryOptions, cleanType op case errors.As(err, &te) && te.StatusCode == http.StatusBadRequest: // Docker registry >=v2.3 requires does not allow deleting the OCI object name directly, must use the digest instead. // See https://github.com/distribution/distribution/blob/main/docs/content/spec/api.md#deleting-an-image - if err := deleteByDigest(t, remoteOpts...); err != nil { - if errors.As(err, &te) && te.StatusCode == http.StatusNotFound { //nolint: revive + tTag, ok := t.(name.Tag) + if ok { + if err := deleteByDigest(tTag, remoteOpts...); err != nil { + if errors.As(err, &te) && te.StatusCode == http.StatusNotFound { //nolint: revive + } else { + fmt.Fprintf(os.Stderr, "could not delete %s by digest from %s:\n%v\n", t, imageRef, err) + } } else { - fmt.Fprintf(os.Stderr, "could not delete %s by digest from %s:\n%v\n", t, imageRef, err) + fmt.Fprintf(os.Stderr, "Removed %s from %s\n", t, imageRef) } - } else { - fmt.Fprintf(os.Stderr, "Removed %s from %s\n", t, imageRef) } default: fmt.Fprintf(os.Stderr, "could not delete %s from %s:\n%v\n", t, imageRef, err) @@ -138,6 +206,8 @@ func prompt(cleanType options.CleanType) string { return "this will remove all SBOMs from the image" case options.CleanTypeAttestation: return "this will remove all attestations from the image" + case options.CleanTypeReferrer: + return "this will remove all referrer attestations and/or signatures from the image" case options.CleanTypeAll: return "this will remove all signatures, SBOMs and attestations from the image" } diff --git a/cmd/cosign/cli/commands.go b/cmd/cosign/cli/commands.go index b4d5e5887c5..36c5fd6bb9c 100644 --- a/cmd/cosign/cli/commands.go +++ b/cmd/cosign/cli/commands.go @@ -21,8 +21,8 @@ import ( cranecmd "github.com/google/go-containerregistry/cmd/crane/cmd" "github.com/google/go-containerregistry/pkg/logs" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/templates" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/templates" "github.com/spf13/cobra" "github.com/spf13/pflag" cobracompletefig "github.com/withfig/autocomplete-tools/integrations/cobra" diff --git a/cmd/cosign/cli/copy.go b/cmd/cosign/cli/copy.go index 62e487a508c..16e3c8ff798 100644 --- a/cmd/cosign/cli/copy.go +++ b/cmd/cosign/cli/copy.go @@ -16,8 +16,8 @@ package cli import ( - "github.com/sigstore/cosign/v2/cmd/cosign/cli/copy" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/copy" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" "github.com/spf13/cobra" ) diff --git a/cmd/cosign/cli/copy/copy.go b/cmd/cosign/cli/copy/copy.go index fefe8d3bc88..bcc4c2b1c51 100644 --- a/cmd/cosign/cli/copy/copy.go +++ b/cmd/cosign/cli/copy/copy.go @@ -26,11 +26,11 @@ import ( v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/remote" "github.com/google/go-containerregistry/pkg/v1/remote/transport" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/pkg/oci" - ociplatform "github.com/sigstore/cosign/v2/pkg/oci/platform" - ociremote "github.com/sigstore/cosign/v2/pkg/oci/remote" - "github.com/sigstore/cosign/v2/pkg/oci/walk" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/pkg/oci" + ociplatform "github.com/sigstore/cosign/v3/pkg/oci/platform" + ociremote "github.com/sigstore/cosign/v3/pkg/oci/remote" + "github.com/sigstore/cosign/v3/pkg/oci/walk" "golang.org/x/sync/errgroup" "k8s.io/apimachinery/pkg/util/sets" ) diff --git a/cmd/cosign/cli/copy/copy_test.go b/cmd/cosign/cli/copy/copy_test.go index 737e0df9dd6..d6ceed02b20 100644 --- a/cmd/cosign/cli/copy/copy_test.go +++ b/cmd/cosign/cli/copy/copy_test.go @@ -19,8 +19,8 @@ import ( "reflect" "testing" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - ociremote "github.com/sigstore/cosign/v2/pkg/oci/remote" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + ociremote "github.com/sigstore/cosign/v3/pkg/oci/remote" ) func TestCopyAttachmentTagPrefix(t *testing.T) { diff --git a/cmd/cosign/cli/debug.go b/cmd/cosign/cli/debug.go index 277c85a2830..a6c1bccd5a6 100644 --- a/cmd/cosign/cli/debug.go +++ b/cmd/cosign/cli/debug.go @@ -15,7 +15,7 @@ package cli import ( - "github.com/sigstore/cosign/v2/cmd/cosign/cli/debug" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/debug" "github.com/spf13/cobra" ) diff --git a/cmd/cosign/cli/debug/provider.go b/cmd/cosign/cli/debug/provider.go index debf57d1bd1..1d7af3d2c53 100644 --- a/cmd/cosign/cli/debug/provider.go +++ b/cmd/cosign/cli/debug/provider.go @@ -19,7 +19,7 @@ import ( "fmt" "io" - "github.com/sigstore/cosign/v2/pkg/providers" + "github.com/sigstore/cosign/v3/pkg/providers" ) func ProviderCmd(ctx context.Context, w io.Writer) error { diff --git a/cmd/cosign/cli/dockerfile.go b/cmd/cosign/cli/dockerfile.go index 5f207af2cc9..f988ed89921 100644 --- a/cmd/cosign/cli/dockerfile.go +++ b/cmd/cosign/cli/dockerfile.go @@ -18,9 +18,9 @@ package cli import ( "fmt" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/dockerfile" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/verify" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/dockerfile" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/verify" "github.com/spf13/cobra" ) diff --git a/cmd/cosign/cli/dockerfile/verify.go b/cmd/cosign/cli/dockerfile/verify.go index e0ffb8851ee..a6d51e6e16b 100644 --- a/cmd/cosign/cli/dockerfile/verify.go +++ b/cmd/cosign/cli/dockerfile/verify.go @@ -24,8 +24,8 @@ import ( "os" "strings" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/verify" - "github.com/sigstore/cosign/v2/internal/ui" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/verify" + "github.com/sigstore/cosign/v3/internal/ui" ) // VerifyCommand verifies a signature on a supplied container image diff --git a/cmd/cosign/cli/download.go b/cmd/cosign/cli/download.go index 61d0b9eca2a..a38f2e966fc 100644 --- a/cmd/cosign/cli/download.go +++ b/cmd/cosign/cli/download.go @@ -19,8 +19,8 @@ import ( "fmt" "os" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/download" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/download" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" "github.com/spf13/cobra" ) @@ -49,7 +49,7 @@ func downloadSignature() *cobra.Command { Args: cobra.ExactArgs(1), PersistentPreRun: options.BindViper, RunE: func(cmd *cobra.Command, args []string) error { - return download.SignatureCmd(cmd.Context(), *o, args[0]) + return download.SignatureCmd(cmd.Context(), *o, args[0], cmd.OutOrStdout()) }, } @@ -94,7 +94,7 @@ func downloadAttestation() *cobra.Command { Args: cobra.ExactArgs(1), PersistentPreRun: options.BindViper, RunE: func(cmd *cobra.Command, args []string) error { - return download.AttestationCmd(cmd.Context(), *o, *ao, args[0]) + return download.AttestationCmd(cmd.Context(), *o, *ao, args[0], cmd.OutOrStdout()) }, } diff --git a/cmd/cosign/cli/download/attestation.go b/cmd/cosign/cli/download/attestation.go index 152e934103d..cbbb965a7c4 100644 --- a/cmd/cosign/cli/download/attestation.go +++ b/cmd/cosign/cli/download/attestation.go @@ -19,16 +19,16 @@ import ( "context" "encoding/json" "errors" - "fmt" + "io" "github.com/google/go-containerregistry/pkg/name" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/pkg/cosign" - "github.com/sigstore/cosign/v2/pkg/oci/platform" - ociremote "github.com/sigstore/cosign/v2/pkg/oci/remote" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/pkg/cosign" + "github.com/sigstore/cosign/v3/pkg/oci/platform" + ociremote "github.com/sigstore/cosign/v3/pkg/oci/remote" ) -func AttestationCmd(ctx context.Context, regOpts options.RegistryOptions, attOptions options.AttestationDownloadOptions, imageRef string) error { +func AttestationCmd(ctx context.Context, regOpts options.RegistryOptions, attOptions options.AttestationDownloadOptions, imageRef string, out io.Writer) error { ref, err := name.ParseReference(imageRef, regOpts.NameOptions()...) if err != nil { return err @@ -46,6 +46,35 @@ func AttestationCmd(ctx context.Context, regOpts options.RegistryOptions, attOpt } } + // Try bundles first + newBundles, _, err := cosign.GetBundles(ctx, ref, ociremoteOpts) + if err == nil && len(newBundles) > 0 { + for _, eachBundle := range newBundles { + if predicateType != "" { + envelope, err := eachBundle.Envelope() + if err != nil || envelope == nil { + continue + } + statement, err := envelope.Statement() + if err != nil || statement == nil { + continue + } + if statement.PredicateType != predicateType { + continue + } + } + b, err := json.Marshal(eachBundle) + if err != nil { + return err + } + _, err = out.Write(append(b, byte('\n'))) + if err != nil { + return err + } + } + return nil + } + se, err := ociremote.SignedEntity(ref, ociremoteOpts...) var entityNotFoundError *ociremote.EntityNotFoundError if err != nil { @@ -76,7 +105,10 @@ func AttestationCmd(ctx context.Context, regOpts options.RegistryOptions, attOpt if err != nil { return err } - fmt.Println(string(b)) + _, err = out.Write(append(b, byte('\n'))) + if err != nil { + return err + } } return nil } diff --git a/cmd/cosign/cli/download/sbom.go b/cmd/cosign/cli/download/sbom.go index 66ff4257259..4191d517dd1 100644 --- a/cmd/cosign/cli/download/sbom.go +++ b/cmd/cosign/cli/download/sbom.go @@ -23,10 +23,10 @@ import ( "os" "github.com/google/go-containerregistry/pkg/name" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/pkg/oci" - "github.com/sigstore/cosign/v2/pkg/oci/platform" - ociremote "github.com/sigstore/cosign/v2/pkg/oci/remote" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/pkg/oci" + "github.com/sigstore/cosign/v3/pkg/oci/platform" + ociremote "github.com/sigstore/cosign/v3/pkg/oci/remote" ) func SBOMCmd( diff --git a/cmd/cosign/cli/download/signature.go b/cmd/cosign/cli/download/signature.go index 64639c3232f..deb3d67c3be 100644 --- a/cmd/cosign/cli/download/signature.go +++ b/cmd/cosign/cli/download/signature.go @@ -18,14 +18,14 @@ package download import ( "context" "encoding/json" - "fmt" + "io" "github.com/google/go-containerregistry/pkg/name" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/pkg/cosign" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/pkg/cosign" ) -func SignatureCmd(ctx context.Context, regOpts options.RegistryOptions, imageRef string) error { +func SignatureCmd(ctx context.Context, regOpts options.RegistryOptions, imageRef string, out io.Writer) error { ref, err := name.ParseReference(imageRef, regOpts.NameOptions()...) if err != nil { return err @@ -34,6 +34,23 @@ func SignatureCmd(ctx context.Context, regOpts options.RegistryOptions, imageRef if err != nil { return err } + + // Try bundles first + newBundles, _, err := cosign.GetBundles(ctx, ref, ociremoteOpts) + if err == nil && len(newBundles) > 0 { + for _, eachBundle := range newBundles { + b, err := json.Marshal(eachBundle) + if err != nil { + return err + } + _, err = out.Write(append(b, byte('\n'))) + if err != nil { + return err + } + } + return nil + } + signatures, err := cosign.FetchSignaturesForReference(ctx, ref, ociremoteOpts...) if err != nil { return err @@ -43,7 +60,10 @@ func SignatureCmd(ctx context.Context, regOpts options.RegistryOptions, imageRef if err != nil { return err } - fmt.Println(string(b)) + _, err = out.Write(append(b, byte('\n'))) + if err != nil { + return err + } } return nil } diff --git a/cmd/cosign/cli/env.go b/cmd/cosign/cli/env.go index 981a7bbb785..ff4105d0099 100644 --- a/cmd/cosign/cli/env.go +++ b/cmd/cosign/cli/env.go @@ -21,8 +21,8 @@ import ( "sort" "strings" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/pkg/cosign/env" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/pkg/cosign/env" "github.com/spf13/cobra" ) diff --git a/cmd/cosign/cli/env_test.go b/cmd/cosign/cli/env_test.go index 7cb64c9206d..a8cc286e169 100644 --- a/cmd/cosign/cli/env_test.go +++ b/cmd/cosign/cli/env_test.go @@ -21,7 +21,7 @@ import ( "os" "testing" - "github.com/sigstore/cosign/v2/pkg/cosign/env" + "github.com/sigstore/cosign/v3/pkg/cosign/env" ) const ( diff --git a/cmd/cosign/cli/fulcio/depcheck_test.go b/cmd/cosign/cli/fulcio/depcheck_test.go index 0a4562559b7..6a1ef76a769 100644 --- a/cmd/cosign/cli/fulcio/depcheck_test.go +++ b/cmd/cosign/cli/fulcio/depcheck_test.go @@ -23,7 +23,7 @@ import ( func TestNoDeps(t *testing.T) { depcheck.AssertNoDependency(t, map[string][]string{ - "github.com/sigstore/cosign/v2/cmd/cosign/cli/fulcio": { + "github.com/sigstore/cosign/v3/cmd/cosign/cli/fulcio": { // Avoid pulling in a variety of things that are massive dependencies. "github.com/google/trillian", "github.com/envoyproxy/go-control-plane", diff --git a/cmd/cosign/cli/fulcio/fulcio.go b/cmd/cosign/cli/fulcio/fulcio.go index 4a6d753cc8e..dec43db1329 100644 --- a/cmd/cosign/cli/fulcio/fulcio.go +++ b/cmd/cosign/cli/fulcio/fulcio.go @@ -24,44 +24,20 @@ import ( "os" "strings" - "github.com/go-jose/go-jose/v3/jwt" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/sign/privacy" - "github.com/sigstore/cosign/v2/internal/pkg/cosign/fulcio/fulcioroots" - "github.com/sigstore/cosign/v2/internal/ui" - "github.com/sigstore/cosign/v2/pkg/providers" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/internal/auth" + "github.com/sigstore/cosign/v3/internal/pkg/cosign/fulcio/fulcioroots" "github.com/sigstore/fulcio/pkg/api" "github.com/sigstore/sigstore/pkg/cryptoutils" - "github.com/sigstore/sigstore/pkg/oauthflow" "github.com/sigstore/sigstore/pkg/signature" - "golang.org/x/term" ) -const ( - flowNormal = "normal" - flowDevice = "device" - flowToken = "token" - flowClientCredentials = "client_credentials" -) - -type oidcConnector interface { - OIDConnect(string, string, string, string) (*oauthflow.OIDCIDToken, error) -} - -type realConnector struct { - flow oauthflow.TokenGetter -} - -func (rf *realConnector) OIDConnect(url, clientID, secret, redirectURL string) (*oauthflow.OIDCIDToken, error) { - return oauthflow.OIDConnect(url, clientID, secret, redirectURL, rf.flow) -} - -func getCertForOauthID(sv signature.SignerVerifier, fc api.LegacyClient, connector oidcConnector, oidcIssuer, oidcClientID, oidcClientSecret, oidcRedirectURL string) (*api.CertificateResponse, error) { - tok, err := connector.OIDConnect(oidcIssuer, oidcClientID, oidcClientSecret, oidcRedirectURL) +// GetCert returns the PEM-encoded signature of the OIDC identity returned as part of an interactive oauth2 flow plus the PEM-encoded cert chain. +func GetCert(_ context.Context, sv signature.SignerVerifier, idToken, flow, oidcIssuer, oidcClientID, oidcClientSecret, oidcRedirectURL string, fClient api.LegacyClient) (*api.CertificateResponse, error) { + sub, tok, err := auth.AuthenticateCaller(flow, idToken, oidcIssuer, oidcClientID, oidcClientSecret, oidcRedirectURL) if err != nil { return nil, err } - publicKey, err := sv.PublicKey() if err != nil { return nil, err @@ -71,7 +47,7 @@ func getCertForOauthID(sv signature.SignerVerifier, fc api.LegacyClient, connect return nil, err } // Sign the email address as part of the request - proof, err := sv.SignMessage(strings.NewReader(tok.Subject)) + proof, err := sv.SignMessage(strings.NewReader(sub)) if err != nil { return nil, err } @@ -83,26 +59,9 @@ func getCertForOauthID(sv signature.SignerVerifier, fc api.LegacyClient, connect SignedEmailAddress: proof, } - return fc.SigningCert(cr, tok.RawString) -} - -// GetCert returns the PEM-encoded signature of the OIDC identity returned as part of an interactive oauth2 flow plus the PEM-encoded cert chain. -func GetCert(_ context.Context, sv signature.SignerVerifier, idToken, flow, oidcIssuer, oidcClientID, oidcClientSecret, oidcRedirectURL string, fClient api.LegacyClient) (*api.CertificateResponse, error) { - c := &realConnector{} - switch flow { - case flowClientCredentials: - c.flow = oauthflow.NewClientCredentialsFlow(oidcIssuer) - case flowDevice: - c.flow = oauthflow.NewDeviceFlowTokenGetterForIssuer(oidcIssuer) - case flowNormal: - c.flow = oauthflow.DefaultIDTokenGetter - case flowToken: - c.flow = &oauthflow.StaticTokenGetter{RawToken: idToken} - default: - return nil, fmt.Errorf("unsupported oauth flow: %s", flow) - } + fmt.Fprintln(os.Stderr, "Retrieving signed certificate...") - return getCertForOauthID(sv, fClient, c, oidcIssuer, oidcClientID, oidcClientSecret, oidcRedirectURL) + return fClient.SigningCert(cr, tok) } type Signer struct { @@ -118,65 +77,26 @@ func NewSigner(ctx context.Context, ko options.KeyOpts, signer signature.SignerV return nil, fmt.Errorf("creating Fulcio client: %w", err) } - idToken, err := idToken(ko.IDToken) + idToken, err := auth.ReadIDToken(ctx, ko.IDToken, ko.OIDCDisableProviders, ko.OIDCProvider) if err != nil { - return nil, fmt.Errorf("getting id token: %w", err) + return nil, fmt.Errorf("reading id token: %w", err) } - var provider providers.Interface - // If token is not set in the options, get one from the provders - if idToken == "" && providers.Enabled(ctx) && !ko.OIDCDisableProviders { - if ko.OIDCProvider != "" { - provider, err = providers.ProvideFrom(ctx, ko.OIDCProvider) - if err != nil { - return nil, fmt.Errorf("getting provider: %w", err) - } - idToken, err = provider.Provide(ctx, "sigstore") - } else { - idToken, err = providers.Provide(ctx, "sigstore") - } - if err != nil { - return nil, fmt.Errorf("fetching ambient OIDC credentials: %w", err) - } - } - - fmt.Fprintln(os.Stderr, "Retrieving signed certificate...") - var flow string - switch { - case ko.FulcioAuthFlow != "": - // Caller manually set flow option. - flow = ko.FulcioAuthFlow - case idToken != "": - flow = flowToken - case !term.IsTerminal(0): - fmt.Fprintln(os.Stderr, "Non-interactive mode detected, using device flow.") - flow = flowDevice - default: - var statementErr error - privacy.StatementOnce.Do(func() { - ui.Infof(ctx, privacy.Statement) - ui.Infof(ctx, privacy.StatementConfirmation) - if !ko.SkipConfirmation { - if err := ui.ConfirmContinue(ctx); err != nil { - statementErr = err - } - } - }) - if statementErr != nil { - return nil, statementErr - } - flow = flowNormal + flow, err := auth.GetOAuthFlow(ctx, ko.FulcioAuthFlow, idToken, ko.SkipConfirmation) + if err != nil { + return nil, fmt.Errorf("setting auth flow: %w", err) } - Resp, err := GetCert(ctx, signer, idToken, flow, ko.OIDCIssuer, ko.OIDCClientID, ko.OIDCClientSecret, ko.OIDCRedirectURL, fClient) // TODO, use the chain. + + resp, err := GetCert(ctx, signer, idToken, flow, ko.OIDCIssuer, ko.OIDCClientID, ko.OIDCClientSecret, ko.OIDCRedirectURL, fClient) if err != nil { return nil, fmt.Errorf("retrieving cert: %w", err) } f := &Signer{ SignerVerifier: signer, - Cert: Resp.CertPEM, - Chain: Resp.ChainPEM, - SCT: Resp.SCT, + Cert: resp.CertPEM, + Chain: resp.ChainPEM, + SCT: resp.SCT, } return f, nil @@ -204,16 +124,3 @@ func NewClient(fulcioURL string) (api.LegacyClient, error) { fClient := api.NewClient(fulcioServer, api.WithUserAgent(options.UserAgent())) return fClient, nil } - -// idToken allows users to either pass in an identity token directly -// or a path to an identity token via the --identity-token flag -func idToken(s string) (string, error) { - // If this is a valid raw token or is empty, just return it - if _, err := jwt.ParseSigned(s); err == nil || s == "" { - return s, nil - } - - // Otherwise, if this is a path to a token return the contents - c, err := os.ReadFile(s) - return string(c), err -} diff --git a/cmd/cosign/cli/fulcio/fulcio_test.go b/cmd/cosign/cli/fulcio/fulcio_test.go index a4a8783a4fe..f728ed9db7a 100644 --- a/cmd/cosign/cli/fulcio/fulcio_test.go +++ b/cmd/cosign/cli/fulcio/fulcio_test.go @@ -28,28 +28,14 @@ import ( "net/http/httptest" "testing" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/pkg/cosign" - "github.com/sigstore/cosign/v2/test" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/internal/test" + "github.com/sigstore/cosign/v3/pkg/cosign" "github.com/sigstore/fulcio/pkg/api" "github.com/sigstore/sigstore/pkg/cryptoutils" - "github.com/sigstore/sigstore/pkg/oauthflow" "github.com/sigstore/sigstore/pkg/signature" ) -type testFlow struct { - idt *oauthflow.OIDCIDToken - email string - err error -} - -func (tf *testFlow) OIDConnect(url, clientID, secret, redirectURL string) (*oauthflow.OIDCIDToken, error) { //nolint: revive - if tf.err != nil { - return nil, tf.err - } - return tf.idt, nil -} - type testClient struct { payload api.CertificateResponse rootResp api.RootResponse @@ -88,19 +74,15 @@ func TestGetCertForOauthID(t *testing.T) { expectErr bool }{{ - desc: "happy case", - email: "example@oidc.id", - accessToken: "abc123foobar", + desc: "happy case", + email: "example@oidc.id", + // Generated from https://justtrustme.dev/token?sub=test + accessToken: "eyJhbGciOiJSUzI1NiIsImtpZCI6ImFhOWE1YjA5LTExMzktNGU2YS1hNjMxLTA2ZTU3NDU4NzI0MSJ9.eyJleHAiOjE3NTQwMjk5ODcsImlhdCI6MTc1NDAyODE4NywiaXNzIjoiaHR0cHM6Ly9qdXN0dHJ1c3RtZS5kZXYiLCJzdWIiOiJ0ZXN0In0.Fyp07QRXbuK65WKVKE6S7UgB9hvmNeyqWvcCWUvhMAwHwHl9EoRNwE-a5uBXgBgLUfbOCBHfc9fBIEEayzR1dRgfUXouOSIiZYr3DZNyGLdSiptL7wQRNy4rEiW44XCYFcbOuiWaii8icQUnOUO_TehgZHqSDvBSNQZcW-Rtx4A1us-CfVtrjqSNj_d0lCNEZ-vpL-Wp7JkOKzR0bN2KzYhVYHRe-pmvrzMWFfI17khB4wE6wj3e_PjDHAKS1EqGRrIgbr5jFcv9iGaf0zTnyZ_fxCmQM2Xe1u3kFlcCS0HondSJkxQoZRnK_OZHujNyWBT6cONg7Wvclkco3LulRw", }, { - desc: "getIDToken error", - email: "example@oidc.id", - accessToken: "abc123foobar", - tokenGetterErr: errors.New("getIDToken() failed"), - expectErr: true, - }, { - desc: "SigningCert error", - email: "example@oidc.id", - accessToken: "abc123foobar", + desc: "SigningCert error", + email: "example@oidc.id", + // Generated from https://justtrustme.dev/token?sub=test + accessToken: "eyJhbGciOiJSUzI1NiIsImtpZCI6ImFhOWE1YjA5LTExMzktNGU2YS1hNjMxLTA2ZTU3NDU4NzI0MSJ9.eyJleHAiOjE3NTQwMjk5NTMsImlhdCI6MTc1NDAyODE1MywiaXNzIjoiaHR0cHM6Ly9qdXN0dHJ1c3RtZS5kZXYifQ.n2JrybZ64bCeSvVVPYIEf2x9aZM-Xxwzdkq_DcPuPJuwEINFJBRiOsJ6R6MllV0YodQkshFB81YOQ4_QC5h5lfDmr-fmvxcIPw0Iw1oQkiNl73BpiWmT63dQ7DxPPnfCPW9xPmo3j8BTJ8zKNPXTyfwGEHjv6rJ56bMjRDNR0W78vG8di9R8ZCAPD7WOwWfFW4JTYrgNnsSfiTmFWl8Z5iYBnkEBCaEWldpgOuUhofQ_jdG_UbLyY3iXkOmfseKCOnYiWzp0CYbU5EYC8RHk4SfZ5JvG7rv7JPmPw2IFQdTjObX9vY6vLvP2-nMj_7hAUbBWzci9bQOAx-W7usd4qA", signingCertErr: errors.New("SigningCert() failed"), expectErr: true, }} @@ -121,16 +103,7 @@ func TestGetCertForOauthID(t *testing.T) { err: tc.signingCertErr, } - tf := testFlow{ - email: tc.email, - idt: &oauthflow.OIDCIDToken{ - RawString: tc.accessToken, - }, - err: tc.tokenGetterErr, - } - - resp, err := getCertForOauthID(sv, tscp, &tf, "", "", "", "") - + resp, err := GetCert(context.TODO(), sv, tc.accessToken, "token", "", "", "", "", tscp) if err != nil { if !tc.expectErr { t.Fatalf("getCertForOauthID returned error: %v", err) @@ -202,8 +175,8 @@ func TestNewSigner(t *testing.T) { ctx := context.TODO() ko := options.KeyOpts{ OIDCDisableProviders: true, - // random test token - IDToken: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c", + // Generated from https://justtrustme.dev/token?sub=test + IDToken: "eyJhbGciOiJSUzI1NiIsImtpZCI6ImFhOWE1YjA5LTExMzktNGU2YS1hNjMxLTA2ZTU3NDU4NzI0MSJ9.eyJleHAiOjE3NTQwMjk5ODcsImlhdCI6MTc1NDAyODE4NywiaXNzIjoiaHR0cHM6Ly9qdXN0dHJ1c3RtZS5kZXYiLCJzdWIiOiJ0ZXN0In0.Fyp07QRXbuK65WKVKE6S7UgB9hvmNeyqWvcCWUvhMAwHwHl9EoRNwE-a5uBXgBgLUfbOCBHfc9fBIEEayzR1dRgfUXouOSIiZYr3DZNyGLdSiptL7wQRNy4rEiW44XCYFcbOuiWaii8icQUnOUO_TehgZHqSDvBSNQZcW-Rtx4A1us-CfVtrjqSNj_d0lCNEZ-vpL-Wp7JkOKzR0bN2KzYhVYHRe-pmvrzMWFfI17khB4wE6wj3e_PjDHAKS1EqGRrIgbr5jFcv9iGaf0zTnyZ_fxCmQM2Xe1u3kFlcCS0HondSJkxQoZRnK_OZHujNyWBT6cONg7Wvclkco3LulRw", FulcioURL: testServer.URL, FulcioAuthFlow: "token", } diff --git a/cmd/cosign/cli/fulcio/fulcioverifier/fulcioverifier.go b/cmd/cosign/cli/fulcio/fulcioverifier/fulcioverifier.go index 076a763c536..0a9850b5035 100644 --- a/cmd/cosign/cli/fulcio/fulcioverifier/fulcioverifier.go +++ b/cmd/cosign/cli/fulcio/fulcioverifier/fulcioverifier.go @@ -20,10 +20,10 @@ import ( "crypto/x509" "fmt" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/fulcio" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/internal/ui" - "github.com/sigstore/cosign/v2/pkg/cosign" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/fulcio" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/internal/ui" + "github.com/sigstore/cosign/v3/pkg/cosign" "github.com/sigstore/sigstore-go/pkg/verify" "github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/sigstore/sigstore/pkg/signature" diff --git a/cmd/cosign/cli/fulcio/fulcioverifier/fulcioverifier_test.go b/cmd/cosign/cli/fulcio/fulcioverifier/fulcioverifier_test.go index c0b11006ec1..9622ca47874 100644 --- a/cmd/cosign/cli/fulcio/fulcioverifier/fulcioverifier_test.go +++ b/cmd/cosign/cli/fulcio/fulcioverifier/fulcioverifier_test.go @@ -40,9 +40,9 @@ import ( "github.com/google/certificate-transparency-go/trillian/ctfe" ctx509 "github.com/google/certificate-transparency-go/x509" ctx509util "github.com/google/certificate-transparency-go/x509util" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/initialize" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/pkg/cosign" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/initialize" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/pkg/cosign" "github.com/sigstore/fulcio/pkg/ctl" "github.com/sigstore/sigstore-go/pkg/root" "github.com/sigstore/sigstore/pkg/cryptoutils" @@ -168,8 +168,8 @@ func TestNewSigner(t *testing.T) { ctx := context.Background() ko := options.KeyOpts{ OIDCDisableProviders: true, - // random test token - IDToken: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c", + // Generated from https://justtrustme.dev/token?sub=test-subject + IDToken: "eyJhbGciOiJSUzI1NiIsImtpZCI6ImFhOWE1YjA5LTExMzktNGU2YS1hNjMxLTA2ZTU3NDU4NzI0MSJ9.eyJleHAiOjE3NTQwMjgzODMsImlhdCI6MTc1NDAyNjU4MywiaXNzIjoiaHR0cHM6Ly9qdXN0dHJ1c3RtZS5kZXYiLCJzdWIiOiJ0ZXN0LXN1YmplY3QifQ.lfLAxD5XnbtvmGbgJTTV8nLDxUk9_KemdFG3_HydIWwLdKR86KYwwJn_5ONdycVuNluLOx96xA6jc4m1CjzH9N5Dafw4MQpjzXJWFlhM9sehW8VU_TzH1lEfY3KTxwDBRkZnVGXr3bJGowfdTyWLJxgl16nVTqsRAqIsTE4SEVHscDP1r5T0_B7RQ4Sjih1Z7zlIYzXxpAiVCOZ321Gqgxtej_xPfZ9rk1Z5-Uw-8sc6spog8Uca3kqumncPgM0su1ww5bWmawb4msqUnoOcPCPo-oywC-gdssWt_HmFPRhvREvdv5eYNDfp1bjS-nWAGJN7a4iO9qGBJed7zI6JNA", FulcioURL: testServer.URL, FulcioAuthFlow: "token", } @@ -183,12 +183,14 @@ func TestNewSigner(t *testing.T) { } fs, err := NewSigner(ctx, ko, sv) + if err != nil { + t.Fatal(err) + } if test.embeddedSCT { assert.Empty(t, fs.SCT) } else { assert.NotEmpty(t, fs.SCT) } - assert.NoError(t, err) }) } } diff --git a/cmd/cosign/cli/generate.go b/cmd/cosign/cli/generate.go index 4560ce7693c..f1e0d76bf1d 100644 --- a/cmd/cosign/cli/generate.go +++ b/cmd/cosign/cli/generate.go @@ -16,8 +16,8 @@ package cli import ( - "github.com/sigstore/cosign/v2/cmd/cosign/cli/generate" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/generate" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" "github.com/spf13/cobra" ) diff --git a/cmd/cosign/cli/generate/generate.go b/cmd/cosign/cli/generate/generate.go index ee2e6b459a5..21d333945cb 100644 --- a/cmd/cosign/cli/generate/generate.go +++ b/cmd/cosign/cli/generate/generate.go @@ -20,8 +20,8 @@ import ( "io" "github.com/google/go-containerregistry/pkg/name" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - ociremote "github.com/sigstore/cosign/v2/pkg/oci/remote" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + ociremote "github.com/sigstore/cosign/v3/pkg/oci/remote" "github.com/sigstore/sigstore/pkg/signature/payload" ) diff --git a/cmd/cosign/cli/generate/generate_key_pair.go b/cmd/cosign/cli/generate/generate_key_pair.go index 2329f51b819..3e729eb9aec 100644 --- a/cmd/cosign/cli/generate/generate_key_pair.go +++ b/cmd/cosign/cli/generate/generate_key_pair.go @@ -24,15 +24,15 @@ import ( "os" "strings" - "github.com/sigstore/cosign/v2/pkg/cosign/env" - "github.com/sigstore/cosign/v2/pkg/cosign/git" - "github.com/sigstore/cosign/v2/pkg/cosign/git/github" - "github.com/sigstore/cosign/v2/pkg/cosign/git/gitlab" - - icos "github.com/sigstore/cosign/v2/internal/pkg/cosign" - "github.com/sigstore/cosign/v2/internal/ui" - "github.com/sigstore/cosign/v2/pkg/cosign" - "github.com/sigstore/cosign/v2/pkg/cosign/kubernetes" + "github.com/sigstore/cosign/v3/pkg/cosign/env" + "github.com/sigstore/cosign/v3/pkg/cosign/git" + "github.com/sigstore/cosign/v3/pkg/cosign/git/github" + "github.com/sigstore/cosign/v3/pkg/cosign/git/gitlab" + + icos "github.com/sigstore/cosign/v3/internal/pkg/cosign" + "github.com/sigstore/cosign/v3/internal/ui" + "github.com/sigstore/cosign/v3/pkg/cosign" + "github.com/sigstore/cosign/v3/pkg/cosign/kubernetes" "github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/sigstore/sigstore/pkg/signature/kms" ) diff --git a/cmd/cosign/cli/generate/generate_key_pair_test.go b/cmd/cosign/cli/generate/generate_key_pair_test.go index f860382ea4e..13ef47a5f74 100644 --- a/cmd/cosign/cli/generate/generate_key_pair_test.go +++ b/cmd/cosign/cli/generate/generate_key_pair_test.go @@ -21,7 +21,7 @@ import ( "testing" "github.com/google/go-cmp/cmp" - icos "github.com/sigstore/cosign/v2/internal/pkg/cosign" + icos "github.com/sigstore/cosign/v3/internal/pkg/cosign" ) func TestReadPasswordFn_env(t *testing.T) { diff --git a/cmd/cosign/cli/generate_key_pair.go b/cmd/cosign/cli/generate_key_pair.go index 9e64f7b5981..6e22c052acb 100644 --- a/cmd/cosign/cli/generate_key_pair.go +++ b/cmd/cosign/cli/generate_key_pair.go @@ -16,8 +16,8 @@ package cli import ( - "github.com/sigstore/cosign/v2/cmd/cosign/cli/generate" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/generate" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" "github.com/spf13/cobra" ) diff --git a/cmd/cosign/cli/import_key_pair.go b/cmd/cosign/cli/import_key_pair.go index 3ba62aa68ec..f8a323afa93 100644 --- a/cmd/cosign/cli/import_key_pair.go +++ b/cmd/cosign/cli/import_key_pair.go @@ -18,8 +18,8 @@ package cli import ( "github.com/spf13/cobra" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/importkeypair" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/importkeypair" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" ) func ImportKeyPair() *cobra.Command { diff --git a/cmd/cosign/cli/importkeypair/import_key_pair.go b/cmd/cosign/cli/importkeypair/import_key_pair.go index b2d03628e62..3079648185f 100644 --- a/cmd/cosign/cli/importkeypair/import_key_pair.go +++ b/cmd/cosign/cli/importkeypair/import_key_pair.go @@ -21,11 +21,11 @@ import ( "io" "os" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - icos "github.com/sigstore/cosign/v2/internal/pkg/cosign" - "github.com/sigstore/cosign/v2/internal/ui" - "github.com/sigstore/cosign/v2/pkg/cosign" - "github.com/sigstore/cosign/v2/pkg/cosign/env" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + icos "github.com/sigstore/cosign/v3/internal/pkg/cosign" + "github.com/sigstore/cosign/v3/internal/ui" + "github.com/sigstore/cosign/v3/pkg/cosign" + "github.com/sigstore/cosign/v3/pkg/cosign/env" ) var ( diff --git a/cmd/cosign/cli/importkeypair/import_key_pair_test.go b/cmd/cosign/cli/importkeypair/import_key_pair_test.go index bb1519cf17e..82e8e1e8119 100644 --- a/cmd/cosign/cli/importkeypair/import_key_pair_test.go +++ b/cmd/cosign/cli/importkeypair/import_key_pair_test.go @@ -25,8 +25,8 @@ import ( "testing" "github.com/google/go-cmp/cmp" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - icos "github.com/sigstore/cosign/v2/internal/pkg/cosign" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + icos "github.com/sigstore/cosign/v3/internal/pkg/cosign" ) func TestReadPasswordFn_env(t *testing.T) { diff --git a/cmd/cosign/cli/initialize.go b/cmd/cosign/cli/initialize.go index 59b537147f8..cb0a0fdb2fc 100644 --- a/cmd/cosign/cli/initialize.go +++ b/cmd/cosign/cli/initialize.go @@ -16,8 +16,8 @@ package cli import ( - "github.com/sigstore/cosign/v2/cmd/cosign/cli/initialize" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/initialize" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" "github.com/spf13/cobra" ) @@ -39,12 +39,15 @@ This will enable you to point cosign to a separate TUF root. Any updated TUF repository will be written to $HOME/.sigstore/root/. Trusted keys and certificate used in cosign verification (e.g. verifying Fulcio issued certificates -with Fulcio root CA) are pulled form the trusted metadata.`, - Example: `cosign initialize --mirror --out +with Fulcio root CA) are pulled from the trusted metadata.`, + Example: `cosign initialize --mirror -# initialize root with distributed root keys, default mirror, and default out path. +# initialize root with distributed root keys, using the default mirror. cosign initialize +# initialize root with distributed root keys, using the staging mirror. +cosign initialize --staging + # initialize with an out-of-band root key file, using the default mirror. cosign initialize --root @@ -55,6 +58,9 @@ cosign initialize --mirror --root cosign initialize --mirror --root --root-checksum `, PersistentPreRun: options.BindViper, RunE: func(cmd *cobra.Command, _ []string) error { + if o.Staging { + return initialize.DoInitializeStaging(cmd.Context()) + } return initialize.DoInitializeWithRootChecksum(cmd.Context(), o.Root, o.Mirror, o.RootChecksum) }, } diff --git a/cmd/cosign/cli/initialize/init.go b/cmd/cosign/cli/initialize/init.go index fc726cd0d59..c8974a82203 100644 --- a/cmd/cosign/cli/initialize/init.go +++ b/cmd/cosign/cli/initialize/init.go @@ -17,17 +17,16 @@ package initialize import ( "context" - _ "embed" // To enable the `go:embed` directive. "encoding/json" "fmt" "os" "path/filepath" "strings" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/internal/ui" - "github.com/sigstore/cosign/v2/pkg/blob" - "github.com/sigstore/cosign/v2/pkg/cosign/env" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/internal/ui" + "github.com/sigstore/cosign/v3/pkg/blob" + "github.com/sigstore/cosign/v3/pkg/cosign/env" tufroot "github.com/sigstore/sigstore-go/pkg/root" "github.com/sigstore/sigstore-go/pkg/tuf" tufv1 "github.com/sigstore/sigstore/pkg/tuf" @@ -41,6 +40,10 @@ func DoInitializeWithRootChecksum(ctx context.Context, root, mirror, rootChecksu return doInitialize(ctx, root, mirror, rootChecksum, false) } +func DoInitializeStaging(ctx context.Context) error { + return doInitialize(ctx, "", tuf.StagingMirror, "", true) +} + func doInitialize(ctx context.Context, root, mirror, rootChecksum string, forceSkipChecksumValidation bool) error { // Get the initial trusted root contents. var rootFileBytes []byte @@ -68,6 +71,9 @@ func doInitialize(ctx context.Context, root, mirror, rootChecksum string, forceS } if mirror != "" { opts.RepositoryBaseURL = mirror + if mirror == tuf.StagingMirror { + opts.Root = tuf.StagingRoot() + } } if tufCacheDir := env.Getenv(env.VariableTUFRootDir); tufCacheDir != "" { //nolint:forbidigo opts.CachePath = tufCacheDir @@ -79,6 +85,9 @@ func doInitialize(ctx context.Context, root, mirror, rootChecksum string, forceS if err != nil { return err } + if err := os.RemoveAll(opts.CachePath); err != nil { + return fmt.Errorf("clearing cache directory: %w", err) + } if err := os.MkdirAll(opts.CachePath, 0o700); err != nil { return fmt.Errorf("creating cache directory: %w", err) } @@ -86,6 +95,12 @@ func doInitialize(ctx context.Context, root, mirror, rootChecksum string, forceS return fmt.Errorf("storing remote: %w", err) } + // Cache the signing config from the TUF repository + _, err = tufroot.FetchSigningConfigWithOptions(opts) + if err != nil { + ui.Warnf(ctx, "Could not fetch signing_config.json from the TUF mirror (encountered error: %v). It is recommended to use a signing config file rather than provide service URLs when signing.", err) + } + // Cache the trusted root from the TUF repository trustedRoot, err := tufroot.NewLiveTrustedRoot(opts) if err != nil { ui.Warnf(ctx, "Could not fetch trusted_root.json from the TUF mirror (encountered error: %v), falling back to individual targets. It is recommended to update your TUF metadata repository to include trusted_root.json.", err) diff --git a/cmd/cosign/cli/initialize/init_test.go b/cmd/cosign/cli/initialize/init_test.go index 0586a93e5d8..e2932a329ca 100644 --- a/cmd/cosign/cli/initialize/init_test.go +++ b/cmd/cosign/cli/initialize/init_test.go @@ -155,13 +155,16 @@ func TestDoInitialize(t *testing.T) { expectV2 bool }{ { - name: "tuf v2 with trusted root", - targets: map[string][]byte{"trusted_root.json": []byte(`{"mediaType": "application/vnd.dev.sigstore.trustedroot+json;version=0.1"}`)}, + name: "tuf v2 with trusted root and signing config", + targets: map[string][]byte{ + "trusted_root.json": []byte(`{"mediaType": "application/vnd.dev.sigstore.trustedroot+json;version=0.1"}`), + "signing_config.v0.2.json": []byte(`{"mediaType": "application/vnd.dev.sigstore.signingconfig.v0.2+json"}`), + }, root: "1.root.json", wantStdOut: "", wantStdErr: "", wantErr: false, - wantFiles: []string{filepath.Join("targets", "trusted_root.json")}, + wantFiles: []string{filepath.Join("targets", "trusted_root.json"), filepath.Join("targets", "signing_config.v0.2.json")}, expectV2: true, }, { diff --git a/cmd/cosign/cli/load.go b/cmd/cosign/cli/load.go index 80eb9ec7d0a..ef5cc8a31f4 100644 --- a/cmd/cosign/cli/load.go +++ b/cmd/cosign/cli/load.go @@ -20,9 +20,9 @@ import ( "fmt" "github.com/google/go-containerregistry/pkg/name" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/pkg/oci/layout" - "github.com/sigstore/cosign/v2/pkg/oci/remote" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/pkg/oci/layout" + "github.com/sigstore/cosign/v3/pkg/oci/remote" "github.com/spf13/cobra" ) @@ -62,5 +62,5 @@ func LoadCmd(ctx context.Context, opts options.LoadOptions, imageRef string) err return err } - return remote.WriteSignedImageIndexImages(ref, sii, ociremoteOpts...) + return remote.WriteSignedImageIndexImages(ref, sii, opts.Directory, ociremoteOpts...) } diff --git a/cmd/cosign/cli/manifest.go b/cmd/cosign/cli/manifest.go index 02bf8881f3c..786138668a4 100644 --- a/cmd/cosign/cli/manifest.go +++ b/cmd/cosign/cli/manifest.go @@ -18,9 +18,9 @@ package cli import ( "fmt" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/manifest" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/verify" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/manifest" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/verify" "github.com/spf13/cobra" ) diff --git a/cmd/cosign/cli/manifest/verify.go b/cmd/cosign/cli/manifest/verify.go index 9f179b2d8d2..dac0afba31a 100644 --- a/cmd/cosign/cli/manifest/verify.go +++ b/cmd/cosign/cli/manifest/verify.go @@ -27,7 +27,7 @@ import ( "k8s.io/apimachinery/pkg/util/yaml" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/verify" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/verify" ) // VerifyManifestCommand verifies all image signatures on a supplied k8s resource diff --git a/cmd/cosign/cli/options/annotations.go b/cmd/cosign/cli/options/annotations.go index 5da30a3c910..601e2af657a 100644 --- a/cmd/cosign/cli/options/annotations.go +++ b/cmd/cosign/cli/options/annotations.go @@ -19,7 +19,7 @@ import ( "fmt" "strings" - sigs "github.com/sigstore/cosign/v2/pkg/signature" + sigs "github.com/sigstore/cosign/v3/pkg/signature" "github.com/spf13/cobra" ) diff --git a/cmd/cosign/cli/options/annotations_test.go b/cmd/cosign/cli/options/annotations_test.go index c575a397358..01a5faba8b7 100644 --- a/cmd/cosign/cli/options/annotations_test.go +++ b/cmd/cosign/cli/options/annotations_test.go @@ -20,7 +20,7 @@ import ( "github.com/google/go-cmp/cmp" - "github.com/sigstore/cosign/v2/pkg/signature" + "github.com/sigstore/cosign/v3/pkg/signature" ) func TestAnnotationOptions_AnnotationsMap(t *testing.T) { diff --git a/cmd/cosign/cli/options/attach.go b/cmd/cosign/cli/options/attach.go index 4e51d527f08..ee55697fc88 100644 --- a/cmd/cosign/cli/options/attach.go +++ b/cmd/cosign/cli/options/attach.go @@ -20,7 +20,7 @@ import ( "strings" "github.com/google/go-containerregistry/pkg/v1/types" - ctypes "github.com/sigstore/cosign/v2/pkg/types" + ctypes "github.com/sigstore/cosign/v3/pkg/types" "github.com/spf13/cobra" ) @@ -47,6 +47,9 @@ func (o *AttachSignatureOptions) AddFlags(cmd *cobra.Command) { cmd.Flags().StringVar(&o.Payload, "payload", "", "path to the payload covered by the signature") + cmd.Flags().StringVar(&o.Payload, "bundle", "", + "path to bundle containing signature (alias for payload)") + cmd.Flags().StringVar(&o.Cert, "certificate", "", "path to the X.509 certificate in PEM format to include in the OCI Signature") diff --git a/cmd/cosign/cli/options/attest.go b/cmd/cosign/cli/options/attest.go index 7b67e4ee563..bf55898251e 100644 --- a/cmd/cosign/cli/options/attest.go +++ b/cmd/cosign/cli/options/attest.go @@ -26,6 +26,7 @@ type AttestOptions struct { Key string Cert string CertChain string + IssueCertificate bool NoUpload bool Replace bool SkipConfirmation bool @@ -37,7 +38,11 @@ type AttestOptions struct { TSAServerURL string RekorEntryType string RecordCreationTimestamp bool + BundlePath string NewBundleFormat bool + UseSigningConfig bool + SigningConfigPath string + TrustedRootPath string Rekor RekorOptions Fulcio FulcioOptions @@ -83,6 +88,7 @@ func (o *AttestOptions) AddFlags(cmd *cobra.Command) { cmd.Flags().BoolVar(&o.TlogUpload, "tlog-upload", true, "whether or not to upload to the tlog") + _ = cmd.Flags().MarkDeprecated("tlog-upload", "prefer using a --signing-config file with no transparency log services") cmd.Flags().StringVar(&o.RekorEntryType, "rekor-entry-type", rekorEntryTypes[0], "specifies the type to be used for a rekor entry upload ("+strings.Join(rekorEntryTypes, "|")+")") @@ -107,5 +113,23 @@ func (o *AttestOptions) AddFlags(cmd *cobra.Command) { cmd.Flags().BoolVar(&o.RecordCreationTimestamp, "record-creation-timestamp", false, "set the createdAt timestamp in the attestation artifact to the time it was created; by default, cosign sets this to the zero value") - cmd.Flags().BoolVar(&o.NewBundleFormat, "new-bundle-format", false, "attach a Sigstore bundle using OCI referrers API") + cmd.Flags().BoolVar(&o.IssueCertificate, "issue-certificate", false, + "issue a code signing certificate from Fulcio, even if a key is provided") + + cmd.Flags().StringVar(&o.BundlePath, "bundle", "", + "write everything required to verify the blob to a FILE") + _ = cmd.MarkFlagFilename("bundle", bundleExts...) + + cmd.Flags().BoolVar(&o.NewBundleFormat, "new-bundle-format", true, "attach a Sigstore bundle using OCI referrers API") + + cmd.Flags().BoolVar(&o.UseSigningConfig, "use-signing-config", true, + "whether to use a TUF-provided signing config for the service URLs. Must set --new-bundle-format, which will store verification material in the new format") + + cmd.Flags().StringVar(&o.SigningConfigPath, "signing-config", "", + "path to a signing config file. Must provide --new-bundle-format, which will store verification material in the new format") + + cmd.MarkFlagsMutuallyExclusive("use-signing-config", "signing-config") + + cmd.Flags().StringVar(&o.TrustedRootPath, "trusted-root", "", + "optional path to a TrustedRoot JSON file to verify a signature after signing") } diff --git a/cmd/cosign/cli/options/attest_blob.go b/cmd/cosign/cli/options/attest_blob.go index 5b1b8135694..832f7e3bbbf 100644 --- a/cmd/cosign/cli/options/attest_blob.go +++ b/cmd/cosign/cli/options/attest_blob.go @@ -22,9 +22,10 @@ import ( // AttestOptions is the top level wrapper for the attest command. type AttestBlobOptions struct { - Key string - Cert string - CertChain string + Key string + Cert string + CertChain string + IssueCertificate bool SkipConfirmation bool TlogUpload bool @@ -50,6 +51,10 @@ type AttestBlobOptions struct { Fulcio FulcioOptions OIDC OIDCOptions SecurityKey SecurityKeyOptions + + UseSigningConfig bool + SigningConfigPath string + TrustedRootPath string } var _ Interface = (*AttestOptions)(nil) @@ -67,14 +72,14 @@ func (o *AttestBlobOptions) AddFlags(cmd *cobra.Command) { _ = cmd.MarkFlagFilename("key", privateKeyExts...) cmd.Flags().StringVar(&o.Cert, "certificate", "", - "path to the X.509 certificate in PEM format to include in the OCI Signature") + "path to the X.509 certificate for signing attestation") _ = cmd.MarkFlagFilename("certificate", certificateExts...) cmd.Flags().StringVar(&o.CertChain, "certificate-chain", "", "path to a list of CA X.509 certificates in PEM format which will be needed "+ - "when building the certificate chain for the signing certificate. "+ + "when building the certificate chain for the signed attestation. "+ "Must start with the parent intermediate CA certificate of the "+ - "signing certificate and end with the root certificate. Included in the OCI Signature") + "signing certificate and end with the root certificate.") _ = cmd.MarkFlagFilename("certificate-chain", certificateExts...) cmd.Flags().StringVar(&o.OutputSignature, "output-signature", "", @@ -93,10 +98,20 @@ func (o *AttestBlobOptions) AddFlags(cmd *cobra.Command) { "write everything required to verify the blob to a FILE") _ = cmd.MarkFlagFilename("bundle", bundleExts...) - // TODO: have this default to true as a breaking change - cmd.Flags().BoolVar(&o.NewBundleFormat, "new-bundle-format", false, + cmd.Flags().BoolVar(&o.NewBundleFormat, "new-bundle-format", true, "output bundle in new format that contains all verification material") + cmd.Flags().BoolVar(&o.UseSigningConfig, "use-signing-config", true, + "whether to use a TUF-provided signing config for the service URLs. Must provide --bundle, which will output verification material in the new format") + + cmd.Flags().StringVar(&o.SigningConfigPath, "signing-config", "", + "path to a signing config file. Must provide --bundle, which will output verification material in the new format") + + cmd.MarkFlagsMutuallyExclusive("use-signing-config", "signing-config") + + cmd.Flags().StringVar(&o.TrustedRootPath, "trusted-root", "", + "optional path to a TrustedRoot JSON file to verify a signature after signing") + cmd.Flags().StringVar(&o.Hash, "hash", "", "hash of blob in hexadecimal (base16). Used if you want to sign an artifact stored elsewhere and have the hash") _ = cmd.RegisterFlagCompletionFunc("hash", cobra.NoFileCompletions) @@ -106,6 +121,7 @@ func (o *AttestBlobOptions) AddFlags(cmd *cobra.Command) { cmd.Flags().BoolVar(&o.TlogUpload, "tlog-upload", true, "whether or not to upload to the tlog") + _ = cmd.Flags().MarkDeprecated("tlog-upload", "prefer using a --signing-config file with no transparency log services") cmd.Flags().StringVar(&o.RekorEntryType, "rekor-entry-type", rekorEntryTypes[0], "specifies the type to be used for a rekor entry upload ("+strings.Join(rekorEntryTypes, "|")+")") @@ -130,4 +146,7 @@ func (o *AttestBlobOptions) AddFlags(cmd *cobra.Command) { cmd.Flags().StringVar(&o.RFC3161TimestampPath, "rfc3161-timestamp-bundle", "", "path to an RFC 3161 timestamp bundle FILE") // _ = cmd.MarkFlagFilename("rfc3161-timestamp-bundle") // no typical extensions + + cmd.Flags().BoolVar(&o.IssueCertificate, "issue-certificate", false, + "issue a code signing certificate from Fulcio, even if a key is provided") } diff --git a/cmd/cosign/cli/options/certificate.go b/cmd/cosign/cli/options/certificate.go index b14d408fe20..62bbb2fd8f0 100644 --- a/cmd/cosign/cli/options/certificate.go +++ b/cmd/cosign/cli/options/certificate.go @@ -17,7 +17,7 @@ package options import ( "errors" - "github.com/sigstore/cosign/v2/pkg/cosign" + "github.com/sigstore/cosign/v3/pkg/cosign" "github.com/spf13/cobra" ) diff --git a/cmd/cosign/cli/options/clean.go b/cmd/cosign/cli/options/clean.go index 540bc4f1cf5..9470f26566f 100644 --- a/cmd/cosign/cli/options/clean.go +++ b/cmd/cosign/cli/options/clean.go @@ -25,6 +25,7 @@ type CleanType string const ( CleanTypeSignature CleanType = "signature" CleanTypeAttestation CleanType = "attestation" + CleanTypeReferrer CleanType = "referrer" CleanTypeSbom CleanType = "sbom" CleanTypeAll CleanType = "all" ) @@ -41,11 +42,11 @@ func (c *CleanType) String() string { // cleanType implements github.com/spf13/pflag.Value. func (c *CleanType) Set(v string) error { switch v { - case "signature", "attestation", "sbom", "all": + case "signature", "attestation", "referrer", "sbom", "all": *c = CleanType(v) return nil default: - return errors.New(`must be one of "signature", "attestation", "sbom", or "all"`) + return errors.New(`must be one of "signature", "attestation", "referrer", "sbom", or "all"`) } } @@ -65,7 +66,7 @@ var _ Interface = (*CleanOptions)(nil) func (c *CleanOptions) AddFlags(cmd *cobra.Command) { c.Registry.AddFlags(cmd) c.CleanType = defaultCleanType() - cmd.Flags().Var(&c.CleanType, "type", "a type of clean: (sbom is deprecated)") + cmd.Flags().Var(&c.CleanType, "type", "a type of clean: (sbom is deprecated)") // TODO(#2044): Rename to --skip-confirmation for consistency? cmd.Flags().BoolVarP(&c.Force, "force", "f", false, "do not prompt for confirmation") } diff --git a/cmd/cosign/cli/options/experimental.go b/cmd/cosign/cli/options/experimental.go index 5a982fee45e..fed423e0c1b 100644 --- a/cmd/cosign/cli/options/experimental.go +++ b/cmd/cosign/cli/options/experimental.go @@ -17,7 +17,7 @@ package options import ( "strconv" - "github.com/sigstore/cosign/v2/pkg/cosign/env" + "github.com/sigstore/cosign/v3/pkg/cosign/env" ) func EnableExperimental() bool { diff --git a/cmd/cosign/cli/options/files.go b/cmd/cosign/cli/options/files.go index 5d3d185f1ee..7ba77a0b860 100644 --- a/cmd/cosign/cli/options/files.go +++ b/cmd/cosign/cli/options/files.go @@ -19,7 +19,7 @@ import ( "fmt" "strings" - cremote "github.com/sigstore/cosign/v2/pkg/cosign/remote" + cremote "github.com/sigstore/cosign/v3/pkg/cosign/remote" "github.com/spf13/cobra" ) diff --git a/cmd/cosign/cli/options/initialize.go b/cmd/cosign/cli/options/initialize.go index d5eed5346a6..b13bf2ea45a 100644 --- a/cmd/cosign/cli/options/initialize.go +++ b/cmd/cosign/cli/options/initialize.go @@ -25,6 +25,7 @@ type InitializeOptions struct { Mirror string Root string RootChecksum string + Staging bool } var _ Interface = (*InitializeOptions)(nil) @@ -40,4 +41,7 @@ func (o *InitializeOptions) AddFlags(cmd *cobra.Command) { cmd.Flags().StringVar(&o.RootChecksum, "root-checksum", "", "checksum of the initial root, required if root is downloaded via http(s). expects sha256 by default, can be changed to sha512 by providing sha512:") + + cmd.Flags().BoolVar(&o.Staging, "staging", false, + "use the staging TUF repository") } diff --git a/cmd/cosign/cli/options/key.go b/cmd/cosign/cli/options/key.go index 2cae8d5cdbe..66fab5523d3 100644 --- a/cmd/cosign/cli/options/key.go +++ b/cmd/cosign/cli/options/key.go @@ -16,8 +16,9 @@ package options import ( - "github.com/sigstore/cosign/v2/pkg/cosign" + "github.com/sigstore/cosign/v3/pkg/cosign" "github.com/sigstore/sigstore-go/pkg/root" + "github.com/sigstore/sigstore/pkg/signature" ) type KeyOpts struct { @@ -49,7 +50,7 @@ type KeyOpts struct { IssueCertificateForExistingKey bool // FulcioAuthFlow is the auth flow to use when authenticating against - // Fulcio. See https://pkg.go.dev/github.com/sigstore/cosign/v2/cmd/cosign/cli/fulcio#pkg-constants + // Fulcio. See https://pkg.go.dev/github.com/sigstore/cosign/v3/cmd/cosign/cli/fulcio#pkg-constants // for valid values. FulcioAuthFlow string @@ -59,4 +60,20 @@ type KeyOpts struct { // TrustedMaterial contains trusted metadata for all Sigstore services. It is exclusive with RekorPubKeys, RootCerts, IntermediateCerts, CTLogPubKeys, and the TSA* cert fields. TrustedMaterial root.TrustedMaterial + + // SigningConfig contains the list of service URLs for Sigstore services. + SigningConfig *root.SigningConfig + + // DefaultLoadOptions may be set to control the behaviour of + // `LoadDefaultSigner/Verifier` family of functions. Some public/private key + // types have ambiguities with regards to the signing algorithm to use (e.g. + // RSA can be RSASSA-PSS or RSASSA-PKCS1v15). This is a way to control that. + // + // By default, Ed25519ph is used for ed25519 keys and RSA-PKCS1v15 is used + // for RSA keys. + DefaultLoadOptions *[]signature.LoadOption + + // SigningAlgorithm is the AlgorithmDetails string representation used to + // sign/hash the payload. + SigningAlgorithm string } diff --git a/cmd/cosign/cli/options/pkcs11_tool.go b/cmd/cosign/cli/options/pkcs11_tool.go index c391e9de7b6..ce1523fc94b 100644 --- a/cmd/cosign/cli/options/pkcs11_tool.go +++ b/cmd/cosign/cli/options/pkcs11_tool.go @@ -16,7 +16,7 @@ package options import ( - "github.com/sigstore/cosign/v2/pkg/cosign/env" + "github.com/sigstore/cosign/v3/pkg/cosign/env" "github.com/spf13/cobra" ) diff --git a/cmd/cosign/cli/options/predicate.go b/cmd/cosign/cli/options/predicate.go index e08325a376e..f33b347acfb 100644 --- a/cmd/cosign/cli/options/predicate.go +++ b/cmd/cosign/cli/options/predicate.go @@ -22,7 +22,7 @@ import ( "github.com/in-toto/in-toto-golang/in_toto" slsa02 "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.2" slsa1 "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v1" - "github.com/sigstore/cosign/v2/pkg/cosign/attestation" + "github.com/sigstore/cosign/v3/pkg/cosign/attestation" "github.com/spf13/cobra" ) diff --git a/cmd/cosign/cli/options/registry.go b/cmd/cosign/cli/options/registry.go index 6840d532974..011854d91b0 100644 --- a/cmd/cosign/cli/options/registry.go +++ b/cmd/cosign/cli/options/registry.go @@ -32,7 +32,7 @@ import ( "github.com/google/go-containerregistry/pkg/v1/google" "github.com/google/go-containerregistry/pkg/v1/remote" alibabaacr "github.com/mozillazg/docker-credential-acr-helper/pkg/credhelper" - ociremote "github.com/sigstore/cosign/v2/pkg/oci/remote" + ociremote "github.com/sigstore/cosign/v3/pkg/oci/remote" "github.com/spf13/cobra" ) diff --git a/cmd/cosign/cli/options/sign.go b/cmd/cosign/cli/options/sign.go index bcacfd7e63f..c0d6bdef3a2 100644 --- a/cmd/cosign/cli/options/sign.go +++ b/cmd/cosign/cli/options/sign.go @@ -29,6 +29,7 @@ type SignOptions struct { OutputSignature string // TODO: this should be the root output file arg. OutputPayload string OutputCertificate string + BundlePath string PayloadPath string Recursive bool Attachment string @@ -40,8 +41,12 @@ type SignOptions struct { TSAServerName string TSAServerURL string IssueCertificate bool - SignContainerIdentity string + SignContainerIdentities []string RecordCreationTimestamp bool + NewBundleFormat bool + UseSigningConfig bool + SigningConfigPath string + TrustedRootPath string Rekor RekorOptions Fulcio FulcioOptions @@ -93,6 +98,10 @@ func (o *SignOptions) AddFlags(cmd *cobra.Command) { "write the certificate to FILE") _ = cmd.MarkFlagFilename("output-certificate", certificateExts...) + cmd.Flags().StringVar(&o.BundlePath, "bundle", "", + "write everything required to verify the image to FILE") + _ = cmd.MarkFlagFilename("bundle", bundleExts...) + cmd.Flags().StringVar(&o.PayloadPath, "payload", "", "path to a payload file to use rather than generating one") // _ = cmd.MarkFlagFilename("payload") // no typical extensions @@ -109,6 +118,7 @@ func (o *SignOptions) AddFlags(cmd *cobra.Command) { cmd.Flags().BoolVar(&o.TlogUpload, "tlog-upload", true, "whether or not to upload to the tlog") + _ = cmd.Flags().MarkDeprecated("tlog-upload", "prefer using a --signing-config file with no transparency log services") cmd.Flags().StringVar(&o.TSAClientCACert, "timestamp-client-cacert", "", "path to the X.509 CA certificate file in PEM format to be used for the connection to the TSA Server") @@ -133,8 +143,21 @@ func (o *SignOptions) AddFlags(cmd *cobra.Command) { cmd.Flags().BoolVar(&o.IssueCertificate, "issue-certificate", false, "issue a code signing certificate from Fulcio, even if a key is provided") - cmd.Flags().StringVar(&o.SignContainerIdentity, "sign-container-identity", "", - "manually set the .critical.docker-reference field for the signed identity, which is useful when image proxies are being used where the pull reference should match the signature") + cmd.Flags().StringSliceVar(&o.SignContainerIdentities, "sign-container-identity", nil, + "manually set the .critical.docker-reference field for the signed identity, which is useful when image proxies are being used where the pull reference should match the signature, this flag is comma delimited. ex: --sign-container-identity=identity1,identity2") cmd.Flags().BoolVar(&o.RecordCreationTimestamp, "record-creation-timestamp", false, "set the createdAt timestamp in the signature artifact to the time it was created; by default, cosign sets this to the zero value") + + cmd.Flags().BoolVar(&o.NewBundleFormat, "new-bundle-format", true, "expect the signature/attestation to be packaged in a Sigstore bundle") + + cmd.Flags().BoolVar(&o.UseSigningConfig, "use-signing-config", true, + "whether to use a TUF-provided signing config for the service URLs. Must set --new-bundle-format, which will store verification material in the new format") + + cmd.Flags().StringVar(&o.SigningConfigPath, "signing-config", "", + "path to a signing config file. Must provide --new-bundle-format, which will store verification material in the new format") + + cmd.MarkFlagsMutuallyExclusive("use-signing-config", "signing-config") + + cmd.Flags().StringVar(&o.TrustedRootPath, "trusted-root", "", + "optional path to a TrustedRoot JSON file to verify a signature after signing") } diff --git a/cmd/cosign/cli/options/signblob.go b/cmd/cosign/cli/options/signblob.go index 5afff3c8079..8be80b9c031 100644 --- a/cmd/cosign/cli/options/signblob.go +++ b/cmd/cosign/cli/options/signblob.go @@ -16,6 +16,12 @@ package options import ( + "fmt" + "strings" + + "github.com/sigstore/cosign/v3/pkg/cosign" + v1 "github.com/sigstore/protobuf-specs/gen/pb-go/common/v1" + "github.com/sigstore/sigstore/pkg/signature" "github.com/spf13/cobra" ) @@ -23,6 +29,8 @@ import ( // The new output-certificate flag is only in use when COSIGN_EXPERIMENTAL is enabled type SignBlobOptions struct { Key string + Cert string + CertChain string Base64Output bool Output string // deprecated: TODO remove when the output flag is fully deprecated OutputSignature string // TODO: this should be the root output file arg. @@ -43,6 +51,11 @@ type SignBlobOptions struct { TSAServerURL string RFC3161TimestampPath string IssueCertificate bool + SigningAlgorithm string + + UseSigningConfig bool + SigningConfigPath string + TrustedRootPath string } var _ Interface = (*SignBlobOptions)(nil) @@ -58,6 +71,17 @@ func (o *SignBlobOptions) AddFlags(cmd *cobra.Command) { "path to the private key file, KMS URI or Kubernetes Secret") _ = cmd.MarkFlagFilename("key", privateKeyExts...) + cmd.Flags().StringVar(&o.Cert, "certificate", "", + "path to the X.509 certificate for signing attestation") + _ = cmd.MarkFlagFilename("certificate", certificateExts...) + + cmd.Flags().StringVar(&o.CertChain, "certificate-chain", "", + "path to a list of CA X.509 certificates in PEM format which will be needed "+ + "when building the certificate chain for the signed attestation. "+ + "Must start with the parent intermediate CA certificate of the "+ + "signing certificate and end with the root certificate.") + _ = cmd.MarkFlagFilename("certificate-chain", certificateExts...) + cmd.Flags().BoolVar(&o.Base64Output, "b64", true, "whether to base64 encode the output") @@ -77,15 +101,26 @@ func (o *SignBlobOptions) AddFlags(cmd *cobra.Command) { "write everything required to verify the blob to a FILE") _ = cmd.MarkFlagFilename("bundle", bundleExts...) - // TODO: have this default to true as a breaking change - cmd.Flags().BoolVar(&o.NewBundleFormat, "new-bundle-format", false, + cmd.Flags().BoolVar(&o.NewBundleFormat, "new-bundle-format", true, "output bundle in new format that contains all verification material") + cmd.Flags().BoolVar(&o.UseSigningConfig, "use-signing-config", true, + "whether to use a TUF-provided signing config for the service URLs. Must provide --bundle, which will output verification material in the new format") + + cmd.Flags().StringVar(&o.SigningConfigPath, "signing-config", "", + "path to a signing config file. Must provide --bundle, which will output verification material in the new format") + + cmd.MarkFlagsMutuallyExclusive("use-signing-config", "signing-config") + + cmd.Flags().StringVar(&o.TrustedRootPath, "trusted-root", "", + "optional path to a TrustedRoot JSON file to verify a signature after signing") + cmd.Flags().BoolVarP(&o.SkipConfirmation, "yes", "y", false, "skip confirmation prompts for non-destructive operations") cmd.Flags().BoolVar(&o.TlogUpload, "tlog-upload", true, "whether or not to upload to the tlog") + _ = cmd.Flags().MarkDeprecated("tlog-upload", "prefer using a --signing-config file with no transparency log services") cmd.Flags().StringVar(&o.TSAClientCACert, "timestamp-client-cacert", "", "path to the X.509 CA certificate file in PEM format to be used for the connection to the TSA Server") @@ -113,4 +148,9 @@ func (o *SignBlobOptions) AddFlags(cmd *cobra.Command) { cmd.Flags().BoolVar(&o.IssueCertificate, "issue-certificate", false, "issue a code signing certificate from Fulcio, even if a key is provided") + + keyAlgorithmTypes := cosign.GetSupportedAlgorithms() + keyAlgorithmHelp := fmt.Sprintf("signing algorithm to use for signing/hashing (allowed %s)", strings.Join(keyAlgorithmTypes, ", ")) + defaultKeyFlag, _ := signature.FormatSignatureAlgorithmFlag(v1.PublicKeyDetails_PKIX_ECDSA_P256_SHA_256) + cmd.Flags().StringVar(&o.SigningAlgorithm, "signing-algorithm", defaultKeyFlag, keyAlgorithmHelp) } diff --git a/cmd/cosign/cli/options/tree.go b/cmd/cosign/cli/options/tree.go index cbd55967749..965b3478a3a 100644 --- a/cmd/cosign/cli/options/tree.go +++ b/cmd/cosign/cli/options/tree.go @@ -29,6 +29,6 @@ func (c *TreeOptions) AddFlags(cmd *cobra.Command) { c.Registry.AddFlags(cmd) c.RegistryExperimental.AddFlags(cmd) - cmd.Flags().BoolVar(&c.ExperimentalOCI11, "experimental-oci11", false, - "set to true to enable experimental OCI 1.1 behaviour") + cmd.Flags().BoolVar(&c.ExperimentalOCI11, "experimental-oci11", true, + "set to false to ignore OCI 1.1 behavior") } diff --git a/cmd/cosign/cli/options/verify.go b/cmd/cosign/cli/options/verify.go index cb7ac30401a..996a54a24d5 100644 --- a/cmd/cosign/cli/options/verify.go +++ b/cmd/cosign/cli/options/verify.go @@ -18,7 +18,7 @@ package options import ( "github.com/spf13/cobra" - "github.com/sigstore/cosign/v2/internal/pkg/cosign" + "github.com/sigstore/cosign/v3/internal/pkg/cosign" ) type CommonVerifyOptions struct { @@ -37,7 +37,8 @@ type CommonVerifyOptions struct { func (o *CommonVerifyOptions) AddFlags(cmd *cobra.Command) { cmd.Flags().BoolVar(&o.Offline, "offline", false, - "only allow offline verification") + "only verify an artifact's inclusion in a transparency log using a provided proof, rather than querying the log. May still include network requests to retrieve service keys from a TUF repository") + _ = cmd.Flags().MarkDeprecated("offline", "To verify in an airgapped environment, provide a --bundle with the signature and verification material, and a --trusted-root file with the service keys and certificates") cmd.Flags().StringVar(&o.TSACertChainPath, "timestamp-certificate-chain", "", "path to PEM-encoded certificate chain file for the RFC3161 timestamp authority. Must contain the root CA certificate. "+ @@ -54,7 +55,7 @@ func (o *CommonVerifyOptions) AddFlags(cmd *cobra.Command) { "skip transparency log verification when verifying artifacts in a privately deployed infrastructure") cmd.Flags().BoolVar(&o.ExperimentalOCI11, "experimental-oci11", false, - "set to true to enable experimental OCI 1.1 behaviour") + "set to true to enable experimental OCI 1.1 behaviour (unrelated to bundle format)") cmd.Flags().IntVar(&o.MaxWorkers, "max-workers", cosign.DefaultMaxWorkers, "the amount of maximum workers for parallel executions") @@ -62,8 +63,7 @@ func (o *CommonVerifyOptions) AddFlags(cmd *cobra.Command) { cmd.Flags().StringVar(&o.TrustedRootPath, "trusted-root", "", "Path to a Sigstore TrustedRoot JSON file. Requires --new-bundle-format to be set.") - // TODO: have this default to true as a breaking change - cmd.Flags().BoolVar(&o.NewBundleFormat, "new-bundle-format", false, + cmd.Flags().BoolVar(&o.NewBundleFormat, "new-bundle-format", true, "expect the signature/attestation to be packaged in a Sigstore bundle") } @@ -123,6 +123,8 @@ func (o *VerifyOptions) AddFlags(cmd *cobra.Command) { cmd.Flags().BoolVar(&o.LocalImage, "local-image", false, "whether the specified image is a path to an image saved locally via 'cosign save'") + + cmd.MarkFlagsMutuallyExclusive("local-image", "new-bundle-format") } // VerifyAttestationOptions is the top level wrapper for the `verify attestation` command. @@ -137,6 +139,7 @@ type VerifyAttestationOptions struct { CertVerify CertVerifyOptions Registry RegistryOptions Predicate PredicateRemoteOptions + SignatureDigest SignatureDigestOptions Policies []string LocalImage bool } @@ -151,6 +154,7 @@ func (o *VerifyAttestationOptions) AddFlags(cmd *cobra.Command) { o.Registry.AddFlags(cmd) o.Predicate.AddFlags(cmd) o.CommonVerifyOptions.AddFlags(cmd) + o.SignatureDigest.AddFlags(cmd) cmd.Flags().StringVar(&o.Key, "key", "", "path to the public key file, KMS URI or Kubernetes Secret") @@ -166,6 +170,8 @@ func (o *VerifyAttestationOptions) AddFlags(cmd *cobra.Command) { cmd.Flags().BoolVar(&o.LocalImage, "local-image", false, "whether the specified image is a path to an image saved locally via 'cosign save'") + + cmd.MarkFlagsMutuallyExclusive("local-image", "new-bundle-format") } // VerifyBlobOptions is the top level wrapper for the `verify blob` command. @@ -178,6 +184,7 @@ type VerifyBlobOptions struct { CertVerify CertVerifyOptions Rekor RekorOptions CommonVerifyOptions CommonVerifyOptions + SignatureDigest SignatureDigestOptions RFC3161TimestampPath string } @@ -190,6 +197,7 @@ func (o *VerifyBlobOptions) AddFlags(cmd *cobra.Command) { o.Rekor.AddFlags(cmd) o.CertVerify.AddFlags(cmd) o.CommonVerifyOptions.AddFlags(cmd) + o.SignatureDigest.AddFlags(cmd) cmd.Flags().StringVar(&o.Key, "key", "", "path to the public key file, KMS URI or Kubernetes Secret") @@ -233,6 +241,7 @@ type VerifyBlobAttestationOptions struct { CertVerify CertVerifyOptions Rekor RekorOptions CommonVerifyOptions CommonVerifyOptions + SignatureDigest SignatureDigestOptions RFC3161TimestampPath string @@ -249,6 +258,7 @@ func (o *VerifyBlobAttestationOptions) AddFlags(cmd *cobra.Command) { o.Rekor.AddFlags(cmd) o.CertVerify.AddFlags(cmd) o.CommonVerifyOptions.AddFlags(cmd) + o.SignatureDigest.AddFlags(cmd) cmd.Flags().StringVar(&o.Key, "key", "", "path to the public key file, KMS URI or Kubernetes Secret") diff --git a/cmd/cosign/cli/piv_tool.go b/cmd/cosign/cli/piv_tool.go index 855b1a8dead..c30719acfd5 100644 --- a/cmd/cosign/cli/piv_tool.go +++ b/cmd/cosign/cli/piv_tool.go @@ -20,8 +20,8 @@ package cli import ( "encoding/json" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/pivcli" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/pivcli" "github.com/spf13/cobra" ) diff --git a/cmd/cosign/cli/pivcli/commands.go b/cmd/cosign/cli/pivcli/commands.go index 2f532eaaf79..a40771bbee9 100644 --- a/cmd/cosign/cli/pivcli/commands.go +++ b/cmd/cosign/cli/pivcli/commands.go @@ -32,7 +32,7 @@ import ( "github.com/go-piv/piv-go/v2/piv" "github.com/manifoldco/promptui" - "github.com/sigstore/cosign/v2/pkg/cosign/pivkey" + "github.com/sigstore/cosign/v3/pkg/cosign/pivkey" ) func SetManagementKeyCmd(_ context.Context, oldKey, newKey string, randomKey bool) error { diff --git a/cmd/cosign/cli/pkcs11_tool.go b/cmd/cosign/cli/pkcs11_tool.go index bc8e80a4bdc..5249c1e2422 100644 --- a/cmd/cosign/cli/pkcs11_tool.go +++ b/cmd/cosign/cli/pkcs11_tool.go @@ -18,8 +18,8 @@ package cli import ( - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/pkcs11cli" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/pkcs11cli" "github.com/spf13/cobra" ) diff --git a/cmd/cosign/cli/pkcs11cli/commands.go b/cmd/cosign/cli/pkcs11cli/commands.go index 6d4609f5161..59cd5ea8995 100644 --- a/cmd/cosign/cli/pkcs11cli/commands.go +++ b/cmd/cosign/cli/pkcs11cli/commands.go @@ -28,8 +28,8 @@ import ( "syscall" "github.com/miekg/pkcs11" - "github.com/sigstore/cosign/v2/pkg/cosign/env" - "github.com/sigstore/cosign/v2/pkg/cosign/pkcs11key" + "github.com/sigstore/cosign/v3/pkg/cosign/env" + "github.com/sigstore/cosign/v3/pkg/cosign/pkcs11key" "golang.org/x/term" ) diff --git a/cmd/cosign/cli/public_key.go b/cmd/cosign/cli/public_key.go index 6f1b225082e..1f9c9769d1e 100644 --- a/cmd/cosign/cli/public_key.go +++ b/cmd/cosign/cli/public_key.go @@ -18,9 +18,9 @@ package cli import ( "os" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/generate" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/publickey" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/generate" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/publickey" "github.com/spf13/cobra" ) diff --git a/cmd/cosign/cli/publickey/public_key.go b/cmd/cosign/cli/publickey/public_key.go index 36158587912..85060b29597 100644 --- a/cmd/cosign/cli/publickey/public_key.go +++ b/cmd/cosign/cli/publickey/public_key.go @@ -20,11 +20,11 @@ import ( "fmt" "io" - "github.com/sigstore/cosign/v2/internal/ui" - "github.com/sigstore/cosign/v2/pkg/cosign" - "github.com/sigstore/cosign/v2/pkg/cosign/pivkey" - "github.com/sigstore/cosign/v2/pkg/cosign/pkcs11key" - sigs "github.com/sigstore/cosign/v2/pkg/signature" + "github.com/sigstore/cosign/v3/internal/ui" + "github.com/sigstore/cosign/v3/pkg/cosign" + "github.com/sigstore/cosign/v3/pkg/cosign/pivkey" + "github.com/sigstore/cosign/v3/pkg/cosign/pkcs11key" + sigs "github.com/sigstore/cosign/v3/pkg/signature" "github.com/sigstore/sigstore/pkg/signature" signatureoptions "github.com/sigstore/sigstore/pkg/signature/options" ) diff --git a/cmd/cosign/cli/publickey/public_key_test.go b/cmd/cosign/cli/publickey/public_key_test.go index 12a93439ff5..f7de44a9344 100644 --- a/cmd/cosign/cli/publickey/public_key_test.go +++ b/cmd/cosign/cli/publickey/public_key_test.go @@ -23,7 +23,7 @@ import ( "path/filepath" "testing" - "github.com/sigstore/cosign/v2/pkg/cosign" + "github.com/sigstore/cosign/v3/pkg/cosign" ) func pass(s string) cosign.PassFunc { diff --git a/cmd/cosign/cli/rekor/rekor.go b/cmd/cosign/cli/rekor/rekor.go index 76d57ad1b08..c06cef5a0d4 100644 --- a/cmd/cosign/cli/rekor/rekor.go +++ b/cmd/cosign/cli/rekor/rekor.go @@ -18,7 +18,7 @@ import ( rekor "github.com/sigstore/rekor/pkg/client" "github.com/sigstore/rekor/pkg/generated/client" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" ) func NewClient(rekorURL string) (*client.Rekor, error) { diff --git a/cmd/cosign/cli/rekor/rekor_test.go b/cmd/cosign/cli/rekor/rekor_test.go index 31b8f4eb999..94555f09348 100644 --- a/cmd/cosign/cli/rekor/rekor_test.go +++ b/cmd/cosign/cli/rekor/rekor_test.go @@ -19,7 +19,7 @@ import ( "net/http/httptest" "testing" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" ) func TestNewClient(t *testing.T) { diff --git a/cmd/cosign/cli/save.go b/cmd/cosign/cli/save.go index 018bd9f76ed..b8c5f244c0b 100644 --- a/cmd/cosign/cli/save.go +++ b/cmd/cosign/cli/save.go @@ -21,10 +21,10 @@ import ( "fmt" "github.com/google/go-containerregistry/pkg/name" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/pkg/oci" - "github.com/sigstore/cosign/v2/pkg/oci/layout" - ociremote "github.com/sigstore/cosign/v2/pkg/oci/remote" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/pkg/oci" + "github.com/sigstore/cosign/v3/pkg/oci/layout" + ociremote "github.com/sigstore/cosign/v3/pkg/oci/remote" "github.com/spf13/cobra" ) @@ -59,6 +59,36 @@ func SaveCmd(ctx context.Context, opts options.SaveOptions, imageRef string) err return fmt.Errorf("parsing image name %s: %w", imageRef, err) } + // See if we are using referrers + digest, ok := ref.(name.Digest) + if !ok { + var err error + digest, err = ociremote.ResolveDigest(ref, regClientOpts...) + if err != nil { + return fmt.Errorf("resolving digest: %w", err) + } + } + + indexManifest, err := ociremote.Referrers(digest, "", regClientOpts...) + if err != nil { + return fmt.Errorf("getting referrers: %w", err) + } + + for _, manifest := range indexManifest.Manifests { + if manifest.ArtifactType == "" { + continue + } + artifactRef := ref.Context().Digest(manifest.Digest.String()) + si, err := ociremote.SignedImage(artifactRef, regClientOpts...) + if err != nil { + return fmt.Errorf("getting signed image: %w", err) + } + err = layout.WriteSignedImage(opts.Directory, si) + if err != nil { + return err + } + } + se, err := ociremote.SignedEntity(ref, regClientOpts...) if err != nil { return fmt.Errorf("signed entity: %w", err) diff --git a/cmd/cosign/cli/sign.go b/cmd/cosign/cli/sign.go index 24a659bc828..f82074d0dc7 100644 --- a/cmd/cosign/cli/sign.go +++ b/cmd/cosign/cli/sign.go @@ -16,16 +16,13 @@ package cli import ( - "context" "fmt" "os" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/generate" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/sign" - "github.com/sigstore/cosign/v2/internal/ui" - "github.com/sigstore/cosign/v2/pkg/cosign" - "github.com/sigstore/cosign/v2/pkg/cosign/env" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/generate" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/sign" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/signcommon" "github.com/spf13/cobra" ) @@ -93,7 +90,7 @@ race conditions or (worse) malicious tampering. Args: cobra.MinimumNArgs(1), PersistentPreRun: options.BindViper, - RunE: func(_ *cobra.Command, args []string) error { + RunE: func(cmd *cobra.Command, args []string) error { switch o.Attachment { case "sbom": fmt.Fprintln(os.Stderr, options.SBOMAttachmentDeprecation) @@ -131,14 +128,13 @@ race conditions or (worse) malicious tampering. TSAServerURL: o.TSAServerURL, IssueCertificateForExistingKey: o.IssueCertificate, } - if (o.Key == "" || o.IssueCertificate) && env.Getenv(env.VariableSigstoreCTLogPublicKeyFile) == "" { - trustedMaterial, err := cosign.TrustedRoot() - if err != nil { - ui.Warnf(context.Background(), "Could not fetch trusted_root.json from the TUF repository. Continuing with individual targets. Error from TUF: %v", err) - } - ko.TrustedMaterial = trustedMaterial + if err := signcommon.LoadTrustedMaterialAndSigningConfig(cmd.Context(), &ko, o.UseSigningConfig, o.SigningConfigPath, + o.Rekor.URL, o.Fulcio.URL, o.OIDC.Issuer, o.TSAServerURL, o.TrustedRootPath, o.TlogUpload, + o.NewBundleFormat, "", o.Key, o.IssueCertificate, o.Output, "", o.OutputCertificate, o.OutputPayload, o.OutputSignature); err != nil { + return err } - if err := sign.SignCmd(ro, ko, *o, args); err != nil { + + if err := sign.SignCmd(cmd.Context(), ro, ko, *o, args); err != nil { if o.Attachment == "" { return fmt.Errorf("signing %v: %w", args, err) } diff --git a/cmd/cosign/cli/sign/sign.go b/cmd/cosign/cli/sign/sign.go index a6ee88122d1..4f4f239105c 100644 --- a/cmd/cosign/cli/sign/sign.go +++ b/cmd/cosign/cli/sign/sign.go @@ -18,12 +18,8 @@ package sign import ( "bytes" "context" - "crypto" - "crypto/x509" "encoding/base64" "encoding/json" - "encoding/pem" - "errors" "fmt" "os" "path/filepath" @@ -31,80 +27,32 @@ import ( "github.com/google/go-containerregistry/pkg/name" v1 "github.com/google/go-containerregistry/pkg/v1" - "github.com/google/go-containerregistry/pkg/v1/remote" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/fulcio" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/fulcio/fulcioverifier" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/rekor" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/sign/privacy" - icos "github.com/sigstore/cosign/v2/internal/pkg/cosign" - ifulcio "github.com/sigstore/cosign/v2/internal/pkg/cosign/fulcio" - ipayload "github.com/sigstore/cosign/v2/internal/pkg/cosign/payload" - irekor "github.com/sigstore/cosign/v2/internal/pkg/cosign/rekor" - "github.com/sigstore/cosign/v2/internal/pkg/cosign/tsa" - "github.com/sigstore/cosign/v2/internal/pkg/cosign/tsa/client" - "github.com/sigstore/cosign/v2/internal/ui" - "github.com/sigstore/cosign/v2/pkg/cosign" - "github.com/sigstore/cosign/v2/pkg/cosign/pivkey" - "github.com/sigstore/cosign/v2/pkg/cosign/pkcs11key" - cremote "github.com/sigstore/cosign/v2/pkg/cosign/remote" - "github.com/sigstore/cosign/v2/pkg/oci" - "github.com/sigstore/cosign/v2/pkg/oci/mutate" - ociremote "github.com/sigstore/cosign/v2/pkg/oci/remote" - "github.com/sigstore/cosign/v2/pkg/oci/walk" - sigs "github.com/sigstore/cosign/v2/pkg/signature" - "github.com/sigstore/sigstore/pkg/cryptoutils" - "github.com/sigstore/sigstore/pkg/signature" - signatureoptions "github.com/sigstore/sigstore/pkg/signature/options" + intotov1 "github.com/in-toto/attestation/go/v1" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/rekor" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/signcommon" + icos "github.com/sigstore/cosign/v3/internal/pkg/cosign" + ifulcio "github.com/sigstore/cosign/v3/internal/pkg/cosign/fulcio" + ipayload "github.com/sigstore/cosign/v3/internal/pkg/cosign/payload" + irekor "github.com/sigstore/cosign/v3/internal/pkg/cosign/rekor" + "github.com/sigstore/cosign/v3/internal/pkg/cosign/tsa" + "github.com/sigstore/cosign/v3/internal/pkg/cosign/tsa/client" + "github.com/sigstore/cosign/v3/internal/ui" + "github.com/sigstore/cosign/v3/pkg/cosign" + cremote "github.com/sigstore/cosign/v3/pkg/cosign/remote" + "github.com/sigstore/cosign/v3/pkg/oci" + "github.com/sigstore/cosign/v3/pkg/oci/mutate" + ociremote "github.com/sigstore/cosign/v3/pkg/oci/remote" + "github.com/sigstore/cosign/v3/pkg/oci/walk" + "github.com/sigstore/cosign/v3/pkg/types" sigPayload "github.com/sigstore/sigstore/pkg/signature/payload" + "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/types/known/structpb" // Loads OIDC providers - _ "github.com/sigstore/cosign/v2/pkg/providers/all" + _ "github.com/sigstore/cosign/v3/pkg/providers/all" ) -func ShouldUploadToTlog(ctx context.Context, ko options.KeyOpts, ref name.Reference, tlogUpload bool) (bool, error) { - upload := shouldUploadToTlog(ctx, ko, ref, tlogUpload) - var statementErr error - if upload { - privacy.StatementOnce.Do(func() { - ui.Infof(ctx, privacy.Statement) - ui.Infof(ctx, privacy.StatementConfirmation) - if !ko.SkipConfirmation { - if err := ui.ConfirmContinue(ctx); err != nil { - statementErr = err - } - } - }) - } - return upload, statementErr -} - -func shouldUploadToTlog(ctx context.Context, ko options.KeyOpts, ref name.Reference, tlogUpload bool) bool { - // return false if not uploading to the tlog has been requested - if !tlogUpload { - return false - } - - if ko.SkipConfirmation { - return true - } - - // We don't need to validate the ref, just return true - if ref == nil { - return true - } - - // Check if the image is public (no auth in Get) - if _, err := remote.Get(ref, remote.WithContext(ctx)); err != nil { - ui.Warnf(ctx, "%q appears to be a private repository, please confirm uploading to the transparency log at %q", ref.Context().String(), ko.RekorURL) - if ui.ConfirmContinue(ctx) != nil { - ui.Infof(ctx, "not uploading to transparency log") - return false - } - } - return true -} - func GetAttachedImageRef(ref name.Reference, attachment string, opts ...ociremote.Option) (name.Reference, error) { if attachment == "" { return ref, nil @@ -115,35 +63,17 @@ func GetAttachedImageRef(ref name.Reference, attachment string, opts ...ociremot return nil, fmt.Errorf("unknown attachment type %s", attachment) } -// ParseOCIReference parses a string reference to an OCI image into a reference, warning if the reference did not include a digest. -func ParseOCIReference(ctx context.Context, refStr string, opts ...name.Option) (name.Reference, error) { - ref, err := name.ParseReference(refStr, opts...) - if err != nil { - return nil, fmt.Errorf("parsing reference: %w", err) - } - if _, ok := ref.(name.Digest); !ok { - ui.Warnf(ctx, ui.TagReferenceMessage, refStr) - } - return ref, nil -} - // nolint -func SignCmd(ro *options.RootOptions, ko options.KeyOpts, signOpts options.SignOptions, imgs []string) error { +func SignCmd(ctx context.Context, ro *options.RootOptions, ko options.KeyOpts, signOpts options.SignOptions, imgs []string) error { if options.NOf(ko.KeyRef, ko.Sk) > 1 { return &options.KeyParseError{} } - ctx, cancel := context.WithTimeout(context.Background(), ro.Timeout) + ctx, cancel := context.WithTimeout(ctx, ro.Timeout) defer cancel() - sv, err := SignerFromKeyOpts(ctx, signOpts.Cert, signOpts.CertChain, ko) - if err != nil { - return fmt.Errorf("getting signer: %w", err) - } - defer sv.Close() - dd := cremote.NewDupeDetector(sv) - var staticPayload []byte + var err error if signOpts.PayloadPath != "" { ui.Infof(ctx, "Using payload from: %s", signOpts.PayloadPath) staticPayload, err = os.ReadFile(filepath.Clean(signOpts.PayloadPath)) @@ -168,7 +98,7 @@ func SignCmd(ro *options.RootOptions, ko options.KeyOpts, signOpts options.SignO } annotations := am.Annotations for _, inputImg := range imgs { - ref, err := ParseOCIReference(ctx, inputImg, regOpts.NameOptions()...) + ref, err := signcommon.ParseOCIReference(ctx, inputImg, regOpts.NameOptions()...) if err != nil { return err } @@ -184,7 +114,11 @@ func SignCmd(ro *options.RootOptions, ko options.KeyOpts, signOpts options.SignO } else if err != nil { return fmt.Errorf("accessing image: %w", err) } - err = signDigest(ctx, digest, staticPayload, ko, signOpts, annotations, dd, sv, se) + if signOpts.NewBundleFormat { + err = signDigestBundle(ctx, digest, ko, signOpts, annotations) + } else { + err = signDigest(ctx, digest, staticPayload, ko, signOpts, annotations, se) + } if err != nil { return fmt.Errorf("signing digest: %w", err) } @@ -203,7 +137,11 @@ func SignCmd(ro *options.RootOptions, ko options.KeyOpts, signOpts options.SignO return fmt.Errorf("computing digest: %w", err) } digest := ref.Context().Digest(d.String()) - err = signDigest(ctx, digest, staticPayload, ko, signOpts, annotations, dd, sv, se) + if signOpts.NewBundleFormat { + err = signDigestBundle(ctx, digest, ko, signOpts, annotations) + } else { + err = signDigest(ctx, digest, staticPayload, ko, signOpts, annotations, se) + } if err != nil { return fmt.Errorf("signing digest: %w", err) } @@ -216,22 +154,93 @@ func SignCmd(ro *options.RootOptions, ko options.KeyOpts, signOpts options.SignO return nil } +func signDigestBundle(ctx context.Context, digest name.Digest, ko options.KeyOpts, signOpts options.SignOptions, annotations map[string]any) error { + digestParts := strings.Split(digest.DigestStr(), ":") + if len(digestParts) != 2 { + return fmt.Errorf("unable to parse digest %s", digest.DigestStr()) + } + + annoStruct, _ := structpb.NewStruct(annotations) + subject := intotov1.ResourceDescriptor{ + Digest: map[string]string{digestParts[0]: digestParts[1]}, + Annotations: annoStruct, + } + + statement := &intotov1.Statement{ + Type: intotov1.StatementTypeUri, + Subject: []*intotov1.ResourceDescriptor{&subject}, + PredicateType: types.CosignSignPredicateType, + } + + payload, err := protojson.Marshal(statement) + if err != nil { + return err + } + + regOpts := signOpts.Registry + ociremoteOpts, err := regOpts.ClientOpts(ctx) + if err != nil { + return fmt.Errorf("constructing client options: %w", err) + } + if regOpts.AllowHTTPRegistry || regOpts.AllowInsecure { + ociremoteOpts = append(ociremoteOpts, ociremote.WithNameOptions(name.Insecure)) + } + + bundleOpts := signcommon.CommonBundleOpts{ + Payload: payload, + Digest: digest, + PredicateType: types.CosignSignPredicateType, + BundlePath: signOpts.BundlePath, + Upload: signOpts.Upload, + OCIRemoteOpts: ociremoteOpts, + } + + if ko.SigningConfig != nil { + return signcommon.WriteNewBundleWithSigningConfig(ctx, ko, signOpts.Cert, signOpts.CertChain, bundleOpts, ko.SigningConfig, ko.TrustedMaterial) + } + + bundleComponents, closeSV, err := signcommon.GetBundleComponents(ctx, signOpts.Cert, signOpts.CertChain, ko, false, signOpts.TlogUpload, payload, digest, "dsse") + if err != nil { + return fmt.Errorf("getting bundle components: %w", err) + } + defer closeSV() + + return signcommon.WriteBundle(ctx, bundleComponents.SV, bundleComponents.RekorEntry, bundleOpts, bundleComponents.SignedPayload, bundleComponents.SignerBytes, bundleComponents.TimestampBytes) +} + func signDigest(ctx context.Context, digest name.Digest, payload []byte, ko options.KeyOpts, signOpts options.SignOptions, - annotations map[string]interface{}, - dd mutate.DupeDetector, sv *SignerVerifier, se oci.SignedEntity) error { + annotations map[string]interface{}, se oci.SignedEntity) error { var err error + var payloads [][]byte // The payload can be passed to skip generation. if len(payload) == 0 { - payload, err = (&sigPayload.Cosign{ - Image: digest, - ClaimedIdentity: signOpts.SignContainerIdentity, - Annotations: annotations, - }).MarshalJSON() - if err != nil { - return fmt.Errorf("payload: %w", err) + identities := signOpts.SignContainerIdentities + if len(identities) == 0 { + identities = append(identities, "") + } + for _, identity := range identities { + payload, err = (&sigPayload.Cosign{ + Image: digest, + ClaimedIdentity: identity, + Annotations: annotations, + }).MarshalJSON() + if err != nil { + return fmt.Errorf("payload: %w", err) + } + payloads = append(payloads, payload) } + } else { + payloads = append(payloads, payload) } + sv, closeSV, err := signcommon.GetSignerVerifier(ctx, signOpts.Cert, signOpts.CertChain, ko) + if err != nil { + return fmt.Errorf("getting signer: %w", err) + } + defer closeSV() + + dd := cremote.NewDupeDetector(sv) + var s icos.Signer s = ipayload.NewSigner(sv) if sv.Cert != nil { @@ -250,7 +259,7 @@ func signDigest(ctx context.Context, digest name.Digest, payload []byte, ko opti )) } } - shouldUpload, err := ShouldUploadToTlog(ctx, ko, digest, signOpts.TlogUpload) + shouldUpload, err := signcommon.ShouldUploadToTlog(ctx, ko, digest, signOpts.TlogUpload) if err != nil { return fmt.Errorf("should upload to tlog: %w", err) } @@ -262,14 +271,21 @@ func signDigest(ctx context.Context, digest name.Digest, payload []byte, ko opti s = irekor.NewSigner(s, rClient) } - ociSig, _, err := s.Sign(ctx, bytes.NewReader(payload)) - if err != nil { - return err - } + ociSigs := make([]oci.Signature, len(payloads)) + b64sigs := make([]string, len(payloads)) - b64sig, err := ociSig.Base64Signature() - if err != nil { - return err + for i, payload := range payloads { + ociSig, _, err := s.Sign(ctx, bytes.NewReader(payload)) + if err != nil { + return err + } + ociSigs[i] = ociSig + + b64sig, err := ociSig.Base64Signature() + if err != nil { + return err + } + b64sigs[i] = b64sig } outputSignature := signOpts.OutputSignature @@ -278,7 +294,7 @@ func signDigest(ctx context.Context, digest name.Digest, payload []byte, ko opti if signOpts.Recursive { outputSignature = fmt.Sprintf("%s-%s", outputSignature, strings.Replace(digest.DigestStr(), ":", "-", 1)) } - if err := os.WriteFile(outputSignature, []byte(b64sig), 0600); err != nil { + if err := os.WriteFile(outputSignature, []byte(strings.Join(b64sigs, "\n")), 0600); err != nil { return fmt.Errorf("create signature file: %w", err) } } @@ -288,7 +304,7 @@ func signDigest(ctx context.Context, digest name.Digest, payload []byte, ko opti if signOpts.Recursive { outputPayload = fmt.Sprintf("%s-%s", outputPayload, strings.Replace(digest.DigestStr(), ":", "-", 1)) } - if err := os.WriteFile(outputPayload, payload, 0600); err != nil { + if err := os.WriteFile(outputPayload, bytes.Join(payloads, []byte("\n")), 0600); err != nil { return fmt.Errorf("create payload file: %w", err) } } @@ -307,16 +323,20 @@ func signDigest(ctx context.Context, digest name.Digest, payload []byte, ko opti } if ko.BundlePath != "" { - signedPayload, err := fetchLocalSignedPayload(ociSig) - if err != nil { - return fmt.Errorf("failed to fetch signed payload: %w", err) - } + var contents [][]byte + for _, ociSig := range ociSigs { + signedPayload, err := fetchLocalSignedPayload(ociSig) + if err != nil { + return fmt.Errorf("failed to fetch signed payload: %w", err) + } - contents, err := json.Marshal(signedPayload) - if err != nil { - return fmt.Errorf("failed to marshal signed payload: %w", err) + content, err := json.Marshal(signedPayload) + if err != nil { + return fmt.Errorf("failed to marshal signed payload: %w", err) + } + contents = append(contents, content) } - if err := os.WriteFile(ko.BundlePath, contents, 0600); err != nil { + if err := os.WriteFile(ko.BundlePath, bytes.Join(contents, []byte("\n")), 0600); err != nil { return fmt.Errorf("create bundle file: %w", err) } ui.Infof(ctx, "Wrote bundle to file %s", ko.BundlePath) @@ -327,9 +347,13 @@ func signDigest(ctx context.Context, digest name.Digest, payload []byte, ko opti } // Attach the signature to the entity. - newSE, err := mutate.AttachSignatureToEntity(se, ociSig, mutate.WithDupeDetector(dd), mutate.WithRecordCreationTimestamp(signOpts.RecordCreationTimestamp)) - if err != nil { - return err + var newSE oci.SignedEntity + for _, ociSig := range ociSigs { + newSE, err = mutate.AttachSignatureToEntity(se, ociSig, mutate.WithDupeDetector(dd), mutate.WithRecordCreationTimestamp(signOpts.RecordCreationTimestamp)) + if err != nil { + return err + } + se = newSE } // Publish the signatures associated with this entity @@ -355,241 +379,6 @@ func signDigest(ctx context.Context, digest name.Digest, payload []byte, ko opti return ociremote.WriteSignatures(digest.Repository, newSE, walkOpts...) } -func signerFromSecurityKey(ctx context.Context, keySlot string) (*SignerVerifier, error) { - sk, err := pivkey.GetKeyWithSlot(keySlot) - if err != nil { - return nil, err - } - sv, err := sk.SignerVerifier() - if err != nil { - sk.Close() - return nil, err - } - - // Handle the -cert flag. - // With PIV, we assume the certificate is in the same slot on the PIV - // token as the private key. If it's not there, show a warning to the - // user. - certFromPIV, err := sk.Certificate() - var pemBytes []byte - if err != nil { - ui.Warnf(ctx, "no x509 certificate retrieved from the PIV token") - } else { - pemBytes, err = cryptoutils.MarshalCertificateToPEM(certFromPIV) - if err != nil { - sk.Close() - return nil, err - } - } - - return &SignerVerifier{ - Cert: pemBytes, - SignerVerifier: sv, - close: sk.Close, - }, nil -} - -func signerFromKeyRef(ctx context.Context, certPath, certChainPath, keyRef string, passFunc cosign.PassFunc) (*SignerVerifier, error) { - k, err := sigs.SignerVerifierFromKeyRef(ctx, keyRef, passFunc) - if err != nil { - return nil, fmt.Errorf("reading key: %w", err) - } - certSigner := &SignerVerifier{ - SignerVerifier: k, - } - - var leafCert *x509.Certificate - - // Attempt to extract certificate from PKCS11 token - // With PKCS11, we assume the certificate is in the same slot on the PKCS11 - // token as the private key. If it's not there, show a warning to the - // user. - if pkcs11Key, ok := k.(*pkcs11key.Key); ok { - certFromPKCS11, _ := pkcs11Key.Certificate() - certSigner.close = pkcs11Key.Close - - if certFromPKCS11 == nil { - ui.Warnf(ctx, "no x509 certificate retrieved from the PKCS11 token") - } else { - pemBytes, err := cryptoutils.MarshalCertificateToPEM(certFromPKCS11) - if err != nil { - pkcs11Key.Close() - return nil, err - } - // Check that the provided public key and certificate key match - pubKey, err := k.PublicKey() - if err != nil { - pkcs11Key.Close() - return nil, err - } - if cryptoutils.EqualKeys(pubKey, certFromPKCS11.PublicKey) != nil { - pkcs11Key.Close() - return nil, errors.New("pkcs11 key and certificate do not match") - } - leafCert = certFromPKCS11 - certSigner.Cert = pemBytes - } - } - - // Handle --cert flag - if certPath != "" { - // Allow both DER and PEM encoding - certBytes, err := os.ReadFile(certPath) - if err != nil { - return nil, fmt.Errorf("read certificate: %w", err) - } - // Handle PEM - if bytes.HasPrefix(certBytes, []byte("-----")) { - decoded, _ := pem.Decode(certBytes) - if decoded.Type != "CERTIFICATE" { - return nil, fmt.Errorf("supplied PEM file is not a certificate: %s", certPath) - } - certBytes = decoded.Bytes - } - parsedCert, err := x509.ParseCertificate(certBytes) - if err != nil { - return nil, fmt.Errorf("parse x509 certificate: %w", err) - } - pk, err := k.PublicKey() - if err != nil { - return nil, fmt.Errorf("get public key: %w", err) - } - if cryptoutils.EqualKeys(pk, parsedCert.PublicKey) != nil { - return nil, errors.New("public key in certificate does not match the provided public key") - } - pemBytes, err := cryptoutils.MarshalCertificateToPEM(parsedCert) - if err != nil { - return nil, fmt.Errorf("marshaling certificate to PEM: %w", err) - } - if certSigner.Cert != nil { - ui.Warnf(ctx, "overriding x509 certificate retrieved from the PKCS11 token") - } - leafCert = parsedCert - certSigner.Cert = pemBytes - } - - if certChainPath == "" { - return certSigner, nil - } else if certSigner.Cert == nil { - return nil, errors.New("no leaf certificate found or provided while specifying chain") - } - - // Handle --cert-chain flag - // Accept only PEM encoded certificate chain - certChainBytes, err := os.ReadFile(certChainPath) - if err != nil { - return nil, fmt.Errorf("reading certificate chain from path: %w", err) - } - certChain, err := cryptoutils.LoadCertificatesFromPEM(bytes.NewReader(certChainBytes)) - if err != nil { - return nil, fmt.Errorf("loading certificate chain: %w", err) - } - if len(certChain) == 0 { - return nil, errors.New("no certificates in certificate chain") - } - // Verify certificate chain is valid - rootPool := x509.NewCertPool() - rootPool.AddCert(certChain[len(certChain)-1]) - subPool := x509.NewCertPool() - for _, c := range certChain[:len(certChain)-1] { - subPool.AddCert(c) - } - if _, err := cosign.TrustedCert(leafCert, rootPool, subPool); err != nil { - return nil, fmt.Errorf("unable to validate certificate chain: %w", err) - } - certSigner.Chain = certChainBytes - - return certSigner, nil -} - -func signerFromNewKey() (*SignerVerifier, error) { - privKey, err := cosign.GeneratePrivateKey() - if err != nil { - return nil, fmt.Errorf("generating cert: %w", err) - } - sv, err := signature.LoadECDSASignerVerifier(privKey, crypto.SHA256) - if err != nil { - return nil, err - } - - return &SignerVerifier{ - SignerVerifier: sv, - }, nil -} - -func keylessSigner(ctx context.Context, ko options.KeyOpts, sv *SignerVerifier) (*SignerVerifier, error) { - var ( - k *fulcio.Signer - err error - ) - - if ko.InsecureSkipFulcioVerify { - if k, err = fulcio.NewSigner(ctx, ko, sv); err != nil { - return nil, fmt.Errorf("getting key from Fulcio: %w", err) - } - } else { - if k, err = fulcioverifier.NewSigner(ctx, ko, sv); err != nil { - return nil, fmt.Errorf("getting key from Fulcio: %w", err) - } - } - - return &SignerVerifier{ - Cert: k.Cert, - Chain: k.Chain, - SignerVerifier: k, - }, nil -} - -func SignerFromKeyOpts(ctx context.Context, certPath string, certChainPath string, ko options.KeyOpts) (*SignerVerifier, error) { - var sv *SignerVerifier - var err error - genKey := false - switch { - case ko.Sk: - sv, err = signerFromSecurityKey(ctx, ko.Slot) - case ko.KeyRef != "": - sv, err = signerFromKeyRef(ctx, certPath, certChainPath, ko.KeyRef, ko.PassFunc) - default: - genKey = true - ui.Infof(ctx, "Generating ephemeral keys...") - sv, err = signerFromNewKey() - } - if err != nil { - return nil, err - } - - if ko.IssueCertificateForExistingKey || genKey { - return keylessSigner(ctx, ko, sv) - } - - return sv, nil -} - -type SignerVerifier struct { - Cert []byte - Chain []byte - signature.SignerVerifier - close func() -} - -func (c *SignerVerifier) Close() { - if c.close != nil { - c.close() - } -} - -func (c *SignerVerifier) Bytes(ctx context.Context) ([]byte, error) { - if c.Cert != nil { - return c.Cert, nil - } - - pemBytes, err := sigs.PublicKeyPem(c, signatureoptions.WithContext(ctx)) - if err != nil { - return nil, err - } - return pemBytes, nil -} - func fetchLocalSignedPayload(sig oci.Signature) (*cosign.LocalSignedPayload, error) { signedPayload := &cosign.LocalSignedPayload{} var err error diff --git a/cmd/cosign/cli/sign/sign_blob.go b/cmd/cosign/cli/sign/sign_blob.go index c01e7952044..9c1527562a1 100644 --- a/cmd/cosign/cli/sign/sign_blob.go +++ b/cmd/cosign/cli/sign/sign_blob.go @@ -17,55 +17,106 @@ package sign import ( "context" + "crypto" "crypto/sha256" "crypto/x509" "encoding/base64" "encoding/json" "fmt" + "io" "os" "path/filepath" "google.golang.org/protobuf/encoding/protojson" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/rekor" - internal "github.com/sigstore/cosign/v2/internal/pkg/cosign" - "github.com/sigstore/cosign/v2/internal/pkg/cosign/tsa" - "github.com/sigstore/cosign/v2/internal/pkg/cosign/tsa/client" - "github.com/sigstore/cosign/v2/internal/ui" - "github.com/sigstore/cosign/v2/pkg/cosign" - cbundle "github.com/sigstore/cosign/v2/pkg/cosign/bundle" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/signcommon" + internal "github.com/sigstore/cosign/v3/internal/pkg/cosign" + "github.com/sigstore/cosign/v3/internal/ui" + "github.com/sigstore/cosign/v3/pkg/cosign" + cbundle "github.com/sigstore/cosign/v3/pkg/cosign/bundle" protobundle "github.com/sigstore/protobuf-specs/gen/pb-go/bundle/v1" protocommon "github.com/sigstore/protobuf-specs/gen/pb-go/common/v1" + rekorclient "github.com/sigstore/rekor/pkg/generated/client" "github.com/sigstore/rekor/pkg/generated/models" + "github.com/sigstore/sigstore-go/pkg/sign" "github.com/sigstore/sigstore/pkg/cryptoutils" + "github.com/sigstore/sigstore/pkg/signature" signatureoptions "github.com/sigstore/sigstore/pkg/signature/options" ) +func getPayload(ctx context.Context, payloadPath string, hashFunction crypto.Hash) (internal.HashReader, func() error, error) { + if payloadPath == "-" { + return internal.NewHashReader(os.Stdin, hashFunction), func() error { return nil }, nil + } + ui.Infof(ctx, "Using payload from: %s", payloadPath) + f, err := os.Open(filepath.Clean(payloadPath)) + if err != nil { + return internal.HashReader{}, nil, err + } + return internal.NewHashReader(f, hashFunction), f.Close, nil +} + // nolint -func SignBlobCmd(ro *options.RootOptions, ko options.KeyOpts, payloadPath string, b64 bool, outputSignature string, outputCertificate string, tlogUpload bool) ([]byte, error) { +func SignBlobCmd(ctx context.Context, ro *options.RootOptions, ko options.KeyOpts, payloadPath, certPath, certChainPath string, b64 bool, outputSignature string, outputCertificate string, tlogUpload bool) ([]byte, error) { var payload internal.HashReader - ctx, cancel := context.WithTimeout(context.Background(), ro.Timeout) + ctx, cancel := context.WithTimeout(ctx, ro.Timeout) defer cancel() - if payloadPath == "-" { - payload = internal.NewHashReader(os.Stdin, sha256.New()) - } else { - ui.Infof(ctx, "Using payload from: %s", payloadPath) - f, err := os.Open(filepath.Clean(payloadPath)) + // TODO - this does not take ko.SigningConfig into account + if !tlogUpload { + // To maintain backwards compatibility with older cosign versions, + // we do not use ed25519ph for ed25519 keys when the signatures are not + // uploaded to the Tlog. + ko.DefaultLoadOptions = &[]signature.LoadOption{} + } + + keypair, sv, certBytes, idToken, err := signcommon.GetKeypairAndToken(ctx, ko, certPath, certChainPath) + if err != nil { + return nil, fmt.Errorf("getting keypair and token: %w", err) + } + + hashFunction := protoHashAlgoToHash(keypair.GetHashAlgorithm()) + payload, closePayload, err := getPayload(ctx, payloadPath, hashFunction) + if err != nil { + return nil, fmt.Errorf("getting payload: %w", err) + } + defer closePayload() + + if ko.SigningConfig != nil { + data, err := io.ReadAll(&payload) if err != nil { - return nil, err + return nil, fmt.Errorf("reading payload: %w", err) + } + content := &sign.PlainData{ + Data: data, } - defer f.Close() - payload = internal.NewHashReader(f, sha256.New()) + bundle, err := cbundle.SignData(ctx, content, keypair, idToken, certBytes, ko.SigningConfig, ko.TrustedMaterial) + if err != nil { + return nil, fmt.Errorf("signing bundle: %w", err) + } + if err := os.WriteFile(ko.BundlePath, bundle, 0600); err != nil { + return nil, fmt.Errorf("create bundle file: %w", err) + } + ui.Infof(ctx, "Wrote bundle to file %s", ko.BundlePath) + return bundle, nil } - sv, err := SignerFromKeyOpts(ctx, "", "", ko) + shouldUpload, err := signcommon.ShouldUploadToTlog(ctx, ko, nil, tlogUpload) if err != nil { - return nil, err + return nil, fmt.Errorf("upload to tlog: %w", err) + } + + if hashFunction != crypto.SHA256 && !ko.NewBundleFormat && (shouldUpload || (!ko.Sk && ko.KeyRef == "")) { + ui.Infof(ctx, "Non SHA256 hash function is not supported for old bundle format. Use --new-bundle-format to use the new bundle format or use different signing key/algorithm.") + if !ko.SkipConfirmation { + if err := ui.ConfirmContinue(ctx); err != nil { + return nil, err + } + } + ui.Infof(ctx, "Continuing with non SHA256 hash function and old bundle format") } - defer sv.Close() sig, err := sv.SignMessage(&payload, signatureoptions.WithContext(ctx)) if err != nil { @@ -74,68 +125,23 @@ func SignBlobCmd(ro *options.RootOptions, ko options.KeyOpts, payloadPath string digest := payload.Sum(nil) signedPayload := cosign.LocalSignedPayload{} - var rekorEntry *models.LogEntryAnon - var rfc3161Timestamp *cbundle.RFC3161Timestamp - var timestampBytes []byte - if ko.TSAServerURL != "" { - if ko.RFC3161TimestampPath == "" && !ko.NewBundleFormat { - return nil, fmt.Errorf("must use protobuf bundle or set timestamp output path") - } - var err error - if ko.TSAClientCACert == "" && ko.TSAClientCert == "" { // no mTLS params or custom CA - timestampBytes, err = tsa.GetTimestampedSignature(sig, client.NewTSAClient(ko.TSAServerURL)) - if err != nil { - return nil, err - } - } else { - timestampBytes, err = tsa.GetTimestampedSignature(sig, client.NewTSAClientMTLS(ko.TSAServerURL, - ko.TSAClientCACert, - ko.TSAClientCert, - ko.TSAClientKey, - ko.TSAServerName, - )) - if err != nil { - return nil, err - } - } - - rfc3161Timestamp = cbundle.TimestampToRFC3161Timestamp(timestampBytes) - // TODO: Consider uploading RFC3161 TS to Rekor - - if rfc3161Timestamp == nil { - return nil, fmt.Errorf("rfc3161 timestamp is nil") - } + timestampBytes, _, err := signcommon.GetRFC3161Timestamp(sig, ko) + if err != nil { + return nil, fmt.Errorf("getting timestamp: %w", err) + } - if ko.RFC3161TimestampPath != "" { - ts, err := json.Marshal(rfc3161Timestamp) - if err != nil { - return nil, err - } - if err := os.WriteFile(ko.RFC3161TimestampPath, ts, 0600); err != nil { - return nil, fmt.Errorf("create RFC3161 timestamp file: %w", err) - } - ui.Infof(ctx, "RFC3161 timestamp written to file %s\n", ko.RFC3161TimestampPath) - } + signer, err := sv.Bytes(ctx) + if err != nil { + return nil, err } - shouldUpload, err := ShouldUploadToTlog(ctx, ko, nil, tlogUpload) + rekorEntry, err := signcommon.UploadToTlog(ctx, ko, nil, shouldUpload, signer, func(r *rekorclient.Rekor, b []byte) (*models.LogEntryAnon, error) { + return cosign.TLogUploadWithCustomHash(ctx, r, sig, &payload, b) + }) if err != nil { - return nil, fmt.Errorf("upload to tlog: %w", err) + return nil, err } - if shouldUpload { - rekorBytes, err := sv.Bytes(ctx) - if err != nil { - return nil, err - } - rekorClient, err := rekor.NewClient(ko.RekorURL) - if err != nil { - return nil, err - } - rekorEntry, err = cosign.TLogUpload(ctx, rekorClient, sig, &payload, rekorBytes) - if err != nil { - return nil, err - } - ui.Infof(ctx, "tlog entry created with index: %d", *rekorEntry.LogIndex) + if rekorEntry != nil { signedPayload.Bundle = cbundle.EntryToBundle(rekorEntry) } @@ -147,10 +153,6 @@ func SignBlobCmd(ro *options.RootOptions, ko options.KeyOpts, payloadPath string var hint string var rawCert []byte - signer, err := sv.Bytes(ctx) - if err != nil { - return nil, fmt.Errorf("error getting signer: %w", err) - } cert, err := cryptoutils.UnmarshalCertificatesFromPEM(signer) if err != nil || len(cert) == 0 { pubKey, err := sv.PublicKey() @@ -175,7 +177,7 @@ func SignBlobCmd(ro *options.RootOptions, ko options.KeyOpts, payloadPath string bundle.Content = &protobundle.Bundle_MessageSignature{ MessageSignature: &protocommon.MessageSignature{ MessageDigest: &protocommon.HashOutput{ - Algorithm: protocommon.HashAlgorithm_SHA2_256, + Algorithm: hashFuncToProtoBundle(payload.HashFunc()), Digest: digest, }, Signature: sig, @@ -247,7 +249,7 @@ func SignBlobCmd(ro *options.RootOptions, ko options.KeyOpts, payloadPath string } // Extract an encoded certificate from the SignerVerifier. Returns (nil, nil) if verifier is not a certificate. -func extractCertificate(ctx context.Context, sv *SignerVerifier) ([]byte, error) { +func extractCertificate(ctx context.Context, sv *signcommon.SignerVerifier) ([]byte, error) { signer, err := sv.Bytes(ctx) if err != nil { return nil, fmt.Errorf("error getting signer: %w", err) @@ -259,3 +261,29 @@ func extractCertificate(ctx context.Context, sv *SignerVerifier) ([]byte, error) } return nil, nil } + +func hashFuncToProtoBundle(hashFunc crypto.Hash) protocommon.HashAlgorithm { + switch hashFunc { + case crypto.SHA256: + return protocommon.HashAlgorithm_SHA2_256 + case crypto.SHA384: + return protocommon.HashAlgorithm_SHA2_384 + case crypto.SHA512: + return protocommon.HashAlgorithm_SHA2_512 + default: + return protocommon.HashAlgorithm_HASH_ALGORITHM_UNSPECIFIED + } +} + +func protoHashAlgoToHash(hashFunc protocommon.HashAlgorithm) crypto.Hash { + switch hashFunc { + case protocommon.HashAlgorithm_SHA2_256: + return crypto.SHA256 + case protocommon.HashAlgorithm_SHA2_384: + return crypto.SHA384 + case protocommon.HashAlgorithm_SHA2_512: + return crypto.SHA512 + default: + return crypto.Hash(0) + } +} diff --git a/cmd/cosign/cli/sign/sign_blob_test.go b/cmd/cosign/cli/sign/sign_blob_test.go index 2f0853589a4..6e9e7c1d82f 100644 --- a/cmd/cosign/cli/sign/sign_blob_test.go +++ b/cmd/cosign/cli/sign/sign_blob_test.go @@ -15,12 +15,16 @@ package sign import ( + "crypto/x509" + "encoding/pem" "os" "path/filepath" "testing" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/pkg/cosign" + "github.com/secure-systems-lab/go-securesystemslib/encrypted" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/internal/test" + "github.com/sigstore/cosign/v3/pkg/cosign" ) func TestSignBlobCmd(t *testing.T) { @@ -37,7 +41,7 @@ func TestSignBlobCmd(t *testing.T) { keyOpts := options.KeyOpts{KeyRef: keyRef, BundlePath: bundlePath} // Test happy path - _, err := SignBlobCmd(rootOpts, keyOpts, blobPath, true, "", "", false) + _, err := SignBlobCmd(t.Context(), rootOpts, keyOpts, blobPath, "", "", true, "", "", false) if err != nil { t.Fatalf("unexpected error %v", err) } @@ -46,7 +50,32 @@ func TestSignBlobCmd(t *testing.T) { keyOpts.NewBundleFormat = true sigPath := filepath.Join(td, "output.sig") certPath := filepath.Join(td, "output.pem") - _, err = SignBlobCmd(rootOpts, keyOpts, blobPath, false, sigPath, certPath, false) + _, err = SignBlobCmd(t.Context(), rootOpts, keyOpts, blobPath, "", "", false, sigPath, certPath, false) + if err != nil { + t.Fatalf("unexpected error %v", err) + } + + // Test signing with a certificate + rootCert, rootKey, _ := test.GenerateRootCa() + cert, certPrivKey, _ := test.GenerateLeafCert("subject", "oidc-issuer", rootCert, rootKey) + certPemBytes := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw}) + signCertPath := writeFile(t, td, string(certPemBytes), "cert.pem") + x509Encoded, err := x509.MarshalPKCS8PrivateKey(certPrivKey) + if err != nil { + t.Fatalf("unexpected error %v", err) + } + encBytes, err := encrypted.Encrypt(x509Encoded, nil) + if err != nil { + t.Fatalf("unexpected error %v", err) + } + pemBytes := pem.EncodeToMemory(&pem.Block{ + Bytes: encBytes, + Type: cosign.SigstorePrivateKeyPemType, + }) + certPrivKeyRef := writeFile(t, td, string(pemBytes), "certkey.pem") + keyOpts.KeyRef = certPrivKeyRef + + _, err = SignBlobCmd(t.Context(), rootOpts, keyOpts, blobPath, signCertPath, "", false, "", "", false) if err != nil { t.Fatalf("unexpected error %v", err) } @@ -55,7 +84,7 @@ func TestSignBlobCmd(t *testing.T) { func writeFile(t *testing.T, td string, blob string, name string) string { // Write blob to disk blobPath := filepath.Join(td, name) - if err := os.WriteFile(blobPath, []byte(blob), 0644); err != nil { + if err := os.WriteFile(blobPath, []byte(blob), 0o644); err != nil { t.Fatal(err) } return blobPath diff --git a/cmd/cosign/cli/sign/sign_test.go b/cmd/cosign/cli/sign/sign_test.go index 0d9de73f790..4fca2565f90 100644 --- a/cmd/cosign/cli/sign/sign_test.go +++ b/cmd/cosign/cli/sign/sign_test.go @@ -16,98 +16,13 @@ package sign import ( - "context" - "crypto/ecdsa" - "crypto/x509" - "encoding/pem" "errors" - "os" - "reflect" - "strings" "testing" - "github.com/stretchr/testify/assert" - - "github.com/secure-systems-lab/go-securesystemslib/encrypted" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/generate" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/internal/ui" - "github.com/sigstore/cosign/v2/pkg/cosign" - "github.com/sigstore/cosign/v2/test" - "github.com/sigstore/sigstore/pkg/cryptoutils" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/generate" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" ) -func pass(s string) cosign.PassFunc { - return func(_ bool) ([]byte, error) { - return []byte(s), nil - } -} - -func generateCertificateFiles(t *testing.T, tmpDir string, pf cosign.PassFunc) (privFile, certFile, chainFile string, privKey *ecdsa.PrivateKey, cert *x509.Certificate, chain []*x509.Certificate) { - t.Helper() - - rootCert, rootKey, _ := test.GenerateRootCa() - subCert, subKey, _ := test.GenerateSubordinateCa(rootCert, rootKey) - leafCert, privKey, _ := test.GenerateLeafCert("subject", "oidc-issuer", subCert, subKey) - pemRoot := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: rootCert.Raw}) - pemSub := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: subCert.Raw}) - pemLeaf := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: leafCert.Raw}) - - x509Encoded, err := x509.MarshalPKCS8PrivateKey(privKey) - if err != nil { - t.Fatalf("failed to encode private key: %v", err) - } - password := []byte{} - if pf != nil { - password, err = pf(true) - if err != nil { - t.Fatalf("failed to read password: %v", err) - } - } - - encBytes, err := encrypted.Encrypt(x509Encoded, password) - if err != nil { - t.Fatalf("failed to encrypt key: %v", err) - } - - // store in PEM format - privBytes := pem.EncodeToMemory(&pem.Block{ - Bytes: encBytes, - Type: cosign.CosignPrivateKeyPemType, - }) - - tmpPrivFile, err := os.CreateTemp(tmpDir, "cosign_test_*.key") - if err != nil { - t.Fatalf("failed to create temp key file: %v", err) - } - defer tmpPrivFile.Close() - if _, err := tmpPrivFile.Write(privBytes); err != nil { - t.Fatalf("failed to write key file: %v", err) - } - - tmpCertFile, err := os.CreateTemp(tmpDir, "cosign.crt") - if err != nil { - t.Fatalf("failed to create temp certificate file: %v", err) - } - defer tmpCertFile.Close() - if _, err := tmpCertFile.Write(pemLeaf); err != nil { - t.Fatalf("failed to write certificate file: %v", err) - } - - tmpChainFile, err := os.CreateTemp(tmpDir, "cosign_chain.crt") - if err != nil { - t.Fatalf("failed to create temp chain file: %v", err) - } - defer tmpChainFile.Close() - pemChain := pemSub - pemChain = append(pemChain, pemRoot...) - if _, err := tmpChainFile.Write(pemChain); err != nil { - t.Fatalf("failed to write chain file: %v", err) - } - - return tmpPrivFile.Name(), tmpCertFile.Name(), tmpChainFile.Name(), privKey, leafCert, []*x509.Certificate{subCert, rootCert} -} - // TestSignCmdLocalKeyAndSk verifies the SignCmd returns an error // if both a local key path and a sk are specified func TestSignCmdLocalKeyAndSk(t *testing.T) { @@ -122,110 +37,9 @@ func TestSignCmdLocalKeyAndSk(t *testing.T) { }, } { so := options.SignOptions{} - err := SignCmd(ro, ko, so, nil) + err := SignCmd(t.Context(), ro, ko, so, nil) if (errors.Is(err, &options.KeyParseError{}) == false) { t.Fatal("expected KeyParseError") } } } - -func Test_signerFromKeyRefSuccess(t *testing.T) { - tmpDir := t.TempDir() - ctx := context.Background() - keyFile, certFile, chainFile, privKey, cert, chain := generateCertificateFiles(t, tmpDir, pass("foo")) - - signer, err := signerFromKeyRef(ctx, certFile, chainFile, keyFile, pass("foo")) - if err != nil { - t.Fatalf("unexpected error generating signer: %v", err) - } - // Expect public key matches - pubKey, err := signer.PublicKey() - if err != nil { - t.Fatalf("unexpected error fetching pubkey: %v", err) - } - if !privKey.Public().(*ecdsa.PublicKey).Equal(pubKey) { - t.Fatalf("public keys must be equal") - } - // Expect certificate matches - expectedPemBytes, err := cryptoutils.MarshalCertificateToPEM(cert) - if err != nil { - t.Fatalf("unexpected error marshalling certificate: %v", err) - } - if !reflect.DeepEqual(signer.Cert, expectedPemBytes) { - t.Fatalf("certificates must match") - } - // Expect certificate chain matches - expectedPemBytesChain, err := cryptoutils.MarshalCertificatesToPEM(chain) - if err != nil { - t.Fatalf("unexpected error marshalling certificate chain: %v", err) - } - if !reflect.DeepEqual(signer.Chain, expectedPemBytesChain) { - t.Fatalf("certificate chains must match") - } -} - -func Test_signerFromKeyRefFailure(t *testing.T) { - tmpDir := t.TempDir() - ctx := context.Background() - keyFile, certFile, _, _, _, _ := generateCertificateFiles(t, tmpDir, pass("foo")) - // Second set of files - tmpDir2 := t.TempDir() - _, certFile2, chainFile2, _, _, _ := generateCertificateFiles(t, tmpDir2, pass("bar")) - - // Public keys don't match - _, err := signerFromKeyRef(ctx, certFile2, chainFile2, keyFile, pass("foo")) - if err == nil || err.Error() != "public key in certificate does not match the provided public key" { - t.Fatalf("expected mismatched keys error, got %v", err) - } - // Certificate chain cannot be verified - _, err = signerFromKeyRef(ctx, certFile, chainFile2, keyFile, pass("foo")) - if err == nil || !strings.Contains(err.Error(), "unable to validate certificate chain") { - t.Fatalf("expected chain verification error, got %v", err) - } - // Certificate chain specified without certificate - _, err = signerFromKeyRef(ctx, "", chainFile2, keyFile, pass("foo")) - if err == nil || !strings.Contains(err.Error(), "no leaf certificate found or provided while specifying chain") { - t.Fatalf("expected no leaf error, got %v", err) - } -} - -func Test_signerFromKeyRefFailureEmptyChainFile(t *testing.T) { - tmpDir := t.TempDir() - ctx := context.Background() - keyFile, certFile, _, _, _, _ := generateCertificateFiles(t, tmpDir, pass("foo")) - - tmpChainFile, err := os.CreateTemp(tmpDir, "cosign_chain_empty.crt") - if err != nil { - t.Fatalf("failed to create temp chain file: %v", err) - } - defer tmpChainFile.Close() - if _, err := tmpChainFile.Write([]byte{}); err != nil { - t.Fatalf("failed to write chain file: %v", err) - } - - _, err = signerFromKeyRef(ctx, certFile, tmpChainFile.Name(), keyFile, pass("foo")) - if err == nil || err.Error() != "no certificates in certificate chain" { - t.Fatalf("expected empty chain error, got %v", err) - } -} - -func Test_ParseOCIReference(t *testing.T) { - var tests = []struct { - ref string - expectedWarning string - }{ - {"image:bytag", "WARNING: Image reference image:bytag uses a tag, not a digest"}, - {"image:bytag@sha256:abcdef", ""}, - {"image:@sha256:abcdef", ""}, - } - for _, tt := range tests { - stderr := ui.RunWithTestCtx(func(ctx context.Context, _ ui.WriteFunc) { - ParseOCIReference(ctx, tt.ref) - }) - if len(tt.expectedWarning) > 0 { - assert.Contains(t, stderr, tt.expectedWarning, stderr, "bad warning message") - } else { - assert.Empty(t, stderr, "expected no warning") - } - } -} diff --git a/cmd/cosign/cli/signblob.go b/cmd/cosign/cli/signblob.go index 8909b9f90ac..71e66654f42 100644 --- a/cmd/cosign/cli/signblob.go +++ b/cmd/cosign/cli/signblob.go @@ -16,16 +16,15 @@ package cli import ( - "context" "fmt" "os" + "strings" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/generate" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/sign" - "github.com/sigstore/cosign/v2/internal/ui" - "github.com/sigstore/cosign/v2/pkg/cosign" - "github.com/sigstore/cosign/v2/pkg/cosign/env" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/generate" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/sign" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/signcommon" + "github.com/sigstore/cosign/v3/pkg/cosign" "github.com/spf13/cobra" "github.com/spf13/viper" ) @@ -65,9 +64,24 @@ func SignBlob() *cobra.Command { if options.NOf(o.Key, o.SecurityKey.Use) > 1 { return &options.KeyParseError{} } + + // Check if the algorithm is in the list of supported algorithms + supportedAlgorithms := cosign.GetSupportedAlgorithms() + isValid := false + for _, algo := range supportedAlgorithms { + if algo == o.SigningAlgorithm { + isValid = true + break + } + } + if !isValid { + return fmt.Errorf("invalid signing algorithm: %s. Supported algorithms are: %s", + o.SigningAlgorithm, strings.Join(supportedAlgorithms, ", ")) + } + return nil }, - RunE: func(_ *cobra.Command, args []string) error { + RunE: func(cmd *cobra.Command, args []string) error { oidcClientSecret, err := o.OIDC.ClientSecret() if err != nil { return err @@ -98,13 +112,13 @@ func SignBlob() *cobra.Command { TSAServerURL: o.TSAServerURL, RFC3161TimestampPath: o.RFC3161TimestampPath, IssueCertificateForExistingKey: o.IssueCertificate, + SigningAlgorithm: o.SigningAlgorithm, } - if (o.Key == "" || o.IssueCertificate) && env.Getenv(env.VariableSigstoreCTLogPublicKeyFile) == "" { - trustedMaterial, err := cosign.TrustedRoot() - if err != nil { - ui.Warnf(context.Background(), "Could not fetch trusted_root.json from the TUF repository. Continuing with individual targets. Error from TUF: %v", err) - } - ko.TrustedMaterial = trustedMaterial + if err := signcommon.LoadTrustedMaterialAndSigningConfig(cmd.Context(), &ko, o.UseSigningConfig, o.SigningConfigPath, + o.Rekor.URL, o.Fulcio.URL, o.OIDC.Issuer, o.TSAServerURL, o.TrustedRootPath, o.TlogUpload, + o.NewBundleFormat, o.BundlePath, o.Key, o.IssueCertificate, + o.Output, "", o.OutputCertificate, "", o.OutputSignature); err != nil { + return err } for _, blob := range args { @@ -114,7 +128,7 @@ func SignBlob() *cobra.Command { o.OutputSignature = o.Output } - if _, err := sign.SignBlobCmd(ro, ko, blob, o.Base64Output, o.OutputSignature, o.OutputCertificate, o.TlogUpload); err != nil { + if _, err := sign.SignBlobCmd(cmd.Context(), ro, ko, blob, o.Cert, o.CertChain, o.Base64Output, o.OutputSignature, o.OutputCertificate, o.TlogUpload); err != nil { return fmt.Errorf("signing %s: %w", blob, err) } } diff --git a/cmd/cosign/cli/signcommon/common.go b/cmd/cosign/cli/signcommon/common.go new file mode 100644 index 00000000000..aa238c283a4 --- /dev/null +++ b/cmd/cosign/cli/signcommon/common.go @@ -0,0 +1,695 @@ +// Copyright 2025 The Sigstore 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 signcommon + +import ( + "bytes" + "context" + "crypto/x509" + "encoding/json" + "encoding/pem" + "errors" + "fmt" + "os" + + "github.com/google/go-containerregistry/pkg/name" + "github.com/google/go-containerregistry/pkg/v1/remote" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/fulcio" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/fulcio/fulcioverifier" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/rekor" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/sign/privacy" + "github.com/sigstore/cosign/v3/internal/auth" + "github.com/sigstore/cosign/v3/internal/key" + "github.com/sigstore/cosign/v3/internal/pkg/cosign/tsa" + "github.com/sigstore/cosign/v3/internal/pkg/cosign/tsa/client" + "github.com/sigstore/cosign/v3/internal/ui" + "github.com/sigstore/cosign/v3/pkg/cosign" + cbundle "github.com/sigstore/cosign/v3/pkg/cosign/bundle" + "github.com/sigstore/cosign/v3/pkg/cosign/env" + "github.com/sigstore/cosign/v3/pkg/cosign/pivkey" + "github.com/sigstore/cosign/v3/pkg/cosign/pkcs11key" + ociremote "github.com/sigstore/cosign/v3/pkg/oci/remote" + sigs "github.com/sigstore/cosign/v3/pkg/signature" + "github.com/sigstore/cosign/v3/pkg/types" + pb_go_v1 "github.com/sigstore/protobuf-specs/gen/pb-go/common/v1" + rekorclient "github.com/sigstore/rekor/pkg/generated/client" + "github.com/sigstore/rekor/pkg/generated/models" + "github.com/sigstore/sigstore-go/pkg/root" + "github.com/sigstore/sigstore-go/pkg/sign" + "github.com/sigstore/sigstore/pkg/cryptoutils" + "github.com/sigstore/sigstore/pkg/signature" + "github.com/sigstore/sigstore/pkg/signature/dsse" + signatureoptions "github.com/sigstore/sigstore/pkg/signature/options" +) + +// SignerVerifier contains keys or certs to sign and verify. +type SignerVerifier struct { + Cert []byte + Chain []byte + signature.SignerVerifier + close func() +} + +// Close closes the key context if there is one. +func (c *SignerVerifier) Close() { + if c.close != nil { + c.close() + } +} + +// Bytes returns the raw bytes of the cert or key. +func (c *SignerVerifier) Bytes(ctx context.Context) ([]byte, error) { + if c.Cert != nil { + return c.Cert, nil + } + + pemBytes, err := sigs.PublicKeyPem(c, signatureoptions.WithContext(ctx)) + if err != nil { + return nil, err + } + return pemBytes, nil +} + +// GetKeypairAndToken creates a keypair object from provided key or cert flags or generates an ephemeral key. +// For an ephemeral key, it also uses the key to fetch an OIDC token, the pair of which are later used to get a Fulcio cert. +func GetKeypairAndToken(ctx context.Context, ko options.KeyOpts, cert, certChain string) (sign.Keypair, *SignerVerifier, []byte, string, error) { + var keypair sign.Keypair + var ephemeralKeypair bool + var idToken string + var sv *SignerVerifier + var certBytes []byte + var err error + + sv, ephemeralKeypair, err = signerFromKeyOpts(ctx, cert, certChain, ko) + if err != nil { + return nil, nil, nil, "", fmt.Errorf("getting signer: %w", err) + } + keypair, err = key.NewSignerVerifierKeypair(sv, ko.DefaultLoadOptions) + if err != nil { + return nil, nil, nil, "", fmt.Errorf("creating signerverifier keypair: %w", err) + } + certBytes = sv.Cert + defer func() { + if sv != nil { + sv.Close() + } + }() + + if ephemeralKeypair || ko.IssueCertificateForExistingKey { + if ko.SigningConfig == nil { + sv, err = keylessSigner(ctx, ko, sv) + } else { + idToken, err = auth.RetrieveIDToken(ctx, auth.IDTokenConfig{ + TokenOrPath: ko.IDToken, + DisableProviders: ko.OIDCDisableProviders, + Provider: ko.OIDCProvider, + AuthFlow: ko.FulcioAuthFlow, + SkipConfirm: ko.SkipConfirmation, + OIDCServices: ko.SigningConfig.OIDCProviderURLs(), + ClientID: ko.OIDCClientID, + ClientSecret: ko.OIDCClientSecret, + RedirectURL: ko.OIDCRedirectURL, + }) + } + if err != nil { + return nil, nil, nil, "", fmt.Errorf("retrieving ID token: %w", err) + } + } + + return keypair, sv, certBytes, idToken, nil +} + +func keylessSigner(ctx context.Context, ko options.KeyOpts, sv *SignerVerifier) (*SignerVerifier, error) { + var ( + k *fulcio.Signer + err error + ) + + if _, ok := sv.SignerVerifier.(*signature.ED25519phSignerVerifier); ok { + return nil, fmt.Errorf("ed25519ph unsupported by Fulcio") + } + + if ko.InsecureSkipFulcioVerify { + if k, err = fulcio.NewSigner(ctx, ko, sv); err != nil { + return nil, fmt.Errorf("getting key from Fulcio: %w", err) + } + } else { + if k, err = fulcioverifier.NewSigner(ctx, ko, sv); err != nil { + return nil, fmt.Errorf("getting key from Fulcio: %w", err) + } + } + + return &SignerVerifier{ + Cert: k.Cert, + Chain: k.Chain, + SignerVerifier: k, + }, nil +} + +// ShouldUploadToTlog determines whether the user wants to upload the entry to Rekor. +func ShouldUploadToTlog(ctx context.Context, ko options.KeyOpts, ref name.Reference, tlogUpload bool) (bool, error) { + upload := shouldUploadToTlog(ctx, ko, ref, tlogUpload) + var statementErr error + if upload { + privacy.StatementOnce.Do(func() { + ui.Infof(ctx, privacy.Statement) + ui.Infof(ctx, privacy.StatementConfirmation) + if !ko.SkipConfirmation { + if err := ui.ConfirmContinue(ctx); err != nil { + statementErr = err + } + } + }) + } + return upload, statementErr +} + +func shouldUploadToTlog(ctx context.Context, ko options.KeyOpts, ref name.Reference, tlogUpload bool) bool { + // return false if not uploading to the tlog has been requested + if !tlogUpload { + return false + } + + if ko.SkipConfirmation { + return true + } + + // We don't need to validate the ref, just return true + if ref == nil { + return true + } + + // Check if the image is public (no auth in Get) + if _, err := remote.Get(ref, remote.WithContext(ctx)); err != nil { + ui.Warnf(ctx, "%q appears to be a private repository, please confirm uploading to the transparency log at %q", ref.Context().String(), ko.RekorURL) + if ui.ConfirmContinue(ctx) != nil { + ui.Infof(ctx, "not uploading to transparency log") + return false + } + } + return true +} + +// GetSignerVerifier generates a SignerVerifier from provided key flags. +func GetSignerVerifier(ctx context.Context, cert, certChain string, ko options.KeyOpts) (*SignerVerifier, func(), error) { + sv, genKey, err := signerFromKeyOpts(ctx, cert, certChain, ko) + if err != nil { + return nil, nil, fmt.Errorf("getting signer from opts: %w", err) + } + if genKey || ko.IssueCertificateForExistingKey { + sv, err = keylessSigner(ctx, ko, sv) + if err != nil { + return nil, nil, fmt.Errorf("getting Fulcio signer: %w", err) + } + } + return sv, sv.Close, nil +} + +func signerFromKeyOpts(ctx context.Context, certPath string, certChainPath string, ko options.KeyOpts) (*SignerVerifier, bool, error) { + var sv *SignerVerifier + var err error + genKey := false + switch { + case ko.Sk: + sv, err = signerFromSecurityKey(ctx, ko.Slot) + case ko.KeyRef != "": + sv, err = signerFromKeyRef(ctx, certPath, certChainPath, ko.KeyRef, ko.PassFunc, ko.DefaultLoadOptions) + default: + genKey = true + ui.Infof(ctx, "Generating ephemeral keys...") + sv, err = signerFromNewKey(ko.SigningAlgorithm, ko.DefaultLoadOptions) + } + if err != nil { + return nil, false, err + } + return sv, genKey, nil +} + +func signerFromSecurityKey(ctx context.Context, keySlot string) (*SignerVerifier, error) { + sk, err := pivkey.GetKeyWithSlot(keySlot) + if err != nil { + return nil, err + } + sv, err := sk.SignerVerifier() + if err != nil { + sk.Close() + return nil, err + } + + // Handle the -cert flag. + // With PIV, we assume the certificate is in the same slot on the PIV + // token as the private key. If it's not there, show a warning to the + // user. + certFromPIV, err := sk.Certificate() + var pemBytes []byte + if err != nil { + ui.Warnf(ctx, "no x509 certificate retrieved from the PIV token") + } else { + pemBytes, err = cryptoutils.MarshalCertificateToPEM(certFromPIV) + if err != nil { + sk.Close() + return nil, err + } + } + + return &SignerVerifier{ + Cert: pemBytes, + SignerVerifier: sv, + close: sk.Close, + }, nil +} + +func signerFromKeyRef(ctx context.Context, certPath, certChainPath, keyRef string, passFunc cosign.PassFunc, defaultLoadOptions *[]signature.LoadOption) (*SignerVerifier, error) { + k, err := sigs.SignerVerifierFromKeyRef(ctx, keyRef, passFunc, defaultLoadOptions) + if err != nil { + return nil, fmt.Errorf("reading key: %w", err) + } + certSigner := &SignerVerifier{ + SignerVerifier: k, + } + + var leafCert *x509.Certificate + + // Attempt to extract certificate from PKCS11 token + // With PKCS11, we assume the certificate is in the same slot on the PKCS11 + // token as the private key. If it's not there, show a warning to the + // user. + if pkcs11Key, ok := k.(*pkcs11key.Key); ok { + certFromPKCS11, _ := pkcs11Key.Certificate() + certSigner.close = pkcs11Key.Close + + if certFromPKCS11 == nil { + ui.Warnf(ctx, "no x509 certificate retrieved from the PKCS11 token") + } else { + pemBytes, err := cryptoutils.MarshalCertificateToPEM(certFromPKCS11) + if err != nil { + pkcs11Key.Close() + return nil, err + } + // Check that the provided public key and certificate key match + pubKey, err := k.PublicKey() + if err != nil { + pkcs11Key.Close() + return nil, err + } + if cryptoutils.EqualKeys(pubKey, certFromPKCS11.PublicKey) != nil { + pkcs11Key.Close() + return nil, errors.New("pkcs11 key and certificate do not match") + } + leafCert = certFromPKCS11 + certSigner.Cert = pemBytes + } + } + + // Handle --cert flag + if certPath != "" { + // Allow both DER and PEM encoding + certBytes, err := os.ReadFile(certPath) + if err != nil { + return nil, fmt.Errorf("read certificate: %w", err) + } + // Handle PEM + if bytes.HasPrefix(certBytes, []byte("-----")) { + decoded, _ := pem.Decode(certBytes) + if decoded.Type != "CERTIFICATE" { + return nil, fmt.Errorf("supplied PEM file is not a certificate: %s", certPath) + } + certBytes = decoded.Bytes + } + parsedCert, err := x509.ParseCertificate(certBytes) + if err != nil { + return nil, fmt.Errorf("parse x509 certificate: %w", err) + } + pk, err := k.PublicKey() + if err != nil { + return nil, fmt.Errorf("get public key: %w", err) + } + if cryptoutils.EqualKeys(pk, parsedCert.PublicKey) != nil { + return nil, errors.New("public key in certificate does not match the provided public key") + } + pemBytes, err := cryptoutils.MarshalCertificateToPEM(parsedCert) + if err != nil { + return nil, fmt.Errorf("marshaling certificate to PEM: %w", err) + } + if certSigner.Cert != nil { + ui.Warnf(ctx, "overriding x509 certificate retrieved from the PKCS11 token") + } + leafCert = parsedCert + certSigner.Cert = pemBytes + } + + if certChainPath == "" { + return certSigner, nil + } else if certSigner.Cert == nil { + return nil, errors.New("no leaf certificate found or provided while specifying chain") + } + + // Handle --cert-chain flag + // Accept only PEM encoded certificate chain + certChainBytes, err := os.ReadFile(certChainPath) + if err != nil { + return nil, fmt.Errorf("reading certificate chain from path: %w", err) + } + certChain, err := cryptoutils.LoadCertificatesFromPEM(bytes.NewReader(certChainBytes)) + if err != nil { + return nil, fmt.Errorf("loading certificate chain: %w", err) + } + if len(certChain) == 0 { + return nil, errors.New("no certificates in certificate chain") + } + // Verify certificate chain is valid + rootPool := x509.NewCertPool() + rootPool.AddCert(certChain[len(certChain)-1]) + subPool := x509.NewCertPool() + for _, c := range certChain[:len(certChain)-1] { + subPool.AddCert(c) + } + if _, err := cosign.TrustedCert(leafCert, rootPool, subPool); err != nil { + return nil, fmt.Errorf("unable to validate certificate chain: %w", err) + } + certSigner.Chain = certChainBytes + + return certSigner, nil +} + +func signerFromNewKey(signingAlgorithm string, defaultLoadOptions *[]signature.LoadOption) (*SignerVerifier, error) { + keyDetails, err := ParseSignatureAlgorithmFlag(signingAlgorithm) + if err != nil { + return nil, fmt.Errorf("parsing signature algorithm: %w", err) + } + algo, err := signature.GetAlgorithmDetails(keyDetails) + if err != nil { + return nil, fmt.Errorf("getting algorithm details: %w", err) + } + + privKey, err := cosign.GeneratePrivateKeyWithAlgorithm(&algo) + if err != nil { + return nil, fmt.Errorf("generating cert: %w", err) + } + + defaultLoadOptions = cosign.GetDefaultLoadOptions(defaultLoadOptions) + sv, err := signature.LoadSignerVerifierFromAlgorithmDetails(privKey, algo, *defaultLoadOptions...) + if err != nil { + return nil, err + } + + return &SignerVerifier{ + SignerVerifier: sv, + }, nil +} + +// GetRFC3161Timestamp fetches an RFC3161 timestamp as raw bytes and as a RFC3161Timestamp object. +// It either returns both objects to be assembled into a bundle by the calling function, +// or writes the formatted timestamp to the provided file path if not using the new bundle format. +func GetRFC3161Timestamp(payload []byte, ko options.KeyOpts) ([]byte, *cbundle.RFC3161Timestamp, error) { + if ko.TSAServerURL == "" { + return nil, nil, nil + } + if ko.RFC3161TimestampPath == "" && !ko.NewBundleFormat { + return nil, nil, fmt.Errorf("expected either new bundle or an rfc3161-timestamp path when using a TSA server") + } + tc := client.NewTSAClient(ko.TSAServerURL) + if ko.TSAClientCert != "" { + tc = client.NewTSAClientMTLS( + ko.TSAServerURL, + ko.TSAClientCACert, + ko.TSAClientCert, + ko.TSAClientKey, + ko.TSAServerName, + ) + } + timestampBytes, err := tsa.GetTimestampedSignature(payload, tc) + if err != nil { + return nil, nil, fmt.Errorf("getting timestamped signature: %w", err) + } + rfc3161Timestamp := cbundle.TimestampToRFC3161Timestamp(timestampBytes) + if rfc3161Timestamp == nil { + return nil, nil, fmt.Errorf("rfc3161 timestamp is nil") + } + if ko.NewBundleFormat || ko.RFC3161TimestampPath == "" { + return timestampBytes, rfc3161Timestamp, nil + } + ts, err := json.Marshal(rfc3161Timestamp) + if err != nil { + return nil, nil, fmt.Errorf("marshalling timestamp: %w", err) + } + if err := os.WriteFile(ko.RFC3161TimestampPath, ts, 0600); err != nil { + return nil, nil, fmt.Errorf("creating RFC3161 timestamp file: %w", err) + } + fmt.Fprintln(os.Stderr, "RFC3161 timestamp written to file ", ko.RFC3161TimestampPath) + return timestampBytes, rfc3161Timestamp, nil +} + +type tlogUploadFn func(*rekorclient.Rekor, []byte) (*models.LogEntryAnon, error) + +// UploadToTlog uploads an entry to rekor v1 and returns the response from rekor. +func UploadToTlog(ctx context.Context, ko options.KeyOpts, ref name.Reference, tlogUpload bool, rekorBytes []byte, upload tlogUploadFn) (*models.LogEntryAnon, error) { + shouldUpload, err := ShouldUploadToTlog(ctx, ko, ref, tlogUpload) + if err != nil { + return nil, fmt.Errorf("checking upload to tlog: %w", err) + } + if !shouldUpload { + return nil, nil + } + rekorClient, err := rekor.NewClient(ko.RekorURL) + if err != nil { + return nil, fmt.Errorf("creating rekor client: %w", err) + } + entry, err := upload(rekorClient, rekorBytes) + if err != nil { + return nil, fmt.Errorf("uploading to rekor: %w", err) + } + fmt.Fprintln(os.Stderr, "tlog entry created with index:", *entry.LogIndex) + return entry, nil +} + +type CommonBundleOpts struct { + Payload []byte + Digest name.Digest + PredicateType string + BundlePath string + Upload bool + OCIRemoteOpts []ociremote.Option +} + +// WriteBundle compiles a protobuf bundle from components and writes the bundle to the OCI remote layer. +func WriteBundle(ctx context.Context, sv *SignerVerifier, rekorEntry *models.LogEntryAnon, bundleOpts CommonBundleOpts, signedPayload, signerBytes, timestampBytes []byte) error { + pubKey, err := sv.PublicKey() + if err != nil { + return err + } + bundleBytes, err := cbundle.MakeNewBundle(pubKey, rekorEntry, bundleOpts.Payload, signedPayload, signerBytes, timestampBytes) + if err != nil { + return err + } + if bundleOpts.BundlePath != "" { + if err := os.WriteFile(bundleOpts.BundlePath, bundleBytes, 0600); err != nil { + return fmt.Errorf("creating bundle file: %w", err) + } + ui.Infof(ctx, "Wrote bundle to file %s", bundleOpts.BundlePath) + } + if !bundleOpts.Upload { + return nil + } + return ociremote.WriteAttestationNewBundleFormat(bundleOpts.Digest, bundleBytes, bundleOpts.PredicateType, bundleOpts.OCIRemoteOpts...) +} + +// WriteNewBundleWithSigningConfig uses signing config and trusted root to fetch responses from services for the bundle and writes the bundle to the OCI remote layer. +func WriteNewBundleWithSigningConfig(ctx context.Context, ko options.KeyOpts, cert, certChain string, bundleOpts CommonBundleOpts, signingConfig *root.SigningConfig, trustedMaterial root.TrustedMaterial) error { + keypair, _, certBytes, idToken, err := GetKeypairAndToken(ctx, ko, cert, certChain) + if err != nil { + return fmt.Errorf("getting keypair and token: %w", err) + } + + content := &sign.DSSEData{ + Data: bundleOpts.Payload, + PayloadType: "application/vnd.in-toto+json", + } + bundle, err := cbundle.SignData(ctx, content, keypair, idToken, certBytes, signingConfig, trustedMaterial) + if err != nil { + return fmt.Errorf("signing bundle: %w", err) + } + + if bundleOpts.BundlePath != "" { + if err := os.WriteFile(bundleOpts.BundlePath, bundle, 0600); err != nil { + return fmt.Errorf("creating bundle file: %w", err) + } + ui.Infof(ctx, "Wrote bundle to file %s", bundleOpts.BundlePath) + return nil + } + if !bundleOpts.Upload { + return nil + } + return ociremote.WriteAttestationNewBundleFormat(bundleOpts.Digest, bundle, bundleOpts.PredicateType, bundleOpts.OCIRemoteOpts...) +} + +type bundleComponents struct { + SV *SignerVerifier + SignedPayload []byte + TimestampBytes []byte + RFC3161Timestamp *cbundle.RFC3161Timestamp + SignerBytes []byte + RekorEntry *models.LogEntryAnon +} + +// GetBundleComponents fetches data needed to compose the bundle or disparate verification material for any signing command. +func GetBundleComponents(ctx context.Context, cert, certChain string, ko options.KeyOpts, noupload, tlogUpload bool, payload []byte, digest name.Reference, rekorEntryType string) (*bundleComponents, func(), error) { //nolint:revive + bc := &bundleComponents{} + var err error + var closeSV func() + bc.SV, closeSV, err = GetSignerVerifier(ctx, cert, certChain, ko) + if err != nil { + return nil, nil, fmt.Errorf("getting signer: %w", err) + } + wrapped := dsse.WrapSigner(bc.SV, types.IntotoPayloadType) + + bc.SignedPayload, err = wrapped.SignMessage(bytes.NewReader(payload), signatureoptions.WithContext(ctx)) + if err != nil { + closeSV() + return nil, nil, fmt.Errorf("signing: %w", err) + } + if noupload { + return bc, closeSV, nil + } + // We need to decide what signature to send to the timestamp authority. + // + // Historically, cosign sent `signedPayload`, which is the entire JSON DSSE + // Envelope. However, when sigstore clients are verifying a bundle they + // will use the DSSE Sig field, so we choose what signature to send to + // the timestamp authority based on our output format. + tsaPayload := bc.SignedPayload + if ko.NewBundleFormat { + tsaPayload, err = cosign.GetDSSESigBytes(bc.SignedPayload) + if err != nil { + closeSV() + return nil, nil, fmt.Errorf("getting DSSE signature: %w", err) + } + } + bc.TimestampBytes, bc.RFC3161Timestamp, err = GetRFC3161Timestamp(tsaPayload, ko) + if err != nil { + closeSV() + return nil, nil, fmt.Errorf("getting timestamp: %w", err) + } + bc.SignerBytes, err = bc.SV.Bytes(ctx) + if err != nil { + closeSV() + return nil, nil, fmt.Errorf("converting signer to bytes: %w", err) + } + bc.RekorEntry, err = UploadToTlog(ctx, ko, digest, tlogUpload, bc.SignerBytes, func(r *rekorclient.Rekor, b []byte) (*models.LogEntryAnon, error) { + if rekorEntryType == "intoto" { + return cosign.TLogUploadInTotoAttestation(ctx, r, bc.SignedPayload, b) + } + return cosign.TLogUploadDSSEEnvelope(ctx, r, bc.SignedPayload, b) + }) + if err != nil { + closeSV() + return nil, nil, fmt.Errorf("uploading to tlog: %w", err) + } + return bc, closeSV, nil +} + +// ParseOCIReference parses a string reference to an OCI image into a reference, warning if the reference did not include a digest. +func ParseOCIReference(ctx context.Context, refStr string, opts ...name.Option) (name.Reference, error) { + ref, err := name.ParseReference(refStr, opts...) + if err != nil { + return nil, fmt.Errorf("parsing reference: %w", err) + } + if _, ok := ref.(name.Digest); !ok { + ui.Warnf(ctx, ui.TagReferenceMessage, refStr) + } + return ref, nil +} + +func ParseSignatureAlgorithmFlag(signingAlgorithm string) (pb_go_v1.PublicKeyDetails, error) { + if signingAlgorithm == "" { + var err error + signingAlgorithm, err = signature.FormatSignatureAlgorithmFlag(pb_go_v1.PublicKeyDetails_PKIX_ECDSA_P256_SHA_256) + if err != nil { + return pb_go_v1.PublicKeyDetails_PUBLIC_KEY_DETAILS_UNSPECIFIED, fmt.Errorf("formatting signature algorithm: %w", err) + } + } + return signature.ParseSignatureAlgorithmFlag(signingAlgorithm) +} + +// LoadTrustedMaterialAndSigningConfig loads the trusted material and signing config from the given options. +func LoadTrustedMaterialAndSigningConfig(ctx context.Context, ko *options.KeyOpts, useSigningConfig bool, signingConfigPath string, + rekorURL, fulcioURL, oidcIssuer, tsaServerURL, trustedRootPath string, + tlogUpload bool, newBundleFormat bool, bundlePath string, keyRef string, issueCertificate bool, + output, outputAttestation, outputCertificate, outputPayload, outputSignature string) error { + var err error + // If a signing config is used, then service URLs cannot be specified + if (useSigningConfig || signingConfigPath != "") && + ((rekorURL != "" && rekorURL != options.DefaultRekorURL) || + (fulcioURL != "" && fulcioURL != options.DefaultFulcioURL) || + (oidcIssuer != "" && oidcIssuer != options.DefaultOIDCIssuerURL) || + tsaServerURL != "") { + return fmt.Errorf("cannot specify service URLs and use signing config") + } + if (useSigningConfig || signingConfigPath != "") && !tlogUpload { + return fmt.Errorf("--tlog-upload=false is not supported with --signing-config or --use-signing-config. Provide a signing config with --signing-config without a transparency log service, which can be created with `cosign signing-config create` or `curl https://raw.githubusercontent.com/sigstore/root-signing/refs/heads/main/targets/signing_config.v0.2.json | jq 'del(.rekorTlogUrls)'` for the public instance") + } + // Signing config requires a bundle as output for verification materials since sigstore-go is used + if (useSigningConfig || signingConfigPath != "") && !newBundleFormat && bundlePath == "" { + return fmt.Errorf("must provide --new-bundle-format or --bundle where applicable with --signing-config or --use-signing-config") + } + // Fetch a trusted root when: + // * requesting a certificate and no CT log key is provided to verify an SCT + // * using a signing config and signing using sigstore-go + if ((keyRef == "" || issueCertificate) && env.Getenv(env.VariableSigstoreCTLogPublicKeyFile) == "") || + (useSigningConfig || signingConfigPath != "") { + if trustedRootPath != "" { + ko.TrustedMaterial, err = root.NewTrustedRootFromPath(trustedRootPath) + if err != nil { + return fmt.Errorf("loading trusted root: %w", err) + } + } else { + ko.TrustedMaterial, err = cosign.TrustedRoot() + if err != nil { + ui.Warnf(ctx, "Could not fetch trusted_root.json from the TUF repository. Continuing with individual targets. Error from TUF: %v", err) + } + } + } + if signingConfigPath != "" { + ko.SigningConfig, err = root.NewSigningConfigFromPath(signingConfigPath) + if err != nil { + return fmt.Errorf("error reading signing config from file: %w", err) + } + } else if useSigningConfig { + ko.SigningConfig, err = cosign.SigningConfig() + if err != nil { + return fmt.Errorf("error getting signing config from TUF: %w", err) + } + } + + // TODO: Remove deprecated output flags warning in a future release (when flags are removed) + if newBundleFormat && outputSignature != "" { + ui.Warnf(context.Background(), "--output-signature is deprecated when using --new-bundle-format and will be ignored") + } + if newBundleFormat && outputAttestation != "" { + ui.Warnf(context.Background(), "--output-attestation is deprecated when using --new-bundle-format and will be ignored") + } + if newBundleFormat && outputCertificate != "" { + ui.Warnf(context.Background(), "--output-certificate is deprecated when using --new-bundle-format and will be ignored") + } + if newBundleFormat && outputPayload != "" { + ui.Warnf(context.Background(), "--output-payload is deprecated when using --new-bundle-format and will be ignored") + } + if newBundleFormat && output != "" { + ui.Warnf(context.Background(), "--output is deprecated when using --new-bundle-format and will be ignored") + } + + return nil +} diff --git a/cmd/cosign/cli/signcommon/common_test.go b/cmd/cosign/cli/signcommon/common_test.go new file mode 100644 index 00000000000..3c17baed0a0 --- /dev/null +++ b/cmd/cosign/cli/signcommon/common_test.go @@ -0,0 +1,205 @@ +// Copyright 2025 The Sigstore 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 signcommon + +import ( + "context" + "crypto/ecdsa" + "crypto/x509" + "encoding/pem" + "os" + "reflect" + "strings" + "testing" + + "github.com/secure-systems-lab/go-securesystemslib/encrypted" + "github.com/sigstore/cosign/v3/internal/test" + "github.com/sigstore/cosign/v3/internal/ui" + "github.com/sigstore/cosign/v3/pkg/cosign" + "github.com/sigstore/sigstore/pkg/cryptoutils" + "github.com/stretchr/testify/assert" +) + +func pass(s string) cosign.PassFunc { + return func(_ bool) ([]byte, error) { + return []byte(s), nil + } +} + +func generateCertificateFiles(t *testing.T, tmpDir string, pf cosign.PassFunc) (privFile, certFile, chainFile string, privKey *ecdsa.PrivateKey, cert *x509.Certificate, chain []*x509.Certificate) { + t.Helper() + + rootCert, rootKey, _ := test.GenerateRootCa() + subCert, subKey, _ := test.GenerateSubordinateCa(rootCert, rootKey) + leafCert, privKey, _ := test.GenerateLeafCert("subject", "oidc-issuer", subCert, subKey) + pemRoot := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: rootCert.Raw}) + pemSub := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: subCert.Raw}) + pemLeaf := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: leafCert.Raw}) + + x509Encoded, err := x509.MarshalPKCS8PrivateKey(privKey) + if err != nil { + t.Fatalf("failed to encode private key: %v", err) + } + password := []byte{} + if pf != nil { + password, err = pf(true) + if err != nil { + t.Fatalf("failed to read password: %v", err) + } + } + + encBytes, err := encrypted.Encrypt(x509Encoded, password) + if err != nil { + t.Fatalf("failed to encrypt key: %v", err) + } + + // store in PEM format + privBytes := pem.EncodeToMemory(&pem.Block{ + Bytes: encBytes, + Type: cosign.CosignPrivateKeyPemType, + }) + + tmpPrivFile, err := os.CreateTemp(tmpDir, "cosign_test_*.key") + if err != nil { + t.Fatalf("failed to create temp key file: %v", err) + } + defer tmpPrivFile.Close() + if _, err := tmpPrivFile.Write(privBytes); err != nil { + t.Fatalf("failed to write key file: %v", err) + } + + tmpCertFile, err := os.CreateTemp(tmpDir, "cosign.crt") + if err != nil { + t.Fatalf("failed to create temp certificate file: %v", err) + } + defer tmpCertFile.Close() + if _, err := tmpCertFile.Write(pemLeaf); err != nil { + t.Fatalf("failed to write certificate file: %v", err) + } + + tmpChainFile, err := os.CreateTemp(tmpDir, "cosign_chain.crt") + if err != nil { + t.Fatalf("failed to create temp chain file: %v", err) + } + defer tmpChainFile.Close() + pemChain := pemSub + pemChain = append(pemChain, pemRoot...) + if _, err := tmpChainFile.Write(pemChain); err != nil { + t.Fatalf("failed to write chain file: %v", err) + } + + return tmpPrivFile.Name(), tmpCertFile.Name(), tmpChainFile.Name(), privKey, leafCert, []*x509.Certificate{subCert, rootCert} +} + +func Test_signerFromKeyRefSuccess(t *testing.T) { + tmpDir := t.TempDir() + ctx := context.Background() + keyFile, certFile, chainFile, privKey, cert, chain := generateCertificateFiles(t, tmpDir, pass("foo")) + + signer, err := signerFromKeyRef(ctx, certFile, chainFile, keyFile, pass("foo"), nil) + if err != nil { + t.Fatalf("unexpected error generating signer: %v", err) + } + // Expect public key matches + pubKey, err := signer.PublicKey() + if err != nil { + t.Fatalf("unexpected error fetching pubkey: %v", err) + } + if !privKey.Public().(*ecdsa.PublicKey).Equal(pubKey) { + t.Fatalf("public keys must be equal") + } + // Expect certificate matches + expectedPemBytes, err := cryptoutils.MarshalCertificateToPEM(cert) + if err != nil { + t.Fatalf("unexpected error marshalling certificate: %v", err) + } + if !reflect.DeepEqual(signer.Cert, expectedPemBytes) { + t.Fatalf("certificates must match") + } + // Expect certificate chain matches + expectedPemBytesChain, err := cryptoutils.MarshalCertificatesToPEM(chain) + if err != nil { + t.Fatalf("unexpected error marshalling certificate chain: %v", err) + } + if !reflect.DeepEqual(signer.Chain, expectedPemBytesChain) { + t.Fatalf("certificate chains must match") + } +} + +func Test_signerFromKeyRefFailure(t *testing.T) { + tmpDir := t.TempDir() + ctx := context.Background() + keyFile, certFile, _, _, _, _ := generateCertificateFiles(t, tmpDir, pass("foo")) + // Second set of files + tmpDir2 := t.TempDir() + _, certFile2, chainFile2, _, _, _ := generateCertificateFiles(t, tmpDir2, pass("bar")) + + // Public keys don't match + _, err := signerFromKeyRef(ctx, certFile2, chainFile2, keyFile, pass("foo"), nil) + if err == nil || err.Error() != "public key in certificate does not match the provided public key" { + t.Fatalf("expected mismatched keys error, got %v", err) + } + // Certificate chain cannot be verified + _, err = signerFromKeyRef(ctx, certFile, chainFile2, keyFile, pass("foo"), nil) + if err == nil || !strings.Contains(err.Error(), "unable to validate certificate chain") { + t.Fatalf("expected chain verification error, got %v", err) + } + // Certificate chain specified without certificate + _, err = signerFromKeyRef(ctx, "", chainFile2, keyFile, pass("foo"), nil) + if err == nil || !strings.Contains(err.Error(), "no leaf certificate found or provided while specifying chain") { + t.Fatalf("expected no leaf error, got %v", err) + } +} + +func Test_signerFromKeyRefFailureEmptyChainFile(t *testing.T) { + tmpDir := t.TempDir() + ctx := context.Background() + keyFile, certFile, _, _, _, _ := generateCertificateFiles(t, tmpDir, pass("foo")) + + tmpChainFile, err := os.CreateTemp(tmpDir, "cosign_chain_empty.crt") + if err != nil { + t.Fatalf("failed to create temp chain file: %v", err) + } + defer tmpChainFile.Close() + if _, err := tmpChainFile.Write([]byte{}); err != nil { + t.Fatalf("failed to write chain file: %v", err) + } + + _, err = signerFromKeyRef(ctx, certFile, tmpChainFile.Name(), keyFile, pass("foo"), nil) + if err == nil || err.Error() != "no certificates in certificate chain" { + t.Fatalf("expected empty chain error, got %v", err) + } +} + +func Test_ParseOCIReference(t *testing.T) { + var tests = []struct { + ref string + expectedWarning string + }{ + {"image:bytag", "WARNING: Image reference image:bytag uses a tag, not a digest"}, + {"image:bytag@sha256:abcdef", ""}, + {"image:@sha256:abcdef", ""}, + } + for _, tt := range tests { + stderr := ui.RunWithTestCtx(func(ctx context.Context, _ ui.WriteFunc) { + ParseOCIReference(ctx, tt.ref) + }) + if len(tt.expectedWarning) > 0 { + assert.Contains(t, stderr, tt.expectedWarning, stderr, "bad warning message") + } else { + assert.Empty(t, stderr, "expected no warning") + } + } +} diff --git a/cmd/cosign/cli/signingconfig.go b/cmd/cosign/cli/signingconfig.go index 088d2d53bfc..90c5347b311 100644 --- a/cmd/cosign/cli/signingconfig.go +++ b/cmd/cosign/cli/signingconfig.go @@ -17,8 +17,8 @@ package cli import ( "context" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/signingconfig" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/signingconfig" "github.com/spf13/cobra" ) diff --git a/cmd/cosign/cli/templates/templater.go b/cmd/cosign/cli/templates/templater.go index f2aa7f183ca..d86f43378c8 100644 --- a/cmd/cosign/cli/templates/templater.go +++ b/cmd/cosign/cli/templates/templater.go @@ -21,7 +21,7 @@ import ( "text/template" "unicode" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/templates/term" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/templates/term" "github.com/spf13/cobra" flag "github.com/spf13/pflag" ) diff --git a/cmd/cosign/cli/tree.go b/cmd/cosign/cli/tree.go index 521edffc8af..6a53081348b 100644 --- a/cmd/cosign/cli/tree.go +++ b/cmd/cosign/cli/tree.go @@ -18,12 +18,13 @@ package cli import ( "context" "fmt" + "io" "os" "github.com/google/go-containerregistry/pkg/name" v1 "github.com/google/go-containerregistry/pkg/v1" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - ociremote "github.com/sigstore/cosign/v2/pkg/oci/remote" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + ociremote "github.com/sigstore/cosign/v3/pkg/oci/remote" "github.com/spf13/cobra" ) @@ -37,7 +38,7 @@ func Tree() *cobra.Command { Args: cobra.ExactArgs(1), PersistentPreRun: options.BindViper, RunE: func(cmd *cobra.Command, args []string) error { - return TreeCmd(cmd.Context(), c.Registry, c.RegistryExperimental, c.ExperimentalOCI11, args[0]) + return TreeCmd(cmd.Context(), c.Registry, c.RegistryExperimental, c.ExperimentalOCI11, args[0], cmd.OutOrStdout()) }, } @@ -50,7 +51,7 @@ type OCIRelationsKey struct { artifactDigest name.Digest } -func TreeCmd(ctx context.Context, regOpts options.RegistryOptions, regExpOpts options.RegistryExperimentalOptions, experimentalOCI11 bool, imageRef string) error { +func TreeCmd(ctx context.Context, regOpts options.RegistryOptions, regExpOpts options.RegistryExperimentalOptions, experimentalOCI11 bool, imageRef string, out io.Writer) error { scsaMap := map[name.Tag][]v1.Layer{} ociRelationsMap := map[OCIRelationsKey][]v1.Layer{} @@ -63,7 +64,7 @@ func TreeCmd(ctx context.Context, regOpts options.RegistryOptions, regExpOpts op if err != nil { return err } - fmt.Fprintf(os.Stdout, "📦 Supply Chain Security Related artifacts for an image: %s\n", ref.String()) + fmt.Fprintf(out, "📦 Supply Chain Security Related artifacts for an image: %s\n", ref.String()) simg, err := ociremote.SignedEntity(ref, remoteOpts...) if err != nil { @@ -151,6 +152,17 @@ func TreeCmd(ctx context.Context, regOpts options.RegistryOptions, regExpOpts op continue } + artifactType := manifest.ArtifactType + // Check if we are using protobuf bundle, + // and if so update artifactType to the bundle predicate + imageManifest, err := artifactImage.Manifest() + if err == nil { + val, ok := imageManifest.Annotations[ociremote.BundlePredicateType] + if ok { + artifactType = val + } + } + // Get layers for this artifact layers, err := artifactImage.Layers() if err != nil { @@ -159,13 +171,13 @@ func TreeCmd(ctx context.Context, regOpts options.RegistryOptions, regExpOpts op } // Add to the map - key := OCIRelationsKey{manifest.ArtifactType, artifactRef} + key := OCIRelationsKey{artifactType, artifactRef} ociRelationsMap[key] = append(ociRelationsMap[key], layers...) } } if len(scsaMap) == 0 && len(ociRelationsMap) == 0 { - fmt.Fprintf(os.Stdout, "No Supply Chain Security Related Artifacts found for image %s,\n start creating one with simply running"+ + fmt.Fprintf(out, "No Supply Chain Security Related Artifacts found for image %s,\n start creating one with simply running"+ "$ cosign sign ", ref.String()) return nil } @@ -173,14 +185,14 @@ func TreeCmd(ctx context.Context, regOpts options.RegistryOptions, regExpOpts op for t, k := range scsaMap { switch t { case sigRef: - fmt.Fprintf(os.Stdout, "└── 🔐 Signatures for an image tag: %s\n", t.String()) + fmt.Fprintf(out, "└── 🔐 Signatures for an image tag: %s\n", t.String()) case sbomRef: - fmt.Fprintf(os.Stdout, "└── 📦 SBOMs for an image tag: %s\n", t.String()) + fmt.Fprintf(out, "└── 📦 SBOMs for an image tag: %s\n", t.String()) case attRef: - fmt.Fprintf(os.Stdout, "└── 💾 Attestations for an image tag: %s\n", t.String()) + fmt.Fprintf(out, "└── 💾 Attestations for an image tag: %s\n", t.String()) } - if err := printLayers(k); err != nil { + if err := printLayers(k, out); err != nil { return err } } @@ -190,8 +202,8 @@ func TreeCmd(ctx context.Context, regOpts options.RegistryOptions, regExpOpts op // TODO - We could apply different emojis here for different values of key.artifactType - fmt.Fprintf(os.Stdout, "└── %s %s artifacts via OCI referrer: %s\n", emoji, key.artifactType, key.artifactDigest) - if err := printLayers(layers); err != nil { + fmt.Fprintf(out, "└── %s %s artifacts via OCI referrer: %s\n", emoji, key.artifactType, key.artifactDigest) + if err := printLayers(layers, out); err != nil { return err } } @@ -199,7 +211,7 @@ func TreeCmd(ctx context.Context, regOpts options.RegistryOptions, regExpOpts op return nil } -func printLayers(layers []v1.Layer) error { +func printLayers(layers []v1.Layer, out io.Writer) error { for i, l := range layers { last := i == len(layers)-1 var sym string @@ -212,7 +224,7 @@ func printLayers(layers []v1.Layer) error { if err != nil { return err } - fmt.Printf("%s 🍒 %s\n", sym, digest) + fmt.Fprintf(out, "%s 🍒 %s\n", sym, digest) } return nil } diff --git a/cmd/cosign/cli/triangulate.go b/cmd/cosign/cli/triangulate.go index 711b564d02e..c1ad0980502 100644 --- a/cmd/cosign/cli/triangulate.go +++ b/cmd/cosign/cli/triangulate.go @@ -18,8 +18,8 @@ package cli import ( "flag" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/triangulate" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/triangulate" "github.com/spf13/cobra" ) diff --git a/cmd/cosign/cli/triangulate/triangulate.go b/cmd/cosign/cli/triangulate/triangulate.go index 006c94277e6..3a5e558235e 100644 --- a/cmd/cosign/cli/triangulate/triangulate.go +++ b/cmd/cosign/cli/triangulate/triangulate.go @@ -21,9 +21,9 @@ import ( "os" "github.com/google/go-containerregistry/pkg/name" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/pkg/cosign" - ociremote "github.com/sigstore/cosign/v2/pkg/oci/remote" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/pkg/cosign" + ociremote "github.com/sigstore/cosign/v3/pkg/oci/remote" ) func MungeCmd(ctx context.Context, regOpts options.RegistryOptions, imageRef string, attachmentType string) error { diff --git a/cmd/cosign/cli/trustedroot.go b/cmd/cosign/cli/trustedroot.go index 70fa04bc53f..63857083a8f 100644 --- a/cmd/cosign/cli/trustedroot.go +++ b/cmd/cosign/cli/trustedroot.go @@ -18,8 +18,8 @@ package cli import ( "context" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/trustedroot" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/trustedroot" "github.com/spf13/cobra" ) diff --git a/cmd/cosign/cli/trustedroot/trustedroot.go b/cmd/cosign/cli/trustedroot/trustedroot.go index 762433cf3e2..f17041ac4f3 100644 --- a/cmd/cosign/cli/trustedroot/trustedroot.go +++ b/cmd/cosign/cli/trustedroot/trustedroot.go @@ -30,8 +30,8 @@ import ( "strings" "time" - "github.com/sigstore/cosign/v2/pkg/cosign" - "github.com/sigstore/rekor-tiles/pkg/note" + "github.com/sigstore/cosign/v3/pkg/cosign" + "github.com/sigstore/rekor-tiles/v2/pkg/note" "github.com/sigstore/sigstore-go/pkg/root" "github.com/sigstore/sigstore/pkg/cryptoutils" ) diff --git a/cmd/cosign/cli/upload.go b/cmd/cosign/cli/upload.go index 69c8530d036..2e29144f509 100644 --- a/cmd/cosign/cli/upload.go +++ b/cmd/cosign/cli/upload.go @@ -18,8 +18,8 @@ package cli import ( "flag" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/upload" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/upload" "github.com/spf13/cobra" ) diff --git a/cmd/cosign/cli/upload/blob.go b/cmd/cosign/cli/upload/blob.go index 901775a9230..0f64ef92990 100644 --- a/cmd/cosign/cli/upload/blob.go +++ b/cmd/cosign/cli/upload/blob.go @@ -24,8 +24,8 @@ import ( "github.com/google/go-containerregistry/pkg/name" "github.com/google/go-containerregistry/pkg/v1/types" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - cremote "github.com/sigstore/cosign/v2/pkg/cosign/remote" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + cremote "github.com/sigstore/cosign/v3/pkg/cosign/remote" ) func BlobCmd(ctx context.Context, regOpts options.RegistryOptions, files []cremote.File, annotations map[string]string, contentType, imageRef string) error { diff --git a/cmd/cosign/cli/upload/wasm.go b/cmd/cosign/cli/upload/wasm.go index d1b8c0d2de6..b515f5afdb9 100644 --- a/cmd/cosign/cli/upload/wasm.go +++ b/cmd/cosign/cli/upload/wasm.go @@ -22,9 +22,9 @@ import ( "github.com/google/go-containerregistry/pkg/name" "github.com/google/go-containerregistry/pkg/v1/remote" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/pkg/oci/static" - "github.com/sigstore/cosign/v2/pkg/types" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/pkg/oci/static" + "github.com/sigstore/cosign/v3/pkg/types" ) func WasmCmd(ctx context.Context, regOpts options.RegistryOptions, wasmPath, imageRef string) error { diff --git a/cmd/cosign/cli/verify.go b/cmd/cosign/cli/verify.go index a0e4ca7e20f..48d02c0cb7c 100644 --- a/cmd/cosign/cli/verify.go +++ b/cmd/cosign/cli/verify.go @@ -20,9 +20,9 @@ import ( "fmt" "github.com/google/go-containerregistry/pkg/name" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/verify" - "github.com/sigstore/cosign/v2/internal/ui" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/verify" + "github.com/sigstore/cosign/v3/internal/ui" "github.com/spf13/cobra" ) @@ -109,6 +109,7 @@ against the transparency log.`, v := &verify.VerifyCommand{ RegistryOptions: o.Registry, CertVerifyOptions: o.CertVerify, + CommonVerifyOptions: o.CommonVerifyOptions, CheckClaims: o.CheckClaims, KeyRef: o.Key, CertRef: o.CertVerify.Cert, @@ -138,6 +139,7 @@ against the transparency log.`, MaxWorkers: o.CommonVerifyOptions.MaxWorkers, ExperimentalOCI11: o.CommonVerifyOptions.ExperimentalOCI11, UseSignedTimestamps: o.CommonVerifyOptions.UseSignedTimestamps, + NewBundleFormat: o.CommonVerifyOptions.NewBundleFormat, } if o.CommonVerifyOptions.MaxWorkers == 0 { @@ -216,6 +218,11 @@ against the transparency log.`, o.CommonVerifyOptions.IgnoreTlog = true } + hashAlgorithm, err := o.SignatureDigest.HashAlgorithm() + if err != nil { + return err + } + v := &verify.VerifyAttestationCommand{ RegistryOptions: o.Registry, CommonVerifyOptions: o.CommonVerifyOptions, @@ -245,6 +252,7 @@ against the transparency log.`, TSACertChainPath: o.CommonVerifyOptions.TSACertChainPath, IgnoreTlog: o.CommonVerifyOptions.IgnoreTlog, MaxWorkers: o.CommonVerifyOptions.MaxWorkers, + HashAlgorithm: hashAlgorithm, UseSignedTimestamps: o.CommonVerifyOptions.UseSignedTimestamps, } @@ -328,6 +336,11 @@ The blob may be specified as a path to a file or - for stdin.`, o.CommonVerifyOptions.IgnoreTlog = true } + hashAlgorithm, err := o.SignatureDigest.HashAlgorithm() + if err != nil { + return err + } + ko := options.KeyOpts{ KeyRef: o.Key, Sk: o.SecurityKey.Use, @@ -357,6 +370,7 @@ The blob may be specified as a path to a file or - for stdin.`, IgnoreTlog: o.CommonVerifyOptions.IgnoreTlog, UseSignedTimestamps: o.CommonVerifyOptions.UseSignedTimestamps, TrustedRootPath: o.CommonVerifyOptions.TrustedRootPath, + HashAlgorithm: hashAlgorithm, } ctx, cancel := context.WithTimeout(cmd.Context(), ro.Timeout) @@ -399,6 +413,11 @@ The blob may be specified as a path to a file.`, o.CommonVerifyOptions.IgnoreTlog = true } + hashAlgorithm, err := o.SignatureDigest.HashAlgorithm() + if err != nil { + return err + } + ko := options.KeyOpts{ KeyRef: o.Key, Sk: o.SecurityKey.Use, @@ -432,6 +451,7 @@ The blob may be specified as a path to a file.`, TrustedRootPath: o.CommonVerifyOptions.TrustedRootPath, Digest: o.Digest, DigestAlg: o.DigestAlg, + HashAlgorithm: hashAlgorithm, } // We only use the blob if we are checking claims. if o.CheckClaims && len(args) == 0 && (o.Digest == "" || o.DigestAlg == "") { diff --git a/cmd/cosign/cli/verify/common.go b/cmd/cosign/cli/verify/common.go new file mode 100644 index 00000000000..57cecfffc23 --- /dev/null +++ b/cmd/cosign/cli/verify/common.go @@ -0,0 +1,465 @@ +// Copyright 2025 The Sigstore 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 verify + +import ( + "bytes" + "context" + "crypto" + "crypto/x509" + "encoding/base64" + "encoding/json" + "errors" + "fmt" + "os" + "reflect" + + "github.com/sigstore/cosign/v3/cmd/cosign/cli/fulcio" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/rekor" + "github.com/sigstore/cosign/v3/internal/ui" + "github.com/sigstore/cosign/v3/pkg/blob" + "github.com/sigstore/cosign/v3/pkg/cosign" + "github.com/sigstore/cosign/v3/pkg/cosign/env" + "github.com/sigstore/cosign/v3/pkg/cosign/pivkey" + "github.com/sigstore/cosign/v3/pkg/cosign/pkcs11key" + "github.com/sigstore/cosign/v3/pkg/oci" + csignature "github.com/sigstore/cosign/v3/pkg/signature" + "github.com/sigstore/sigstore-go/pkg/root" + "github.com/sigstore/sigstore/pkg/cryptoutils" + "github.com/sigstore/sigstore/pkg/signature" + "github.com/sigstore/sigstore/pkg/signature/payload" +) + +// CheckSigstoreBundleUnsupportedOptions checks for incompatible settings on any Verify* command struct when NewBundleFormat is used. +func CheckSigstoreBundleUnsupportedOptions(cmd any, co *cosign.CheckOpts) error { + if !co.NewBundleFormat { + return nil + } + fieldToErr := map[string]string{ + "CertRef": "certificate must be in bundle and may not be provided using --certificate", + "CertChain": "certificate chain must be in bundle and may not be provided using --certificate-chain", + "CARoots": "CA roots/intermediates must be provided using --trusted-root", + "CAIntermedias": "CA roots/intermediates must be provided using --trusted-root", + "TSACertChainPath": "TSA certificate chain path may only be provided using --trusted-root", + "RFC3161TimestampPath": "RFC3161 timestamp may not be provided using --rfc3161-timestamp", + "SigRef": "signature may not be provided using --signature", + "SCTRef": "SCT may not be provided using --sct", + } + v := reflect.ValueOf(cmd) + for f, e := range fieldToErr { + if field := v.FieldByName(f); field.IsValid() && field.String() != "" { + return fmt.Errorf("unsupported: %s when using --new-bundle-format", e) + } + } + if co.TrustedMaterial == nil { + return fmt.Errorf("trusted root is required when using new bundle format") + } + return nil +} + +// LoadVerifierFromKeyOrCert returns either a signature.Verifier or a certificate from the provided flags to use for verifying an artifact. +// In the case of certain types of keys, it returns a close function that must be called by the calling method. +func LoadVerifierFromKeyOrCert(ctx context.Context, keyRef, slot, certRef, certChain string, hashAlgorithm crypto.Hash, sk, withGetCert bool, co *cosign.CheckOpts) (signature.Verifier, *x509.Certificate, func(), error) { + var sigVerifier signature.Verifier + var err error + switch { + case keyRef != "": + sigVerifier, err = csignature.PublicKeyFromKeyRefWithHashAlgo(ctx, keyRef, hashAlgorithm) + if err != nil { + return nil, nil, nil, fmt.Errorf("loading public key: %w", err) + } + pkcs11Key, ok := sigVerifier.(*pkcs11key.Key) + closeSV := func() {} + if ok { + closeSV = pkcs11Key.Close + } + return sigVerifier, nil, closeSV, nil + case sk: + sk, err := pivkey.GetKeyWithSlot(slot) + if err != nil { + return nil, nil, nil, fmt.Errorf("opening piv token: %w", err) + } + sigVerifier, err = sk.Verifier() + if err != nil { + sk.Close() + return nil, nil, nil, fmt.Errorf("initializing piv token verifier: %w", err) + } + return sigVerifier, nil, sk.Close, nil + case certRef != "": + cert, err := loadCertFromFileOrURL(certRef) + if err != nil { + return nil, nil, nil, fmt.Errorf("loading cert: %w", err) + } + if withGetCert { + return nil, cert, func() {}, nil + } + if certChain == "" { + sigVerifier, err = cosign.ValidateAndUnpackCert(cert, co) + if err != nil { + return nil, nil, nil, fmt.Errorf("validating cert: %w", err) + } + return sigVerifier, nil, func() {}, nil + } + chain, err := loadCertChainFromFileOrURL(certChain) + if err != nil { + return nil, nil, nil, fmt.Errorf("loading cert chain: %w", err) + } + sigVerifier, err = cosign.ValidateAndUnpackCertWithChain(cert, chain, co) + if err != nil { + return nil, nil, nil, fmt.Errorf("validating cert with chain: %w", err) + } + return sigVerifier, nil, func() {}, nil + } + return nil, nil, func() {}, nil +} + +// SetLegacyClientsAndKeys sets up TSA and rekor clients and keys for TSA, rekor, and CT log. +// It may perform an online fetch of keys, so using trusted root instead of these TUF v1 methos is recommended. +// It takes a CheckOpts as input and modifies it. +func SetLegacyClientsAndKeys(ctx context.Context, ignoreTlog, shouldVerifySCT, keylessVerification bool, rekorURL, tsaCertChain, certChain, caRoots, caIntermediates string, co *cosign.CheckOpts) error { + var err error + if !ignoreTlog && !co.NewBundleFormat && rekorURL != "" { + co.RekorClient, err = rekor.NewClient(rekorURL) + if err != nil { + return fmt.Errorf("creating rekor client: %w", err) + } + } + // If trusted material is set, we don't need to fetch disparate keys. + if co.TrustedMaterial != nil { + return nil + } + if co.UseSignedTimestamps { + tsaCertificates, err := cosign.GetTSACerts(ctx, tsaCertChain, cosign.GetTufTargets) + if err != nil { + return fmt.Errorf("loading TSA certificates: %w", err) + } + co.TSACertificate = tsaCertificates.LeafCert + co.TSARootCertificates = tsaCertificates.RootCert + co.TSAIntermediateCertificates = tsaCertificates.IntermediateCerts + } + if !ignoreTlog { + co.RekorPubKeys, err = cosign.GetRekorPubs(ctx) + if err != nil { + return fmt.Errorf("getting rekor public keys: %w", err) + } + } + if shouldVerifySCT { + co.CTLogPubKeys, err = cosign.GetCTLogPubs(ctx) + if err != nil { + return fmt.Errorf("getting ctlog public keys: %w", err) + } + } + if keylessVerification { + if err := loadCertsKeylessVerification(certChain, caRoots, caIntermediates, co); err != nil { + return fmt.Errorf("loading certs for keyless verification: %w", err) + } + } + return nil +} + +// SetTrustedMaterial sets TrustedMaterial on CheckOpts, either from the provided trusted root path or from TUF. +// It does not set TrustedMaterial if the user provided trusted material via other flags or environment variables. +func SetTrustedMaterial(ctx context.Context, trustedRootPath, certChain, caRoots, caIntermediates, tsaCertChainPath string, co *cosign.CheckOpts) error { + var err error + if trustedRootPath != "" { + co.TrustedMaterial, err = root.NewTrustedRootFromPath(trustedRootPath) + if err != nil { + return fmt.Errorf("loading trusted root: %w", err) + } + return nil + } + if options.NOf(certChain, caRoots, caIntermediates, tsaCertChainPath) == 0 && + env.Getenv(env.VariableSigstoreCTLogPublicKeyFile) == "" && + env.Getenv(env.VariableSigstoreRootFile) == "" && + env.Getenv(env.VariableSigstoreRekorPublicKey) == "" && + env.Getenv(env.VariableSigstoreTSACertificateFile) == "" { + co.TrustedMaterial, err = cosign.TrustedRoot() + if err != nil { + ui.Warnf(ctx, "Could not fetch trusted_root.json from the TUF repository. Continuing with individual targets. Error from TUF: %v", err) + } + } + return nil +} + +// PrintVerificationHeader prints boilerplate information after successful verification. +func PrintVerificationHeader(ctx context.Context, imgRef string, co *cosign.CheckOpts, bundleVerified, fulcioVerified bool) { + ui.Infof(ctx, "\nVerification for %s --", imgRef) + ui.Infof(ctx, "The following checks were performed on each of these signatures:") + if co.ClaimVerifier != nil { + if co.Annotations != nil { + ui.Infof(ctx, " - The specified annotations were verified.") + } + ui.Infof(ctx, " - The cosign claims were validated") + } + if bundleVerified { + ui.Infof(ctx, " - Existence of the claims in the transparency log was verified offline") + } else if co.RekorClient != nil { + ui.Infof(ctx, " - The claims were present in the transparency log") + ui.Infof(ctx, " - The signatures were integrated into the transparency log when the certificate was valid") + } + if co.SigVerifier != nil { + ui.Infof(ctx, " - The signatures were verified against the specified public key") + } + if fulcioVerified { + ui.Infof(ctx, " - The code-signing certificate was verified using trusted certificate authority certificates") + } +} + +// PrintVerification logs details about the verification to stdout. +func PrintVerification(ctx context.Context, verified []oci.Signature, output string) { + switch output { + case "text": + for _, sig := range verified { + if cert, err := sig.Cert(); err == nil && cert != nil { + ce := cosign.CertExtensions{Cert: cert} + sub := "" + if sans := cryptoutils.GetSubjectAlternateNames(cert); len(sans) > 0 { + sub = sans[0] + } + ui.Infof(ctx, "Certificate subject: %s", sub) + if issuerURL := ce.GetIssuer(); issuerURL != "" { + ui.Infof(ctx, "Certificate issuer URL: %s", issuerURL) + } + + if githubWorkflowTrigger := ce.GetCertExtensionGithubWorkflowTrigger(); githubWorkflowTrigger != "" { + ui.Infof(ctx, "GitHub Workflow Trigger: %s", githubWorkflowTrigger) + } + + if githubWorkflowSha := ce.GetExtensionGithubWorkflowSha(); githubWorkflowSha != "" { + ui.Infof(ctx, "GitHub Workflow SHA: %s", githubWorkflowSha) + } + if githubWorkflowName := ce.GetCertExtensionGithubWorkflowName(); githubWorkflowName != "" { + ui.Infof(ctx, "GitHub Workflow Name: %s", githubWorkflowName) + } + + if githubWorkflowRepository := ce.GetCertExtensionGithubWorkflowRepository(); githubWorkflowRepository != "" { + ui.Infof(ctx, "GitHub Workflow Repository: %s", githubWorkflowRepository) + } + + if githubWorkflowRef := ce.GetCertExtensionGithubWorkflowRef(); githubWorkflowRef != "" { + ui.Infof(ctx, "GitHub Workflow Ref: %s", githubWorkflowRef) + } + } + + p, err := sig.Payload() + if err != nil { + fmt.Fprintf(os.Stderr, "Error fetching payload: %v", err) + return + } + fmt.Println(string(p)) + } + + default: + var outputKeys []payload.SimpleContainerImage + for _, sig := range verified { + p, err := sig.Payload() + if err != nil { + fmt.Fprintf(os.Stderr, "Error fetching payload: %v", err) + return + } + + ss := payload.SimpleContainerImage{} + if err := json.Unmarshal(p, &ss); err != nil { + fmt.Println("error decoding the payload:", err.Error()) + return + } + + if cert, err := sig.Cert(); err == nil && cert != nil { + ce := cosign.CertExtensions{Cert: cert} + if ss.Optional == nil { + ss.Optional = make(map[string]interface{}) + } + sub := "" + if sans := cryptoutils.GetSubjectAlternateNames(cert); len(sans) > 0 { + sub = sans[0] + } + ss.Optional["Subject"] = sub + if issuerURL := ce.GetIssuer(); issuerURL != "" { + ss.Optional["Issuer"] = issuerURL + ss.Optional[cosign.CertExtensionOIDCIssuer] = issuerURL + } + if githubWorkflowTrigger := ce.GetCertExtensionGithubWorkflowTrigger(); githubWorkflowTrigger != "" { + ss.Optional[cosign.CertExtensionMap[cosign.CertExtensionGithubWorkflowTrigger]] = githubWorkflowTrigger + ss.Optional[cosign.CertExtensionGithubWorkflowTrigger] = githubWorkflowTrigger + } + + if githubWorkflowSha := ce.GetExtensionGithubWorkflowSha(); githubWorkflowSha != "" { + ss.Optional[cosign.CertExtensionMap[cosign.CertExtensionGithubWorkflowSha]] = githubWorkflowSha + ss.Optional[cosign.CertExtensionGithubWorkflowSha] = githubWorkflowSha + } + if githubWorkflowName := ce.GetCertExtensionGithubWorkflowName(); githubWorkflowName != "" { + ss.Optional[cosign.CertExtensionMap[cosign.CertExtensionGithubWorkflowName]] = githubWorkflowName + ss.Optional[cosign.CertExtensionGithubWorkflowName] = githubWorkflowName + } + + if githubWorkflowRepository := ce.GetCertExtensionGithubWorkflowRepository(); githubWorkflowRepository != "" { + ss.Optional[cosign.CertExtensionMap[cosign.CertExtensionGithubWorkflowRepository]] = githubWorkflowRepository + ss.Optional[cosign.CertExtensionGithubWorkflowRepository] = githubWorkflowRepository + } + + if githubWorkflowRef := ce.GetCertExtensionGithubWorkflowRef(); githubWorkflowRef != "" { + ss.Optional[cosign.CertExtensionMap[cosign.CertExtensionGithubWorkflowRef]] = githubWorkflowRef + ss.Optional[cosign.CertExtensionGithubWorkflowRef] = githubWorkflowRef + } + } + if bundle, err := sig.Bundle(); err == nil && bundle != nil { + if ss.Optional == nil { + ss.Optional = make(map[string]interface{}) + } + ss.Optional["Bundle"] = bundle + } + if rfc3161Timestamp, err := sig.RFC3161Timestamp(); err == nil && rfc3161Timestamp != nil { + if ss.Optional == nil { + ss.Optional = make(map[string]interface{}) + } + ss.Optional["RFC3161Timestamp"] = rfc3161Timestamp + } + + outputKeys = append(outputKeys, ss) + } + + b, err := json.Marshal(outputKeys) + if err != nil { + fmt.Println("error when generating the output:", err.Error()) + return + } + + fmt.Printf("\n%s\n", string(b)) + } +} + +func loadCertFromFileOrURL(path string) (*x509.Certificate, error) { + pems, err := blob.LoadFileOrURL(path) + if err != nil { + return nil, err + } + return loadCertFromPEM(pems) +} + +func loadCertFromPEM(pems []byte) (*x509.Certificate, error) { + var out []byte + out, err := base64.StdEncoding.DecodeString(string(pems)) + if err != nil { + // not a base64 + out = pems + } + + certs, err := cryptoutils.UnmarshalCertificatesFromPEM(out) + if err != nil { + return nil, err + } + if len(certs) == 0 { + return nil, errors.New("no certs found in pem file") + } + return certs[0], nil +} + +func loadCertChainFromFileOrURL(path string) ([]*x509.Certificate, error) { + pems, err := blob.LoadFileOrURL(path) + if err != nil { + return nil, err + } + certs, err := cryptoutils.LoadCertificatesFromPEM(bytes.NewReader(pems)) + if err != nil { + return nil, err + } + return certs, nil +} + +func keylessVerification(keyRef string, sk bool) bool { + if keyRef != "" { + return false + } + if sk { + return false + } + return true +} + +func shouldVerifySCT(ignoreSCT bool, keyRef string, sk bool) bool { + if keyRef != "" { + return false + } + if sk { + return false + } + if ignoreSCT { + return false + } + return true +} + +// loadCertsKeylessVerification loads certificates provided as a certificate chain or CA roots + CA intermediate +// certificate files. If both certChain and caRootsFile are empty strings, the Fulcio roots are loaded. +// +// The co *cosign.CheckOpts is both input and output parameter - it gets updated +// with the root and intermediate certificates needed for verification. +func loadCertsKeylessVerification(certChainFile string, + caRootsFile string, + caIntermediatesFile string, + co *cosign.CheckOpts) error { + var err error + switch { + case certChainFile != "": + chain, err := loadCertChainFromFileOrURL(certChainFile) + if err != nil { + return err + } + co.RootCerts = x509.NewCertPool() + co.RootCerts.AddCert(chain[len(chain)-1]) + if len(chain) > 1 { + co.IntermediateCerts = x509.NewCertPool() + for _, cert := range chain[:len(chain)-1] { + co.IntermediateCerts.AddCert(cert) + } + } + case caRootsFile != "": + caRoots, err := loadCertChainFromFileOrURL(caRootsFile) + if err != nil { + return err + } + co.RootCerts = x509.NewCertPool() + if len(caRoots) > 0 { + for _, cert := range caRoots { + co.RootCerts.AddCert(cert) + } + } + if caIntermediatesFile != "" { + caIntermediates, err := loadCertChainFromFileOrURL(caIntermediatesFile) + if err != nil { + return err + } + if len(caIntermediates) > 0 { + co.IntermediateCerts = x509.NewCertPool() + for _, cert := range caIntermediates { + co.IntermediateCerts.AddCert(cert) + } + } + } + default: + // This performs an online fetch of the Fulcio roots from a TUF repository. + // This is needed for verifying keyless certificates (both online and offline). + co.RootCerts, err = fulcio.GetRoots() + if err != nil { + return fmt.Errorf("getting Fulcio roots: %w", err) + } + co.IntermediateCerts, err = fulcio.GetIntermediates() + if err != nil { + return fmt.Errorf("getting Fulcio intermediates: %w", err) + } + } + + return nil +} diff --git a/cmd/cosign/cli/verify/verify.go b/cmd/cosign/cli/verify/verify.go index 01a3ea60067..e9fc06bce7e 100644 --- a/cmd/cosign/cli/verify/verify.go +++ b/cmd/cosign/cli/verify/verify.go @@ -16,35 +16,25 @@ package verify import ( - "bytes" "context" "crypto" - "crypto/x509" - "encoding/base64" "encoding/json" - "errors" "flag" "fmt" "os" "path/filepath" "github.com/google/go-containerregistry/pkg/name" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/fulcio" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/rekor" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/sign" - cosignError "github.com/sigstore/cosign/v2/cmd/cosign/errors" - "github.com/sigstore/cosign/v2/internal/ui" - "github.com/sigstore/cosign/v2/pkg/blob" - "github.com/sigstore/cosign/v2/pkg/cosign" - "github.com/sigstore/cosign/v2/pkg/cosign/env" - "github.com/sigstore/cosign/v2/pkg/cosign/pivkey" - "github.com/sigstore/cosign/v2/pkg/cosign/pkcs11key" - "github.com/sigstore/cosign/v2/pkg/oci" - sigs "github.com/sigstore/cosign/v2/pkg/signature" - "github.com/sigstore/sigstore-go/pkg/root" - "github.com/sigstore/sigstore/pkg/cryptoutils" - "github.com/sigstore/sigstore/pkg/signature" + in_toto_attest "github.com/in-toto/attestation/go/v1" + "github.com/in-toto/in-toto-golang/in_toto" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/sign" + cosignError "github.com/sigstore/cosign/v3/cmd/cosign/errors" + "github.com/sigstore/cosign/v3/pkg/cosign" + "github.com/sigstore/cosign/v3/pkg/oci" + "github.com/sigstore/cosign/v3/pkg/oci/static" + sigs "github.com/sigstore/cosign/v3/pkg/signature" + "github.com/sigstore/protobuf-specs/gen/pb-go/dsse" "github.com/sigstore/sigstore/pkg/signature/payload" ) @@ -85,6 +75,7 @@ type VerifyCommand struct { IgnoreTlog bool MaxWorkers int ExperimentalOCI11 bool + NewBundleFormat bool } // Exec runs the verification command @@ -119,6 +110,9 @@ func (c *VerifyCommand) Exec(ctx context.Context, images []string) (err error) { if err != nil { return fmt.Errorf("constructing client options: %w", err) } + if c.AllowHTTPRegistry || c.AllowInsecure { + c.NameOptions = append(c.NameOptions, name.Insecure) + } co := &cosign.CheckOpts{ Annotations: c.Annotations.Annotations, @@ -140,148 +134,54 @@ func (c *VerifyCommand) Exec(ctx context.Context, images []string) (err error) { NewBundleFormat: c.NewBundleFormat, } - if c.TrustedRootPath != "" { - co.TrustedMaterial, err = root.NewTrustedRootFromPath(c.TrustedRootPath) - if err != nil { - return fmt.Errorf("loading trusted root: %w", err) - } - } else if options.NOf(c.CertChain, c.CARoots, c.CAIntermediates, c.TSACertChainPath) == 0 && - env.Getenv(env.VariableSigstoreCTLogPublicKeyFile) == "" && - env.Getenv(env.VariableSigstoreRootFile) == "" && - env.Getenv(env.VariableSigstoreRekorPublicKey) == "" && - env.Getenv(env.VariableSigstoreTSACertificateFile) == "" { - // don't overrule the user's intentions if they provided their own keys - co.TrustedMaterial, err = cosign.TrustedRoot() - if err != nil { - ui.Warnf(ctx, "Could not fetch trusted_root.json from the TUF repository. Continuing with individual targets. Error from TUF: %v", err) + // Check to see if we are using the new bundle format or not + if !c.LocalImage { + ref, err := name.ParseReference(images[0], c.NameOptions...) + if err == nil && c.NewBundleFormat { + newBundles, _, err := cosign.GetBundles(ctx, ref, co.RegistryClientOpts, c.NameOptions...) + if len(newBundles) == 0 || err != nil { + co.NewBundleFormat = false + } } } - if c.CheckClaims { - co.ClaimVerifier = cosign.SimpleClaimVerifier + err = SetTrustedMaterial(ctx, c.TrustedRootPath, c.CertChain, c.CARoots, c.CAIntermediates, c.TSACertChainPath, co) + if err != nil { + return fmt.Errorf("setting trusted material: %w", err) } - // If we are using signed timestamps and there is no trusted root, we need to load the TSA certificates - if co.UseSignedTimestamps && co.TrustedMaterial == nil { - tsaCertificates, err := cosign.GetTSACerts(ctx, c.TSACertChainPath, cosign.GetTufTargets) - if err != nil { - return fmt.Errorf("unable to load TSA certificates: %w", err) - } - co.TSACertificate = tsaCertificates.LeafCert - co.TSARootCertificates = tsaCertificates.RootCert - co.TSAIntermediateCertificates = tsaCertificates.IntermediateCerts + if err = CheckSigstoreBundleUnsupportedOptions(*c, co); err != nil { + return err } - if !c.IgnoreTlog { - if c.RekorURL != "" { - rekorClient, err := rekor.NewClient(c.RekorURL) - if err != nil { - return fmt.Errorf("creating Rekor client: %w", err) - } - co.RekorClient = rekorClient - } - if co.TrustedMaterial == nil { - // This performs an online fetch of the Rekor public keys, but this is needed - // for verifying tlog entries (both online and offline). - co.RekorPubKeys, err = cosign.GetRekorPubs(ctx) - if err != nil { - return fmt.Errorf("getting Rekor public keys: %w", err) - } - } - } - if co.TrustedMaterial == nil && keylessVerification(c.KeyRef, c.Sk) { - if err := loadCertsKeylessVerification(c.CertChain, c.CARoots, c.CAIntermediates, co); err != nil { - return err + if c.CheckClaims { + if co.NewBundleFormat { + co.ClaimVerifier = cosign.IntotoSubjectClaimVerifier + } else { + co.ClaimVerifier = cosign.SimpleClaimVerifier } } - keyRef := c.KeyRef - certRef := c.CertRef - - // Ignore Signed Certificate Timestamp if the flag is set or a key is provided - if co.TrustedMaterial == nil && shouldVerifySCT(c.IgnoreSCT, c.KeyRef, c.Sk) { - co.CTLogPubKeys, err = cosign.GetCTLogPubs(ctx) - if err != nil { - return fmt.Errorf("getting ctlog public keys: %w", err) - } + err = SetLegacyClientsAndKeys(ctx, c.IgnoreTlog, shouldVerifySCT(c.IgnoreSCT, c.KeyRef, c.Sk), keylessVerification(c.KeyRef, c.Sk), c.RekorURL, c.TSACertChainPath, c.CertChain, c.CARoots, c.CAIntermediates, co) + if err != nil { + return fmt.Errorf("setting up clients and keys: %w", err) } // Keys are optional! - var pubKey signature.Verifier - switch { - case keyRef != "": - pubKey, err = sigs.PublicKeyFromKeyRefWithHashAlgo(ctx, keyRef, c.HashAlgorithm) - if err != nil { - return fmt.Errorf("loading public key: %w", err) - } - pkcs11Key, ok := pubKey.(*pkcs11key.Key) - if ok { - defer pkcs11Key.Close() - } - case c.Sk: - sk, err := pivkey.GetKeyWithSlot(c.Slot) - if err != nil { - return fmt.Errorf("opening piv token: %w", err) - } - defer sk.Close() - pubKey, err = sk.Verifier() - if err != nil { - return fmt.Errorf("initializing piv token verifier: %w", err) - } - case certRef != "": - cert, err := loadCertFromFileOrURL(c.CertRef) - if err != nil { - return err - } - switch { - case c.CertChain == "" && co.RootCerts == nil: - // If no certChain and no CARoots are passed, the Fulcio root certificate will be used - if co.TrustedMaterial == nil { - co.RootCerts, err = fulcio.GetRoots() - if err != nil { - return fmt.Errorf("getting Fulcio roots: %w", err) - } - co.IntermediateCerts, err = fulcio.GetIntermediates() - if err != nil { - return fmt.Errorf("getting Fulcio intermediates: %w", err) - } - } - pubKey, err = cosign.ValidateAndUnpackCert(cert, co) - if err != nil { - return err - } - case c.CertChain != "": - // Verify certificate with chain - chain, err := loadCertChainFromFileOrURL(c.CertChain) - if err != nil { - return err - } - pubKey, err = cosign.ValidateAndUnpackCertWithChain(cert, chain, co) - if err != nil { - return err - } - case co.RootCerts != nil: - // Verify certificate with root (and if given, intermediate) certificate - pubKey, err = cosign.ValidateAndUnpackCert(cert, co) - if err != nil { - return err - } - default: - return errors.New("no certificate chain provided to verify certificate") - } + var closeSV func() + co.SigVerifier, _, closeSV, err = LoadVerifierFromKeyOrCert(ctx, c.KeyRef, c.Slot, c.CertRef, c.CertChain, c.HashAlgorithm, c.Sk, false, co) + if err != nil { + return fmt.Errorf("loading verifier from key opts: %w", err) + } + defer closeSV() - if c.SCTRef != "" { - sct, err := os.ReadFile(filepath.Clean(c.SCTRef)) - if err != nil { - return fmt.Errorf("reading sct from file: %w", err) - } - co.SCT = sct + if c.CertRef != "" && c.SCTRef != "" { + sct, err := os.ReadFile(filepath.Clean(c.SCTRef)) + if err != nil { + return fmt.Errorf("reading sct from file: %w", err) } - default: - // Do nothing. Neither keyRef, c.Sk, nor certRef were set - can happen for example when using Fulcio and TSA. - // For an example see the TestAttachWithRFC3161Timestamp test in test/e2e_test.go. + co.SCT = sct } - co.SigVerifier = pubKey // NB: There are only 2 kinds of verification right now: // 1. You gave us the public key explicitly to verify against so co.SigVerifier is non-nil or, @@ -292,10 +192,20 @@ func (c *VerifyCommand) Exec(ctx context.Context, images []string) (err error) { fulcioVerified := (co.SigVerifier == nil) for _, img := range images { + var verified []oci.Signature + var bundleVerified bool + if c.LocalImage { - verified, bundleVerified, err := cosign.VerifyLocalImageSignatures(ctx, img, co) - if err != nil { - return err + if co.NewBundleFormat { + verified, bundleVerified, err = cosign.VerifyLocalImageAttestations(ctx, img, co) + if err != nil { + return err + } + } else { + verified, bundleVerified, err = cosign.VerifyLocalImageSignatures(ctx, img, co) + if err != nil { + return err + } } PrintVerificationHeader(ctx, img, co, bundleVerified, fulcioVerified) PrintVerification(ctx, verified, c.Output) @@ -304,290 +214,99 @@ func (c *VerifyCommand) Exec(ctx context.Context, images []string) (err error) { if err != nil { return fmt.Errorf("parsing reference: %w", err) } - ref, err = sign.GetAttachedImageRef(ref, c.Attachment, ociremoteOpts...) - if err != nil { - return fmt.Errorf("resolving attachment type %s for image %s: %w", c.Attachment, img, err) - } - - verified, bundleVerified, err := cosign.VerifyImageSignatures(ctx, ref, co) - if err != nil { - return cosignError.WrapError(err) - } - - PrintVerificationHeader(ctx, ref.Name(), co, bundleVerified, fulcioVerified) - PrintVerification(ctx, verified, c.Output) - } - } - - return nil -} - -func PrintVerificationHeader(ctx context.Context, imgRef string, co *cosign.CheckOpts, bundleVerified, fulcioVerified bool) { - ui.Infof(ctx, "\nVerification for %s --", imgRef) - ui.Infof(ctx, "The following checks were performed on each of these signatures:") - if co.ClaimVerifier != nil { - if co.Annotations != nil { - ui.Infof(ctx, " - The specified annotations were verified.") - } - ui.Infof(ctx, " - The cosign claims were validated") - } - if bundleVerified { - ui.Infof(ctx, " - Existence of the claims in the transparency log was verified offline") - } else if co.RekorClient != nil { - ui.Infof(ctx, " - The claims were present in the transparency log") - ui.Infof(ctx, " - The signatures were integrated into the transparency log when the certificate was valid") - } - if co.SigVerifier != nil { - ui.Infof(ctx, " - The signatures were verified against the specified public key") - } - if fulcioVerified { - ui.Infof(ctx, " - The code-signing certificate was verified using trusted certificate authority certificates") - } -} - -// PrintVerification logs details about the verification to stdout -func PrintVerification(ctx context.Context, verified []oci.Signature, output string) { - switch output { - case "text": - for _, sig := range verified { - if cert, err := sig.Cert(); err == nil && cert != nil { - ce := cosign.CertExtensions{Cert: cert} - sub := "" - if sans := cryptoutils.GetSubjectAlternateNames(cert); len(sans) > 0 { - sub = sans[0] - } - ui.Infof(ctx, "Certificate subject: %s", sub) - if issuerURL := ce.GetIssuer(); issuerURL != "" { - ui.Infof(ctx, "Certificate issuer URL: %s", issuerURL) - } - if githubWorkflowTrigger := ce.GetCertExtensionGithubWorkflowTrigger(); githubWorkflowTrigger != "" { - ui.Infof(ctx, "GitHub Workflow Trigger: %s", githubWorkflowTrigger) + if co.NewBundleFormat { + // OCI bundle always contains attestation + verified, bundleVerified, err = cosign.VerifyImageAttestations(ctx, ref, co, c.NameOptions...) + if err != nil { + return err } - if githubWorkflowSha := ce.GetExtensionGithubWorkflowSha(); githubWorkflowSha != "" { - ui.Infof(ctx, "GitHub Workflow SHA: %s", githubWorkflowSha) - } - if githubWorkflowName := ce.GetCertExtensionGithubWorkflowName(); githubWorkflowName != "" { - ui.Infof(ctx, "GitHub Workflow Name: %s", githubWorkflowName) + verifiedOutput, err := transformOutput(verified, ref.Name()) + if err == nil { + verified = verifiedOutput } - - if githubWorkflowRepository := ce.GetCertExtensionGithubWorkflowRepository(); githubWorkflowRepository != "" { - ui.Infof(ctx, "GitHub Workflow Repository: %s", githubWorkflowRepository) + } else { + ref, err = sign.GetAttachedImageRef(ref, c.Attachment, ociremoteOpts...) + if err != nil { + return fmt.Errorf("resolving attachment type %s for image %s: %w", c.Attachment, img, err) } - if githubWorkflowRef := ce.GetCertExtensionGithubWorkflowRef(); githubWorkflowRef != "" { - ui.Infof(ctx, "GitHub Workflow Ref: %s", githubWorkflowRef) + verified, bundleVerified, err = cosign.VerifyImageSignatures(ctx, ref, co) + if err != nil { + return cosignError.WrapError(err) } } - p, err := sig.Payload() - if err != nil { - fmt.Fprintf(os.Stderr, "Error fetching payload: %v", err) - return - } - fmt.Println(string(p)) + PrintVerificationHeader(ctx, ref.Name(), co, bundleVerified, fulcioVerified) + PrintVerification(ctx, verified, c.Output) } + } - default: - var outputKeys []payload.SimpleContainerImage - for _, sig := range verified { - p, err := sig.Payload() - if err != nil { - fmt.Fprintf(os.Stderr, "Error fetching payload: %v", err) - return - } - - ss := payload.SimpleContainerImage{} - if err := json.Unmarshal(p, &ss); err != nil { - fmt.Println("error decoding the payload:", err.Error()) - return - } - - if cert, err := sig.Cert(); err == nil && cert != nil { - ce := cosign.CertExtensions{Cert: cert} - if ss.Optional == nil { - ss.Optional = make(map[string]interface{}) - } - sub := "" - if sans := cryptoutils.GetSubjectAlternateNames(cert); len(sans) > 0 { - sub = sans[0] - } - ss.Optional["Subject"] = sub - if issuerURL := ce.GetIssuer(); issuerURL != "" { - ss.Optional["Issuer"] = issuerURL - ss.Optional[cosign.CertExtensionOIDCIssuer] = issuerURL - } - if githubWorkflowTrigger := ce.GetCertExtensionGithubWorkflowTrigger(); githubWorkflowTrigger != "" { - ss.Optional[cosign.CertExtensionMap[cosign.CertExtensionGithubWorkflowTrigger]] = githubWorkflowTrigger - ss.Optional[cosign.CertExtensionGithubWorkflowTrigger] = githubWorkflowTrigger - } - - if githubWorkflowSha := ce.GetExtensionGithubWorkflowSha(); githubWorkflowSha != "" { - ss.Optional[cosign.CertExtensionMap[cosign.CertExtensionGithubWorkflowSha]] = githubWorkflowSha - ss.Optional[cosign.CertExtensionGithubWorkflowSha] = githubWorkflowSha - } - if githubWorkflowName := ce.GetCertExtensionGithubWorkflowName(); githubWorkflowName != "" { - ss.Optional[cosign.CertExtensionMap[cosign.CertExtensionGithubWorkflowName]] = githubWorkflowName - ss.Optional[cosign.CertExtensionGithubWorkflowName] = githubWorkflowName - } - - if githubWorkflowRepository := ce.GetCertExtensionGithubWorkflowRepository(); githubWorkflowRepository != "" { - ss.Optional[cosign.CertExtensionMap[cosign.CertExtensionGithubWorkflowRepository]] = githubWorkflowRepository - ss.Optional[cosign.CertExtensionGithubWorkflowRepository] = githubWorkflowRepository - } - - if githubWorkflowRef := ce.GetCertExtensionGithubWorkflowRef(); githubWorkflowRef != "" { - ss.Optional[cosign.CertExtensionMap[cosign.CertExtensionGithubWorkflowRef]] = githubWorkflowRef - ss.Optional[cosign.CertExtensionGithubWorkflowRef] = githubWorkflowRef - } - } - if bundle, err := sig.Bundle(); err == nil && bundle != nil { - if ss.Optional == nil { - ss.Optional = make(map[string]interface{}) - } - ss.Optional["Bundle"] = bundle - } - if rfc3161Timestamp, err := sig.RFC3161Timestamp(); err == nil && rfc3161Timestamp != nil { - if ss.Optional == nil { - ss.Optional = make(map[string]interface{}) - } - ss.Optional["RFC3161Timestamp"] = rfc3161Timestamp - } + return nil +} - outputKeys = append(outputKeys, ss) +func transformOutput(verified []oci.Signature, name string) (verifiedOutput []oci.Signature, err error) { + for _, v := range verified { + dssePayload, err := v.Payload() + if err != nil { + return nil, err } - - b, err := json.Marshal(outputKeys) + var dsseEnvelope dsse.Envelope + err = json.Unmarshal(dssePayload, &dsseEnvelope) if err != nil { - fmt.Println("error when generating the output:", err.Error()) - return + return nil, err } - - fmt.Printf("\n%s\n", string(b)) - } -} - -func loadCertFromFileOrURL(path string) (*x509.Certificate, error) { - pems, err := blob.LoadFileOrURL(path) - if err != nil { - return nil, err - } - return loadCertFromPEM(pems) -} - -func loadCertFromPEM(pems []byte) (*x509.Certificate, error) { - var out []byte - out, err := base64.StdEncoding.DecodeString(string(pems)) - if err != nil { - // not a base64 - out = pems - } - - certs, err := cryptoutils.UnmarshalCertificatesFromPEM(out) - if err != nil { - return nil, err - } - if len(certs) == 0 { - return nil, errors.New("no certs found in pem file") - } - return certs[0], nil -} - -func loadCertChainFromFileOrURL(path string) ([]*x509.Certificate, error) { - pems, err := blob.LoadFileOrURL(path) - if err != nil { - return nil, err - } - certs, err := cryptoutils.LoadCertificatesFromPEM(bytes.NewReader(pems)) - if err != nil { - return nil, err - } - return certs, nil -} - -func keylessVerification(keyRef string, sk bool) bool { - if keyRef != "" { - return false - } - if sk { - return false - } - return true -} - -func shouldVerifySCT(ignoreSCT bool, keyRef string, sk bool) bool { - if keyRef != "" { - return false - } - if sk { - return false - } - if ignoreSCT { - return false - } - return true -} - -// loadCertsKeylessVerification loads certificates provided as a certificate chain or CA roots + CA intermediate -// certificate files. If both certChain and caRootsFile are empty strings, the Fulcio roots are loaded. -// -// The co *cosign.CheckOpts is both input and output parameter - it gets updated -// with the root and intermediate certificates needed for verification. -func loadCertsKeylessVerification(certChainFile string, - caRootsFile string, - caIntermediatesFile string, - co *cosign.CheckOpts) error { - var err error - switch { - case certChainFile != "": - chain, err := loadCertChainFromFileOrURL(certChainFile) + if dsseEnvelope.PayloadType != in_toto.PayloadType { + return nil, fmt.Errorf("unable to understand payload type %s", dsseEnvelope.PayloadType) + } + // Unmarshal first into in_toto.StatementHeader which should correctly parse the predicate type + var intotoStatement in_toto.StatementHeader + err = json.Unmarshal(dsseEnvelope.Payload, &intotoStatement) if err != nil { - return err + return nil, err } - co.RootCerts = x509.NewCertPool() - co.RootCerts.AddCert(chain[len(chain)-1]) - if len(chain) > 1 { - co.IntermediateCerts = x509.NewCertPool() - for _, cert := range chain[:len(chain)-1] { - co.IntermediateCerts.AddCert(cert) - } + if len(intotoStatement.Subject) < 1 || len(intotoStatement.Subject[0].Digest) < 1 { + return nil, fmt.Errorf("no intoto subject or digest found") } - case caRootsFile != "": - caRoots, err := loadCertChainFromFileOrURL(caRootsFile) + // Unmarshal again into in_toto_attest.Statement in order to parse annotations + var intotoAnnoStatement in_toto_attest.Statement + err = json.Unmarshal(dsseEnvelope.Payload, &intotoAnnoStatement) if err != nil { - return err + return nil, err } - co.RootCerts = x509.NewCertPool() - if len(caRoots) > 0 { - for _, cert := range caRoots { - co.RootCerts.AddCert(cert) - } + if len(intotoAnnoStatement.Subject) < 1 || len(intotoAnnoStatement.Subject[0].Digest) < 1 { + return nil, fmt.Errorf("no intoto subject or digest found") } - if caIntermediatesFile != "" { - caIntermediates, err := loadCertChainFromFileOrURL(caIntermediatesFile) - if err != nil { - return err - } - if len(caIntermediates) > 0 { - co.IntermediateCerts = x509.NewCertPool() - for _, cert := range caIntermediates { - co.IntermediateCerts.AddCert(cert) - } - } + + var digest string + for k, v := range intotoStatement.Subject[0].Digest { + digest = k + ":" + v } - default: - // This performs an online fetch of the Fulcio roots from a TUF repository. - // This is needed for verifying keyless certificates (both online and offline). - co.RootCerts, err = fulcio.GetRoots() + annotations := intotoAnnoStatement.Subject[0].Annotations.AsMap() + + sci := payload.SimpleContainerImage{ + Critical: payload.Critical{ + Identity: payload.Identity{ + DockerReference: name, + }, + Image: payload.Image{ + DockerManifestDigest: digest, + }, + Type: intotoStatement.PredicateType, + }, + Optional: annotations, + } + p, err := json.Marshal(sci) if err != nil { - return fmt.Errorf("getting Fulcio roots: %w", err) + return nil, err } - co.IntermediateCerts, err = fulcio.GetIntermediates() + att, err := static.NewAttestation(p) if err != nil { - return fmt.Errorf("getting Fulcio intermediates: %w", err) + return nil, err } + verifiedOutput = append(verifiedOutput, att) } - return nil + return verifiedOutput, nil } diff --git a/cmd/cosign/cli/verify/verify_attestation.go b/cmd/cosign/cli/verify/verify_attestation.go index 39baabce400..edbfac10c66 100644 --- a/cmd/cosign/cli/verify/verify_attestation.go +++ b/cmd/cosign/cli/verify/verify_attestation.go @@ -17,6 +17,7 @@ package verify import ( "context" + "crypto" "errors" "flag" "fmt" @@ -25,20 +26,13 @@ import ( "strings" "github.com/google/go-containerregistry/pkg/name" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/fulcio" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/rekor" - "github.com/sigstore/cosign/v2/internal/ui" - "github.com/sigstore/cosign/v2/pkg/cosign" - "github.com/sigstore/cosign/v2/pkg/cosign/cue" - "github.com/sigstore/cosign/v2/pkg/cosign/env" - "github.com/sigstore/cosign/v2/pkg/cosign/pivkey" - "github.com/sigstore/cosign/v2/pkg/cosign/pkcs11key" - "github.com/sigstore/cosign/v2/pkg/cosign/rego" - "github.com/sigstore/cosign/v2/pkg/oci" - "github.com/sigstore/cosign/v2/pkg/policy" - sigs "github.com/sigstore/cosign/v2/pkg/signature" - "github.com/sigstore/sigstore-go/pkg/root" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/internal/ui" + "github.com/sigstore/cosign/v3/pkg/cosign" + "github.com/sigstore/cosign/v3/pkg/cosign/cue" + "github.com/sigstore/cosign/v3/pkg/cosign/rego" + "github.com/sigstore/cosign/v3/pkg/oci" + "github.com/sigstore/cosign/v3/pkg/policy" ) // VerifyAttestationCommand verifies a signature on a supplied container image @@ -73,6 +67,7 @@ type VerifyAttestationCommand struct { IgnoreTlog bool MaxWorkers int UseSignedTimestamps bool + HashAlgorithm crypto.Hash } // Exec runs the verification command @@ -81,6 +76,11 @@ func (c *VerifyAttestationCommand) Exec(ctx context.Context, images []string) (e return flag.ErrHelp } + // always default to sha256 if the algorithm hasn't been explicitly set + if c.HashAlgorithm == 0 { + c.HashAlgorithm = crypto.SHA256 + } + // We can't have both a key and a security key if options.NOf(c.KeyRef, c.Sk) > 1 { return &options.KeyParseError{} @@ -98,20 +98,8 @@ func (c *VerifyAttestationCommand) Exec(ctx context.Context, images []string) (e if err != nil { return fmt.Errorf("constructing client options: %w", err) } - - trustedMaterial, err := cosign.TrustedRoot() - if err != nil { - ui.Warnf(ctx, "Could not fetch trusted_root.json from the TUF repository. Continuing with individual targets. Error from TUF: %v", err) - } - - if options.NOf(c.CertChain, c.CARoots, c.CAIntermediates, c.TSACertChainPath) > 0 || - env.Getenv(env.VariableSigstoreCTLogPublicKeyFile) != "" || - env.Getenv(env.VariableSigstoreRootFile) != "" || - env.Getenv(env.VariableSigstoreRekorPublicKey) != "" || - env.Getenv(env.VariableSigstoreTSACertificateFile) != "" { - // trusted_root.json was found, but a cert chain was explicitly provided, or environment variables point to the key material, - // so don't overrule the user's intentions. - trustedMaterial = nil + if c.AllowHTTPRegistry || c.AllowInsecure { + c.NameOptions = append(c.NameOptions, name.Insecure) } co := &cosign.CheckOpts{ @@ -128,157 +116,51 @@ func (c *VerifyAttestationCommand) Exec(ctx context.Context, images []string) (e MaxWorkers: c.MaxWorkers, UseSignedTimestamps: c.TSACertChainPath != "" || c.UseSignedTimestamps, NewBundleFormat: c.NewBundleFormat, - TrustedMaterial: trustedMaterial, - } - if c.CheckClaims { - co.ClaimVerifier = cosign.IntotoSubjectClaimVerifier } - if c.TrustedRootPath != "" { - co.TrustedMaterial, err = root.NewTrustedRootFromPath(c.TrustedRootPath) - if err != nil { - return fmt.Errorf("loading trusted root: %w", err) - } - } else if options.NOf(c.CertChain, c.CARoots, c.CAIntermediates, c.TSACertChainPath) == 0 && - env.Getenv(env.VariableSigstoreCTLogPublicKeyFile) == "" && - env.Getenv(env.VariableSigstoreRootFile) == "" && - env.Getenv(env.VariableSigstoreRekorPublicKey) == "" && - env.Getenv(env.VariableSigstoreTSACertificateFile) == "" { - co.TrustedMaterial, err = cosign.TrustedRoot() - if err != nil { - ui.Warnf(ctx, "Could not fetch trusted_root.json from the TUF repository. Continuing with individual targets. Error from TUF: %v", err) + // Check to see if we are using the new bundle format or not + if !c.LocalImage { + ref, err := name.ParseReference(images[0], c.NameOptions...) + if err == nil && c.NewBundleFormat { + newBundles, _, err := cosign.GetBundles(ctx, ref, co.RegistryClientOpts, c.NameOptions...) + if len(newBundles) == 0 || err != nil { + co.NewBundleFormat = false + } } } - if c.NewBundleFormat { - if err = checkSigstoreBundleUnsupportedOptions(c); err != nil { - return err - } - if co.TrustedMaterial == nil { - return fmt.Errorf("trusted root is required when using new bundle format") - } + if c.CheckClaims { + co.ClaimVerifier = cosign.IntotoSubjectClaimVerifier } - // Ignore Signed Certificate Timestamp if the flag is set or a key is provided - if co.TrustedMaterial == nil && shouldVerifySCT(c.IgnoreSCT, c.KeyRef, c.Sk) && !c.NewBundleFormat { - co.CTLogPubKeys, err = cosign.GetCTLogPubs(ctx) - if err != nil { - return fmt.Errorf("getting ctlog public keys: %w", err) - } + err = SetTrustedMaterial(ctx, c.TrustedRootPath, c.CertChain, c.CARoots, c.CAIntermediates, c.TSACertChainPath, co) + if err != nil { + return fmt.Errorf("setting trusted material: %w", err) } - // If we are using signed timestamps, we need to load the TSA certificates - if co.UseSignedTimestamps && co.TrustedMaterial == nil && !c.NewBundleFormat { - tsaCertificates, err := cosign.GetTSACerts(ctx, c.TSACertChainPath, cosign.GetTufTargets) - if err != nil { - return fmt.Errorf("unable to load TSA certificates: %w", err) - } - co.TSACertificate = tsaCertificates.LeafCert - co.TSARootCertificates = tsaCertificates.RootCert - co.TSAIntermediateCertificates = tsaCertificates.IntermediateCerts + if err = CheckSigstoreBundleUnsupportedOptions(*c, co); err != nil { + return err } - if !c.IgnoreTlog && !co.NewBundleFormat { - if c.RekorURL != "" { - rekorClient, err := rekor.NewClient(c.RekorURL) - if err != nil { - return fmt.Errorf("creating Rekor client: %w", err) - } - co.RekorClient = rekorClient - } - if co.TrustedMaterial == nil { - // This performs an online fetch of the Rekor public keys, but this is needed - // for verifying tlog entries (both online and offline). - co.RekorPubKeys, err = cosign.GetRekorPubs(ctx) - if err != nil { - return fmt.Errorf("getting Rekor public keys: %w", err) - } - } + err = SetLegacyClientsAndKeys(ctx, c.IgnoreTlog, shouldVerifySCT(c.IgnoreSCT, c.KeyRef, c.Sk), keylessVerification(c.KeyRef, c.Sk), c.RekorURL, c.TSACertChainPath, c.CertChain, c.CARoots, c.CAIntermediates, co) + if err != nil { + return fmt.Errorf("setting up clients and keys: %w", err) } - if co.TrustedMaterial == nil && keylessVerification(c.KeyRef, c.Sk) { - if err := loadCertsKeylessVerification(c.CertChain, c.CARoots, c.CAIntermediates, co); err != nil { - return err - } + // Keys are optional! + var closeSV func() + co.SigVerifier, _, closeSV, err = LoadVerifierFromKeyOrCert(ctx, c.KeyRef, c.Slot, c.CertRef, c.CertChain, c.HashAlgorithm, c.Sk, false, co) + if err != nil { + return fmt.Errorf("loading verifierfrom key opts: %w", err) } + defer closeSV() - keyRef := c.KeyRef - - // Keys are optional! - switch { - case keyRef != "": - co.SigVerifier, err = sigs.PublicKeyFromKeyRef(ctx, keyRef) - if err != nil { - return fmt.Errorf("loading public key: %w", err) - } - pkcs11Key, ok := co.SigVerifier.(*pkcs11key.Key) - if ok { - defer pkcs11Key.Close() - } - case c.Sk: - sk, err := pivkey.GetKeyWithSlot(c.Slot) + if c.CertRef != "" && c.SCTRef != "" { + sct, err := os.ReadFile(filepath.Clean(c.SCTRef)) if err != nil { - return fmt.Errorf("opening piv token: %w", err) - } - defer sk.Close() - co.SigVerifier, err = sk.Verifier() - if err != nil { - return fmt.Errorf("initializing piv token verifier: %w", err) - } - case c.CertRef != "": - if c.NewBundleFormat { - // This shouldn't happen because we already checked for this above in checkSigstoreBundleUnsupportedOptions - return fmt.Errorf("unsupported: certificate reference currently not supported with --new-bundle-format") - } - cert, err := loadCertFromFileOrURL(c.CertRef) - if err != nil { - return fmt.Errorf("loading certificate from reference: %w", err) - } - if c.CertChain == "" { - // If no certChain is passed, the Fulcio root certificate will be used - if co.TrustedMaterial == nil { - co.RootCerts, err = fulcio.GetRoots() - if err != nil { - return fmt.Errorf("getting Fulcio roots: %w", err) - } - co.IntermediateCerts, err = fulcio.GetIntermediates() - if err != nil { - return fmt.Errorf("getting Fulcio intermediates: %w", err) - } - } - co.SigVerifier, err = cosign.ValidateAndUnpackCert(cert, co) - if err != nil { - return fmt.Errorf("creating certificate verifier: %w", err) - } - } else { - // Verify certificate with chain - chain, err := loadCertChainFromFileOrURL(c.CertChain) - if err != nil { - return err - } - co.SigVerifier, err = cosign.ValidateAndUnpackCertWithChain(cert, chain, co) - if err != nil { - return fmt.Errorf("creating certificate verifier: %w", err) - } - } - if c.SCTRef != "" { - sct, err := os.ReadFile(filepath.Clean(c.SCTRef)) - if err != nil { - return fmt.Errorf("reading sct from file: %w", err) - } - co.SCT = sct - } - case c.TrustedRootPath != "": - if !c.NewBundleFormat { - return fmt.Errorf("unsupported: trusted root path currently only supported with --new-bundle-format") + return fmt.Errorf("reading sct from file: %w", err) } - - // If a trusted root path is provided, we will use it to verify the bundle. - // Otherwise, the verifier will default to the public good instance. - // co.TrustedMaterial is already loaded from c.TrustedRootPath above, - case c.CARoots != "": - // CA roots + possible intermediates are already loaded into co.RootCerts with the call to - // loadCertsKeylessVerification above. + co.SCT = sct } // NB: There are only 2 kinds of verification right now: @@ -303,7 +185,7 @@ func (c *VerifyAttestationCommand) Exec(ctx context.Context, images []string) (e return err } - verified, bundleVerified, err = cosign.VerifyImageAttestations(ctx, ref, co) + verified, bundleVerified, err = cosign.VerifyImageAttestations(ctx, ref, co, c.NameOptions...) if err != nil { return err } @@ -380,19 +262,3 @@ func (c *VerifyAttestationCommand) Exec(ctx context.Context, images []string) (e return nil } - -func checkSigstoreBundleUnsupportedOptions(c *VerifyAttestationCommand) error { - if c.CertRef != "" { - return fmt.Errorf("unsupported: certificate may not be provided using --certificate when using --new-bundle-format (cert must be in bundle)") - } - if c.CertChain != "" { - return fmt.Errorf("unsupported: certificate chain may not be provided using --certificate-chain when using --new-bundle-format (cert must be in bundle)") - } - if c.CARoots != "" || c.CAIntermediates != "" { - return fmt.Errorf("unsupported: CA roots/intermediates must be provided using --trusted-root when using --new-bundle-format") - } - if c.TSACertChainPath != "" { - return fmt.Errorf("unsupported: TSA certificate chain path may only be provided using --trusted-root when using --new-bundle-format") - } - return nil -} diff --git a/cmd/cosign/cli/verify/verify_attestation_test.go b/cmd/cosign/cli/verify/verify_attestation_test.go index ee3c0d99659..23288390acc 100644 --- a/cmd/cosign/cli/verify/verify_attestation_test.go +++ b/cmd/cosign/cli/verify/verify_attestation_test.go @@ -18,7 +18,7 @@ import ( "context" "testing" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" ) func TestVerifyAttestationMissingSubject(t *testing.T) { diff --git a/cmd/cosign/cli/verify/verify_blob.go b/cmd/cosign/cli/verify/verify_blob.go index 926ad71fe48..bfe73b965f0 100644 --- a/cmd/cosign/cli/verify/verify_blob.go +++ b/cmd/cosign/cli/verify/verify_blob.go @@ -31,19 +31,14 @@ import ( "path/filepath" "strings" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/rekor" - "github.com/sigstore/cosign/v2/internal/ui" - "github.com/sigstore/cosign/v2/pkg/blob" - "github.com/sigstore/cosign/v2/pkg/cosign" - "github.com/sigstore/cosign/v2/pkg/cosign/bundle" - "github.com/sigstore/cosign/v2/pkg/cosign/env" - "github.com/sigstore/cosign/v2/pkg/cosign/pivkey" - "github.com/sigstore/cosign/v2/pkg/cosign/pkcs11key" - "github.com/sigstore/cosign/v2/pkg/oci/static" - sigs "github.com/sigstore/cosign/v2/pkg/signature" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/internal/ui" + "github.com/sigstore/cosign/v3/pkg/blob" + "github.com/sigstore/cosign/v3/pkg/cosign" + "github.com/sigstore/cosign/v3/pkg/cosign/bundle" + "github.com/sigstore/cosign/v3/pkg/oci/static" + sigs "github.com/sigstore/cosign/v3/pkg/signature" sgbundle "github.com/sigstore/sigstore-go/pkg/bundle" - "github.com/sigstore/sigstore-go/pkg/root" sgverify "github.com/sigstore/sigstore-go/pkg/verify" "github.com/sigstore/sigstore/pkg/cryptoutils" @@ -74,10 +69,16 @@ type VerifyBlobCmd struct { Offline bool UseSignedTimestamps bool IgnoreTlog bool + HashAlgorithm crypto.Hash } // nolint func (c *VerifyBlobCmd) Exec(ctx context.Context, blobRef string) error { + // always default to sha256 if the algorithm hasn't been explicitly set + if c.HashAlgorithm == 0 { + c.HashAlgorithm = crypto.SHA256 + } + // Require a certificate/key OR a local bundle file that has the cert. if options.NOf(c.KeyRef, c.CertRef, c.Sk, c.BundlePath) == 0 { return fmt.Errorf("provide a key with --key or --sk, a certificate to verify against with --certificate, or a bundle with --bundle") @@ -108,64 +109,28 @@ func (c *VerifyBlobCmd) Exec(ctx context.Context, blobRef string) error { Offline: c.Offline, IgnoreTlog: c.IgnoreTlog, UseSignedTimestamps: c.TSACertChainPath != "" || c.UseSignedTimestamps, - NewBundleFormat: c.KeyOpts.NewBundleFormat || checkNewBundle(c.BundlePath), + NewBundleFormat: c.KeyOpts.NewBundleFormat && checkNewBundle(c.BundlePath), } // Keys are optional! + var closeSV func() var cert *x509.Certificate - opts := make([]static.Option, 0) - switch { - case c.KeyRef != "": - co.SigVerifier, err = sigs.PublicKeyFromKeyRef(ctx, c.KeyRef) - if err != nil { - return fmt.Errorf("loading public key: %w", err) - } - pkcs11Key, ok := co.SigVerifier.(*pkcs11key.Key) - if ok { - defer pkcs11Key.Close() - } - case c.Sk: - sk, err := pivkey.GetKeyWithSlot(c.Slot) - if err != nil { - return fmt.Errorf("opening piv token: %w", err) - } - defer sk.Close() - co.SigVerifier, err = sk.Verifier() - if err != nil { - return fmt.Errorf("loading public key from token: %w", err) - } - case c.CertRef != "": - cert, err = loadCertFromFileOrURL(c.CertRef) - if err != nil { - return err - } + co.SigVerifier, cert, closeSV, err = LoadVerifierFromKeyOrCert(ctx, c.KeyRef, c.Slot, c.CertRef, "", c.HashAlgorithm, c.Sk, true, co) + if err != nil { + return fmt.Errorf("loading verifier from key opts: %w", err) } + defer closeSV() - if c.TrustedRootPath != "" { - co.TrustedMaterial, err = root.NewTrustedRootFromPath(c.TrustedRootPath) - if err != nil { - return fmt.Errorf("loading trusted root: %w", err) - } - } else if options.NOf(c.CertChain, c.CARoots, c.CAIntermediates, c.TSACertChainPath) == 0 && - env.Getenv(env.VariableSigstoreCTLogPublicKeyFile) == "" && - env.Getenv(env.VariableSigstoreRootFile) == "" && - env.Getenv(env.VariableSigstoreRekorPublicKey) == "" && - env.Getenv(env.VariableSigstoreTSACertificateFile) == "" { - co.TrustedMaterial, err = cosign.TrustedRoot() - if err != nil { - ui.Warnf(ctx, "Could not fetch trusted_root.json from the TUF repository. Continuing with individual targets. Error from TUF: %v", err) - } + err = SetTrustedMaterial(ctx, c.TrustedRootPath, c.CertChain, c.CARoots, c.CAIntermediates, c.TSACertChainPath, co) + if err != nil { + return fmt.Errorf("setting trusted material: %w", err) } - if co.NewBundleFormat { - if options.NOf(c.RFC3161TimestampPath, c.TSACertChainPath, c.CertChain, c.CARoots, c.CAIntermediates, c.CertRef, c.SigRef, c.SCTRef) > 0 { - return fmt.Errorf("when using --new-bundle-format, please supply signed content with --bundle and verification content with --trusted-root") - } - - if co.TrustedMaterial == nil { - return fmt.Errorf("trusted root is required when using new bundle format") - } + if err = CheckSigstoreBundleUnsupportedOptions(*c, co); err != nil { + return err + } + if co.NewBundleFormat { bundle, err := sgbundle.LoadJSONFromPath(c.BundlePath) if err != nil { return err @@ -205,39 +170,13 @@ func (c *VerifyBlobCmd) Exec(ctx context.Context, blobRef string) error { } else if c.RFC3161TimestampPath == "" && co.UseSignedTimestamps { return fmt.Errorf("when specifying --use-signed-timestamps or --timestamp-certificate-chain, you must also specify --rfc3161-timestamp-path") } - if co.UseSignedTimestamps && co.TrustedMaterial == nil { - tsaCertificates, err := cosign.GetTSACerts(ctx, c.TSACertChainPath, cosign.GetTufTargets) - if err != nil { - return fmt.Errorf("unable to load TSA certificates: %w", err) - } - co.TSACertificate = tsaCertificates.LeafCert - co.TSARootCertificates = tsaCertificates.RootCert - co.TSAIntermediateCertificates = tsaCertificates.IntermediateCerts - } - if !c.IgnoreTlog { - if c.RekorURL != "" { - rekorClient, err := rekor.NewClient(c.RekorURL) - if err != nil { - return fmt.Errorf("creating Rekor client: %w", err) - } - co.RekorClient = rekorClient - } - if co.TrustedMaterial == nil { - // This performs an online fetch of the Rekor public keys, but this is needed - // for verifying tlog entries (both online and offline). - co.RekorPubKeys, err = cosign.GetRekorPubs(ctx) - if err != nil { - return fmt.Errorf("getting Rekor public keys: %w", err) - } - } + err = SetLegacyClientsAndKeys(ctx, c.IgnoreTlog, shouldVerifySCT(c.IgnoreSCT, c.KeyRef, c.Sk), keylessVerification(c.KeyRef, c.Sk), c.RekorURL, c.TSACertChainPath, c.CertChain, c.CARoots, c.CAIntermediates, co) + if err != nil { + return fmt.Errorf("setting up clients and keys: %w", err) } - if co.TrustedMaterial == nil && keylessVerification(c.KeyRef, c.Sk) { - if err := loadCertsKeylessVerification(c.CertChain, c.CARoots, c.CAIntermediates, co); err != nil { - return err - } - } + opts := make([]static.Option, 0) if c.BundlePath != "" { b, err := cosign.FetchLocalSignedPayloadFromPath(c.BundlePath) if err != nil { @@ -330,14 +269,6 @@ func (c *VerifyBlobCmd) Exec(ctx context.Context, blobRef string) error { opts = append(opts, static.WithCertChain(certPEM, chainPEM)) } - // Ignore Signed Certificate Timestamp if the flag is set or a key is provided - if co.TrustedMaterial == nil && shouldVerifySCT(c.IgnoreSCT, c.KeyRef, c.Sk) { - co.CTLogPubKeys, err = cosign.GetCTLogPubs(ctx) - if err != nil { - return fmt.Errorf("getting ctlog public keys: %w", err) - } - } - sig, err := base64signature(c.SigRef, c.BundlePath) if err != nil { return err diff --git a/cmd/cosign/cli/verify/verify_blob_attestation.go b/cmd/cosign/cli/verify/verify_blob_attestation.go index 3968ee653c8..8ca38177baf 100644 --- a/cmd/cosign/cli/verify/verify_blob_attestation.go +++ b/cmd/cosign/cli/verify/verify_blob_attestation.go @@ -18,7 +18,6 @@ package verify import ( "context" "crypto" - "crypto/sha256" "crypto/x509" "encoding/base64" "encoding/hex" @@ -30,22 +29,17 @@ import ( "path/filepath" v1 "github.com/google/go-containerregistry/pkg/v1" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/rekor" - internal "github.com/sigstore/cosign/v2/internal/pkg/cosign" - payloadsize "github.com/sigstore/cosign/v2/internal/pkg/cosign/payload/size" - "github.com/sigstore/cosign/v2/internal/ui" - "github.com/sigstore/cosign/v2/pkg/blob" - "github.com/sigstore/cosign/v2/pkg/cosign" - "github.com/sigstore/cosign/v2/pkg/cosign/bundle" - "github.com/sigstore/cosign/v2/pkg/cosign/env" - "github.com/sigstore/cosign/v2/pkg/cosign/pivkey" - "github.com/sigstore/cosign/v2/pkg/cosign/pkcs11key" - "github.com/sigstore/cosign/v2/pkg/oci/static" - "github.com/sigstore/cosign/v2/pkg/policy" - sigs "github.com/sigstore/cosign/v2/pkg/signature" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + internal "github.com/sigstore/cosign/v3/internal/pkg/cosign" + payloadsize "github.com/sigstore/cosign/v3/internal/pkg/cosign/payload/size" + "github.com/sigstore/cosign/v3/internal/ui" + "github.com/sigstore/cosign/v3/pkg/blob" + "github.com/sigstore/cosign/v3/pkg/cosign" + "github.com/sigstore/cosign/v3/pkg/cosign/bundle" + "github.com/sigstore/cosign/v3/pkg/oci/static" + "github.com/sigstore/cosign/v3/pkg/policy" + sigs "github.com/sigstore/cosign/v3/pkg/signature" sgbundle "github.com/sigstore/sigstore-go/pkg/bundle" - "github.com/sigstore/sigstore-go/pkg/root" sgverify "github.com/sigstore/sigstore-go/pkg/verify" "github.com/sigstore/sigstore/pkg/cryptoutils" ) @@ -80,8 +74,9 @@ type VerifyBlobAttestationCommand struct { SignaturePath string // Path to the signature UseSignedTimestamps bool - Digest string - DigestAlg string + Digest string + DigestAlg string + HashAlgorithm crypto.Hash } // Exec runs the verification command @@ -90,6 +85,11 @@ func (c *VerifyBlobAttestationCommand) Exec(ctx context.Context, artifactPath st return fmt.Errorf("please specify path to the DSSE envelope signature via --signature or --bundle") } + // always default to sha256 if the algorithm hasn't been explicitly set + if c.HashAlgorithm == 0 { + c.HashAlgorithm = crypto.SHA256 + } + // Require a certificate/key OR a local bundle file that has the cert. if options.NOf(c.KeyRef, c.CertRef, c.Sk, c.BundlePath) == 0 { return fmt.Errorf("provide a key with --key or --sk, a certificate to verify against with --certificate, or a bundle with --bundle") @@ -119,41 +119,17 @@ func (c *VerifyBlobAttestationCommand) Exec(ctx context.Context, artifactPath st Offline: c.Offline, IgnoreTlog: c.IgnoreTlog, UseSignedTimestamps: c.TSACertChainPath != "" || c.UseSignedTimestamps, - NewBundleFormat: c.NewBundleFormat || checkNewBundle(c.BundlePath), + NewBundleFormat: c.NewBundleFormat && checkNewBundle(c.BundlePath), } // Keys are optional! + var closeSV func() var cert *x509.Certificate - opts := make([]static.Option, 0) - switch { - case c.KeyRef != "": - co.SigVerifier, err = sigs.PublicKeyFromKeyRef(ctx, c.KeyRef) - if err != nil { - return fmt.Errorf("loading public key: %w", err) - } - pkcs11Key, ok := co.SigVerifier.(*pkcs11key.Key) - if ok { - defer pkcs11Key.Close() - } - case c.Sk: - sk, err := pivkey.GetKeyWithSlot(c.Slot) - if err != nil { - return fmt.Errorf("opening piv token: %w", err) - } - defer sk.Close() - co.SigVerifier, err = sk.Verifier() - if err != nil { - return fmt.Errorf("loading public key from token: %w", err) - } - case c.CertRef != "": - cert, err = loadCertFromFileOrURL(c.CertRef) - if err != nil { - return err - } - case c.CARoots != "": - // CA roots + possible intermediates are already loaded into co.RootCerts with the call to - // loadCertsKeylessVerification above. + co.SigVerifier, cert, closeSV, err = LoadVerifierFromKeyOrCert(ctx, c.KeyRef, c.Slot, c.CertRef, "", c.HashAlgorithm, c.Sk, true, co) + if err != nil { + return fmt.Errorf("loading verifier from key opts: %w", err) } + defer closeSV() var h v1.Hash var digest []byte @@ -178,7 +154,7 @@ func (c *VerifyBlobAttestationCommand) Exec(ctx context.Context, artifactPath st return err } - payload = internal.NewHashReader(f, sha256.New()) + payload = internal.NewHashReader(f, crypto.SHA256) if _, err := io.ReadAll(&payload); err != nil { return err } @@ -200,37 +176,29 @@ func (c *VerifyBlobAttestationCommand) Exec(ctx context.Context, artifactPath st co.ClaimVerifier = cosign.IntotoSubjectClaimVerifier } - if c.TrustedRootPath != "" { - co.TrustedMaterial, err = root.NewTrustedRootFromPath(c.TrustedRootPath) - if err != nil { - return fmt.Errorf("loading trusted root: %w", err) - } - } else if options.NOf(c.CertChain, c.CARoots, c.CAIntermediates, c.TSACertChainPath) == 0 && - env.Getenv(env.VariableSigstoreCTLogPublicKeyFile) == "" && - env.Getenv(env.VariableSigstoreRootFile) == "" && - env.Getenv(env.VariableSigstoreRekorPublicKey) == "" && - env.Getenv(env.VariableSigstoreTSACertificateFile) == "" { - co.TrustedMaterial, err = cosign.TrustedRoot() - if err != nil { - ui.Warnf(ctx, "Could not fetch trusted_root.json from the TUF repository. Continuing with individual targets. Error from TUF: %v", err) - } + err = SetTrustedMaterial(ctx, c.TrustedRootPath, c.CertChain, c.CARoots, c.CAIntermediates, c.TSACertChainPath, co) + if err != nil { + return fmt.Errorf("setting trusted material: %w", err) } - if co.NewBundleFormat { - if options.NOf(c.RFC3161TimestampPath, c.TSACertChainPath, c.CertChain, c.CARoots, c.CAIntermediates, c.CertRef, c.SCTRef) > 0 { - return fmt.Errorf("when using --new-bundle-format, please supply signed content with --bundle and verification content with --trusted-root") - } - - if co.TrustedMaterial == nil { - return fmt.Errorf("trusted root is required when using new bundle format") - } + if err = CheckSigstoreBundleUnsupportedOptions(*c, co); err != nil { + return err + } + if co.NewBundleFormat { bundle, err := sgbundle.LoadJSONFromPath(c.BundlePath) if err != nil { return err } - _, err = cosign.VerifyNewBundle(ctx, co, sgverify.WithArtifactDigest(h.Algorithm, digest), bundle) + var policyOpt sgverify.ArtifactPolicyOption + if c.CheckClaims { + policyOpt = sgverify.WithArtifactDigest(h.Algorithm, digest) + } else { + policyOpt = sgverify.WithoutArtifactUnsafe() + } + + _, err = cosign.VerifyNewBundle(ctx, co, policyOpt, bundle) if err != nil { return err } @@ -247,45 +215,10 @@ func (c *VerifyBlobAttestationCommand) Exec(ctx context.Context, artifactPath st } else if c.RFC3161TimestampPath == "" && co.UseSignedTimestamps { return fmt.Errorf("when specifying --use-signed-timestamps or --timestamp-certificate-chain, you must also specify --rfc3161-timestamp-path") } - if co.UseSignedTimestamps && co.TrustedMaterial == nil { - tsaCertificates, err := cosign.GetTSACerts(ctx, c.TSACertChainPath, cosign.GetTufTargets) - if err != nil { - return fmt.Errorf("unable to load TSA certificates: %w", err) - } - co.TSACertificate = tsaCertificates.LeafCert - co.TSARootCertificates = tsaCertificates.RootCert - co.TSAIntermediateCertificates = tsaCertificates.IntermediateCerts - } - if !c.IgnoreTlog { - if c.RekorURL != "" { - rekorClient, err := rekor.NewClient(c.RekorURL) - if err != nil { - return fmt.Errorf("creating Rekor client: %w", err) - } - co.RekorClient = rekorClient - } - if co.TrustedMaterial == nil { - // This performs an online fetch of the Rekor public keys, but this is needed - // for verifying tlog entries (both online and offline). - co.RekorPubKeys, err = cosign.GetRekorPubs(ctx) - if err != nil { - return fmt.Errorf("getting Rekor public keys: %w", err) - } - } - } - if co.TrustedMaterial == nil && keylessVerification(c.KeyRef, c.Sk) { - if err := loadCertsKeylessVerification(c.CertChain, c.CARoots, c.CAIntermediates, co); err != nil { - return err - } - } - - // Ignore Signed Certificate Timestamp if the flag is set or a key is provided - if co.TrustedMaterial == nil && shouldVerifySCT(c.IgnoreSCT, c.KeyRef, c.Sk) { - co.CTLogPubKeys, err = cosign.GetCTLogPubs(ctx) - if err != nil { - return fmt.Errorf("getting ctlog public keys: %w", err) - } + err = SetLegacyClientsAndKeys(ctx, c.IgnoreTlog, shouldVerifySCT(c.IgnoreSCT, c.KeyRef, c.Sk), keylessVerification(c.KeyRef, c.Sk), c.RekorURL, c.TSACertChainPath, c.CertChain, c.CARoots, c.CAIntermediates, co) + if err != nil { + return fmt.Errorf("setting up clients and keys: %w", err) } var encodedSig []byte @@ -296,6 +229,7 @@ func (c *VerifyBlobAttestationCommand) Exec(ctx context.Context, artifactPath st } } + opts := make([]static.Option, 0) if c.BundlePath != "" { b, err := cosign.FetchLocalSignedPayloadFromPath(c.BundlePath) if err != nil { diff --git a/cmd/cosign/cli/verify/verify_blob_attestation_test.go b/cmd/cosign/cli/verify/verify_blob_attestation_test.go index ed2e24183ca..aba94036aec 100644 --- a/cmd/cosign/cli/verify/verify_blob_attestation_test.go +++ b/cmd/cosign/cli/verify/verify_blob_attestation_test.go @@ -25,8 +25,8 @@ import ( protodsse "github.com/sigstore/protobuf-specs/gen/pb-go/dsse" "google.golang.org/protobuf/encoding/protojson" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/pkg/cosign/bundle" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/pkg/cosign/bundle" ) const pubkey = `-----BEGIN PUBLIC KEY----- @@ -185,6 +185,7 @@ func TestVerifyBlobAttestationNoCheckClaims(t *testing.T) { description string blobPath string signature string + bundlePath string }{ { description: "verify a predicate", @@ -198,6 +199,11 @@ func TestVerifyBlobAttestationNoCheckClaims(t *testing.T) { signature: blobSLSAProvenanceSignature, // This works because we're not checking the claims. It doesn't matter what we put in here - it should pass so long as the DSSE signagure can be verified. blobPath: anotherBlobPath, + }, { + description: "verify a predicate with a bundle with another blob path", + // From blobSLSAProvenanceSignature + bundlePath: makeLocalAttestNewBundle(t, "eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjAuMSIsInByZWRpY2F0ZVR5cGUiOiJodHRwczovL3Nsc2EuZGV2L3Byb3ZlbmFuY2UvdjAuMiIsInN1YmplY3QiOlt7Im5hbWUiOiJibG9iIiwiZGlnZXN0Ijp7InNoYTI1NiI6IjY1ODc4MWNkNGVkOWJjYTYwZGFjZDA5ZjdiYjkxNGJiNTE1MDJlOGI1ZDYxOWY1N2YzOWExZDY1MjU5NmNjMjQifX1dLCJwcmVkaWNhdGUiOnsiYnVpbGRlciI6eyJpZCI6IjIifSwiYnVpbGRUeXBlIjoieCIsImludm9jYXRpb24iOnsiY29uZmlnU291cmNlIjp7fX19fQ==", "application/vnd.in-toto+json", "MEUCIA8KjZqkrt90fzBojSwwtj3Bqb41E6ruxQk97TLnpzdYAiEAzOAjOTzyvTHqbpFDAn6zhrg6EZv7kxK5faRoVGYMh2c="), + blobPath: anotherBlobPath, }, { description: "verify a predicate with /dev/null", signature: blobSLSAProvenanceSignature, @@ -220,6 +226,11 @@ func TestVerifyBlobAttestationNoCheckClaims(t *testing.T) { CheckClaims: false, PredicateType: "slsaprovenance", } + if test.bundlePath != "" { + cmd.BundlePath = test.bundlePath + cmd.NewBundleFormat = true + cmd.TrustedRootPath = writeTrustedRootFile(t, td, "{\"mediaType\":\"application/vnd.dev.sigstore.trustedroot+json;version=0.1\"}") + } if err := cmd.Exec(ctx, test.blobPath); err != nil { t.Fatalf("verifyBlobAttestation()= %v", err) } diff --git a/cmd/cosign/cli/verify/verify_blob_test.go b/cmd/cosign/cli/verify/verify_blob_test.go index 0e54449dd93..b219d3166bb 100644 --- a/cmd/cosign/cli/verify/verify_blob_test.go +++ b/cmd/cosign/cli/verify/verify_blob_test.go @@ -37,14 +37,14 @@ import ( "github.com/cyberphone/json-canonicalization/go/src/webpki.org/jsoncanonicalizer" "github.com/go-openapi/runtime" - "github.com/go-openapi/swag" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/internal/pkg/cosign/tsa/mock" - "github.com/sigstore/cosign/v2/pkg/cosign" - "github.com/sigstore/cosign/v2/pkg/cosign/bundle" - sigs "github.com/sigstore/cosign/v2/pkg/signature" - ctypes "github.com/sigstore/cosign/v2/pkg/types" - "github.com/sigstore/cosign/v2/test" + "github.com/go-openapi/swag/conv" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/internal/pkg/cosign/tsa/mock" + "github.com/sigstore/cosign/v3/internal/test" + "github.com/sigstore/cosign/v3/pkg/cosign" + "github.com/sigstore/cosign/v3/pkg/cosign/bundle" + sigs "github.com/sigstore/cosign/v3/pkg/signature" + ctypes "github.com/sigstore/cosign/v3/pkg/types" protobundle "github.com/sigstore/protobuf-specs/gen/pb-go/bundle/v1" protocommon "github.com/sigstore/protobuf-specs/gen/pb-go/common/v1" "github.com/sigstore/rekor/pkg/generated/models" @@ -162,6 +162,18 @@ func TestVerifyBlob(t *testing.T) { time.Now().Add(-time.Hour), leafPriv, rootCert, rootPriv) expiredLeafPem, _ := cryptoutils.MarshalCertificateToPEM(expiredLeafCert) + unrelatedPriv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + t.Fatal(err) + } + unrelatedSigner, err := signature.LoadECDSASignerVerifier(unrelatedPriv, crypto.SHA256) + if err != nil { + t.Fatal(err) + } + unrelatedLeafCert, _ := test.GenerateLeafCertWithExpiration(identity, issuer, + time.Now(), unrelatedPriv, rootCert, rootPriv) + unrelatedCertPem, _ := cryptoutils.MarshalCertificateToPEM(unrelatedLeafCert) + // Make rekor signer rekorPriv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { @@ -178,7 +190,7 @@ func TestVerifyBlob(t *testing.T) { tmpRekorPubFile := writeBlobFile(t, td, string(pemRekor), "rekor_pub.key") t.Setenv("SIGSTORE_REKOR_PUBLIC_KEY", tmpRekorPubFile) - var makeSignature = func(blob []byte) string { + var makeSignature = func(blob []byte, signer signature.SignerVerifier) string { sig, err := signer.SignMessage(bytes.NewReader(blob)) if err != nil { t.Fatal(err) @@ -186,10 +198,12 @@ func TestVerifyBlob(t *testing.T) { return string(sig) } blobBytes := []byte("foo") - blobSignature := makeSignature(blobBytes) + blobSignature := makeSignature(blobBytes, signer) otherBytes := []byte("bar") - otherSignature := makeSignature(otherBytes) + otherSignature := makeSignature(otherBytes, signer) + + unrelatedSignature := makeSignature(blobBytes, unrelatedSigner) // initialize timestamp for expired and unexpired certificates expiredTSAOpts := mock.TSAClientOptions{Time: time.Now().Add(-time.Hour), Message: []byte(blobSignature)} @@ -300,18 +314,27 @@ func TestVerifyBlob(t *testing.T) { { name: "valid signature with public key - bad bundle cert mismatch", blob: blobBytes, + signature: unrelatedSignature, + key: pubKeyBytes, + bundlePath: makeLocalBundle(t, *rekorSigner, blobBytes, []byte(unrelatedSignature), + unrelatedCertPem, true), + shouldErr: true, + }, + { + name: "valid signature with public key and bundle cert derived from public key", + blob: blobBytes, signature: blobSignature, key: pubKeyBytes, bundlePath: makeLocalBundle(t, *rekorSigner, blobBytes, []byte(blobSignature), unexpiredCertPem, true), - shouldErr: true, + shouldErr: false, }, { name: "valid signature with public key - bad bundle signature mismatch", blob: blobBytes, signature: blobSignature, key: pubKeyBytes, - bundlePath: makeLocalBundle(t, *rekorSigner, blobBytes, []byte(makeSignature(blobBytes)), + bundlePath: makeLocalBundle(t, *rekorSigner, blobBytes, []byte(makeSignature(blobBytes, signer)), pubKeyBytes, true), shouldErr: true, }, @@ -365,21 +388,12 @@ func TestVerifyBlob(t *testing.T) { cert: unexpiredLeafCert, shouldErr: true, }, - { - name: "valid signature with unexpired certificate - bad bundle cert mismatch", - blob: blobBytes, - signature: blobSignature, - key: pubKeyBytes, - bundlePath: makeLocalBundle(t, *rekorSigner, blobBytes, []byte(blobSignature), - unexpiredCertPem, true), - shouldErr: true, - }, { name: "valid signature with unexpired certificate - bad bundle signature mismatch", blob: blobBytes, signature: blobSignature, cert: unexpiredLeafCert, - bundlePath: makeLocalBundle(t, *rekorSigner, blobBytes, []byte(makeSignature(blobBytes)), + bundlePath: makeLocalBundle(t, *rekorSigner, blobBytes, []byte(makeSignature(blobBytes, signer)), unexpiredCertPem, true), shouldErr: true, }, @@ -701,9 +715,9 @@ func makeRekorEntry(t *testing.T, rekorSigner signature.ECDSASignerVerifier, } e := models.LogEntryAnon{ Body: base64.StdEncoding.EncodeToString(leaf), - IntegratedTime: swag.Int64(integratedTime.Unix()), - LogIndex: swag.Int64(0), - LogID: swag.String(logID), + IntegratedTime: conv.Pointer(integratedTime.Unix()), + LogIndex: conv.Pointer(int64(0)), + LogID: conv.Pointer(logID), } // Marshal payload, sign, and set SET in Bundle jsonPayload, err := json.Marshal(e) @@ -723,9 +737,9 @@ func makeRekorEntry(t *testing.T, rekorSigner signature.ECDSASignerVerifier, e.Verification = &models.LogEntryAnonVerification{ SignedEntryTimestamp: bundleSig, InclusionProof: &models.InclusionProof{ - LogIndex: swag.Int64(0), - TreeSize: swag.Int64(1), - RootHash: swag.String(hex.EncodeToString(uuid)), + LogIndex: conv.Pointer(int64(0)), + TreeSize: conv.Pointer(int64(1)), + RootHash: conv.Pointer(hex.EncodeToString(uuid)), Hashes: []string{}, }, } diff --git a/cmd/cosign/cli/verify/verify_bundle.go b/cmd/cosign/cli/verify/verify_bundle.go index 3d876f9a5c5..ab43fb2b44a 100644 --- a/cmd/cosign/cli/verify/verify_bundle.go +++ b/cmd/cosign/cli/verify/verify_bundle.go @@ -35,7 +35,7 @@ import ( "github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/sigstore/sigstore/pkg/signature" - "github.com/sigstore/cosign/v2/pkg/cosign" + "github.com/sigstore/cosign/v3/pkg/cosign" ) func checkNewBundle(bundlePath string) bool { diff --git a/cmd/cosign/cli/verify/verify_test.go b/cmd/cosign/cli/verify/verify_test.go index 620c841b6f9..020272711d3 100644 --- a/cmd/cosign/cli/verify/verify_test.go +++ b/cmd/cosign/cli/verify/verify_test.go @@ -35,13 +35,13 @@ import ( "testing" "github.com/google/go-containerregistry/pkg/name" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/internal/pkg/cosign/fulcio/fulcioroots" - "github.com/sigstore/cosign/v2/internal/ui" - "github.com/sigstore/cosign/v2/pkg/cosign" - "github.com/sigstore/cosign/v2/pkg/oci" - "github.com/sigstore/cosign/v2/pkg/oci/static" - "github.com/sigstore/cosign/v2/test" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/internal/pkg/cosign/fulcio/fulcioroots" + "github.com/sigstore/cosign/v3/internal/test" + "github.com/sigstore/cosign/v3/internal/ui" + "github.com/sigstore/cosign/v3/pkg/cosign" + "github.com/sigstore/cosign/v3/pkg/oci" + "github.com/sigstore/cosign/v3/pkg/oci/static" "github.com/sigstore/sigstore/pkg/signature/payload" "github.com/stretchr/testify/assert" ) @@ -346,3 +346,53 @@ func TestLoadCertsKeylessVerification(t *testing.T) { }) } } +func TestTransformOutputSuccess(t *testing.T) { + // Build minimal in-toto statement + stmt := `{ + "_type": "https://in-toto.io/Statement/v0.1", + "subject": [ + { "name": "artifact", "digest": { "sha256": "deadbeef" }, "annotations": { "foo": "bar" } } + ], + "predicateType": "https://slsa.dev/provenance/v0.2" + }` + // DSSE payloadType for in-toto + payloadType := "application/vnd.in-toto+json" + encodedStmt := base64.StdEncoding.EncodeToString([]byte(stmt)) + dsseEnv := fmt.Sprintf(`{ + "payloadType": "%s", + "payload": "%s", + "signatures": [ + { "keyid": "test", "sig": "MAo=" } + ] + }`, payloadType, encodedStmt) + + sig, err := static.NewSignature([]byte(dsseEnv), "") + if err != nil { + t.Fatalf("creating static signature: %v", err) + } + fmt.Println(dsseEnv) + + name := "example.com/my/image" + out, err := transformOutput([]oci.Signature{sig}, name) + if err != nil { + t.Fatalf("transformOutput returned error: %v", err) + } + if len(out) != 1 { + t.Fatalf("expected 1 transformed signature, got %d", len(out)) + } + + payloadBytes, err := out[0].Payload() + if err != nil { + t.Fatalf("reading transformed payload: %v", err) + } + + var sci payload.SimpleContainerImage + if err := json.Unmarshal(payloadBytes, &sci); err != nil { + t.Fatalf("unmarshal transformed payload: %v", err) + } + + assert.Equal(t, name, sci.Critical.Identity.DockerReference, "docker reference mismatch") + assert.Equal(t, "sha256:deadbeef", sci.Critical.Image.DockerManifestDigest, "digest mismatch") + assert.Equal(t, "https://slsa.dev/provenance/v0.2", sci.Critical.Type, "type mismatch") + assert.Equal(t, map[string]any{"foo": "bar"}, sci.Optional, "missing annotation") +} diff --git a/cmd/cosign/errors/exit_code_lookup.go b/cmd/cosign/errors/exit_code_lookup.go index 93d097ab79a..7b038d5a9fa 100644 --- a/cmd/cosign/errors/exit_code_lookup.go +++ b/cmd/cosign/errors/exit_code_lookup.go @@ -18,7 +18,7 @@ package errors import ( "errors" - cosignError "github.com/sigstore/cosign/v2/pkg/cosign" + cosignError "github.com/sigstore/cosign/v3/pkg/cosign" ) func LookupExitCodeForError(err interface{ error }) int { diff --git a/cmd/cosign/errors/exit_code_lookup_test.go b/cmd/cosign/errors/exit_code_lookup_test.go index 88ff7bef17c..edc2494cb6b 100644 --- a/cmd/cosign/errors/exit_code_lookup_test.go +++ b/cmd/cosign/errors/exit_code_lookup_test.go @@ -19,7 +19,7 @@ import ( "fmt" "testing" - pkgError "github.com/sigstore/cosign/v2/pkg/cosign" + pkgError "github.com/sigstore/cosign/v3/pkg/cosign" ) func TestDefaultExitCodeReturnIfErrorTypeToExitCodeMappingDoesNotExist(t *testing.T) { diff --git a/cmd/cosign/main.go b/cmd/cosign/main.go index 50edaefcecc..1f87be21333 100644 --- a/cmd/cosign/main.go +++ b/cmd/cosign/main.go @@ -22,9 +22,9 @@ import ( "os" "strings" - "github.com/sigstore/cosign/v2/cmd/cosign/cli" - cosignError "github.com/sigstore/cosign/v2/cmd/cosign/errors" - "github.com/sigstore/cosign/v2/internal/ui" + "github.com/sigstore/cosign/v3/cmd/cosign/cli" + cosignError "github.com/sigstore/cosign/v3/cmd/cosign/errors" + "github.com/sigstore/cosign/v3/internal/ui" // Register the provider-specific plugins _ "github.com/sigstore/sigstore/pkg/signature/kms/aws" diff --git a/cmd/help/main.go b/cmd/help/main.go index c91eb8b3bac..88e31e04277 100644 --- a/cmd/help/main.go +++ b/cmd/help/main.go @@ -18,9 +18,9 @@ import ( "fmt" "os" - "github.com/sigstore/cosign/v2/cmd/cosign/cli" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/templates" - errors "github.com/sigstore/cosign/v2/cmd/cosign/errors" + "github.com/sigstore/cosign/v3/cmd/cosign/cli" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/templates" + errors "github.com/sigstore/cosign/v3/cmd/cosign/errors" "github.com/spf13/cobra" "github.com/spf13/cobra/doc" ) diff --git a/doc/cosign_attach_signature.md b/doc/cosign_attach_signature.md index a0355876e0e..e9b00729deb 100644 --- a/doc/cosign_attach_signature.md +++ b/doc/cosign_attach_signature.md @@ -35,6 +35,7 @@ cosign attach signature [flags] --allow-http-registry whether to allow using HTTP protocol while connecting to registries. Don't use this for anything but testing --allow-insecure-registry whether to allow insecure connections to registries (e.g., with expired or self-signed TLS certificates). Don't use this for anything but testing --attachment-tag-prefix [AttachmentTagPrefix]sha256-[TargetImageDigest].[AttachmentName] optional custom prefix to use for attached image tags. Attachment images are tagged as: [AttachmentTagPrefix]sha256-[TargetImageDigest].[AttachmentName] + --bundle string path to bundle containing signature (alias for payload) --certificate string path to the X.509 certificate in PEM format to include in the OCI Signature --certificate-chain string path to a list of CA X.509 certificates in PEM format which will be needed when building the certificate chain for the signing certificate. Must start with the parent intermediate CA certificate of the signing certificate and end with the root certificate. Included in the OCI Signature -h, --help help for signature diff --git a/doc/cosign_attest-blob.md b/doc/cosign_attest-blob.md index 3a46e1fbafd..b4d73eb2d1c 100644 --- a/doc/cosign_attest-blob.md +++ b/doc/cosign_attest-blob.md @@ -34,16 +34,17 @@ cosign attest-blob [flags] ``` --bundle string write everything required to verify the blob to a FILE - --certificate string path to the X.509 certificate in PEM format to include in the OCI Signature - --certificate-chain string path to a list of CA X.509 certificates in PEM format which will be needed when building the certificate chain for the signing certificate. Must start with the parent intermediate CA certificate of the signing certificate and end with the root certificate. Included in the OCI Signature + --certificate string path to the X.509 certificate for signing attestation + --certificate-chain string path to a list of CA X.509 certificates in PEM format which will be needed when building the certificate chain for the signed attestation. Must start with the parent intermediate CA certificate of the signing certificate and end with the root certificate. --fulcio-auth-flow string fulcio interactive oauth2 flow to use for certificate from fulcio. Defaults to determining the flow based on the runtime environment. (options) normal|device|token|client_credentials --fulcio-url string address of sigstore PKI server (default "https://fulcio.sigstore.dev") --hash string hash of blob in hexadecimal (base16). Used if you want to sign an artifact stored elsewhere and have the hash -h, --help help for attest-blob --identity-token string identity token to use for certificate from fulcio. the token or a path to a file containing the token is accepted. --insecure-skip-verify skip verifying fulcio published to the SCT (this should only be used for testing). + --issue-certificate issue a code signing certificate from Fulcio, even if a key is provided --key string path to the private key file, KMS URI or Kubernetes Secret - --new-bundle-format output bundle in new format that contains all verification material + --new-bundle-format output bundle in new format that contains all verification material (default true) --oidc-client-id string OIDC client ID for application (default "sigstore") --oidc-client-secret-file string Path to file containing OIDC client secret for application --oidc-disable-ambient-providers Disable ambient OIDC providers. When true, ambient credentials will not be read @@ -57,6 +58,7 @@ cosign attest-blob [flags] --rekor-entry-type string specifies the type to be used for a rekor entry upload (dsse|intoto) (default "dsse") --rekor-url string address of rekor STL server (default "https://rekor.sigstore.dev") --rfc3161-timestamp-bundle string path to an RFC 3161 timestamp bundle FILE + --signing-config string path to a signing config file. Must provide --bundle, which will output verification material in the new format --sk whether to use a hardware security key --slot string security key slot to use for generated key (default: signature) (authentication|signature|card-authentication|key-management) --statement string path to the statement file. @@ -65,8 +67,9 @@ cosign attest-blob [flags] --timestamp-client-key string path to the X.509 private key file in PEM format to be used, together with the 'timestamp-client-cert' value, for the connection to the TSA Server --timestamp-server-name string SAN name to use as the 'ServerName' tls.Config field to verify the mTLS connection to the TSA Server --timestamp-server-url string url to the Timestamp RFC3161 server, default none. Must be the path to the API to request timestamp responses, e.g. https://freetsa.org/tsr - --tlog-upload whether or not to upload to the tlog (default true) + --trusted-root string optional path to a TrustedRoot JSON file to verify a signature after signing --type string specify a predicate type (slsaprovenance|slsaprovenance02|slsaprovenance1|link|spdx|spdxjson|cyclonedx|vuln|openvex|custom) or an URI (default "custom") + --use-signing-config whether to use a TUF-provided signing config for the service URLs. Must provide --bundle, which will output verification material in the new format (default true) -y, --yes skip confirmation prompts for non-destructive operations ``` diff --git a/doc/cosign_attest.md b/doc/cosign_attest.md index 5ad9f4e70f4..7beb3dbdf0b 100644 --- a/doc/cosign_attest.md +++ b/doc/cosign_attest.md @@ -51,6 +51,7 @@ cosign attest [flags] --allow-http-registry whether to allow using HTTP protocol while connecting to registries. Don't use this for anything but testing --allow-insecure-registry whether to allow insecure connections to registries (e.g., with expired or self-signed TLS certificates). Don't use this for anything but testing --attachment-tag-prefix [AttachmentTagPrefix]sha256-[TargetImageDigest].[AttachmentName] optional custom prefix to use for attached image tags. Attachment images are tagged as: [AttachmentTagPrefix]sha256-[TargetImageDigest].[AttachmentName] + --bundle string write everything required to verify the blob to a FILE --certificate string path to the X.509 certificate in PEM format to include in the OCI Signature --certificate-chain string path to a list of CA X.509 certificates in PEM format which will be needed when building the certificate chain for the signing certificate. Must start with the parent intermediate CA certificate of the signing certificate and end with the root certificate. Included in the OCI Signature --fulcio-auth-flow string fulcio interactive oauth2 flow to use for certificate from fulcio. Defaults to determining the flow based on the runtime environment. (options) normal|device|token|client_credentials @@ -58,9 +59,10 @@ cosign attest [flags] -h, --help help for attest --identity-token string identity token to use for certificate from fulcio. the token or a path to a file containing the token is accepted. --insecure-skip-verify skip verifying fulcio published to the SCT (this should only be used for testing). + --issue-certificate issue a code signing certificate from Fulcio, even if a key is provided --k8s-keychain whether to use the kubernetes keychain instead of the default keychain (supports workload identity). --key string path to the private key file, KMS URI or Kubernetes Secret - --new-bundle-format attach a Sigstore bundle using OCI referrers API + --new-bundle-format attach a Sigstore bundle using OCI referrers API (default true) --no-upload do not upload the generated attestation, but send the attestation output to STDOUT --oidc-client-id string OIDC client ID for application (default "sigstore") --oidc-client-secret-file string Path to file containing OIDC client secret for application @@ -80,6 +82,7 @@ cosign attest [flags] --rekor-entry-type string specifies the type to be used for a rekor entry upload (dsse|intoto) (default "dsse") --rekor-url string address of rekor STL server (default "https://rekor.sigstore.dev") --replace + --signing-config string path to a signing config file. Must provide --new-bundle-format, which will store verification material in the new format --sk whether to use a hardware security key --slot string security key slot to use for generated key (default: signature) (authentication|signature|card-authentication|key-management) --statement string path to the statement file. @@ -88,8 +91,9 @@ cosign attest [flags] --timestamp-client-key string path to the X.509 private key file in PEM format to be used, together with the 'timestamp-client-cert' value, for the connection to the TSA Server --timestamp-server-name string SAN name to use as the 'ServerName' tls.Config field to verify the mTLS connection to the TSA Server --timestamp-server-url string url to the Timestamp RFC3161 server, default none. Must be the path to the API to request timestamp responses, e.g. https://freetsa.org/tsr - --tlog-upload whether or not to upload to the tlog (default true) + --trusted-root string optional path to a TrustedRoot JSON file to verify a signature after signing --type string specify a predicate type (slsaprovenance|slsaprovenance02|slsaprovenance1|link|spdx|spdxjson|cyclonedx|vuln|openvex|custom) or an URI (default "custom") + --use-signing-config whether to use a TUF-provided signing config for the service URLs. Must set --new-bundle-format, which will store verification material in the new format (default true) -y, --yes skip confirmation prompts for non-destructive operations ``` diff --git a/doc/cosign_clean.md b/doc/cosign_clean.md index fba11ddce57..96f47c68a97 100644 --- a/doc/cosign_clean.md +++ b/doc/cosign_clean.md @@ -28,7 +28,7 @@ cosign clean [flags] --registry-server-name string SAN name to use as the 'ServerName' tls.Config field to verify the mTLS connection to the registry --registry-token string registry bearer auth token --registry-username string registry basic auth username - --type CLEAN_TYPE a type of clean: (sbom is deprecated) (default all) + --type CLEAN_TYPE a type of clean: (sbom is deprecated) (default all) ``` ### Options inherited from parent commands diff --git a/doc/cosign_dockerfile_verify.md b/doc/cosign_dockerfile_verify.md index 3ee9b0d34c0..c522e3c8915 100644 --- a/doc/cosign_dockerfile_verify.md +++ b/doc/cosign_dockerfile_verify.md @@ -69,7 +69,7 @@ cosign dockerfile verify [flags] --certificate-oidc-issuer string The OIDC issuer expected in a valid Fulcio certificate, e.g. https://token.actions.githubusercontent.com or https://oauth2.sigstore.dev/auth. Either --certificate-oidc-issuer or --certificate-oidc-issuer-regexp must be set for keyless flows. --certificate-oidc-issuer-regexp string A regular expression alternative to --certificate-oidc-issuer. Accepts the Go regular expression syntax described at https://golang.org/s/re2syntax. Either --certificate-oidc-issuer or --certificate-oidc-issuer-regexp must be set for keyless flows. --check-claims whether to check the claims found (default true) - --experimental-oci11 set to true to enable experimental OCI 1.1 behaviour + --experimental-oci11 set to true to enable experimental OCI 1.1 behaviour (unrelated to bundle format) -h, --help help for verify --insecure-ignore-sct when set, verification will not check that a certificate contains an embedded SCT, a proof of inclusion in a certificate transparency log --insecure-ignore-tlog ignore transparency log verification, to be used when an artifact signature has not been uploaded to the transparency log. Artifacts cannot be publicly verified when not included in a log @@ -77,8 +77,7 @@ cosign dockerfile verify [flags] --key string path to the public key file, KMS URI or Kubernetes Secret --local-image whether the specified image is a path to an image saved locally via 'cosign save' --max-workers int the amount of maximum workers for parallel executions (default 10) - --new-bundle-format expect the signature/attestation to be packaged in a Sigstore bundle - --offline only allow offline verification + --new-bundle-format expect the signature/attestation to be packaged in a Sigstore bundle (default true) -o, --output string output format for the signing image information (json|text) (default "json") --payload string payload path or remote URL --private-infrastructure skip transparency log verification when verifying artifacts in a privately deployed infrastructure diff --git a/doc/cosign_initialize.md b/doc/cosign_initialize.md index 1b927192696..287297dfc07 100644 --- a/doc/cosign_initialize.md +++ b/doc/cosign_initialize.md @@ -16,7 +16,7 @@ This will enable you to point cosign to a separate TUF root. Any updated TUF repository will be written to $HOME/.sigstore/root/. Trusted keys and certificate used in cosign verification (e.g. verifying Fulcio issued certificates -with Fulcio root CA) are pulled form the trusted metadata. +with Fulcio root CA) are pulled from the trusted metadata. ``` cosign initialize [flags] @@ -25,11 +25,14 @@ cosign initialize [flags] ### Examples ``` -cosign initialize --mirror --out +cosign initialize --mirror -# initialize root with distributed root keys, default mirror, and default out path. +# initialize root with distributed root keys, using the default mirror. cosign initialize +# initialize root with distributed root keys, using the staging mirror. +cosign initialize --staging + # initialize with an out-of-band root key file, using the default mirror. cosign initialize --root @@ -47,6 +50,7 @@ cosign initialize --mirror --root --root-checksum --mirror string GCS bucket to a SigStore TUF repository, or HTTP(S) base URL, or file:/// for local filestore remote (air-gap) (default "https://tuf-repo-cdn.sigstore.dev") --root string path to trusted initial root. defaults to embedded root --root-checksum string checksum of the initial root, required if root is downloaded via http(s). expects sha256 by default, can be changed to sha512 by providing sha512: + --staging use the staging TUF repository ``` ### Options inherited from parent commands diff --git a/doc/cosign_manifest_verify.md b/doc/cosign_manifest_verify.md index 0914e691f68..316a88ed827 100644 --- a/doc/cosign_manifest_verify.md +++ b/doc/cosign_manifest_verify.md @@ -63,7 +63,7 @@ cosign manifest verify [flags] --certificate-oidc-issuer string The OIDC issuer expected in a valid Fulcio certificate, e.g. https://token.actions.githubusercontent.com or https://oauth2.sigstore.dev/auth. Either --certificate-oidc-issuer or --certificate-oidc-issuer-regexp must be set for keyless flows. --certificate-oidc-issuer-regexp string A regular expression alternative to --certificate-oidc-issuer. Accepts the Go regular expression syntax described at https://golang.org/s/re2syntax. Either --certificate-oidc-issuer or --certificate-oidc-issuer-regexp must be set for keyless flows. --check-claims whether to check the claims found (default true) - --experimental-oci11 set to true to enable experimental OCI 1.1 behaviour + --experimental-oci11 set to true to enable experimental OCI 1.1 behaviour (unrelated to bundle format) -h, --help help for verify --insecure-ignore-sct when set, verification will not check that a certificate contains an embedded SCT, a proof of inclusion in a certificate transparency log --insecure-ignore-tlog ignore transparency log verification, to be used when an artifact signature has not been uploaded to the transparency log. Artifacts cannot be publicly verified when not included in a log @@ -71,8 +71,7 @@ cosign manifest verify [flags] --key string path to the public key file, KMS URI or Kubernetes Secret --local-image whether the specified image is a path to an image saved locally via 'cosign save' --max-workers int the amount of maximum workers for parallel executions (default 10) - --new-bundle-format expect the signature/attestation to be packaged in a Sigstore bundle - --offline only allow offline verification + --new-bundle-format expect the signature/attestation to be packaged in a Sigstore bundle (default true) -o, --output string output format for the signing image information (json|text) (default "json") --payload string payload path or remote URL --private-infrastructure skip transparency log verification when verifying artifacts in a privately deployed infrastructure diff --git a/doc/cosign_sign-blob.md b/doc/cosign_sign-blob.md index d78f9fb250e..05b94ad827c 100644 --- a/doc/cosign_sign-blob.md +++ b/doc/cosign_sign-blob.md @@ -38,6 +38,8 @@ cosign sign-blob [flags] ``` --b64 whether to base64 encode the output (default true) --bundle string write everything required to verify the blob to a FILE + --certificate string path to the X.509 certificate for signing attestation + --certificate-chain string path to a list of CA X.509 certificates in PEM format which will be needed when building the certificate chain for the signed attestation. Must start with the parent intermediate CA certificate of the signing certificate and end with the root certificate. --fulcio-auth-flow string fulcio interactive oauth2 flow to use for certificate from fulcio. Defaults to determining the flow based on the runtime environment. (options) normal|device|token|client_credentials --fulcio-url string address of sigstore PKI server (default "https://fulcio.sigstore.dev") -h, --help help for sign-blob @@ -45,7 +47,7 @@ cosign sign-blob [flags] --insecure-skip-verify skip verifying fulcio published to the SCT (this should only be used for testing). --issue-certificate issue a code signing certificate from Fulcio, even if a key is provided --key string path to the private key file, KMS URI or Kubernetes Secret - --new-bundle-format output bundle in new format that contains all verification material + --new-bundle-format output bundle in new format that contains all verification material (default true) --oidc-client-id string OIDC client ID for application (default "sigstore") --oidc-client-secret-file string Path to file containing OIDC client secret for application --oidc-disable-ambient-providers Disable ambient OIDC providers. When true, ambient credentials will not be read @@ -57,6 +59,8 @@ cosign sign-blob [flags] --output-signature string write the signature to FILE --rekor-url string address of rekor STL server (default "https://rekor.sigstore.dev") --rfc3161-timestamp string write the RFC3161 timestamp to a file + --signing-algorithm string signing algorithm to use for signing/hashing (allowed ecdsa-sha2-256-nistp256, ecdsa-sha2-384-nistp384, ecdsa-sha2-512-nistp521, rsa-sign-pkcs1-2048-sha256, rsa-sign-pkcs1-3072-sha256, rsa-sign-pkcs1-4096-sha256) (default "ecdsa-sha2-256-nistp256") + --signing-config string path to a signing config file. Must provide --bundle, which will output verification material in the new format --sk whether to use a hardware security key --slot string security key slot to use for generated key (default: signature) (authentication|signature|card-authentication|key-management) --timestamp-client-cacert string path to the X.509 CA certificate file in PEM format to be used for the connection to the TSA Server @@ -64,7 +68,8 @@ cosign sign-blob [flags] --timestamp-client-key string path to the X.509 private key file in PEM format to be used, together with the 'timestamp-client-cert' value, for the connection to the TSA Server --timestamp-server-name string SAN name to use as the 'ServerName' tls.Config field to verify the mTLS connection to the TSA Server --timestamp-server-url string url to the Timestamp RFC3161 server, default none. Must be the path to the API to request timestamp responses, e.g. https://freetsa.org/tsr - --tlog-upload whether or not to upload to the tlog (default true) + --trusted-root string optional path to a TrustedRoot JSON file to verify a signature after signing + --use-signing-config whether to use a TUF-provided signing config for the service URLs. Must provide --bundle, which will output verification material in the new format (default true) -y, --yes skip confirmation prompts for non-destructive operations ``` diff --git a/doc/cosign_sign.md b/doc/cosign_sign.md index 07c3bb98fa3..bb5049c760e 100644 --- a/doc/cosign_sign.md +++ b/doc/cosign_sign.md @@ -77,6 +77,7 @@ cosign sign [flags] -a, --annotations strings extra key=value pairs to sign --attachment string DEPRECATED, related image attachment to sign (sbom), default none --attachment-tag-prefix [AttachmentTagPrefix]sha256-[TargetImageDigest].[AttachmentName] optional custom prefix to use for attached image tags. Attachment images are tagged as: [AttachmentTagPrefix]sha256-[TargetImageDigest].[AttachmentName] + --bundle string write everything required to verify the image to FILE --certificate string path to the X.509 certificate in PEM format to include in the OCI Signature --certificate-chain string path to a list of CA X.509 certificates in PEM format which will be needed when building the certificate chain for the signing certificate. Must start with the parent intermediate CA certificate of the signing certificate and end with the root certificate. Included in the OCI Signature --fulcio-auth-flow string fulcio interactive oauth2 flow to use for certificate from fulcio. Defaults to determining the flow based on the runtime environment. (options) normal|device|token|client_credentials @@ -87,6 +88,7 @@ cosign sign [flags] --issue-certificate issue a code signing certificate from Fulcio, even if a key is provided --k8s-keychain whether to use the kubernetes keychain instead of the default keychain (supports workload identity). --key string path to the private key file, KMS URI or Kubernetes Secret + --new-bundle-format expect the signature/attestation to be packaged in a Sigstore bundle (default true) --oidc-client-id string OIDC client ID for application (default "sigstore") --oidc-client-secret-file string Path to file containing OIDC client secret for application --oidc-disable-ambient-providers Disable ambient OIDC providers. When true, ambient credentials will not be read @@ -108,7 +110,8 @@ cosign sign [flags] --registry-token string registry bearer auth token --registry-username string registry basic auth username --rekor-url string address of rekor STL server (default "https://rekor.sigstore.dev") - --sign-container-identity string manually set the .critical.docker-reference field for the signed identity, which is useful when image proxies are being used where the pull reference should match the signature + --sign-container-identity strings manually set the .critical.docker-reference field for the signed identity, which is useful when image proxies are being used where the pull reference should match the signature, this flag is comma delimited. ex: --sign-container-identity=identity1,identity2 + --signing-config string path to a signing config file. Must provide --new-bundle-format, which will store verification material in the new format --sk whether to use a hardware security key --slot string security key slot to use for generated key (default: signature) (authentication|signature|card-authentication|key-management) --timestamp-client-cacert string path to the X.509 CA certificate file in PEM format to be used for the connection to the TSA Server @@ -116,8 +119,9 @@ cosign sign [flags] --timestamp-client-key string path to the X.509 private key file in PEM format to be used, together with the 'timestamp-client-cert' value, for the connection to the TSA Server --timestamp-server-name string SAN name to use as the 'ServerName' tls.Config field to verify the mTLS connection to the TSA Server --timestamp-server-url string url to the Timestamp RFC3161 server, default none. Must be the path to the API to request timestamp responses, e.g. https://freetsa.org/tsr - --tlog-upload whether or not to upload to the tlog (default true) + --trusted-root string optional path to a TrustedRoot JSON file to verify a signature after signing --upload whether to upload the signature (default true) + --use-signing-config whether to use a TUF-provided signing config for the service URLs. Must set --new-bundle-format, which will store verification material in the new format (default true) -y, --yes skip confirmation prompts for non-destructive operations ``` diff --git a/doc/cosign_tree.md b/doc/cosign_tree.md index fc005d9c244..c272a7a675e 100644 --- a/doc/cosign_tree.md +++ b/doc/cosign_tree.md @@ -18,7 +18,7 @@ cosign tree [flags] --allow-http-registry whether to allow using HTTP protocol while connecting to registries. Don't use this for anything but testing --allow-insecure-registry whether to allow insecure connections to registries (e.g., with expired or self-signed TLS certificates). Don't use this for anything but testing --attachment-tag-prefix [AttachmentTagPrefix]sha256-[TargetImageDigest].[AttachmentName] optional custom prefix to use for attached image tags. Attachment images are tagged as: [AttachmentTagPrefix]sha256-[TargetImageDigest].[AttachmentName] - --experimental-oci11 set to true to enable experimental OCI 1.1 behaviour + --experimental-oci11 set to false to ignore OCI 1.1 behavior (default true) -h, --help help for tree --k8s-keychain whether to use the kubernetes keychain instead of the default keychain (supports workload identity). --registry-cacert string path to the X.509 CA certificate file in PEM format to be used for the connection to the registry diff --git a/doc/cosign_verify-attestation.md b/doc/cosign_verify-attestation.md index b29905644ec..19c0f2629e2 100644 --- a/doc/cosign_verify-attestation.md +++ b/doc/cosign_verify-attestation.md @@ -73,7 +73,7 @@ cosign verify-attestation [flags] --certificate-oidc-issuer string The OIDC issuer expected in a valid Fulcio certificate, e.g. https://token.actions.githubusercontent.com or https://oauth2.sigstore.dev/auth. Either --certificate-oidc-issuer or --certificate-oidc-issuer-regexp must be set for keyless flows. --certificate-oidc-issuer-regexp string A regular expression alternative to --certificate-oidc-issuer. Accepts the Go regular expression syntax described at https://golang.org/s/re2syntax. Either --certificate-oidc-issuer or --certificate-oidc-issuer-regexp must be set for keyless flows. --check-claims whether to check the claims found (default true) - --experimental-oci11 set to true to enable experimental OCI 1.1 behaviour + --experimental-oci11 set to true to enable experimental OCI 1.1 behaviour (unrelated to bundle format) -h, --help help for verify-attestation --insecure-ignore-sct when set, verification will not check that a certificate contains an embedded SCT, a proof of inclusion in a certificate transparency log --insecure-ignore-tlog ignore transparency log verification, to be used when an artifact signature has not been uploaded to the transparency log. Artifacts cannot be publicly verified when not included in a log @@ -81,8 +81,7 @@ cosign verify-attestation [flags] --key string path to the public key file, KMS URI or Kubernetes Secret --local-image whether the specified image is a path to an image saved locally via 'cosign save' --max-workers int the amount of maximum workers for parallel executions (default 10) - --new-bundle-format expect the signature/attestation to be packaged in a Sigstore bundle - --offline only allow offline verification + --new-bundle-format expect the signature/attestation to be packaged in a Sigstore bundle (default true) -o, --output string output format for the signing image information (json|text) (default "json") --policy strings specify CUE or Rego files with policies to be used for validation --private-infrastructure skip transparency log verification when verifying artifacts in a privately deployed infrastructure @@ -95,6 +94,7 @@ cosign verify-attestation [flags] --registry-username string registry basic auth username --rekor-url string address of rekor STL server (default "https://rekor.sigstore.dev") --sct string path to a detached Signed Certificate Timestamp, formatted as a RFC6962 AddChainResponse struct. If a certificate contains an SCT, verification will check both the detached and embedded SCTs. + --signature-digest-algorithm string digest algorithm to use when processing a signature (sha224|sha256|sha384|sha512) (default "sha256") --sk whether to use a hardware security key --slot string security key slot to use for generated key (default: signature) (authentication|signature|card-authentication|key-management) --timestamp-certificate-chain string path to PEM-encoded certificate chain file for the RFC3161 timestamp authority. Must contain the root CA certificate. Optionally may contain intermediate CA certificates, and may contain the leaf TSA certificate if not present in the timestamp diff --git a/doc/cosign_verify-blob-attestation.md b/doc/cosign_verify-blob-attestation.md index d65c180e79a..d09c868c345 100644 --- a/doc/cosign_verify-blob-attestation.md +++ b/doc/cosign_verify-blob-attestation.md @@ -45,19 +45,19 @@ cosign verify-blob-attestation [flags] --check-claims if true, verifies the digest exists in the in-toto subject (using either the provided digest and digest algorithm or the provided blob's sha256 digest). If false, only the DSSE envelope is verified. (default true) --digest string Digest to use for verifying in-toto subject (instead of providing a blob) --digestAlg string Digest algorithm to use for verifying in-toto subject (instead of providing a blob) - --experimental-oci11 set to true to enable experimental OCI 1.1 behaviour + --experimental-oci11 set to true to enable experimental OCI 1.1 behaviour (unrelated to bundle format) -h, --help help for verify-blob-attestation --insecure-ignore-sct when set, verification will not check that a certificate contains an embedded SCT, a proof of inclusion in a certificate transparency log --insecure-ignore-tlog ignore transparency log verification, to be used when an artifact signature has not been uploaded to the transparency log. Artifacts cannot be publicly verified when not included in a log --key string path to the public key file, KMS URI or Kubernetes Secret --max-workers int the amount of maximum workers for parallel executions (default 10) - --new-bundle-format expect the signature/attestation to be packaged in a Sigstore bundle - --offline only allow offline verification + --new-bundle-format expect the signature/attestation to be packaged in a Sigstore bundle (default true) --private-infrastructure skip transparency log verification when verifying artifacts in a privately deployed infrastructure --rekor-url string address of rekor STL server (default "https://rekor.sigstore.dev") --rfc3161-timestamp string path to RFC3161 timestamp FILE --sct string path to a detached Signed Certificate Timestamp, formatted as a RFC6962 AddChainResponse struct. If a certificate contains an SCT, verification will check both the detached and embedded SCTs. --signature string path to base64-encoded signature over attestation in DSSE format + --signature-digest-algorithm string digest algorithm to use when processing a signature (sha224|sha256|sha384|sha512) (default "sha256") --sk whether to use a hardware security key --slot string security key slot to use for generated key (default: signature) (authentication|signature|card-authentication|key-management) --timestamp-certificate-chain string path to PEM-encoded certificate chain file for the RFC3161 timestamp authority. Must contain the root CA certificate. Optionally may contain intermediate CA certificates, and may contain the leaf TSA certificate if not present in the timestamp diff --git a/doc/cosign_verify-blob.md b/doc/cosign_verify-blob.md index 016a04da5de..04d9e1665f6 100644 --- a/doc/cosign_verify-blob.md +++ b/doc/cosign_verify-blob.md @@ -78,19 +78,19 @@ cosign verify-blob [flags] --certificate-identity-regexp string A regular expression alternative to --certificate-identity. Accepts the Go regular expression syntax described at https://golang.org/s/re2syntax. Either --certificate-identity or --certificate-identity-regexp must be set for keyless flows. --certificate-oidc-issuer string The OIDC issuer expected in a valid Fulcio certificate, e.g. https://token.actions.githubusercontent.com or https://oauth2.sigstore.dev/auth. Either --certificate-oidc-issuer or --certificate-oidc-issuer-regexp must be set for keyless flows. --certificate-oidc-issuer-regexp string A regular expression alternative to --certificate-oidc-issuer. Accepts the Go regular expression syntax described at https://golang.org/s/re2syntax. Either --certificate-oidc-issuer or --certificate-oidc-issuer-regexp must be set for keyless flows. - --experimental-oci11 set to true to enable experimental OCI 1.1 behaviour + --experimental-oci11 set to true to enable experimental OCI 1.1 behaviour (unrelated to bundle format) -h, --help help for verify-blob --insecure-ignore-sct when set, verification will not check that a certificate contains an embedded SCT, a proof of inclusion in a certificate transparency log --insecure-ignore-tlog ignore transparency log verification, to be used when an artifact signature has not been uploaded to the transparency log. Artifacts cannot be publicly verified when not included in a log --key string path to the public key file, KMS URI or Kubernetes Secret --max-workers int the amount of maximum workers for parallel executions (default 10) - --new-bundle-format expect the signature/attestation to be packaged in a Sigstore bundle - --offline only allow offline verification + --new-bundle-format expect the signature/attestation to be packaged in a Sigstore bundle (default true) --private-infrastructure skip transparency log verification when verifying artifacts in a privately deployed infrastructure --rekor-url string address of rekor STL server (default "https://rekor.sigstore.dev") --rfc3161-timestamp string path to RFC3161 timestamp FILE --sct string path to a detached Signed Certificate Timestamp, formatted as a RFC6962 AddChainResponse struct. If a certificate contains an SCT, verification will check both the detached and embedded SCTs. --signature string signature content or path or remote URL + --signature-digest-algorithm string digest algorithm to use when processing a signature (sha224|sha256|sha384|sha512) (default "sha256") --sk whether to use a hardware security key --slot string security key slot to use for generated key (default: signature) (authentication|signature|card-authentication|key-management) --timestamp-certificate-chain string path to PEM-encoded certificate chain file for the RFC3161 timestamp authority. Must contain the root CA certificate. Optionally may contain intermediate CA certificates, and may contain the leaf TSA certificate if not present in the timestamp diff --git a/doc/cosign_verify.md b/doc/cosign_verify.md index 42ee11c7b28..edfc4cce485 100644 --- a/doc/cosign_verify.md +++ b/doc/cosign_verify.md @@ -90,7 +90,7 @@ cosign verify [flags] --certificate-oidc-issuer string The OIDC issuer expected in a valid Fulcio certificate, e.g. https://token.actions.githubusercontent.com or https://oauth2.sigstore.dev/auth. Either --certificate-oidc-issuer or --certificate-oidc-issuer-regexp must be set for keyless flows. --certificate-oidc-issuer-regexp string A regular expression alternative to --certificate-oidc-issuer. Accepts the Go regular expression syntax described at https://golang.org/s/re2syntax. Either --certificate-oidc-issuer or --certificate-oidc-issuer-regexp must be set for keyless flows. --check-claims whether to check the claims found (default true) - --experimental-oci11 set to true to enable experimental OCI 1.1 behaviour + --experimental-oci11 set to true to enable experimental OCI 1.1 behaviour (unrelated to bundle format) -h, --help help for verify --insecure-ignore-sct when set, verification will not check that a certificate contains an embedded SCT, a proof of inclusion in a certificate transparency log --insecure-ignore-tlog ignore transparency log verification, to be used when an artifact signature has not been uploaded to the transparency log. Artifacts cannot be publicly verified when not included in a log @@ -98,8 +98,7 @@ cosign verify [flags] --key string path to the public key file, KMS URI or Kubernetes Secret --local-image whether the specified image is a path to an image saved locally via 'cosign save' --max-workers int the amount of maximum workers for parallel executions (default 10) - --new-bundle-format expect the signature/attestation to be packaged in a Sigstore bundle - --offline only allow offline verification + --new-bundle-format expect the signature/attestation to be packaged in a Sigstore bundle (default true) -o, --output string output format for the signing image information (json|text) (default "json") --payload string payload path or remote URL --private-infrastructure skip transparency log verification when verifying artifacts in a privately deployed infrastructure diff --git a/go.mod b/go.mod index aae71c6b087..46124068a03 100644 --- a/go.mod +++ b/go.mod @@ -1,25 +1,26 @@ -module github.com/sigstore/cosign/v2 +module github.com/sigstore/cosign/v3 -go 1.24.3 +go 1.25.0 require ( - cuelang.org/go v0.12.1 + cuelang.org/go v0.15.1 github.com/ThalesIgnite/crypto11 v1.2.5 - github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.9.1 - github.com/buildkite/agent/v3 v3.103.0 + github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.11.0 + github.com/buildkite/agent/v3 v3.114.1 github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb27589 github.com/cyberphone/json-canonicalization v0.0.0-20241213102144-19d51d7fe467 github.com/depcheck-test/depcheck-test v0.0.0-20220607135614-199033aaa936 github.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7 github.com/dustin/go-humanize v1.0.1 - github.com/go-jose/go-jose/v3 v3.0.4 - github.com/go-openapi/runtime v0.28.0 - github.com/go-openapi/strfmt v0.23.0 - github.com/go-openapi/swag v0.23.1 + github.com/go-jose/go-jose/v4 v4.1.3 + github.com/go-openapi/runtime v0.29.2 + github.com/go-openapi/strfmt v0.25.0 + github.com/go-openapi/swag v0.25.4 + github.com/go-openapi/swag/conv v0.25.4 github.com/go-piv/piv-go/v2 v2.4.0 github.com/google/certificate-transparency-go v1.3.2 github.com/google/go-cmp v0.7.0 - github.com/google/go-containerregistry v0.20.6 + github.com/google/go-containerregistry v0.20.7 github.com/google/go-github/v73 v73.0.0 github.com/in-toto/attestation v1.1.2 github.com/in-toto/in-toto-golang v0.9.0 @@ -30,62 +31,58 @@ require ( github.com/moby/term v0.5.2 github.com/mozillazg/docker-credential-acr-helper v0.4.0 github.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481 - github.com/open-policy-agent/opa v1.6.0 - github.com/secure-systems-lab/go-securesystemslib v0.9.0 - github.com/sigstore/fulcio v1.7.1 + github.com/open-policy-agent/opa v1.10.1 + github.com/secure-systems-lab/go-securesystemslib v0.9.1 + github.com/sigstore/fulcio v1.8.3 github.com/sigstore/protobuf-specs v0.5.0 - github.com/sigstore/rekor v1.3.10 - github.com/sigstore/rekor-tiles v0.1.7-0.20250624231741-98cd4a77300f - github.com/sigstore/sigstore v1.9.5 - github.com/sigstore/sigstore-go v1.1.0 - github.com/sigstore/sigstore/pkg/signature/kms/aws v1.9.5 - github.com/sigstore/sigstore/pkg/signature/kms/azure v1.9.5 - github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.9.5 - github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.9.5 - github.com/sigstore/timestamp-authority v1.2.8 - github.com/spf13/cobra v1.9.1 - github.com/spf13/pflag v1.0.7 - github.com/spf13/viper v1.20.1 - github.com/spiffe/go-spiffe/v2 v2.5.0 - github.com/stretchr/testify v1.10.0 - github.com/theupdateframework/go-tuf/v2 v2.1.1 + github.com/sigstore/rekor v1.4.3 + github.com/sigstore/rekor-tiles/v2 v2.0.1 + github.com/sigstore/sigstore v1.10.0 + github.com/sigstore/sigstore-go v1.1.4-0.20251201121426-2cdedea80894 + github.com/sigstore/sigstore/pkg/signature/kms/aws v1.10.0 + github.com/sigstore/sigstore/pkg/signature/kms/azure v1.10.0 + github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.10.0 + github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.10.0 + github.com/sigstore/timestamp-authority/v2 v2.0.3 + github.com/spf13/cobra v1.10.2 + github.com/spf13/pflag v1.0.10 + github.com/spf13/viper v1.21.0 + github.com/spiffe/go-spiffe/v2 v2.6.0 + github.com/stretchr/testify v1.11.1 + github.com/theupdateframework/go-tuf/v2 v2.3.0 github.com/transparency-dev/merkle v0.0.2 github.com/withfig/autocomplete-tools/integrations/cobra v1.2.1 - gitlab.com/gitlab-org/api/client-go v0.137.0 - golang.org/x/crypto v0.40.0 - golang.org/x/oauth2 v0.30.0 - golang.org/x/sync v0.16.0 - golang.org/x/term v0.33.0 - google.golang.org/api v0.243.0 - google.golang.org/protobuf v1.36.6 - k8s.io/api v0.33.3 - k8s.io/apimachinery v0.33.3 - k8s.io/client-go v0.33.3 - k8s.io/utils v0.0.0-20241210054802-24370beab758 - sigs.k8s.io/release-utils v0.12.0 + gitlab.com/gitlab-org/api/client-go v0.160.0 + golang.org/x/crypto v0.45.0 + golang.org/x/oauth2 v0.33.0 + golang.org/x/sync v0.18.0 + golang.org/x/term v0.37.0 + google.golang.org/api v0.256.0 + google.golang.org/protobuf v1.36.10 + k8s.io/api v0.34.2 + k8s.io/apimachinery v0.34.2 + k8s.io/client-go v0.34.2 + k8s.io/utils v0.0.0-20250820121507-0af2bda4dd1d + sigs.k8s.io/release-utils v0.12.2 ) require ( - cel.dev/expr v0.24.0 // indirect - cloud.google.com/go v0.121.1 // indirect - cloud.google.com/go/auth v0.16.3 // indirect + cloud.google.com/go v0.121.6 // indirect + cloud.google.com/go/auth v0.17.0 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect - cloud.google.com/go/compute/metadata v0.7.0 // indirect - cloud.google.com/go/iam v1.5.2 // indirect - cloud.google.com/go/kms v1.22.0 // indirect + cloud.google.com/go/compute/metadata v0.9.0 // indirect + cloud.google.com/go/iam v1.5.3 // indirect + cloud.google.com/go/kms v1.23.2 // indirect cloud.google.com/go/longrunning v0.6.7 // indirect - cloud.google.com/go/monitoring v1.24.2 // indirect - cloud.google.com/go/spanner v1.82.0 // indirect - cloud.google.com/go/storage v1.55.0 // indirect - cuelabs.dev/go/oci/ociregistry v0.0.0-20241125120445-2c00c104c6e1 // indirect + cuelabs.dev/go/oci/ociregistry v0.0.0-20250722084951-074d06050084 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/provider v0.14.0 // indirect github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1 // indirect - github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 // indirect - github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.3.1 // indirect - github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.1.1 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.20.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 // indirect + github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.4.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.2.0 // indirect github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect github.com/Azure/go-autorest/autorest v0.11.29 // indirect @@ -95,11 +92,7 @@ require ( 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/AzureAD/microsoft-authentication-library-for-go v1.4.2 // indirect - github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp v1.5.2 // indirect - github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0 // indirect - github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0 // indirect - github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0 // indirect + github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect github.com/agnivade/levenshtein v1.2.1 // indirect github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4 // indirect @@ -114,84 +107,90 @@ require ( github.com/alibabacloud-go/tea-xml v1.1.3 // indirect github.com/aliyun/credentials-go v1.3.2 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect - github.com/avast/retry-go/v4 v4.6.1 // indirect - github.com/aws/aws-sdk-go v1.55.7 // indirect - github.com/aws/aws-sdk-go-v2 v1.36.6 // indirect - github.com/aws/aws-sdk-go-v2/config v1.29.18 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.17.71 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.33 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.37 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.37 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect - github.com/aws/aws-sdk-go-v2/service/ecr v1.40.3 // indirect - github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.31.2 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.18 // indirect - github.com/aws/aws-sdk-go-v2/service/kms v1.41.3 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.25.6 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.4 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.34.1 // indirect - github.com/aws/smithy-go v1.22.4 // indirect + github.com/aws/aws-sdk-go v1.55.8 // indirect + github.com/aws/aws-sdk-go-v2 v1.40.0 // indirect + github.com/aws/aws-sdk-go-v2/config v1.32.2 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.19.2 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.14 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.14 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.14 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 // indirect + github.com/aws/aws-sdk-go-v2/service/ecr v1.51.2 // indirect + github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.38.2 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.14 // indirect + github.com/aws/aws-sdk-go-v2/service/kms v1.49.1 // indirect + github.com/aws/aws-sdk-go-v2/service/signin v1.0.2 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.30.5 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.10 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.41.2 // indirect + github.com/aws/smithy-go v1.24.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver v3.5.1+incompatible // indirect - github.com/buildkite/go-pipeline v0.14.0 // indirect + github.com/buildkite/go-pipeline v0.16.0 // indirect github.com/buildkite/interpolate v0.1.5 // indirect - github.com/buildkite/roko v1.3.1 // indirect + github.com/buildkite/roko v1.4.0 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect - github.com/cenkalti/backoff/v5 v5.0.2 // indirect + github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/chzyer/readline v1.5.1 // indirect github.com/clbanning/mxj/v2 v2.7.0 // indirect - github.com/cncf/xds/go v0.0.0-20250326154945-ae57f3c0d45f // indirect github.com/cockroachdb/apd/v3 v3.2.1 // indirect github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be // indirect - github.com/containerd/stargz-snapshotter/estargz v0.16.3 // indirect - github.com/coreos/go-oidc/v3 v3.14.1 // indirect + github.com/containerd/stargz-snapshotter/estargz v0.18.1 // indirect + github.com/coreos/go-oidc/v3 v3.17.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect github.com/digitorus/pkcs7 v0.0.0-20230818184609-3a137a874352 // indirect github.com/dimchansky/utfbom v1.1.1 // indirect - github.com/docker/cli v28.2.2+incompatible // indirect + github.com/docker/cli v29.0.3+incompatible // indirect github.com/docker/distribution v2.8.3+incompatible // indirect - github.com/docker/docker-credential-helpers v0.9.3 // indirect + github.com/docker/docker-credential-helpers v0.9.4 // indirect github.com/docker/go-units v0.5.0 // indirect - github.com/emicklei/go-restful/v3 v3.11.0 // indirect - github.com/emicklei/proto v1.13.4 // indirect - github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect - github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect + github.com/emicklei/go-restful/v3 v3.12.2 // indirect + github.com/emicklei/proto v1.14.2 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect - github.com/fxamacker/cbor/v2 v2.7.0 // indirect - github.com/globocom/go-buffer v1.2.2 // indirect + github.com/fxamacker/cbor/v2 v2.9.0 // indirect github.com/go-chi/chi v4.1.2+incompatible // indirect + github.com/go-chi/chi/v5 v5.2.3 // indirect github.com/go-ini/ini v1.67.0 // indirect - github.com/go-jose/go-jose/v4 v4.0.5 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-openapi/analysis v0.23.0 // indirect - github.com/go-openapi/errors v0.22.1 // indirect - github.com/go-openapi/jsonpointer v0.21.0 // indirect - github.com/go-openapi/jsonreference v0.21.0 // indirect - github.com/go-openapi/loads v0.22.0 // indirect - github.com/go-openapi/spec v0.21.0 // indirect - github.com/go-openapi/validate v0.24.0 // indirect - github.com/go-sql-driver/mysql v1.9.2 // indirect - github.com/go-viper/mapstructure/v2 v2.3.0 // indirect + github.com/go-openapi/analysis v0.24.1 // indirect + github.com/go-openapi/errors v0.22.4 // indirect + github.com/go-openapi/jsonpointer v0.22.1 // indirect + github.com/go-openapi/jsonreference v0.21.3 // indirect + github.com/go-openapi/loads v0.23.2 // indirect + github.com/go-openapi/spec v0.22.1 // indirect + github.com/go-openapi/swag/cmdutils v0.25.4 // indirect + github.com/go-openapi/swag/fileutils v0.25.4 // indirect + github.com/go-openapi/swag/jsonname v0.25.4 // indirect + github.com/go-openapi/swag/jsonutils v0.25.4 // indirect + github.com/go-openapi/swag/loading v0.25.4 // indirect + github.com/go-openapi/swag/mangling v0.25.4 // indirect + github.com/go-openapi/swag/netutils v0.25.4 // indirect + github.com/go-openapi/swag/stringutils v0.25.4 // indirect + github.com/go-openapi/swag/typeutils v0.25.4 // indirect + github.com/go-openapi/swag/yamlutils v0.25.4 // indirect + github.com/go-openapi/validate v0.25.1 // indirect + github.com/go-sql-driver/mysql v1.9.3 // indirect + github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/gobwas/glob v0.2.3 // indirect + github.com/goccy/go-json v0.10.5 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v4 v4.5.2 // indirect - github.com/golang-jwt/jwt/v5 v5.2.2 // indirect - github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect + github.com/golang-jwt/jwt/v5 v5.3.0 // indirect github.com/golang/snappy v0.0.4 // indirect - github.com/google/gnostic-models v0.6.9 // indirect + github.com/google/gnostic-models v0.7.0 // indirect github.com/google/go-querystring v1.1.0 // indirect - github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect github.com/google/s2a-go v0.1.9 // indirect github.com/google/trillian v1.7.2 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.7 // indirect github.com/googleapis/gax-go/v2 v2.15.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect @@ -201,111 +200,113 @@ require ( github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect github.com/hashicorp/go-sockaddr v1.0.7 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect - github.com/hashicorp/hcl v1.0.1-vault-5 // indirect - github.com/hashicorp/vault/api v1.16.0 // indirect + github.com/hashicorp/hcl v1.0.1-vault-7 // indirect + github.com/hashicorp/vault/api v1.22.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect github.com/jackc/pgx/v5 v5.7.5 // indirect github.com/jackc/puddle/v2 v2.2.2 // indirect github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267 // indirect - github.com/jellydator/ttlcache/v3 v3.3.0 // indirect + github.com/jellydator/ttlcache/v3 v3.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.18.0 // indirect + github.com/klauspost/compress v1.18.1 // indirect github.com/kylelemons/godebug v1.1.0 // indirect - github.com/letsencrypt/boulder v0.0.0-20240620165639-de9c06129bec // indirect - github.com/mailru/easyjson v0.9.0 // indirect + github.com/lestrrat-go/blackmagic v1.0.4 // indirect + github.com/lestrrat-go/dsig v1.0.0 // indirect + github.com/lestrrat-go/dsig-secp256k1 v1.0.0 // indirect + github.com/lestrrat-go/httpcc v1.0.1 // indirect + github.com/lestrrat-go/httprc/v3 v3.0.1 // indirect + github.com/lestrrat-go/jwx/v3 v3.0.11 // indirect + github.com/lestrrat-go/option v1.0.1 // indirect + github.com/lestrrat-go/option/v2 v2.0.0 // indirect + github.com/letsencrypt/boulder v0.20251110.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/mapstructure v1.5.1-0.20231216201459-8508981c8b6c // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/natefinch/atomic v1.0.1 // indirect github.com/oklog/ulid v1.3.1 // indirect github.com/oleiade/reflections v1.1.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.1 // indirect - github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/pborman/uuid v1.2.1 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/prometheus/client_golang v1.22.0 // indirect + github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect - github.com/prometheus/common v0.63.0 // indirect - github.com/prometheus/procfs v0.15.1 // indirect - github.com/protocolbuffers/txtpbfmt v0.0.0-20241112170944-20d2c9ebc01d // indirect - github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect + github.com/prometheus/common v0.67.4 // indirect + github.com/prometheus/procfs v0.17.0 // indirect + github.com/protocolbuffers/txtpbfmt v0.0.0-20251016062345-16587c79cd91 // indirect + github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 // indirect github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/rs/cors v1.11.1 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/ryanuber/go-glob v1.0.0 // indirect - github.com/sagikazarmark/locafero v0.7.0 // indirect + github.com/sagikazarmark/locafero v0.11.0 // indirect github.com/sassoftware/relic v7.2.1+incompatible // indirect - github.com/segmentio/ksuid v1.0.4 // indirect + github.com/segmentio/asm v1.2.0 // indirect github.com/shibumi/go-pathspec v1.3.0 // indirect - github.com/sirupsen/logrus v1.9.3 // indirect - github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect - github.com/sourcegraph/conc v0.3.0 // indirect - github.com/spf13/afero v1.12.0 // indirect - github.com/spf13/cast v1.7.1 // indirect + github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af // indirect + github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect + github.com/spf13/afero v1.15.0 // indirect + github.com/spf13/cast v1.10.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect - github.com/tchap/go-patricia/v2 v2.3.2 // indirect + github.com/tchap/go-patricia/v2 v2.3.3 // indirect github.com/thales-e-security/pool v0.0.2 // indirect github.com/theupdateframework/go-tuf v0.7.0 // indirect github.com/tink-crypto/tink-go-awskms/v2 v2.1.0 // indirect github.com/tink-crypto/tink-go-gcpkms/v2 v2.2.0 // indirect github.com/tink-crypto/tink-go-hcvault/v2 v2.3.0 // indirect - github.com/tink-crypto/tink-go/v2 v2.4.0 // indirect + github.com/tink-crypto/tink-go/v2 v2.5.0 // indirect github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect github.com/tjfoc/gmsm v1.4.1 // indirect - github.com/transparency-dev/formats v0.0.0-20250421220931-bb8ad4d07c26 // indirect - github.com/transparency-dev/tessera v0.2.1-0.20250610150926-8ee4e93b2823 // indirect + github.com/transparency-dev/formats v0.0.0-20251017110053-404c0d5b696c // indirect github.com/urfave/negroni v1.0.0 // indirect - github.com/vbatts/tar-split v0.12.1 // indirect - github.com/vektah/gqlparser/v2 v2.5.28 // indirect + github.com/valyala/fastjson v1.6.4 // indirect + github.com/vbatts/tar-split v0.12.2 // indirect + github.com/vektah/gqlparser/v2 v2.5.30 // 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/yashtewari/glob-intersection v0.2.0 // indirect - github.com/zeebo/errs v1.4.0 // indirect - go.mongodb.org/mongo-driver v1.14.0 // indirect - go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/auto/sdk v1.1.0 // indirect - go.opentelemetry.io/contrib/detectors/gcp v1.36.0 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect - go.opentelemetry.io/otel v1.37.0 // indirect - go.opentelemetry.io/otel/metric v1.37.0 // indirect - go.opentelemetry.io/otel/sdk v1.37.0 // indirect - go.opentelemetry.io/otel/sdk/metric v1.36.0 // indirect - go.opentelemetry.io/otel/trace v1.37.0 // indirect - go.step.sm/crypto v0.67.0 // indirect + go.mongodb.org/mongo-driver v1.17.6 // indirect + go.opentelemetry.io/auto/sdk v1.2.1 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 // indirect + go.opentelemetry.io/otel v1.38.0 // indirect + go.opentelemetry.io/otel/metric v1.38.0 // indirect + go.opentelemetry.io/otel/sdk v1.38.0 // indirect + go.opentelemetry.io/otel/trace v1.38.0 // indirect + go.step.sm/crypto v0.74.0 // indirect go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.27.0 // indirect - golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect - golang.org/x/mod v0.26.0 // indirect - golang.org/x/net v0.42.0 // indirect - golang.org/x/sys v0.34.0 // indirect - golang.org/x/text v0.27.0 // indirect - golang.org/x/time v0.12.0 // indirect - golang.org/x/tools v0.35.0 // indirect - google.golang.org/genproto v0.0.0-20250603155806-513f23925822 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250715232539-7130f93afb79 // indirect - google.golang.org/grpc v1.73.0 // indirect + go.uber.org/zap v1.27.1 // indirect + go.yaml.in/yaml/v2 v2.4.3 // indirect + go.yaml.in/yaml/v3 v3.0.4 // indirect + golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // indirect + golang.org/x/mod v0.30.0 // indirect + golang.org/x/net v0.47.0 // indirect + golang.org/x/sys v0.38.0 // indirect + golang.org/x/text v0.31.0 // indirect + golang.org/x/time v0.14.0 // indirect + golang.org/x/tools v0.39.0 // indirect + google.golang.org/genproto v0.0.0-20250922171735-9219d122eba9 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251103181224-f26f9409b101 // indirect + google.golang.org/grpc v1.77.0 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/klog/v2 v2.130.1 // indirect - k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect - sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect + k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b // indirect + sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect sigs.k8s.io/randfill v1.0.0 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect - sigs.k8s.io/yaml v1.4.0 // indirect + sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect + sigs.k8s.io/yaml v1.6.0 // indirect ) diff --git a/go.sum b/go.sum index 2f111d8bcf7..835dd28099b 100644 --- a/go.sum +++ b/go.sum @@ -1,652 +1,44 @@ -al.essio.dev/pkg/shellescape v1.5.1 h1:86HrALUujYS/h+GtqoB26SBEdkWfmMI6FubjXlsXyho= -al.essio.dev/pkg/shellescape v1.5.1/go.mod h1:6sIqp7X2P6mThCQ7twERpZTuigpr6KbZWtls1U8I890= -cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY= -cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= +al.essio.dev/pkg/shellescape v1.6.0 h1:NxFcEqzFSEVCGN2yq7Huv/9hyCEGVa/TncnOOBBeXHA= +al.essio.dev/pkg/shellescape v1.6.0/go.mod h1:6sIqp7X2P6mThCQ7twERpZTuigpr6KbZWtls1U8I890= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= -cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= -cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= -cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= -cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= -cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= -cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= -cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= -cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= -cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= -cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= -cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= -cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= -cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= -cloud.google.com/go v0.100.1/go.mod h1:fs4QogzfH5n2pBXBP9vRiU+eCny7lD2vmFZy79Iuw1U= -cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= -cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= -cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU= -cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA= -cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM= -cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= -cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= -cloud.google.com/go v0.121.1 h1:S3kTQSydxmu1JfLRLpKtxRPA7rSrYPRPEUmL/PavVUw= -cloud.google.com/go v0.121.1/go.mod h1:nRFlrHq39MNVWu+zESP2PosMWA0ryJw8KUBZ2iZpxbw= -cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= -cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= -cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= -cloud.google.com/go/accesscontextmanager v1.3.0/go.mod h1:TgCBehyr5gNMz7ZaH9xubp+CE8dkrszb4oK9CWyvD4o= -cloud.google.com/go/accesscontextmanager v1.4.0/go.mod h1:/Kjh7BBu/Gh83sv+K60vN9QE5NJcd80sU33vIe2IFPE= -cloud.google.com/go/accesscontextmanager v1.6.0/go.mod h1:8XCvZWfYw3K/ji0iVnp+6pu7huxoQTLmxAbVjbloTtM= -cloud.google.com/go/accesscontextmanager v1.7.0/go.mod h1:CEGLewx8dwa33aDAZQujl7Dx+uYhS0eay198wB/VumQ= -cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw= -cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY= -cloud.google.com/go/aiplatform v1.27.0/go.mod h1:Bvxqtl40l0WImSb04d0hXFU7gDOiq9jQmorivIiWcKg= -cloud.google.com/go/aiplatform v1.35.0/go.mod h1:7MFT/vCaOyZT/4IIFfxH4ErVg/4ku6lKv3w0+tFTgXQ= -cloud.google.com/go/aiplatform v1.36.1/go.mod h1:WTm12vJRPARNvJ+v6P52RDHCNe4AhvjcIZ/9/RRHy/k= -cloud.google.com/go/aiplatform v1.37.0/go.mod h1:IU2Cv29Lv9oCn/9LkFiiuKfwrRTq+QQMbW+hPCxJGZw= -cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI= -cloud.google.com/go/analytics v0.12.0/go.mod h1:gkfj9h6XRf9+TS4bmuhPEShsh3hH8PAZzm/41OOhQd4= -cloud.google.com/go/analytics v0.17.0/go.mod h1:WXFa3WSym4IZ+JiKmavYdJwGG/CvpqiqczmL59bTD9M= -cloud.google.com/go/analytics v0.18.0/go.mod h1:ZkeHGQlcIPkw0R/GW+boWHhCOR43xz9RN/jn7WcqfIE= -cloud.google.com/go/analytics v0.19.0/go.mod h1:k8liqf5/HCnOUkbawNtrWWc+UAzyDlW89doe8TtoDsE= -cloud.google.com/go/apigateway v1.3.0/go.mod h1:89Z8Bhpmxu6AmUxuVRg/ECRGReEdiP3vQtk4Z1J9rJk= -cloud.google.com/go/apigateway v1.4.0/go.mod h1:pHVY9MKGaH9PQ3pJ4YLzoj6U5FUDeDFBllIz7WmzJoc= -cloud.google.com/go/apigateway v1.5.0/go.mod h1:GpnZR3Q4rR7LVu5951qfXPJCHquZt02jf7xQx7kpqN8= -cloud.google.com/go/apigeeconnect v1.3.0/go.mod h1:G/AwXFAKo0gIXkPTVfZDd2qA1TxBXJ3MgMRBQkIi9jc= -cloud.google.com/go/apigeeconnect v1.4.0/go.mod h1:kV4NwOKqjvt2JYR0AoIWo2QGfoRtn/pkS3QlHp0Ni04= -cloud.google.com/go/apigeeconnect v1.5.0/go.mod h1:KFaCqvBRU6idyhSNyn3vlHXc8VMDJdRmwDF6JyFRqZ8= -cloud.google.com/go/apigeeregistry v0.4.0/go.mod h1:EUG4PGcsZvxOXAdyEghIdXwAEi/4MEaoqLMLDMIwKXY= -cloud.google.com/go/apigeeregistry v0.5.0/go.mod h1:YR5+s0BVNZfVOUkMa5pAR2xGd0A473vA5M7j247o1wM= -cloud.google.com/go/apigeeregistry v0.6.0/go.mod h1:BFNzW7yQVLZ3yj0TKcwzb8n25CFBri51GVGOEUcgQsc= -cloud.google.com/go/apikeys v0.4.0/go.mod h1:XATS/yqZbaBK0HOssf+ALHp8jAlNHUgyfprvNcBIszU= -cloud.google.com/go/apikeys v0.5.0/go.mod h1:5aQfwY4D+ewMMWScd3hm2en3hCj+BROlyrt3ytS7KLI= -cloud.google.com/go/apikeys v0.6.0/go.mod h1:kbpXu5upyiAlGkKrJgQl8A0rKNNJ7dQ377pdroRSSi8= -cloud.google.com/go/appengine v1.4.0/go.mod h1:CS2NhuBuDXM9f+qscZ6V86m1MIIqPj3WC/UoEuR1Sno= -cloud.google.com/go/appengine v1.5.0/go.mod h1:TfasSozdkFI0zeoxW3PTBLiNqRmzraodCWatWI9Dmak= -cloud.google.com/go/appengine v1.6.0/go.mod h1:hg6i0J/BD2cKmDJbaFSYHFyZkgBEfQrDg/X0V5fJn84= -cloud.google.com/go/appengine v1.7.0/go.mod h1:eZqpbHFCqRGa2aCdope7eC0SWLV1j0neb/QnMJVWx6A= -cloud.google.com/go/appengine v1.7.1/go.mod h1:IHLToyb/3fKutRysUlFO0BPt5j7RiQ45nrzEJmKTo6E= -cloud.google.com/go/area120 v0.5.0/go.mod h1:DE/n4mp+iqVyvxHN41Vf1CR602GiHQjFPusMFW6bGR4= -cloud.google.com/go/area120 v0.6.0/go.mod h1:39yFJqWVgm0UZqWTOdqkLhjoC7uFfgXRC8g/ZegeAh0= -cloud.google.com/go/area120 v0.7.0/go.mod h1:a3+8EUD1SX5RUcCs3MY5YasiO1z6yLiNLRiFrykbynY= -cloud.google.com/go/area120 v0.7.1/go.mod h1:j84i4E1RboTWjKtZVWXPqvK5VHQFJRF2c1Nm69pWm9k= -cloud.google.com/go/artifactregistry v1.6.0/go.mod h1:IYt0oBPSAGYj/kprzsBjZ/4LnG/zOcHyFHjWPCi6SAQ= -cloud.google.com/go/artifactregistry v1.7.0/go.mod h1:mqTOFOnGZx8EtSqK/ZWcsm/4U8B77rbcLP6ruDU2Ixk= -cloud.google.com/go/artifactregistry v1.8.0/go.mod h1:w3GQXkJX8hiKN0v+at4b0qotwijQbYUqF2GWkZzAhC0= -cloud.google.com/go/artifactregistry v1.9.0/go.mod h1:2K2RqvA2CYvAeARHRkLDhMDJ3OXy26h3XW+3/Jh2uYc= -cloud.google.com/go/artifactregistry v1.11.1/go.mod h1:lLYghw+Itq9SONbCa1YWBoWs1nOucMH0pwXN1rOBZFI= -cloud.google.com/go/artifactregistry v1.11.2/go.mod h1:nLZns771ZGAwVLzTX/7Al6R9ehma4WUEhZGWV6CeQNQ= -cloud.google.com/go/artifactregistry v1.12.0/go.mod h1:o6P3MIvtzTOnmvGagO9v/rOjjA0HmhJ+/6KAXrmYDCI= -cloud.google.com/go/artifactregistry v1.13.0/go.mod h1:uy/LNfoOIivepGhooAUpL1i30Hgee3Cu0l4VTWHUC08= -cloud.google.com/go/asset v1.5.0/go.mod h1:5mfs8UvcM5wHhqtSv8J1CtxxaQq3AdBxxQi2jGW/K4o= -cloud.google.com/go/asset v1.7.0/go.mod h1:YbENsRK4+xTiL+Ofoj5Ckf+O17kJtgp3Y3nn4uzZz5s= -cloud.google.com/go/asset v1.8.0/go.mod h1:mUNGKhiqIdbr8X7KNayoYvyc4HbbFO9URsjbytpUaW0= -cloud.google.com/go/asset v1.9.0/go.mod h1:83MOE6jEJBMqFKadM9NLRcs80Gdw76qGuHn8m3h8oHQ= -cloud.google.com/go/asset v1.10.0/go.mod h1:pLz7uokL80qKhzKr4xXGvBQXnzHn5evJAEAtZiIb0wY= -cloud.google.com/go/asset v1.11.1/go.mod h1:fSwLhbRvC9p9CXQHJ3BgFeQNM4c9x10lqlrdEUYXlJo= -cloud.google.com/go/asset v1.12.0/go.mod h1:h9/sFOa4eDIyKmH6QMpm4eUK3pDojWnUhTgJlk762Hg= -cloud.google.com/go/asset v1.13.0/go.mod h1:WQAMyYek/b7NBpYq/K4KJWcRqzoalEsxz/t/dTk4THw= -cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY= -cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw= -cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVoYoxeLBoj4XkKYscNI= -cloud.google.com/go/assuredworkloads v1.8.0/go.mod h1:AsX2cqyNCOvEQC8RMPnoc0yEarXQk6WEKkxYfL6kGIo= -cloud.google.com/go/assuredworkloads v1.9.0/go.mod h1:kFuI1P78bplYtT77Tb1hi0FMxM0vVpRC7VVoJC3ZoT0= -cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= -cloud.google.com/go/auth v0.16.3 h1:kabzoQ9/bobUmnseYnBO6qQG7q4a/CffFRlJSxv2wCc= -cloud.google.com/go/auth v0.16.3/go.mod h1:NucRGjaXfzP1ltpcQ7On/VTZ0H4kWB5Jy+Y9Dnm76fA= +cloud.google.com/go v0.121.6 h1:waZiuajrI28iAf40cWgycWNgaXPO06dupuS+sgibK6c= +cloud.google.com/go v0.121.6/go.mod h1:coChdst4Ea5vUpiALcYKXEpR1S9ZgXbhEzzMcMR66vI= +cloud.google.com/go/auth v0.17.0 h1:74yCm7hCj2rUyyAocqnFzsAYXgJhrG26XCFimrc/Kz4= +cloud.google.com/go/auth v0.17.0/go.mod h1:6wv/t5/6rOPAX4fJiRjKkJCvswLwdet7G8+UGXt7nCQ= cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc= cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c= -cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= -cloud.google.com/go/automl v1.6.0/go.mod h1:ugf8a6Fx+zP0D59WLhqgTDsQI9w07o64uf/Is3Nh5p8= -cloud.google.com/go/automl v1.7.0/go.mod h1:RL9MYCCsJEOmt0Wf3z9uzG0a7adTT1fe+aObgSpkCt8= -cloud.google.com/go/automl v1.8.0/go.mod h1:xWx7G/aPEe/NP+qzYXktoBSDfjO+vnKMGgsApGJJquM= -cloud.google.com/go/automl v1.12.0/go.mod h1:tWDcHDp86aMIuHmyvjuKeeHEGq76lD7ZqfGLN6B0NuU= -cloud.google.com/go/baremetalsolution v0.3.0/go.mod h1:XOrocE+pvK1xFfleEnShBlNAXf+j5blPPxrhjKgnIFc= -cloud.google.com/go/baremetalsolution v0.4.0/go.mod h1:BymplhAadOO/eBa7KewQ0Ppg4A4Wplbn+PsFKRLo0uI= -cloud.google.com/go/baremetalsolution v0.5.0/go.mod h1:dXGxEkmR9BMwxhzBhV0AioD0ULBmuLZI8CdwalUxuss= -cloud.google.com/go/batch v0.3.0/go.mod h1:TR18ZoAekj1GuirsUsR1ZTKN3FC/4UDnScjT8NXImFE= -cloud.google.com/go/batch v0.4.0/go.mod h1:WZkHnP43R/QCGQsZ+0JyG4i79ranE2u8xvjq/9+STPE= -cloud.google.com/go/batch v0.7.0/go.mod h1:vLZN95s6teRUqRQ4s3RLDsH8PvboqBK+rn1oevL159g= -cloud.google.com/go/beyondcorp v0.2.0/go.mod h1:TB7Bd+EEtcw9PCPQhCJtJGjk/7TC6ckmnSFS+xwTfm4= -cloud.google.com/go/beyondcorp v0.3.0/go.mod h1:E5U5lcrcXMsCuoDNyGrpyTm/hn7ne941Jz2vmksAxW8= -cloud.google.com/go/beyondcorp v0.4.0/go.mod h1:3ApA0mbhHx6YImmuubf5pyW8srKnCEPON32/5hj+RmM= -cloud.google.com/go/beyondcorp v0.5.0/go.mod h1:uFqj9X+dSfrheVp7ssLTaRHd2EHqSL4QZmH4e8WXGGU= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/bigquery v1.42.0/go.mod h1:8dRTJxhtG+vwBKzE5OseQn/hiydoQN3EedCaOdYmxRA= -cloud.google.com/go/bigquery v1.43.0/go.mod h1:ZMQcXHsl+xmU1z36G2jNGZmKp9zNY5BUua5wDgmNCfw= -cloud.google.com/go/bigquery v1.44.0/go.mod h1:0Y33VqXTEsbamHJvJHdFmtqHvMIY28aK1+dFsvaChGc= -cloud.google.com/go/bigquery v1.47.0/go.mod h1:sA9XOgy0A8vQK9+MWhEQTY6Tix87M/ZurWFIxmF9I/E= -cloud.google.com/go/bigquery v1.48.0/go.mod h1:QAwSz+ipNgfL5jxiaK7weyOhzdoAy1zFm0Nf1fysJac= -cloud.google.com/go/bigquery v1.49.0/go.mod h1:Sv8hMmTFFYBlt/ftw2uN6dFdQPzBlREY9yBh7Oy7/4Q= -cloud.google.com/go/bigquery v1.50.0/go.mod h1:YrleYEh2pSEbgTBZYMJ5SuSr0ML3ypjRB1zgf7pvQLU= -cloud.google.com/go/billing v1.4.0/go.mod h1:g9IdKBEFlItS8bTtlrZdVLWSSdSyFUZKXNS02zKMOZY= -cloud.google.com/go/billing v1.5.0/go.mod h1:mztb1tBc3QekhjSgmpf/CV4LzWXLzCArwpLmP2Gm88s= -cloud.google.com/go/billing v1.6.0/go.mod h1:WoXzguj+BeHXPbKfNWkqVtDdzORazmCjraY+vrxcyvI= -cloud.google.com/go/billing v1.7.0/go.mod h1:q457N3Hbj9lYwwRbnlD7vUpyjq6u5U1RAOArInEiD5Y= -cloud.google.com/go/billing v1.12.0/go.mod h1:yKrZio/eu+okO/2McZEbch17O5CB5NpZhhXG6Z766ss= -cloud.google.com/go/billing v1.13.0/go.mod h1:7kB2W9Xf98hP9Sr12KfECgfGclsH3CQR0R08tnRlRbc= -cloud.google.com/go/binaryauthorization v1.1.0/go.mod h1:xwnoWu3Y84jbuHa0zd526MJYmtnVXn0syOjaJgy4+dM= -cloud.google.com/go/binaryauthorization v1.2.0/go.mod h1:86WKkJHtRcv5ViNABtYMhhNWRrD1Vpi//uKEy7aYEfI= -cloud.google.com/go/binaryauthorization v1.3.0/go.mod h1:lRZbKgjDIIQvzYQS1p99A7/U1JqvqeZg0wiI5tp6tg0= -cloud.google.com/go/binaryauthorization v1.4.0/go.mod h1:tsSPQrBd77VLplV70GUhBf/Zm3FsKmgSqgm4UmiDItk= -cloud.google.com/go/binaryauthorization v1.5.0/go.mod h1:OSe4OU1nN/VswXKRBmciKpo9LulY41gch5c68htf3/Q= -cloud.google.com/go/certificatemanager v1.3.0/go.mod h1:n6twGDvcUBFu9uBgt4eYvvf3sQ6My8jADcOVwHmzadg= -cloud.google.com/go/certificatemanager v1.4.0/go.mod h1:vowpercVFyqs8ABSmrdV+GiFf2H/ch3KyudYQEMM590= -cloud.google.com/go/certificatemanager v1.6.0/go.mod h1:3Hh64rCKjRAX8dXgRAyOcY5vQ/fE1sh8o+Mdd6KPgY8= -cloud.google.com/go/channel v1.8.0/go.mod h1:W5SwCXDJsq/rg3tn3oG0LOxpAo6IMxNa09ngphpSlnk= -cloud.google.com/go/channel v1.9.0/go.mod h1:jcu05W0my9Vx4mt3/rEHpfxc9eKi9XwsdDL8yBMbKUk= -cloud.google.com/go/channel v1.11.0/go.mod h1:IdtI0uWGqhEeatSB62VOoJ8FSUhJ9/+iGkJVqp74CGE= -cloud.google.com/go/channel v1.12.0/go.mod h1:VkxCGKASi4Cq7TbXxlaBezonAYpp1GCnKMY6tnMQnLU= -cloud.google.com/go/cloudbuild v1.3.0/go.mod h1:WequR4ULxlqvMsjDEEEFnOG5ZSRSgWOywXYDb1vPE6U= -cloud.google.com/go/cloudbuild v1.4.0/go.mod h1:5Qwa40LHiOXmz3386FrjrYM93rM/hdRr7b53sySrTqA= -cloud.google.com/go/cloudbuild v1.6.0/go.mod h1:UIbc/w9QCbH12xX+ezUsgblrWv+Cv4Tw83GiSMHOn9M= -cloud.google.com/go/cloudbuild v1.7.0/go.mod h1:zb5tWh2XI6lR9zQmsm1VRA+7OCuve5d8S+zJUul8KTg= -cloud.google.com/go/cloudbuild v1.9.0/go.mod h1:qK1d7s4QlO0VwfYn5YuClDGg2hfmLZEb4wQGAbIgL1s= -cloud.google.com/go/clouddms v1.3.0/go.mod h1:oK6XsCDdW4Ib3jCCBugx+gVjevp2TMXFtgxvPSee3OM= -cloud.google.com/go/clouddms v1.4.0/go.mod h1:Eh7sUGCC+aKry14O1NRljhjyrr0NFC0G2cjwX0cByRk= -cloud.google.com/go/clouddms v1.5.0/go.mod h1:QSxQnhikCLUw13iAbffF2CZxAER3xDGNHjsTAkQJcQA= -cloud.google.com/go/cloudtasks v1.5.0/go.mod h1:fD92REy1x5woxkKEkLdvavGnPJGEn8Uic9nWuLzqCpY= -cloud.google.com/go/cloudtasks v1.6.0/go.mod h1:C6Io+sxuke9/KNRkbQpihnW93SWDU3uXt92nu85HkYI= -cloud.google.com/go/cloudtasks v1.7.0/go.mod h1:ImsfdYWwlWNJbdgPIIGJWC+gemEGTBK/SunNQQNCAb4= -cloud.google.com/go/cloudtasks v1.8.0/go.mod h1:gQXUIwCSOI4yPVK7DgTVFiiP0ZW/eQkydWzwVMdHxrI= -cloud.google.com/go/cloudtasks v1.9.0/go.mod h1:w+EyLsVkLWHcOaqNEyvcKAsWp9p29dL6uL9Nst1cI7Y= -cloud.google.com/go/cloudtasks v1.10.0/go.mod h1:NDSoTLkZ3+vExFEWu2UJV1arUyzVDAiZtdWcsUyNwBs= -cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= -cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= -cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= -cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= -cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= -cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= -cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= -cloud.google.com/go/compute v1.12.0/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= -cloud.google.com/go/compute v1.12.1/go.mod h1:e8yNOBcBONZU1vJKCvCoDw/4JQsA0dpM4x/6PIIOocU= -cloud.google.com/go/compute v1.13.0/go.mod h1:5aPTS0cUNMIc1CE546K+Th6weJUNQErARyZtRXDJ8GE= -cloud.google.com/go/compute v1.14.0/go.mod h1:YfLtxrj9sU4Yxv+sXzZkyPjEyPBZfXHUvjxega5vAdo= -cloud.google.com/go/compute v1.15.1/go.mod h1:bjjoF/NtFUrkD/urWfdHaKuOPDR5nWIs63rR+SXhcpA= -cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= -cloud.google.com/go/compute v1.19.0/go.mod h1:rikpw2y+UMidAe9tISo04EHNOIf42RLYF/q8Bs93scU= -cloud.google.com/go/compute v1.19.1/go.mod h1:6ylj3a05WF8leseCdIf77NK0g1ey+nj5IKd5/kvShxE= -cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU= -cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= -cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= -cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -cloud.google.com/go/compute/metadata v0.7.0 h1:PBWF+iiAerVNe8UCHxdOt6eHLVc3ydFeOCw78U8ytSU= -cloud.google.com/go/compute/metadata v0.7.0/go.mod h1:j5MvL9PprKL39t166CoB1uVHfQMs4tFQZZcKwksXUjo= -cloud.google.com/go/contactcenterinsights v1.3.0/go.mod h1:Eu2oemoePuEFc/xKFPjbTuPSj0fYJcPls9TFlPNnHHY= -cloud.google.com/go/contactcenterinsights v1.4.0/go.mod h1:L2YzkGbPsv+vMQMCADxJoT9YiTTnSEd6fEvCeHTYVck= -cloud.google.com/go/contactcenterinsights v1.6.0/go.mod h1:IIDlT6CLcDoyv79kDv8iWxMSTZhLxSCofVV5W6YFM/w= -cloud.google.com/go/container v1.6.0/go.mod h1:Xazp7GjJSeUYo688S+6J5V+n/t+G5sKBTFkKNudGRxg= -cloud.google.com/go/container v1.7.0/go.mod h1:Dp5AHtmothHGX3DwwIHPgq45Y8KmNsgN3amoYfxVkLo= -cloud.google.com/go/container v1.13.1/go.mod h1:6wgbMPeQRw9rSnKBCAJXnds3Pzj03C4JHamr8asWKy4= -cloud.google.com/go/container v1.14.0/go.mod h1:3AoJMPhHfLDxLvrlVWaK57IXzaPnLaZq63WX59aQBfM= -cloud.google.com/go/container v1.15.0/go.mod h1:ft+9S0WGjAyjDggg5S06DXj+fHJICWg8L7isCQe9pQA= -cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= -cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4= -cloud.google.com/go/containeranalysis v0.7.0/go.mod h1:9aUL+/vZ55P2CXfuZjS4UjQ9AgXoSw8Ts6lemfmxBxI= -cloud.google.com/go/containeranalysis v0.9.0/go.mod h1:orbOANbwk5Ejoom+s+DUCTTJ7IBdBQJDcSylAx/on9s= -cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0= -cloud.google.com/go/datacatalog v1.5.0/go.mod h1:M7GPLNQeLfWqeIm3iuiruhPzkt65+Bx8dAKvScX8jvs= -cloud.google.com/go/datacatalog v1.6.0/go.mod h1:+aEyF8JKg+uXcIdAmmaMUmZ3q1b/lKLtXCmXdnc0lbc= -cloud.google.com/go/datacatalog v1.7.0/go.mod h1:9mEl4AuDYWw81UGc41HonIHH7/sn52H0/tc8f8ZbZIE= -cloud.google.com/go/datacatalog v1.8.0/go.mod h1:KYuoVOv9BM8EYz/4eMFxrr4DUKhGIOXxZoKYF5wdISM= -cloud.google.com/go/datacatalog v1.8.1/go.mod h1:RJ58z4rMp3gvETA465Vg+ag8BGgBdnRPEMMSTr5Uv+M= -cloud.google.com/go/datacatalog v1.12.0/go.mod h1:CWae8rFkfp6LzLumKOnmVh4+Zle4A3NXLzVJ1d1mRm0= -cloud.google.com/go/datacatalog v1.13.0/go.mod h1:E4Rj9a5ZtAxcQJlEBTLgMTphfP11/lNaAshpoBgemX8= -cloud.google.com/go/dataflow v0.6.0/go.mod h1:9QwV89cGoxjjSR9/r7eFDqqjtvbKxAK2BaYU6PVk9UM= -cloud.google.com/go/dataflow v0.7.0/go.mod h1:PX526vb4ijFMesO1o202EaUmouZKBpjHsTlCtB4parQ= -cloud.google.com/go/dataflow v0.8.0/go.mod h1:Rcf5YgTKPtQyYz8bLYhFoIV/vP39eL7fWNcSOyFfLJE= -cloud.google.com/go/dataform v0.3.0/go.mod h1:cj8uNliRlHpa6L3yVhDOBrUXH+BPAO1+KFMQQNSThKo= -cloud.google.com/go/dataform v0.4.0/go.mod h1:fwV6Y4Ty2yIFL89huYlEkwUPtS7YZinZbzzj5S9FzCE= -cloud.google.com/go/dataform v0.5.0/go.mod h1:GFUYRe8IBa2hcomWplodVmUx/iTL0FrsauObOM3Ipr0= -cloud.google.com/go/dataform v0.6.0/go.mod h1:QPflImQy33e29VuapFdf19oPbE4aYTJxr31OAPV+ulA= -cloud.google.com/go/dataform v0.7.0/go.mod h1:7NulqnVozfHvWUBpMDfKMUESr+85aJsC/2O0o3jWPDE= -cloud.google.com/go/datafusion v1.4.0/go.mod h1:1Zb6VN+W6ALo85cXnM1IKiPw+yQMKMhB9TsTSRDo/38= -cloud.google.com/go/datafusion v1.5.0/go.mod h1:Kz+l1FGHB0J+4XF2fud96WMmRiq/wj8N9u007vyXZ2w= -cloud.google.com/go/datafusion v1.6.0/go.mod h1:WBsMF8F1RhSXvVM8rCV3AeyWVxcC2xY6vith3iw3S+8= -cloud.google.com/go/datalabeling v0.5.0/go.mod h1:TGcJ0G2NzcsXSE/97yWjIZO0bXj0KbVlINXMG9ud42I= -cloud.google.com/go/datalabeling v0.6.0/go.mod h1:WqdISuk/+WIGeMkpw/1q7bK/tFEZxsrFJOJdY2bXvTQ= -cloud.google.com/go/datalabeling v0.7.0/go.mod h1:WPQb1y08RJbmpM3ww0CSUAGweL0SxByuW2E+FU+wXcM= -cloud.google.com/go/dataplex v1.3.0/go.mod h1:hQuRtDg+fCiFgC8j0zV222HvzFQdRd+SVX8gdmFcZzA= -cloud.google.com/go/dataplex v1.4.0/go.mod h1:X51GfLXEMVJ6UN47ESVqvlsRplbLhcsAt0kZCCKsU0A= -cloud.google.com/go/dataplex v1.5.2/go.mod h1:cVMgQHsmfRoI5KFYq4JtIBEUbYwc3c7tXmIDhRmNNVQ= -cloud.google.com/go/dataplex v1.6.0/go.mod h1:bMsomC/aEJOSpHXdFKFGQ1b0TDPIeL28nJObeO1ppRs= -cloud.google.com/go/dataproc v1.7.0/go.mod h1:CKAlMjII9H90RXaMpSxQ8EU6dQx6iAYNPcYPOkSbi8s= -cloud.google.com/go/dataproc v1.8.0/go.mod h1:5OW+zNAH0pMpw14JVrPONsxMQYMBqJuzORhIBfBn9uI= -cloud.google.com/go/dataproc v1.12.0/go.mod h1:zrF3aX0uV3ikkMz6z4uBbIKyhRITnxvr4i3IjKsKrw4= -cloud.google.com/go/dataqna v0.5.0/go.mod h1:90Hyk596ft3zUQ8NkFfvICSIfHFh1Bc7C4cK3vbhkeo= -cloud.google.com/go/dataqna v0.6.0/go.mod h1:1lqNpM7rqNLVgWBJyk5NF6Uen2PHym0jtVJonplVsDA= -cloud.google.com/go/dataqna v0.7.0/go.mod h1:Lx9OcIIeqCrw1a6KdO3/5KMP1wAmTc0slZWwP12Qq3c= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/datastore v1.10.0/go.mod h1:PC5UzAmDEkAmkfaknstTYbNpgE49HAgW2J1gcgUfmdM= -cloud.google.com/go/datastore v1.11.0/go.mod h1:TvGxBIHCS50u8jzG+AW/ppf87v1of8nwzFNgEZU1D3c= -cloud.google.com/go/datastream v1.2.0/go.mod h1:i/uTP8/fZwgATHS/XFu0TcNUhuA0twZxxQ3EyCUQMwo= -cloud.google.com/go/datastream v1.3.0/go.mod h1:cqlOX8xlyYF/uxhiKn6Hbv6WjwPPuI9W2M9SAXwaLLQ= -cloud.google.com/go/datastream v1.4.0/go.mod h1:h9dpzScPhDTs5noEMQVWP8Wx8AFBRyS0s8KWPx/9r0g= -cloud.google.com/go/datastream v1.5.0/go.mod h1:6TZMMNPwjUqZHBKPQ1wwXpb0d5VDVPl2/XoS5yi88q4= -cloud.google.com/go/datastream v1.6.0/go.mod h1:6LQSuswqLa7S4rPAOZFVjHIG3wJIjZcZrw8JDEDJuIs= -cloud.google.com/go/datastream v1.7.0/go.mod h1:uxVRMm2elUSPuh65IbZpzJNMbuzkcvu5CjMqVIUHrww= -cloud.google.com/go/deploy v1.4.0/go.mod h1:5Xghikd4VrmMLNaF6FiRFDlHb59VM59YoDQnOUdsH/c= -cloud.google.com/go/deploy v1.5.0/go.mod h1:ffgdD0B89tToyW/U/D2eL0jN2+IEV/3EMuXHA0l4r+s= -cloud.google.com/go/deploy v1.6.0/go.mod h1:f9PTHehG/DjCom3QH0cntOVRm93uGBDt2vKzAPwpXQI= -cloud.google.com/go/deploy v1.8.0/go.mod h1:z3myEJnA/2wnB4sgjqdMfgxCA0EqC3RBTNcVPs93mtQ= -cloud.google.com/go/dialogflow v1.15.0/go.mod h1:HbHDWs33WOGJgn6rfzBW1Kv807BE3O1+xGbn59zZWI4= -cloud.google.com/go/dialogflow v1.16.1/go.mod h1:po6LlzGfK+smoSmTBnbkIZY2w8ffjz/RcGSS+sh1el0= -cloud.google.com/go/dialogflow v1.17.0/go.mod h1:YNP09C/kXA1aZdBgC/VtXX74G/TKn7XVCcVumTflA+8= -cloud.google.com/go/dialogflow v1.18.0/go.mod h1:trO7Zu5YdyEuR+BhSNOqJezyFQ3aUzz0njv7sMx/iek= -cloud.google.com/go/dialogflow v1.19.0/go.mod h1:JVmlG1TwykZDtxtTXujec4tQ+D8SBFMoosgy+6Gn0s0= -cloud.google.com/go/dialogflow v1.29.0/go.mod h1:b+2bzMe+k1s9V+F2jbJwpHPzrnIyHihAdRFMtn2WXuM= -cloud.google.com/go/dialogflow v1.31.0/go.mod h1:cuoUccuL1Z+HADhyIA7dci3N5zUssgpBJmCzI6fNRB4= -cloud.google.com/go/dialogflow v1.32.0/go.mod h1:jG9TRJl8CKrDhMEcvfcfFkkpp8ZhgPz3sBGmAUYJ2qE= -cloud.google.com/go/dlp v1.6.0/go.mod h1:9eyB2xIhpU0sVwUixfBubDoRwP+GjeUoxxeueZmqvmM= -cloud.google.com/go/dlp v1.7.0/go.mod h1:68ak9vCiMBjbasxeVD17hVPxDEck+ExiHavX8kiHG+Q= -cloud.google.com/go/dlp v1.9.0/go.mod h1:qdgmqgTyReTz5/YNSSuueR8pl7hO0o9bQ39ZhtgkWp4= -cloud.google.com/go/documentai v1.7.0/go.mod h1:lJvftZB5NRiFSX4moiye1SMxHx0Bc3x1+p9e/RfXYiU= -cloud.google.com/go/documentai v1.8.0/go.mod h1:xGHNEB7CtsnySCNrCFdCyyMz44RhFEEX2Q7UD0c5IhU= -cloud.google.com/go/documentai v1.9.0/go.mod h1:FS5485S8R00U10GhgBC0aNGrJxBP8ZVpEeJ7PQDZd6k= -cloud.google.com/go/documentai v1.10.0/go.mod h1:vod47hKQIPeCfN2QS/jULIvQTugbmdc0ZvxxfQY1bg4= -cloud.google.com/go/documentai v1.16.0/go.mod h1:o0o0DLTEZ+YnJZ+J4wNfTxmDVyrkzFvttBXXtYRMHkM= -cloud.google.com/go/documentai v1.18.0/go.mod h1:F6CK6iUH8J81FehpskRmhLq/3VlwQvb7TvwOceQ2tbs= -cloud.google.com/go/domains v0.6.0/go.mod h1:T9Rz3GasrpYk6mEGHh4rymIhjlnIuB4ofT1wTxDeT4Y= -cloud.google.com/go/domains v0.7.0/go.mod h1:PtZeqS1xjnXuRPKE/88Iru/LdfoRyEHYA9nFQf4UKpg= -cloud.google.com/go/domains v0.8.0/go.mod h1:M9i3MMDzGFXsydri9/vW+EWz9sWb4I6WyHqdlAk0idE= -cloud.google.com/go/edgecontainer v0.1.0/go.mod h1:WgkZ9tp10bFxqO8BLPqv2LlfmQF1X8lZqwW4r1BTajk= -cloud.google.com/go/edgecontainer v0.2.0/go.mod h1:RTmLijy+lGpQ7BXuTDa4C4ssxyXT34NIuHIgKuP4s5w= -cloud.google.com/go/edgecontainer v0.3.0/go.mod h1:FLDpP4nykgwwIfcLt6zInhprzw0lEi2P1fjO6Ie0qbc= -cloud.google.com/go/edgecontainer v1.0.0/go.mod h1:cttArqZpBB2q58W/upSG++ooo6EsblxDIolxa3jSjbY= -cloud.google.com/go/errorreporting v0.3.0/go.mod h1:xsP2yaAp+OAW4OIm60An2bbLpqIhKXdWR/tawvl7QzU= -cloud.google.com/go/essentialcontacts v1.3.0/go.mod h1:r+OnHa5jfj90qIfZDO/VztSFqbQan7HV75p8sA+mdGI= -cloud.google.com/go/essentialcontacts v1.4.0/go.mod h1:8tRldvHYsmnBCHdFpvU+GL75oWiBKl80BiqlFh9tp+8= -cloud.google.com/go/essentialcontacts v1.5.0/go.mod h1:ay29Z4zODTuwliK7SnX8E86aUF2CTzdNtvv42niCX0M= -cloud.google.com/go/eventarc v1.7.0/go.mod h1:6ctpF3zTnaQCxUjHUdcfgcA1A2T309+omHZth7gDfmc= -cloud.google.com/go/eventarc v1.8.0/go.mod h1:imbzxkyAU4ubfsaKYdQg04WS1NvncblHEup4kvF+4gw= -cloud.google.com/go/eventarc v1.10.0/go.mod h1:u3R35tmZ9HvswGRBnF48IlYgYeBcPUCjkr4BTdem2Kw= -cloud.google.com/go/eventarc v1.11.0/go.mod h1:PyUjsUKPWoRBCHeOxZd/lbOOjahV41icXyUY5kSTvVY= -cloud.google.com/go/filestore v1.3.0/go.mod h1:+qbvHGvXU1HaKX2nD0WEPo92TP/8AQuCVEBXNY9z0+w= -cloud.google.com/go/filestore v1.4.0/go.mod h1:PaG5oDfo9r224f8OYXURtAsY+Fbyq/bLYoINEK8XQAI= -cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs= -cloud.google.com/go/filestore v1.6.0/go.mod h1:di5unNuss/qfZTw2U9nhFqo8/ZDSc466dre85Kydllg= -cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= -cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk= -cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg= -cloud.google.com/go/functions v1.8.0/go.mod h1:RTZ4/HsQjIqIYP9a9YPbU+QFoQsAlYgrwOXJWHn1POY= -cloud.google.com/go/functions v1.9.0/go.mod h1:Y+Dz8yGguzO3PpIjhLTbnqV1CWmgQ5UwtlpzoyquQ08= -cloud.google.com/go/functions v1.10.0/go.mod h1:0D3hEOe3DbEvCXtYOZHQZmD+SzYsi1YbI7dGvHfldXw= -cloud.google.com/go/functions v1.12.0/go.mod h1:AXWGrF3e2C/5ehvwYo/GH6O5s09tOPksiKhz+hH8WkA= -cloud.google.com/go/functions v1.13.0/go.mod h1:EU4O007sQm6Ef/PwRsI8N2umygGqPBS/IZQKBQBcJ3c= -cloud.google.com/go/gaming v1.5.0/go.mod h1:ol7rGcxP/qHTRQE/RO4bxkXq+Fix0j6D4LFPzYTIrDM= -cloud.google.com/go/gaming v1.6.0/go.mod h1:YMU1GEvA39Qt3zWGyAVA9bpYz/yAhTvaQ1t2sK4KPUA= -cloud.google.com/go/gaming v1.7.0/go.mod h1:LrB8U7MHdGgFG851iHAfqUdLcKBdQ55hzXy9xBJz0+w= -cloud.google.com/go/gaming v1.8.0/go.mod h1:xAqjS8b7jAVW0KFYeRUxngo9My3f33kFmua++Pi+ggM= -cloud.google.com/go/gaming v1.9.0/go.mod h1:Fc7kEmCObylSWLO334NcO+O9QMDyz+TKC4v1D7X+Bc0= -cloud.google.com/go/gkebackup v0.2.0/go.mod h1:XKvv/4LfG829/B8B7xRkk8zRrOEbKtEam6yNfuQNH60= -cloud.google.com/go/gkebackup v0.3.0/go.mod h1:n/E671i1aOQvUxT541aTkCwExO/bTer2HDlj4TsBRAo= -cloud.google.com/go/gkebackup v0.4.0/go.mod h1:byAyBGUwYGEEww7xsbnUTBHIYcOPy/PgUWUtOeRm9Vg= -cloud.google.com/go/gkeconnect v0.5.0/go.mod h1:c5lsNAg5EwAy7fkqX/+goqFsU1Da/jQFqArp+wGNr/o= -cloud.google.com/go/gkeconnect v0.6.0/go.mod h1:Mln67KyU/sHJEBY8kFZ0xTeyPtzbq9StAVvEULYK16A= -cloud.google.com/go/gkeconnect v0.7.0/go.mod h1:SNfmVqPkaEi3bF/B3CNZOAYPYdg7sU+obZ+QTky2Myw= -cloud.google.com/go/gkehub v0.9.0/go.mod h1:WYHN6WG8w9bXU0hqNxt8rm5uxnk8IH+lPY9J2TV7BK0= -cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y977wO+hBH0= -cloud.google.com/go/gkehub v0.11.0/go.mod h1:JOWHlmN+GHyIbuWQPl47/C2RFhnFKH38jH9Ascu3n0E= -cloud.google.com/go/gkehub v0.12.0/go.mod h1:djiIwwzTTBrF5NaXCGv3mf7klpEMcST17VBTVVDcuaw= -cloud.google.com/go/gkemulticloud v0.3.0/go.mod h1:7orzy7O0S+5kq95e4Hpn7RysVA7dPs8W/GgfUtsPbrA= -cloud.google.com/go/gkemulticloud v0.4.0/go.mod h1:E9gxVBnseLWCk24ch+P9+B2CoDFJZTyIgLKSalC7tuI= -cloud.google.com/go/gkemulticloud v0.5.0/go.mod h1:W0JDkiyi3Tqh0TJr//y19wyb1yf8llHVto2Htf2Ja3Y= -cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc= -cloud.google.com/go/gsuiteaddons v1.3.0/go.mod h1:EUNK/J1lZEZO8yPtykKxLXI6JSVN2rg9bN8SXOa0bgM= -cloud.google.com/go/gsuiteaddons v1.4.0/go.mod h1:rZK5I8hht7u7HxFQcFei0+AtfS9uSushomRlg+3ua1o= -cloud.google.com/go/gsuiteaddons v1.5.0/go.mod h1:TFCClYLd64Eaa12sFVmUyG62tk4mdIsI7pAnSXRkcFo= -cloud.google.com/go/iam v0.1.0/go.mod h1:vcUNEa0pEm0qRVpmWepWaFMIAI8/hjB9mO8rNCJtF6c= -cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= -cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc= -cloud.google.com/go/iam v0.6.0/go.mod h1:+1AH33ueBne5MzYccyMHtEKqLE4/kJOibtffMHDMFMc= -cloud.google.com/go/iam v0.7.0/go.mod h1:H5Br8wRaDGNc8XP3keLc4unfUUZeyH3Sfl9XpQEYOeg= -cloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGESjkE= -cloud.google.com/go/iam v0.11.0/go.mod h1:9PiLDanza5D+oWFZiH1uG+RnRCfEGKoyl6yo4cgWZGY= -cloud.google.com/go/iam v0.12.0/go.mod h1:knyHGviacl11zrtZUoDuYpDgLjvr28sLQaG0YB2GYAY= -cloud.google.com/go/iam v0.13.0/go.mod h1:ljOg+rcNfzZ5d6f1nAUJ8ZIxOaZUVoS14bKCtaLZ/D0= -cloud.google.com/go/iam v1.5.2 h1:qgFRAGEmd8z6dJ/qyEchAuL9jpswyODjA2lS+w234g8= -cloud.google.com/go/iam v1.5.2/go.mod h1:SE1vg0N81zQqLzQEwxL2WI6yhetBdbNQuTvIKCSkUHE= -cloud.google.com/go/iap v1.4.0/go.mod h1:RGFwRJdihTINIe4wZ2iCP0zF/qu18ZwyKxrhMhygBEc= -cloud.google.com/go/iap v1.5.0/go.mod h1:UH/CGgKd4KyohZL5Pt0jSKE4m3FR51qg6FKQ/z/Ix9A= -cloud.google.com/go/iap v1.6.0/go.mod h1:NSuvI9C/j7UdjGjIde7t7HBz+QTwBcapPE07+sSRcLk= -cloud.google.com/go/iap v1.7.0/go.mod h1:beqQx56T9O1G1yNPph+spKpNibDlYIiIixiqsQXxLIo= -cloud.google.com/go/iap v1.7.1/go.mod h1:WapEwPc7ZxGt2jFGB/C/bm+hP0Y6NXzOYGjpPnmMS74= -cloud.google.com/go/ids v1.1.0/go.mod h1:WIuwCaYVOzHIj2OhN9HAwvW+DBdmUAdcWlFxRl+KubM= -cloud.google.com/go/ids v1.2.0/go.mod h1:5WXvp4n25S0rA/mQWAg1YEEBBq6/s+7ml1RDCW1IrcY= -cloud.google.com/go/ids v1.3.0/go.mod h1:JBdTYwANikFKaDP6LtW5JAi4gubs57SVNQjemdt6xV4= -cloud.google.com/go/iot v1.3.0/go.mod h1:r7RGh2B61+B8oz0AGE+J72AhA0G7tdXItODWsaA2oLs= -cloud.google.com/go/iot v1.4.0/go.mod h1:dIDxPOn0UvNDUMD8Ger7FIaTuvMkj+aGk94RPP0iV+g= -cloud.google.com/go/iot v1.5.0/go.mod h1:mpz5259PDl3XJthEmh9+ap0affn/MqNSP4My77Qql9o= -cloud.google.com/go/iot v1.6.0/go.mod h1:IqdAsmE2cTYYNO1Fvjfzo9po179rAtJeVGUvkLN3rLE= -cloud.google.com/go/kms v1.4.0/go.mod h1:fajBHndQ+6ubNw6Ss2sSd+SWvjL26RNo/dr7uxsnnOA= -cloud.google.com/go/kms v1.5.0/go.mod h1:QJS2YY0eJGBg3mnDfuaCyLauWwBJiHRboYxJ++1xJNg= -cloud.google.com/go/kms v1.6.0/go.mod h1:Jjy850yySiasBUDi6KFUwUv2n1+o7QZFyuUJg6OgjA0= -cloud.google.com/go/kms v1.8.0/go.mod h1:4xFEhYFqvW+4VMELtZyxomGSYtSQKzM178ylFW4jMAg= -cloud.google.com/go/kms v1.9.0/go.mod h1:qb1tPTgfF9RQP8e1wq4cLFErVuTJv7UsSC915J8dh3w= -cloud.google.com/go/kms v1.10.0/go.mod h1:ng3KTUtQQU9bPX3+QGLsflZIHlkbn8amFAMY63m8d24= -cloud.google.com/go/kms v1.10.1/go.mod h1:rIWk/TryCkR59GMC3YtHtXeLzd634lBbKenvyySAyYI= -cloud.google.com/go/kms v1.22.0 h1:dBRIj7+GDeeEvatJeTB19oYZNV0aj6wEqSIT/7gLqtk= -cloud.google.com/go/kms v1.22.0/go.mod h1:U7mf8Sva5jpOb4bxYZdtw/9zsbIjrklYwPcvMk34AL8= -cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= -cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= -cloud.google.com/go/language v1.7.0/go.mod h1:DJ6dYN/W+SQOjF8e1hLQXMF21AkH2w9wiPzPCJa2MIE= -cloud.google.com/go/language v1.8.0/go.mod h1:qYPVHf7SPoNNiCL2Dr0FfEFNil1qi3pQEyygwpgVKB8= -cloud.google.com/go/language v1.9.0/go.mod h1:Ns15WooPM5Ad/5no/0n81yUetis74g3zrbeJBE+ptUY= -cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8= -cloud.google.com/go/lifesciences v0.6.0/go.mod h1:ddj6tSX/7BOnhxCSd3ZcETvtNr8NZ6t/iPhY2Tyfu08= -cloud.google.com/go/lifesciences v0.8.0/go.mod h1:lFxiEOMqII6XggGbOnKiyZ7IBwoIqA84ClvoezaA/bo= -cloud.google.com/go/logging v1.6.1/go.mod h1:5ZO0mHHbvm8gEmeEUHrmDlTDSu5imF6MUP9OfilNXBw= -cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M= -cloud.google.com/go/logging v1.13.0 h1:7j0HgAp0B94o1YRDqiqm26w4q1rDMH7XNRU34lJXHYc= -cloud.google.com/go/logging v1.13.0/go.mod h1:36CoKh6KA/M0PbhPKMq6/qety2DCAErbhXT62TuXALA= -cloud.google.com/go/longrunning v0.1.1/go.mod h1:UUFxuDWkv22EuY93jjmDMFT5GPQKeFVJBIF6QlTqdsE= -cloud.google.com/go/longrunning v0.3.0/go.mod h1:qth9Y41RRSUE69rDcOn6DdK3HfQfsUI0YSmW3iIlLJc= -cloud.google.com/go/longrunning v0.4.1/go.mod h1:4iWDqhBZ70CvZ6BfETbvam3T8FMvLK+eFj0E6AaRQTo= +cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs= +cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10= +cloud.google.com/go/iam v1.5.3 h1:+vMINPiDF2ognBJ97ABAYYwRgsaqxPbQDlMnbHMjolc= +cloud.google.com/go/iam v1.5.3/go.mod h1:MR3v9oLkZCTlaqljW6Eb2d3HGDGK5/bDv93jhfISFvU= +cloud.google.com/go/kms v1.23.2 h1:4IYDQL5hG4L+HzJBhzejUySoUOheh3Lk5YT4PCyyW6k= +cloud.google.com/go/kms v1.23.2/go.mod h1:rZ5kK0I7Kn9W4erhYVoIRPtpizjunlrfU4fUkumUp8g= cloud.google.com/go/longrunning v0.6.7 h1:IGtfDWHhQCgCjwQjV9iiLnUta9LBCo8R9QmAFsS/PrE= cloud.google.com/go/longrunning v0.6.7/go.mod h1:EAFV3IZAKmM56TyiE6VAP3VoTzhZzySwI/YI1s/nRsY= -cloud.google.com/go/managedidentities v1.3.0/go.mod h1:UzlW3cBOiPrzucO5qWkNkh0w33KFtBJU281hacNvsdE= -cloud.google.com/go/managedidentities v1.4.0/go.mod h1:NWSBYbEMgqmbZsLIyKvxrYbtqOsxY1ZrGM+9RgDqInM= -cloud.google.com/go/managedidentities v1.5.0/go.mod h1:+dWcZ0JlUmpuxpIDfyP5pP5y0bLdRwOS4Lp7gMni/LA= -cloud.google.com/go/maps v0.1.0/go.mod h1:BQM97WGyfw9FWEmQMpZ5T6cpovXXSd1cGmFma94eubI= -cloud.google.com/go/maps v0.6.0/go.mod h1:o6DAMMfb+aINHz/p/jbcY+mYeXBoZoxTfdSQ8VAJaCw= -cloud.google.com/go/maps v0.7.0/go.mod h1:3GnvVl3cqeSvgMcpRlQidXsPYuDGQ8naBis7MVzpXsY= -cloud.google.com/go/mediatranslation v0.5.0/go.mod h1:jGPUhGTybqsPQn91pNXw0xVHfuJ3leR1wj37oU3y1f4= -cloud.google.com/go/mediatranslation v0.6.0/go.mod h1:hHdBCTYNigsBxshbznuIMFNe5QXEowAuNmmC7h8pu5w= -cloud.google.com/go/mediatranslation v0.7.0/go.mod h1:LCnB/gZr90ONOIQLgSXagp8XUW1ODs2UmUMvcgMfI2I= -cloud.google.com/go/memcache v1.4.0/go.mod h1:rTOfiGZtJX1AaFUrOgsMHX5kAzaTQ8azHiuDoTPzNsE= -cloud.google.com/go/memcache v1.5.0/go.mod h1:dk3fCK7dVo0cUU2c36jKb4VqKPS22BTkf81Xq617aWM= -cloud.google.com/go/memcache v1.6.0/go.mod h1:XS5xB0eQZdHtTuTF9Hf8eJkKtR3pVRCcvJwtm68T3rA= -cloud.google.com/go/memcache v1.7.0/go.mod h1:ywMKfjWhNtkQTxrWxCkCFkoPjLHPW6A7WOTVI8xy3LY= -cloud.google.com/go/memcache v1.9.0/go.mod h1:8oEyzXCu+zo9RzlEaEjHl4KkgjlNDaXbCQeQWlzNFJM= -cloud.google.com/go/metastore v1.5.0/go.mod h1:2ZNrDcQwghfdtCwJ33nM0+GrBGlVuh8rakL3vdPY3XY= -cloud.google.com/go/metastore v1.6.0/go.mod h1:6cyQTls8CWXzk45G55x57DVQ9gWg7RiH65+YgPsNh9s= -cloud.google.com/go/metastore v1.7.0/go.mod h1:s45D0B4IlsINu87/AsWiEVYbLaIMeUSoxlKKDqBGFS8= -cloud.google.com/go/metastore v1.8.0/go.mod h1:zHiMc4ZUpBiM7twCIFQmJ9JMEkDSyZS9U12uf7wHqSI= -cloud.google.com/go/metastore v1.10.0/go.mod h1:fPEnH3g4JJAk+gMRnrAnoqyv2lpUCqJPWOodSaf45Eo= -cloud.google.com/go/monitoring v1.7.0/go.mod h1:HpYse6kkGo//7p6sT0wsIC6IBDET0RhIsnmlA53dvEk= -cloud.google.com/go/monitoring v1.8.0/go.mod h1:E7PtoMJ1kQXWxPjB6mv2fhC5/15jInuulFdYYtlcvT4= -cloud.google.com/go/monitoring v1.12.0/go.mod h1:yx8Jj2fZNEkL/GYZyTLS4ZtZEZN8WtDEiEqG4kLK50w= -cloud.google.com/go/monitoring v1.13.0/go.mod h1:k2yMBAB1H9JT/QETjNkgdCGD9bPF712XiLTVr+cBrpw= -cloud.google.com/go/monitoring v1.24.2 h1:5OTsoJ1dXYIiMiuL+sYscLc9BumrL3CarVLL7dd7lHM= -cloud.google.com/go/monitoring v1.24.2/go.mod h1:x7yzPWcgDRnPEv3sI+jJGBkwl5qINf+6qY4eq0I9B4U= -cloud.google.com/go/networkconnectivity v1.4.0/go.mod h1:nOl7YL8odKyAOtzNX73/M5/mGZgqqMeryi6UPZTk/rA= -cloud.google.com/go/networkconnectivity v1.5.0/go.mod h1:3GzqJx7uhtlM3kln0+x5wyFvuVH1pIBJjhCpjzSt75o= -cloud.google.com/go/networkconnectivity v1.6.0/go.mod h1:OJOoEXW+0LAxHh89nXd64uGG+FbQoeH8DtxCHVOMlaM= -cloud.google.com/go/networkconnectivity v1.7.0/go.mod h1:RMuSbkdbPwNMQjB5HBWD5MpTBnNm39iAVpC3TmsExt8= -cloud.google.com/go/networkconnectivity v1.10.0/go.mod h1:UP4O4sWXJG13AqrTdQCD9TnLGEbtNRqjuaaA7bNjF5E= -cloud.google.com/go/networkconnectivity v1.11.0/go.mod h1:iWmDD4QF16VCDLXUqvyspJjIEtBR/4zq5hwnY2X3scM= -cloud.google.com/go/networkmanagement v1.4.0/go.mod h1:Q9mdLLRn60AsOrPc8rs8iNV6OHXaGcDdsIQe1ohekq8= -cloud.google.com/go/networkmanagement v1.5.0/go.mod h1:ZnOeZ/evzUdUsnvRt792H0uYEnHQEMaz+REhhzJRcf4= -cloud.google.com/go/networkmanagement v1.6.0/go.mod h1:5pKPqyXjB/sgtvB5xqOemumoQNB7y95Q7S+4rjSOPYY= -cloud.google.com/go/networksecurity v0.5.0/go.mod h1:xS6fOCoqpVC5zx15Z/MqkfDwH4+m/61A3ODiDV1xmiQ= -cloud.google.com/go/networksecurity v0.6.0/go.mod h1:Q5fjhTr9WMI5mbpRYEbiexTzROf7ZbDzvzCrNl14nyU= -cloud.google.com/go/networksecurity v0.7.0/go.mod h1:mAnzoxx/8TBSyXEeESMy9OOYwo1v+gZ5eMRnsT5bC8k= -cloud.google.com/go/networksecurity v0.8.0/go.mod h1:B78DkqsxFG5zRSVuwYFRZ9Xz8IcQ5iECsNrPn74hKHU= -cloud.google.com/go/notebooks v1.2.0/go.mod h1:9+wtppMfVPUeJ8fIWPOq1UnATHISkGXGqTkxeieQ6UY= -cloud.google.com/go/notebooks v1.3.0/go.mod h1:bFR5lj07DtCPC7YAAJ//vHskFBxA5JzYlH68kXVdk34= -cloud.google.com/go/notebooks v1.4.0/go.mod h1:4QPMngcwmgb6uw7Po99B2xv5ufVoIQ7nOGDyL4P8AgA= -cloud.google.com/go/notebooks v1.5.0/go.mod h1:q8mwhnP9aR8Hpfnrc5iN5IBhrXUy8S2vuYs+kBJ/gu0= -cloud.google.com/go/notebooks v1.7.0/go.mod h1:PVlaDGfJgj1fl1S3dUwhFMXFgfYGhYQt2164xOMONmE= -cloud.google.com/go/notebooks v1.8.0/go.mod h1:Lq6dYKOYOWUCTvw5t2q1gp1lAp0zxAxRycayS0iJcqQ= -cloud.google.com/go/optimization v1.1.0/go.mod h1:5po+wfvX5AQlPznyVEZjGJTMr4+CAkJf2XSTQOOl9l4= -cloud.google.com/go/optimization v1.2.0/go.mod h1:Lr7SOHdRDENsh+WXVmQhQTrzdu9ybg0NecjHidBq6xs= -cloud.google.com/go/optimization v1.3.1/go.mod h1:IvUSefKiwd1a5p0RgHDbWCIbDFgKuEdB+fPPuP0IDLI= -cloud.google.com/go/orchestration v1.3.0/go.mod h1:Sj5tq/JpWiB//X/q3Ngwdl5K7B7Y0KZ7bfv0wL6fqVA= -cloud.google.com/go/orchestration v1.4.0/go.mod h1:6W5NLFWs2TlniBphAViZEVhrXRSMgUGDfW7vrWKvsBk= -cloud.google.com/go/orchestration v1.6.0/go.mod h1:M62Bevp7pkxStDfFfTuCOaXgaaqRAga1yKyoMtEoWPQ= -cloud.google.com/go/orgpolicy v1.4.0/go.mod h1:xrSLIV4RePWmP9P3tBl8S93lTmlAxjm06NSm2UTmKvE= -cloud.google.com/go/orgpolicy v1.5.0/go.mod h1:hZEc5q3wzwXJaKrsx5+Ewg0u1LxJ51nNFlext7Tanwc= -cloud.google.com/go/orgpolicy v1.10.0/go.mod h1:w1fo8b7rRqlXlIJbVhOMPrwVljyuW5mqssvBtU18ONc= -cloud.google.com/go/osconfig v1.7.0/go.mod h1:oVHeCeZELfJP7XLxcBGTMBvRO+1nQ5tFG9VQTmYS2Fs= -cloud.google.com/go/osconfig v1.8.0/go.mod h1:EQqZLu5w5XA7eKizepumcvWx+m8mJUhEwiPqWiZeEdg= -cloud.google.com/go/osconfig v1.9.0/go.mod h1:Yx+IeIZJ3bdWmzbQU4fxNl8xsZ4amB+dygAwFPlvnNo= -cloud.google.com/go/osconfig v1.10.0/go.mod h1:uMhCzqC5I8zfD9zDEAfvgVhDS8oIjySWh+l4WK6GnWw= -cloud.google.com/go/osconfig v1.11.0/go.mod h1:aDICxrur2ogRd9zY5ytBLV89KEgT2MKB2L/n6x1ooPw= -cloud.google.com/go/oslogin v1.4.0/go.mod h1:YdgMXWRaElXz/lDk1Na6Fh5orF7gvmJ0FGLIs9LId4E= -cloud.google.com/go/oslogin v1.5.0/go.mod h1:D260Qj11W2qx/HVF29zBg+0fd6YCSjSqLUkY/qEenQU= -cloud.google.com/go/oslogin v1.6.0/go.mod h1:zOJ1O3+dTU8WPlGEkFSh7qeHPPSoxrcMbbK1Nm2iX70= -cloud.google.com/go/oslogin v1.7.0/go.mod h1:e04SN0xO1UNJ1M5GP0vzVBFicIe4O53FOfcixIqTyXo= -cloud.google.com/go/oslogin v1.9.0/go.mod h1:HNavntnH8nzrn8JCTT5fj18FuJLFJc4NaZJtBnQtKFs= -cloud.google.com/go/phishingprotection v0.5.0/go.mod h1:Y3HZknsK9bc9dMi+oE8Bim0lczMU6hrX0UpADuMefr0= -cloud.google.com/go/phishingprotection v0.6.0/go.mod h1:9Y3LBLgy0kDTcYET8ZH3bq/7qni15yVUoAxiFxnlSUA= -cloud.google.com/go/phishingprotection v0.7.0/go.mod h1:8qJI4QKHoda/sb/7/YmMQ2omRLSLYSu9bU0EKCNI+Lk= -cloud.google.com/go/policytroubleshooter v1.3.0/go.mod h1:qy0+VwANja+kKrjlQuOzmlvscn4RNsAc0e15GGqfMxg= -cloud.google.com/go/policytroubleshooter v1.4.0/go.mod h1:DZT4BcRw3QoO8ota9xw/LKtPa8lKeCByYeKTIf/vxdE= -cloud.google.com/go/policytroubleshooter v1.5.0/go.mod h1:Rz1WfV+1oIpPdN2VvvuboLVRsB1Hclg3CKQ53j9l8vw= -cloud.google.com/go/policytroubleshooter v1.6.0/go.mod h1:zYqaPTsmfvpjm5ULxAyD/lINQxJ0DDsnWOP/GZ7xzBc= -cloud.google.com/go/privatecatalog v0.5.0/go.mod h1:XgosMUvvPyxDjAVNDYxJ7wBW8//hLDDYmnsNcMGq1K0= -cloud.google.com/go/privatecatalog v0.6.0/go.mod h1:i/fbkZR0hLN29eEWiiwue8Pb+GforiEIBnV9yrRUOKI= -cloud.google.com/go/privatecatalog v0.7.0/go.mod h1:2s5ssIFO69F5csTXcwBP7NPFTZvps26xGzvQ2PQaBYg= -cloud.google.com/go/privatecatalog v0.8.0/go.mod h1:nQ6pfaegeDAq/Q5lrfCQzQLhubPiZhSaNhIgfJlnIXs= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/pubsub v1.26.0/go.mod h1:QgBH3U/jdJy/ftjPhTkyXNj543Tin1pRYcdcPRnFIRI= -cloud.google.com/go/pubsub v1.27.1/go.mod h1:hQN39ymbV9geqBnfQq6Xf63yNhUAhv9CZhzp5O6qsW0= -cloud.google.com/go/pubsub v1.28.0/go.mod h1:vuXFpwaVoIPQMGXqRyUQigu/AX1S3IWugR9xznmcXX8= -cloud.google.com/go/pubsub v1.30.0/go.mod h1:qWi1OPS0B+b5L+Sg6Gmc9zD1Y+HaM0MdUr7LsupY1P4= -cloud.google.com/go/pubsublite v1.5.0/go.mod h1:xapqNQ1CuLfGi23Yda/9l4bBCKz/wC3KIJ5gKcxveZg= -cloud.google.com/go/pubsublite v1.6.0/go.mod h1:1eFCS0U11xlOuMFV/0iBqw3zP12kddMeCbj/F3FSj9k= -cloud.google.com/go/pubsublite v1.7.0/go.mod h1:8hVMwRXfDfvGm3fahVbtDbiLePT3gpoiJYJY+vxWxVM= -cloud.google.com/go/recaptchaenterprise v1.3.1/go.mod h1:OdD+q+y4XGeAlxRaMn1Y7/GveP6zmq76byL6tjPE7d4= -cloud.google.com/go/recaptchaenterprise/v2 v2.1.0/go.mod h1:w9yVqajwroDNTfGuhmOjPDN//rZGySaf6PtFVcSCa7o= -cloud.google.com/go/recaptchaenterprise/v2 v2.2.0/go.mod h1:/Zu5jisWGeERrd5HnlS3EUGb/D335f9k51B/FVil0jk= -cloud.google.com/go/recaptchaenterprise/v2 v2.3.0/go.mod h1:O9LwGCjrhGHBQET5CA7dd5NwwNQUErSgEDit1DLNTdo= -cloud.google.com/go/recaptchaenterprise/v2 v2.4.0/go.mod h1:Am3LHfOuBstrLrNCBrlI5sbwx9LBg3te2N6hGvHn2mE= -cloud.google.com/go/recaptchaenterprise/v2 v2.5.0/go.mod h1:O8LzcHXN3rz0j+LBC91jrwI3R+1ZSZEWrfL7XHgNo9U= -cloud.google.com/go/recaptchaenterprise/v2 v2.6.0/go.mod h1:RPauz9jeLtB3JVzg6nCbe12qNoaa8pXc4d/YukAmcnA= -cloud.google.com/go/recaptchaenterprise/v2 v2.7.0/go.mod h1:19wVj/fs5RtYtynAPJdDTb69oW0vNHYDBTbB4NvMD9c= -cloud.google.com/go/recommendationengine v0.5.0/go.mod h1:E5756pJcVFeVgaQv3WNpImkFP8a+RptV6dDLGPILjvg= -cloud.google.com/go/recommendationengine v0.6.0/go.mod h1:08mq2umu9oIqc7tDy8sx+MNJdLG0fUi3vaSVbztHgJ4= -cloud.google.com/go/recommendationengine v0.7.0/go.mod h1:1reUcE3GIu6MeBz/h5xZJqNLuuVjNg1lmWMPyjatzac= -cloud.google.com/go/recommender v1.5.0/go.mod h1:jdoeiBIVrJe9gQjwd759ecLJbxCDED4A6p+mqoqDvTg= -cloud.google.com/go/recommender v1.6.0/go.mod h1:+yETpm25mcoiECKh9DEScGzIRyDKpZ0cEhWGo+8bo+c= -cloud.google.com/go/recommender v1.7.0/go.mod h1:XLHs/W+T8olwlGOgfQenXBTbIseGclClff6lhFVe9Bs= -cloud.google.com/go/recommender v1.8.0/go.mod h1:PkjXrTT05BFKwxaUxQmtIlrtj0kph108r02ZZQ5FE70= -cloud.google.com/go/recommender v1.9.0/go.mod h1:PnSsnZY7q+VL1uax2JWkt/UegHssxjUVVCrX52CuEmQ= -cloud.google.com/go/redis v1.7.0/go.mod h1:V3x5Jq1jzUcg+UNsRvdmsfuFnit1cfe3Z/PGyq/lm4Y= -cloud.google.com/go/redis v1.8.0/go.mod h1:Fm2szCDavWzBk2cDKxrkmWBqoCiL1+Ctwq7EyqBCA/A= -cloud.google.com/go/redis v1.9.0/go.mod h1:HMYQuajvb2D0LvMgZmLDZW8V5aOC/WxstZHiy4g8OiA= -cloud.google.com/go/redis v1.10.0/go.mod h1:ThJf3mMBQtW18JzGgh41/Wld6vnDDc/F/F35UolRZPM= -cloud.google.com/go/redis v1.11.0/go.mod h1:/X6eicana+BWcUda5PpwZC48o37SiFVTFSs0fWAJ7uQ= -cloud.google.com/go/resourcemanager v1.3.0/go.mod h1:bAtrTjZQFJkiWTPDb1WBjzvc6/kifjj4QBYuKCCoqKA= -cloud.google.com/go/resourcemanager v1.4.0/go.mod h1:MwxuzkumyTX7/a3n37gmsT3py7LIXwrShilPh3P1tR0= -cloud.google.com/go/resourcemanager v1.5.0/go.mod h1:eQoXNAiAvCf5PXxWxXjhKQoTMaUSNrEfg+6qdf/wots= -cloud.google.com/go/resourcemanager v1.6.0/go.mod h1:YcpXGRs8fDzcUl1Xw8uOVmI8JEadvhRIkoXXUNVYcVo= -cloud.google.com/go/resourcemanager v1.7.0/go.mod h1:HlD3m6+bwhzj9XCouqmeiGuni95NTrExfhoSrkC/3EI= -cloud.google.com/go/resourcesettings v1.3.0/go.mod h1:lzew8VfESA5DQ8gdlHwMrqZs1S9V87v3oCnKCWoOuQU= -cloud.google.com/go/resourcesettings v1.4.0/go.mod h1:ldiH9IJpcrlC3VSuCGvjR5of/ezRrOxFtpJoJo5SmXg= -cloud.google.com/go/resourcesettings v1.5.0/go.mod h1:+xJF7QSG6undsQDfsCJyqWXyBwUoJLhetkRMDRnIoXA= -cloud.google.com/go/retail v1.8.0/go.mod h1:QblKS8waDmNUhghY2TI9O3JLlFk8jybHeV4BF19FrE4= -cloud.google.com/go/retail v1.9.0/go.mod h1:g6jb6mKuCS1QKnH/dpu7isX253absFl6iE92nHwlBUY= -cloud.google.com/go/retail v1.10.0/go.mod h1:2gDk9HsL4HMS4oZwz6daui2/jmKvqShXKQuB2RZ+cCc= -cloud.google.com/go/retail v1.11.0/go.mod h1:MBLk1NaWPmh6iVFSz9MeKG/Psyd7TAgm6y/9L2B4x9Y= -cloud.google.com/go/retail v1.12.0/go.mod h1:UMkelN/0Z8XvKymXFbD4EhFJlYKRx1FGhQkVPU5kF14= -cloud.google.com/go/run v0.2.0/go.mod h1:CNtKsTA1sDcnqqIFR3Pb5Tq0usWxJJvsWOCPldRU3Do= -cloud.google.com/go/run v0.3.0/go.mod h1:TuyY1+taHxTjrD0ZFk2iAR+xyOXEA0ztb7U3UNA0zBo= -cloud.google.com/go/run v0.8.0/go.mod h1:VniEnuBwqjigv0A7ONfQUaEItaiCRVujlMqerPPiktM= -cloud.google.com/go/run v0.9.0/go.mod h1:Wwu+/vvg8Y+JUApMwEDfVfhetv30hCG4ZwDR/IXl2Qg= -cloud.google.com/go/scheduler v1.4.0/go.mod h1:drcJBmxF3aqZJRhmkHQ9b3uSSpQoltBPGPxGAWROx6s= -cloud.google.com/go/scheduler v1.5.0/go.mod h1:ri073ym49NW3AfT6DZi21vLZrG07GXr5p3H1KxN5QlI= -cloud.google.com/go/scheduler v1.6.0/go.mod h1:SgeKVM7MIwPn3BqtcBntpLyrIJftQISRrYB5ZtT+KOk= -cloud.google.com/go/scheduler v1.7.0/go.mod h1:jyCiBqWW956uBjjPMMuX09n3x37mtyPJegEWKxRsn44= -cloud.google.com/go/scheduler v1.8.0/go.mod h1:TCET+Y5Gp1YgHT8py4nlg2Sew8nUHMqcpousDgXJVQc= -cloud.google.com/go/scheduler v1.9.0/go.mod h1:yexg5t+KSmqu+njTIh3b7oYPheFtBWGcbVUYF1GGMIc= -cloud.google.com/go/secretmanager v1.6.0/go.mod h1:awVa/OXF6IiyaU1wQ34inzQNc4ISIDIrId8qE5QGgKA= -cloud.google.com/go/secretmanager v1.8.0/go.mod h1:hnVgi/bN5MYHd3Gt0SPuTPPp5ENina1/LxM+2W9U9J4= -cloud.google.com/go/secretmanager v1.9.0/go.mod h1:b71qH2l1yHmWQHt9LC80akm86mX8AL6X1MA01dW8ht4= -cloud.google.com/go/secretmanager v1.10.0/go.mod h1:MfnrdvKMPNra9aZtQFvBcvRU54hbPD8/HayQdlUgJpU= -cloud.google.com/go/security v1.5.0/go.mod h1:lgxGdyOKKjHL4YG3/YwIL2zLqMFCKs0UbQwgyZmfJl4= -cloud.google.com/go/security v1.7.0/go.mod h1:mZklORHl6Bg7CNnnjLH//0UlAlaXqiG7Lb9PsPXLfD0= -cloud.google.com/go/security v1.8.0/go.mod h1:hAQOwgmaHhztFhiQ41CjDODdWP0+AE1B3sX4OFlq+GU= -cloud.google.com/go/security v1.9.0/go.mod h1:6Ta1bO8LXI89nZnmnsZGp9lVoVWXqsVbIq/t9dzI+2Q= -cloud.google.com/go/security v1.10.0/go.mod h1:QtOMZByJVlibUT2h9afNDWRZ1G96gVywH8T5GUSb9IA= -cloud.google.com/go/security v1.12.0/go.mod h1:rV6EhrpbNHrrxqlvW0BWAIawFWq3X90SduMJdFwtLB8= -cloud.google.com/go/security v1.13.0/go.mod h1:Q1Nvxl1PAgmeW0y3HTt54JYIvUdtcpYKVfIB8AOMZ+0= -cloud.google.com/go/securitycenter v1.13.0/go.mod h1:cv5qNAqjY84FCN6Y9z28WlkKXyWsgLO832YiWwkCWcU= -cloud.google.com/go/securitycenter v1.14.0/go.mod h1:gZLAhtyKv85n52XYWt6RmeBdydyxfPeTrpToDPw4Auc= -cloud.google.com/go/securitycenter v1.15.0/go.mod h1:PeKJ0t8MoFmmXLXWm41JidyzI3PJjd8sXWaVqg43WWk= -cloud.google.com/go/securitycenter v1.16.0/go.mod h1:Q9GMaLQFUD+5ZTabrbujNWLtSLZIZF7SAR0wWECrjdk= -cloud.google.com/go/securitycenter v1.18.1/go.mod h1:0/25gAzCM/9OL9vVx4ChPeM/+DlfGQJDwBy/UC8AKK0= -cloud.google.com/go/securitycenter v1.19.0/go.mod h1:LVLmSg8ZkkyaNy4u7HCIshAngSQ8EcIRREP3xBnyfag= -cloud.google.com/go/servicecontrol v1.4.0/go.mod h1:o0hUSJ1TXJAmi/7fLJAedOovnujSEvjKCAFNXPQ1RaU= -cloud.google.com/go/servicecontrol v1.5.0/go.mod h1:qM0CnXHhyqKVuiZnGKrIurvVImCs8gmqWsDoqe9sU1s= -cloud.google.com/go/servicecontrol v1.10.0/go.mod h1:pQvyvSRh7YzUF2efw7H87V92mxU8FnFDawMClGCNuAA= -cloud.google.com/go/servicecontrol v1.11.0/go.mod h1:kFmTzYzTUIuZs0ycVqRHNaNhgR+UMUpw9n02l/pY+mc= -cloud.google.com/go/servicecontrol v1.11.1/go.mod h1:aSnNNlwEFBY+PWGQ2DoM0JJ/QUXqV5/ZD9DOLB7SnUk= -cloud.google.com/go/servicedirectory v1.4.0/go.mod h1:gH1MUaZCgtP7qQiI+F+A+OpeKF/HQWgtAddhTbhL2bs= -cloud.google.com/go/servicedirectory v1.5.0/go.mod h1:QMKFL0NUySbpZJ1UZs3oFAmdvVxhhxB6eJ/Vlp73dfg= -cloud.google.com/go/servicedirectory v1.6.0/go.mod h1:pUlbnWsLH9c13yGkxCmfumWEPjsRs1RlmJ4pqiNjVL4= -cloud.google.com/go/servicedirectory v1.7.0/go.mod h1:5p/U5oyvgYGYejufvxhgwjL8UVXjkuw7q5XcG10wx1U= -cloud.google.com/go/servicedirectory v1.8.0/go.mod h1:srXodfhY1GFIPvltunswqXpVxFPpZjf8nkKQT7XcXaY= -cloud.google.com/go/servicedirectory v1.9.0/go.mod h1:29je5JjiygNYlmsGz8k6o+OZ8vd4f//bQLtvzkPPT/s= -cloud.google.com/go/servicemanagement v1.4.0/go.mod h1:d8t8MDbezI7Z2R1O/wu8oTggo3BI2GKYbdG4y/SJTco= -cloud.google.com/go/servicemanagement v1.5.0/go.mod h1:XGaCRe57kfqu4+lRxaFEAuqmjzF0r+gWHjWqKqBvKFo= -cloud.google.com/go/servicemanagement v1.6.0/go.mod h1:aWns7EeeCOtGEX4OvZUWCCJONRZeFKiptqKf1D0l/Jc= -cloud.google.com/go/servicemanagement v1.8.0/go.mod h1:MSS2TDlIEQD/fzsSGfCdJItQveu9NXnUniTrq/L8LK4= -cloud.google.com/go/serviceusage v1.3.0/go.mod h1:Hya1cozXM4SeSKTAgGXgj97GlqUvF5JaoXacR1JTP/E= -cloud.google.com/go/serviceusage v1.4.0/go.mod h1:SB4yxXSaYVuUBYUml6qklyONXNLt83U0Rb+CXyhjEeU= -cloud.google.com/go/serviceusage v1.5.0/go.mod h1:w8U1JvqUqwJNPEOTQjrMHkw3IaIFLoLsPLvsE3xueec= -cloud.google.com/go/serviceusage v1.6.0/go.mod h1:R5wwQcbOWsyuOfbP9tGdAnCAc6B9DRwPG1xtWMDeuPA= -cloud.google.com/go/shell v1.3.0/go.mod h1:VZ9HmRjZBsjLGXusm7K5Q5lzzByZmJHf1d0IWHEN5X4= -cloud.google.com/go/shell v1.4.0/go.mod h1:HDxPzZf3GkDdhExzD/gs8Grqk+dmYcEjGShZgYa9URw= -cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+qE2f9A= -cloud.google.com/go/spanner v1.41.0/go.mod h1:MLYDBJR/dY4Wt7ZaMIQ7rXOTLjYrmxLE/5ve9vFfWos= -cloud.google.com/go/spanner v1.44.0/go.mod h1:G8XIgYdOK+Fbcpbs7p2fiprDw4CaZX63whnSMLVBxjk= -cloud.google.com/go/spanner v1.45.0/go.mod h1:FIws5LowYz8YAE1J8fOS7DJup8ff7xJeetWEo5REA2M= -cloud.google.com/go/spanner v1.82.0 h1:w9uO8RqEoBooBLX4nqV1RtgudyU2ZX780KTLRgeVg60= -cloud.google.com/go/spanner v1.82.0/go.mod h1:BzybQHFQ/NqGxvE/M+/iU29xgutJf7Q85/4U9RWMto0= -cloud.google.com/go/speech v1.6.0/go.mod h1:79tcr4FHCimOp56lwC01xnt/WPJZc4v3gzyT7FoBkCM= -cloud.google.com/go/speech v1.7.0/go.mod h1:KptqL+BAQIhMsj1kOP2la5DSEEerPDuOP/2mmkhHhZQ= -cloud.google.com/go/speech v1.8.0/go.mod h1:9bYIl1/tjsAnMgKGHKmBZzXKEkGgtU+MpdDPTE9f7y0= -cloud.google.com/go/speech v1.9.0/go.mod h1:xQ0jTcmnRFFM2RfX/U+rk6FQNUF6DQlydUSyoooSpco= -cloud.google.com/go/speech v1.14.1/go.mod h1:gEosVRPJ9waG7zqqnsHpYTOoAS4KouMRLDFMekpJ0J0= -cloud.google.com/go/speech v1.15.0/go.mod h1:y6oH7GhqCaZANH7+Oe0BhgIogsNInLlz542tg3VqeYI= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= -cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= -cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeLgDvXzfIXc= -cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s= -cloud.google.com/go/storage v1.28.1/go.mod h1:Qnisd4CqDdo6BGs2AD5LLnEsmSQ80wQ5ogcBBKhU86Y= -cloud.google.com/go/storage v1.29.0/go.mod h1:4puEjyTKnku6gfKoTfNOU/W+a9JyuVNxjpS5GBrB8h4= -cloud.google.com/go/storage v1.55.0 h1:NESjdAToN9u1tmhVqhXCaCwYBuvEhZLLv0gBr+2znf0= -cloud.google.com/go/storage v1.55.0/go.mod h1:ztSmTTwzsdXe5syLVS0YsbFxXuvEmEyZj7v7zChEmuY= -cloud.google.com/go/storagetransfer v1.5.0/go.mod h1:dxNzUopWy7RQevYFHewchb29POFv3/AaBgnhqzqiK0w= -cloud.google.com/go/storagetransfer v1.6.0/go.mod h1:y77xm4CQV/ZhFZH75PLEXY0ROiS7Gh6pSKrM8dJyg6I= -cloud.google.com/go/storagetransfer v1.7.0/go.mod h1:8Giuj1QNb1kfLAiWM1bN6dHzfdlDAVC9rv9abHot2W4= -cloud.google.com/go/storagetransfer v1.8.0/go.mod h1:JpegsHHU1eXg7lMHkvf+KE5XDJ7EQu0GwNJbbVGanEw= -cloud.google.com/go/talent v1.1.0/go.mod h1:Vl4pt9jiHKvOgF9KoZo6Kob9oV4lwd/ZD5Cto54zDRw= -cloud.google.com/go/talent v1.2.0/go.mod h1:MoNF9bhFQbiJ6eFD3uSsg0uBALw4n4gaCaEjBw9zo8g= -cloud.google.com/go/talent v1.3.0/go.mod h1:CmcxwJ/PKfRgd1pBjQgU6W3YBwiewmUzQYH5HHmSCmM= -cloud.google.com/go/talent v1.4.0/go.mod h1:ezFtAgVuRf8jRsvyE6EwmbTK5LKciD4KVnHuDEFmOOA= -cloud.google.com/go/talent v1.5.0/go.mod h1:G+ODMj9bsasAEJkQSzO2uHQWXHHXUomArjWQQYkqK6c= -cloud.google.com/go/texttospeech v1.4.0/go.mod h1:FX8HQHA6sEpJ7rCMSfXuzBcysDAuWusNNNvN9FELDd8= -cloud.google.com/go/texttospeech v1.5.0/go.mod h1:oKPLhR4n4ZdQqWKURdwxMy0uiTS1xU161C8W57Wkea4= -cloud.google.com/go/texttospeech v1.6.0/go.mod h1:YmwmFT8pj1aBblQOI3TfKmwibnsfvhIBzPXcW4EBovc= -cloud.google.com/go/tpu v1.3.0/go.mod h1:aJIManG0o20tfDQlRIej44FcwGGl/cD0oiRyMKG19IQ= -cloud.google.com/go/tpu v1.4.0/go.mod h1:mjZaX8p0VBgllCzF6wcU2ovUXN9TONFLd7iz227X2Xg= -cloud.google.com/go/tpu v1.5.0/go.mod h1:8zVo1rYDFuW2l4yZVY0R0fb/v44xLh3llq7RuV61fPM= -cloud.google.com/go/trace v1.3.0/go.mod h1:FFUE83d9Ca57C+K8rDl/Ih8LwOzWIV1krKgxg6N0G28= -cloud.google.com/go/trace v1.4.0/go.mod h1:UG0v8UBqzusp+z63o7FK74SdFE+AXpCLdFb1rshXG+Y= -cloud.google.com/go/trace v1.8.0/go.mod h1:zH7vcsbAhklH8hWFig58HvxcxyQbaIqMarMg9hn5ECA= -cloud.google.com/go/trace v1.9.0/go.mod h1:lOQqpE5IaWY0Ixg7/r2SjixMuc6lfTFeO4QGM4dQWOk= -cloud.google.com/go/trace v1.11.6 h1:2O2zjPzqPYAHrn3OKl029qlqG6W8ZdYaOWRyr8NgMT4= -cloud.google.com/go/trace v1.11.6/go.mod h1:GA855OeDEBiBMzcckLPE2kDunIpC72N+Pq8WFieFjnI= -cloud.google.com/go/translate v1.3.0/go.mod h1:gzMUwRjvOqj5i69y/LYLd8RrNQk+hOmIXTi9+nb3Djs= -cloud.google.com/go/translate v1.4.0/go.mod h1:06Dn/ppvLD6WvA5Rhdp029IX2Mi3Mn7fpMRLPvXT5Wg= -cloud.google.com/go/translate v1.5.0/go.mod h1:29YDSYveqqpA1CQFD7NQuP49xymq17RXNaUDdc0mNu0= -cloud.google.com/go/translate v1.6.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= -cloud.google.com/go/translate v1.7.0/go.mod h1:lMGRudH1pu7I3n3PETiOB2507gf3HnfLV8qlkHZEyos= -cloud.google.com/go/video v1.8.0/go.mod h1:sTzKFc0bUSByE8Yoh8X0mn8bMymItVGPfTuUBUyRgxk= -cloud.google.com/go/video v1.9.0/go.mod h1:0RhNKFRF5v92f8dQt0yhaHrEuH95m068JYOvLZYnJSw= -cloud.google.com/go/video v1.12.0/go.mod h1:MLQew95eTuaNDEGriQdcYn0dTwf9oWiA4uYebxM5kdg= -cloud.google.com/go/video v1.13.0/go.mod h1:ulzkYlYgCp15N2AokzKjy7MQ9ejuynOJdf1tR5lGthk= -cloud.google.com/go/video v1.14.0/go.mod h1:SkgaXwT+lIIAKqWAJfktHT/RbgjSuY6DobxEp0C5yTQ= -cloud.google.com/go/video v1.15.0/go.mod h1:SkgaXwT+lIIAKqWAJfktHT/RbgjSuY6DobxEp0C5yTQ= -cloud.google.com/go/videointelligence v1.6.0/go.mod h1:w0DIDlVRKtwPCn/C4iwZIJdvC69yInhW0cfi+p546uU= -cloud.google.com/go/videointelligence v1.7.0/go.mod h1:k8pI/1wAhjznARtVT9U1llUaFNPh7muw8QyOUpavru4= -cloud.google.com/go/videointelligence v1.8.0/go.mod h1:dIcCn4gVDdS7yte/w+koiXn5dWVplOZkE+xwG9FgK+M= -cloud.google.com/go/videointelligence v1.9.0/go.mod h1:29lVRMPDYHikk3v8EdPSaL8Ku+eMzDljjuvRs105XoU= -cloud.google.com/go/videointelligence v1.10.0/go.mod h1:LHZngX1liVtUhZvi2uNS0VQuOzNi2TkY1OakiuoUOjU= -cloud.google.com/go/vision v1.2.0/go.mod h1:SmNwgObm5DpFBme2xpyOyasvBc1aPdjvMk2bBk0tKD0= -cloud.google.com/go/vision/v2 v2.2.0/go.mod h1:uCdV4PpN1S0jyCyq8sIM42v2Y6zOLkZs+4R9LrGYwFo= -cloud.google.com/go/vision/v2 v2.3.0/go.mod h1:UO61abBx9QRMFkNBbf1D8B1LXdS2cGiiCRx0vSpZoUo= -cloud.google.com/go/vision/v2 v2.4.0/go.mod h1:VtI579ll9RpVTrdKdkMzckdnwMyX2JILb+MhPqRbPsY= -cloud.google.com/go/vision/v2 v2.5.0/go.mod h1:MmaezXOOE+IWa+cS7OhRRLK2cNv1ZL98zhqFFZaaH2E= -cloud.google.com/go/vision/v2 v2.6.0/go.mod h1:158Hes0MvOS9Z/bDMSFpjwsUrZ5fPrdwuyyvKSGAGMY= -cloud.google.com/go/vision/v2 v2.7.0/go.mod h1:H89VysHy21avemp6xcf9b9JvZHVehWbET0uT/bcuY/0= -cloud.google.com/go/vmmigration v1.2.0/go.mod h1:IRf0o7myyWFSmVR1ItrBSFLFD/rJkfDCUTO4vLlJvsE= -cloud.google.com/go/vmmigration v1.3.0/go.mod h1:oGJ6ZgGPQOFdjHuocGcLqX4lc98YQ7Ygq8YQwHh9A7g= -cloud.google.com/go/vmmigration v1.5.0/go.mod h1:E4YQ8q7/4W9gobHjQg4JJSgXXSgY21nA5r8swQV+Xxc= -cloud.google.com/go/vmmigration v1.6.0/go.mod h1:bopQ/g4z+8qXzichC7GW1w2MjbErL54rk3/C843CjfY= -cloud.google.com/go/vmwareengine v0.1.0/go.mod h1:RsdNEf/8UDvKllXhMz5J40XxDrNJNN4sagiox+OI208= -cloud.google.com/go/vmwareengine v0.2.2/go.mod h1:sKdctNJxb3KLZkE/6Oui94iw/xs9PRNC2wnNLXsHvH8= -cloud.google.com/go/vmwareengine v0.3.0/go.mod h1:wvoyMvNWdIzxMYSpH/R7y2h5h3WFkx6d+1TIsP39WGY= -cloud.google.com/go/vpcaccess v1.4.0/go.mod h1:aQHVbTWDYUR1EbTApSVvMq1EnT57ppDmQzZ3imqIk4w= -cloud.google.com/go/vpcaccess v1.5.0/go.mod h1:drmg4HLk9NkZpGfCmZ3Tz0Bwnm2+DKqViEpeEpOq0m8= -cloud.google.com/go/vpcaccess v1.6.0/go.mod h1:wX2ILaNhe7TlVa4vC5xce1bCnqE3AeH27RV31lnmZes= -cloud.google.com/go/webrisk v1.4.0/go.mod h1:Hn8X6Zr+ziE2aNd8SliSDWpEnSS1u4R9+xXZmFiHmGE= -cloud.google.com/go/webrisk v1.5.0/go.mod h1:iPG6fr52Tv7sGk0H6qUFzmL3HHZev1htXuWDEEsqMTg= -cloud.google.com/go/webrisk v1.6.0/go.mod h1:65sW9V9rOosnc9ZY7A7jsy1zoHS5W9IAXv6dGqhMQMc= -cloud.google.com/go/webrisk v1.7.0/go.mod h1:mVMHgEYH0r337nmt1JyLthzMr6YxwN1aAIEc2fTcq7A= -cloud.google.com/go/webrisk v1.8.0/go.mod h1:oJPDuamzHXgUc+b8SiHRcVInZQuybnvEW72PqTc7sSg= -cloud.google.com/go/websecurityscanner v1.3.0/go.mod h1:uImdKm2wyeXQevQJXeh8Uun/Ym1VqworNDlBXQevGMo= -cloud.google.com/go/websecurityscanner v1.4.0/go.mod h1:ebit/Fp0a+FWu5j4JOmJEV8S8CzdTkAS77oDsiSqYWQ= -cloud.google.com/go/websecurityscanner v1.5.0/go.mod h1:Y6xdCPy81yi0SQnDY1xdNTNpfY1oAgXUlcfN3B3eSng= -cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1Vwf+KmJENM0= -cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= -cloud.google.com/go/workflows v1.8.0/go.mod h1:ysGhmEajwZxGn1OhGOGKsTXc5PyxOc0vfKf5Af+to4M= -cloud.google.com/go/workflows v1.9.0/go.mod h1:ZGkj1aFIOd9c8Gerkjjq7OW7I5+l6cSvT3ujaO/WwSA= -cloud.google.com/go/workflows v1.10.0/go.mod h1:fZ8LmRmZQWacon9UCX1r/g/DfAXx5VcPALq2CxzdePw= -cuelabs.dev/go/oci/ociregistry v0.0.0-20241125120445-2c00c104c6e1 h1:mRwydyTyhtRX2wXS3mqYWzR2qlv6KsmoKXmlz5vInjg= -cuelabs.dev/go/oci/ociregistry v0.0.0-20241125120445-2c00c104c6e1/go.mod h1:5A4xfTzHTXfeVJBU6RAUf+QrlfTCW+017q/QiW+sMLg= -cuelang.org/go v0.12.1 h1:5I+zxmXim9MmiN2tqRapIqowQxABv2NKTgbOspud1Eo= -cuelang.org/go v0.12.1/go.mod h1:B4+kjvGGQnbkz+GuAv1dq/R308gTkp0sO28FdMrJ2Kw= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +cuelabs.dev/go/oci/ociregistry v0.0.0-20250722084951-074d06050084 h1:4k1yAtPvZJZQTu8DRY8muBo0LHv6TqtrE0AO5n6IPYs= +cuelabs.dev/go/oci/ociregistry v0.0.0-20250722084951-074d06050084/go.mod h1:4WWeZNxUO1vRoZWAHIG0KZOd6dA25ypyWuwD3ti0Tdc= +cuelang.org/go v0.15.1 h1:MRnjc/KJE+K42rnJ3a+425f1jqXeOOgq9SK4tYRTtWw= +cuelang.org/go v0.15.1/go.mod h1:NYw6n4akZcTjA7QQwJ1/gqWrrhsN4aZwhcAL0jv9rZE= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= -gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= -git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc= github.com/AdamKorcz/go-fuzz-headers-1 v0.0.0-20230919221257-8b5d3ce2d11d h1:zjqpY4C7H15HjRPEenkS4SAn3Jy2eRRjkjZbGR30TOg= github.com/AdamKorcz/go-fuzz-headers-1 v0.0.0-20230919221257-8b5d3ce2d11d/go.mod h1:XNqJ7hv2kY++g8XEHREpi+JqZo3+0l+CH2egBVN4yqM= github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/provider v0.14.0 h1:kcnfY4vljxXliXDBrA9K9lwF8IoEZ4Up6Eg9kWTIm28= github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/provider v0.14.0/go.mod h1:tlqp9mUGbsP+0z3Q+c0Q5MgSdq/OMwQhm5bffR3Q3ss= 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.18.0 h1:Gt0j3wceWMwPmiazCa8MzMA0MfhmPIz0Qp0FJ6qcM0U= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0/go.mod h1:Ot/6aikWnKWi4l9QB7qVSwa8iMphQNqkWALMoNT3rzM= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1 h1:B+blDbyVIG3WaikNxPnhPiJ1MThR03b3vKGtER95TP4= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1/go.mod h1:JdM5psgjfBf5fo2uWOZhflPWyDBZ/O/CNAH9CtsuZE4= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.20.0 h1:JXg2dwJUmPB9JmtVmdEB16APJ7jurfbY5jnfXpJoRMc= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.20.0/go.mod h1:YD5h/ldMsG0XiIw7PdyNhLxaM317eFh5yNLccNfGdyw= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1 h1:Hk5QBxZQC1jb2Fwj6mpzme37xbCDdNTxU7O9eb5+LB4= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1/go.mod h1:IYus9qsFobWIc2YVwe/WPjcnyCkPKtnHAqUYeebc8z0= github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2 h1:yz1bePFlP5Vws5+8ez6T3HWXPmwOK7Yvq8QxDBD3SKY= github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2/go.mod h1:Pa9ZNPuoNu/GztvBSKk9J1cDJW6vk/n0zLtV4mgd8N8= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 h1:FPKJS1T+clwv+OLGt13a8UjqeRuh0O4SJ3lUriThc+4= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1/go.mod h1:j2chePtV91HrC22tGoRX3sGY42uF13WzmmV80/OdVAA= -github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.3.1 h1:Wgf5rZba3YZqeTNJPtvqZoBu1sBN/L4sry+u2U3Y75w= -github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.3.1/go.mod h1:xxCBG/f/4Vbmh2XQJBsOmNdxWUY5j/s27jujKPbQf14= -github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.1.1 h1:bFWuoEKg+gImo7pvkiQEFAc8ocibADgXeiLAxWhWmkI= -github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.1.1/go.mod h1:Vih/3yc6yac2JzU4hzpaDupBJP0Flaia9rXXrU8xyww= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 h1:9iefClla7iYpfYWdzPCRDozdmndjTm8DXdpCzPajMgA= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2/go.mod h1:XtLgD3ZD34DAaVIIAyG3objl5DynM3CQ/vMcbBNJZGI= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.4.0 h1:E4MgwLBGeVB5f2MdcIVD3ELVAWpr+WD6MUe1i+tM/PA= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.4.0/go.mod h1:Y2b/1clN4zsAoUd/pgNAQHjLDnTis/6ROkUfyob6psM= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.2.0 h1:nCYfgcSyHZXJI8J0IWE5MsCGlb2xp9fJiXyxWgmOFg4= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.2.0/go.mod h1:ucUjca2JtSZboY8IoUqyQyuuXvwbMBVwFOm0vdQPNhA= github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg= github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= @@ -674,34 +66,17 @@ 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/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.4.2 h1:oygO0locgZJe7PpYPXT5A29ZkwJaPqcva7BVeemZOZs= -github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= +github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0 h1:XRzhVemXdgvJqCH0sFfrBUTnUJSBrBf7++ypk+twtRs= +github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0/go.mod h1:HKpQxkWaGLJ+D/5H8QRpyQXA1eKjxkFlOMwck5+33Jk= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU= github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU= -github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp v1.5.2 h1:DBjmt6/otSdULyJdVg2BlG0qGZO5tKL4VzOs0jpvw5Q= -github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp v1.5.2/go.mod h1:dppbR7CwXD4pgtV9t3wD1812RaLDcBjtblcDF5f1vI0= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0 h1:ErKg/3iS1AKcTkf3yixlZ54f9U1rljCkQyEXWUnIUxc= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0/go.mod h1:yAZHSGnqScoU556rBOVkwLze6WP5N+U11RHuWaGVxwY= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0 h1:owcC2UnmsZycprQ5RfRgjydWhuoxg71LUfyiQdijZuM= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0/go.mod h1:ZPpqegjbE99EPKsu3iUWV22A04wzGPcAY/ziSIQEEgs= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.53.0 h1:4LP6hvB4I5ouTbGgWtixJhgED6xdf67twf9PoY96Tbg= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.53.0/go.mod h1:jUZ5LYlw40WMd07qxcQJD5M40aUxrfwqQX1g7zxYnrQ= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0 h1:Ron4zCA/yk6U7WOBXhTJcDpsUBG9npumK6xw2auFltQ= -github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0/go.mod h1:cSgYe11MCNYunTnRXrKiR/tHc0eoKjICUuWpNZoVCOo= -github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/ThalesIgnite/crypto11 v1.2.5 h1:1IiIIEqYmBvUYFeMnHqRft4bwf/O36jryEUpY+9ef8E= github.com/ThalesIgnite/crypto11 v1.2.5/go.mod h1:ILDKtnCKiQ7zRoNxcp36Y1ZR8LBPmR2E23+wTQe/MlE= github.com/agnivade/levenshtein v1.2.1 h1:EHBY3UOn1gwdy/VbFwgo4cxecRznFk7fKWN1KOX7eoM= github.com/agnivade/levenshtein v1.2.1/go.mod h1:QVVI16kDrtSuwcpd0p1+xMC6Z/VfhtCyDIjcwga4/DU= -github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= -github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk= -github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= -github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM= 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= @@ -746,79 +121,67 @@ github.com/aliyun/credentials-go v1.3.2 h1:L4WppI9rctC8PdlMgyTkF8bBsy9pyKQEzBD1b github.com/aliyun/credentials-go v1.3.2/go.mod h1:tlpz4uys4Rn7Ik4/piGRrTbXy2uLKvePgQJJduE+Y5c= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= -github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= -github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/apache/arrow/go/v10 v10.0.1/go.mod h1:YvhnlEePVnBS4+0z3fhPfUy7W1Ikj0Ih0vcRo/gZ1M0= -github.com/apache/arrow/go/v11 v11.0.0/go.mod h1:Eg5OsL5H+e299f7u5ssuXsuHQVEGC4xei5aX110hRiI= -github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q= 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/avast/retry-go/v4 v4.6.1 h1:VkOLRubHdisGrHnTu89g08aQEWEgRU7LVEop3GbIcMk= -github.com/avast/retry-go/v4 v4.6.1/go.mod h1:V6oF8njAwxJ5gRo1Q7Cxab24xs5NCWZBeaHHBklR8mA= -github.com/aws/aws-sdk-go v1.55.7 h1:UJrkFq7es5CShfBwlWAC8DA077vp8PyVbQd3lqLiztE= -github.com/aws/aws-sdk-go v1.55.7/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= -github.com/aws/aws-sdk-go-v2 v1.36.6 h1:zJqGjVbRdTPojeCGWn5IR5pbJwSQSBh5RWFTQcEQGdU= -github.com/aws/aws-sdk-go-v2 v1.36.6/go.mod h1:EYrzvCCN9CMUTa5+6lf6MM4tq3Zjp8UhSGR/cBsjai0= -github.com/aws/aws-sdk-go-v2/config v1.29.18 h1:x4T1GRPnqKV8HMJOMtNktbpQMl3bIsfx8KbqmveUO2I= -github.com/aws/aws-sdk-go-v2/config v1.29.18/go.mod h1:bvz8oXugIsH8K7HLhBv06vDqnFv3NsGDt2Znpk7zmOU= -github.com/aws/aws-sdk-go-v2/credentials v1.17.71 h1:r2w4mQWnrTMJjOyIsZtGp3R3XGY3nqHn8C26C2lQWgA= -github.com/aws/aws-sdk-go-v2/credentials v1.17.71/go.mod h1:E7VF3acIup4GB5ckzbKFrCK0vTvEQxOxgdq4U3vcMCY= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.33 h1:D9ixiWSG4lyUBL2DDNK924Px9V/NBVpML90MHqyTADY= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.33/go.mod h1:caS/m4DI+cij2paz3rtProRBI4s/+TCiWoaWZuQ9010= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.37 h1:osMWfm/sC/L4tvEdQ65Gri5ZZDCUpuYJZbTTDrsn4I0= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.37/go.mod h1:ZV2/1fbjOPr4G4v38G3Ww5TBT4+hmsK45s/rxu1fGy0= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.37 h1:v+X21AvTb2wZ+ycg1gx+orkB/9U6L7AOp93R7qYxsxM= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.37/go.mod h1:G0uM1kyssELxmJ2VZEfG0q2npObR3BAkF3c1VsfVnfs= -github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo= -github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo= -github.com/aws/aws-sdk-go-v2/service/ecr v1.40.3 h1:a+210FCU/pR5hhKRaskRfX/ogcyyzFBrehcTk5DTAyU= -github.com/aws/aws-sdk-go-v2/service/ecr v1.40.3/go.mod h1:dtD3a4sjUjVL86e0NUvaqdGvds5ED6itUiZPDaT+Gh8= -github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.31.2 h1:E6/Myrj9HgLF22medmDrKmbpm4ULsa+cIBNx3phirBk= -github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.31.2/go.mod h1:OQ8NALFcchBJ/qruak6zKUQodovnTKKaReTuCkc5/9Y= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4 h1:CXV68E2dNqhuynZJPB80bhPQwAKqBWVer887figW6Jc= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4/go.mod h1:/xFi9KtvBXP97ppCz1TAEvU1Uf66qvid89rbem3wCzQ= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.18 h1:vvbXsA2TVO80/KT7ZqCbx934dt6PY+vQ8hZpUZ/cpYg= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.18/go.mod h1:m2JJHledjBGNMsLOF1g9gbAxprzq3KjC8e4lxtn+eWg= -github.com/aws/aws-sdk-go-v2/service/kms v1.41.3 h1:P0mjq/4mqTRA8SlS/4jL946RBW287kkKI/fazTTDJ3E= -github.com/aws/aws-sdk-go-v2/service/kms v1.41.3/go.mod h1:79gw7fH6dqzJz3a5qwDnQv5GDPs8b6eJIb9hJ+/c/YU= -github.com/aws/aws-sdk-go-v2/service/sso v1.25.6 h1:rGtWqkQbPk7Bkwuv3NzpE/scwwL9sC1Ul3tn9x83DUI= -github.com/aws/aws-sdk-go-v2/service/sso v1.25.6/go.mod h1:u4ku9OLv4TO4bCPdxf4fA1upaMaJmP9ZijGk3AAOC6Q= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.4 h1:OV/pxyXh+eMA0TExHEC4jyWdumLxNbzz1P0zJoezkJc= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.4/go.mod h1:8Mm5VGYwtm+r305FfPSuc+aFkrypeylGYhFim6XEPoc= -github.com/aws/aws-sdk-go-v2/service/sts v1.34.1 h1:aUrLQwJfZtwv3/ZNG2xRtEen+NqI3iesuacjP51Mv1s= -github.com/aws/aws-sdk-go-v2/service/sts v1.34.1/go.mod h1:3wFBZKoWnX3r+Sm7in79i54fBmNfwhdNdQuscCw7QIk= -github.com/aws/smithy-go v1.22.4 h1:uqXzVZNuNexwc/xrh6Tb56u89WDlJY6HS+KC0S4QSjw= -github.com/aws/smithy-go v1.22.4/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI= -github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.9.1 h1:50sS0RWhGpW/yZx2KcDNEb1u1MANv5BMEkJgcieEDTA= -github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.9.1/go.mod h1:ErZOtbzuHabipRTDTor0inoRlYwbsV1ovwSxjGs/uJo= +github.com/aws/aws-sdk-go v1.55.8 h1:JRmEUbU52aJQZ2AjX4q4Wu7t4uZjOu71uyNmaWlUkJQ= +github.com/aws/aws-sdk-go v1.55.8/go.mod h1:ZkViS9AqA6otK+JBBNH2++sx1sgxrPKcSzPPvQkUtXk= +github.com/aws/aws-sdk-go-v2 v1.40.0 h1:/WMUA0kjhZExjOQN2z3oLALDREea1A7TobfuiBrKlwc= +github.com/aws/aws-sdk-go-v2 v1.40.0/go.mod h1:c9pm7VwuW0UPxAEYGyTmyurVcNrbF6Rt/wixFqDhcjE= +github.com/aws/aws-sdk-go-v2/config v1.32.2 h1:4liUsdEpUUPZs5WVapsJLx5NPmQhQdez7nYFcovrytk= +github.com/aws/aws-sdk-go-v2/config v1.32.2/go.mod h1:l0hs06IFz1eCT+jTacU/qZtC33nvcnLADAPL/XyrkZI= +github.com/aws/aws-sdk-go-v2/credentials v1.19.2 h1:qZry8VUyTK4VIo5aEdUcBjPZHL2v4FyQ3QEOaWcFLu4= +github.com/aws/aws-sdk-go-v2/credentials v1.19.2/go.mod h1:YUqm5a1/kBnoK+/NY5WEiMocZihKSo15/tJdmdXnM5g= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.14 h1:WZVR5DbDgxzA0BJeudId89Kmgy6DIU4ORpxwsVHz0qA= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.14/go.mod h1:Dadl9QO0kHgbrH1GRqGiZdYtW5w+IXXaBNCHTIaheM4= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.14 h1:PZHqQACxYb8mYgms4RZbhZG0a7dPW06xOjmaH0EJC/I= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.14/go.mod h1:VymhrMJUWs69D8u0/lZ7jSB6WgaG/NqHi3gX0aYf6U0= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.14 h1:bOS19y6zlJwagBfHxs0ESzr1XCOU2KXJCWcq3E2vfjY= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.14/go.mod h1:1ipeGBMAxZ0xcTm6y6paC2C/J6f6OO7LBODV9afuAyM= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 h1:WKuaxf++XKWlHWu9ECbMlha8WOEGm0OUEZqm4K/Gcfk= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4/go.mod h1:ZWy7j6v1vWGmPReu0iSGvRiise4YI5SkR3OHKTZ6Wuc= +github.com/aws/aws-sdk-go-v2/service/ecr v1.51.2 h1:aq2N/9UkbEyljIQ7OFcudEgUsJzO8MYucmfsM/k/dmc= +github.com/aws/aws-sdk-go-v2/service/ecr v1.51.2/go.mod h1:1NVD1KuMjH2GqnPwMotPndQaT/MreKkWpjkF12d6oKU= +github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.38.2 h1:9fe6w8bydUwNAhFVmjo+SRqAJjbBMOyILL/6hTTVkyA= +github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.38.2/go.mod h1:x7gU4CAyAz4BsM9hlRkhHiYw2GIr1QCmN45uwQw9l/E= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3 h1:x2Ibm/Af8Fi+BH+Hsn9TXGdT+hKbDd5XOTZxTMxDk7o= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3/go.mod h1:IW1jwyrQgMdhisceG8fQLmQIydcT/jWY21rFhzgaKwo= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.14 h1:FIouAnCE46kyYqyhs0XEBDFFSREtdnr8HQuLPQPLCrY= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.14/go.mod h1:UTwDc5COa5+guonQU8qBikJo1ZJ4ln2r1MkF7Dqag1E= +github.com/aws/aws-sdk-go-v2/service/kms v1.49.1 h1:U0asSZ3ifpuIehDPkRI2rxHbmFUMplDA2VeR9Uogrmw= +github.com/aws/aws-sdk-go-v2/service/kms v1.49.1/go.mod h1:NZo9WJqQ0sxQ1Yqu1IwCHQFQunTms2MlVgejg16S1rY= +github.com/aws/aws-sdk-go-v2/service/signin v1.0.2 h1:MxMBdKTYBjPQChlJhi4qlEueqB1p1KcbTEa7tD5aqPs= +github.com/aws/aws-sdk-go-v2/service/signin v1.0.2/go.mod h1:iS6EPmNeqCsGo+xQmXv0jIMjyYtQfnwg36zl2FwEouk= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.5 h1:ksUT5KtgpZd3SAiFJNJ0AFEJVva3gjBmN7eXUZjzUwQ= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.5/go.mod h1:av+ArJpoYf3pgyrj6tcehSFW+y9/QvAY8kMooR9bZCw= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.10 h1:GtsxyiF3Nd3JahRBJbxLCCdYW9ltGQYrFWg8XdkGDd8= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.10/go.mod h1:/j67Z5XBVDx8nZVp9EuFM9/BS5dvBznbqILGuu73hug= +github.com/aws/aws-sdk-go-v2/service/sts v1.41.2 h1:a5UTtD4mHBU3t0o6aHQZFJTNKVfxFWfPX7J0Lr7G+uY= +github.com/aws/aws-sdk-go-v2/service/sts v1.41.2/go.mod h1:6TxbXoDSgBQ225Qd8Q+MbxUxUh6TtNKwbRt/EPS9xso= +github.com/aws/smithy-go v1.24.0 h1:LpilSUItNPFr1eY85RYgTIg5eIEPtvFbskaFcmmIUnk= +github.com/aws/smithy-go v1.24.0/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0= +github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.11.0 h1:GOPttfOAf5qAgx7r6b+zCWZrvCsfKffkL4H6mSYx1kA= +github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.11.0/go.mod h1:a2HN6+p7k0JLDO8514sMr0l4cnrR52z4sWoZ/Uc82ho= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= -github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= -github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= -github.com/buildkite/agent/v3 v3.103.0 h1:yzHF1gVuSNHO+fsOyyJun95fx8oTSGQmdudjKTaaW8M= -github.com/buildkite/agent/v3 v3.103.0/go.mod h1:5N1KWTrYKq7D2k7g10Hit6DnQ0jfjKgE3JPnJVr5teM= -github.com/buildkite/go-pipeline v0.14.0 h1:TMkFalrkniy2l5wEfmGyckT5kf21akWOY07i4esosAI= -github.com/buildkite/go-pipeline v0.14.0/go.mod h1:VE37qY3X5pmAKKUMoDZvPsHOQuyakB9cmXj9Qn6QasA= +github.com/buildkite/agent/v3 v3.114.1 h1:UpSJmnOjoep5YQyMC7rHeCx4cSRKoBZvEtZGW2akQA0= +github.com/buildkite/agent/v3 v3.114.1/go.mod h1:KJOGdrc9M4VNAkSesOrSNHIXXdQ3esyqEOCptmuFTQs= +github.com/buildkite/go-pipeline v0.16.0 h1:wEgWUMRAgSg1ZnWOoA3AovtYYdTvN0dLY1zwUWmPP+4= +github.com/buildkite/go-pipeline v0.16.0/go.mod h1:VE37qY3X5pmAKKUMoDZvPsHOQuyakB9cmXj9Qn6QasA= github.com/buildkite/interpolate v0.1.5 h1:v2Ji3voik69UZlbfoqzx+qfcsOKLA61nHdU79VV+tPU= github.com/buildkite/interpolate v0.1.5/go.mod h1:dHnrwHew5O8VNOAgMDpwRlFnhL5VSN6M1bHVmRZ9Ccc= -github.com/buildkite/roko v1.3.1 h1:t7K30ceLLYn6k7hQP4oq1c7dVlhgD5nRcuSRDEEnY1s= -github.com/buildkite/roko v1.3.1/go.mod h1:23R9e6nHxgedznkwwfmqZ6+0VJZJZ2Sg/uVcp2cP46I= -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/buildkite/roko v1.4.0 h1:DxixoCdpNqxu4/1lXrXbfsKbJSd7r1qoxtef/TT2J80= +github.com/buildkite/roko v1.4.0/go.mod h1:0vbODqUFEcVf4v2xVXRfZZRsqJVsCCHTG/TBRByGK4E= +github.com/bytecodealliance/wasmtime-go/v37 v37.0.0 h1:DPjdn2V3JhXHMoZ2ymRqGK+y1bDyr9wgpyYCvhjMky8= +github.com/bytecodealliance/wasmtime-go/v37 v37.0.0/go.mod h1:Pf1l2JCTUFMnOqDIwkjzx1qfVJ09xbaXETKgRVE4jZ0= 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/cenkalti/backoff/v5 v5.0.2 h1:rIfFVxEf1QsI7E1ZHfp/B4DF/6QBAUhmgkxc0H7Zss8= -github.com/cenkalti/backoff/v5 v5.0.2/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= +github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= +github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb27589 h1:krfRl01rzPzxSxyLyrChD+U+MzsBXbm0OwYYB67uF+4= @@ -837,52 +200,39 @@ github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyM github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= -github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= -github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20250326154945-ae57f3c0d45f h1:C5bqEmzEPLsHm9Mv73lSE9e9bKV23aB1vxOsmZrkl3k= -github.com/cncf/xds/go v0.0.0-20250326154945-ae57f3c0d45f/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= +github.com/cncf/xds/go v0.0.0-20251022180443-0feb69152e9f h1:Y8xYupdHxryycyPlc9Y+bSQAYZnetRJ70VMVKm5CKI0= +github.com/cncf/xds/go v0.0.0-20251022180443-0feb69152e9f/go.mod h1:HlzOvOjVBOfTGSRXRyY0OiCS/3J1akRGQQpRO/7zyF4= github.com/cockroachdb/apd/v3 v3.2.1 h1:U+8j7t0axsIgvQUqthuNm82HIrYXodOV2iWLWtEaIwg= github.com/cockroachdb/apd/v3 v3.2.1/go.mod h1:klXJcjp+FffLTHlhIG69tezTDvdP065naDsHzKhYSqc= github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb h1:EDmT6Q9Zs+SbUoc7Ik9EfrFqcylYqgPZ9ANSbTAntnE= github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb/go.mod h1:ZjrT6AXHbDs86ZSdt/osfBi5qfexBrKUdONk989Wnk4= github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be h1:J5BL2kskAlV9ckgEsNQXscjIaLiOYiZ75d4e94E6dcQ= github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be/go.mod h1:mk5IQ+Y0ZeO87b858TlA645sVcEcbiX6YqP98kt+7+w= -github.com/containerd/stargz-snapshotter/estargz v0.16.3 h1:7evrXtoh1mSbGj/pfRccTampEyKpjpOnS3CyiV1Ebr8= -github.com/containerd/stargz-snapshotter/estargz v0.16.3/go.mod h1:uyr4BfYfOj3G9WBVE8cOlQmXAbPN9VEQpBBeJIuOipU= -github.com/coreos/go-oidc/v3 v3.14.1 h1:9ePWwfdwC4QKRlCXsJGou56adA/owXczOzwKdOumLqk= -github.com/coreos/go-oidc/v3 v3.14.1/go.mod h1:HaZ3szPaZ0e4r6ebqvsLWlk2Tn+aejfmrfah6hnSYEU= +github.com/containerd/stargz-snapshotter/estargz v0.18.1 h1:cy2/lpgBXDA3cDKSyEfNOFMA/c10O1axL69EU7iirO8= +github.com/containerd/stargz-snapshotter/estargz v0.18.1/go.mod h1:ALIEqa7B6oVDsrF37GkGN20SuvG/pIMm7FwP7ZmRb0Q= +github.com/coreos/go-oidc/v3 v3.17.0 h1:hWBGaQfbi0iVviX4ibC7bk8OKT5qNr4klBaCHVNvehc= +github.com/coreos/go-oidc/v3 v3.17.0/go.mod h1:wqPbKFrVnE90vty060SB40FCJ8fTHTxSwyXJqZH+sI8= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo= github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.19 h1:tUN6H7LWqNx4hQVxomd0CVsDwaDr9gaRQaI4GpSmrsA= github.com/creack/pty v1.1.19/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/cyberphone/json-canonicalization v0.0.0-20241213102144-19d51d7fe467 h1:uX1JmpONuD549D73r6cgnxyUu18Zb7yHAy5AYU0Pm4Q= github.com/cyberphone/json-canonicalization v0.0.0-20241213102144-19d51d7fe467/go.mod h1:uzvlm1mxhHkdfqitSA92i7Se+S9ksOn3a3qmv/kyOCw= -github.com/danieljoos/wincred v1.2.2 h1:774zMFJrqaeYCK2W57BgAem/MLi6mtSE47MB6BOJ0i0= -github.com/danieljoos/wincred v1.2.2/go.mod h1:w7w4Utbrz8lqeMbDAK0lkNJUv5sAOkFi7nd/ogr0Uh8= +github.com/danieljoos/wincred v1.2.3 h1:v7dZC2x32Ut3nEfRH+vhoZGvN72+dQ/snVXo/vMFLdQ= +github.com/danieljoos/wincred v1.2.3/go.mod h1:6qqX0WNrS4RzPZ1tnroDzq9kY3fu1KwE7MRLQK4X0bs= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40= github.com/depcheck-test/depcheck-test v0.0.0-20220607135614-199033aaa936 h1:foGzavPWwtoyBvjWyKJYDYsyzy+23iBV7NKTwdk+LRY= github.com/depcheck-test/depcheck-test v0.0.0-20220607135614-199033aaa936/go.mod h1:ttKPnOepYt4LLzD+loXQ1rT6EmpyIYHro7TAJuIIlHo= -github.com/dgraph-io/badger/v4 v4.7.0 h1:Q+J8HApYAY7UMpL8d9owqiB+odzEc0zn/aqOD9jhc6Y= -github.com/dgraph-io/badger/v4 v4.7.0/go.mod h1:He7TzG3YBy3j4f5baj5B7Zl2XyfNe5bl4Udl0aPemVA= +github.com/dgraph-io/badger/v4 v4.8.0 h1:JYph1ChBijCw8SLeybvPINizbDKWZ5n/GYbz2yhN/bs= +github.com/dgraph-io/badger/v4 v4.8.0/go.mod h1:U6on6e8k/RTbUWxqKR0MvugJuVmkxSNc79ap4917h4w= github.com/dgraph-io/ristretto/v2 v2.2.0 h1:bkY3XzJcXoMuELV8F+vS8kzNgicwQFAaGINAEJdWGOM= github.com/dgraph-io/ristretto/v2 v2.2.0/go.mod h1:RZrm63UmcBAaYWC1DotLYBmTvgkrs0+XhBd7Npn7/zI= -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-20230903005119-f50d829f2e54 h1:SG7nF6SRlWhcT7cNTs5R6Hk4V2lcmLz2NsG2VnInyNo= github.com/dgryski/trifles v0.0.0-20230903005119-f50d829f2e54/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= github.com/digitorus/pkcs7 v0.0.0-20230713084857-e76b763bdc49/go.mod h1:SKVExuS+vpu2l9IoOc0RwqE7NYnb0JlcFHFnEJkVDzc= @@ -892,51 +242,32 @@ github.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7 h1:lxmTCgmHE1G github.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7/go.mod h1:GvWntX9qiTlOud0WkQ6ewFm0LPy5JUR1Xo0Ngbd1w6Y= github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U= github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE= -github.com/docker/cli v28.2.2+incompatible h1:qzx5BNUDFqlvyq4AHzdNB7gSyVTmU4cgsyN9SdInc1A= -github.com/docker/cli v28.2.2+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v29.0.3+incompatible h1:8J+PZIcF2xLd6h5sHPsp5pvvJA+Sr2wGQxHkRl53a1E= +github.com/docker/cli v29.0.3+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker-credential-helpers v0.9.3 h1:gAm/VtF9wgqJMoxzT3Gj5p4AqIjCBS4wrsOh9yRqcz8= -github.com/docker/docker-credential-helpers v0.9.3/go.mod h1:x+4Gbw9aGmChi3qTLZj8Dfn0TD20M/fuWy0E5+WDeCo= +github.com/docker/docker-credential-helpers v0.9.4 h1:76ItO69/AP/V4yT9V4uuuItG0B1N8hvt0T0c0NN/DzI= +github.com/docker/docker-credential-helpers v0.9.4/go.mod h1:v1S+hepowrQXITkEfw6o4+BMbGot02wiKpzWhGUZK6c= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= -github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= -github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -github.com/emicklei/proto v1.13.4 h1:myn1fyf8t7tAqIzV91Tj9qXpvyXXGXk8OS2H6IBSc9g= -github.com/emicklei/proto v1.13.4/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A= +github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU= +github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/proto v1.14.2 h1:wJPxPy2Xifja9cEMrcA/g08art5+7CGJNFNk35iXC1I= +github.com/emicklei/proto v1.14.2/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= -github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= -github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= -github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= -github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= -github.com/envoyproxy/go-control-plane v0.11.1-0.20230524094728-9239064ad72f/go.mod h1:sfYdkwUW4BA3PbKjySwjJy+O4Pu0h62rlqCMHNk+K+Q= -github.com/envoyproxy/go-control-plane v0.13.4 h1:zEqyPVyku6IvWCFwux4x9RxkLOMUL+1vC9xUFv5l2/M= -github.com/envoyproxy/go-control-plane v0.13.4/go.mod h1:kDfuBlDVsSj2MjrLEtRWtHlsWIFcGyB2RMO44Dc5GZA= -github.com/envoyproxy/go-control-plane/envoy v1.32.4 h1:jb83lalDRZSpPWW2Z7Mck/8kXZ5CQAFYVjQcdVIr83A= -github.com/envoyproxy/go-control-plane/envoy v1.32.4/go.mod h1:Gzjc5k8JcJswLjAx1Zm+wSYE20UrLtt7JZMWiWQXQEw= -github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 h1:/G9QYbddjL25KvtKTv3an9lx6VBE2cnb8wp1vEGNYGI= -github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4= +github.com/envoyproxy/go-control-plane v0.13.5-0.20251024222203-75eaa193e329 h1:K+fnvUM0VZ7ZFJf0n4L/BRlnsb9pL/GuDG6FqaH+PwM= +github.com/envoyproxy/go-control-plane/envoy v1.35.0 h1:ixjkELDE+ru6idPxcHLj8LBVc2bFP7iBytj353BoHUo= +github.com/envoyproxy/go-control-plane/envoy v1.35.0/go.mod h1:09qwbGVuSWWAyN5t/b3iyVfz5+z8QWGrzkoqm/8SbEs= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo= -github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= -github.com/envoyproxy/protoc-gen-validate v0.10.1/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= github.com/envoyproxy/protoc-gen-validate v1.2.1 h1:DEo3O99U8j4hBFwbJfrz9VtgcDfUKS7KJ7spH3d86P8= github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= -github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/foxcpp/go-mockdns v1.1.0 h1:jI0rD8M0wuYAxL7r/ynTrCQQq0BVqfB99Vgk7DlmewI= @@ -948,75 +279,89 @@ github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4 github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= -github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= -github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/globocom/go-buffer v1.2.2 h1:ICgtlUe5GIYIZFdAVj57+5WYBR4DA56cX+PYZDhGDwc= -github.com/globocom/go-buffer v1.2.2/go.mod h1:kY1ALQS0ChiiThmWhsFoT5CYSiuad0t3keIew5LsWdM= +github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM= +github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= github.com/go-chi/chi v4.1.2+incompatible h1:fGFk2Gmi/YKXk0OmGfBh0WgmN3XB8lVnEyNz34tQRec= github.com/go-chi/chi v4.1.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= -github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g= -github.com/go-fonts/latin-modern v0.2.0/go.mod h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3T0ecnM9pNujks= -github.com/go-fonts/liberation v0.1.1/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= -github.com/go-fonts/liberation v0.2.0/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= -github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmnUIzUY= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-chi/chi/v5 v5.2.3 h1:WQIt9uxdsAbgIYgid+BpYc+liqQZGMHRaUwp0JUcvdE= +github.com/go-chi/chi/v5 v5.2.3/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops= github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A= github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= -github.com/go-jose/go-jose/v3 v3.0.4 h1:Wp5HA7bLQcKnf6YYao/4kpRpVMp/yf6+pJKV8WFSaNY= -github.com/go-jose/go-jose/v3 v3.0.4/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= -github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE= -github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA= -github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U= -github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpxhq9o2S/CELCSUxEWWAuoCUcVCQWv7G2OCk= +github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs= +github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-openapi/analysis v0.23.0 h1:aGday7OWupfMs+LbmLZG4k0MYXIANxcuBTYUC03zFCU= -github.com/go-openapi/analysis v0.23.0/go.mod h1:9mz9ZWaSlV8TvjQHLl2mUW2PbZtemkE8yA5v22ohupo= -github.com/go-openapi/errors v0.22.1 h1:kslMRRnK7NCb/CvR1q1VWuEQCEIsBGn5GgKD9e+HYhU= -github.com/go-openapi/errors v0.22.1/go.mod h1:+n/5UdIqdVnLIJ6Q9Se8HNGUXYaY6CN8ImWzfi/Gzp0= -github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= -github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= -github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= -github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= -github.com/go-openapi/loads v0.22.0 h1:ECPGd4jX1U6NApCGG1We+uEozOAvXvJSF4nnwHZ8Aco= -github.com/go-openapi/loads v0.22.0/go.mod h1:yLsaTCS92mnSAZX5WWoxszLj0u+Ojl+Zs5Stn1oF+rs= -github.com/go-openapi/runtime v0.28.0 h1:gpPPmWSNGo214l6n8hzdXYhPuJcGtziTOgUpvsFWGIQ= -github.com/go-openapi/runtime v0.28.0/go.mod h1:QN7OzcS+XuYmkQLw05akXk0jRH/eZ3kb18+1KwW9gyc= -github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY= -github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= -github.com/go-openapi/strfmt v0.23.0 h1:nlUS6BCqcnAk0pyhi9Y+kdDVZdZMHfEKQiS4HaMgO/c= -github.com/go-openapi/strfmt v0.23.0/go.mod h1:NrtIpfKtWIygRkKVsxh7XQMDQW5HKQl6S5ik2elW+K4= -github.com/go-openapi/swag v0.23.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU= -github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0= -github.com/go-openapi/validate v0.24.0 h1:LdfDKwNbpB6Vn40xhTdNZAnfLECL81w+VX3BumrGD58= -github.com/go-openapi/validate v0.24.0/go.mod h1:iyeX1sEufmv3nPbBdX3ieNviWnOZaJ1+zquzJEf2BAQ= -github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= -github.com/go-pdf/fpdf v0.6.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= +github.com/go-openapi/analysis v0.24.1 h1:Xp+7Yn/KOnVWYG8d+hPksOYnCYImE3TieBa7rBOesYM= +github.com/go-openapi/analysis v0.24.1/go.mod h1:dU+qxX7QGU1rl7IYhBC8bIfmWQdX4Buoea4TGtxXY84= +github.com/go-openapi/errors v0.22.4 h1:oi2K9mHTOb5DPW2Zjdzs/NIvwi2N3fARKaTJLdNabaM= +github.com/go-openapi/errors v0.22.4/go.mod h1:z9S8ASTUqx7+CP1Q8dD8ewGH/1JWFFLX/2PmAYNQLgk= +github.com/go-openapi/jsonpointer v0.22.1 h1:sHYI1He3b9NqJ4wXLoJDKmUmHkWy/L7rtEo92JUxBNk= +github.com/go-openapi/jsonpointer v0.22.1/go.mod h1:pQT9OsLkfz1yWoMgYFy4x3U5GY5nUlsOn1qSBH5MkCM= +github.com/go-openapi/jsonreference v0.21.3 h1:96Dn+MRPa0nYAR8DR1E03SblB5FJvh7W6krPI0Z7qMc= +github.com/go-openapi/jsonreference v0.21.3/go.mod h1:RqkUP0MrLf37HqxZxrIAtTWW4ZJIK1VzduhXYBEeGc4= +github.com/go-openapi/loads v0.23.2 h1:rJXAcP7g1+lWyBHC7iTY+WAF0rprtM+pm8Jxv1uQJp4= +github.com/go-openapi/loads v0.23.2/go.mod h1:IEVw1GfRt/P2Pplkelxzj9BYFajiWOtY2nHZNj4UnWY= +github.com/go-openapi/runtime v0.29.2 h1:UmwSGWNmWQqKm1c2MGgXVpC2FTGwPDQeUsBMufc5Yj0= +github.com/go-openapi/runtime v0.29.2/go.mod h1:biq5kJXRJKBJxTDJXAa00DOTa/anflQPhT0/wmjuy+0= +github.com/go-openapi/spec v0.22.1 h1:beZMa5AVQzRspNjvhe5aG1/XyBSMeX1eEOs7dMoXh/k= +github.com/go-openapi/spec v0.22.1/go.mod h1:c7aeIQT175dVowfp7FeCvXXnjN/MrpaONStibD2WtDA= +github.com/go-openapi/strfmt v0.25.0 h1:7R0RX7mbKLa9EYCTHRcCuIPcaqlyQiWNPTXwClK0saQ= +github.com/go-openapi/strfmt v0.25.0/go.mod h1:nNXct7OzbwrMY9+5tLX4I21pzcmE6ccMGXl3jFdPfn8= +github.com/go-openapi/swag v0.25.4 h1:OyUPUFYDPDBMkqyxOTkqDYFnrhuhi9NR6QVUvIochMU= +github.com/go-openapi/swag v0.25.4/go.mod h1:zNfJ9WZABGHCFg2RnY0S4IOkAcVTzJ6z2Bi+Q4i6qFQ= +github.com/go-openapi/swag/cmdutils v0.25.4 h1:8rYhB5n6WawR192/BfUu2iVlxqVR9aRgGJP6WaBoW+4= +github.com/go-openapi/swag/cmdutils v0.25.4/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0= +github.com/go-openapi/swag/conv v0.25.4 h1:/Dd7p0LZXczgUcC/Ikm1+YqVzkEeCc9LnOWjfkpkfe4= +github.com/go-openapi/swag/conv v0.25.4/go.mod h1:3LXfie/lwoAv0NHoEuY1hjoFAYkvlqI/Bn5EQDD3PPU= +github.com/go-openapi/swag/fileutils v0.25.4 h1:2oI0XNW5y6UWZTC7vAxC8hmsK/tOkWXHJQH4lKjqw+Y= +github.com/go-openapi/swag/fileutils v0.25.4/go.mod h1:cdOT/PKbwcysVQ9Tpr0q20lQKH7MGhOEb6EwmHOirUk= +github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= +github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= +github.com/go-openapi/swag/jsonutils v0.25.4 h1:VSchfbGhD4UTf4vCdR2F4TLBdLwHyUDTd1/q4i+jGZA= +github.com/go-openapi/swag/jsonutils v0.25.4/go.mod h1:7OYGXpvVFPn4PpaSdPHJBtF0iGnbEaTk8AvBkoWnaAY= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4 h1:IACsSvBhiNJwlDix7wq39SS2Fh7lUOCJRmx/4SN4sVo= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4/go.mod h1:Mt0Ost9l3cUzVv4OEZG+WSeoHwjWLnarzMePNDAOBiM= +github.com/go-openapi/swag/loading v0.25.4 h1:jN4MvLj0X6yhCDduRsxDDw1aHe+ZWoLjW+9ZQWIKn2s= +github.com/go-openapi/swag/loading v0.25.4/go.mod h1:rpUM1ZiyEP9+mNLIQUdMiD7dCETXvkkC30z53i+ftTE= +github.com/go-openapi/swag/mangling v0.25.4 h1:2b9kBJk9JvPgxr36V23FxJLdwBrpijI26Bx5JH4Hp48= +github.com/go-openapi/swag/mangling v0.25.4/go.mod h1:6dxwu6QyORHpIIApsdZgb6wBk/DPU15MdyYj/ikn0Hg= +github.com/go-openapi/swag/netutils v0.25.4 h1:Gqe6K71bGRb3ZQLusdI8p/y1KLgV4M/k+/HzVSqT8H0= +github.com/go-openapi/swag/netutils v0.25.4/go.mod h1:m2W8dtdaoX7oj9rEttLyTeEFFEBvnAx9qHd5nJEBzYg= +github.com/go-openapi/swag/stringutils v0.25.4 h1:O6dU1Rd8bej4HPA3/CLPciNBBDwZj9HiEpdVsb8B5A8= +github.com/go-openapi/swag/stringutils v0.25.4/go.mod h1:GTsRvhJW5xM5gkgiFe0fV3PUlFm0dr8vki6/VSRaZK0= +github.com/go-openapi/swag/typeutils v0.25.4 h1:1/fbZOUN472NTc39zpa+YGHn3jzHWhv42wAJSN91wRw= +github.com/go-openapi/swag/typeutils v0.25.4/go.mod h1:Ou7g//Wx8tTLS9vG0UmzfCsjZjKhpjxayRKTHXf2pTE= +github.com/go-openapi/swag/yamlutils v0.25.4 h1:6jdaeSItEUb7ioS9lFoCZ65Cne1/RZtPBZ9A56h92Sw= +github.com/go-openapi/swag/yamlutils v0.25.4/go.mod h1:MNzq1ulQu+yd8Kl7wPOut/YHAAU/H6hL91fF+E2RFwc= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2 h1:0+Y41Pz1NkbTHz8NngxTuAXxEodtNSI1WG1c/m5Akw4= +github.com/go-openapi/testify/enable/yaml/v2 v2.0.2/go.mod h1:kme83333GCtJQHXQ8UKX3IBZu6z8T5Dvy5+CW3NLUUg= +github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= +github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= +github.com/go-openapi/validate v0.25.1 h1:sSACUI6Jcnbo5IWqbYHgjibrhhmt3vR6lCzKZnmAgBw= +github.com/go-openapi/validate v0.25.1/go.mod h1:RMVyVFYte0gbSTaZ0N4KmTn6u/kClvAFp+mAVfS/DQc= github.com/go-piv/piv-go/v2 v2.4.0 h1:xamQ/fR4MJiw/Ndbk6yi7MVwhjrwlnDAPuaH9zcGb+I= github.com/go-piv/piv-go/v2 v2.4.0/go.mod h1:ShZi74nnrWNQEdWzRUd/3cSig3uNOcEZp+EWl0oewnI= github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI= github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow= github.com/go-rod/rod v0.116.2 h1:A5t2Ky2A+5eD/ZJQr1EfsQSe5rms5Xof/qj296e+ZqA= github.com/go-rod/rod v0.116.2/go.mod h1:H+CMO9SCNc2TJ2WfrG+pKhITz57uGNYU43qYHh438Mg= -github.com/go-sql-driver/mysql v1.9.2 h1:4cNKDYQ1I84SXslGddlsrMhc8k4LeDVj6Ad6WRjiHuU= -github.com/go-sql-driver/mysql v1.9.2/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU= +github.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo= +github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U= github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= -github.com/go-viper/mapstructure/v2 v2.3.0 h1:27XbWsHIqhbdR5TIC911OfYvgSaW93HM+dX7970Q7jk= -github.com/go-viper/mapstructure/v2 v2.3.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= +github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= -github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= +github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= @@ -1026,79 +371,43 @@ github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzw github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= -github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8= -github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= -github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= +github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= +github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= -github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ= -github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/mock v1.7.0-rc.1 h1:YojYx61/OLFsiv6Rw1Z96LpldJIy31o+UHmwAUMJ6/U= github.com/golang/mock v1.7.0-rc.1/go.mod h1:s42URUywIqd+OcERslBJvOjepvNymP31m3q8d/GkuRs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/certificate-transparency-go v1.3.2 h1:9ahSNZF2o7SYMaKaXhAumVEzXB2QaayzII9C8rv7v+A= github.com/google/certificate-transparency-go v1.3.2/go.mod h1:H5FpMUaGa5Ab2+KCYsxg6sELw3Flkl7pGZzWdBoYLXs= -github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/flatbuffers v25.2.10+incompatible h1:F3vclr7C3HpB1k9mxCGRMXq6FdUalZ6H/pNX4FP1v0Q= github.com/google/flatbuffers v25.2.10+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= -github.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw= -github.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw= +github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo= +github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= -github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= -github.com/google/go-containerregistry v0.20.6 h1:cvWX87UxxLgaH76b4hIvya6Dzz9qHB31qAwjAohdSTU= -github.com/google/go-containerregistry v0.20.6/go.mod h1:T0x8MuoAoKX/873bkeSfLD2FAkwCDf9/HZgsFJ02E2Y= +github.com/google/go-containerregistry v0.20.7 h1:24VGNpS0IwrOZ2ms2P1QE3Xa5X9p4phx0aUgzYzHW6I= +github.com/google/go-containerregistry v0.20.7/go.mod h1:Lx5LCZQjLH1QBaMPeGwsME9biPeo1lPx6lbGj/UmzgM= github.com/google/go-github/v73 v73.0.0 h1:aR+Utnh+Y4mMkS+2qLQwcQ/cF9mOTpdwnzlaw//rG24= github.com/google/go-github/v73 v73.0.0/go.mod h1:fa6w8+/V+edSU0muqdhCVY7Beh1M8F1IlQPZIANKIYw= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= @@ -1106,71 +415,26 @@ github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 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/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= -github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= -github.com/google/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9Fc= -github.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8= -github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/pprof v0.0.0-20250602020802-c6617b811d0e h1:FJta/0WsADCe1r9vQjdHbd3KuiLPu7Y9WlyLGwMUNyE= +github.com/google/pprof v0.0.0-20250602020802-c6617b811d0e/go.mod h1:5hDyRhoBCxViHszMt12TnOpEI4VVi+U8Gm9iphldiMA= github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM= github.com/google/trillian v1.7.2 h1:EPBxc4YWY4Ak8tcuhyFleY+zYlbCDCa4Sn24e1Ka8Js= github.com/google/trillian v1.7.2/go.mod h1:mfQJW4qRH6/ilABtPYNBerVJAJ/upxHLX81zxNQw05s= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 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.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= -github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= -github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= -github.com/googleapis/enterprise-certificate-proxy v0.2.1/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= -github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= -github.com/googleapis/enterprise-certificate-proxy v0.3.6 h1:GW/XbdyBFQ8Qe+YAmFU9uHLo7OnF5tL52HFAgMmyrf4= -github.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= -github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= -github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= -github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= -github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= -github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo= -github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= -github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= -github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= +github.com/googleapis/enterprise-certificate-proxy v0.3.7 h1:zrn2Ee/nWmHulBx5sAVrGgAa0f2/R35S4DJwfFaUPFQ= +github.com/googleapis/enterprise-certificate-proxy v0.3.7/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA= github.com/googleapis/gax-go/v2 v2.15.0 h1:SyjDc1mGgZU5LncH8gimWo9lW1DtIfPibOG81vgd/bo= github.com/googleapis/gax-go/v2 v2.15.0/go.mod h1:zVVkkxAQHa1RQpg9z2AUCMnKhi0Qld9rcmyfL1OZhoc= -github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= -github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= 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/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 h1:X5VWvz21y3gzm9Nw/kaUeku/1+uBhcekkmy4IkffJww= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1/go.mod h1:Zanoh4+gvIgluNqcfMVTJueD4wSS5hT7zTt4Mrutd90= +github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= +github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 h1:NmZ1PKzSTQbuGHw9DGPFomqkkLWMC+vZCkfs+FHv1Vg= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3/go.mod h1:zQrxl1YP88HQlA6i9c63DSVPFklWpGX4OWAc9bFuaH4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -1190,19 +454,15 @@ github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9 github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= github.com/hashicorp/go-sockaddr v1.0.7 h1:G+pTkSO01HpR5qCxg7lxfsFEZaG+C0VssTy/9dbT+Fw= github.com/hashicorp/go-sockaddr v1.0.7/go.mod h1:FZQbEYa1pxkQ7WLpyXJ6cbjpT8q0YgQaK/JakXqGyWw= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= -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.16.0 h1:nbEYGJiAPGzT9U4oWgaaB0g+Rj8E59QuHKyA5LhwQN4= -github.com/hashicorp/vault/api v1.16.0/go.mod h1:KhuUhzOD8lDSk29AtzNjgAu2kxRA9jL9NAbkFlqvkBA= +github.com/hashicorp/hcl v1.0.1-vault-7 h1:ag5OxFVy3QYTFTJODRzTKVZ6xvdfLLCA1cy/Y6xGI0I= +github.com/hashicorp/hcl v1.0.1-vault-7/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM= +github.com/hashicorp/vault/api v1.22.0 h1:+HYFquE35/B74fHoIeXlZIP2YADVboaPjaSicHEZiH0= +github.com/hashicorp/vault/api v1.22.0/go.mod h1:IUZA2cDvr4Ok3+NtK2Oq/r+lJeXkeCrHRmqdyWfpmGM= 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= -github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/in-toto/attestation v1.1.2 h1:MBFn6lsMq6dptQZJBhalXTcWMb/aJy3V+GX3VYj/V1E= github.com/in-toto/attestation v1.1.2/go.mod h1:gYFddHMZj3DiQ0b62ltNi1Vj5rC879bTmBbrv9CRHpM= @@ -1220,40 +480,26 @@ github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= 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.3.0 h1:BdoC9cE81qXfrxeb9eoJi9dWrdhSuwXMAnHTbnBm4Wc= -github.com/jellydator/ttlcache/v3 v3.3.0/go.mod h1:bj2/e0l4jRnQdrnSTaGTsh4GSXvMjQcy41i7th0GVGw= +github.com/jellydator/ttlcache/v3 v3.4.0 h1:YS4P125qQS0tNhtL6aeYkheEaB/m8HCqdMMP4mnWdTY= +github.com/jellydator/ttlcache/v3 v3.4.0/go.mod h1:Hw9EgjymziQD3yGsQdf1FqFdpp7YjFMd4Srg5EJlgD4= 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= github.com/jmhodges/clock v1.2.0/go.mod h1:qKjhA7x7u/lQpPB1XAqX1b1lCI/w3/fNuYpI/ZjLynI= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 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/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= -github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= -github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= github.com/keybase/go-keychain v0.0.1 h1:way+bWYa6lDppZoZcgMbYsvC7GxljxrskdNInRtuthU= github.com/keybase/go-keychain v0.0.1/go.mod h1:PdEILRW3i9D8JcdM+FmY6RwkHGnhHxXwkPPMeUgOK1k= 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/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE= -github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= -github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= -github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= -github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/klauspost/compress v1.18.1 h1:bcSGx7UbpBqMChDtsF28Lw6v/G94LPrrbMbdC3JH2co= +github.com/klauspost/compress v1.18.1/go.mod h1:ZQFFVG+MdnR0P+l6wpXgIL4NTtwiKIdBnrBd8Nrxr+0= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -1262,31 +508,37 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/letsencrypt/boulder v0.0.0-20240620165639-de9c06129bec h1:2tTW6cDth2TSgRbAhD7yjZzTQmcN25sDRPEeinR51yQ= -github.com/letsencrypt/boulder v0.0.0-20240620165639-de9c06129bec/go.mod h1:TmwEoGCwIti7BCeJ9hescZgRtatxRE+A72pCoPfmcfk= +github.com/lestrrat-go/blackmagic v1.0.4 h1:IwQibdnf8l2KoO+qC3uT4OaTWsW7tuRQXy9TRN9QanA= +github.com/lestrrat-go/blackmagic v1.0.4/go.mod h1:6AWFyKNNj0zEXQYfTMPfZrAXUWUfTIZ5ECEUEJaijtw= +github.com/lestrrat-go/dsig v1.0.0 h1:OE09s2r9Z81kxzJYRn07TFM9XA4akrUdoMwr0L8xj38= +github.com/lestrrat-go/dsig v1.0.0/go.mod h1:dEgoOYYEJvW6XGbLasr8TFcAxoWrKlbQvmJgCR0qkDo= +github.com/lestrrat-go/dsig-secp256k1 v1.0.0 h1:JpDe4Aybfl0soBvoVwjqDbp+9S1Y2OM7gcrVVMFPOzY= +github.com/lestrrat-go/dsig-secp256k1 v1.0.0/go.mod h1:CxUgAhssb8FToqbL8NjSPoGQlnO4w3LG1P0qPWQm/NU= +github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE= +github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E= +github.com/lestrrat-go/httprc/v3 v3.0.1 h1:3n7Es68YYGZb2Jf+k//llA4FTZMl3yCwIjFIk4ubevI= +github.com/lestrrat-go/httprc/v3 v3.0.1/go.mod h1:2uAvmbXE4Xq8kAUjVrZOq1tZVYYYs5iP62Cmtru00xk= +github.com/lestrrat-go/jwx/v3 v3.0.11 h1:yEeUGNUuNjcez/Voxvr7XPTYNraSQTENJgtVTfwvG/w= +github.com/lestrrat-go/jwx/v3 v3.0.11/go.mod h1:XSOAh2SiXm0QgRe3DulLZLyt+wUuEdFo81zuKTLcvgQ= +github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU= +github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= +github.com/lestrrat-go/option/v2 v2.0.0 h1:XxrcaJESE1fokHy3FpaQ/cXW8ZsIdWcdFzzLOcID3Ss= +github.com/lestrrat-go/option/v2 v2.0.0/go.mod h1:oSySsmzMoR0iRzCDCaUfsCzxQHUEuhOViQObyy7S6Vg= +github.com/letsencrypt/boulder v0.20251110.0 h1:J8MnKICeilO91dyQ2n5eBbab24neHzUpYMUIOdOtbjc= +github.com/letsencrypt/boulder v0.20251110.0/go.mod h1:ogKCJQwll82m7OVHWyTuf8eeFCjuzdRQlgnZcCl0V+8= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= -github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= -github.com/lyft/protoc-gen-star/v2 v2.0.1/go.mod h1:RcCdONR2ScXaYnQC5tUzxzlpA3WVYF7/opLeUgcQs/o= -github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= -github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA= github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= -github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4= -github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY= +github.com/miekg/dns v1.1.61 h1:nLxbwF3XxhwVSm8g9Dghm9MHPaUZuqhPiGL+675ZmEs= +github.com/miekg/dns v1.1.61/go.mod h1:mnAarhS3nWaW+NVP2wTkYVIZyHNJ098SJZUki3eykwQ= github.com/miekg/pkcs11 v1.0.3-0.20190429190417-a667d056470f/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU= github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= -github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY= -github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= @@ -1300,12 +552,15 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= +github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mozillazg/docker-credential-acr-helper v0.4.0 h1:Uoh3Z9CcpEDnLiozDx+D7oDgRq7X+R296vAqAumnOcw= github.com/mozillazg/docker-credential-acr-helper v0.4.0/go.mod h1:2kiicb3OlPytmlNC9XGkLvVC+f0qTiJw3f/mhmeeQBg= 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/natefinch/atomic v1.0.1 h1:ZPYKxkqQOx3KZ+RsbnP/YsgvxWQPGxjC0oBt2AhwV0A= +github.com/natefinch/atomic v1.0.1/go.mod h1:N/D/ELrljoqDyT3rZrsUmtsuzvHkeB/wWjHV22AZRbM= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481 h1:Up6+btDp321ZG5/zdSLo48H9Iaq0UQGthrhWC6pCxzE= github.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481/go.mod h1:yKZQO8QE2bHlgozqWDiRVqTFlLQSj30K/6SAK8EeYFw= @@ -1319,7 +574,6 @@ github.com/oleiade/reflections v1.1.0 h1:D+I/UsXQB4esMathlt0kkZRJZdUDmhv5zGi/HOw github.com/oleiade/reflections v1.1.0/go.mod h1:mCxx0QseeVCHs5Um5HhJeCKVC7AwS8kO67tky4rdisA= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= @@ -1330,189 +584,158 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= -github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8= -github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY= -github.com/open-policy-agent/opa v1.6.0 h1:/S/cnNQJ2MUMNzizHPbisTWBHowmLkPrugY5jjkPlRQ= -github.com/open-policy-agent/opa v1.6.0/go.mod h1:zFmw4P+W62+CWGYRDDswfVYSCnPo6oYaktQnfIaRFC4= +github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4= +github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= +github.com/open-policy-agent/opa v1.10.1 h1:haIvxZSPky8HLjRrvQwWAjCPLg8JDFSZMbbG4yyUHgY= +github.com/open-policy-agent/opa v1.10.1/go.mod h1:7uPI3iRpOalJ0BhK6s1JALWPU9HvaV1XeBSSMZnr/PM= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= -github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= -github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= 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.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= -github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY= -github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= -github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= -github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= 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/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= -github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= 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.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= -github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= +github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= +github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= -github.com/prometheus/common v0.63.0 h1:YR/EIY1o3mEFP/kZCD7iDMnLPlGyuU2Gb3HIcXnA98k= -github.com/prometheus/common v0.63.0/go.mod h1:VVFF/fBIoToEnWRVkYoXEkq3R3paCoxG9PXP74SnV18= -github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= -github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= -github.com/protocolbuffers/txtpbfmt v0.0.0-20241112170944-20d2c9ebc01d h1:HWfigq7lB31IeJL8iy7jkUmU/PG1Sr8jVGhS749dbUA= -github.com/protocolbuffers/txtpbfmt v0.0.0-20241112170944-20d2c9ebc01d/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.8.0 h1:q3nRvjrlge/6UD7eTu/DSg2uYiU2mCL0G/uzBWqhicI= -github.com/redis/go-redis/v9 v9.8.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw= -github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= -github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/prometheus/common v0.67.4 h1:yR3NqWO1/UyO1w2PhUvXlGQs/PtFmoveVO0KZ4+Lvsc= +github.com/prometheus/common v0.67.4/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= +github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0= +github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw= +github.com/protocolbuffers/txtpbfmt v0.0.0-20251016062345-16587c79cd91 h1:s1LvMaU6mVwoFtbxv/rCZKE7/fwDmDY684FfUe4c1Io= +github.com/protocolbuffers/txtpbfmt v0.0.0-20251016062345-16587c79cd91/go.mod h1:JSbkp0BviKovYYt9XunS95M3mLPibE9bGg+Y95DsEEY= +github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 h1:bsUq1dX0N8AOIL7EB/X911+m4EHsnWEHeJ0c+3TTBrg= +github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= -github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk= github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= -github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo= -github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k= +github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc= +github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik= github.com/sassoftware/relic v7.2.1+incompatible h1:Pwyh1F3I0r4clFJXkSI8bOyJINGqpgjJU3DYAZeI05A= github.com/sassoftware/relic v7.2.1+incompatible/go.mod h1:CWfAxv73/iLZ17rbyhIEq3K9hs5w6FpNMdUT//qR+zk= github.com/sassoftware/relic/v7 v7.6.2 h1:rS44Lbv9G9eXsukknS4mSjIAuuX+lMq/FnStgmZlUv4= github.com/sassoftware/relic/v7 v7.6.2/go.mod h1:kjmP0IBVkJZ6gXeAu35/KCEfca//+PKM6vTAsyDPY+k= -github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= -github.com/secure-systems-lab/go-securesystemslib v0.9.0 h1:rf1HIbL64nUpEIZnjLZ3mcNEL9NBPB0iuVjyxvq3LZc= -github.com/secure-systems-lab/go-securesystemslib v0.9.0/go.mod h1:DVHKMcZ+V4/woA/peqr+L0joiRXbPpQ042GgJckkFgw= -github.com/segmentio/ksuid v1.0.4 h1:sBo2BdShXjmcugAMwjugoGUdUV0pcxY5mW4xKRn3v4c= -github.com/segmentio/ksuid v1.0.4/go.mod h1:/XUiZBD3kVx5SmUOl55voK5yeAbBNNIed+2O73XgrPE= -github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= -github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= +github.com/secure-systems-lab/go-securesystemslib v0.9.1 h1:nZZaNz4DiERIQguNy0cL5qTdn9lR8XKHf4RUyG1Sx3g= +github.com/secure-systems-lab/go-securesystemslib v0.9.1/go.mod h1:np53YzT0zXGMv6x4iEWc9Z59uR+x+ndLwCLqPYpLXVU= +github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= +github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= +github.com/sergi/go-diff v1.4.0 h1:n/SP9D5ad1fORl+llWyN+D6qoUETXNZARKjyY2/KVCw= +github.com/sergi/go-diff v1.4.0/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= github.com/shibumi/go-pathspec v1.3.0 h1:QUyMZhFo0Md5B8zV8x2tesohbb5kfbpTi9rBnKh5dkI= github.com/shibumi/go-pathspec v1.3.0/go.mod h1:Xutfslp817l2I1cZvgcfeMQJG5QnU2lh5tVaaMCl3jE= -github.com/sigstore/fulcio v1.7.1 h1:RcoW20Nz49IGeZyu3y9QYhyyV3ZKQ85T+FXPKkvE+aQ= -github.com/sigstore/fulcio v1.7.1/go.mod h1:7lYY+hsd8Dt+IvKQRC+KEhWpCZ/GlmNvwIa5JhypMS8= +github.com/sigstore/fulcio v1.8.3 h1:zkuAkRHbD53hhYGlBHHeAW4NRDrrTiDHumAbcfSyyFw= +github.com/sigstore/fulcio v1.8.3/go.mod h1:YxP7TTdn9H5Gg+dXOsu61X36LLYxT2ZuvODhWelMNwA= github.com/sigstore/protobuf-specs v0.5.0 h1:F8YTI65xOHw70NrvPwJ5PhAzsvTnuJMGLkA4FIkofAY= github.com/sigstore/protobuf-specs v0.5.0/go.mod h1:+gXR+38nIa2oEupqDdzg4qSBT0Os+sP7oYv6alWewWc= -github.com/sigstore/rekor v1.3.10 h1:/mSvRo4MZ/59ECIlARhyykAlQlkmeAQpvBPlmJtZOCU= -github.com/sigstore/rekor v1.3.10/go.mod h1:JvryKJ40O0XA48MdzYUPu0y4fyvqt0C4iSY7ri9iu3A= -github.com/sigstore/rekor-tiles v0.1.7-0.20250624231741-98cd4a77300f h1:zaqWahYAlVouSm5qwCH+2vZ3eenZFBwzzuBz/IZyy5c= -github.com/sigstore/rekor-tiles v0.1.7-0.20250624231741-98cd4a77300f/go.mod h1:1Epq0PQ73v5Z276rAY241JyaP8gtD64I6sgYIECHPvc= -github.com/sigstore/sigstore v1.9.5 h1:Wm1LT9yF4LhQdEMy5A2JeGRHTrAWGjT3ubE5JUSrGVU= -github.com/sigstore/sigstore v1.9.5/go.mod h1:VtxgvGqCmEZN9X2zhFSOkfXxvKUjpy8RpUW39oCtoII= -github.com/sigstore/sigstore-go v1.1.0 h1:NBfyvL/LiBIplnIZAtC7GtDZ7qj82A/GTpn0+5WV7BM= -github.com/sigstore/sigstore-go v1.1.0/go.mod h1:97lDVpZVBCTFX114KPAManEsShVe934KyaVhZGhPVBM= -github.com/sigstore/sigstore/pkg/signature/kms/aws v1.9.5 h1:qp2VFyKuFQvTGmZwk5Q7m5nE4NwnF9tHwkyz0gtWAck= -github.com/sigstore/sigstore/pkg/signature/kms/aws v1.9.5/go.mod h1:DKlQjjr+GsWljEYPycI0Sf8URLCk4EbGA9qYjF47j4g= -github.com/sigstore/sigstore/pkg/signature/kms/azure v1.9.5 h1:CRZcdYn5AOptStsLRAAACudAVmb1qUbhMlzrvm7ju3o= -github.com/sigstore/sigstore/pkg/signature/kms/azure v1.9.5/go.mod h1:b9rFfITq2fp1M3oJmq6lFFhSrAz5vOEJH1qzbMsZWN4= -github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.9.5 h1:7U0GsO0UGG1PdtgS6wBkRC0sMgq7BRVaFlPRwN4m1Qg= -github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.9.5/go.mod h1:/2qrI0nnCy/DTIPOMFaZlFnNPWEn5UeS70P37XEM88o= -github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.9.5 h1:S2ukEfN1orLKw2wEQIUHDDlzk0YcylhcheeZ5TGk8LI= -github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.9.5/go.mod h1:m7sQxVJmDa+rsmS1m6biQxaLX83pzNS7ThUEyjOqkCU= -github.com/sigstore/timestamp-authority v1.2.8 h1:BEV3fkphwU4zBp3allFAhCqQb99HkiyCXB853RIwuEE= -github.com/sigstore/timestamp-authority v1.2.8/go.mod h1:G2/0hAZmLPnevEwT1S9IvtNHUm9Ktzvso6xuRhl94ZY= -github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= -github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA= -github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog= +github.com/sigstore/rekor v1.4.3 h1:2+aw4Gbgumv8vYM/QVg6b+hvr4x4Cukur8stJrVPKU0= +github.com/sigstore/rekor v1.4.3/go.mod h1:o0zgY087Q21YwohVvGwV9vK1/tliat5mfnPiVI3i75o= +github.com/sigstore/rekor-tiles/v2 v2.0.1 h1:1Wfz15oSRNGF5Dzb0lWn5W8+lfO50ork4PGIfEKjZeo= +github.com/sigstore/rekor-tiles/v2 v2.0.1/go.mod h1:Pjsbhzj5hc3MKY8FfVTYHBUHQEnP0ozC4huatu4x7OU= +github.com/sigstore/sigstore v1.10.0 h1:lQrmdzqlR8p9SCfWIpFoGUqdXEzJSZT2X+lTXOMPaQI= +github.com/sigstore/sigstore v1.10.0/go.mod h1:Ygq+L/y9Bm3YnjpJTlQrOk/gXyrjkpn3/AEJpmk1n9Y= +github.com/sigstore/sigstore-go v1.1.4-0.20251201121426-2cdedea80894 h1:K8hnZhun6XacjxAdCdxkowSi7+FpmfYnAcMhTXZQyPg= +github.com/sigstore/sigstore-go v1.1.4-0.20251201121426-2cdedea80894/go.mod h1:uuR+Edo6P+iwi0HKscycUm8mxXL748nAureqSg6jFLA= +github.com/sigstore/sigstore/pkg/signature/kms/aws v1.10.0 h1:UOHpiyezCj5RuixgIvCV3QyuxIGQT+N6nGZEXA7OTTY= +github.com/sigstore/sigstore/pkg/signature/kms/aws v1.10.0/go.mod h1:U0CZmA2psabDa8DdiV7yXab0AHODzfKqvD2isH7Hrvw= +github.com/sigstore/sigstore/pkg/signature/kms/azure v1.10.0 h1:fq4+8Y4YadxeF8mzhoMRPZ1mVvDYXmI3BfS0vlkPT7M= +github.com/sigstore/sigstore/pkg/signature/kms/azure v1.10.0/go.mod h1:u05nqPWY05lmcdHhv2lPaWTH3FGUhJzO7iW2hbboK3Q= +github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.10.0 h1:iUEf5MZYOuXGnXxdF/WrarJrk0DTVHqeIOjYdtpVXtc= +github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.10.0/go.mod h1:i6vg5JfEQix46R1rhQlrKmUtJoeH91drltyYOJEk1T4= +github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.10.0 h1:dUvPv/MP23ZPIXZUW45kvCIgC0ZRfYxEof57AB6bAtU= +github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.10.0/go.mod h1:fR/gDdPvJWGWL70/NgBBIL1O0/3Wma6JHs3tSSYg3s4= +github.com/sigstore/timestamp-authority/v2 v2.0.3 h1:sRyYNtdED/ttLCMdaYnwpf0zre1A9chvjTnCmWWxN8Y= +github.com/sigstore/timestamp-authority/v2 v2.0.3/go.mod h1:mDaHxkt3HmZYoIlwYj4QWo0RUr7VjYU52aVO5f5Qb3I= +github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af h1:Sp5TG9f7K39yfB+If0vjp97vuT74F72r8hfRpP8jLU0= +github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= -github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= -github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= -github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= -github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs= -github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4= -github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= -github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= -github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= -github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= -github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M= -github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4= -github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4= -github.com/spiffe/go-spiffe/v2 v2.5.0 h1:N2I01KCUkv1FAjZXJMwh95KK1ZIQLYbPfhaxw8WS0hE= -github.com/spiffe/go-spiffe/v2 v2.5.0/go.mod h1:P+NxobPc6wXhVtINNtFjNWGBTreew1GBUCwT2wPmb7g= +github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw= +github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U= +github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= +github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= +github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY= +github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= +github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU= +github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4= +github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= +github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU= +github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY= +github.com/spiffe/go-spiffe/v2 v2.6.0 h1:l+DolpxNWYgruGQVV0xsfeya3CsC7m8iBzDnMpsbLuo= +github.com/spiffe/go-spiffe/v2 v2.6.0/go.mod h1:gm2SeUoMZEtpnzPNs2Csc0D/gX33k1xIx7lEzqblHEs= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 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= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDdvS342BElfbETmL1Aiz3i2t0zfRj16Hs= github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= -github.com/tchap/go-patricia/v2 v2.3.2 h1:xTHFutuitO2zqKAQ5rCROYgUb7Or/+IC3fts9/Yc7nM= -github.com/tchap/go-patricia/v2 v2.3.2/go.mod h1:VZRHKAb53DLaG+nA9EaYYiaEx6YztwDlLElMsnSHD4k= +github.com/tchap/go-patricia/v2 v2.3.3 h1:xfNEsODumaEcCcY3gI0hYPZ/PcpVv5ju6RMAhgwZDDc= +github.com/tchap/go-patricia/v2 v2.3.3/go.mod h1:VZRHKAb53DLaG+nA9EaYYiaEx6YztwDlLElMsnSHD4k= github.com/thales-e-security/pool v0.0.2 h1:RAPs4q2EbWsTit6tpzuvTFlgFRJ3S8Evf5gtvVDbmPg= github.com/thales-e-security/pool v0.0.2/go.mod h1:qtpMm2+thHtqhLzTwgDBj/OuNnMpupY8mv0Phz0gjhU= github.com/theupdateframework/go-tuf v0.7.0 h1:CqbQFrWo1ae3/I0UCblSbczevCCbS31Qvs5LdxRWqRI= github.com/theupdateframework/go-tuf v0.7.0/go.mod h1:uEB7WSY+7ZIugK6R1hiBMBjQftaFzn7ZCDJcp1tCUug= -github.com/theupdateframework/go-tuf/v2 v2.1.1 h1:OWcoHItwsGO+7m0wLa7FDWPR4oB1cj0zOr1kosE4G+I= -github.com/theupdateframework/go-tuf/v2 v2.1.1/go.mod h1:V675cQGhZONR0OGQ8r1feO0uwtsTBYPDWHzAAPn5rjE= +github.com/theupdateframework/go-tuf/v2 v2.3.0 h1:gt3X8xT8qu/HT4w+n1jgv+p7koi5ad8XEkLXXZqG9AA= +github.com/theupdateframework/go-tuf/v2 v2.3.0/go.mod h1:xW8yNvgXRncmovMLvBxKwrKpsOwJZu/8x+aB0KtFcdw= github.com/tink-crypto/tink-go-awskms/v2 v2.1.0 h1:N9UxlsOzu5mttdjhxkDLbzwtEecuXmlxZVo/ds7JKJI= github.com/tink-crypto/tink-go-awskms/v2 v2.1.0/go.mod h1:PxSp9GlOkKL9rlybW804uspnHuO9nbD98V/fDX4uSis= github.com/tink-crypto/tink-go-gcpkms/v2 v2.2.0 h1:3B9i6XBXNTRspfkTC0asN5W0K6GhOSgcujNiECNRNb0= github.com/tink-crypto/tink-go-gcpkms/v2 v2.2.0/go.mod h1:jY5YN2BqD/KSCHM9SqZPIpJNG/u3zwfLXHgws4x2IRw= github.com/tink-crypto/tink-go-hcvault/v2 v2.3.0 h1:6nAX1aRGnkg2SEUMwO5toB2tQkP0Jd6cbmZ/K5Le1V0= github.com/tink-crypto/tink-go-hcvault/v2 v2.3.0/go.mod h1:HOC5NWW1wBI2Vke1FGcRBvDATkEYE7AUDiYbXqi2sBw= -github.com/tink-crypto/tink-go/v2 v2.4.0 h1:8VPZeZI4EeZ8P/vB6SIkhlStrJfivTJn+cQ4dtyHNh0= -github.com/tink-crypto/tink-go/v2 v2.4.0/go.mod h1:l//evrF2Y3MjdbpNDNGnKgCpo5zSmvUvnQ4MU+yE2sw= +github.com/tink-crypto/tink-go/v2 v2.5.0 h1:B8KLF6AofxdBIE4UJIaFbmoj5/1ehEtt7/MmzfI4Zpw= +github.com/tink-crypto/tink-go/v2 v2.5.0/go.mod h1:2WbBA6pfNsAfBwDCggboaHeB2X29wkU8XHtGwh2YIk8= github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 h1:e/5i7d4oYZ+C1wj2THlRK+oAhjeS/TRQwMfkIuet3w0= github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399/go.mod h1:LdwHTNJT99C5fTAzDz0ud328OgXz+gierycbcIx2fRs= github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w= github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho= github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE= -github.com/transparency-dev/formats v0.0.0-20250421220931-bb8ad4d07c26 h1:YTbkeFbzcer+42bIgo6Za2194nKwhZPgaZKsP76QffE= -github.com/transparency-dev/formats v0.0.0-20250421220931-bb8ad4d07c26/go.mod h1:ODywn0gGarHMMdSkWT56ULoK8Hk71luOyRseKek9COw= +github.com/transparency-dev/formats v0.0.0-20251017110053-404c0d5b696c h1:5a2XDQ2LiAUV+/RjckMyq9sXudfrPSuCY4FuPC1NyAw= +github.com/transparency-dev/formats v0.0.0-20251017110053-404c0d5b696c/go.mod h1:g85IafeFJZLxlzZCDRu4JLpfS7HKzR+Hw9qRh3bVzDI= github.com/transparency-dev/merkle v0.0.2 h1:Q9nBoQcZcgPamMkGn7ghV8XiTZ/kRxn1yCG81+twTK4= github.com/transparency-dev/merkle v0.0.2/go.mod h1:pqSy+OXefQ1EDUVmAJ8MUhHB9TXGuzVAT58PqBoHz1A= -github.com/transparency-dev/tessera v0.2.1-0.20250610150926-8ee4e93b2823 h1:s3p7wNrK/mnKI2bdp9PrQd9eBVxo1i5rU6O5hKkN0zc= -github.com/transparency-dev/tessera v0.2.1-0.20250610150926-8ee4e93b2823/go.mod h1:Jv2IDwG1q8QNXZTaI1X6QX8s96WlJn73ka2hT1n4N5c= github.com/urfave/negroni v1.0.0 h1:kIimOitoypq34K7TG7DUaJ9kq/N4Ofuwi1sjz0KipXc= github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= -github.com/vbatts/tar-split v0.12.1 h1:CqKoORW7BUWBe7UL/iqTVvkTBOF8UvOMKOIZykxnnbo= -github.com/vbatts/tar-split v0.12.1/go.mod h1:eF6B6i6ftWQcDqEn3/iGFRFRo8cBIMSJVOpnNdfTMFA= -github.com/vektah/gqlparser/v2 v2.5.28 h1:bIulcl3LF69ba6EiZVGD88y4MkM+Jxrf3P2MX8xLRkY= -github.com/vektah/gqlparser/v2 v2.5.28/go.mod h1:D1/VCZtV3LPnQrcPBeR/q5jkSQIPti0uYCP/RI0gIeo= +github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ= +github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY= +github.com/vbatts/tar-split v0.12.2 h1:w/Y6tjxpeiFMR47yzZPlPj/FcPLpXbTUi/9H7d3CPa4= +github.com/vbatts/tar-split v0.12.2/go.mod h1:eF6B6i6ftWQcDqEn3/iGFRFRo8cBIMSJVOpnNdfTMFA= +github.com/vektah/gqlparser/v2 v2.5.30 h1:EqLwGAFLIzt1wpx1IPpY67DwUujF1OfzgEyDsLrN6kE= +github.com/vektah/gqlparser/v2 v2.5.30/go.mod h1:D1/VCZtV3LPnQrcPBeR/q5jkSQIPti0uYCP/RI0gIeo= github.com/withfig/autocomplete-tools/integrations/cobra v1.2.1 h1:+dBg5k7nuTE38VVdoroRsT0Z88fmvdYrI2EjzJst35I= github.com/withfig/autocomplete-tools/integrations/cobra v1.2.1/go.mod h1:nmuySobZb4kFgFy6BptpXp/BBw+xFSyvVPP6auoJB4k= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= @@ -1533,764 +756,221 @@ github.com/ysmood/gson v0.7.3 h1:QFkWbTH8MxyUTKPkVWAENJhxqdBa4lYTQWqZCiLG6kE= github.com/ysmood/gson v0.7.3/go.mod h1:3Kzs5zDl21g5F/BlLTNcuAGAYLKt2lV5G8D1zF3RNmg= github.com/ysmood/leakless v0.9.0 h1:qxCG5VirSBvmi3uynXFkcnLMzkphdh3xx5FtrORwDCU= github.com/ysmood/leakless v0.9.0/go.mod h1:R8iAXPRaG97QJwqxs74RdwzcRHT1SWCGTNqY8q0JvMQ= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.30/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/zalando/go-keyring v0.2.6 h1:r7Yc3+H+Ux0+M72zacZoItR3UDxeWfKTcabvkI8ua9s= github.com/zalando/go-keyring v0.2.6/go.mod h1:2TCrxYrbUNYfNS/Kgy/LSrkSQzZ5UPVH85RwfczwvcI= -github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= -github.com/zeebo/errs v1.4.0 h1:XNdoD/RRMKP7HD0UhJnIzUy74ISdGGxURlYG8HSWSfM= -github.com/zeebo/errs v1.4.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4= -github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= -gitlab.com/gitlab-org/api/client-go v0.137.0 h1:H26yL44qnb38Czl20pEINCJrcj63W6/BX8iKPVUKQP0= -gitlab.com/gitlab-org/api/client-go v0.137.0/go.mod h1:AcAYES3lfkIS4zhso04S/wyUaWQmDYve2Fd9AF7C6qc= -go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd80= -go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= -go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= -go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= -go.opentelemetry.io/contrib/detectors/gcp v1.36.0 h1:F7q2tNlCaHY9nMKHR6XH9/qkp8FktLnIcy6jJNyOCQw= -go.opentelemetry.io/contrib/detectors/gcp v1.36.0/go.mod h1:IbBN8uAIIx734PTonTPxAxnjc2pQTxWNkwfstZ+6H2k= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 h1:q4XOmH/0opmeuJtPsbFNivyl7bCt7yRBbeEm2sC/XtQ= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0/go.mod h1:snMWehoOh2wsEwnvvwtDyFCxVeDAODenXHtn5vzrKjo= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q= -go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ= -go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 h1:Ahq7pZmv87yiyn3jeFz/LekZmPLLdKejuO3NcK9MssM= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0/go.mod h1:MJTqhM0im3mRLw1i8uGHnCvUEeS7VwRyxlLC78PA18M= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 h1:EtFWSnwW9hGObjkIdmlnWSydO+Qs8OwzfzXLUPg4xOc= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0/go.mod h1:QjUEoiGCPkvFZ/MjK6ZZfNOS6mfVEVKYE99dFhuN2LI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.37.0 h1:bDMKF3RUSxshZ5OjOTi8rsHGaPKsAt76FaqgvIUySLc= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.37.0/go.mod h1:dDT67G/IkA46Mr2l9Uj7HsQVwsjASyV9SjGofsiUZDA= -go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0 h1:rixTyDGXFxRy1xzhKrotaHy3/KXdPhlWARrCgK+eqUY= -go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0/go.mod h1:dowW6UsM9MKbJq5JTz2AMVp3/5iW5I/TStsk8S+CfHw= -go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE= -go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E= -go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI= -go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg= -go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis= -go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4= -go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4= -go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= -go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= -go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= -go.opentelemetry.io/proto/otlp v1.7.0 h1:jX1VolD6nHuFzOYso2E73H85i92Mv8JQYk0K9vz09os= -go.opentelemetry.io/proto/otlp v1.7.0/go.mod h1:fSKjH6YJ7HDlwzltzyMj036AJ3ejJLCgCSHGj4efDDo= -go.step.sm/crypto v0.67.0 h1:1km9LmxMKG/p+mKa1R4luPN04vlJYnRLlLQrWv7egGU= -go.step.sm/crypto v0.67.0/go.mod h1:+AoDpB0mZxbW/PmOXuwkPSpXRgaUaoIK+/Wx/HGgtAU= +gitlab.com/gitlab-org/api/client-go v0.160.0 h1:aMQzbcE8zFe0lR/J+a3zneEgH+/EBFs8rD8Chrr4Snw= +gitlab.com/gitlab-org/api/client-go v0.160.0/go.mod h1:ooCNtKB7OyP7GBa279+HrUS3eeJF6Yi6XABZZy7RTSk= +go.mongodb.org/mongo-driver v1.17.6 h1:87JUG1wZfWsr6rIz3ZmpH90rL5tea7O3IHuSwHUpsss= +go.mongodb.org/mongo-driver v1.17.6/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 h1:YH4g8lQroajqUwWbq/tr2QX1JFmEXaDLgG+ew9bLMWo= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0/go.mod h1:fvPi2qXDqFs8M4B4fmJhE92TyQs9Ydjlg3RvfUp+NbQ= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 h1:RbKq8BG0FI8OiXhBfcRtqqHcZcka+gU3cskNuf05R18= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0/go.mod h1:h06DGIukJOevXaj/xrNjhi/2098RZzcLTbc0jDAUbsg= +go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= +go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 h1:lwI4Dc5leUqENgGuQImwLo4WnuXFPetmPpkLi2IrX54= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0/go.mod h1:Kz/oCE7z5wuyhPxsXDuaPteSWqjSBD5YaSdbxZYGbGk= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 h1:aTL7F04bJHUlztTsNGJ2l+6he8c+y/b//eR0jjjemT4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0/go.mod h1:kldtb7jDTeol0l3ewcmd8SDvx3EmIE7lyvqbasU3QC4= +go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= +go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= +go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= +go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= +go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= +go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= +go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= +go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= +go.opentelemetry.io/proto/otlp v1.8.0 h1:fRAZQDcAFHySxpJ1TwlA1cJ4tvcrw7nXl9xWWC8N5CE= +go.opentelemetry.io/proto/otlp v1.8.0/go.mod h1:tIeYOeNBU4cvmPqpaji1P+KbB4Oloai8wN4rWzRrFF0= +go.step.sm/crypto v0.74.0 h1:/APBEv45yYR4qQFg47HA8w1nesIGcxh44pGyQNw6JRA= +go.step.sm/crypto v0.74.0/go.mod h1:UoXqCAJjjRgzPte0Llaqen7O9P7XjPmgjgTHQGkKCDk= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= -go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= +go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= +go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= 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.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= -golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= -golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= -golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= +golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3/go.mod h1:NOZ3BPKG0ec/BKJQgnvsSFpcKLM5xXVWnvZS97DWHgE= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= -golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM= -golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8= -golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20210216034530-4410531fe030/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= -golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= -golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= -golang.org/x/image v0.0.0-20220302094943-723b81ca9867/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= +golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/yqS/lQJ6PmkyIV3YP+o= +golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8= 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-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 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.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= -golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg= -golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ= +golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= +golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= 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= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.0.0-20221012135044-0b7e1fb9d458/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= -golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -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.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= 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.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= -golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= +golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= +golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= -golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= -golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.0.0-20221006150949-b44042a4b9c1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= -golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= -golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= -golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= -golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= -golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= +golang.org/x/oauth2 v0.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo= +golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= 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-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/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.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= -golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= +golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= 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-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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.7.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.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= -golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= +golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= 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= -golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= -golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= 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.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= 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.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= -golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg= -golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= +golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/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= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= 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.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= -golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= -golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= -golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= +golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= +golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= 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-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200509030707-2212a7e161a5/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= -golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= -golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0= -golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw= +golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= +golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= -gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= -gonum.org/v1/gonum v0.9.3/go.mod h1:TZumC3NeyVQskjXqmyWt4S3bINhy7B4eYwW69EbyX+0= -gonum.org/v1/gonum v0.11.0/go.mod h1:fSG4YDCxxUZQJ7rKsQrj0gMOg00Il0Z96/qMA4bVQhA= -gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= -gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= -gonum.org/v1/plot v0.9.0/go.mod h1:3Pcqqmp6RHvJI72kgb8fThyUnav364FOsdDo2aGW5lY= -gonum.org/v1/plot v0.10.1/go.mod h1:VZW5OlhkL1mysU9vaqNHnsy86inf6Ot+jB3r+BczCEo= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= -google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= -google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= -google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= -google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= -google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= -google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= -google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= -google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= -google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= -google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= -google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= -google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= -google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= -google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= -google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= -google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= -google.golang.org/api v0.77.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= -google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= -google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= -google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= -google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g= -google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= -google.golang.org/api v0.93.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw= -google.golang.org/api v0.95.0/go.mod h1:eADj+UBuxkh5zlrSntJghuNeg8HwQ1w5lTKkuqaETEI= -google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= -google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= -google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= -google.golang.org/api v0.99.0/go.mod h1:1YOf74vkVndF7pG6hIHuINsM7eWwpVTAfNMNiL91A08= -google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70= -google.golang.org/api v0.102.0/go.mod h1:3VFl6/fzoA+qNuS1N1/VfXY4LjoXN/wzeIp7TweWwGo= -google.golang.org/api v0.103.0/go.mod h1:hGtW6nK1AC+d9si/UBhw8Xli+QMOf6xyNAyJw4qU9w0= -google.golang.org/api v0.106.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= -google.golang.org/api v0.107.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= -google.golang.org/api v0.108.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/O9MY= -google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60ca7iI= -google.golang.org/api v0.111.0/go.mod h1:qtFHvU9mhgTJegR31csQ+rwxyUTHOKFqCKWp1J0fdw0= -google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg= -google.golang.org/api v0.243.0 h1:sw+ESIJ4BVnlJcWu9S+p2Z6Qq1PjG77T8IJ1xtp4jZQ= -google.golang.org/api v0.243.0/go.mod h1:GE4QtYfaybx1KmeHMdBnNnyLzBZCVihGBXAmJu/uUr8= +gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= +gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= +google.golang.org/api v0.256.0 h1:u6Khm8+F9sxbCTYNoBHg6/Hwv0N/i+V94MvkOSor6oI= +google.golang.org/api v0.256.0/go.mod h1:KIgPhksXADEKJlnEoRa9qAII4rXcy40vfI8HRqcU964= 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.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7/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-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= -google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= -google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= -google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= -google.golang.org/genproto v0.0.0-20220329172620-7be39ac1afc7/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220502173005-c8bf987b8c21/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20220722212130-b98a9ff5e252/go.mod h1:GkXuJDJ6aQ7lnJcRF+SJVgFdQhypqgl3LB1C9vabdRE= -google.golang.org/genproto v0.0.0-20220801145646-83ce21fca29f/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc= -google.golang.org/genproto v0.0.0-20220815135757-37a418bb8959/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220817144833-d7fd3f11b9b1/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220829144015-23454907ede3/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220829175752-36a9c930ecbf/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk= -google.golang.org/genproto v0.0.0-20220913154956-18f8339a66a5/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220914142337-ca0e39ece12f/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220915135415-7fd63a7952de/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220919141832-68c03719ef51/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= -google.golang.org/genproto v0.0.0-20220920201722-2b89144ce006/go.mod h1:ht8XFiar2npT/g4vkk7O0WYS1sHOHbdujxbEp7CJWbw= -google.golang.org/genproto v0.0.0-20220926165614-551eb538f295/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= -google.golang.org/genproto v0.0.0-20220926220553-6981cbe3cfce/go.mod h1:woMGP53BroOrRY3xTxlbr8Y3eB/nzAvvFM83q7kG2OI= -google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqwhZAwq4wsRUaVG555sVgsNmIjRtO7t/JH29U= -google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= -google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= -google.golang.org/genproto v0.0.0-20221024153911-1573dae28c9c/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= -google.golang.org/genproto v0.0.0-20221024183307-1bc688fe9f3e/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= -google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c/go.mod h1:CGI5F/G+E5bKwmfYo09AXuVN4dD894kIKUFmVbP2/Fo= -google.golang.org/genproto v0.0.0-20221109142239-94d6d90a7d66/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221114212237-e4508ebdbee1/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221117204609-8f9c96812029/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221201204527-e3fa12d562f3/go.mod h1:rZS5c/ZVYMaOGBfO68GWtjOw/eLaZM1X6iVtgjZ+EWg= -google.golang.org/genproto v0.0.0-20221202195650-67e5cbc046fd/go.mod h1:cTsE614GARnxrLsqKREzmNYJACSWWpAWdNMwnD7c2BE= -google.golang.org/genproto v0.0.0-20221227171554-f9683d7f8bef/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230112194545-e10362b5ecf9/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230113154510-dbe35b8444a5/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230123190316-2c411cf9d197/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230124163310-31e0e69b6fc2/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230125152338-dcaf20b6aeaa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230127162408-596548ed4efa/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230209215440-0dfe4f8abfcc/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/genproto v0.0.0-20230216225411-c8e22ba71e44/go.mod h1:8B0gmkoRebU8ukX6HP+4wrVQUY1+6PkQ44BSyIlflHA= -google.golang.org/genproto v0.0.0-20230222225845-10f96fb3dbec/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw= -google.golang.org/genproto v0.0.0-20230223222841-637eb2293923/go.mod h1:3Dl5ZL0q0isWJt+FVcfpQyirqemEuLAK/iFvg1UP1Hw= -google.golang.org/genproto v0.0.0-20230303212802-e74f57abe488/go.mod h1:TvhZT5f700eVlTNwND1xoEZQeWTB2RY/65kplwl/bFA= -google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= -google.golang.org/genproto v0.0.0-20230320184635-7606e756e683/go.mod h1:NWraEVixdDnqcqQ30jipen1STv2r/n24Wb7twVTGR4s= -google.golang.org/genproto v0.0.0-20230323212658-478b75c54725/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= -google.golang.org/genproto v0.0.0-20230330154414-c0448cd141ea/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= -google.golang.org/genproto v0.0.0-20230331144136-dcfb400f0633/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= -google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= -google.golang.org/genproto v0.0.0-20250603155806-513f23925822 h1:rHWScKit0gvAPuOnu87KpaYtjK5zBMLcULh7gxkCXu4= -google.golang.org/genproto v0.0.0-20250603155806-513f23925822/go.mod h1:HubltRL7rMh0LfnQPkMH4NPDFEWp0jw3vixw7jEM53s= -google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 h1:oWVWY3NzT7KJppx2UKhKmzPq4SRe0LdCijVRwvGeikY= -google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822/go.mod h1:h3c4v36UTKzUiuaOKQ6gr3S+0hovBtUrXzTG/i3+XEc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250715232539-7130f93afb79 h1:1ZwqphdOdWYXsUHgMpU/101nCtf/kSp9hOrcvFsnl10= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250715232539-7130f93afb79/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/genproto v0.0.0-20250922171735-9219d122eba9 h1:LvZVVaPE0JSqL+ZWb6ErZfnEOKIqqFWUJE2D0fObSmc= +google.golang.org/genproto v0.0.0-20250922171735-9219d122eba9/go.mod h1:QFOrLhdAe2PsTp3vQY4quuLKTi9j3XG3r6JPPaw7MSc= +google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8 h1:mepRgnBZa07I4TRuomDE4sTIYieg/osKmzIf4USdWS4= +google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8/go.mod h1:fDMmzKV90WSg1NbozdqrE64fkuTv6mlq2zxo9ad+3yo= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251103181224-f26f9409b101 h1:tRPGkdGHuewF4UisLzzHHr1spKw92qLM98nIzxbC0wY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251103181224-f26f9409b101/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= 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.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= -google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= -google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= -google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= -google.golang.org/grpc v1.52.3/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5vorUY= -google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= -google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= -google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= -google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok= -google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= +google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= +google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= 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= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 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.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= -google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= +google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= 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= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4= gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= @@ -2302,7 +982,6 @@ gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -2314,73 +993,28 @@ gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= -k8s.io/api v0.33.3 h1:SRd5t//hhkI1buzxb288fy2xvjubstenEKL9K51KBI8= -k8s.io/api v0.33.3/go.mod h1:01Y/iLUjNBM3TAvypct7DIj0M0NIZc+PzAHCIo0CYGE= -k8s.io/apimachinery v0.33.3 h1:4ZSrmNa0c/ZpZJhAgRdcsFcZOw1PQU1bALVQ0B3I5LA= -k8s.io/apimachinery v0.33.3/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM= -k8s.io/client-go v0.33.3 h1:M5AfDnKfYmVJif92ngN532gFqakcGi6RvaOF16efrpA= -k8s.io/client-go v0.33.3/go.mod h1:luqKBQggEf3shbxHY4uVENAxrDISLOarxpTKMiUuujg= +k8s.io/api v0.34.2 h1:fsSUNZhV+bnL6Aqrp6O7lMTy6o5x2C4XLjnh//8SLYY= +k8s.io/api v0.34.2/go.mod h1:MMBPaWlED2a8w4RSeanD76f7opUoypY8TFYkSM+3XHw= +k8s.io/apimachinery v0.34.2 h1:zQ12Uk3eMHPxrsbUJgNF8bTauTVR2WgqJsTmwTE/NW4= +k8s.io/apimachinery v0.34.2/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= +k8s.io/client-go v0.34.2 h1:Co6XiknN+uUZqiddlfAjT68184/37PS4QAzYvQvDR8M= +k8s.io/client-go v0.34.2/go.mod h1:2VYDl1XXJsdcAxw7BenFslRQX28Dxz91U9MWKjX97fE= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4= -k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff/go.mod h1:5jIi+8yX4RIb8wk3XwBo5Pq2ccx4FP10ohkbSKCZoK8= -k8s.io/utils v0.0.0-20241210054802-24370beab758 h1:sdbE21q2nlQtFh65saZY+rRM6x6aJJI8IUa1AmH/qa0= -k8s.io/utils v0.0.0-20241210054802-24370beab758/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= -lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= -modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= -modernc.org/cc/v3 v3.36.2/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= -modernc.org/cc/v3 v3.36.3/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= -modernc.org/ccgo/v3 v3.0.0-20220428102840-41399a37e894/go.mod h1:eI31LL8EwEBKPpNpA4bU1/i+sKOwOrQy8D87zWUcRZc= -modernc.org/ccgo/v3 v3.0.0-20220430103911-bc99d88307be/go.mod h1:bwdAnOoaIt8Ax9YdWGjxWsdkPcZyRPHqrOvJxaKAKGw= -modernc.org/ccgo/v3 v3.16.4/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= -modernc.org/ccgo/v3 v3.16.6/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= -modernc.org/ccgo/v3 v3.16.8/go.mod h1:zNjwkizS+fIFDrDjIAgBSCLkWbJuHF+ar3QRn+Z9aws= -modernc.org/ccgo/v3 v3.16.9/go.mod h1:zNMzC9A9xeNUepy6KuZBbugn3c0Mc9TeiJO4lgvkJDo= -modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= -modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= -modernc.org/libc v0.0.0-20220428101251-2d5f3daf273b/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= -modernc.org/libc v1.16.0/go.mod h1:N4LD6DBE9cf+Dzf9buBlzVJndKr/iJHG97vGLHYnb5A= -modernc.org/libc v1.16.1/go.mod h1:JjJE0eu4yeK7tab2n4S1w8tlWd9MxXLRzheaRnAKymU= -modernc.org/libc v1.16.17/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU= -modernc.org/libc v1.16.19/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= -modernc.org/libc v1.17.0/go.mod h1:XsgLldpP4aWlPlsjqKRdHPqCxCjISdHfM/yeWC5GyW0= -modernc.org/libc v1.17.1/go.mod h1:FZ23b+8LjxZs7XtFMbSzL/EhPxNbfZbErxEHc7cbD9s= -modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= -modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= -modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= -modernc.org/memory v1.1.1/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= -modernc.org/memory v1.2.0/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= -modernc.org/memory v1.2.1/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= -modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= -modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= -modernc.org/sqlite v1.18.1/go.mod h1:6ho+Gow7oX5V+OiOQ6Tr4xeqbx13UZ6t+Fw9IRUG4d4= -modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw= -modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= -modernc.org/tcl v1.13.1/go.mod h1:XOLfOwzhkljL4itZkK6T72ckMgvj0BDsnKNdZVUOecw= -modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= -modernc.org/z v1.5.1/go.mod h1:eWFB510QWW5Th9YGZT81s+LwvaAs3Q2yr4sP0rmLkv8= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8= -sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo= -sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= +k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b h1:MloQ9/bdJyIu9lb1PzujOPolHyvO06MXG5TUIj2mNAA= +k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b/go.mod h1:UZ2yyWbFTpuhSbFhv24aGNOdoRdJZgsIObGBUaYVsts= +k8s.io/utils v0.0.0-20250820121507-0af2bda4dd1d h1:wAhiDyZ4Tdtt7e46e9M5ZSAJ/MnPGPs+Ki1gHw4w1R0= +k8s.io/utils v0.0.0-20250820121507-0af2bda4dd1d/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE= +sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/release-utils v0.12.0 h1:+Z8cEUAaxItrMcTOJ0jtUg3Fm1uNgPNol+VIL6XtQqQ= -sigs.k8s.io/release-utils v0.12.0/go.mod h1:TveYRPK4Mq6qXA0PJiUMEOlWvvIQG0Mh5APQmHD5JpA= -sigs.k8s.io/structured-merge-diff/v4 v4.6.0 h1:IUA9nvMmnKWcj5jl84xn+T5MnlZKThmUW1TdblaLVAc= -sigs.k8s.io/structured-merge-diff/v4 v4.6.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= -sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= -sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= +sigs.k8s.io/release-utils v0.12.2 h1:H06v3FuLElAkf7Ikkd9ll8hnhdtQ+OgktJAni3iIAl8= +sigs.k8s.io/release-utils v0.12.2/go.mod h1:Ab9Lb/FpGUw4lUXj1QYbUcF2TRzll+GS7Md54W1G7sA= +sigs.k8s.io/structured-merge-diff/v6 v6.3.0 h1:jTijUJbW353oVOd9oTlifJqOGEkUw2jB/fXCbTiQEco= +sigs.k8s.io/structured-merge-diff/v6 v6.3.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= +sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= software.sslmate.com/src/go-pkcs12 v0.4.0 h1:H2g08FrTvSFKUj+D309j1DPfk5APnIdAQAB8aEykJ5k= software.sslmate.com/src/go-pkcs12 v0.4.0/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI= diff --git a/internal/auth/auth.go b/internal/auth/auth.go new file mode 100644 index 00000000000..6a9e64a1221 --- /dev/null +++ b/internal/auth/auth.go @@ -0,0 +1,172 @@ +// Copyright 2025 The Sigstore 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 auth + +import ( + "context" + "fmt" + "os" + "time" + + "github.com/go-jose/go-jose/v4" + "github.com/go-jose/go-jose/v4/jwt" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/sign/privacy" + "github.com/sigstore/cosign/v3/internal/ui" + "github.com/sigstore/cosign/v3/pkg/providers" + "github.com/sigstore/sigstore-go/pkg/root" + "github.com/sigstore/sigstore/pkg/oauthflow" + "golang.org/x/term" +) + +const ( + flowNormal = "normal" + flowDevice = "device" + flowToken = "token" + flowClientCredentials = "client_credentials" +) + +var SigstoreOIDCIssuerAPIVersions = []uint32{1} + +type IDTokenConfig struct { + TokenOrPath string + DisableProviders bool + Provider string + AuthFlow string + SkipConfirm bool + OIDCServices []root.Service + ClientID string + ClientSecret string + RedirectURL string +} + +// RetrieveIDToken returns an ID token from one of the following sources: +// * Flag value +// * File, path provided by flag +// * Provider, e.g. a well-known location of a token for an environment like K8s or CI/CD +// * OpenID Connect authentication protocol +func RetrieveIDToken(ctx context.Context, c IDTokenConfig) (string, error) { + idToken, err := ReadIDToken(ctx, c.TokenOrPath, c.DisableProviders, c.Provider) + if err != nil { + return "", fmt.Errorf("reading ID token: %w", err) + } + if idToken != "" { + return idToken, nil + } + flow, err := GetOAuthFlow(ctx, c.AuthFlow, idToken, c.SkipConfirm) + if err != nil { + return "", fmt.Errorf("setting auth flow: %w", err) + } + oidcIssuerSvc, err := root.SelectService(c.OIDCServices, SigstoreOIDCIssuerAPIVersions, time.Now()) + if err != nil { + return "", fmt.Errorf("selecting OIDC issuer: %w", err) + } + _, idToken, err = AuthenticateCaller(flow, idToken, oidcIssuerSvc.URL, c.ClientID, c.ClientSecret, c.RedirectURL) + if err != nil { + return "", fmt.Errorf("authenticating caller: %w", err) + } + return idToken, err +} + +// ReadIDToken returns an OpenID Connect token from either a file or a well-known location from an identity provider +func ReadIDToken(ctx context.Context, tokOrPath string, disableProviders bool, oidcProvider string) (string, error) { + idToken, err := idToken(tokOrPath) + if err != nil { + return "", fmt.Errorf("getting id token: %w", err) + } + var provider providers.Interface + // If token is not set in the options, get one from the provders + if idToken == "" && providers.Enabled(ctx) && !disableProviders { + if oidcProvider != "" { + provider, err = providers.ProvideFrom(ctx, oidcProvider) + if err != nil { + return "", fmt.Errorf("getting provider: %w", err) + } + idToken, err = provider.Provide(ctx, "sigstore") + } else { + idToken, err = providers.Provide(ctx, "sigstore") + } + if err != nil { + return "", fmt.Errorf("fetching ambient OIDC credentials: %w", err) + } + } + return idToken, nil +} + +// GetOAuthFlow returns authentication flow that the client will initiate +func GetOAuthFlow(ctx context.Context, authFlow, idToken string, skipConfirm bool) (string, error) { + var flow string + switch { + case authFlow != "": + // Caller manually set flow option. + flow = authFlow + case idToken != "": + flow = flowToken + case !term.IsTerminal(0): + fmt.Fprintln(os.Stderr, "Non-interactive mode detected, using device flow.") + flow = flowDevice + default: + var statementErr error + privacy.StatementOnce.Do(func() { + ui.Infof(ctx, privacy.Statement) + ui.Infof(ctx, privacy.StatementConfirmation) + if !skipConfirm { + if err := ui.ConfirmContinue(ctx); err != nil { + statementErr = err + } + } + }) + if statementErr != nil { + return "", statementErr + } + flow = flowNormal + } + return flow, nil +} + +// AuthenticateCaller performs an OpenID Connect authentication to exchange credentials for an identity token +func AuthenticateCaller(flow, idToken, oidcIssuer, oidcClientID, oidcClientSecret, oidcRedirectURL string) (string, string, error) { + var tokenGetter oauthflow.TokenGetter + switch flow { + case flowClientCredentials: + tokenGetter = oauthflow.NewClientCredentialsFlow(oidcIssuer) + case flowDevice: + tokenGetter = oauthflow.NewDeviceFlowTokenGetterForIssuer(oidcIssuer) + case flowNormal: + tokenGetter = oauthflow.DefaultIDTokenGetter + case flowToken: + tokenGetter = &oauthflow.StaticTokenGetter{RawToken: idToken} + default: + return "", "", fmt.Errorf("unsupported oauth flow: %s", flow) + } + + tok, err := oauthflow.OIDConnect(oidcIssuer, oidcClientID, oidcClientSecret, oidcRedirectURL, tokenGetter) + if err != nil { + return "", "", err + } + return tok.Subject, tok.RawString, nil +} + +// idToken allows users to either pass in an identity token directly +// or a path to an identity token via the --identity-token flag +func idToken(s string) (string, error) { + // If this is a valid raw token or is empty, just return it + if _, err := jwt.ParseSigned(s, []jose.SignatureAlgorithm{"RS256"}); err == nil || s == "" { + return s, nil + } + + // Otherwise, if this is a path to a token return the contents + c, err := os.ReadFile(s) + return string(c), err +} diff --git a/internal/auth/auth_test.go b/internal/auth/auth_test.go new file mode 100644 index 00000000000..8b1d32fbb38 --- /dev/null +++ b/internal/auth/auth_test.go @@ -0,0 +1,208 @@ +// Copyright 2025 The Sigstore 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 auth + +import ( + "context" + "errors" + "os" + "path/filepath" + "testing" + + "github.com/sigstore/cosign/v3/pkg/providers" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +var ( + // Generated from https://justtrustme.dev/token?sub=test-subject + dummyJWT = "eyJhbGciOiJSUzI1NiIsImtpZCI6ImFhOWE1YjA5LTExMzktNGU2YS1hNjMxLTA2ZTU3NDU4NzI0MSJ9.eyJleHAiOjE3NTM4MzY1NTIsImlhdCI6MTc1MzgzNDc1MiwiaXNzIjoiaHR0cHM6Ly9qdXN0dHJ1c3RtZS5kZXYiLCJzdWIiOiJ0ZXN0LXN1YmplY3QifQ.WWNGLWQsSDcz0cFlGbMfmLkGaMpiAsVfik2vAj_YPIXNG6jgkMmIF69TbrwH-qlSfKNNI1GTktxlufsQwOUiseVdqV7fOCdvPhQsozHye8JT-AgZ9wcH3DGcdp-5R5KOKlFNXHFcBjI9lS0KIelWoJLj8YzisOi0hWRdAwpJwuselV-d7IlcLZhJiZO3n-d15YB4fRMpjTr_aj--hdec7ywzmCQqKL3XdAjAmR99JExMKs_w25-6K7akjVSE1lljf8Wf9CBfOlwvWKxXPvIwzE0DC2yWS103yWfGHEf3UbKPlF34Xqo6beHTnf9uiO0HdWTaQp2e0eShsQDX9hpIeg" +) + +func Test_idToken(t *testing.T) { + td := t.TempDir() + tokenFile := filepath.Join(td, "token.jwt") + err := os.WriteFile(tokenFile, []byte(dummyJWT), 0600) + require.NoError(t, err) + + nonExistentFile := filepath.Join(td, "nonexistent") + + tests := []struct { + name string + s string + want string + wantErr bool + }{ + { + name: "empty string", + s: "", + want: "", + }, + { + name: "valid jwt", + s: dummyJWT, + want: dummyJWT, + }, + { + name: "not a jwt or file", + s: "not-a-jwt", + wantErr: true, + }, + { + name: "file path", + s: tokenFile, + want: dummyJWT, + }, + { + name: "non-existent file", + s: nonExistentFile, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := idToken(tt.s) + if (err != nil) != tt.wantErr { + t.Errorf("idToken() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("idToken() = %v, want %v", got, tt.want) + } + }) + } +} + +type mockProvider struct { + token string + err error +} + +func (m *mockProvider) Enabled(_ context.Context) bool { + return true +} + +func (m *mockProvider) Provide(_ context.Context, _ string) (string, error) { + return m.token, m.err +} + +func TestReadIDToken(t *testing.T) { + ctx := context.Background() + td := t.TempDir() + tokenFile := filepath.Join(td, "token.jwt") + err := os.WriteFile(tokenFile, []byte(dummyJWT), 0600) + require.NoError(t, err) + + providers.Register("mock-success", &mockProvider{token: "mock-token"}) + providers.Register("mock-fail", &mockProvider{err: errors.New("mock error")}) + + tests := []struct { + name string + tokOrPath string + disableProviders bool + oidcProvider string + want string + wantErr bool + }{ + { + name: "raw token", + tokOrPath: dummyJWT, + want: dummyJWT, + }, + { + name: "token from file", + tokOrPath: tokenFile, + want: dummyJWT, + }, + { + name: "no token, providers disabled", + tokOrPath: "", + disableProviders: true, + want: "", + }, + { + name: "no token, specific provider success", + tokOrPath: "", + oidcProvider: "mock-success", + want: "mock-token", + }, + { + name: "no token, specific provider fail", + tokOrPath: "", + oidcProvider: "mock-fail", + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := ReadIDToken(ctx, tt.tokOrPath, tt.disableProviders, tt.oidcProvider) + if (err != nil) != tt.wantErr { + t.Errorf("ReadIDToken() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("ReadIDToken() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestGetOAuthFlow(t *testing.T) { + tests := []struct { + name string + authFlow string + idToken string + want string + }{ + { + name: "auth flow set explicitly", + authFlow: "client_credentials", + want: "client_credentials", + }, + { + name: "id token set", + idToken: dummyJWT, + want: "token", + }, + // Other flows can't be easily tested due to lack of interactivity + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := GetOAuthFlow(context.Background(), tt.authFlow, tt.idToken, false) + + if err != nil { + t.Errorf("GetOAuthFlow() error = %v", err) + } + if got != tt.want { + t.Errorf("GetOAuthFlow() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestAuthenticateCaller(t *testing.T) { + t.Run("token flow", func(t *testing.T) { + subject, token, err := AuthenticateCaller("token", dummyJWT, "", "", "", "") + require.NoError(t, err) + assert.Equal(t, "test-subject", subject) + assert.Equal(t, dummyJWT, token) + }) + + t.Run("unsupported flow", func(t *testing.T) { + _, _, err := AuthenticateCaller("bad-flow", "", "", "", "", "") + require.Error(t, err) + assert.Contains(t, err.Error(), "unsupported oauth flow") + }) +} diff --git a/internal/key/svkeypair.go b/internal/key/svkeypair.go new file mode 100644 index 00000000000..eee7d2eacc1 --- /dev/null +++ b/internal/key/svkeypair.go @@ -0,0 +1,137 @@ +// Copyright 2025 The Sigstore 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 key + +import ( + "bytes" + "context" + "crypto" + "crypto/ecdsa" + "crypto/ed25519" + "crypto/rsa" + "crypto/sha256" + "crypto/x509" + "encoding/base64" + "errors" + "fmt" + + "github.com/sigstore/cosign/v3/pkg/cosign" + protocommon "github.com/sigstore/protobuf-specs/gen/pb-go/common/v1" + "github.com/sigstore/sigstore/pkg/cryptoutils" + "github.com/sigstore/sigstore/pkg/signature" + signatureoptions "github.com/sigstore/sigstore/pkg/signature/options" +) + +// SignerVerifierKeypair is a wrapper around a SignerVerifier that implements +// sigstore-go's Keypair interface. +type SignerVerifierKeypair struct { + sv signature.SignerVerifier + hint []byte + keyAlg string + sigAlg signature.AlgorithmDetails +} + +// NewSignerVerifierKeypair creates a new SignerVerifierKeypair from a SignerVerifier. +func NewSignerVerifierKeypair(sv signature.SignerVerifier, defaultLoadOptions *[]signature.LoadOption) (*SignerVerifierKeypair, error) { + pubKey, err := sv.PublicKey() + if err != nil { + return nil, fmt.Errorf("getting public key: %w", err) + } + pubKeyBytes, err := x509.MarshalPKIXPublicKey(pubKey) + if err != nil { + return nil, fmt.Errorf("marshalling public key: %w", err) + } + hashedBytes := sha256.Sum256(pubKeyBytes) + hint := []byte(base64.StdEncoding.EncodeToString(hashedBytes[:])) + + var keyAlg string + switch pubKey.(type) { + case *ecdsa.PublicKey: + keyAlg = "ECDSA" + case *rsa.PublicKey: + keyAlg = "RSA" + case ed25519.PublicKey: + keyAlg = "ED25519" + default: + return nil, errors.New("unsupported key type") + } + + algo, err := signature.GetDefaultAlgorithmDetails(pubKey, *cosign.GetDefaultLoadOptions(defaultLoadOptions)...) + if err != nil { + return nil, fmt.Errorf("getting default algorithm details: %w", err) + } + + return &SignerVerifierKeypair{ + sv: sv, + hint: hint, + keyAlg: keyAlg, + sigAlg: algo, + }, nil +} + +// GetHashAlgorithm returns the hash algorithm to generate the digest to be signed. +func (k *SignerVerifierKeypair) GetHashAlgorithm() protocommon.HashAlgorithm { + return k.sigAlg.GetProtoHashType() +} + +func (k *SignerVerifierKeypair) GetSigningAlgorithm() protocommon.PublicKeyDetails { + return k.sigAlg.GetSignatureAlgorithm() +} + +// GetHint returns a hint for the public key. +func (k *SignerVerifierKeypair) GetHint() []byte { + return k.hint +} + +// GetKeyAlgorithm returns the key algorithm, to be used in requests to Fulcio. +func (k *SignerVerifierKeypair) GetKeyAlgorithm() string { + return k.keyAlg +} + +// GetPublicKey returns the public key. +func (k *SignerVerifierKeypair) GetPublicKey() crypto.PublicKey { + pubKey, err := k.sv.PublicKey() + if err != nil { + // The interface does not allow returning an error + return nil + } + return pubKey +} + +// GetPublicKeyPem returns the public key in PEM format. +func (k *SignerVerifierKeypair) GetPublicKeyPem() (string, error) { + pubKey, err := k.sv.PublicKey() + if err != nil { + return "", err + } + pemBytes, err := cryptoutils.MarshalPublicKeyToPEM(pubKey) + if err != nil { + return "", err + } + return string(pemBytes), nil +} + +// SignData signs the given data with the SignerVerifier. +func (k *SignerVerifierKeypair) SignData(ctx context.Context, data []byte) ([]byte, []byte, error) { + h := k.sigAlg.GetHashType().New() + h.Write(data) + digest := h.Sum(nil) + sOpts := []signature.SignOption{signatureoptions.WithContext(ctx), signatureoptions.WithDigest(digest)} + sig, err := k.sv.SignMessage(bytes.NewReader(data), sOpts...) + if err != nil { + return nil, nil, err + } + return sig, digest, nil +} diff --git a/internal/key/svkeypair_test.go b/internal/key/svkeypair_test.go new file mode 100644 index 00000000000..15422b70dfa --- /dev/null +++ b/internal/key/svkeypair_test.go @@ -0,0 +1,242 @@ +// Copyright 2025 The Sigstore 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 key + +import ( + "bytes" + "context" + "crypto" + "crypto/ecdsa" + "crypto/ed25519" + "crypto/elliptic" + "crypto/rand" + "crypto/rsa" + "crypto/sha256" + "crypto/x509" + "encoding/base64" + "errors" + "io" + "strings" + "testing" + + protocommon "github.com/sigstore/protobuf-specs/gen/pb-go/common/v1" + "github.com/sigstore/sigstore/pkg/cryptoutils" + "github.com/sigstore/sigstore/pkg/signature" +) + +// mockSignerVerifier is a mock implementation of signature.SignerVerifier for testing. +type mockSignerVerifier struct { + pubKey crypto.PublicKey + pubKeyErr error + signErr error +} + +func (m *mockSignerVerifier) PublicKey(_ ...signature.PublicKeyOption) (crypto.PublicKey, error) { + if m.pubKeyErr != nil { + return nil, m.pubKeyErr + } + return m.pubKey, nil +} + +func (m *mockSignerVerifier) SignMessage(_ io.Reader, _ ...signature.SignOption) ([]byte, error) { + if m.signErr != nil { + return nil, m.signErr + } + return []byte("mock-signature"), nil +} + +func (m *mockSignerVerifier) VerifySignature(_, _ io.Reader, _ ...signature.VerifyOption) error { + return errors.New("not implemented") +} + +func TestNewKMSKeypair(t *testing.T) { + ecdsaPriv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + t.Fatalf("failed to generate ecdsa key: %v", err) + } + rsaPriv, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + t.Fatalf("failed to generate rsa key: %v", err) + } + _, ed25519Priv, err := ed25519.GenerateKey(rand.Reader) + if err != nil { + t.Fatalf("failed to generate ed25519 key: %v", err) + } + + testCases := []struct { + name string + sv signature.SignerVerifier + expectErr bool + errMsg string + }{ + { + name: "ECDSA key", + sv: &mockSignerVerifier{ + pubKey: &ecdsaPriv.PublicKey, + }, + expectErr: false, + }, + { + name: "RSA key", + sv: &mockSignerVerifier{ + pubKey: &rsaPriv.PublicKey, + }, + expectErr: false, + }, + { + name: "ED25519 key", + sv: &mockSignerVerifier{ + pubKey: ed25519Priv.Public(), + }, + expectErr: false, + }, + { + name: "Unsupported key type", + sv: &mockSignerVerifier{ + pubKey: "not a key", + }, + expectErr: true, + errMsg: "unsupported public key type", + }, + { + name: "PublicKey returns error", + sv: &mockSignerVerifier{ + pubKeyErr: errors.New("pubkey error"), + }, + expectErr: true, + errMsg: "getting public key: pubkey error", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + kp, err := NewSignerVerifierKeypair(tc.sv, nil) + if tc.expectErr { + if err == nil { + t.Errorf("expected an error, but got none") + } else if !strings.Contains(err.Error(), tc.errMsg) { + t.Errorf("expected error message '%s', got '%s'", tc.errMsg, err.Error()) + } + } else { + if err != nil { + t.Errorf("unexpected error: %v", err) + } + if kp == nil { + t.Error("expected a keypair, but got nil") + } + } + }) + } +} + +func TestKMSKeypair_Methods(t *testing.T) { + ecdsaPriv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + t.Fatalf("failed to generate ecdsa key: %v", err) + } + sv := &mockSignerVerifier{pubKey: &ecdsaPriv.PublicKey} + kp, err := NewSignerVerifierKeypair(sv, nil) + if err != nil { + t.Fatalf("failed to create KMSKeypair: %v", err) + } + + t.Run("GetHashAlgorithm", func(t *testing.T) { + if kp.GetHashAlgorithm() != protocommon.HashAlgorithm_SHA2_256 { + t.Errorf("expected SHA2_256, got %v", kp.GetHashAlgorithm()) + } + }) + + t.Run("GetSigningAlgorithm", func(t *testing.T) { + if kp.GetSigningAlgorithm() != protocommon.PublicKeyDetails_PKIX_ECDSA_P256_SHA_256 { + t.Errorf("expected ECDSA_P256_SHA256, got %v", kp.GetSigningAlgorithm()) + } + }) + + t.Run("GetHint", func(t *testing.T) { + pubKeyBytes, err := x509.MarshalPKIXPublicKey(&ecdsaPriv.PublicKey) + if err != nil { + t.Fatalf("marshalling public key: %v", err) + } + hashedBytes := sha256.Sum256(pubKeyBytes) + expectedHint := base64.StdEncoding.EncodeToString(hashedBytes[:]) + + if string(kp.GetHint()) != expectedHint { + t.Errorf("expected hint %s, got %s", expectedHint, string(kp.GetHint())) + } + }) + + t.Run("GetKeyAlgorithm", func(t *testing.T) { + if kp.GetKeyAlgorithm() != "ECDSA" { + t.Errorf("expected ECDSA, got %s", kp.GetKeyAlgorithm()) + } + }) + + t.Run("GetPublicKey", func(t *testing.T) { + pub := kp.GetPublicKey() + if !pub.(*ecdsa.PublicKey).Equal(&ecdsaPriv.PublicKey) { + t.Error("public keys do not match") + } + }) + + t.Run("GetPublicKeyPem", func(t *testing.T) { + pem, err := kp.GetPublicKeyPem() + if err != nil { + t.Fatalf("GetPublicKeyPem returned an error: %v", err) + } + pub, err := cryptoutils.UnmarshalPEMToPublicKey([]byte(pem)) + if err != nil { + t.Fatalf("failed to unmarshal pem: %v", err) + } + if !pub.(*ecdsa.PublicKey).Equal(&ecdsaPriv.PublicKey) { + t.Error("public keys do not match") + } + }) + + t.Run("SignData", func(t *testing.T) { + data := []byte("some data to sign") + sig, digest, err := kp.SignData(context.Background(), data) + if err != nil { + t.Fatalf("SignData returned an error: %v", err) + } + if string(sig) != "mock-signature" { + t.Errorf("expected signature 'mock-signature', got '%s'", string(sig)) + } + + h := sha256.New() + h.Write(data) + expectedDigest := h.Sum(nil) + if !bytes.Equal(digest, expectedDigest) { + t.Errorf("expected digest %x, got %x", expectedDigest, digest) + } + }) + + t.Run("SignData with error", func(t *testing.T) { + errSV := &mockSignerVerifier{ + pubKey: &ecdsaPriv.PublicKey, + signErr: errors.New("signing failed"), + } + errKP, err := NewSignerVerifierKeypair(errSV, nil) + if err != nil { + t.Fatalf("failed to create KMSKeypair: %v", err) + } + + _, _, err = errKP.SignData(context.Background(), []byte("data")) + if err == nil { + t.Error("expected an error, but got none") + } else if err.Error() != "signing failed" { + t.Errorf("expected error 'signing failed', got '%s'", err.Error()) + } + }) +} diff --git a/internal/pkg/cosign/common.go b/internal/pkg/cosign/common.go index a1aa8ebc35f..44027402e24 100644 --- a/internal/pkg/cosign/common.go +++ b/internal/pkg/cosign/common.go @@ -15,6 +15,7 @@ package cosign import ( + "crypto" "errors" "hash" "io" @@ -39,14 +40,17 @@ func FileExists(filename string) (bool, error) { // HashReader hashes while it reads. type HashReader struct { - r io.Reader - h hash.Hash + r io.Reader + h hash.Hash + ch crypto.Hash } -func NewHashReader(r io.Reader, h hash.Hash) HashReader { +func NewHashReader(r io.Reader, ch crypto.Hash) HashReader { + h := ch.New() return HashReader{ - r: io.TeeReader(r, h), - h: h, + r: io.TeeReader(r, h), + h: h, + ch: ch, } } @@ -67,3 +71,6 @@ func (h *HashReader) BlockSize() int { return h.h.BlockSize() } // Write implements hash.Hash func (h *HashReader) Write(p []byte) (int, error) { return 0, errors.New("not implemented") } //nolint: revive + +// HashFunc implements cosign.NamedHash +func (h *HashReader) HashFunc() crypto.Hash { return h.ch } diff --git a/internal/pkg/cosign/common_test.go b/internal/pkg/cosign/common_test.go index 4a54109e435..4f38e07865c 100644 --- a/internal/pkg/cosign/common_test.go +++ b/internal/pkg/cosign/common_test.go @@ -17,6 +17,7 @@ package cosign import ( "bytes" + "crypto" "crypto/sha256" "io" "os" @@ -55,7 +56,7 @@ func Test_FileExists(t *testing.T) { func Test_HashReader(t *testing.T) { input := []byte("hello world") - r := NewHashReader(bytes.NewReader(input), sha256.New()) + r := NewHashReader(bytes.NewReader(input), crypto.SHA256) got, err := io.ReadAll(&r) if err != nil { diff --git a/internal/pkg/cosign/dsse.go b/internal/pkg/cosign/dsse.go index 690e534508a..d33730fbf8b 100644 --- a/internal/pkg/cosign/dsse.go +++ b/internal/pkg/cosign/dsse.go @@ -19,7 +19,7 @@ import ( "crypto" "io" - "github.com/sigstore/cosign/v2/pkg/oci" + "github.com/sigstore/cosign/v3/pkg/oci" ) // DSSEAttestor creates attestations in the form of `oci.Signature`s diff --git a/internal/pkg/cosign/ephemeral/signer.go b/internal/pkg/cosign/ephemeral/signer.go index 801dcabcd02..9e304a7bc24 100644 --- a/internal/pkg/cosign/ephemeral/signer.go +++ b/internal/pkg/cosign/ephemeral/signer.go @@ -22,10 +22,10 @@ import ( "fmt" "io" - icosign "github.com/sigstore/cosign/v2/internal/pkg/cosign" - "github.com/sigstore/cosign/v2/pkg/cosign" - "github.com/sigstore/cosign/v2/pkg/oci" - "github.com/sigstore/cosign/v2/pkg/oci/static" + icosign "github.com/sigstore/cosign/v3/internal/pkg/cosign" + "github.com/sigstore/cosign/v3/pkg/cosign" + "github.com/sigstore/cosign/v3/pkg/oci" + "github.com/sigstore/cosign/v3/pkg/oci/static" "github.com/sigstore/sigstore/pkg/signature" ) diff --git a/internal/pkg/cosign/fulcio/fulcioroots/fulcioroots.go b/internal/pkg/cosign/fulcio/fulcioroots/fulcioroots.go index 3b44da88420..c68af1994b3 100644 --- a/internal/pkg/cosign/fulcio/fulcioroots/fulcioroots.go +++ b/internal/pkg/cosign/fulcio/fulcioroots/fulcioroots.go @@ -22,7 +22,7 @@ import ( "os" "sync" - "github.com/sigstore/cosign/v2/pkg/cosign/env" + "github.com/sigstore/cosign/v3/pkg/cosign/env" "github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/sigstore/sigstore/pkg/fulcioroots" ) diff --git a/internal/pkg/cosign/fulcio/fulcioroots/fulcioroots_test.go b/internal/pkg/cosign/fulcio/fulcioroots/fulcioroots_test.go index 7d7ad46254e..4c7095b60f4 100644 --- a/internal/pkg/cosign/fulcio/fulcioroots/fulcioroots_test.go +++ b/internal/pkg/cosign/fulcio/fulcioroots/fulcioroots_test.go @@ -19,7 +19,7 @@ import ( "sync" "testing" - "github.com/sigstore/cosign/v2/test" + "github.com/sigstore/cosign/v3/internal/test" "github.com/sigstore/sigstore/pkg/cryptoutils" ) diff --git a/internal/pkg/cosign/fulcio/signer.go b/internal/pkg/cosign/fulcio/signer.go index fb805425f04..371c85bfae3 100644 --- a/internal/pkg/cosign/fulcio/signer.go +++ b/internal/pkg/cosign/fulcio/signer.go @@ -19,9 +19,9 @@ import ( "crypto" "io" - "github.com/sigstore/cosign/v2/internal/pkg/cosign" - "github.com/sigstore/cosign/v2/pkg/oci" - "github.com/sigstore/cosign/v2/pkg/oci/mutate" + "github.com/sigstore/cosign/v3/internal/pkg/cosign" + "github.com/sigstore/cosign/v3/pkg/oci" + "github.com/sigstore/cosign/v3/pkg/oci/mutate" ) // signerWrapper still needs to actually upload keys to Fulcio and receive diff --git a/internal/pkg/cosign/fulcio/signer_test.go b/internal/pkg/cosign/fulcio/signer_test.go index 5bac26fb87b..9119ae07e38 100644 --- a/internal/pkg/cosign/fulcio/signer_test.go +++ b/internal/pkg/cosign/fulcio/signer_test.go @@ -21,8 +21,8 @@ import ( "strings" "testing" - "github.com/sigstore/cosign/v2/internal/pkg/cosign/payload" - "github.com/sigstore/cosign/v2/pkg/cosign" + "github.com/sigstore/cosign/v3/internal/pkg/cosign/payload" + "github.com/sigstore/cosign/v3/pkg/cosign" "github.com/sigstore/sigstore/pkg/signature" ) diff --git a/internal/pkg/cosign/payload/attestor.go b/internal/pkg/cosign/payload/attestor.go index d7bbb16c0a6..5c407124f97 100644 --- a/internal/pkg/cosign/payload/attestor.go +++ b/internal/pkg/cosign/payload/attestor.go @@ -22,10 +22,10 @@ import ( "io" "github.com/secure-systems-lab/go-securesystemslib/dsse" - "github.com/sigstore/cosign/v2/internal/pkg/cosign" - "github.com/sigstore/cosign/v2/pkg/oci" - "github.com/sigstore/cosign/v2/pkg/oci/static" - "github.com/sigstore/cosign/v2/pkg/types" + "github.com/sigstore/cosign/v3/internal/pkg/cosign" + "github.com/sigstore/cosign/v3/pkg/oci" + "github.com/sigstore/cosign/v3/pkg/oci/static" + "github.com/sigstore/cosign/v3/pkg/types" "github.com/sigstore/sigstore/pkg/signature" ) diff --git a/internal/pkg/cosign/payload/attestor_test.go b/internal/pkg/cosign/payload/attestor_test.go index 23cf90d2f9a..3e80c364829 100644 --- a/internal/pkg/cosign/payload/attestor_test.go +++ b/internal/pkg/cosign/payload/attestor_test.go @@ -24,7 +24,7 @@ import ( "testing" "github.com/secure-systems-lab/go-securesystemslib/dsse" - "github.com/sigstore/cosign/v2/pkg/types" + "github.com/sigstore/cosign/v3/pkg/types" "github.com/sigstore/sigstore/pkg/signature" ) diff --git a/internal/pkg/cosign/payload/signer.go b/internal/pkg/cosign/payload/signer.go index 6cefbe3a656..c9b1ff9e5d0 100644 --- a/internal/pkg/cosign/payload/signer.go +++ b/internal/pkg/cosign/payload/signer.go @@ -22,9 +22,9 @@ import ( "fmt" "io" - "github.com/sigstore/cosign/v2/internal/pkg/cosign" - "github.com/sigstore/cosign/v2/pkg/oci" - "github.com/sigstore/cosign/v2/pkg/oci/static" + "github.com/sigstore/cosign/v3/internal/pkg/cosign" + "github.com/sigstore/cosign/v3/pkg/oci" + "github.com/sigstore/cosign/v3/pkg/oci/static" "github.com/sigstore/sigstore/pkg/signature" signatureoptions "github.com/sigstore/sigstore/pkg/signature/options" ) diff --git a/internal/pkg/cosign/payload/signer_test.go b/internal/pkg/cosign/payload/signer_test.go index d2ccf7dcb24..9f3bb55ce71 100644 --- a/internal/pkg/cosign/payload/signer_test.go +++ b/internal/pkg/cosign/payload/signer_test.go @@ -21,7 +21,7 @@ import ( "strings" "testing" - "github.com/sigstore/cosign/v2/pkg/cosign" + "github.com/sigstore/cosign/v3/pkg/cosign" "github.com/sigstore/sigstore/pkg/signature" ) diff --git a/internal/pkg/cosign/payload/size/size.go b/internal/pkg/cosign/payload/size/size.go index f867477c732..aac4dca2c5b 100644 --- a/internal/pkg/cosign/payload/size/size.go +++ b/internal/pkg/cosign/payload/size/size.go @@ -16,7 +16,7 @@ package payload import ( "github.com/dustin/go-humanize" - "github.com/sigstore/cosign/v2/pkg/cosign/env" + "github.com/sigstore/cosign/v3/pkg/cosign/env" ) const defaultMaxSize = uint64(134217728) // 128MiB diff --git a/internal/pkg/cosign/rekor/signer.go b/internal/pkg/cosign/rekor/signer.go index 2fa5e2595ef..a32c3afbd59 100644 --- a/internal/pkg/cosign/rekor/signer.go +++ b/internal/pkg/cosign/rekor/signer.go @@ -23,11 +23,11 @@ import ( "io" "os" - "github.com/sigstore/cosign/v2/internal/pkg/cosign" - cosignv1 "github.com/sigstore/cosign/v2/pkg/cosign" - cbundle "github.com/sigstore/cosign/v2/pkg/cosign/bundle" - "github.com/sigstore/cosign/v2/pkg/oci" - "github.com/sigstore/cosign/v2/pkg/oci/mutate" + "github.com/sigstore/cosign/v3/internal/pkg/cosign" + cosignv1 "github.com/sigstore/cosign/v3/pkg/cosign" + cbundle "github.com/sigstore/cosign/v3/pkg/cosign/bundle" + "github.com/sigstore/cosign/v3/pkg/oci" + "github.com/sigstore/cosign/v3/pkg/oci/mutate" "github.com/sigstore/rekor/pkg/generated/client" "github.com/sigstore/rekor/pkg/generated/models" diff --git a/internal/pkg/cosign/rekor/signer_test.go b/internal/pkg/cosign/rekor/signer_test.go index 5f3dfa02351..b524f121731 100644 --- a/internal/pkg/cosign/rekor/signer_test.go +++ b/internal/pkg/cosign/rekor/signer_test.go @@ -21,10 +21,10 @@ import ( "strings" "testing" - "github.com/go-openapi/swag" - "github.com/sigstore/cosign/v2/internal/pkg/cosign/payload" - "github.com/sigstore/cosign/v2/internal/pkg/cosign/rekor/mock" - "github.com/sigstore/cosign/v2/pkg/cosign" + "github.com/go-openapi/swag/conv" + "github.com/sigstore/cosign/v3/internal/pkg/cosign/payload" + "github.com/sigstore/cosign/v3/internal/pkg/cosign/rekor/mock" + "github.com/sigstore/cosign/v3/pkg/cosign" "github.com/sigstore/rekor/pkg/generated/client" "github.com/sigstore/rekor/pkg/generated/models" "github.com/sigstore/sigstore/pkg/signature" @@ -52,7 +52,7 @@ func TestSigner(t *testing.T) { mClient.Entries = &mock.EntriesClient{ Entries: []*models.LogEntry{{"123": models.LogEntryAnon{ - LogIndex: swag.Int64(123), + LogIndex: conv.Pointer(int64(123)), }}}, } diff --git a/internal/pkg/cosign/sign.go b/internal/pkg/cosign/sign.go index b2f746daee4..93873c101be 100644 --- a/internal/pkg/cosign/sign.go +++ b/internal/pkg/cosign/sign.go @@ -19,7 +19,7 @@ import ( "crypto" "io" - "github.com/sigstore/cosign/v2/pkg/oci" + "github.com/sigstore/cosign/v3/pkg/oci" ) // Signer signs payloads in the form of `oci.Signature`s diff --git a/internal/pkg/cosign/tsa/mock/mock_tsa_client.go b/internal/pkg/cosign/tsa/mock/mock_tsa_client.go index f85b5f0a8b6..44412769206 100644 --- a/internal/pkg/cosign/tsa/mock/mock_tsa_client.go +++ b/internal/pkg/cosign/tsa/mock/mock_tsa_client.go @@ -24,10 +24,10 @@ import ( "time" "github.com/digitorus/timestamp" - "github.com/sigstore/cosign/v2/internal/pkg/cosign/tsa/client" + "github.com/sigstore/cosign/v3/internal/pkg/cosign/tsa/client" "github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/sigstore/sigstore/pkg/signature" - "github.com/sigstore/timestamp-authority/pkg/signer" + "github.com/sigstore/timestamp-authority/v2/pkg/signer" ) // TSAClient creates RFC3161 timestamps and implements client.TimestampAuthority. diff --git a/internal/pkg/cosign/tsa/signer.go b/internal/pkg/cosign/tsa/signer.go index 9fb0b66b407..721117a7d58 100644 --- a/internal/pkg/cosign/tsa/signer.go +++ b/internal/pkg/cosign/tsa/signer.go @@ -24,11 +24,11 @@ import ( "strings" "github.com/digitorus/timestamp" - "github.com/sigstore/cosign/v2/internal/pkg/cosign" - "github.com/sigstore/cosign/v2/internal/pkg/cosign/tsa/client" - "github.com/sigstore/cosign/v2/pkg/cosign/bundle" - "github.com/sigstore/cosign/v2/pkg/oci" - "github.com/sigstore/cosign/v2/pkg/oci/mutate" + "github.com/sigstore/cosign/v3/internal/pkg/cosign" + "github.com/sigstore/cosign/v3/internal/pkg/cosign/tsa/client" + "github.com/sigstore/cosign/v3/pkg/cosign/bundle" + "github.com/sigstore/cosign/v3/pkg/oci" + "github.com/sigstore/cosign/v3/pkg/oci/mutate" "github.com/sigstore/sigstore/pkg/cryptoutils" ) diff --git a/internal/pkg/cosign/tsa/signer_test.go b/internal/pkg/cosign/tsa/signer_test.go index 4cb136b5de6..c06de523569 100644 --- a/internal/pkg/cosign/tsa/signer_test.go +++ b/internal/pkg/cosign/tsa/signer_test.go @@ -22,9 +22,9 @@ import ( "testing" "time" - "github.com/sigstore/cosign/v2/internal/pkg/cosign/payload" - "github.com/sigstore/cosign/v2/internal/pkg/cosign/tsa/mock" - "github.com/sigstore/cosign/v2/pkg/cosign" + "github.com/sigstore/cosign/v3/internal/pkg/cosign/payload" + "github.com/sigstore/cosign/v3/internal/pkg/cosign/tsa/mock" + "github.com/sigstore/cosign/v3/pkg/cosign" "github.com/sigstore/sigstore/pkg/signature" ) diff --git a/internal/pkg/cosign/tsa/utils_test.go b/internal/pkg/cosign/tsa/utils_test.go index ba294ffe8f0..a0769ab9aaa 100644 --- a/internal/pkg/cosign/tsa/utils_test.go +++ b/internal/pkg/cosign/tsa/utils_test.go @@ -19,7 +19,7 @@ import ( "reflect" "testing" - "github.com/sigstore/cosign/v2/test" + "github.com/sigstore/cosign/v3/internal/test" "github.com/sigstore/sigstore/pkg/cryptoutils" ) diff --git a/test/cert_utils.go b/internal/test/cert_utils.go similarity index 100% rename from test/cert_utils.go rename to internal/test/cert_utils.go diff --git a/internal/ui/log_test.go b/internal/ui/log_test.go index b1172367f02..01b96aad044 100644 --- a/internal/ui/log_test.go +++ b/internal/ui/log_test.go @@ -17,7 +17,7 @@ import ( "context" "testing" - "github.com/sigstore/cosign/v2/internal/ui" + "github.com/sigstore/cosign/v3/internal/ui" "github.com/stretchr/testify/assert" ) diff --git a/internal/ui/prompt_test.go b/internal/ui/prompt_test.go index 26c97ca49d1..3910d9b8bdf 100644 --- a/internal/ui/prompt_test.go +++ b/internal/ui/prompt_test.go @@ -19,7 +19,7 @@ import ( "errors" "testing" - "github.com/sigstore/cosign/v2/internal/ui" + "github.com/sigstore/cosign/v3/internal/ui" "github.com/stretchr/testify/assert" ) diff --git a/internal/ui/spinner.go b/internal/ui/spinner.go new file mode 100644 index 00000000000..f0598bfbf08 --- /dev/null +++ b/internal/ui/spinner.go @@ -0,0 +1,66 @@ +// Copyright 2025 The Sigstore 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 ui + +import ( + "context" + "fmt" + "os" + "strings" + "time" + + "github.com/moby/term" +) + +// Spinner shows progress for long-running operations in the terminal +type Spinner struct { + done chan struct{} +} + +// NewSpinner starts a spinner in a goroutine and returns it. +func NewSpinner(ctx context.Context, message string) *Spinner { + s := &Spinner{ + done: make(chan struct{}), + } + + go func() { + // Don't show spinner if not in a terminal + fd := os.Stderr.Fd() + if !term.IsTerminal(fd) { + Infof(ctx, "%s", message) + return + } + + ticker := time.NewTicker(100 * time.Millisecond) + defer ticker.Stop() + spinnerChars := []rune{'|', '/', '-', '\\'} + i := 0 + for { + select { + case <-ticker.C: + i++ + fmt.Fprintf(os.Stderr, "\r%s %c ", message, spinnerChars[i%len(spinnerChars)]) + case <-s.done: + fmt.Fprintf(os.Stderr, "\r%s\r", strings.Repeat(" ", len(message)+3)) + return + } + } + }() + return s +} + +func (s *Spinner) Stop() { + close(s.done) +} diff --git a/pkg/cosign/bundle/protobundle.go b/pkg/cosign/bundle/protobundle.go index a26e2fb2bb7..5291249f426 100644 --- a/pkg/cosign/bundle/protobundle.go +++ b/pkg/cosign/bundle/protobundle.go @@ -15,17 +15,28 @@ package bundle import ( + "crypto" + "crypto/sha256" + "crypto/x509" + "encoding/base64" + "encoding/json" + "fmt" + + "github.com/secure-systems-lab/go-securesystemslib/dsse" protobundle "github.com/sigstore/protobuf-specs/gen/pb-go/bundle/v1" protocommon "github.com/sigstore/protobuf-specs/gen/pb-go/common/v1" + protodsse "github.com/sigstore/protobuf-specs/gen/pb-go/dsse" protorekor "github.com/sigstore/protobuf-specs/gen/pb-go/rekor/v1" "github.com/sigstore/rekor/pkg/generated/models" "github.com/sigstore/rekor/pkg/tle" + "github.com/sigstore/sigstore/pkg/cryptoutils" + "google.golang.org/protobuf/encoding/protojson" ) -const bundleV03MediaType = "application/vnd.dev.sigstore.bundle.v0.3+json" +const BundleV03MediaType = "application/vnd.dev.sigstore.bundle.v0.3+json" func MakeProtobufBundle(hint string, rawCert []byte, rekorEntry *models.LogEntryAnon, timestampBytes []byte) (*protobundle.Bundle, error) { - bundle := &protobundle.Bundle{MediaType: bundleV03MediaType} + bundle := &protobundle.Bundle{MediaType: BundleV03MediaType} if hint != "" { bundle.VerificationMaterial = &protobundle.VerificationMaterial{ @@ -63,3 +74,60 @@ func MakeProtobufBundle(hint string, rawCert []byte, rekorEntry *models.LogEntry return bundle, nil } + +func MakeNewBundle(pubKey crypto.PublicKey, rekorEntry *models.LogEntryAnon, payload, sig, signer, timestampBytes []byte) ([]byte, error) { + // Determine if the signer is a certificate or not + var hint string + var rawCert []byte + + cert, err := cryptoutils.UnmarshalCertificatesFromPEM(signer) + if err != nil || len(cert) == 0 { + pkixPubKey, err := x509.MarshalPKIXPublicKey(pubKey) + if err != nil { + return nil, err + } + hashedBytes := sha256.Sum256(pkixPubKey) + hint = base64.StdEncoding.EncodeToString(hashedBytes[:]) + } else { + rawCert = cert[0].Raw + } + + bundle, err := MakeProtobufBundle(hint, rawCert, rekorEntry, timestampBytes) + if err != nil { + return nil, err + } + + var envelope dsse.Envelope + err = json.Unmarshal(sig, &envelope) + if err != nil { + return nil, err + } + + if len(envelope.Signatures) == 0 { + return nil, fmt.Errorf("no signature in DSSE envelope") + } + + sigBytes, err := base64.StdEncoding.DecodeString(envelope.Signatures[0].Sig) + if err != nil { + return nil, err + } + + bundle.Content = &protobundle.Bundle_DsseEnvelope{ + DsseEnvelope: &protodsse.Envelope{ + Payload: payload, + PayloadType: envelope.PayloadType, + Signatures: []*protodsse.Signature{ + { + Sig: sigBytes, + }, + }, + }, + } + + contents, err := protojson.Marshal(bundle) + if err != nil { + return nil, err + } + + return contents, nil +} diff --git a/pkg/cosign/bundle/protobundle_test.go b/pkg/cosign/bundle/protobundle_test.go index dea1bce59bb..4de8851ea03 100644 --- a/pkg/cosign/bundle/protobundle_test.go +++ b/pkg/cosign/bundle/protobundle_test.go @@ -18,7 +18,7 @@ import ( "testing" "github.com/go-openapi/strfmt" - "github.com/go-openapi/swag" + "github.com/go-openapi/swag/conv" "github.com/sigstore/rekor/pkg/generated/models" _ "github.com/sigstore/rekor/pkg/types/hashedrekord" _ "github.com/sigstore/rekor/pkg/types/hashedrekord/v0.0.1" @@ -52,16 +52,16 @@ func TestMakeProtobufBundle(t *testing.T) { rawCert: []byte("cert stuff"), rekorEntry: &models.LogEntryAnon{ Body: "eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiI2MmQwOGYyOGM2OWNhZGE3YjQyYTQ1Nzk0YjQ3ZWU2YzgxYTdkZmE3MTY4NDZiMzljODhmMGFkMTljMjA2OTk3In19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FVUNJQm14U0N1TW1HSzhNQWRMd1FWZ21TZjVXKzlkdU5iQXN1cUNQNlNucUxCUkFpRUFvNGtGRVdDTG9HcTVUaysrUEhtTEgrb3N1emVTRjN4OTdBbmVicTRlbVRvPSIsInB1YmxpY0tleSI6eyJjb250ZW50IjoiTFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVUk1ha05EUVhKVFowRjNTVUpCWjBsVVRWQkRlVXdyYmxOb2MycHdaa2hZYUZkYVRVWkNUVUZIUlVSQlMwSm5aM0ZvYTJwUFVGRlJSRUY2UVhFS1RWSlZkMFYzV1VSV1VWRkxSWGQ0ZW1GWFpIcGtSemw1V2xNMWExcFlXWGhGVkVGUVFtZE9Wa0pCVFZSRFNFNXdXak5PTUdJelNteE5RalJZUkZSSmVRcE5SRWwzVFdwRmQwNUVXWGhOVm05WVJGUkplVTFFU1hkTmFrVjNUbFJaZUUxR2IzZEZla1ZTVFVFNFIwRXhWVVZEYUUxSll6SnNibU16VW5aamJWVjNDbGRVUVZSQ1oyTnhhR3RxVDFCUlNVSkNaMmR4YUd0cVQxQlJUVUpDZDA1RFFVRlVVMVJ2VEhWS2N5OTFSV05IU2tRME5VWmFiVE5wWmxKTU4yOXVRVWNLWlZaNWJuWkhVbmN6WnpKMU0wbFhTREZuU2tSamNERjRSWFI2UVZCUWJYQmhlVGRtTmxCNE1XeFpNa0ZyWnpsMGEyb3dRa1J2UTNkdk5FbENlbXBEUXdwQlkyOTNSR2RaUkZaU01GQkJVVWd2UWtGUlJFRm5aVUZOUWsxSFFURlZaRXBSVVUxTlFXOUhRME56UjBGUlZVWkNkMDFFVFVGM1IwRXhWV1JGZDBWQ0NpOTNVVU5OUVVGM1NGRlpSRlpTTUU5Q1FsbEZSazlSYTNZNVoyMVpXVFpWU0doQ1pWSnJMMWx4VlVsaU1WRldiMDFDT0VkQk1WVmtTWGRSV1UxQ1lVRUtSa1pxUVVoc0sxSlNZVlp0Y1ZoeVRXdExSMVJKZEVGeGVHTllOazFIVFVkQk1WVmtSVkZTWTAxR2NVZFhSMmd3WkVoQ2VrOXBPSFphTW13d1lVaFdhUXBNYlU1MllsTTVjbGx1VGpCTU0xSnNZMjVLYUZwdE9YbGlVekZ5WkZkS2JHTXpVbWhaTW5OMlRHMWtjR1JIYURGWmFUa3pZak5LY2xwdGVIWmtNMDEyQ21KWFJuQmlhVFUxWWxkNFFXTnRWbTFqZVRsdldsZEdhMk41T1hSWldFNHdXbGhKZDBWbldVdExkMWxDUWtGSFJIWjZRVUpCWjFGRlkwaFdlbUZFUVcwS1FtZHZja0puUlVWQldVOHZUVUZGUmtKQ2FISlpiazR3VEROU2JHTnVTbWhhYlRsNVlsTXhjbVJYU214ak0xSm9XVEp6ZDA1bldVdExkMWxDUWtGSFJBcDJla0ZDUVhkUmIxcHFSVEZPVjFGNVdXMUplRTU2V210TlZFVTFXV3BHYlU5VVNUSk9WRlV6V1hwTk5WbDZTbWxQVkdzMVdtcFNhRnBxWjNkWmVrRTFDa0puYjNKQ1owVkZRVmxQTDAxQlJVSkNRM1J2WkVoU2QyTjZiM1pNTTFKMllUSldkVXh0Um1wa1IyeDJZbTVOZFZveWJEQmhTRlpwWkZoT2JHTnRUbllLWW01U2JHSnVVWFZaTWpsMFRVSTRSME5wYzBkQlVWRkNaemM0ZDBGUldVVkZXRXBzV201TmRtRkhWbWhhU0UxMllsZEdlbVJIVm5sTlEwRkhRMmx6UndwQlVWRkNaemM0ZDBGUlVVVkZhMG94WVZkNGEwbEdVbXhqTTFGblZVaFdhV0pIYkhwaFJFRkxRbWRuY1docmFrOVFVVkZFUVhkT2IwRkVRbXhCYWtWQkNtdDJORTFLYUdGRGFFMUJaMHBWVTNWWll6bFBWRWt3WTB0bU9XTnlObU14Y1RreVYyOXFMM1ZsV0RKRFR6Z3JMMDQyU25SM1FVNTRVSElyTjNWNlpGQUtRV3BDYVhwR2NHZEVMelJzWW5aa1NuRnplWE5HYlVSeU1TdFNNSGhKWjI1S1N5c3JaWGROYmtKaVMxQkVMemd3VTNJelFYTTVMMWxxV1U5M05EVjRkUXA2ZVdzOUNpMHRMUzB0UlU1RUlFTkZVbFJKUmtsRFFWUkZMUzB0TFMwSyJ9fX19", - IntegratedTime: swag.Int64(123), - LogID: swag.String("deadbeef"), - LogIndex: swag.Int64(2), + IntegratedTime: conv.Pointer(int64(123)), + LogID: conv.Pointer("deadbeef"), + LogIndex: conv.Pointer(int64(2)), Verification: &models.LogEntryAnonVerification{ InclusionProof: &models.InclusionProof{ - Checkpoint: swag.String("checkpoint"), + Checkpoint: conv.Pointer("checkpoint"), Hashes: []string{"deadbeef", "abcdefaa"}, - LogIndex: swag.Int64(1), - RootHash: swag.String("abcdefaa"), - TreeSize: swag.Int64(2), + LogIndex: conv.Pointer(int64(1)), + RootHash: conv.Pointer("abcdefaa"), + TreeSize: conv.Pointer(int64(2)), }, SignedEntryTimestamp: strfmt.Base64("set"), }, diff --git a/pkg/cosign/bundle/rekor_test.go b/pkg/cosign/bundle/rekor_test.go index eb0e26ad6fb..dbf5e6808a7 100644 --- a/pkg/cosign/bundle/rekor_test.go +++ b/pkg/cosign/bundle/rekor_test.go @@ -21,7 +21,7 @@ import ( "time" "github.com/go-openapi/strfmt" - "github.com/go-openapi/swag" + "github.com/go-openapi/swag/conv" "github.com/sigstore/rekor/pkg/generated/models" ) @@ -34,24 +34,24 @@ func TestRekorBundle(t *testing.T) { name: "tlog entry without verification - nil bundle", logEntry: &models.LogEntryAnon{ Body: base64.StdEncoding.EncodeToString([]byte("TEST")), - IntegratedTime: swag.Int64(time.Now().Unix()), - LogIndex: swag.Int64(0), - LogID: swag.String("c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d"), + IntegratedTime: conv.Pointer(time.Now().Unix()), + LogIndex: conv.Pointer(int64(0)), + LogID: conv.Pointer("c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d"), }, expectedRekorBundle: nil, }, { name: "tlog entry with verification", logEntry: &models.LogEntryAnon{ Body: base64.StdEncoding.EncodeToString([]byte("TEST")), - IntegratedTime: swag.Int64(time.Now().Unix()), - LogIndex: swag.Int64(0), - LogID: swag.String("c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d"), + IntegratedTime: conv.Pointer(time.Now().Unix()), + LogIndex: conv.Pointer(int64(0)), + LogID: conv.Pointer("c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d"), Verification: &models.LogEntryAnonVerification{ SignedEntryTimestamp: strfmt.Base64([]byte("signature")), InclusionProof: &models.InclusionProof{ - LogIndex: swag.Int64(0), - TreeSize: swag.Int64(1), - RootHash: swag.String("TEST"), + LogIndex: conv.Pointer(int64(0)), + TreeSize: conv.Pointer(int64(1)), + RootHash: conv.Pointer("TEST"), Hashes: []string{}, }, }, diff --git a/pkg/cosign/bundle/sign.go b/pkg/cosign/bundle/sign.go new file mode 100644 index 00000000000..6f50cb98da6 --- /dev/null +++ b/pkg/cosign/bundle/sign.go @@ -0,0 +1,147 @@ +// Copyright 2025 The Sigstore 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 bundle + +import ( + "context" + "crypto/x509" + "encoding/pem" + "fmt" + "log" + "time" + + "github.com/sigstore/cosign/v3/internal/ui" + "github.com/sigstore/sigstore-go/pkg/root" + "github.com/sigstore/sigstore-go/pkg/sign" + "github.com/sigstore/sigstore/pkg/signature" + "google.golang.org/protobuf/encoding/protojson" +) + +func SignData(ctx context.Context, content sign.Content, keypair sign.Keypair, idToken string, cert []byte, signingConfig *root.SigningConfig, trustedMaterial root.TrustedMaterial) ([]byte, error) { + var opts sign.BundleOptions + + if trustedMaterial != nil { + opts.TrustedRoot = trustedMaterial + } + + switch { + case idToken != "": + if len(signingConfig.FulcioCertificateAuthorityURLs()) == 0 { + return nil, fmt.Errorf("no fulcio URLs provided in signing config") + } + fulcioSvc, err := root.SelectService(signingConfig.FulcioCertificateAuthorityURLs(), sign.FulcioAPIVersions, time.Now()) + if err != nil { + return nil, err + } + fulcioOpts := &sign.FulcioOptions{ + BaseURL: fulcioSvc.URL, + Timeout: 30 * time.Second, + Retries: 1, + } + opts.CertificateProvider = sign.NewFulcio(fulcioOpts) + opts.CertificateProviderOptions = &sign.CertificateProviderOptions{ + IDToken: idToken, + } + case cert != nil: + opts.CertificateProvider = &localCertProvider{cert} + default: + publicKeyPem, err := keypair.GetPublicKeyPem() + if err != nil { + return nil, err + } + block, _ := pem.Decode([]byte(publicKeyPem)) + pubKey, err := x509.ParsePKIXPublicKey(block.Bytes) + if err != nil { + log.Fatal(err) + } + verifier, err := signature.LoadDefaultVerifier(pubKey) + if err != nil { + log.Fatal(err) + } + key := root.NewExpiringKey(verifier, time.Time{}, time.Time{}) + keyTrustedMaterial := root.NewTrustedPublicKeyMaterial(func(_ string) (root.TimeConstrainedVerifier, error) { + return key, nil + }) + trustedMaterial := &verifyTrustedMaterial{ + TrustedMaterial: opts.TrustedRoot, + keyTrustedMaterial: keyTrustedMaterial, + } + opts.TrustedRoot = trustedMaterial + } + + if len(signingConfig.TimestampAuthorityURLs()) != 0 { + tsaSvcs, err := root.SelectServices(signingConfig.TimestampAuthorityURLs(), + signingConfig.TimestampAuthorityURLsConfig(), sign.TimestampAuthorityAPIVersions, time.Now()) + if err != nil { + log.Fatal(err) + } + for _, tsaSvc := range tsaSvcs { + tsaOpts := &sign.TimestampAuthorityOptions{ + URL: tsaSvc.URL, + Timeout: 30 * time.Second, + Retries: 1, + } + opts.TimestampAuthorities = append(opts.TimestampAuthorities, sign.NewTimestampAuthority(tsaOpts)) + } + } + + if len(signingConfig.RekorLogURLs()) != 0 { + rekorSvcs, err := root.SelectServices(signingConfig.RekorLogURLs(), + signingConfig.RekorLogURLsConfig(), sign.RekorAPIVersions, time.Now()) + if err != nil { + return nil, err + } + for _, rekorSvc := range rekorSvcs { + rekorOpts := &sign.RekorOptions{ + BaseURL: rekorSvc.URL, + Timeout: 90 * time.Second, + Retries: 1, + Version: rekorSvc.MajorAPIVersion, + } + opts.TransparencyLogs = append(opts.TransparencyLogs, sign.NewRekor(rekorOpts)) + } + } + + spinner := ui.NewSpinner(ctx, "Signing artifact...") + defer spinner.Stop() + + bundle, err := sign.Bundle(content, keypair, opts) + + if err != nil { + return nil, fmt.Errorf("error signing bundle: %w", err) + } + return protojson.Marshal(bundle) +} + +type verifyTrustedMaterial struct { + root.TrustedMaterial + keyTrustedMaterial root.TrustedMaterial +} + +func (v *verifyTrustedMaterial) PublicKeyVerifier(hint string) (root.TimeConstrainedVerifier, error) { + return v.keyTrustedMaterial.PublicKeyVerifier(hint) +} + +type localCertProvider struct { + cert []byte +} + +func (c *localCertProvider) GetCertificate(_ context.Context, _ sign.Keypair, _ *sign.CertificateProviderOptions) ([]byte, error) { + certBlock, _ := pem.Decode(c.cert) + if certBlock == nil { + return nil, fmt.Errorf("could not decode cert") + } + return certBlock.Bytes, nil +} diff --git a/pkg/cosign/ctlog.go b/pkg/cosign/ctlog.go index 9f2ebc3d5ec..5ad76a00b14 100644 --- a/pkg/cosign/ctlog.go +++ b/pkg/cosign/ctlog.go @@ -20,7 +20,7 @@ import ( "fmt" "os" - "github.com/sigstore/cosign/v2/pkg/cosign/env" + "github.com/sigstore/cosign/v3/pkg/cosign/env" "github.com/sigstore/sigstore/pkg/tuf" ) diff --git a/pkg/cosign/cue/cue_test.go b/pkg/cosign/cue/cue_test.go index 9748fad3437..e16b3782622 100644 --- a/pkg/cosign/cue/cue_test.go +++ b/pkg/cosign/cue/cue_test.go @@ -157,7 +157,7 @@ func TestValidationJSON(t *testing.T) { } `, pass: false, - errorMsg: "authorityMatches.keysignature.signatures: invalid value [{subject:\"PLACEHOLDER\",issuer:\"PLACEHOLDER\"}] (does not satisfy list.MinItems(2))", + errorMsg: "authorityMatches.keysignature.signatures: invalid value [{subject:\"PLACEHOLDER\",issuer:\"PLACEHOLDER\"}] (does not satisfy list.MinItems(2)): len(list) < MinItems(2) (1 < 2)", }, } diff --git a/pkg/cosign/fetch.go b/pkg/cosign/fetch.go index 709333ac77f..53e3ce34a38 100644 --- a/pkg/cosign/fetch.go +++ b/pkg/cosign/fetch.go @@ -28,9 +28,9 @@ import ( "github.com/google/go-containerregistry/pkg/name" "github.com/in-toto/in-toto-golang/in_toto" - "github.com/sigstore/cosign/v2/pkg/cosign/bundle" - "github.com/sigstore/cosign/v2/pkg/oci" - ociremote "github.com/sigstore/cosign/v2/pkg/oci/remote" + "github.com/sigstore/cosign/v3/pkg/cosign/bundle" + "github.com/sigstore/cosign/v3/pkg/oci" + ociremote "github.com/sigstore/cosign/v3/pkg/oci/remote" "golang.org/x/sync/errgroup" ) diff --git a/pkg/cosign/fuzz_test.go b/pkg/cosign/fuzz_test.go index db56ab11e1f..9cf9afc579f 100644 --- a/pkg/cosign/fuzz_test.go +++ b/pkg/cosign/fuzz_test.go @@ -24,7 +24,7 @@ import ( "github.com/google/go-containerregistry/pkg/name" v1 "github.com/google/go-containerregistry/pkg/v1" - "github.com/sigstore/cosign/v2/pkg/oci/mutate" + "github.com/sigstore/cosign/v3/pkg/oci/mutate" ) var ( @@ -61,7 +61,7 @@ func FuzzImportKeyPairLoadPrivateKey(f *testing.F) { return } // Loading the private key should also work. - _, err = LoadPrivateKey(keyBytes.PrivateBytes, password) + _, err = LoadPrivateKey(keyBytes.PrivateBytes, password, nil) if err != nil { t.Fatal(err) } diff --git a/pkg/cosign/git/git.go b/pkg/cosign/git/git.go index b4380f2c137..4a1b81d0ece 100644 --- a/pkg/cosign/git/git.go +++ b/pkg/cosign/git/git.go @@ -18,9 +18,9 @@ package git import ( "context" - "github.com/sigstore/cosign/v2/pkg/cosign" - "github.com/sigstore/cosign/v2/pkg/cosign/git/github" - "github.com/sigstore/cosign/v2/pkg/cosign/git/gitlab" + "github.com/sigstore/cosign/v3/pkg/cosign" + "github.com/sigstore/cosign/v3/pkg/cosign/git/github" + "github.com/sigstore/cosign/v3/pkg/cosign/git/gitlab" ) var providerMap = map[string]Git{ diff --git a/pkg/cosign/git/github/github.go b/pkg/cosign/git/github/github.go index 3b8ce918308..07ff3634108 100644 --- a/pkg/cosign/git/github/github.go +++ b/pkg/cosign/git/github/github.go @@ -29,8 +29,8 @@ import ( "golang.org/x/crypto/nacl/box" "golang.org/x/oauth2" - "github.com/sigstore/cosign/v2/pkg/cosign" - "github.com/sigstore/cosign/v2/pkg/cosign/env" + "github.com/sigstore/cosign/v3/pkg/cosign" + "github.com/sigstore/cosign/v3/pkg/cosign/env" ) const ( diff --git a/pkg/cosign/git/gitlab/gitlab.go b/pkg/cosign/git/gitlab/gitlab.go index b1246913218..1c25b5fe74e 100644 --- a/pkg/cosign/git/gitlab/gitlab.go +++ b/pkg/cosign/git/gitlab/gitlab.go @@ -21,9 +21,9 @@ import ( "io" "os" - "github.com/sigstore/cosign/v2/internal/ui" - "github.com/sigstore/cosign/v2/pkg/cosign" - "github.com/sigstore/cosign/v2/pkg/cosign/env" + "github.com/sigstore/cosign/v3/internal/ui" + "github.com/sigstore/cosign/v3/pkg/cosign" + "github.com/sigstore/cosign/v3/pkg/cosign/env" gitlab "gitlab.com/gitlab-org/api/client-go" ) diff --git a/pkg/cosign/keys.go b/pkg/cosign/keys.go index ed5bbc16d4b..7493782cae0 100644 --- a/pkg/cosign/keys.go +++ b/pkg/cosign/keys.go @@ -19,7 +19,6 @@ import ( "crypto" "crypto/ecdsa" "crypto/ed25519" - "crypto/elliptic" "crypto/rand" "crypto/rsa" _ "crypto/sha256" // for `crypto.SHA256` @@ -29,11 +28,15 @@ import ( "fmt" "os" "path/filepath" + "sort" "github.com/secure-systems-lab/go-securesystemslib/encrypted" - "github.com/sigstore/cosign/v2/pkg/oci/static" + "github.com/sigstore/cosign/v3/pkg/oci/static" + v1 "github.com/sigstore/protobuf-specs/gen/pb-go/common/v1" "github.com/sigstore/sigstore/pkg/cryptoutils" + "github.com/sigstore/sigstore/pkg/cryptoutils/goodkey" "github.com/sigstore/sigstore/pkg/signature" + "github.com/sigstore/sigstore/pkg/signature/options" ) const ( @@ -49,6 +52,17 @@ const ( RFC3161TimestampKey = static.RFC3161TimestampAnnotationKey ) +var SupportedKeyDetails = []v1.PublicKeyDetails{ + v1.PublicKeyDetails_PKIX_ECDSA_P256_SHA_256, + v1.PublicKeyDetails_PKIX_ECDSA_P384_SHA_384, + v1.PublicKeyDetails_PKIX_ECDSA_P521_SHA_512, + v1.PublicKeyDetails_PKIX_RSA_PKCS1V15_2048_SHA256, + v1.PublicKeyDetails_PKIX_RSA_PKCS1V15_3072_SHA256, + v1.PublicKeyDetails_PKIX_RSA_PKCS1V15_4096_SHA256, + // Ed25519ph is not supported by Fulcio, so we don't support it here for now. + // v1.PublicKeyDetails_PKIX_ED25519_PH, +} + // PassFunc is the function to be called to retrieve the signer password. If // nil, then it assumes that no password is provided. type PassFunc func(bool) ([]byte, error) @@ -70,7 +84,48 @@ func (k *KeysBytes) Password() []byte { // GeneratePrivateKey generates an ECDSA private key with the P-256 curve. func GeneratePrivateKey() (*ecdsa.PrivateKey, error) { - return ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + priv, err := GeneratePrivateKeyWithAlgorithm(nil) + if err != nil { + return nil, err + } + return priv.(*ecdsa.PrivateKey), nil +} + +// GeneratePrivateKeyWithAlgorithm generates a private key for the given algorithm +func GeneratePrivateKeyWithAlgorithm(algo *signature.AlgorithmDetails) (crypto.PrivateKey, error) { + var currentAlgo signature.AlgorithmDetails + if algo == nil { + var err error + currentAlgo, err = signature.GetAlgorithmDetails(v1.PublicKeyDetails_PKIX_ECDSA_P256_SHA_256) + if err != nil { + return nil, fmt.Errorf("error getting algorithm details for default algorithm: %w", err) + } + } else { + currentAlgo = *algo + } + + switch currentAlgo.GetKeyType() { + case signature.ECDSA: + curve, err := currentAlgo.GetECDSACurve() + if err != nil { + return nil, fmt.Errorf("error getting ECDSA curve: %w", err) + } + return ecdsa.GenerateKey(*curve, rand.Reader) + case signature.RSA: + rsaKeySize, err := currentAlgo.GetRSAKeySize() + if err != nil { + return nil, fmt.Errorf("error getting RSA key size: %w", err) + } + return rsa.GenerateKey(rand.Reader, int(rsaKeySize)) + case signature.ED25519: + _, priv, err := ed25519.GenerateKey(rand.Reader) + if err != nil { + return nil, fmt.Errorf("error generating ED25519 key: %w", err) + } + return priv, nil + default: + return nil, fmt.Errorf("unsupported key type: %v", currentAlgo.GetKeyType()) + } } // ImportKeyPair imports a key pair from a file containing a PEM-encoded @@ -98,7 +153,7 @@ func ImportKeyPair(keyPath string, pf PassFunc) (*KeysBytes, error) { if err != nil { return nil, fmt.Errorf("error parsing rsa private key: %w", err) } - if err = cryptoutils.ValidatePubKey(rsaPk.Public()); err != nil { + if err = goodkey.ValidatePubKey(rsaPk.Public()); err != nil { return nil, fmt.Errorf("error validating rsa key: %w", err) } pk = rsaPk @@ -107,7 +162,7 @@ func ImportKeyPair(keyPath string, pf PassFunc) (*KeysBytes, error) { if err != nil { return nil, fmt.Errorf("error parsing ecdsa private key") } - if err = cryptoutils.ValidatePubKey(ecdsaPk.Public()); err != nil { + if err = goodkey.ValidatePubKey(ecdsaPk.Public()); err != nil { return nil, fmt.Errorf("error validating ecdsa key: %w", err) } pk = ecdsaPk @@ -118,17 +173,17 @@ func ImportKeyPair(keyPath string, pf PassFunc) (*KeysBytes, error) { } switch k := pkcs8Pk.(type) { case *rsa.PrivateKey: - if err = cryptoutils.ValidatePubKey(k.Public()); err != nil { + if err = goodkey.ValidatePubKey(k.Public()); err != nil { return nil, fmt.Errorf("error validating rsa key: %w", err) } pk = k case *ecdsa.PrivateKey: - if err = cryptoutils.ValidatePubKey(k.Public()); err != nil { + if err = goodkey.ValidatePubKey(k.Public()); err != nil { return nil, fmt.Errorf("error validating ecdsa key: %w", err) } pk = k case ed25519.PrivateKey: - if err = cryptoutils.ValidatePubKey(k.Public()); err != nil { + if err = goodkey.ValidatePubKey(k.Public()); err != nil { return nil, fmt.Errorf("error validating ed25519 key: %w", err) } pk = k @@ -194,6 +249,19 @@ func GenerateKeyPair(pf PassFunc) (*KeysBytes, error) { return marshalKeyPair(SigstorePrivateKeyPemType, Keys{priv, priv.Public()}, pf) } +func GenerateKeyPairWithAlgorithm(algo *signature.AlgorithmDetails, pf PassFunc) (*KeysBytes, error) { + priv, err := GeneratePrivateKeyWithAlgorithm(algo) + if err != nil { + return nil, err + } + signer, ok := priv.(crypto.Signer) + if !ok { + return nil, fmt.Errorf("private key is not a signer verifier") + } + // Emit SIGSTORE keys by default + return marshalKeyPair(SigstorePrivateKeyPemType, Keys{signer, signer.Public()}, pf) +} + // PemToECDSAKey marshals and returns the PEM-encoded ECDSA public key. func PemToECDSAKey(pemBytes []byte) (*ecdsa.PublicKey, error) { pub, err := cryptoutils.UnmarshalPEMToPublicKey(pemBytes) @@ -209,7 +277,7 @@ func PemToECDSAKey(pemBytes []byte) (*ecdsa.PublicKey, error) { // LoadPrivateKey loads a cosign PEM private key encrypted with the given passphrase, // and returns a SignerVerifier instance. The private key must be in the PKCS #8 format. -func LoadPrivateKey(key []byte, pass []byte) (signature.SignerVerifier, error) { +func LoadPrivateKey(key []byte, pass []byte, defaultLoadOptions *[]signature.LoadOption) (signature.SignerVerifier, error) { // Decrypt first p, _ := pem.Decode(key) if p == nil { @@ -227,14 +295,32 @@ func LoadPrivateKey(key []byte, pass []byte) (signature.SignerVerifier, error) { if err != nil { return nil, fmt.Errorf("parsing private key: %w", err) } - switch pk := pk.(type) { - case *rsa.PrivateKey: - return signature.LoadRSAPKCS1v15SignerVerifier(pk, crypto.SHA256) - case *ecdsa.PrivateKey: - return signature.LoadECDSASignerVerifier(pk, crypto.SHA256) - case ed25519.PrivateKey: - return signature.LoadED25519SignerVerifier(pk) - default: - return nil, errors.New("unsupported key type") + defaultLoadOptions = GetDefaultLoadOptions(defaultLoadOptions) + return signature.LoadDefaultSignerVerifier(pk, *defaultLoadOptions...) +} + +func GetDefaultLoadOptions(defaultLoadOptions *[]signature.LoadOption) *[]signature.LoadOption { + if defaultLoadOptions == nil { + // Cosign uses ED25519ph by default for ED25519 keys, because that's the + // only available option for hashedrekord entries. This behaviour is + // configurable because we want to maintain compatibility with older + // cosign versions that used PureEd25519 for ED25519 keys (but which did + // not support TLog uploads). + return &[]signature.LoadOption{options.WithED25519ph()} + } + return defaultLoadOptions +} + +// GetSupportedAlgorithms returns a list of supported algorithms sorted alphabetically. +func GetSupportedAlgorithms() []string { + algorithms := make([]string, 0, len(SupportedKeyDetails)) + for _, algorithm := range SupportedKeyDetails { + signatureFlag, err := signature.FormatSignatureAlgorithmFlag(algorithm) + if err != nil { + continue + } + algorithms = append(algorithms, signatureFlag) } + sort.Strings(algorithms) + return algorithms } diff --git a/pkg/cosign/keys_test.go b/pkg/cosign/keys_test.go index f1408da27e5..41ace7df23d 100644 --- a/pkg/cosign/keys_test.go +++ b/pkg/cosign/keys_test.go @@ -339,12 +339,12 @@ func TestLoadECDSAPrivateKey(t *testing.T) { } // Load the private key with the right password - if _, err := LoadPrivateKey(keys.PrivateBytes, []byte("hello")); err != nil { + if _, err := LoadPrivateKey(keys.PrivateBytes, []byte("hello"), nil); err != nil { t.Errorf("unexpected error decrypting key: %s", err) } // Try it with the wrong one - if _, err := LoadPrivateKey(keys.PrivateBytes, []byte("wrong")); err == nil { + if _, err := LoadPrivateKey(keys.PrivateBytes, []byte("wrong"), nil); err == nil { t.Error("expected error decrypting key!") } @@ -353,7 +353,7 @@ func TestLoadECDSAPrivateKey(t *testing.T) { if _, err := rand.Read(buf[:]); err != nil { t.Fatal(err) } - if _, err := LoadPrivateKey(buf[:], []byte("wrong")); err == nil { + if _, err := LoadPrivateKey(buf[:], []byte("wrong"), nil); err == nil { t.Error("expected error decrypting key!") } } @@ -384,7 +384,7 @@ func TestReadingPrivatePemTypes(t *testing.T) { for _, tc := range testCases { t.Run(tc.pemType, func(t *testing.T) { - _, err := LoadPrivateKey(tc.pemData, []byte("hello")) + _, err := LoadPrivateKey(tc.pemData, []byte("hello"), nil) if tc.expected == nil { require.NoError(t, err) } else { @@ -497,7 +497,7 @@ func TestImportPrivateKey(t *testing.T) { if err == nil || tc.expected == nil { require.Equal(t, tc.expected, err) // Loading the private key should also work. - _, err = LoadPrivateKey(keyBytes.PrivateBytes, []byte("hello")) + _, err = LoadPrivateKey(keyBytes.PrivateBytes, []byte("hello"), nil) require.Equal(t, tc.expected, err) } else { require.Equal(t, tc.expected.Error(), err.Error()) diff --git a/pkg/cosign/kubernetes/secret.go b/pkg/cosign/kubernetes/secret.go index 11289888192..3aaa0f16364 100644 --- a/pkg/cosign/kubernetes/secret.go +++ b/pkg/cosign/kubernetes/secret.go @@ -21,7 +21,7 @@ import ( "os" "strings" - "github.com/sigstore/cosign/v2/pkg/cosign" + "github.com/sigstore/cosign/v3/pkg/cosign" v1 "k8s.io/api/core/v1" k8serrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" diff --git a/pkg/cosign/kubernetes/secret_test.go b/pkg/cosign/kubernetes/secret_test.go index d626d9eada6..4b257ce31db 100644 --- a/pkg/cosign/kubernetes/secret_test.go +++ b/pkg/cosign/kubernetes/secret_test.go @@ -18,7 +18,7 @@ import ( "reflect" "testing" - "github.com/sigstore/cosign/v2/pkg/cosign" + "github.com/sigstore/cosign/v3/pkg/cosign" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/utils/ptr" diff --git a/pkg/cosign/obsolete.go b/pkg/cosign/obsolete.go index 817f05bead0..66ceed55678 100644 --- a/pkg/cosign/obsolete.go +++ b/pkg/cosign/obsolete.go @@ -19,7 +19,7 @@ import ( "context" "github.com/google/go-containerregistry/pkg/name" - "github.com/sigstore/cosign/v2/internal/ui" + "github.com/sigstore/cosign/v3/internal/ui" "github.com/sigstore/sigstore/pkg/signature/payload" ) diff --git a/pkg/cosign/obsolete_test.go b/pkg/cosign/obsolete_test.go index b03ddb91312..22b2b1c8098 100644 --- a/pkg/cosign/obsolete_test.go +++ b/pkg/cosign/obsolete_test.go @@ -20,7 +20,7 @@ import ( "testing" "github.com/google/go-containerregistry/pkg/name" - "github.com/sigstore/cosign/v2/internal/ui" + "github.com/sigstore/cosign/v3/internal/ui" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/pkg/cosign/pkcs11key/pkcs11key.go b/pkg/cosign/pkcs11key/pkcs11key.go index c034a3f4fac..50dfb1ed178 100644 --- a/pkg/cosign/pkcs11key/pkcs11key.go +++ b/pkg/cosign/pkcs11key/pkcs11key.go @@ -34,7 +34,7 @@ import ( "github.com/ThalesIgnite/crypto11" "github.com/miekg/pkcs11" - "github.com/sigstore/cosign/v2/pkg/cosign/env" + "github.com/sigstore/cosign/v3/pkg/cosign/env" "github.com/sigstore/sigstore/pkg/signature" "golang.org/x/term" ) diff --git a/pkg/cosign/pkcs11key/util.go b/pkg/cosign/pkcs11key/util.go index beb74a70770..ce30a873ef4 100644 --- a/pkg/cosign/pkcs11key/util.go +++ b/pkg/cosign/pkcs11key/util.go @@ -21,7 +21,7 @@ import ( "strconv" "strings" - "github.com/sigstore/cosign/v2/pkg/cosign/env" + "github.com/sigstore/cosign/v3/pkg/cosign/env" ) const ( diff --git a/pkg/cosign/remote/index.go b/pkg/cosign/remote/index.go index f14f42911cf..e62d875d0ad 100644 --- a/pkg/cosign/remote/index.go +++ b/pkg/cosign/remote/index.go @@ -27,7 +27,7 @@ import ( "github.com/google/go-containerregistry/pkg/v1/mutate" "github.com/google/go-containerregistry/pkg/v1/remote" "github.com/google/go-containerregistry/pkg/v1/types" - "github.com/sigstore/cosign/v2/pkg/oci/static" + "github.com/sigstore/cosign/v3/pkg/oci/static" ) type File interface { diff --git a/pkg/cosign/remote/remote.go b/pkg/cosign/remote/remote.go index 5c1b800af1c..8c46a65dbcd 100644 --- a/pkg/cosign/remote/remote.go +++ b/pkg/cosign/remote/remote.go @@ -22,9 +22,9 @@ import ( "fmt" "os" - "github.com/sigstore/cosign/v2/pkg/oci" - "github.com/sigstore/cosign/v2/pkg/oci/mutate" - "github.com/sigstore/cosign/v2/pkg/oci/static" + "github.com/sigstore/cosign/v3/pkg/oci" + "github.com/sigstore/cosign/v3/pkg/oci/mutate" + "github.com/sigstore/cosign/v3/pkg/oci/static" "github.com/sigstore/sigstore/pkg/signature" ) diff --git a/pkg/cosign/tlog.go b/pkg/cosign/tlog.go index bd3c2a897e6..875dc2a3975 100644 --- a/pkg/cosign/tlog.go +++ b/pkg/cosign/tlog.go @@ -32,9 +32,9 @@ import ( "github.com/go-openapi/strfmt" "github.com/go-openapi/swag" - "github.com/sigstore/cosign/v2/internal/ui" - "github.com/sigstore/cosign/v2/pkg/cosign/bundle" - "github.com/sigstore/cosign/v2/pkg/cosign/env" + "github.com/sigstore/cosign/v3/internal/ui" + "github.com/sigstore/cosign/v3/pkg/cosign/bundle" + "github.com/sigstore/cosign/v3/pkg/cosign/env" "github.com/sigstore/rekor/pkg/generated/client" "github.com/sigstore/rekor/pkg/generated/client/entries" "github.com/sigstore/rekor/pkg/generated/models" @@ -55,6 +55,36 @@ import ( // This is the rekor transparency log public key target name var rekorTargetStr = `rekor.pub` +type NamedHash interface { + hash.Hash + crypto.SignerOpts +} + +type CryptoNamedHash struct { + hash.Hash + hashType crypto.Hash +} + +func (h CryptoNamedHash) HashFunc() crypto.Hash { + return h.hashType +} + +func NewCryptoNamedHash(hashType crypto.Hash) NamedHash { + return CryptoNamedHash{Hash: hashType.New(), hashType: hashType} +} + +type SHA256NamedHash struct { + hash.Hash +} + +func (h SHA256NamedHash) HashFunc() crypto.Hash { + return crypto.SHA256 +} + +func WrapSHA256Hash(hash hash.Hash) NamedHash { + return SHA256NamedHash{Hash: hash} +} + // TransparencyLogPubKey contains the ECDSA verification key and the current status // of the key according to TUF metadata, whether it's active or expired. type TransparencyLogPubKey struct { @@ -172,7 +202,14 @@ func rekorPubsFromClient(rekorClient *client.Rekor) (*TrustedTransparencyLogPubK // TLogUpload will upload the signature, public key and payload to the transparency log. func TLogUpload(ctx context.Context, rekorClient *client.Rekor, signature []byte, sha256CheckSum hash.Hash, pemBytes []byte) (*models.LogEntryAnon, error) { - re := rekorEntry(sha256CheckSum, signature, pemBytes) + cryptoChecksum := WrapSHA256Hash(sha256CheckSum) + return TLogUploadWithCustomHash(ctx, rekorClient, signature, cryptoChecksum, pemBytes) +} + +// TLogUploadWithCustomHash will upload the signature, public key and payload to +// the transparency log. Clients can use this to specify a custom hash function. +func TLogUploadWithCustomHash(ctx context.Context, rekorClient *client.Rekor, signature []byte, checksum NamedHash, pemBytes []byte) (*models.LogEntryAnon, error) { + re := rekorEntry(checksum, signature, pemBytes) returnVal := models.Hashedrekord{ APIVersion: swag.String(re.APIVersion()), Spec: re.HashedRekordObj, @@ -231,16 +268,26 @@ func doUpload(ctx context.Context, rekorClient *client.Rekor, pe models.Proposed return nil, errors.New("bad response from server") } -func rekorEntry(sha256CheckSum hash.Hash, signature, pubKey []byte) hashedrekord_v001.V001Entry { - // TODO: Signatures created on a digest using a hash algorithm other than SHA256 will fail - // upload right now. Plumb information on the hash algorithm used when signing from the - // SignerVerifier to use for the HashedRekordObj.Data.Hash.Algorithm. +func rekorEntryHashAlgorithm(checksum crypto.SignerOpts) string { + switch checksum.HashFunc() { + case crypto.SHA256: + return models.HashedrekordV001SchemaDataHashAlgorithmSha256 + case crypto.SHA384: + return models.HashedrekordV001SchemaDataHashAlgorithmSha384 + case crypto.SHA512: + return models.HashedrekordV001SchemaDataHashAlgorithmSha512 + default: + return models.HashedrekordV001SchemaDataHashAlgorithmSha256 + } +} + +func rekorEntry(checksum NamedHash, signature, pubKey []byte) hashedrekord_v001.V001Entry { return hashedrekord_v001.V001Entry{ HashedRekordObj: models.HashedrekordV001Schema{ Data: &models.HashedrekordV001SchemaData{ Hash: &models.HashedrekordV001SchemaDataHash{ - Algorithm: swag.String(models.HashedrekordV001SchemaDataHashAlgorithmSha256), - Value: swag.String(hex.EncodeToString(sha256CheckSum.Sum(nil))), + Algorithm: swag.String(rekorEntryHashAlgorithm(checksum)), + Value: swag.String(hex.EncodeToString(checksum.Sum(nil))), }, }, Signature: &models.HashedrekordV001SchemaSignature{ @@ -393,7 +440,7 @@ func proposedEntries(b64Sig string, payload, pubKey []byte) ([]models.ProposedEn } proposedEntry = []models.ProposedEntry{dsseEntry, intotoEntry} } else { - sha256CheckSum := sha256.New() + sha256CheckSum := NewCryptoNamedHash(crypto.SHA256) if _, err := sha256CheckSum.Write(payload); err != nil { return nil, err } diff --git a/pkg/cosign/tlog_test.go b/pkg/cosign/tlog_test.go index 16a1abd58cd..aeaf53e3b7d 100644 --- a/pkg/cosign/tlog_test.go +++ b/pkg/cosign/tlog_test.go @@ -29,7 +29,7 @@ import ( "testing" "time" - "github.com/go-openapi/swag" + "github.com/go-openapi/swag/conv" ttestdata "github.com/google/certificate-transparency-go/trillian/testdata" "github.com/sigstore/rekor/pkg/generated/models" rtypes "github.com/sigstore/rekor/pkg/types" @@ -214,9 +214,9 @@ func TestVerifyTLogEntryOfflineFailsWithInvalidPublicKey(t *testing.T) { } lea := &models.LogEntryAnon{ Body: base64.StdEncoding.EncodeToString(canonicalEntry), - LogIndex: swag.Int64(0), - LogID: swag.String(logID), - IntegratedTime: swag.Int64(time.Now().Unix()), + LogIndex: conv.Pointer(int64(0)), + LogID: conv.Pointer(logID), + IntegratedTime: conv.Pointer(time.Now().Unix()), } entryUUID, err := ComputeLeafHash(lea) if err != nil { @@ -224,9 +224,9 @@ func TestVerifyTLogEntryOfflineFailsWithInvalidPublicKey(t *testing.T) { } lea.Verification = &models.LogEntryAnonVerification{ InclusionProof: &models.InclusionProof{ - LogIndex: swag.Int64(0), - TreeSize: swag.Int64(1), - RootHash: swag.String(hex.EncodeToString(entryUUID)), + LogIndex: conv.Pointer(int64(0)), + TreeSize: conv.Pointer(int64(1)), + RootHash: conv.Pointer(hex.EncodeToString(entryUUID)), Hashes: []string{}, }, } diff --git a/pkg/cosign/tsa.go b/pkg/cosign/tsa.go index c2032f396e8..b97b96bb4c6 100644 --- a/pkg/cosign/tsa.go +++ b/pkg/cosign/tsa.go @@ -18,10 +18,13 @@ import ( "bytes" "context" "crypto/x509" + "encoding/base64" + "encoding/json" "fmt" "os" - "github.com/sigstore/cosign/v2/pkg/cosign/env" + "github.com/secure-systems-lab/go-securesystemslib/dsse" + "github.com/sigstore/cosign/v3/pkg/cosign/env" "github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/sigstore/sigstore/pkg/tuf" ) @@ -152,3 +155,15 @@ func splitPEMCertificateChain(pem []byte) (leaves, intermediates, roots []*x509. return leaves, intermediates, roots, nil } + +func GetDSSESigBytes(envelopeBytes []byte) ([]byte, error) { + var envelope dsse.Envelope + err := json.Unmarshal(envelopeBytes, &envelope) + if err != nil { + return nil, err + } + if len(envelope.Signatures) == 0 { + return nil, fmt.Errorf("envelope has no signatures") + } + return base64.StdEncoding.DecodeString(envelope.Signatures[0].Sig) +} diff --git a/pkg/cosign/tuf.go b/pkg/cosign/tuf.go index 2a7049feec4..bf664b4bc4e 100644 --- a/pkg/cosign/tuf.go +++ b/pkg/cosign/tuf.go @@ -21,7 +21,7 @@ import ( "os" "path/filepath" - "github.com/sigstore/cosign/v2/pkg/cosign/env" + "github.com/sigstore/cosign/v3/pkg/cosign/env" "github.com/sigstore/sigstore-go/pkg/root" "github.com/sigstore/sigstore-go/pkg/tuf" ) @@ -38,6 +38,18 @@ func TrustedRoot() (root.TrustedMaterial, error) { return tr, nil } +func SigningConfig() (*root.SigningConfig, error) { + opts, err := setTUFOpts() + if err != nil { + return nil, fmt.Errorf("error setting TUF options: %w", err) + } + sc, err := root.FetchSigningConfigWithOptions(opts) + if err != nil { + return nil, fmt.Errorf("error getting signing config from TUF: %w", err) + } + return sc, nil +} + // setTUFOpts sets the TUF cache directory, the mirror URL, and the root.json in the TUF options. // The cache directory is provided by the user as an environment variable TUF_ROOT, or the default $HOME/.sigstore/root is used. // The mirror URL is provided by the user as an environment variable TUF_MIRROR. If not overridden by the user, the value set during `cosign initialize` in remote.json in the cache directory is used. diff --git a/pkg/cosign/verifiers.go b/pkg/cosign/verifiers.go index 41f82491907..95f901f67e4 100644 --- a/pkg/cosign/verifiers.go +++ b/pkg/cosign/verifiers.go @@ -22,10 +22,10 @@ import ( "fmt" v1 "github.com/google/go-containerregistry/pkg/v1" - "github.com/in-toto/in-toto-golang/in_toto" + in_toto "github.com/in-toto/attestation/go/v1" "github.com/secure-systems-lab/go-securesystemslib/dsse" - "github.com/sigstore/cosign/v2/pkg/oci" + "github.com/sigstore/cosign/v3/pkg/oci" "github.com/sigstore/sigstore/pkg/signature/payload" ) @@ -56,7 +56,7 @@ func SimpleClaimVerifier(sig oci.Signature, imageDigest v1.Hash, annotations map } // IntotoSubjectClaimVerifier verifies that sig.Payload() is an Intoto statement which references the given image digest. -func IntotoSubjectClaimVerifier(sig oci.Signature, imageDigest v1.Hash, _ map[string]interface{}) error { +func IntotoSubjectClaimVerifier(sig oci.Signature, imageDigest v1.Hash, annotations map[string]interface{}) error { p, err := sig.Payload() if err != nil { return err @@ -82,9 +82,13 @@ func IntotoSubjectClaimVerifier(sig oci.Signature, imageDigest v1.Hash, _ map[st continue } subjDigest := "sha256:" + dgst - if subjDigest == imageDigest.String() { - return nil + if subjDigest != imageDigest.String() { + continue + } + if !correctAnnotations(annotations, subj.Annotations.AsMap()) { + return errors.New("missing or incorrect annotation") } + return nil } return errors.New("no matching subject digest found") } diff --git a/pkg/cosign/verifiers_test.go b/pkg/cosign/verifiers_test.go index 81633dcbff5..766d2300ac0 100644 --- a/pkg/cosign/verifiers_test.go +++ b/pkg/cosign/verifiers_test.go @@ -18,7 +18,7 @@ import ( "testing" v1 "github.com/google/go-containerregistry/pkg/v1" - "github.com/sigstore/cosign/v2/pkg/oci/static" + "github.com/sigstore/cosign/v3/pkg/oci/static" ) /* diff --git a/pkg/cosign/verify.go b/pkg/cosign/verify.go index 00206560992..109171817f9 100644 --- a/pkg/cosign/verify.go +++ b/pkg/cosign/verify.go @@ -44,16 +44,16 @@ import ( "github.com/google/go-containerregistry/pkg/v1/remote/transport" "github.com/nozzle/throttler" ssldsse "github.com/secure-systems-lab/go-securesystemslib/dsse" - "github.com/sigstore/cosign/v2/internal/pkg/cosign" - ociexperimental "github.com/sigstore/cosign/v2/internal/pkg/oci/remote" - "github.com/sigstore/cosign/v2/internal/ui" - "github.com/sigstore/cosign/v2/pkg/blob" - cbundle "github.com/sigstore/cosign/v2/pkg/cosign/bundle" - "github.com/sigstore/cosign/v2/pkg/oci" - "github.com/sigstore/cosign/v2/pkg/oci/layout" - ociremote "github.com/sigstore/cosign/v2/pkg/oci/remote" - "github.com/sigstore/cosign/v2/pkg/oci/static" - "github.com/sigstore/cosign/v2/pkg/types" + "github.com/sigstore/cosign/v3/internal/pkg/cosign" + ociexperimental "github.com/sigstore/cosign/v3/internal/pkg/oci/remote" + "github.com/sigstore/cosign/v3/internal/ui" + "github.com/sigstore/cosign/v3/pkg/blob" + cbundle "github.com/sigstore/cosign/v3/pkg/cosign/bundle" + "github.com/sigstore/cosign/v3/pkg/oci" + "github.com/sigstore/cosign/v3/pkg/oci/layout" + ociremote "github.com/sigstore/cosign/v3/pkg/oci/remote" + "github.com/sigstore/cosign/v3/pkg/oci/static" + "github.com/sigstore/cosign/v3/pkg/types" protobundle "github.com/sigstore/protobuf-specs/gen/pb-go/bundle/v1" "github.com/sigstore/rekor/pkg/generated/client" "github.com/sigstore/rekor/pkg/generated/models" @@ -73,7 +73,7 @@ import ( "github.com/sigstore/sigstore/pkg/signature/dsse" "github.com/sigstore/sigstore/pkg/signature/options" "github.com/sigstore/sigstore/pkg/tuf" - tsaverification "github.com/sigstore/timestamp-authority/pkg/verification" + tsaverification "github.com/sigstore/timestamp-authority/v2/pkg/verification" ) // Identity specifies an issuer/subject to verify a signature against. @@ -247,13 +247,29 @@ func (co *CheckOpts) verificationOptions() (trustedMaterial root.TrustedMaterial } if !co.IgnoreTlog { - verifierOptions = append(verifierOptions, verify.WithTransparencyLog(1), verify.WithIntegratedTimestamps(1)) + verifierOptions = append(verifierOptions, verify.WithTransparencyLog(1)) + // If you aren't using a signed timestamp, use the time from the transparency log + // to verify Fulcio certificates, or require no timestamp to verify a key. + // For Rekor v2, a signed timestamp must be provided. + if !co.UseSignedTimestamps { + if co.SigVerifier == nil { + verifierOptions = append(verifierOptions, verify.WithIntegratedTimestamps(1)) + } else { + verifierOptions = append(verifierOptions, verify.WithNoObserverTimestamps()) + } + } } if co.UseSignedTimestamps { verifierOptions = append(verifierOptions, verify.WithSignedTimestamps(1)) } + // A time verification policy must be provided. Without a signed timestamp or integrated timestamp, + // verify a certificate with the current time, or require no timestamp to verify a key. if co.IgnoreTlog && !co.UseSignedTimestamps { - verifierOptions = append(verifierOptions, verify.WithCurrentTime()) + if co.SigVerifier == nil { + verifierOptions = append(verifierOptions, verify.WithCurrentTime()) + } else { + verifierOptions = append(verifierOptions, verify.WithNoObserverTimestamps()) + } } return vTrustedMaterial, verifierOptions, policyOptions, nil @@ -929,15 +945,23 @@ func keyBytes(sig oci.Signature, co *CheckOpts) ([]byte, error) { if err != nil { return nil, err } - // We have a public key. + var pub crypto.PublicKey if co.SigVerifier != nil { - pub, err := co.SigVerifier.PublicKey(co.PKOpts...) + pub, err = co.SigVerifier.PublicKey(co.PKOpts...) if err != nil { return nil, err } - return cryptoutils.MarshalPublicKeyToPEM(pub) } - return cryptoutils.MarshalCertificateToPEM(cert) + if cert != nil && co.SigVerifier != nil { + if err := cryptoutils.EqualKeys(cert.PublicKey, pub); err != nil { + return nil, fmt.Errorf("both public key and certificate were provided but did not match") + } + } + + if cert != nil { + return cryptoutils.MarshalCertificateToPEM(cert) + } + return cryptoutils.MarshalPublicKeyToPEM(pub) } // VerifyBlobSignature verifies a blob signature. @@ -997,13 +1021,13 @@ func loadSignatureFromFile(ctx context.Context, sigRef string, signedImgRef name // VerifyImageAttestations does all the main cosign checks in a loop, returning the verified attestations. // If there were no valid attestations, we return an error. -func VerifyImageAttestations(ctx context.Context, signedImgRef name.Reference, co *CheckOpts) (checkedAttestations []oci.Signature, bundleVerified bool, err error) { +func VerifyImageAttestations(ctx context.Context, signedImgRef name.Reference, co *CheckOpts, nameOpts ...name.Option) (checkedAttestations []oci.Signature, bundleVerified bool, err error) { // Enforce this up front. if co.RootCerts == nil && co.SigVerifier == nil && co.TrustedMaterial == nil { return nil, false, errors.New("one of verifier, root certs, or TrustedMaterial is required") } if co.NewBundleFormat { - return verifyImageAttestationsSigstoreBundle(ctx, signedImgRef, co) + return verifyImageAttestationsSigstoreBundle(ctx, signedImgRef, co, nameOpts...) } // This is a carefully optimized sequence for fetching the attestations of @@ -1081,6 +1105,9 @@ func VerifyBlobAttestation(ctx context.Context, att oci.Signature, h v1.Hash, co } func VerifyImageAttestation(ctx context.Context, atts oci.Signatures, h v1.Hash, co *CheckOpts) (checkedAttestations []oci.Signature, bundleVerified bool, err error) { + if atts == nil { + return nil, false, errors.New("no attestations provided") + } sl, err := atts.Get() if err != nil { return nil, false, err @@ -1602,10 +1629,10 @@ func verifyImageSignaturesExperimentalOCI(ctx context.Context, signedImgRef name return verifySignatures(ctx, sigs, h, co) } -func getBundles(_ context.Context, signedImgRef name.Reference, co *CheckOpts) ([]*sgbundle.Bundle, *v1.Hash, error) { +func GetBundles(_ context.Context, signedImgRef name.Reference, registryClientOpts []ociremote.Option, nameOpts ...name.Option) ([]*sgbundle.Bundle, *v1.Hash, error) { // This is a carefully optimized sequence for fetching the signatures of the // entity that minimizes registry requests when supplied with a digest input - digest, err := ociremote.ResolveDigest(signedImgRef, co.RegistryClientOpts...) + digest, err := ociremote.ResolveDigest(signedImgRef, registryClientOpts...) if err != nil { if terr := (&transport.Error{}); errors.As(err, &terr) && terr.StatusCode == http.StatusNotFound { return nil, nil, &ErrImageTagNotFound{ @@ -1619,17 +1646,17 @@ func getBundles(_ context.Context, signedImgRef name.Reference, co *CheckOpts) ( return nil, nil, err } - index, err := ociremote.Referrers(digest, "", co.RegistryClientOpts...) + index, err := ociremote.Referrers(digest, "", registryClientOpts...) if err != nil { return nil, nil, err } var bundles = make([]*sgbundle.Bundle, 0, len(index.Manifests)) for _, result := range index.Manifests { - st, err := name.ParseReference(fmt.Sprintf("%s@%s", digest.Repository, result.Digest.String())) + st, err := name.ParseReference(fmt.Sprintf("%s@%s", digest.Repository, result.Digest.String()), nameOpts...) if err != nil { return nil, nil, err } - bundle, err := ociremote.Bundle(st, co.RegistryClientOpts...) + bundle, err := ociremote.Bundle(st, registryClientOpts...) if err != nil { // There may be non-Sigstore referrers in the index, so we can ignore them. // TODO: Should we surface any errors here (e.g. if the bundle is invalid)? @@ -1648,8 +1675,8 @@ func getBundles(_ context.Context, signedImgRef name.Reference, co *CheckOpts) ( } // verifyImageAttestationsSigstoreBundle verifies attestations from attached sigstore bundles -func verifyImageAttestationsSigstoreBundle(ctx context.Context, signedImgRef name.Reference, co *CheckOpts) (checkedAttestations []oci.Signature, atLeastOneBundleVerified bool, err error) { - bundles, hash, err := getBundles(ctx, signedImgRef, co) +func verifyImageAttestationsSigstoreBundle(ctx context.Context, signedImgRef name.Reference, co *CheckOpts, nameOpts ...name.Option) (checkedAttestations []oci.Signature, atLeastOneBundleVerified bool, err error) { + bundles, hash, err := GetBundles(ctx, signedImgRef, co.RegistryClientOpts, nameOpts...) if err != nil { return nil, false, err } @@ -1697,6 +1724,11 @@ func verifyImageAttestationsSigstoreBundle(ctx context.Context, signedImgRef nam if err != nil { return err } + if co.ClaimVerifier != nil { + if err := co.ClaimVerifier(att, *hash, co.Annotations); err != nil { + return err + } + } bundlesVerified[index] = true return err diff --git a/pkg/cosign/verify_bundle_test.go b/pkg/cosign/verify_bundle_test.go index a1c705c0362..57cdcb286a5 100644 --- a/pkg/cosign/verify_bundle_test.go +++ b/pkg/cosign/verify_bundle_test.go @@ -27,7 +27,7 @@ import ( "fmt" "testing" - "github.com/sigstore/cosign/v2/pkg/cosign" + "github.com/sigstore/cosign/v3/pkg/cosign" protobundle "github.com/sigstore/protobuf-specs/gen/pb-go/bundle/v1" protocommon "github.com/sigstore/protobuf-specs/gen/pb-go/common/v1" sgbundle "github.com/sigstore/sigstore-go/pkg/bundle" @@ -43,6 +43,7 @@ type bundleMutator struct { eraseTSA bool eraseTlog bool + eraseSET bool } func (b *bundleMutator) Timestamps() ([][]byte, error) { @@ -56,6 +57,21 @@ func (b *bundleMutator) TlogEntries() ([]*tlog.Entry, error) { if b.eraseTlog { return []*tlog.Entry{}, nil } + if b.eraseSET { + var entries []*tlog.Entry + oldEntries, err := b.SignedEntity.TlogEntries() + if err != nil { + return nil, err + } + for _, entry := range oldEntries { + mutEntry, err := tlog.NewEntry([]byte(entry.Body().(string)), entry.IntegratedTime().Unix(), entry.LogIndex(), []byte(entry.LogKeyID()), []byte{}, nil) + if err != nil { + return nil, err + } + entries = append(entries, mutEntry) + } + return entries, nil + } return b.SignedEntity.TlogEntries() } @@ -262,6 +278,19 @@ func TestVerifyBundle(t *testing.T) { entity: &bundleMutator{SignedEntity: attestation, eraseTlog: true}, wantErr: true, }, + { + name: "require SET, missing set", + checkOpts: &cosign.CheckOpts{ + Identities: standardIdentities, + IgnoreSCT: true, + IgnoreTlog: false, + UseSignedTimestamps: false, // both set to false requires an SET + TrustedMaterial: virtualSigstore, + }, + artifactPolicyOption: verify.WithArtifact(bytes.NewReader(artifact)), + entity: &bundleMutator{SignedEntity: attestation, eraseSET: true}, + wantErr: true, + }, { name: "require tsa, missing tsa", checkOpts: &cosign.CheckOpts{ diff --git a/pkg/cosign/verify_oci_test.go b/pkg/cosign/verify_oci_test.go index aa80eabf981..3ad8690b998 100644 --- a/pkg/cosign/verify_oci_test.go +++ b/pkg/cosign/verify_oci_test.go @@ -30,7 +30,7 @@ import ( "github.com/stretchr/testify/assert" "google.golang.org/protobuf/proto" - ociremote "github.com/sigstore/cosign/v2/pkg/oci/remote" + ociremote "github.com/sigstore/cosign/v3/pkg/oci/remote" sgbundle "github.com/sigstore/sigstore-go/pkg/bundle" "github.com/sigstore/sigstore-go/pkg/root" ) @@ -53,7 +53,7 @@ func TestGetBundles_Empty(t *testing.T) { assert.NoError(t, err) // If tag doesn't exist, should return ErrImageTagNotFound - bundles, hash, err := getBundles(context.Background(), ref, &CheckOpts{}) + bundles, hash, err := GetBundles(context.Background(), ref, []ociremote.Option{}) imgTagNotFound := &ErrImageTagNotFound{} assert.ErrorAs(t, err, &imgTagNotFound) assert.Len(t, bundles, 0) @@ -65,7 +65,7 @@ func TestGetBundles_Empty(t *testing.T) { assert.NoError(t, remote.Write(ref, img)) // Check that no matching attestation error is returned - bundles, hash, err = getBundles(context.Background(), ref, &CheckOpts{}) + bundles, hash, err = GetBundles(context.Background(), ref, []ociremote.Option{}) var noMatchErr *ErrNoMatchingAttestations assert.ErrorAs(t, err, &noMatchErr) assert.Len(t, bundles, 0) @@ -81,7 +81,7 @@ func TestGetBundles_Empty(t *testing.T) { assert.NoError(t, err) // Should still return no matching attestation error, as it failed to parse the bundle - bundles, hash, err = getBundles(context.Background(), ref, &CheckOpts{}) + bundles, hash, err = GetBundles(context.Background(), ref, []ociremote.Option{}) assert.ErrorAs(t, err, &noMatchErr) assert.Len(t, bundles, 0) assert.Nil(t, hash) @@ -111,7 +111,7 @@ func TestGetBundles_Valid(t *testing.T) { assert.NoError(t, err) // Retrieve the attestation - bundles, hash, err := getBundles(context.Background(), ref, &CheckOpts{}) + bundles, hash, err := GetBundles(context.Background(), ref, []ociremote.Option{}) assert.NoError(t, err) assert.Len(t, bundles, 1) assert.NotNil(t, hash) diff --git a/pkg/cosign/verify_sct.go b/pkg/cosign/verify_sct.go index 444c488149c..fc5e7d75051 100644 --- a/pkg/cosign/verify_sct.go +++ b/pkg/cosign/verify_sct.go @@ -25,7 +25,7 @@ import ( ct "github.com/google/certificate-transparency-go" ctx509 "github.com/google/certificate-transparency-go/x509" "github.com/google/certificate-transparency-go/x509util" - "github.com/sigstore/cosign/v2/pkg/cosign/fulcioverifier/ctutil" + "github.com/sigstore/cosign/v3/pkg/cosign/fulcioverifier/ctutil" "github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/sigstore/sigstore/pkg/tuf" diff --git a/pkg/cosign/verify_test.go b/pkg/cosign/verify_test.go index a1dad623084..47fc9212b25 100644 --- a/pkg/cosign/verify_test.go +++ b/pkg/cosign/verify_test.go @@ -40,19 +40,19 @@ import ( "github.com/cyberphone/json-canonicalization/go/src/webpki.org/jsoncanonicalizer" "github.com/go-openapi/strfmt" - "github.com/go-openapi/swag" + "github.com/go-openapi/swag/conv" v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/in-toto/in-toto-golang/in_toto" "github.com/secure-systems-lab/go-securesystemslib/dsse" - "github.com/sigstore/cosign/v2/internal/pkg/cosign/payload" - "github.com/sigstore/cosign/v2/internal/pkg/cosign/rekor/mock" - "github.com/sigstore/cosign/v2/internal/pkg/cosign/tsa" - tsaMock "github.com/sigstore/cosign/v2/internal/pkg/cosign/tsa/mock" - "github.com/sigstore/cosign/v2/pkg/cosign/bundle" - "github.com/sigstore/cosign/v2/pkg/oci" - "github.com/sigstore/cosign/v2/pkg/oci/static" - "github.com/sigstore/cosign/v2/pkg/types" - "github.com/sigstore/cosign/v2/test" + "github.com/sigstore/cosign/v3/internal/pkg/cosign/payload" + "github.com/sigstore/cosign/v3/internal/pkg/cosign/rekor/mock" + "github.com/sigstore/cosign/v3/internal/pkg/cosign/tsa" + tsaMock "github.com/sigstore/cosign/v3/internal/pkg/cosign/tsa/mock" + "github.com/sigstore/cosign/v3/internal/test" + "github.com/sigstore/cosign/v3/pkg/cosign/bundle" + "github.com/sigstore/cosign/v3/pkg/oci" + "github.com/sigstore/cosign/v3/pkg/oci/static" + "github.com/sigstore/cosign/v3/pkg/types" "github.com/sigstore/rekor/pkg/generated/client" "github.com/sigstore/rekor/pkg/generated/client/entries" "github.com/sigstore/rekor/pkg/generated/models" @@ -326,6 +326,57 @@ func TestVerifyImageSignatureWithNoChain(t *testing.T) { t.Fatalf("expected verified=true, got verified=false") } } + +func TestVerifyImageSignatureWithKeyAndCert(t *testing.T) { + ctx := context.Background() + rootCert, rootKey, _ := test.GenerateRootCa() + sv, _, err := signature.NewECDSASignerVerifier(elliptic.P256(), rand.Reader, crypto.SHA256) + if err != nil { + t.Fatalf("creating signer: %v", err) + } + + leafCert, privKey, _ := test.GenerateLeafCert("subject@mail.com", "oidc-issuer", rootCert, rootKey) + pemLeaf := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: leafCert.Raw}) + + rootPool := x509.NewCertPool() + rootPool.AddCert(rootCert) + + payload := []byte{1, 2, 3, 4} + h := sha256.Sum256(payload) + sig, _ := privKey.Sign(rand.Reader, h[:], crypto.SHA256) + + // Create a fake bundle + pe, _ := proposedEntries(base64.StdEncoding.EncodeToString(sig), payload, pemLeaf) + entry, _ := rtypes.UnmarshalEntry(pe[0]) + leaf, _ := entry.Canonicalize(ctx) + rekorBundle := CreateTestBundle(ctx, t, sv, leaf) + pemBytes, _ := cryptoutils.MarshalPublicKeyToPEM(sv.Public()) + rekorPubKeys := NewTrustedTransparencyLogPubKeys() + rekorPubKeys.AddTransparencyLogPubKey(pemBytes, tuf.Active) + + opts := []static.Option{static.WithCertChain(pemLeaf, []byte{}), static.WithBundle(rekorBundle)} + ociSig, _ := static.NewSignature(payload, base64.StdEncoding.EncodeToString(sig), opts...) + + leafSV, err := signature.LoadECDSASignerVerifier(privKey, crypto.SHA256) + if err != nil { + t.Fatal(err) + } + + verified, err := VerifyImageSignature(context.TODO(), ociSig, v1.Hash{}, + &CheckOpts{ + SigVerifier: leafSV, + RootCerts: rootPool, + IgnoreSCT: true, + Identities: []Identity{{Subject: "subject@mail.com", Issuer: "oidc-issuer"}}, + RekorPubKeys: &rekorPubKeys}) + if err != nil { + t.Fatalf("unexpected error %v", err) + } + if verified == false { + t.Fatalf("expected verified=true, got verified=false") + } +} + func TestVerifyImageSignatureWithInvalidPublicKeyType(t *testing.T) { ctx := context.Background() rootCert, rootKey, _ := test.GenerateRootCa() @@ -1648,6 +1699,12 @@ func TestVerifyRFC3161Timestamp(t *testing.T) { } } +func TestVerifyImageAttestation(t *testing.T) { + if _, _, err := VerifyImageAttestation(context.TODO(), nil, v1.Hash{}, nil); err == nil { + t.Error("VerifyImageAttestation() should error when given nil attestations") + } +} + // Mock Rekor client type mockEntriesClient struct { entries.ClientService @@ -1689,9 +1746,9 @@ func createRekorEntry(ctx context.Context, t *testing.T, logID string, signer si integratedTime := time.Now().Unix() logEntry := models.LogEntryAnon{ Body: base64.StdEncoding.EncodeToString(canonicalEntry), - IntegratedTime: swag.Int64(integratedTime), - LogIndex: swag.Int64(0), - LogID: swag.String(logID), + IntegratedTime: conv.Pointer(integratedTime), + LogIndex: conv.Pointer(int64(0)), + LogID: conv.Pointer(logID), } // Canonicalize the log entry and sign it @@ -1711,9 +1768,9 @@ func createRekorEntry(ctx context.Context, t *testing.T, logID string, signer si logEntry.Verification = &models.LogEntryAnonVerification{ SignedEntryTimestamp: signedEntryTimestamp, InclusionProof: &models.InclusionProof{ - LogIndex: swag.Int64(0), - TreeSize: swag.Int64(1), - RootHash: swag.String(hex.EncodeToString(entryUUID)), + LogIndex: conv.Pointer(int64(0)), + TreeSize: conv.Pointer(int64(1)), + RootHash: conv.Pointer(hex.EncodeToString(entryUUID)), Hashes: []string{}, }, } diff --git a/pkg/oci/empty/empty.go b/pkg/oci/empty/empty.go index 599ad08f8ef..65d86542378 100644 --- a/pkg/oci/empty/empty.go +++ b/pkg/oci/empty/empty.go @@ -21,7 +21,7 @@ import ( "github.com/google/go-containerregistry/pkg/v1/mutate" "github.com/google/go-containerregistry/pkg/v1/types" - "github.com/sigstore/cosign/v2/pkg/oci" + "github.com/sigstore/cosign/v3/pkg/oci" ) // Signatures constructs an empty oci.Signatures. diff --git a/pkg/oci/empty/empty_test.go b/pkg/oci/empty/empty_test.go index c9aad1fc23d..ba123ca61ff 100644 --- a/pkg/oci/empty/empty_test.go +++ b/pkg/oci/empty/empty_test.go @@ -21,7 +21,7 @@ import ( "github.com/google/go-containerregistry/pkg/v1/types" - "github.com/sigstore/cosign/v2/pkg/cosign/env" + "github.com/sigstore/cosign/v3/pkg/cosign/env" ) func TestEmptyImage(t *testing.T) { diff --git a/pkg/oci/empty/signed.go b/pkg/oci/empty/signed.go index 9847e128c4a..385ed0e2b5d 100644 --- a/pkg/oci/empty/signed.go +++ b/pkg/oci/empty/signed.go @@ -22,7 +22,7 @@ import ( "github.com/google/go-containerregistry/pkg/name" v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/empty" - "github.com/sigstore/cosign/v2/pkg/oci" + "github.com/sigstore/cosign/v3/pkg/oci" ) type signedImage struct { diff --git a/pkg/oci/internal/signature/layer.go b/pkg/oci/internal/signature/layer.go index 4bd5e456c77..8106e983558 100644 --- a/pkg/oci/internal/signature/layer.go +++ b/pkg/oci/internal/signature/layer.go @@ -24,9 +24,9 @@ import ( "strings" v1 "github.com/google/go-containerregistry/pkg/v1" - payloadsize "github.com/sigstore/cosign/v2/internal/pkg/cosign/payload/size" - "github.com/sigstore/cosign/v2/pkg/cosign/bundle" - "github.com/sigstore/cosign/v2/pkg/oci" + payloadsize "github.com/sigstore/cosign/v3/internal/pkg/cosign/payload/size" + "github.com/sigstore/cosign/v3/pkg/cosign/bundle" + "github.com/sigstore/cosign/v3/pkg/oci" "github.com/sigstore/sigstore/pkg/cryptoutils" ) diff --git a/pkg/oci/internal/signature/layer_test.go b/pkg/oci/internal/signature/layer_test.go index d3895f9c42a..ef61de523b1 100644 --- a/pkg/oci/internal/signature/layer_test.go +++ b/pkg/oci/internal/signature/layer_test.go @@ -28,7 +28,7 @@ import ( v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/random" "github.com/google/go-containerregistry/pkg/v1/types" - "github.com/sigstore/cosign/v2/pkg/cosign/bundle" + "github.com/sigstore/cosign/v3/pkg/cosign/bundle" ) func mustDecode(s string) []byte { diff --git a/pkg/oci/layout/index.go b/pkg/oci/layout/index.go index 1242740dc69..e122301a6af 100644 --- a/pkg/oci/layout/index.go +++ b/pkg/oci/layout/index.go @@ -20,8 +20,8 @@ import ( v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/layout" - "github.com/sigstore/cosign/v2/pkg/oci" - "github.com/sigstore/cosign/v2/pkg/oci/signed" + "github.com/sigstore/cosign/v3/pkg/oci" + "github.com/sigstore/cosign/v3/pkg/oci/signed" ) const ( diff --git a/pkg/oci/layout/signatures.go b/pkg/oci/layout/signatures.go index 80541f11a07..ca169d46757 100644 --- a/pkg/oci/layout/signatures.go +++ b/pkg/oci/layout/signatures.go @@ -17,8 +17,8 @@ package layout import ( v1 "github.com/google/go-containerregistry/pkg/v1" - "github.com/sigstore/cosign/v2/pkg/oci" - "github.com/sigstore/cosign/v2/pkg/oci/internal/signature" + "github.com/sigstore/cosign/v3/pkg/oci" + "github.com/sigstore/cosign/v3/pkg/oci/internal/signature" ) const maxLayers = 1000 diff --git a/pkg/oci/layout/write.go b/pkg/oci/layout/write.go index c3c8c2055d7..2917d5f5e44 100644 --- a/pkg/oci/layout/write.go +++ b/pkg/oci/layout/write.go @@ -21,7 +21,7 @@ import ( v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/empty" "github.com/google/go-containerregistry/pkg/v1/layout" - "github.com/sigstore/cosign/v2/pkg/oci" + "github.com/sigstore/cosign/v3/pkg/oci" ) // WriteSignedImage writes the image and all related signatures, attestations and attachments diff --git a/pkg/oci/layout/write_test.go b/pkg/oci/layout/write_test.go index 823a27329f0..8e47254c358 100644 --- a/pkg/oci/layout/write_test.go +++ b/pkg/oci/layout/write_test.go @@ -23,15 +23,15 @@ import ( "github.com/google/go-cmp/cmp" v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/random" - "github.com/sigstore/cosign/v2/pkg/oci" - "github.com/sigstore/cosign/v2/pkg/oci/mutate" - "github.com/sigstore/cosign/v2/pkg/oci/signed" - "github.com/sigstore/cosign/v2/pkg/oci/static" + "github.com/sigstore/cosign/v3/pkg/oci" + "github.com/sigstore/cosign/v3/pkg/oci/mutate" + "github.com/sigstore/cosign/v3/pkg/oci/signed" + "github.com/sigstore/cosign/v3/pkg/oci/static" ) func TestReadWrite(t *testing.T) { if runtime.GOOS == "windows" { - t.Skip("test is flaky on windows, see https://github.com/sigstore/cosign/v2/issues/1389") + t.Skip("test is flaky on windows, see https://github.com/sigstore/cosign/issues/1389") } // write random signed image to disk si := randomSignedImage(t) diff --git a/pkg/oci/mediatypes.go b/pkg/oci/mediatypes.go index a189047720b..c23862f9b69 100644 --- a/pkg/oci/mediatypes.go +++ b/pkg/oci/mediatypes.go @@ -18,7 +18,7 @@ package oci import ( "strconv" - "github.com/sigstore/cosign/v2/pkg/cosign/env" + "github.com/sigstore/cosign/v3/pkg/cosign/env" ) const ( diff --git a/pkg/oci/mutate/map.go b/pkg/oci/mutate/map.go index 8c31fc1892b..8af264aa4c8 100644 --- a/pkg/oci/mutate/map.go +++ b/pkg/oci/mutate/map.go @@ -24,7 +24,7 @@ import ( "github.com/google/go-containerregistry/pkg/v1/empty" "github.com/google/go-containerregistry/pkg/v1/mutate" "github.com/google/go-containerregistry/pkg/v1/types" - "github.com/sigstore/cosign/v2/pkg/oci" + "github.com/sigstore/cosign/v3/pkg/oci" ) // Fn is the signature of the callback supplied to Map. diff --git a/pkg/oci/mutate/map_test.go b/pkg/oci/mutate/map_test.go index b243de17c85..d1cbe585ff3 100644 --- a/pkg/oci/mutate/map_test.go +++ b/pkg/oci/mutate/map_test.go @@ -23,8 +23,8 @@ import ( "github.com/google/go-containerregistry/pkg/v1/mutate" "github.com/google/go-containerregistry/pkg/v1/random" "github.com/google/go-containerregistry/pkg/v1/types" - "github.com/sigstore/cosign/v2/pkg/oci" - "github.com/sigstore/cosign/v2/pkg/oci/signed" + "github.com/sigstore/cosign/v3/pkg/oci" + "github.com/sigstore/cosign/v3/pkg/oci/signed" ) func TestMapImage(t *testing.T) { diff --git a/pkg/oci/mutate/mutate.go b/pkg/oci/mutate/mutate.go index 59ba2c0c0ff..f7e83087b3b 100644 --- a/pkg/oci/mutate/mutate.go +++ b/pkg/oci/mutate/mutate.go @@ -21,9 +21,9 @@ import ( v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/mutate" - "github.com/sigstore/cosign/v2/pkg/oci" - "github.com/sigstore/cosign/v2/pkg/oci/empty" - "github.com/sigstore/cosign/v2/pkg/oci/signed" + "github.com/sigstore/cosign/v3/pkg/oci" + "github.com/sigstore/cosign/v3/pkg/oci/empty" + "github.com/sigstore/cosign/v3/pkg/oci/signed" ) // Appendable is our signed version of mutate.Appendable diff --git a/pkg/oci/mutate/mutate_test.go b/pkg/oci/mutate/mutate_test.go index b0e85be2a43..f6e93e39055 100644 --- a/pkg/oci/mutate/mutate_test.go +++ b/pkg/oci/mutate/mutate_test.go @@ -25,9 +25,9 @@ import ( v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/mutate" "github.com/google/go-containerregistry/pkg/v1/random" - "github.com/sigstore/cosign/v2/pkg/oci" - "github.com/sigstore/cosign/v2/pkg/oci/signed" - "github.com/sigstore/cosign/v2/pkg/oci/static" + "github.com/sigstore/cosign/v3/pkg/oci" + "github.com/sigstore/cosign/v3/pkg/oci/signed" + "github.com/sigstore/cosign/v3/pkg/oci/static" ) func TestAppendManifests(t *testing.T) { diff --git a/pkg/oci/mutate/options.go b/pkg/oci/mutate/options.go index 342eea4e7c5..9299cfd223a 100644 --- a/pkg/oci/mutate/options.go +++ b/pkg/oci/mutate/options.go @@ -17,8 +17,8 @@ package mutate import ( "github.com/google/go-containerregistry/pkg/v1/types" - "github.com/sigstore/cosign/v2/pkg/cosign/bundle" - "github.com/sigstore/cosign/v2/pkg/oci" + "github.com/sigstore/cosign/v3/pkg/cosign/bundle" + "github.com/sigstore/cosign/v3/pkg/oci" ) // DupeDetector scans a list of signatures looking for a duplicate. diff --git a/pkg/oci/mutate/signature.go b/pkg/oci/mutate/signature.go index f9b36a03abb..ad1cd018518 100644 --- a/pkg/oci/mutate/signature.go +++ b/pkg/oci/mutate/signature.go @@ -23,9 +23,9 @@ import ( v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/types" - "github.com/sigstore/cosign/v2/pkg/cosign/bundle" - "github.com/sigstore/cosign/v2/pkg/oci" - "github.com/sigstore/cosign/v2/pkg/oci/static" + "github.com/sigstore/cosign/v3/pkg/cosign/bundle" + "github.com/sigstore/cosign/v3/pkg/oci" + "github.com/sigstore/cosign/v3/pkg/oci/static" "github.com/sigstore/sigstore/pkg/cryptoutils" ) diff --git a/pkg/oci/mutate/signature_test.go b/pkg/oci/mutate/signature_test.go index 578fe4fcbd7..ba4a1f6daf3 100644 --- a/pkg/oci/mutate/signature_test.go +++ b/pkg/oci/mutate/signature_test.go @@ -21,9 +21,9 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-containerregistry/pkg/v1/types" - "github.com/sigstore/cosign/v2/pkg/cosign/bundle" - "github.com/sigstore/cosign/v2/pkg/oci" - "github.com/sigstore/cosign/v2/pkg/oci/static" + "github.com/sigstore/cosign/v3/pkg/cosign/bundle" + "github.com/sigstore/cosign/v3/pkg/oci" + "github.com/sigstore/cosign/v3/pkg/oci/static" ) var ( diff --git a/pkg/oci/mutate/signatures.go b/pkg/oci/mutate/signatures.go index 75a1053802e..ede9f678ffd 100644 --- a/pkg/oci/mutate/signatures.go +++ b/pkg/oci/mutate/signatures.go @@ -18,9 +18,9 @@ package mutate import ( v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/mutate" - "github.com/sigstore/cosign/v2/internal/pkg/now" - "github.com/sigstore/cosign/v2/pkg/oci" - "github.com/sigstore/cosign/v2/pkg/oci/empty" + "github.com/sigstore/cosign/v3/internal/pkg/now" + "github.com/sigstore/cosign/v3/pkg/oci" + "github.com/sigstore/cosign/v3/pkg/oci/empty" ) const maxLayers = 1000 diff --git a/pkg/oci/mutate/signatures_test.go b/pkg/oci/mutate/signatures_test.go index 1a0bf6d5a69..6c525e11eee 100644 --- a/pkg/oci/mutate/signatures_test.go +++ b/pkg/oci/mutate/signatures_test.go @@ -21,9 +21,9 @@ import ( v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/types" - "github.com/sigstore/cosign/v2/pkg/oci" - "github.com/sigstore/cosign/v2/pkg/oci/empty" - "github.com/sigstore/cosign/v2/pkg/oci/static" + "github.com/sigstore/cosign/v3/pkg/oci" + "github.com/sigstore/cosign/v3/pkg/oci/empty" + "github.com/sigstore/cosign/v3/pkg/oci/static" ) func TestAppendSignatures(t *testing.T) { diff --git a/pkg/oci/platform/platform.go b/pkg/oci/platform/platform.go index a2939d73660..b06e754fd00 100644 --- a/pkg/oci/platform/platform.go +++ b/pkg/oci/platform/platform.go @@ -19,7 +19,7 @@ import ( "strings" v1 "github.com/google/go-containerregistry/pkg/v1" - "github.com/sigstore/cosign/v2/pkg/oci" + "github.com/sigstore/cosign/v3/pkg/oci" ) type List []struct { diff --git a/pkg/oci/remote/image.go b/pkg/oci/remote/image.go index 8c6eda5ff0e..30d30a7d53d 100644 --- a/pkg/oci/remote/image.go +++ b/pkg/oci/remote/image.go @@ -23,7 +23,7 @@ import ( v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/partial" "github.com/google/go-containerregistry/pkg/v1/remote/transport" - "github.com/sigstore/cosign/v2/pkg/oci" + "github.com/sigstore/cosign/v3/pkg/oci" ) var ErrImageNotFound = errors.New("image not found in registry") diff --git a/pkg/oci/remote/index.go b/pkg/oci/remote/index.go index 6269e9bfaaf..0aad7480d7f 100644 --- a/pkg/oci/remote/index.go +++ b/pkg/oci/remote/index.go @@ -22,7 +22,7 @@ import ( "github.com/google/go-containerregistry/pkg/name" v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/remote/transport" - "github.com/sigstore/cosign/v2/pkg/oci" + "github.com/sigstore/cosign/v3/pkg/oci" ) // SignedImageIndex provides access to a remote index reference, and its signatures. diff --git a/pkg/oci/remote/index_test.go b/pkg/oci/remote/index_test.go index 93e841808c9..8ef16012c35 100644 --- a/pkg/oci/remote/index_test.go +++ b/pkg/oci/remote/index_test.go @@ -25,7 +25,7 @@ import ( "github.com/google/go-containerregistry/pkg/v1/random" "github.com/google/go-containerregistry/pkg/v1/remote" "github.com/google/go-containerregistry/pkg/v1/types" - "github.com/sigstore/cosign/v2/pkg/oci" + "github.com/sigstore/cosign/v3/pkg/oci" ) func TestSignedImageIndex(t *testing.T) { diff --git a/pkg/oci/remote/options.go b/pkg/oci/remote/options.go index 6eeaadd0105..c29c2970aeb 100644 --- a/pkg/oci/remote/options.go +++ b/pkg/oci/remote/options.go @@ -21,7 +21,7 @@ import ( "github.com/google/go-containerregistry/pkg/authn" "github.com/google/go-containerregistry/pkg/name" "github.com/google/go-containerregistry/pkg/v1/remote" - "github.com/sigstore/cosign/v2/pkg/cosign/env" + "github.com/sigstore/cosign/v3/pkg/cosign/env" ) const ( diff --git a/pkg/oci/remote/remote.go b/pkg/oci/remote/remote.go index eab4e1f9b01..ad554ced1ea 100644 --- a/pkg/oci/remote/remote.go +++ b/pkg/oci/remote/remote.go @@ -26,17 +26,20 @@ import ( "github.com/google/go-containerregistry/pkg/v1/remote" "github.com/google/go-containerregistry/pkg/v1/remote/transport" "github.com/google/go-containerregistry/pkg/v1/types" - payloadsize "github.com/sigstore/cosign/v2/internal/pkg/cosign/payload/size" - ociexperimental "github.com/sigstore/cosign/v2/internal/pkg/oci/remote" - "github.com/sigstore/cosign/v2/pkg/oci" + payloadsize "github.com/sigstore/cosign/v3/internal/pkg/cosign/payload/size" + ociexperimental "github.com/sigstore/cosign/v3/internal/pkg/oci/remote" + "github.com/sigstore/cosign/v3/pkg/oci" ) // These enable mocking for unit testing without faking an entire registry. var ( - remoteImage = remote.Image - remoteIndex = remote.Index - remoteGet = remote.Get - remoteWrite = remote.Write + remoteImage = remote.Image + remoteIndex = remote.Index + remoteGet = remote.Get + remoteWrite = remote.Write + remoteHead = remote.Head + remoteWriteLayer = remote.WriteLayer + remotePut = remote.Put ) // EntityNotFoundError is the error that SignedEntity returns when the diff --git a/pkg/oci/remote/signatures.go b/pkg/oci/remote/signatures.go index bde786ae28c..24a3e4dc8e6 100644 --- a/pkg/oci/remote/signatures.go +++ b/pkg/oci/remote/signatures.go @@ -25,9 +25,9 @@ import ( v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/partial" "github.com/google/go-containerregistry/pkg/v1/remote/transport" - "github.com/sigstore/cosign/v2/pkg/oci" - "github.com/sigstore/cosign/v2/pkg/oci/empty" - "github.com/sigstore/cosign/v2/pkg/oci/internal/signature" + "github.com/sigstore/cosign/v3/pkg/oci" + "github.com/sigstore/cosign/v3/pkg/oci/empty" + "github.com/sigstore/cosign/v3/pkg/oci/internal/signature" sgbundle "github.com/sigstore/sigstore-go/pkg/bundle" ) diff --git a/pkg/oci/remote/unknown.go b/pkg/oci/remote/unknown.go index 90a0fc9acb1..8ddb9f5a045 100644 --- a/pkg/oci/remote/unknown.go +++ b/pkg/oci/remote/unknown.go @@ -18,7 +18,7 @@ package remote import ( "github.com/google/go-containerregistry/pkg/name" v1 "github.com/google/go-containerregistry/pkg/v1" - "github.com/sigstore/cosign/v2/pkg/oci" + "github.com/sigstore/cosign/v3/pkg/oci" ) // SignedUnknown provides access to signed metadata without directly accessing diff --git a/pkg/oci/remote/write.go b/pkg/oci/remote/write.go index d353c6b0883..28f1aec2e86 100644 --- a/pkg/oci/remote/write.go +++ b/pkg/oci/remote/write.go @@ -20,24 +20,29 @@ import ( "encoding/json" "fmt" "os" + "path/filepath" + "strings" "time" "github.com/google/go-containerregistry/pkg/name" v1 "github.com/google/go-containerregistry/pkg/v1" - "github.com/google/go-containerregistry/pkg/v1/remote" + goremote "github.com/google/go-containerregistry/pkg/v1/remote" "github.com/google/go-containerregistry/pkg/v1/static" "github.com/google/go-containerregistry/pkg/v1/types" - ociexperimental "github.com/sigstore/cosign/v2/internal/pkg/oci/remote" - "github.com/sigstore/cosign/v2/pkg/oci" - ctypes "github.com/sigstore/cosign/v2/pkg/types" + ociexperimental "github.com/sigstore/cosign/v3/internal/pkg/oci/remote" + "github.com/sigstore/cosign/v3/pkg/cosign/bundle" + "github.com/sigstore/cosign/v3/pkg/oci" + ctypes "github.com/sigstore/cosign/v3/pkg/types" sgbundle "github.com/sigstore/sigstore-go/pkg/bundle" ) +const BundlePredicateType string = "dev.sigstore.bundle.predicateType" + // WriteSignedImageIndexImages writes the images within the image index // This includes the signed image and associated signatures in the image index // TODO (priyawadhwa@): write the `index.json` itself to the repo as well // TODO (priyawadhwa@): write the attestations -func WriteSignedImageIndexImages(ref name.Reference, sii oci.SignedImageIndex, opts ...Option) error { +func WriteSignedImageIndexImages(ref name.Reference, sii oci.SignedImageIndex, directory string, opts ...Option) error { repo := ref.Context() o := makeOptions(repo, opts...) @@ -47,7 +52,7 @@ func WriteSignedImageIndexImages(ref name.Reference, sii oci.SignedImageIndex, o return fmt.Errorf("signed image index: %w", err) } if ii != nil { - if err := remote.WriteIndex(ref, ii, o.ROpt...); err != nil { + if err := goremote.WriteIndex(ref, ii, o.ROpt...); err != nil { return fmt.Errorf("writing index: %w", err) } } @@ -90,6 +95,74 @@ func WriteSignedImageIndexImages(ref name.Reference, sii oci.SignedImageIndex, o } return remoteWrite(attsTag, atts, o.ROpt...) } + + // Look for any referring artifacts + digest, ok := ref.(name.Digest) + if !ok { + var err error + digest, err = ResolveDigest(ref, opts...) + if err != nil { + return fmt.Errorf("resolving digest: %w", err) + } + } + blobPath := filepath.Join(directory, "blobs", "sha256") + + files, err := os.ReadDir(blobPath) + if err != nil { + return err + } + + for _, file := range files { + fd, err := os.Open(filepath.Join(blobPath, file.Name())) + if err != nil { + return err + } + manifest, err := v1.ParseManifest(fd) + if err != nil || manifest.Subject == nil { + continue + } + if strings.Compare(manifest.Subject.Digest.String(), digest.DigestStr()) == 0 { + // Get the predicate type + predicateType := "" + if manifest.Annotations != nil { + if v, ok := manifest.Annotations[BundlePredicateType]; ok { + predicateType = v + } + } + if predicateType != "" { + // Write the empty layer + _, _, err := writeEmptyConfigLayer(o) + if err != nil { + return err + } + + // Write the manifest + m := referrerManifest{*manifest, bundle.BundleV03MediaType} + targetRef, err := m.targetRef(o.TargetRepository, opts...) + if err != nil { + return fmt.Errorf("failed to create target reference: %w", err) + } + if err := remotePut(targetRef, m, o.ROpt...); err != nil { + return fmt.Errorf("failed to upload manifest: %w", err) + } + + // Write bundle layers + for _, layer := range manifest.Layers { + bundlePath := filepath.Join(directory, "blobs", "sha256", layer.Digest.Hex) + bundleBytes, err := os.ReadFile(bundlePath) + if err != nil { + return err + } + layer := static.NewLayer(bundleBytes, types.MediaType(bundle.BundleV03MediaType)) + err = remoteWriteLayer(o.TargetRepository, layer, o.ROpt...) + if err != nil { + return err + } + } + } + } + } + return nil } @@ -146,7 +219,7 @@ func WriteSignaturesExperimentalOCI(d name.Digest, se oci.SignedEntity, opts ... if err != nil { return err } - desc, err := remote.Head(ref, o.ROpt...) + desc, err := remoteHead(ref, o.ROpt...) if err != nil { return err } @@ -161,7 +234,7 @@ func WriteSignaturesExperimentalOCI(d name.Digest, se oci.SignedEntity, opts ... return err } for _, v := range s { - if err := remote.WriteLayer(d.Repository, v, o.ROpt...); err != nil { + if err := remoteWriteLayer(d.Repository, v, o.ROpt...); err != nil { return err } } @@ -176,7 +249,7 @@ func WriteSignaturesExperimentalOCI(d name.Digest, se oci.SignedEntity, opts ... return err } configLayer := static.NewLayer(configBytes, configDesc.MediaType) - if err := remote.WriteLayer(d.Repository, configLayer, o.ROpt...); err != nil { + if err := remoteWriteLayer(d.Repository, configLayer, o.ROpt...); err != nil { return err } @@ -208,7 +281,7 @@ func WriteSignaturesExperimentalOCI(d name.Digest, se oci.SignedEntity, opts ... // TODO: use ui.Infof fmt.Fprintf(os.Stderr, "Uploading signature for [%s] to [%s] with config.mediaType [%s] layers[0].mediaType [%s].\n", d.String(), targetRef.String(), artifactType, ctypes.SimpleSigningMediaType) - return remote.Put(targetRef, &taggableManifest{raw: b, mediaType: m.MediaType}, o.ROpt...) + return remotePut(targetRef, &taggableManifest{raw: b, mediaType: m.MediaType}, o.ROpt...) } type taggableManifest struct { @@ -224,55 +297,68 @@ func (taggable taggableManifest) MediaType() (types.MediaType, error) { return taggable.mediaType, nil } -func WriteAttestationNewBundleFormat(d name.Digest, bundleBytes []byte, predicateType string, opts ...Option) error { - o := makeOptions(d.Repository, opts...) - - signTarget := d.String() - ref, err := name.ParseReference(signTarget, o.NameOpts...) - if err != nil { - return err - } - desc, err := remote.Head(ref, o.ROpt...) - if err != nil { - return err - } - - // Write the empty config layer +func writeEmptyConfigLayer(o *options) (v1.Hash, int64, error) { configLayer := static.NewLayer([]byte("{}"), "application/vnd.oci.image.config.v1+json") configDigest, err := configLayer.Digest() if err != nil { - return fmt.Errorf("failed to calculate digest: %w", err) + return v1.Hash{}, 0, fmt.Errorf("failed to calculate digest: %w", err) } configSize, err := configLayer.Size() if err != nil { - return fmt.Errorf("failed to calculate size: %w", err) + return v1.Hash{}, 0, fmt.Errorf("failed to calculate size: %w", err) } - err = remote.WriteLayer(d.Repository, configLayer, o.ROpt...) + err = remoteWriteLayer(o.TargetRepository, configLayer, o.ROpt...) if err != nil { - return fmt.Errorf("failed to upload layer: %w", err) + return v1.Hash{}, 0, fmt.Errorf("failed to upload layer: %w", err) } + return configDigest, configSize, nil +} - // generate bundle media type string - bundleMediaType, err := sgbundle.MediaTypeString("0.3") +// WriteReferrer writes a referrer manifest for a given subject digest. +// It uploads the provided layers and creates a manifest that refers to the subject. +func WriteReferrer(d name.Digest, artifactType string, layers []v1.Layer, annotations map[string]string, opts ...Option) error { + o := makeOptions(d.Repository, opts...) + + signTarget := d.String() + ref, err := name.ParseReference(signTarget, o.NameOpts...) if err != nil { - return fmt.Errorf("failed to generate bundle media type string: %w", err) + return err } - - // Write the bundle layer - layer := static.NewLayer(bundleBytes, types.MediaType(bundleMediaType)) - blobDigest, err := layer.Digest() + desc, err := remoteHead(ref, o.ROpt...) if err != nil { - return fmt.Errorf("failed to calculate digest: %w", err) + return err } - blobSize, err := layer.Size() + // Write the empty config layer + configDigest, configSize, err := writeEmptyConfigLayer(o) if err != nil { - return fmt.Errorf("failed to calculate size: %w", err) + return err } - err = remote.WriteLayer(d.Repository, layer, o.ROpt...) - if err != nil { - return fmt.Errorf("failed to upload layer: %w", err) + layerDescriptors := make([]v1.Descriptor, len(layers)) + for i, layer := range layers { + mediaType, err := layer.MediaType() + if err != nil { + return fmt.Errorf("failed to get media type: %w", err) + } + layerDigest, err := layer.Digest() + if err != nil { + return fmt.Errorf("failed to calculate digest: %w", err) + } + layerSize, err := layer.Size() + if err != nil { + return fmt.Errorf("failed to calculate size: %w", err) + } + + err = remoteWriteLayer(o.TargetRepository, layer, o.ROpt...) + if err != nil { + return fmt.Errorf("failed to upload layer: %w", err) + } + layerDescriptors[i] = v1.Descriptor{ + MediaType: mediaType, + Digest: layerDigest, + Size: layerSize, + } } // Create a manifest that includes the blob as a layer @@ -281,42 +367,76 @@ func WriteAttestationNewBundleFormat(d name.Digest, bundleBytes []byte, predicat MediaType: types.OCIManifestSchema1, Config: v1.Descriptor{ MediaType: types.MediaType("application/vnd.oci.empty.v1+json"), - ArtifactType: bundleMediaType, + ArtifactType: artifactType, Digest: configDigest, Size: configSize, }, - Layers: []v1.Descriptor{ - { - MediaType: types.MediaType(bundleMediaType), - Digest: blobDigest, - Size: blobSize, - }, - }, + Layers: layerDescriptors, Subject: &v1.Descriptor{ MediaType: desc.MediaType, Digest: desc.Digest, Size: desc.Size, }, - Annotations: map[string]string{ - "org.opencontainers.image.created": time.Now().UTC().Format(time.RFC3339), - "dev.sigstore.bundle.content": "dsse-envelope", - "dev.sigstore.bundle.predicateType": predicateType, - }, - }, bundleMediaType} + Annotations: annotations, + }, artifactType} - targetRef, err := manifest.targetRef(d.Repository) + targetRef, err := manifest.targetRef(o.TargetRepository, opts...) if err != nil { return fmt.Errorf("failed to create target reference: %w", err) } - if err := remote.Put(targetRef, manifest, o.ROpt...); err != nil { + if err := remotePut(targetRef, manifest, o.ROpt...); err != nil { return fmt.Errorf("failed to upload manifest: %w", err) } return nil } -// referrerManifest implements Taggable for use in remote.Put. +func WriteAttestationNewBundleFormat(d name.Digest, bundleBytes []byte, predicateType string, opts ...Option) error { + // generate bundle media type string + bundleMediaType, err := sgbundle.MediaTypeString("0.3") + if err != nil { + return fmt.Errorf("failed to generate bundle media type string: %w", err) + } + + // Write the bundle layer + layer := static.NewLayer(bundleBytes, types.MediaType(bundleMediaType)) + + annotations := map[string]string{ + "org.opencontainers.image.created": time.Now().UTC().Format(time.RFC3339), + "dev.sigstore.bundle.content": "dsse-envelope", + BundlePredicateType: predicateType, + } + + return WriteReferrer(d, bundleMediaType, []v1.Layer{layer}, annotations, opts...) +} + +// WriteAttestationsReferrer publishes the attestations attached to the given entity +// into the provided repository using the referrers API. +func WriteAttestationsReferrer(d name.Digest, se oci.SignedEntity, opts ...Option) error { + atts, err := se.Attestations() + if err != nil { + return err + } + layers, err := atts.Layers() + if err != nil { + return err + } + + annotations := map[string]string{ + "org.opencontainers.image.created": time.Now().UTC().Format(time.RFC3339), + } + + // We have to pick an artifactType for the referrer manifest. The attestation + // layers themselves are DSSE envelopes, which wrap in-toto statements. + // For discovery, the artifactType should describe the semantic content (the + // in-toto statement) rather than the wrapper format (the DSSE envelope). + // Using the in-toto media type is the most appropriate and conventional choice, + // as policy engines and other tools will query for attestations using this type. + return WriteReferrer(d, ctypes.IntotoPayloadType, layers, annotations, opts...) +} + +// referrerManifest implements Taggable for use in remotePut. // This type also augments the built-in v1.Manifest with an ArtifactType field // which is part of the OCI 1.1 Image Manifest spec but is unsupported by // go-containerregistry at this time. @@ -331,7 +451,8 @@ func (r referrerManifest) RawManifest() ([]byte, error) { return json.Marshal(r) } -func (r referrerManifest) targetRef(repo name.Repository) (name.Reference, error) { +func (r referrerManifest) targetRef(repo name.Repository, opts ...Option) (name.Reference, error) { + o := makeOptions(repo, opts...) manifestBytes, err := r.RawManifest() if err != nil { return nil, err @@ -340,7 +461,7 @@ func (r referrerManifest) targetRef(repo name.Repository) (name.Reference, error if err != nil { return nil, err } - return name.ParseReference(fmt.Sprintf("%s/%s@%s", repo.RegistryStr(), repo.RepositoryStr(), digest.String())) + return name.ParseReference(fmt.Sprintf("%s/%s@%s", repo.RegistryStr(), repo.RepositoryStr(), digest.String()), o.NameOpts...) } func (r referrerManifest) MediaType() (types.MediaType, error) { diff --git a/pkg/oci/remote/write_test.go b/pkg/oci/remote/write_test.go index 32be283fff1..b507c0bd046 100644 --- a/pkg/oci/remote/write_test.go +++ b/pkg/oci/remote/write_test.go @@ -17,15 +17,19 @@ package remote import ( "fmt" + "strings" "testing" "github.com/google/go-containerregistry/pkg/name" v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/random" "github.com/google/go-containerregistry/pkg/v1/remote" - "github.com/sigstore/cosign/v2/pkg/oci/mutate" - "github.com/sigstore/cosign/v2/pkg/oci/signed" - "github.com/sigstore/cosign/v2/pkg/oci/static" + "github.com/google/go-containerregistry/pkg/v1/static" + "github.com/google/go-containerregistry/pkg/v1/types" + "github.com/sigstore/cosign/v3/pkg/oci/mutate" + "github.com/sigstore/cosign/v3/pkg/oci/signed" + cosignstatic "github.com/sigstore/cosign/v3/pkg/oci/static" + ctypes "github.com/sigstore/cosign/v3/pkg/types" ) func TestWriteSignatures(t *testing.T) { @@ -41,7 +45,7 @@ func TestWriteSignatures(t *testing.T) { want := 6 // Add 6 signatures for i := 0; i < want; i++ { - sig, err := static.NewSignature(nil, fmt.Sprintf("%d", i)) + sig, err := cosignstatic.NewSignature(nil, fmt.Sprintf("%d", i)) if err != nil { t.Fatalf("static.NewSignature() = %v", err) } @@ -83,7 +87,7 @@ func TestWriteAttestations(t *testing.T) { want := 6 // Add 6 attestations for i := 0; i < want; i++ { - sig, err := static.NewAttestation([]byte(fmt.Sprintf("%d", i))) + sig, err := cosignstatic.NewAttestation([]byte(fmt.Sprintf("%d", i))) if err != nil { t.Fatalf("static.NewSignature() = %v", err) } @@ -111,3 +115,334 @@ func TestWriteAttestations(t *testing.T) { t.Fatalf("WriteAttestations() = %v", err) } } + +func TestReferrerManifest(t *testing.T) { + // Test referrerManifest.RawManifest() + rm := referrerManifest{ + Manifest: v1.Manifest{ + SchemaVersion: 2, + MediaType: types.OCIManifestSchema1, + Config: v1.Descriptor{ + MediaType: "application/vnd.oci.empty.v1+json", + Digest: v1.Hash{Algorithm: "sha256", Hex: "abc123"}, + Size: 100, + }, + Layers: []v1.Descriptor{}, + }, + ArtifactType: "test.artifact.type", + } + + manifestBytes, err := rm.RawManifest() + if err != nil { + t.Fatalf("RawManifest() = %v", err) + } + + if len(manifestBytes) == 0 { + t.Error("RawManifest returned empty bytes") + } + + // Test referrerManifest.MediaType() + mediaType, err := rm.MediaType() + if err != nil { + t.Fatalf("MediaType() = %v", err) + } + if mediaType != types.OCIManifestSchema1 { + t.Errorf("MediaType() = %s, want %s", mediaType, types.OCIManifestSchema1) + } + + // Test referrerManifest.targetRef() + repo := name.MustParseReference("gcr.io/test/repo").Context() + targetRef, err := rm.targetRef(repo) + if err != nil { + t.Fatalf("targetRef() = %v", err) + } + if targetRef == nil { + t.Error("targetRef returned nil") + } +} + +func TestTaggableManifest(t *testing.T) { + // Test taggableManifest.RawManifest() + tm := taggableManifest{ + raw: []byte(`{"test":"manifest"}`), + mediaType: types.DockerManifestSchema2, + } + + manifestBytes, err := tm.RawManifest() + if err != nil { + t.Fatalf("RawManifest() = %v", err) + } + if string(manifestBytes) != `{"test":"manifest"}` { + t.Errorf("RawManifest() = %s, want %s", string(manifestBytes), `{"test":"manifest"}`) + } + + // Test taggableManifest.MediaType() + mediaType, err := tm.MediaType() + if err != nil { + t.Fatalf("MediaType() = %v", err) + } + if mediaType != types.DockerManifestSchema2 { + t.Errorf("MediaType() = %s, want %s", mediaType, types.DockerManifestSchema2) + } +} + +func TestWriteAttestationNewBundleFormat(t *testing.T) { + // Save original functions + origHead := remoteHead + origWriteLayer := remoteWriteLayer + origPut := remotePut + t.Cleanup(func() { + remoteHead = origHead + remoteWriteLayer = origWriteLayer + remotePut = origPut + }) + + bundleBytes := []byte(`{"payload":"test","signatures":[]}`) + predicateType := "https://test.predicate.type" + digest := name.MustParseReference("gcr.io/test/image@sha256:1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef").(name.Digest) + + // Mock remoteHead to return a descriptor + remoteHead = func(name.Reference, ...remote.Option) (*v1.Descriptor, error) { + return &v1.Descriptor{ + MediaType: types.DockerManifestSchema2, + Digest: v1.Hash{Algorithm: "sha256", Hex: "abcdef1234567890"}, + Size: 100, + }, nil + } + + // Mock remoteWriteLayer to succeed + remoteWriteLayer = func(name.Repository, v1.Layer, ...remote.Option) error { + return nil + } + + // Mock remotePut to capture the manifest + var capturedManifest remote.Taggable + remotePut = func(_ name.Reference, manifest remote.Taggable, _ ...remote.Option) error { + capturedManifest = manifest + return nil + } + + err := WriteAttestationNewBundleFormat(digest, bundleBytes, predicateType) + if err != nil { + t.Fatalf("WriteAttestationNewBundleFormat() = %v", err) + } + + // Verify that a manifest was uploaded + if capturedManifest == nil { + t.Error("Expected manifest to be uploaded, but none was captured") + } + + // Verify it's a referrerManifest + refManifest, ok := capturedManifest.(referrerManifest) + if !ok { + t.Errorf("Expected referrerManifest, got %T", capturedManifest) + return + } + + // Verify the artifact type contains bundle media type + if refManifest.ArtifactType == "" { + t.Error("Expected ArtifactType to be set") + } + + // Verify annotations are set correctly + if refManifest.Annotations["dev.sigstore.bundle.content"] != "dsse-envelope" { + t.Errorf("Expected bundle.content annotation to be 'dsse-envelope', got %s", refManifest.Annotations["dev.sigstore.bundle.content"]) + } + if refManifest.Annotations["dev.sigstore.bundle.predicateType"] != predicateType { + t.Errorf("Expected predicateType annotation to be %s, got %s", predicateType, refManifest.Annotations["dev.sigstore.bundle.predicateType"]) + } +} + +func TestWriteAttestationsReferrer(t *testing.T) { + // Save original functions + origHead := remoteHead + origWriteLayer := remoteWriteLayer + origPut := remotePut + t.Cleanup(func() { + remoteHead = origHead + remoteWriteLayer = origWriteLayer + remotePut = origPut + }) + + digest := name.MustParseReference("gcr.io/test/image@sha256:1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef").(name.Digest) + + // Create a test signed entity with attestations + i, err := random.Image(300, 1) + if err != nil { + t.Fatalf("random.Image() = %v", err) + } + si := signed.Image(i) + + // Add an attestation + att, err := cosignstatic.NewAttestation([]byte("test-attestation")) + if err != nil { + t.Fatalf("static.NewAttestation() = %v", err) + } + si, err = mutate.AttachAttestationToImage(si, att) + if err != nil { + t.Fatalf("AttachAttestationToImage() = %v", err) + } + + // Mock remoteHead to return a descriptor + remoteHead = func(name.Reference, ...remote.Option) (*v1.Descriptor, error) { + return &v1.Descriptor{ + MediaType: types.DockerManifestSchema2, + Digest: v1.Hash{Algorithm: "sha256", Hex: "abcdef1234567890"}, + Size: 100, + }, nil + } + + // Mock remoteWriteLayer to succeed + remoteWriteLayer = func(name.Repository, v1.Layer, ...remote.Option) error { + return nil + } + + // Mock remotePut to capture the manifest + var capturedManifest remote.Taggable + remotePut = func(_ name.Reference, manifest remote.Taggable, _ ...remote.Option) error { + capturedManifest = manifest + return nil + } + + err = WriteAttestationsReferrer(digest, si) + if err != nil { + t.Fatalf("WriteAttestationsReferrer() = %v", err) + } + + // Verify that a manifest was uploaded + if capturedManifest == nil { + t.Error("Expected manifest to be uploaded, but none was captured") + } + + // Verify it's a referrerManifest + refManifest, ok := capturedManifest.(referrerManifest) + if !ok { + t.Errorf("Expected referrerManifest, got %T", capturedManifest) + return + } + + // Verify the artifact type is set to in-toto payload type + if refManifest.ArtifactType != ctypes.IntotoPayloadType { + t.Errorf("Expected ArtifactType to be %s, got %s", ctypes.IntotoPayloadType, refManifest.ArtifactType) + } + + // Verify annotations include created timestamp + if _, exists := refManifest.Annotations["org.opencontainers.image.created"]; !exists { + t.Error("Expected created annotation to be set") + } + + // Verify we have at least one layer + if len(refManifest.Layers) == 0 { + t.Error("Expected at least one layer in manifest") + } +} + +func TestWriteReferrer(t *testing.T) { + // Save original functions + origHead := remoteHead + origWriteLayer := remoteWriteLayer + origPut := remotePut + t.Cleanup(func() { + remoteHead = origHead + remoteWriteLayer = origWriteLayer + remotePut = origPut + }) + + digest := name.MustParseReference("gcr.io/test/image@sha256:1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef").(name.Digest) + + // Create a test layer + testLayer := static.NewLayer([]byte("test-data"), "application/octet-stream") + layers := []v1.Layer{testLayer} + annotations := map[string]string{ + "test.annotation": "test-value", + } + artifactType := "test.artifact.type" + + // Mock remoteHead to return a descriptor + remoteHead = func(name.Reference, ...remote.Option) (*v1.Descriptor, error) { + return &v1.Descriptor{ + MediaType: types.DockerManifestSchema2, + Digest: v1.Hash{Algorithm: "sha256", Hex: "abcdef1234567890"}, + Size: 100, + }, nil + } + + // Mock remoteWriteLayer to succeed + remoteWriteLayer = func(name.Repository, v1.Layer, ...remote.Option) error { + return nil + } + + // Mock remotePut to capture the manifest + var capturedManifest remote.Taggable + remotePut = func(_ name.Reference, manifest remote.Taggable, _ ...remote.Option) error { + capturedManifest = manifest + return nil + } + + err := WriteReferrer(digest, artifactType, layers, annotations) + if err != nil { + t.Fatalf("WriteReferrer() = %v", err) + } + + // Verify that a manifest was uploaded + if capturedManifest == nil { + t.Error("Expected manifest to be uploaded, but none was captured") + } + + // Verify it's a referrerManifest + refManifest, ok := capturedManifest.(referrerManifest) + if !ok { + t.Errorf("Expected referrerManifest, got %T", capturedManifest) + return + } + + // Verify the artifact type is set correctly + if refManifest.ArtifactType != artifactType { + t.Errorf("Expected ArtifactType to be %s, got %s", artifactType, refManifest.ArtifactType) + } + + // Verify annotations are passed through + if refManifest.Annotations["test.annotation"] != "test-value" { + t.Errorf("Expected annotation to be 'test-value', got %s", refManifest.Annotations["test.annotation"]) + } + + // Verify we have the expected number of layers + if len(refManifest.Layers) != 1 { + t.Errorf("Expected 1 layer, got %d", len(refManifest.Layers)) + } + + // Verify the subject is set + if refManifest.Subject == nil { + t.Error("Expected Subject to be set") + } + + // Verify config descriptor + if refManifest.Config.ArtifactType != artifactType { + t.Errorf("Expected Config.ArtifactType to be %s, got %s", artifactType, refManifest.Config.ArtifactType) + } +} + +func TestWriteReferrerErrorHandling(t *testing.T) { + // Save original functions + origHead := remoteHead + t.Cleanup(func() { + remoteHead = origHead + }) + + digest := name.MustParseReference("gcr.io/test/image@sha256:1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef").(name.Digest) + layers := []v1.Layer{} + annotations := map[string]string{} + + // Mock remoteHead to return an error + remoteHead = func(name.Reference, ...remote.Option) (*v1.Descriptor, error) { + return nil, fmt.Errorf("remote head failed") + } + + err := WriteReferrer(digest, "test.type", layers, annotations) + if err == nil { + t.Error("Expected error from WriteReferrer when remoteHead fails") + } + if !strings.Contains(err.Error(), "remote head failed") { + t.Errorf("Expected error to contain 'remote head failed', got %v", err) + } +} diff --git a/pkg/oci/signature/layer.go b/pkg/oci/signature/layer.go index 4bd5e456c77..8106e983558 100644 --- a/pkg/oci/signature/layer.go +++ b/pkg/oci/signature/layer.go @@ -24,9 +24,9 @@ import ( "strings" v1 "github.com/google/go-containerregistry/pkg/v1" - payloadsize "github.com/sigstore/cosign/v2/internal/pkg/cosign/payload/size" - "github.com/sigstore/cosign/v2/pkg/cosign/bundle" - "github.com/sigstore/cosign/v2/pkg/oci" + payloadsize "github.com/sigstore/cosign/v3/internal/pkg/cosign/payload/size" + "github.com/sigstore/cosign/v3/pkg/cosign/bundle" + "github.com/sigstore/cosign/v3/pkg/oci" "github.com/sigstore/sigstore/pkg/cryptoutils" ) diff --git a/pkg/oci/signature/layer_test.go b/pkg/oci/signature/layer_test.go index e88157d2150..ac894278266 100644 --- a/pkg/oci/signature/layer_test.go +++ b/pkg/oci/signature/layer_test.go @@ -28,7 +28,7 @@ import ( v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/random" "github.com/google/go-containerregistry/pkg/v1/types" - "github.com/sigstore/cosign/v2/pkg/cosign/bundle" + "github.com/sigstore/cosign/v3/pkg/cosign/bundle" ) func mustDecode(s string) []byte { diff --git a/pkg/oci/signatures.go b/pkg/oci/signatures.go index 32f2f890c03..92526319506 100644 --- a/pkg/oci/signatures.go +++ b/pkg/oci/signatures.go @@ -19,7 +19,7 @@ import ( "crypto/x509" v1 "github.com/google/go-containerregistry/pkg/v1" - "github.com/sigstore/cosign/v2/pkg/cosign/bundle" + "github.com/sigstore/cosign/v3/pkg/cosign/bundle" ) // Signatures represents a set of signatures that are associated with a particular diff --git a/pkg/oci/signed/image.go b/pkg/oci/signed/image.go index 2bcade64b02..ccdc383efab 100644 --- a/pkg/oci/signed/image.go +++ b/pkg/oci/signed/image.go @@ -20,8 +20,8 @@ import ( v1 "github.com/google/go-containerregistry/pkg/v1" - "github.com/sigstore/cosign/v2/pkg/oci" - "github.com/sigstore/cosign/v2/pkg/oci/empty" + "github.com/sigstore/cosign/v3/pkg/oci" + "github.com/sigstore/cosign/v3/pkg/oci/empty" ) // Image returns an oci.SignedImage form of the v1.Image with no signatures. diff --git a/pkg/oci/signed/index.go b/pkg/oci/signed/index.go index b686b4f62e5..61da79403c2 100644 --- a/pkg/oci/signed/index.go +++ b/pkg/oci/signed/index.go @@ -20,8 +20,8 @@ import ( v1 "github.com/google/go-containerregistry/pkg/v1" - "github.com/sigstore/cosign/v2/pkg/oci" - "github.com/sigstore/cosign/v2/pkg/oci/empty" + "github.com/sigstore/cosign/v3/pkg/oci" + "github.com/sigstore/cosign/v3/pkg/oci/empty" ) // ImageIndex returns an oci.SignedImageIndex form of the v1.ImageIndex with diff --git a/pkg/oci/signed/index_test.go b/pkg/oci/signed/index_test.go index 11523187df8..55c71b1baf5 100644 --- a/pkg/oci/signed/index_test.go +++ b/pkg/oci/signed/index_test.go @@ -22,7 +22,7 @@ import ( "github.com/google/go-containerregistry/pkg/v1/mutate" "github.com/google/go-containerregistry/pkg/v1/random" "github.com/google/go-containerregistry/pkg/v1/types" - "github.com/sigstore/cosign/v2/pkg/oci" + "github.com/sigstore/cosign/v3/pkg/oci" ) func TestImageIndex(t *testing.T) { diff --git a/pkg/oci/static/file.go b/pkg/oci/static/file.go index 18ec65c3af8..5297d8666d0 100644 --- a/pkg/oci/static/file.go +++ b/pkg/oci/static/file.go @@ -22,10 +22,10 @@ import ( "github.com/google/go-containerregistry/pkg/v1/empty" "github.com/google/go-containerregistry/pkg/v1/mutate" "github.com/google/go-containerregistry/pkg/v1/types" - payloadsize "github.com/sigstore/cosign/v2/internal/pkg/cosign/payload/size" - "github.com/sigstore/cosign/v2/internal/pkg/now" - "github.com/sigstore/cosign/v2/pkg/oci" - "github.com/sigstore/cosign/v2/pkg/oci/signed" + payloadsize "github.com/sigstore/cosign/v3/internal/pkg/cosign/payload/size" + "github.com/sigstore/cosign/v3/internal/pkg/now" + "github.com/sigstore/cosign/v3/pkg/oci" + "github.com/sigstore/cosign/v3/pkg/oci/signed" ) // NewFile constructs a new v1.Image with the provided payload. diff --git a/pkg/oci/static/options.go b/pkg/oci/static/options.go index b240fb228ae..f0515992ea4 100644 --- a/pkg/oci/static/options.go +++ b/pkg/oci/static/options.go @@ -19,8 +19,8 @@ import ( "encoding/json" "github.com/google/go-containerregistry/pkg/v1/types" - "github.com/sigstore/cosign/v2/pkg/cosign/bundle" - ctypes "github.com/sigstore/cosign/v2/pkg/types" + "github.com/sigstore/cosign/v3/pkg/cosign/bundle" + ctypes "github.com/sigstore/cosign/v3/pkg/types" ) // Option is a functional option for customizing static signatures. diff --git a/pkg/oci/static/options_test.go b/pkg/oci/static/options_test.go index d63ec0fb01a..0f07dee2b0d 100644 --- a/pkg/oci/static/options_test.go +++ b/pkg/oci/static/options_test.go @@ -21,8 +21,8 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-containerregistry/pkg/v1/types" - cbundle "github.com/sigstore/cosign/v2/pkg/cosign/bundle" - ctypes "github.com/sigstore/cosign/v2/pkg/types" + cbundle "github.com/sigstore/cosign/v3/pkg/cosign/bundle" + ctypes "github.com/sigstore/cosign/v3/pkg/types" ) func TestOptions(t *testing.T) { diff --git a/pkg/oci/static/signature.go b/pkg/oci/static/signature.go index 406386347f2..817c7c6786f 100644 --- a/pkg/oci/static/signature.go +++ b/pkg/oci/static/signature.go @@ -23,8 +23,8 @@ import ( v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/types" - "github.com/sigstore/cosign/v2/pkg/cosign/bundle" - "github.com/sigstore/cosign/v2/pkg/oci" + "github.com/sigstore/cosign/v3/pkg/cosign/bundle" + "github.com/sigstore/cosign/v3/pkg/oci" "github.com/sigstore/sigstore/pkg/cryptoutils" ) diff --git a/pkg/oci/static/signature_test.go b/pkg/oci/static/signature_test.go index 1ca8e96e3df..07096a8275d 100644 --- a/pkg/oci/static/signature_test.go +++ b/pkg/oci/static/signature_test.go @@ -24,7 +24,7 @@ import ( "github.com/google/go-cmp/cmp" v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/types" - "github.com/sigstore/cosign/v2/pkg/cosign/bundle" + "github.com/sigstore/cosign/v3/pkg/cosign/bundle" ) func TestNewSignatureBasic(t *testing.T) { diff --git a/pkg/oci/walk/walk.go b/pkg/oci/walk/walk.go index 097d05bfa30..ec40c62b8da 100644 --- a/pkg/oci/walk/walk.go +++ b/pkg/oci/walk/walk.go @@ -18,8 +18,8 @@ package walk import ( "context" - "github.com/sigstore/cosign/v2/pkg/oci" - "github.com/sigstore/cosign/v2/pkg/oci/mutate" + "github.com/sigstore/cosign/v3/pkg/oci" + "github.com/sigstore/cosign/v3/pkg/oci/mutate" ) // Fn is the signature of the callback supplied to SignedEntity. diff --git a/pkg/oci/walk/walk_test.go b/pkg/oci/walk/walk_test.go index 8ba5b225508..3f2d3d7a56f 100644 --- a/pkg/oci/walk/walk_test.go +++ b/pkg/oci/walk/walk_test.go @@ -22,8 +22,8 @@ import ( "github.com/google/go-containerregistry/pkg/v1/mutate" "github.com/google/go-containerregistry/pkg/v1/random" - "github.com/sigstore/cosign/v2/pkg/oci" - "github.com/sigstore/cosign/v2/pkg/oci/signed" + "github.com/sigstore/cosign/v3/pkg/oci" + "github.com/sigstore/cosign/v3/pkg/oci/signed" ) func TestMapImage(t *testing.T) { diff --git a/pkg/policy/attestation.go b/pkg/policy/attestation.go index 63377d44221..04c53bc7a00 100644 --- a/pkg/policy/attestation.go +++ b/pkg/policy/attestation.go @@ -23,9 +23,9 @@ import ( "fmt" "github.com/in-toto/in-toto-golang/in_toto" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/pkg/cosign/attestation" - "github.com/sigstore/cosign/v2/pkg/oci" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/pkg/cosign/attestation" + "github.com/sigstore/cosign/v3/pkg/oci" ) // PayloadProvider is a subset of oci.Signature that only provides the diff --git a/pkg/policy/attestation_test.go b/pkg/policy/attestation_test.go index 908f0696081..193a0faeff4 100644 --- a/pkg/policy/attestation_test.go +++ b/pkg/policy/attestation_test.go @@ -29,10 +29,10 @@ import ( v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/types" "github.com/in-toto/in-toto-golang/in_toto" - "github.com/sigstore/cosign/v2/pkg/cosign/attestation" - "github.com/sigstore/cosign/v2/pkg/cosign/bundle" - "github.com/sigstore/cosign/v2/pkg/oci" - "github.com/sigstore/cosign/v2/pkg/oci/static" + "github.com/sigstore/cosign/v3/pkg/cosign/attestation" + "github.com/sigstore/cosign/v3/pkg/cosign/bundle" + "github.com/sigstore/cosign/v3/pkg/oci" + "github.com/sigstore/cosign/v3/pkg/oci/static" ) type failingAttestation struct { diff --git a/pkg/policy/eval.go b/pkg/policy/eval.go index 9e33a8a005d..b29d86b342a 100644 --- a/pkg/policy/eval.go +++ b/pkg/policy/eval.go @@ -20,7 +20,7 @@ import ( "fmt" "cuelang.org/go/cue/cuecontext" - "github.com/sigstore/cosign/v2/pkg/cosign/rego" + "github.com/sigstore/cosign/v3/pkg/cosign/rego" ) // EvaluatePolicyAgainstJson is used to run a policy engine against JSON bytes. diff --git a/pkg/providers/all/all.go b/pkg/providers/all/all.go index 6f5952e7e98..7082e4c6e81 100644 --- a/pkg/providers/all/all.go +++ b/pkg/providers/all/all.go @@ -16,20 +16,20 @@ package all import ( - "github.com/sigstore/cosign/v2/pkg/providers" + "github.com/sigstore/cosign/v3/pkg/providers" // Link in all of the providers. // Link the GitHub one first, since we might be running in a GitHub self-hosted // runner running in one of the other environments, and we should prefer GitHub // credentials if we can find them. - _ "github.com/sigstore/cosign/v2/pkg/providers/github" + _ "github.com/sigstore/cosign/v3/pkg/providers/github" // Link in the rest of the providers. - _ "github.com/sigstore/cosign/v2/pkg/providers/buildkite" - _ "github.com/sigstore/cosign/v2/pkg/providers/envvar" - _ "github.com/sigstore/cosign/v2/pkg/providers/filesystem" - _ "github.com/sigstore/cosign/v2/pkg/providers/google" - _ "github.com/sigstore/cosign/v2/pkg/providers/spiffe" + _ "github.com/sigstore/cosign/v3/pkg/providers/buildkite" + _ "github.com/sigstore/cosign/v3/pkg/providers/envvar" + _ "github.com/sigstore/cosign/v3/pkg/providers/filesystem" + _ "github.com/sigstore/cosign/v3/pkg/providers/google" + _ "github.com/sigstore/cosign/v3/pkg/providers/spiffe" ) // Alias these methods, so that folks can import this to get all providers. diff --git a/pkg/providers/buildkite/buildkite.go b/pkg/providers/buildkite/buildkite.go index f225e68d1f7..63991710184 100644 --- a/pkg/providers/buildkite/buildkite.go +++ b/pkg/providers/buildkite/buildkite.go @@ -22,8 +22,8 @@ import ( "github.com/buildkite/agent/v3/api" "github.com/buildkite/agent/v3/logger" - "github.com/sigstore/cosign/v2/pkg/cosign/env" - "github.com/sigstore/cosign/v2/pkg/providers" + "github.com/sigstore/cosign/v3/pkg/cosign/env" + "github.com/sigstore/cosign/v3/pkg/providers" ) func init() { diff --git a/pkg/providers/envvar/env.go b/pkg/providers/envvar/env.go index 67de28fa953..d6c9df85a83 100644 --- a/pkg/providers/envvar/env.go +++ b/pkg/providers/envvar/env.go @@ -18,8 +18,8 @@ package envvar import ( "context" - "github.com/sigstore/cosign/v2/pkg/cosign/env" - "github.com/sigstore/cosign/v2/pkg/providers" + "github.com/sigstore/cosign/v3/pkg/cosign/env" + "github.com/sigstore/cosign/v3/pkg/providers" ) func init() { diff --git a/pkg/providers/envvar/env_test.go b/pkg/providers/envvar/env_test.go index cdc8f2ae9f3..2ecd28a8e9d 100644 --- a/pkg/providers/envvar/env_test.go +++ b/pkg/providers/envvar/env_test.go @@ -20,7 +20,7 @@ import ( "fmt" "testing" - "github.com/sigstore/cosign/v2/pkg/cosign/env" + "github.com/sigstore/cosign/v3/pkg/cosign/env" ) func TestEnvVar(t *testing.T) { diff --git a/pkg/providers/filesystem/filesystem.go b/pkg/providers/filesystem/filesystem.go index 56b57c34720..334aaf67dd5 100644 --- a/pkg/providers/filesystem/filesystem.go +++ b/pkg/providers/filesystem/filesystem.go @@ -19,7 +19,7 @@ import ( "context" "os" - "github.com/sigstore/cosign/v2/pkg/providers" + "github.com/sigstore/cosign/v3/pkg/providers" ) func init() { diff --git a/pkg/providers/github/github.go b/pkg/providers/github/github.go index f7427d57857..e8bd1baebe9 100644 --- a/pkg/providers/github/github.go +++ b/pkg/providers/github/github.go @@ -24,8 +24,8 @@ import ( "strings" "time" - "github.com/sigstore/cosign/v2/pkg/cosign/env" - "github.com/sigstore/cosign/v2/pkg/providers" + "github.com/sigstore/cosign/v3/pkg/cosign/env" + "github.com/sigstore/cosign/v3/pkg/providers" ) const ( diff --git a/pkg/providers/google/google.go b/pkg/providers/google/google.go index fc186dcfc50..30e3e5119e2 100644 --- a/pkg/providers/google/google.go +++ b/pkg/providers/google/google.go @@ -23,8 +23,8 @@ import ( "google.golang.org/api/idtoken" "google.golang.org/api/impersonate" - "github.com/sigstore/cosign/v2/pkg/cosign/env" - "github.com/sigstore/cosign/v2/pkg/providers" + "github.com/sigstore/cosign/v3/pkg/cosign/env" + "github.com/sigstore/cosign/v3/pkg/providers" ) func init() { diff --git a/pkg/providers/spiffe/spiffe.go b/pkg/providers/spiffe/spiffe.go index 2e134ca7af0..3672f1e6960 100644 --- a/pkg/providers/spiffe/spiffe.go +++ b/pkg/providers/spiffe/spiffe.go @@ -21,8 +21,8 @@ import ( "github.com/spiffe/go-spiffe/v2/svid/jwtsvid" - "github.com/sigstore/cosign/v2/pkg/cosign/env" - "github.com/sigstore/cosign/v2/pkg/providers" + "github.com/sigstore/cosign/v3/pkg/cosign/env" + "github.com/sigstore/cosign/v3/pkg/providers" "github.com/spiffe/go-spiffe/v2/workloadapi" ) diff --git a/pkg/signature/keys.go b/pkg/signature/keys.go index dfac964725d..3b7879a6f4f 100644 --- a/pkg/signature/keys.go +++ b/pkg/signature/keys.go @@ -21,12 +21,12 @@ import ( "fmt" "strings" - "github.com/sigstore/cosign/v2/pkg/blob" - "github.com/sigstore/cosign/v2/pkg/cosign" - "github.com/sigstore/cosign/v2/pkg/cosign/git" - "github.com/sigstore/cosign/v2/pkg/cosign/git/gitlab" - "github.com/sigstore/cosign/v2/pkg/cosign/kubernetes" - "github.com/sigstore/cosign/v2/pkg/cosign/pkcs11key" + "github.com/sigstore/cosign/v3/pkg/blob" + "github.com/sigstore/cosign/v3/pkg/cosign" + "github.com/sigstore/cosign/v3/pkg/cosign/git" + "github.com/sigstore/cosign/v3/pkg/cosign/git/gitlab" + "github.com/sigstore/cosign/v3/pkg/cosign/kubernetes" + "github.com/sigstore/cosign/v3/pkg/cosign/pkcs11key" "github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/sigstore/sigstore/pkg/signature" @@ -72,7 +72,7 @@ func VerifierForKeyRef(ctx context.Context, keyRef string, hashAlgorithm crypto. return signature.LoadVerifier(pubKey, hashAlgorithm) } -func loadKey(keyPath string, pf cosign.PassFunc) (signature.SignerVerifier, error) { +func loadKey(keyPath string, pf cosign.PassFunc, defaultLoadOptions *[]signature.LoadOption) (signature.SignerVerifier, error) { kb, err := blob.LoadFileOrURL(keyPath) if err != nil { return nil, err @@ -84,7 +84,7 @@ func loadKey(keyPath string, pf cosign.PassFunc) (signature.SignerVerifier, erro return nil, err } } - return cosign.LoadPrivateKey(kb, pass) + return cosign.LoadPrivateKey(kb, pass, defaultLoadOptions) } // LoadPublicKeyRaw loads a verifier from a PEM-encoded public key @@ -97,10 +97,10 @@ func LoadPublicKeyRaw(raw []byte, hashAlgorithm crypto.Hash) (signature.Verifier } func SignerFromKeyRef(ctx context.Context, keyRef string, pf cosign.PassFunc) (signature.Signer, error) { - return SignerVerifierFromKeyRef(ctx, keyRef, pf) + return SignerVerifierFromKeyRef(ctx, keyRef, pf, nil) } -func SignerVerifierFromKeyRef(ctx context.Context, keyRef string, pf cosign.PassFunc) (signature.SignerVerifier, error) { +func SignerVerifierFromKeyRef(ctx context.Context, keyRef string, pf cosign.PassFunc, defaultLoadOptions *[]signature.LoadOption) (signature.SignerVerifier, error) { switch { case strings.HasPrefix(keyRef, pkcs11key.ReferenceScheme): pkcs11UriConfig := pkcs11key.NewPkcs11UriConfig() @@ -129,7 +129,7 @@ func SignerVerifierFromKeyRef(ctx context.Context, keyRef string, pf cosign.Pass } if len(s.Data) > 0 { - return cosign.LoadPrivateKey(s.Data["cosign.key"], s.Data["cosign.password"]) + return cosign.LoadPrivateKey(s.Data["cosign.key"], s.Data["cosign.password"], defaultLoadOptions) } case strings.HasPrefix(keyRef, gitlab.ReferenceScheme): split := strings.Split(keyRef, "://") @@ -150,7 +150,7 @@ func SignerVerifierFromKeyRef(ctx context.Context, keyRef string, pf cosign.Pass return nil, err } - return cosign.LoadPrivateKey([]byte(pk), []byte(pass)) + return cosign.LoadPrivateKey([]byte(pk), []byte(pass), defaultLoadOptions) } if strings.Contains(keyRef, "://") { @@ -165,7 +165,7 @@ func SignerVerifierFromKeyRef(ctx context.Context, keyRef string, pf cosign.Pass // ProviderNotFoundError is okay; loadKey handles other URL schemes } - return loadKey(keyRef, pf) + return loadKey(keyRef, pf, defaultLoadOptions) } func PublicKeyFromKeyRef(ctx context.Context, keyRef string) (signature.Verifier, error) { diff --git a/pkg/signature/keys_test.go b/pkg/signature/keys_test.go index 0365aa34911..7e2710ab2bc 100644 --- a/pkg/signature/keys_test.go +++ b/pkg/signature/keys_test.go @@ -21,8 +21,8 @@ import ( "os" "testing" - "github.com/sigstore/cosign/v2/pkg/blob" - "github.com/sigstore/cosign/v2/pkg/cosign" + "github.com/sigstore/cosign/v3/pkg/blob" + "github.com/sigstore/cosign/v3/pkg/cosign" sigsignature "github.com/sigstore/sigstore/pkg/signature" "github.com/sigstore/sigstore/pkg/signature/kms" ) @@ -135,7 +135,7 @@ func TestSignerVerifierFromEnvVar(t *testing.T) { os.Setenv("MY_ENV_VAR", string(keys.PrivateBytes)) defer os.Unsetenv("MY_ENV_VAR") - if _, err := SignerVerifierFromKeyRef(ctx, "env://MY_ENV_VAR", passFunc); err != nil { + if _, err := SignerVerifierFromKeyRef(ctx, "env://MY_ENV_VAR", passFunc, nil); err != nil { t.Fatalf("SignerVerifierFromKeyRef returned error: %v", err) } } diff --git a/pkg/types/predicate.go b/pkg/types/predicate.go new file mode 100644 index 00000000000..8a187192018 --- /dev/null +++ b/pkg/types/predicate.go @@ -0,0 +1,20 @@ +// +// Copyright 2021 The Sigstore 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 types //nolint: revive // that is a valid package name :) + +const ( + CosignSignPredicateType = "https://sigstore.dev/cosign/sign/v1" +) diff --git a/release/cloudbuild.yaml b/release/cloudbuild.yaml index 0edc5bda010..8b55670d750 100644 --- a/release/cloudbuild.yaml +++ b/release/cloudbuild.yaml @@ -32,20 +32,19 @@ steps: echo "Checking out ${_GIT_TAG}" git checkout ${_GIT_TAG} - - name: 'ghcr.io/sigstore/cosign/cosign:v2.5.2-dev@sha256:14a20131240190350e18f002bdd61345d2803eff370913737392281e834ee22a' + - name: 'ghcr.io/sigstore/cosign/cosign:v3.0.2-dev@sha256:322c53c5f3e4516351bd8cb793ff46ad3809eed48a53daf0da1bae8f4d550e18' dir: "go/src/sigstore/cosign" env: - TUF_ROOT=/tmp args: - 'verify' - - 'ghcr.io/gythialy/golang-cross:v1.24.5-0@sha256:492c51e60ed27ff597511b0a24e6c5acb6e3e2e97bb68d7bd35f81a7e3dfa4d0' + - 'ghcr.io/gythialy/golang-cross:v1.25.5-0@sha256:3a7d463d9e3438513b6bd597c79f7d5db756023e04718259cc25aabd5d00fc17' - '--certificate-oidc-issuer' - "https://token.actions.githubusercontent.com" - '--certificate-identity' - - "https://github.com/gythialy/golang-cross/.github/workflows/release-golang-cross.yml@refs/tags/v1.24.5-0" - + - "https://github.com/gythialy/golang-cross/.github/workflows/release-golang-cross.yml@refs/tags/v1.25.5-0" # maybe we can build our own image and use that to be more in a safe side - - name: ghcr.io/gythialy/golang-cross:v1.24.5-0@sha256:492c51e60ed27ff597511b0a24e6c5acb6e3e2e97bb68d7bd35f81a7e3dfa4d0 + - name: ghcr.io/gythialy/golang-cross:v1.25.5-0@sha256:3a7d463d9e3438513b6bd597c79f7d5db756023e04718259cc25aabd5d00fc17 entrypoint: /bin/sh dir: "go/src/sigstore/cosign" env: @@ -68,7 +67,7 @@ steps: gcloud auth configure-docker \ && make release - - name: ghcr.io/gythialy/golang-cross:v1.24.5-0@sha256:492c51e60ed27ff597511b0a24e6c5acb6e3e2e97bb68d7bd35f81a7e3dfa4d0 + - name: ghcr.io/gythialy/golang-cross:v1.25.5-0@sha256:3a7d463d9e3438513b6bd597c79f7d5db756023e04718259cc25aabd5d00fc17 entrypoint: 'bash' dir: "go/src/sigstore/cosign" env: diff --git a/test/config/gettoken/gettoken.yaml b/test/config/gettoken/gettoken.yaml index 16012b072fb..e5608621268 100644 --- a/test/config/gettoken/gettoken.yaml +++ b/test/config/gettoken/gettoken.yaml @@ -21,7 +21,7 @@ spec: spec: containers: - name: gettoken - image: ko://github.com/sigstore/cosign/v2/test/cmd/getoidctoken + image: ko://github.com/sigstore/cosign/v3/test/cmd/getoidctoken env: - name: OIDC_FILE value: "/var/run/sigstore/cosign/oidc-token" diff --git a/test/e2e_attach_test.go b/test/e2e_attach_test.go index 7385da4f4a6..085351fec57 100644 --- a/test/e2e_attach_test.go +++ b/test/e2e_attach_test.go @@ -38,18 +38,19 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-containerregistry/pkg/name" "github.com/google/go-containerregistry/pkg/v1/types" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/attach" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/download" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/generate" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - cliverify "github.com/sigstore/cosign/v2/cmd/cosign/cli/verify" - "github.com/sigstore/cosign/v2/internal/pkg/cosign/tsa" - "github.com/sigstore/cosign/v2/internal/pkg/cosign/tsa/client" - "github.com/sigstore/cosign/v2/pkg/cosign" - "github.com/sigstore/cosign/v2/pkg/cosign/bundle" - ociremote "github.com/sigstore/cosign/v2/pkg/oci/remote" - tsaclient "github.com/sigstore/timestamp-authority/pkg/client" - "github.com/sigstore/timestamp-authority/pkg/server" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/attach" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/download" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/generate" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + cliverify "github.com/sigstore/cosign/v3/cmd/cosign/cli/verify" + "github.com/sigstore/cosign/v3/internal/pkg/cosign/tsa" + "github.com/sigstore/cosign/v3/internal/pkg/cosign/tsa/client" + cert_test "github.com/sigstore/cosign/v3/internal/test" + "github.com/sigstore/cosign/v3/pkg/cosign" + "github.com/sigstore/cosign/v3/pkg/cosign/bundle" + ociremote "github.com/sigstore/cosign/v3/pkg/oci/remote" + tsaclient "github.com/sigstore/timestamp-authority/v2/pkg/client" + "github.com/sigstore/timestamp-authority/v2/pkg/server" "github.com/spf13/viper" ) @@ -73,11 +74,11 @@ func TestAttachSignature(t *testing.T) { // Scenario 1: attach a single signature with certificate and certificate chain to an artifact // and verify it using the root certificate. - rootCert1, rootKey1, _ := GenerateRootCa() + rootCert1, rootKey1, _ := cert_test.GenerateRootCa() pemRoot1 := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: rootCert1.Raw}) pemRootRef1 := mkfile(string(pemRoot1), td, t) - subCert1, subKey1, _ := GenerateSubordinateCa(rootCert1, rootKey1) - leafCert1, privKey1, _ := GenerateLeafCert("foo@example.com", "oidc-issuer", subCert1, subKey1) + subCert1, subKey1, _ := cert_test.GenerateSubordinateCa(rootCert1, rootKey1) + leafCert1, privKey1, _ := cert_test.GenerateLeafCert("foo@example.com", "oidc-issuer", subCert1, subKey1) pemSub1 := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: subCert1.Raw}) pemLeaf1 := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: leafCert1.Raw}) pemLeafRef1 := mkfile(string(pemLeaf1), td, t) @@ -122,11 +123,11 @@ func TestAttachSignature(t *testing.T) { // Scenario 2: Attaches second signature with another certificate and certificate chain to the // same artifact and verify it using both root certificates separately. - rootCert2, rootKey2, _ := GenerateRootCa() + rootCert2, rootKey2, _ := cert_test.GenerateRootCa() pemRoot2 := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: rootCert2.Raw}) pemRootRef2 := mkfile(string(pemRoot2), td, t) - subCert2, subKey2, _ := GenerateSubordinateCa(rootCert2, rootKey2) - leafCert2, privKey2, _ := GenerateLeafCert("foo@exampleclient.com", "oidc-issuer", subCert2, subKey2) + subCert2, subKey2, _ := cert_test.GenerateSubordinateCa(rootCert2, rootKey2) + leafCert2, privKey2, _ := cert_test.GenerateLeafCert("foo@exampleclient.com", "oidc-issuer", subCert2, subKey2) pemSub2 := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: subCert2.Raw}) pemLeaf2 := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: leafCert2.Raw}) pemLeafRef2 := mkfile(string(pemLeaf2), td, t) @@ -187,9 +188,9 @@ func TestAttachWithRFC3161Timestamp(t *testing.T) { b := bytes.Buffer{} must(generate.GenerateCmd(context.Background(), options.RegistryOptions{}, imgName, nil, &b), t) - rootCert, rootKey, _ := GenerateRootCa() - subCert, subKey, _ := GenerateSubordinateCa(rootCert, rootKey) - leafCert, privKey, _ := GenerateLeafCert("subject@mail.com", "oidc-issuer", subCert, subKey) + rootCert, rootKey, _ := cert_test.GenerateRootCa() + subCert, subKey, _ := cert_test.GenerateSubordinateCa(rootCert, rootKey) + leafCert, privKey, _ := cert_test.GenerateLeafCert("subject@mail.com", "oidc-issuer", subCert, subKey) pemRoot := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: rootCert.Raw}) pemSub := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: subCert.Raw}) pemLeaf := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: leafCert.Raw}) @@ -257,9 +258,9 @@ func TestAttachWithRekorBundle(t *testing.T) { b := bytes.Buffer{} must(generate.GenerateCmd(context.Background(), options.RegistryOptions{}, imgName, nil, &b), t) - rootCert, rootKey, _ := GenerateRootCa() - subCert, subKey, _ := GenerateSubordinateCa(rootCert, rootKey) - leafCert, privKey, _ := GenerateLeafCert("subject@mail.com", "oidc-issuer", subCert, subKey) + rootCert, rootKey, _ := cert_test.GenerateRootCa() + subCert, subKey, _ := cert_test.GenerateSubordinateCa(rootCert, rootKey) + leafCert, privKey, _ := cert_test.GenerateLeafCert("subject@mail.com", "oidc-issuer", subCert, subKey) pemRoot := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: rootCert.Raw}) pemSub := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: subCert.Raw}) pemLeaf := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: leafCert.Raw}) diff --git a/test/e2e_insecure_registry_test.go b/test/e2e_insecure_registry_test.go index 0da6ec6380d..d59273797e4 100644 --- a/test/e2e_insecure_registry_test.go +++ b/test/e2e_insecure_registry_test.go @@ -22,16 +22,20 @@ import ( "net/http" "os" "path" + "path/filepath" "testing" + "time" "github.com/google/go-containerregistry/pkg/name" "github.com/google/go-containerregistry/pkg/v1/random" "github.com/google/go-containerregistry/pkg/v1/remote" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/sign" - cliverify "github.com/sigstore/cosign/v2/cmd/cosign/cli/verify" - "github.com/sigstore/cosign/v2/pkg/cosign/env" - ociremote "github.com/sigstore/cosign/v2/pkg/oci/remote" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/attest" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/initialize" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/sign" + cliverify "github.com/sigstore/cosign/v3/cmd/cosign/cli/verify" + "github.com/sigstore/cosign/v3/pkg/cosign" + ociremote "github.com/sigstore/cosign/v3/pkg/oci/remote" ) const ( @@ -56,7 +60,13 @@ func TestInsecureRegistry(t *testing.T) { useOCI11 := os.Getenv("oci11Var") != "" rekorURL := os.Getenv(rekorURLVar) - must(downloadAndSetEnv(t, rekorURL+"/api/v1/log/publicKey", env.VariableSigstoreRekorPublicKey.String(), td), t) + + ctx := context.Background() + tufLocalCache := t.TempDir() + t.Setenv("TUF_ROOT", tufLocalCache) + rootPath := os.Getenv("TUF_ROOT_JSON") + mirror := os.Getenv("TUF_MIRROR") + must(initialize.DoInitialize(ctx, rootPath, mirror), t) ko := options.KeyOpts{ KeyRef: privKey, @@ -64,36 +74,130 @@ func TestInsecureRegistry(t *testing.T) { RekorURL: rekorURL, SkipConfirmation: true, } + trustedMaterial, err := cosign.TrustedRoot() + must(err, t) + ko.TrustedMaterial = trustedMaterial + + // Sign without bundle format so := options.SignOptions{ Upload: true, TlogUpload: true, } - mustErr(sign.SignCmd(ro, ko, so, []string{imgName}), t) + mustErr(sign.SignCmd(t.Context(), ro, ko, so, []string{imgName}), t) so.Registry = options.RegistryOptions{ - AllowInsecure: true, + AllowInsecure: true, + AllowHTTPRegistry: true, } if useOCI11 { so.RegistryExperimental = options.RegistryExperimentalOptions{ RegistryReferrersMode: options.RegistryReferrersModeOCI11, } } - must(sign.SignCmd(ro, ko, so, []string{imgName}), t) + must(sign.SignCmd(t.Context(), ro, ko, so, []string{imgName}), t) mustErr(verify(pubKey, imgName, true, nil, "", false), t) cmd := cliverify.VerifyCommand{ KeyRef: pubKey, CheckClaims: true, RegistryOptions: options.RegistryOptions{ - AllowInsecure: true, + AllowInsecure: true, + AllowHTTPRegistry: true, }, } if useOCI11 { cmd.ExperimentalOCI11 = true } must(cmd.Exec(context.Background(), []string{imgName}), t) + + // Sign new image with new bundle format + // (Must be a new image or the old bundle may be verified instead) + imgName = path.Join(repo, "cosign-registry-e2e-2") + cleanup2 := makeImageIndexWithInsecureRegistry(t, imgName) + defer cleanup2() + + so.NewBundleFormat = true + must(sign.SignCmd(t.Context(), ro, ko, so, []string{imgName}), t) + cmd.NewBundleFormat = true + must(cmd.Exec(context.Background(), []string{imgName}), t) +} + +func TestAttestInsecureRegistry(t *testing.T) { + if os.Getenv("COSIGN_TEST_REPO") == "" { + t.Fatal("COSIGN_TEST_REPO must be set to an insecure registry for this test") + } + repo, stop := reg(t) + defer stop() + td := t.TempDir() + + imgName := path.Join(repo, "cosign-registry-e2e") + cleanup := makeImageIndexWithInsecureRegistry(t, imgName) + defer cleanup() + + _, privKey, pubKey := keypair(t, td) + + rekorURL := os.Getenv(rekorURLVar) + + ctx := context.Background() + tufLocalCache := t.TempDir() + t.Setenv("TUF_ROOT", tufLocalCache) + rootPath := os.Getenv("TUF_ROOT_JSON") + mirror := os.Getenv("TUF_MIRROR") + must(initialize.DoInitialize(ctx, rootPath, mirror), t) + + ko := options.KeyOpts{ + KeyRef: privKey, + PassFunc: passFunc, + RekorURL: rekorURL, + SkipConfirmation: true, + } + trustedMaterial, err := cosign.TrustedRoot() + must(err, t) + ko.TrustedMaterial = trustedMaterial + + slsaAttestation := `{ "buildType": "x", "builder": { "id": "2" }, "recipe": {} }` + slsaAttestationPath := filepath.Join(td, "attestation.slsa.json") + if err := os.WriteFile(slsaAttestationPath, []byte(slsaAttestation), 0o600); err != nil { + t.Fatal(err) + } + + // Attest without bundle + attestCmd := attest.AttestCommand{ + KeyOpts: ko, + PredicatePath: slsaAttestationPath, + PredicateType: "slsaprovenance", + Timeout: 30 * time.Second, + RekorEntryType: "dsse", + TlogUpload: true, + RegistryOptions: options.RegistryOptions{ + AllowInsecure: true, + AllowHTTPRegistry: true, + }, + } + must(attestCmd.Exec(ctx, imgName), t) + verifyAttestation := cliverify.VerifyAttestationCommand{ + KeyRef: pubKey, + PredicateType: "slsaprovenance", + RegistryOptions: options.RegistryOptions{ + AllowInsecure: true, + AllowHTTPRegistry: true, + }, + } + must(verifyAttestation.Exec(ctx, []string{imgName}), t) + + // Attest with new bundle + imgName = path.Join(repo, "cosign-registry-e2e-2") + cleanup2 := makeImageIndexWithInsecureRegistry(t, imgName) + defer cleanup2() + + ko.NewBundleFormat = true + attestCmd.KeyOpts = ko + must(attestCmd.Exec(ctx, imgName), t) + verifyAttestation.CommonVerifyOptions.NewBundleFormat = true + verifyAttestation.IgnoreTlog = false + must(verifyAttestation.Exec(ctx, []string{imgName}), t) } func makeImageIndexWithInsecureRegistry(t *testing.T, n string) func() { - ref, err := name.ParseReference(n, name.WeakValidation) + ref, err := name.ParseReference(n, name.WeakValidation, name.Insecure) if err != nil { t.Fatal(err) } diff --git a/test/e2e_kms_test.go b/test/e2e_kms_test.go index 0050c2a39d4..2d212c85d52 100644 --- a/test/e2e_kms_test.go +++ b/test/e2e_kms_test.go @@ -22,10 +22,10 @@ import ( "path" "testing" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/generate" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/sign" - "github.com/sigstore/cosign/v2/pkg/cosign/env" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/generate" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/sign" + "github.com/sigstore/cosign/v3/pkg/cosign/env" _ "github.com/sigstore/sigstore/pkg/signature/kms/hashivault" ) @@ -75,7 +75,7 @@ func TestSecretsKMS(t *testing.T) { Upload: true, TlogUpload: true, } - must(sign.SignCmd(ro, ko, so, []string{imgName}), t) + must(sign.SignCmd(t.Context(), ro, ko, so, []string{imgName}), t) must(verify(pubKey, imgName, true, nil, "", false), t) // Sign and verify with annotations @@ -87,12 +87,12 @@ func TestSecretsKMS(t *testing.T) { Annotations: []string{"foo=bar"}, }, } - must(sign.SignCmd(ro, ko, soAnno, []string{imgName}), t) + must(sign.SignCmd(t.Context(), ro, ko, soAnno, []string{imgName}), t) must(verify(pubKey, imgName, true, map[string]any{"foo": "bar"}, "", false), t) // Store signatures in a different repo t.Setenv("COSIGN_REPOSITORY", path.Join(repo, "subbedrepo")) - must(sign.SignCmd(ro, ko, so, []string{imgName}), t) + must(sign.SignCmd(t.Context(), ro, ko, so, []string{imgName}), t) must(verify(pubKey, imgName, true, nil, "", false), t) os.Unsetenv("COSIGN_REPOSITORY") } diff --git a/test/e2e_test.go b/test/e2e_test.go index a57d197b99f..a9b0bb6deac 100644 --- a/test/e2e_test.go +++ b/test/e2e_test.go @@ -21,62 +21,74 @@ import ( "bytes" "context" "crypto" + "crypto/ecdsa" "crypto/ed25519" + "crypto/elliptic" "crypto/rand" "crypto/sha256" "crypto/x509" + "crypto/x509/pkix" "encoding/base64" + "encoding/hex" "encoding/json" "encoding/pem" "fmt" "io" + "math/big" "net/http" "net/http/httptest" "net/url" "os" "path" "path/filepath" + "regexp" "strings" "testing" "time" "github.com/google/go-cmp/cmp" + "github.com/google/go-containerregistry/pkg/crane" "github.com/google/go-containerregistry/pkg/name" "github.com/google/go-containerregistry/pkg/v1/remote" + "github.com/stretchr/testify/assert" "github.com/theupdateframework/go-tuf/v2/metadata" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" k8s "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/clientcmd" // Initialize all known client auth plugins - "github.com/sigstore/cosign/v2/cmd/cosign/cli" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/attach" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/attest" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/dockerfile" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/download" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/generate" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/initialize" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/manifest" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/publickey" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/sign" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/trustedroot" - cliverify "github.com/sigstore/cosign/v2/cmd/cosign/cli/verify" - "github.com/sigstore/cosign/v2/internal/pkg/cosign/fulcio/fulcioroots" - "github.com/sigstore/cosign/v2/internal/pkg/cosign/tsa" - "github.com/sigstore/cosign/v2/internal/pkg/cosign/tsa/client" - "github.com/sigstore/cosign/v2/pkg/cosign" - "github.com/sigstore/cosign/v2/pkg/cosign/bundle" - "github.com/sigstore/cosign/v2/pkg/cosign/env" - "github.com/sigstore/cosign/v2/pkg/cosign/kubernetes" - "github.com/sigstore/cosign/v2/pkg/oci/mutate" - ociremote "github.com/sigstore/cosign/v2/pkg/oci/remote" + "github.com/sigstore/cosign/v3/cmd/cosign/cli" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/attach" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/attest" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/dockerfile" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/download" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/generate" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/initialize" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/manifest" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/publickey" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/sign" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/signingconfig" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/trustedroot" + cliverify "github.com/sigstore/cosign/v3/cmd/cosign/cli/verify" + "github.com/sigstore/cosign/v3/internal/pkg/cosign/fulcio/fulcioroots" + "github.com/sigstore/cosign/v3/internal/pkg/cosign/tsa" + "github.com/sigstore/cosign/v3/internal/pkg/cosign/tsa/client" + cert_test "github.com/sigstore/cosign/v3/internal/test" + "github.com/sigstore/cosign/v3/pkg/cosign" + "github.com/sigstore/cosign/v3/pkg/cosign/bundle" + "github.com/sigstore/cosign/v3/pkg/cosign/env" + "github.com/sigstore/cosign/v3/pkg/cosign/kubernetes" + "github.com/sigstore/cosign/v3/pkg/oci/mutate" + ociremote "github.com/sigstore/cosign/v3/pkg/oci/remote" + sigs "github.com/sigstore/cosign/v3/pkg/signature" + v1 "github.com/sigstore/protobuf-specs/gen/pb-go/common/v1" "github.com/sigstore/sigstore-go/pkg/root" "github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/sigstore/sigstore/pkg/signature" "github.com/sigstore/sigstore/pkg/signature/payload" - tsaclient "github.com/sigstore/timestamp-authority/pkg/client" - "github.com/sigstore/timestamp-authority/pkg/server" + tsaclient "github.com/sigstore/timestamp-authority/v2/pkg/client" + "github.com/sigstore/timestamp-authority/v2/pkg/server" "github.com/spf13/viper" _ "k8s.io/client-go/plugin/pkg/client/auth" ) @@ -102,7 +114,7 @@ func TestSignVerify(t *testing.T) { // Verify should fail at first mustErr(verify(pubKeyPath, imgName, true, nil, "", false), t) // So should download - mustErr(download.SignatureCmd(ctx, options.RegistryOptions{}, imgName), t) + mustErr(download.SignatureCmd(ctx, options.RegistryOptions{}, imgName, os.Stdout), t) // Now sign the image ko := options.KeyOpts{ @@ -115,11 +127,19 @@ func TestSignVerify(t *testing.T) { Upload: true, TlogUpload: true, } - must(sign.SignCmd(ro, ko, so, []string{imgName}), t) + must(sign.SignCmd(ctx, ro, ko, so, []string{imgName}), t) // Now verify and download should work! must(verify(pubKeyPath, imgName, true, nil, "", false), t) - must(download.SignatureCmd(ctx, options.RegistryOptions{}, imgName), t) + must(download.SignatureCmd(ctx, options.RegistryOptions{}, imgName, os.Stdout), t) + + // Ensure it verifies if you default to the new protobuf bundle format + cmd := cliverify.VerifyCommand{ + KeyRef: pubKeyPath, + RekorURL: rekorURL, + NewBundleFormat: true, + } + must(cmd.Exec(ctx, []string{imgName}), t) // Look for a specific annotation mustErr(verify(pubKeyPath, imgName, true, map[string]interface{}{"foo": "bar"}, "", false), t) @@ -128,7 +148,7 @@ func TestSignVerify(t *testing.T) { Annotations: []string{"foo=bar"}, } // Sign the image with an annotation - must(sign.SignCmd(ro, ko, so, []string{imgName}), t) + must(sign.SignCmd(ctx, ro, ko, so, []string{imgName}), t) // It should match this time. must(verify(pubKeyPath, imgName, true, map[string]interface{}{"foo": "bar"}, "", false), t) @@ -160,7 +180,7 @@ func TestSignVerifyCertBundle(t *testing.T) { // Verify should fail at first mustErr(verifyCertBundle(pubKeyPath, caCertFile, caIntermediateCertFile, imgName, true, nil, "", true), t) // So should download - mustErr(download.SignatureCmd(ctx, options.RegistryOptions{}, imgName), t) + mustErr(download.SignatureCmd(ctx, options.RegistryOptions{}, imgName, os.Stdout), t) // Now sign the image ko := options.KeyOpts{ @@ -173,14 +193,14 @@ func TestSignVerifyCertBundle(t *testing.T) { Upload: true, TlogUpload: true, } - must(sign.SignCmd(ro, ko, so, []string{imgName}), t) + must(sign.SignCmd(ctx, ro, ko, so, []string{imgName}), t) // Now verify and download should work! ignoreTlog := true must(verifyCertBundle(pubKeyPath, caCertFile, caIntermediateCertFile, imgName, true, nil, "", ignoreTlog), t) // verification with certificate chain instead of root/intermediate files should work as well must(verifyCertChain(pubKeyPath, certChainFile, certFile, imgName, true, nil, "", ignoreTlog), t) - must(download.SignatureCmd(ctx, options.RegistryOptions{}, imgName), t) + must(download.SignatureCmd(ctx, options.RegistryOptions{}, imgName, os.Stdout), t) // Look for a specific annotation mustErr(verifyCertBundle(pubKeyPath, caCertFile, caIntermediateCertFile, imgName, true, map[string]interface{}{"foo": "bar"}, "", ignoreTlog), t) @@ -189,7 +209,7 @@ func TestSignVerifyCertBundle(t *testing.T) { Annotations: []string{"foo=bar"}, } // Sign the image with an annotation - must(sign.SignCmd(ro, ko, so, []string{imgName}), t) + must(sign.SignCmd(ctx, ro, ko, so, []string{imgName}), t) // It should match this time. must(verifyCertBundle(pubKeyPath, caCertFile, caIntermediateCertFile, imgName, true, map[string]interface{}{"foo": "bar"}, "", ignoreTlog), t) @@ -227,11 +247,11 @@ func TestSignVerifyClean(t *testing.T) { Upload: true, TlogUpload: true, } - must(sign.SignCmd(ro, ko, so, []string{imgName}), t) + must(sign.SignCmd(ctx, ro, ko, so, []string{imgName}), t) // Now verify and download should work! must(verify(pubKeyPath, imgName, true, nil, "", false), t) - must(download.SignatureCmd(ctx, options.RegistryOptions{}, imgName), t) + must(download.SignatureCmd(ctx, options.RegistryOptions{}, imgName, os.Stdout), t) // Now clean signature from the given image must(cli.CleanCmd(ctx, options.RegistryOptions{}, "all", imgName, true), t) @@ -269,17 +289,39 @@ func TestImportSignVerifyClean(t *testing.T) { Upload: true, TlogUpload: true, } - must(sign.SignCmd(ro, ko, so, []string{imgName}), t) + must(sign.SignCmd(ctx, ro, ko, so, []string{imgName}), t) // Now verify and download should work! must(verify(pubKeyPath, imgName, true, nil, "", false), t) - must(download.SignatureCmd(ctx, options.RegistryOptions{}, imgName), t) + must(download.SignatureCmd(ctx, options.RegistryOptions{}, imgName, os.Stdout), t) // Now clean signature from the given image must(cli.CleanCmd(ctx, options.RegistryOptions{}, "all", imgName, true), t) // It doesn't work mustErr(verify(pubKeyPath, imgName, true, nil, "", false), t) + + // Sign with new bundle format + so.NewBundleFormat = true + must(sign.SignCmd(ctx, ro, ko, so, []string{imgName}), t) + + // Verify should work again + trustedRootPath := prepareTrustedRoot(t, "") + bundleVerifyCmd := cliverify.VerifyCommand{ + CommonVerifyOptions: options.CommonVerifyOptions{ + TrustedRootPath: trustedRootPath, + }, + KeyRef: pubKeyPath, + NewBundleFormat: true, + UseSignedTimestamps: false, + } + must(bundleVerifyCmd.Exec(ctx, []string{imgName}), t) + + // Clean again + must(cli.CleanCmd(ctx, options.RegistryOptions{}, "all", imgName, true), t) + + // Verify should fail again + mustErr(bundleVerifyCmd.Exec(ctx, []string{imgName}), t) } type targetInfo struct { @@ -294,7 +336,7 @@ func downloadTargets(td string, targets []targetInfo, targetsMeta *metadata.Meta if err != nil { return err } - err = os.Mkdir(targetsDir, 0700) + err = os.Mkdir(targetsDir, 0o700) if err != nil { return err } @@ -556,8 +598,7 @@ func downloadTSACerts(downloadDirectory string, tsaServer string) (string, strin return leafPath, intermediatePath, rootPath, nil } -func prepareTrustedRoot(t *testing.T, tsaURL string) string { - downloadDirectory := t.TempDir() +func trustedRootCmd(t *testing.T, downloadDirectory, tsaURL string) *trustedroot.CreateCmd { caPath := filepath.Join(downloadDirectory, "fulcio.crt.pem") caFP, err := os.Create(caPath) must(err, t) @@ -572,20 +613,36 @@ func prepareTrustedRoot(t *testing.T, tsaURL string) string { home, err := os.UserHomeDir() must(err, t) must(copyFile(filepath.Join(home, "fulcio", "config", "ctfe", "pubkey.pem"), ctfePath), t) - tsaPath := filepath.Join(downloadDirectory, "tsa.crt.pem") - tsaFP, err := os.Create(tsaPath) - must(err, t) - must(downloadFile(tsaURL+"/api/v1/timestamp/certchain", tsaFP), t) out := filepath.Join(downloadDirectory, "trusted_root.json") cmd := &trustedroot.CreateCmd{ - CertChain: []string{caPath}, - CtfeKeyPath: []string{ctfePath}, - Out: out, - RekorKeyPath: []string{rekorPath}, - TSACertChainPath: []string{tsaPath}, - } + CertChain: []string{caPath}, + CtfeKeyPath: []string{ctfePath}, + Out: out, + RekorKeyPath: []string{rekorPath}, + } + if tsaURL != "" { + tsaPath := filepath.Join(downloadDirectory, "tsa.crt.pem") + tsaFP, err := os.Create(tsaPath) + must(err, t) + must(downloadFile(tsaURL+"/api/v1/timestamp/certchain", tsaFP), t) + cmd.TSACertChainPath = []string{tsaPath} + } + return cmd +} + +func prepareTrustedRoot(t *testing.T, tsaURL string) string { + downloadDirectory := t.TempDir() + cmd := trustedRootCmd(t, downloadDirectory, tsaURL) must(cmd.Exec(context.TODO()), t) - return out + return cmd.Out +} + +func prepareTrustedRootWithSelfSignedCertificate(t *testing.T, certPath, tsaURL string) string { + td := t.TempDir() + cmd := trustedRootCmd(t, td, tsaURL) + cmd.CertChain = append(cmd.CertChain, certPath) + must(cmd.Exec(context.TODO()), t) + return cmd.Out } func TestSignVerifyWithTUFMirror(t *testing.T) { @@ -770,7 +827,7 @@ func TestSignVerifyWithTUFMirror(t *testing.T) { TlogUpload: true, SkipConfirmation: true, } - gotErr := sign.SignCmd(ro, ko, so, []string{imgName}) + gotErr := sign.SignCmd(ctx, ro, ko, so, []string{imgName}) if test.wantSignErr { mustErr(gotErr, t) return @@ -799,7 +856,7 @@ func TestSignVerifyWithTUFMirror(t *testing.T) { blob := "someblob" blobDir := t.TempDir() bp := filepath.Join(blobDir, blob) - if err := os.WriteFile(bp, []byte(blob), 0644); err != nil { + if err := os.WriteFile(bp, []byte(blob), 0o644); err != nil { t.Fatal(err) } tsPath := filepath.Join(blobDir, "ts.txt") @@ -807,7 +864,7 @@ func TestSignVerifyWithTUFMirror(t *testing.T) { // TODO(cmurphy): make this work with ko.NewBundleFormat = true ko.BundlePath = bundlePath ko.RFC3161TimestampPath = tsPath - _, gotErr = sign.SignBlobCmd(ro, ko, bp, true, "", "", true) + _, gotErr = sign.SignBlobCmd(ctx, ro, ko, bp, "", "", true, "", "", true) if test.wantSignErr { mustErr(gotErr, t) } else { @@ -834,162 +891,750 @@ func TestSignVerifyWithTUFMirror(t *testing.T) { } } -func TestAttestVerify(t *testing.T) { - for _, newBundleFormat := range []bool{false, true} { - attestVerify(t, - newBundleFormat, - "slsaprovenance", - `{ "buildType": "x", "builder": { "id": "2" }, "recipe": {} }`, - `predicate: builder: id: "2"`, - `predicate: builder: id: "1"`, - ) +func prepareSigningConfig(t *testing.T, fulcioURL, rekorURL, oidcURL, tsaURL string) string { //nolint: unparam + startTime := "2024-01-01T00:00:00Z" + fulcioSpec := fmt.Sprintf("url=%s,api-version=1,operator=fulcio-op,start-time=%s", fulcioURL, startTime) + rekorSpec := fmt.Sprintf("url=%s,api-version=1,operator=rekor-op,start-time=%s", rekorURL, startTime) + oidcSpec := fmt.Sprintf("url=%s,api-version=1,operator=oidc-op,start-time=%s", oidcURL, startTime) + tsaSpec := fmt.Sprintf("url=%s,api-version=1,operator=tsa-op,start-time=%s", tsaURL, startTime) + + downloadDirectory := t.TempDir() + out := filepath.Join(downloadDirectory, "signing_config.v0.2.json") + cmd := &signingconfig.CreateCmd{ + FulcioSpecs: []string{fulcioSpec}, + RekorSpecs: []string{rekorSpec}, + OIDCProviderSpecs: []string{oidcSpec}, + TSASpecs: []string{tsaSpec}, + RekorConfig: "EXACT:1", + TSAConfig: "ANY", + Out: out, } + must(cmd.Exec(context.TODO()), t) + return out } -func TestAttestVerifySPDXJSON(t *testing.T) { - attestationBytes, err := os.ReadFile("./testdata/bom-go-mod.spdx.json") +func TestSignAttestVerifyBlobWithSigningConfig(t *testing.T) { + tufLocalCache := t.TempDir() + t.Setenv("TUF_ROOT", tufLocalCache) + tufMirror := t.TempDir() + viper.Set("timestamp-signer", "memory") + viper.Set("timestamp-signer-hash", "sha256") + tsaAPIServer := server.NewRestAPIServer("localhost", 0, []string{"http"}, false, 10*time.Second, 10*time.Second) + tsaServer := httptest.NewServer(tsaAPIServer.GetHandler()) + t.Cleanup(tsaServer.Close) + tufServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + http.FileServer(http.Dir(tufMirror)).ServeHTTP(w, r) + })) + mirror := tufServer.URL + trustedRoot := prepareTrustedRoot(t, tsaServer.URL) + signingConfigStr := prepareSigningConfig(t, fulcioURL, rekorURL, "unused", tsaServer.URL+"/api/v1/timestamp") + sc, err := os.ReadFile(signingConfigStr) + must(err, t) + fmt.Println(string(sc)) + fmt.Println(fulcioURL) + + _, err = newTUF(tufMirror, []targetInfo{ + { + name: "trusted_root.json", + source: trustedRoot, + }, + { + name: "signing_config.v0.2.json", + source: signingConfigStr, + }, + }) + must(err, t) + + ctx := context.Background() + + rootPath := filepath.Join(tufMirror, "1.root.json") + must(initialize.DoInitialize(ctx, rootPath, mirror), t) + + identityToken, err := getOIDCToken() if err != nil { t.Fatal(err) } - for _, newBundleFormat := range []bool{false, true} { - attestVerify(t, - newBundleFormat, - "spdxjson", - string(attestationBytes), - `predicate: spdxVersion: "SPDX-2.2"`, - `predicate: spdxVersion: "SPDX-9.9"`, - ) + + ko := options.KeyOpts{ + IDToken: identityToken, + SkipConfirmation: true, } -} + trustedMaterial, err := cosign.TrustedRoot() + must(err, t) + ko.TrustedMaterial = trustedMaterial + signingConfig, err := cosign.SigningConfig() + must(err, t) + ko.SigningConfig = signingConfig -func TestAttestVerifyCycloneDXJSON(t *testing.T) { - attestationBytes, err := os.ReadFile("./testdata/bom-go-mod.cyclonedx.json") - if err != nil { + // Sign a blob + blob := "someblob" + blobDir := t.TempDir() + bp := filepath.Join(blobDir, blob) + if err := os.WriteFile(bp, []byte(blob), 0o644); err != nil { t.Fatal(err) } - for _, newBundleFormat := range []bool{false, true} { - attestVerify(t, - newBundleFormat, - "cyclonedx", - string(attestationBytes), - `predicate: specVersion: "1.4"`, - `predicate: specVersion: "7.7"`, - ) + bundlePath := filepath.Join(blobDir, "bundle.json") + ko.NewBundleFormat = true + ko.BundlePath = bundlePath + + _, err = sign.SignBlobCmd(ctx, ro, ko, bp, "", "", false, "", "", true) + must(err, t) + + // Verify a blob + issuer := os.Getenv("OIDC_URL") + verifyBlobCmd := cliverify.VerifyBlobCmd{ + KeyOpts: ko, + CertVerifyOptions: options.CertVerifyOptions{ + CertOidcIssuer: issuer, + CertIdentity: certID, + }, + UseSignedTimestamps: true, } -} + err = verifyBlobCmd.Exec(ctx, bp) + must(err, t) -func TestAttestVerifyURI(t *testing.T) { - attestationBytes, err := os.ReadFile("./testdata/test-result.json") - if err != nil { + // Sign an attestation + statement := `{"_type":"https://in-toto.io/Statement/v1","subject":[{"name":"someblob","digest":{"alg":"7e9b6e7ba2842c91cf49f3e214d04a7a496f8214356f41d81a6e6dcad11f11e3"}}],"predicateType":"something","predicate":{}}` + attestDir := t.TempDir() + statementPath := filepath.Join(attestDir, "statement") + if err := os.WriteFile(statementPath, []byte(statement), 0o644); err != nil { t.Fatal(err) } - for _, newBundleFormat := range []bool{false, true} { - attestVerify(t, - newBundleFormat, - "https://example.com/TestResult/v1", - string(attestationBytes), - `predicate: passed: true`, - `predicate: passed: false"`, - ) + attBundlePath := filepath.Join(attestDir, "attest.bundle.json") + ko.NewBundleFormat = true + ko.BundlePath = attBundlePath + + attestBlobCmd := attest.AttestBlobCommand{ + KeyOpts: ko, + RekorEntryType: "dsse", + StatementPath: statementPath, + TlogUpload: true, + } + must(attestBlobCmd.Exec(ctx, bp), t) + + // Verify an attestation + verifyBlobAttestationCmd := cliverify.VerifyBlobAttestationCommand{ + KeyOpts: ko, + CertVerifyOptions: options.CertVerifyOptions{ + CertOidcIssuer: issuer, + CertIdentity: certID, + }, + UseSignedTimestamps: true, + Digest: "7e9b6e7ba2842c91cf49f3e214d04a7a496f8214356f41d81a6e6dcad11f11e3", + DigestAlg: "alg", + CheckClaims: true, } + err = verifyBlobAttestationCmd.Exec(ctx, "") + must(err, t) } -func attestVerify(t *testing.T, newBundleFormat bool, predicateType, attestation, goodCue, badCue string) { +func TestSignAttestVerifyContainerWithSigningConfig(t *testing.T) { + tufLocalCache := t.TempDir() + t.Setenv("TUF_ROOT", tufLocalCache) + tufMirror := t.TempDir() + viper.Set("timestamp-signer", "memory") + viper.Set("timestamp-signer-hash", "sha256") + tsaAPIServer := server.NewRestAPIServer("localhost", 0, []string{"http"}, false, 10*time.Second, 10*time.Second) + tsaServer := httptest.NewServer(tsaAPIServer.GetHandler()) + t.Cleanup(tsaServer.Close) + tufServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + http.FileServer(http.Dir(tufMirror)).ServeHTTP(w, r) + })) + mirror := tufServer.URL + trustedRoot := prepareTrustedRoot(t, tsaServer.URL) + signingConfigStr := prepareSigningConfig(t, fulcioURL, rekorURL, "unused", tsaServer.URL+"/api/v1/timestamp") + + _, err := newTUF(tufMirror, []targetInfo{ + { + name: "trusted_root.json", + source: trustedRoot, + }, + { + name: "signing_config.v0.2.json", + source: signingConfigStr, + }, + }) + must(err, t) + repo, stop := reg(t) defer stop() - td := t.TempDir() - - var imgName, attestationPath string - if _, err := url.ParseRequestURI(predicateType); err == nil { - // If the predicate type is URI, it cannot be included as image name and path. - imgName = path.Join(repo, "cosign-attest-uri-e2e-image") - attestationPath = filepath.Join(td, "cosign-attest-uri-e2e-attestation") - } else { - imgName = path.Join(repo, fmt.Sprintf("cosign-attest-%s-e2e-image", predicateType)) - attestationPath = filepath.Join(td, fmt.Sprintf("cosign-attest-%s-e2e-attestation", predicateType)) - } + imgName := path.Join(repo, "cosign-e2e") _, _, cleanup := mkimage(t, imgName) defer cleanup() - _, privKeyPath, pubKeyPath := keypair(t, td) - ctx := context.Background() - // Verify should fail at first - verifyAttestation := cliverify.VerifyAttestationCommand{ - KeyRef: pubKeyPath, - IgnoreTlog: true, - MaxWorkers: 10, + rootPath := filepath.Join(tufMirror, "1.root.json") + must(initialize.DoInitialize(ctx, rootPath, mirror), t) + + identityToken, err := getOIDCToken() + if err != nil { + t.Fatal(err) } - if newBundleFormat { - verifyAttestation.NewBundleFormat = true + ko := options.KeyOpts{ + IDToken: identityToken, + NewBundleFormat: true, + SkipConfirmation: true, } + trustedMaterial, err := cosign.TrustedRoot() + must(err, t) + ko.TrustedMaterial = trustedMaterial + signingConfig, err := cosign.SigningConfig() + must(err, t) + ko.SigningConfig = signingConfig - // Fail case when using without type and policy flag - mustErr(verifyAttestation.Exec(ctx, []string{imgName}), t) + // Sign image with identity token in bundle format + so := options.SignOptions{ + Upload: true, + NewBundleFormat: true, + TlogUpload: true, + } + must(sign.SignCmd(ctx, ro, ko, so, []string{imgName}), t) - if err := os.WriteFile(attestationPath, []byte(attestation), 0600); err != nil { - t.Fatal(err) + // Verify Fulcio-signed image + cmd := cliverify.VerifyCommand{ + CertVerifyOptions: options.CertVerifyOptions{ + CertOidcIssuer: os.Getenv("OIDC_URL"), + CertIdentity: certID, + }, + NewBundleFormat: true, + UseSignedTimestamps: true, } + args := []string{imgName} + must(cmd.Exec(ctx, args), t) - // Now attest the image - ko := options.KeyOpts{KeyRef: privKeyPath, PassFunc: passFunc, NewBundleFormat: newBundleFormat} + // Attest image + predicate := `{ "buildType": "x", "builder": { "id": "2" }, "recipe": {} }` + predicatePath := filepath.Join(t.TempDir(), "predicate.json") + if err := os.WriteFile(predicatePath, []byte(predicate), 0o644); err != nil { + t.Fatal(err) + } attestCmd := attest.AttestCommand{ KeyOpts: ko, - PredicatePath: attestationPath, - PredicateType: predicateType, + PredicatePath: predicatePath, + PredicateType: "slsaprovenance", Timeout: 30 * time.Second, RekorEntryType: "dsse", + TlogUpload: true, } must(attestCmd.Exec(ctx, imgName), t) - // Use cue to verify attestation - policyPath := filepath.Join(td, "policy.cue") - verifyAttestation.PredicateType = predicateType - verifyAttestation.Policies = []string{policyPath} + // Verify attestation + verifyAttestation := cliverify.VerifyAttestationCommand{ + CertVerifyOptions: options.CertVerifyOptions{ + CertOidcIssuer: os.Getenv("OIDC_URL"), + CertIdentity: certID, + }, + CommonVerifyOptions: options.CommonVerifyOptions{ + NewBundleFormat: true, + }, + PredicateType: "slsaprovenance", + UseSignedTimestamps: true, + CheckClaims: true, + } + must(verifyAttestation.Exec(ctx, []string{imgName}), t) +} - // Fail case - if err := os.WriteFile(policyPath, []byte(badCue), 0600); err != nil { - t.Fatal(err) +func TestSignVerifyContainerWithSigningConfigWithCertificate(t *testing.T) { + tufLocalCache := t.TempDir() + t.Setenv("TUF_ROOT", tufLocalCache) + viper.Set("timestamp-signer", "memory") + viper.Set("timestamp-signer-hash", "sha256") + tsaAPIServer := server.NewRestAPIServer("localhost", 0, []string{"http"}, false, 10*time.Second, 10*time.Second) + tsaServer := httptest.NewServer(tsaAPIServer.GetHandler()) + t.Cleanup(tsaServer.Close) + tufMirror := t.TempDir() + tufServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + http.FileServer(http.Dir(tufMirror)).ServeHTTP(w, r) + })) + mirror := tufServer.URL + + cert, privKey, err := selfSignedCertificate() + must(err, t) + keysDir := t.TempDir() + privKeyPath := filepath.Join(keysDir, "priv.key") + privDer, err := x509.MarshalECPrivateKey(privKey) + must(err, t) + keyWriter, err := os.OpenFile(privKeyPath, os.O_WRONLY|os.O_CREATE, 0o600) + must(err, t) + defer keyWriter.Close() + block := &pem.Block{ + Type: "EC PRIVATE KEY", + Bytes: privDer, } - mustErr(verifyAttestation.Exec(ctx, []string{imgName}), t) + must(pem.Encode(keyWriter, block), t) - // Success case - if err := os.WriteFile(policyPath, []byte(goodCue), 0600); err != nil { - t.Fatal(err) + certPath := filepath.Join(keysDir, "cert.pem") + certWriter, err := os.OpenFile(certPath, os.O_WRONLY|os.O_CREATE, 0o600) + must(err, t) + defer certWriter.Close() + block = &pem.Block{ + Type: "CERTIFICATE", + Bytes: cert.Raw, } - must(verifyAttestation.Exec(ctx, []string{imgName}), t) + must(pem.Encode(certWriter, block), t) - // Look for a specific annotation - mustErr(verify(pubKeyPath, imgName, true, map[string]interface{}{"foo": "bar"}, "", false), t) -} + keys, err := cosign.ImportKeyPair(privKeyPath, passFunc) + must(err, t) + importKeyPath := filepath.Join(keysDir, "import-priv.key") + must(os.WriteFile(importKeyPath, keys.PrivateBytes, 0o600), t) + + trustedRoot := prepareTrustedRootWithSelfSignedCertificate(t, certPath, tsaServer.URL) + signingConfigStr := prepareSigningConfig(t, fulcioURL, rekorURL, "unused", tsaServer.URL+"/api/v1/timestamp") + + _, err = newTUF(tufMirror, []targetInfo{ + { + name: "trusted_root.json", + source: trustedRoot, + }, + { + name: "signing_config.v0.2.json", + source: signingConfigStr, + }, + }) + must(err, t) -func TestAttestationDownload(t *testing.T) { repo, stop := reg(t) defer stop() - td := t.TempDir() - - imgName := path.Join(repo, "cosign-attest-download-e2e") + imgName := path.Join(repo, "cosign-e2e") _, _, cleanup := mkimage(t, imgName) defer cleanup() - _, privKeyPath, _ := keypair(t, td) - ko := options.KeyOpts{KeyRef: privKeyPath, PassFunc: passFunc} - ctx := context.Background() - slsaAttestation := `{ "buildType": "x", "builder": { "id": "2" }, "recipe": {} }` - slsaAttestationPath := filepath.Join(td, "attestation.slsa.json") - if err := os.WriteFile(slsaAttestationPath, []byte(slsaAttestation), 0600); err != nil { - t.Fatal(err) + rootPath := filepath.Join(tufMirror, "1.root.json") + must(initialize.DoInitialize(ctx, rootPath, mirror), t) + + ko := options.KeyOpts{ + NewBundleFormat: true, + SkipConfirmation: true, + KeyRef: importKeyPath, + PassFunc: passFunc, } + trustedMaterial, err := cosign.TrustedRoot() + must(err, t) + ko.TrustedMaterial = trustedMaterial + signingConfig, err := cosign.SigningConfig() + must(err, t) + ko.SigningConfig = signingConfig - vulnAttestation := ` - { - "invocation": { + // Sign image with cert in bundle format + so := options.SignOptions{ + Upload: true, + NewBundleFormat: true, + Key: importKeyPath, + Cert: certPath, + TlogUpload: false, + } + must(sign.SignCmd(ctx, ro, ko, so, []string{imgName}), t) + + // Verify image + cmd := cliverify.VerifyCommand{ + CertVerifyOptions: options.CertVerifyOptions{ + CertOidcIssuerRegexp: ".*", + CertIdentity: "foo@bar.com", + }, + NewBundleFormat: true, + IgnoreSCT: true, + } + args := []string{imgName} + must(cmd.Exec(ctx, args), t) +} + +func TestSignVerifyWithSigningConfigWithKey(t *testing.T) { + tufLocalCache := t.TempDir() + t.Setenv("TUF_ROOT", tufLocalCache) + tufMirror := t.TempDir() + viper.Set("timestamp-signer", "memory") + viper.Set("timestamp-signer-hash", "sha256") + tsaAPIServer := server.NewRestAPIServer("localhost", 0, []string{"http"}, false, 10*time.Second, 10*time.Second) + tsaServer := httptest.NewServer(tsaAPIServer.GetHandler()) + t.Cleanup(tsaServer.Close) + tufServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + http.FileServer(http.Dir(tufMirror)).ServeHTTP(w, r) + })) + mirror := tufServer.URL + trustedRoot := prepareTrustedRoot(t, tsaServer.URL) + signingConfigStr := prepareSigningConfig(t, fulcioURL, rekorURL, "unused", tsaServer.URL+"/api/v1/timestamp") + + _, err := newTUF(tufMirror, []targetInfo{ + { + name: "trusted_root.json", + source: trustedRoot, + }, + { + name: "signing_config.v0.2.json", + source: signingConfigStr, + }, + }) + must(err, t) + + ctx := context.Background() + + rootPath := filepath.Join(tufMirror, "1.root.json") + must(initialize.DoInitialize(ctx, rootPath, mirror), t) + + _, privKeyPath, pubKeyPath := keypair(t, t.TempDir()) + + ko := options.KeyOpts{ + PassFunc: passFunc, + SkipConfirmation: true, + } + trustedMaterial, err := cosign.TrustedRoot() + must(err, t) + ko.TrustedMaterial = trustedMaterial + signingConfig, err := cosign.SigningConfig() + must(err, t) + ko.SigningConfig = signingConfig + + // Sign a blob using a provided key + blob := "someblob" + blobDir := t.TempDir() + bp := filepath.Join(blobDir, blob) + if err := os.WriteFile(bp, []byte(blob), 0o644); err != nil { + t.Fatal(err) + } + bundlePath := filepath.Join(blobDir, "bundle.json") + ko.NewBundleFormat = true + ko.BundlePath = bundlePath + ko.KeyRef = privKeyPath + + _, err = sign.SignBlobCmd(ctx, ro, ko, bp, "", "", false, "", "", true) + must(err, t) + + // Verify a blob with the key in the trusted root + ko.KeyRef = pubKeyPath + verifyBlobCmd := cliverify.VerifyBlobCmd{ + KeyOpts: ko, + } + err = verifyBlobCmd.Exec(ctx, bp) + must(err, t) + + // Sign an attestation with a provided key + statement := `{"_type":"https://in-toto.io/Statement/v1","subject":[{"name":"someblob","digest":{"alg":"7e9b6e7ba2842c91cf49f3e214d04a7a496f8214356f41d81a6e6dcad11f11e3"}}],"predicateType":"something","predicate":{}}` + attestDir := t.TempDir() + statementPath := filepath.Join(attestDir, "statement") + if err := os.WriteFile(statementPath, []byte(statement), 0o644); err != nil { + t.Fatal(err) + } + attBundlePath := filepath.Join(attestDir, "attest.bundle.json") + ko.NewBundleFormat = true + ko.BundlePath = attBundlePath + ko.KeyRef = privKeyPath + + attestBlobCmd := attest.AttestBlobCommand{ + KeyOpts: ko, + RekorEntryType: "dsse", + StatementPath: statementPath, + TlogUpload: true, + } + must(attestBlobCmd.Exec(ctx, bp), t) + + // Verify an attestation with the key in the trusted root + ko.KeyRef = pubKeyPath + verifyBlobAttestationCmd := cliverify.VerifyBlobAttestationCommand{ + KeyOpts: ko, + Digest: "7e9b6e7ba2842c91cf49f3e214d04a7a496f8214356f41d81a6e6dcad11f11e3", + DigestAlg: "alg", + CheckClaims: true, + } + err = verifyBlobAttestationCmd.Exec(ctx, "") + must(err, t) +} + +func TestSignVerifyBundle(t *testing.T) { + td := t.TempDir() + repo, stop := reg(t) + defer stop() + + imgName := path.Join(repo, "cosign-e2e") + + _, _, cleanup := mkimage(t, imgName) + defer cleanup() + + _, privKeyPath, pubKeyPath := keypair(t, td) + + ctx := context.Background() + + // Sign image with key in bundle format + ko := options.KeyOpts{ + KeyRef: privKeyPath, + PassFunc: passFunc, + RekorURL: rekorURL, + SkipConfirmation: true, + } + so := options.SignOptions{ + Upload: true, + NewBundleFormat: true, + TlogUpload: true, + } + must(sign.SignCmd(ctx, ro, ko, so, []string{imgName}), t) + + // Verify bundle + trustedRootPath := prepareTrustedRoot(t, "") + + cmd := cliverify.VerifyCommand{ + CommonVerifyOptions: options.CommonVerifyOptions{ + TrustedRootPath: trustedRootPath, + }, + KeyRef: pubKeyPath, + NewBundleFormat: true, + UseSignedTimestamps: false, + } + args := []string{imgName} + must(cmd.Exec(ctx, args), t) + + // Sign image with key in bundle format without Rekor + _, privKeyPath, pubKeyPath = keypair(t, td) + ko = options.KeyOpts{ + KeyRef: privKeyPath, + PassFunc: passFunc, + SkipConfirmation: true, + } + so = options.SignOptions{ + Upload: true, + NewBundleFormat: true, + TlogUpload: false, + } + must(sign.SignCmd(ctx, ro, ko, so, []string{imgName}), t) + // Verify bundle without Rekor + cmd = cliverify.VerifyCommand{ + CommonVerifyOptions: options.CommonVerifyOptions{ + TrustedRootPath: trustedRootPath, + }, + KeyRef: pubKeyPath, + NewBundleFormat: true, + IgnoreTlog: true, + UseSignedTimestamps: false, + } + must(cmd.Exec(ctx, args), t) + + // Sign image with Fulcio + identityToken, err := getOIDCToken() + if err != nil { + t.Fatal(err) + } + + ko = options.KeyOpts{ + IDToken: identityToken, + FulcioURL: fulcioURL, + RekorURL: rekorURL, + SkipConfirmation: true, + } + so = options.SignOptions{ + Upload: true, + NewBundleFormat: true, + TlogUpload: true, + } + must(sign.SignCmd(ctx, ro, ko, so, []string{imgName}), t) + + // Verify Fulcio-signed image + cmd = cliverify.VerifyCommand{ + CertVerifyOptions: options.CertVerifyOptions{ + CertOidcIssuer: os.Getenv("OIDC_URL"), + CertIdentityRegexp: ".+", + }, + CommonVerifyOptions: options.CommonVerifyOptions{ + TrustedRootPath: trustedRootPath, + }, + NewBundleFormat: true, + UseSignedTimestamps: false, + } + must(cmd.Exec(ctx, args), t) + + // Add annotations and verify claims + _, privKeyPath, pubKeyPath = keypair(t, td) + ko = options.KeyOpts{ + KeyRef: privKeyPath, + PassFunc: passFunc, + RekorURL: rekorURL, + SkipConfirmation: true, + } + so = options.SignOptions{ + Upload: true, + NewBundleFormat: true, + TlogUpload: true, + AnnotationOptions: options.AnnotationOptions{ + Annotations: []string{"foo=bar"}, + }, + } + must(sign.SignCmd(ctx, ro, ko, so, []string{imgName}), t) + cmd = cliverify.VerifyCommand{ + CommonVerifyOptions: options.CommonVerifyOptions{ + TrustedRootPath: trustedRootPath, + }, + KeyRef: pubKeyPath, + NewBundleFormat: true, + UseSignedTimestamps: false, + Annotations: sigs.AnnotationsMap{Annotations: map[string]any{"foo": "bar"}}, + CheckClaims: true, + } + must(cmd.Exec(ctx, args), t) + + // Verfying other annotations should not work + cmd.Annotations.Annotations["baz"] = "bat" + mustErr(cmd.Exec(ctx, args), t) +} + +func TestAttestVerify(t *testing.T) { + for _, newBundleFormat := range []bool{false, true} { + attestVerify(t, + newBundleFormat, + "slsaprovenance", + `{ "buildType": "x", "builder": { "id": "2" }, "recipe": {} }`, + `predicate: builder: id: "2"`, + `predicate: builder: id: "1"`, + ) + } +} + +func TestAttestVerifySPDXJSON(t *testing.T) { + attestationBytes, err := os.ReadFile("./testdata/bom-go-mod.spdx.json") + if err != nil { + t.Fatal(err) + } + for _, newBundleFormat := range []bool{false, true} { + attestVerify(t, + newBundleFormat, + "spdxjson", + string(attestationBytes), + `predicate: spdxVersion: "SPDX-2.2"`, + `predicate: spdxVersion: "SPDX-9.9"`, + ) + } +} + +func TestAttestVerifyCycloneDXJSON(t *testing.T) { + attestationBytes, err := os.ReadFile("./testdata/bom-go-mod.cyclonedx.json") + if err != nil { + t.Fatal(err) + } + for _, newBundleFormat := range []bool{false, true} { + attestVerify(t, + newBundleFormat, + "cyclonedx", + string(attestationBytes), + `predicate: specVersion: "1.4"`, + `predicate: specVersion: "7.7"`, + ) + } +} + +func TestAttestVerifyURI(t *testing.T) { + attestationBytes, err := os.ReadFile("./testdata/test-result.json") + if err != nil { + t.Fatal(err) + } + for _, newBundleFormat := range []bool{false, true} { + attestVerify(t, + newBundleFormat, + "https://example.com/TestResult/v1", + string(attestationBytes), + `predicate: passed: true`, + `predicate: passed: false"`, + ) + } +} + +func attestVerify(t *testing.T, newBundleFormat bool, predicateType, attestation, goodCue, badCue string) { + repo, stop := reg(t) + defer stop() + td := t.TempDir() + + var imgName, attestationPath string + if _, err := url.ParseRequestURI(predicateType); err == nil { + // If the predicate type is URI, it cannot be included as image name and path. + imgName = path.Join(repo, "cosign-attest-uri-e2e-image") + attestationPath = filepath.Join(td, "cosign-attest-uri-e2e-attestation") + } else { + imgName = path.Join(repo, fmt.Sprintf("cosign-attest-%s-e2e-image", predicateType)) + attestationPath = filepath.Join(td, fmt.Sprintf("cosign-attest-%s-e2e-attestation", predicateType)) + } + + _, _, cleanup := mkimage(t, imgName) + defer cleanup() + + _, privKeyPath, pubKeyPath := keypair(t, td) + + ctx := context.Background() + + // Verify should fail at first + verifyAttestation := cliverify.VerifyAttestationCommand{ + KeyRef: pubKeyPath, + IgnoreTlog: true, + MaxWorkers: 10, + } + + if newBundleFormat { + verifyAttestation.NewBundleFormat = true + } + + // Fail case when using without type and policy flag + mustErr(verifyAttestation.Exec(ctx, []string{imgName}), t) + + if err := os.WriteFile(attestationPath, []byte(attestation), 0o600); err != nil { + t.Fatal(err) + } + + // Now attest the image + ko := options.KeyOpts{KeyRef: privKeyPath, PassFunc: passFunc, NewBundleFormat: newBundleFormat} + attestCmd := attest.AttestCommand{ + KeyOpts: ko, + PredicatePath: attestationPath, + PredicateType: predicateType, + Timeout: 30 * time.Second, + RekorEntryType: "dsse", + } + must(attestCmd.Exec(ctx, imgName), t) + + // Use cue to verify attestation + policyPath := filepath.Join(td, "policy.cue") + verifyAttestation.PredicateType = predicateType + verifyAttestation.Policies = []string{policyPath} + + // Fail case + if err := os.WriteFile(policyPath, []byte(badCue), 0o600); err != nil { + t.Fatal(err) + } + mustErr(verifyAttestation.Exec(ctx, []string{imgName}), t) + + // Success case + if err := os.WriteFile(policyPath, []byte(goodCue), 0o600); err != nil { + t.Fatal(err) + } + must(verifyAttestation.Exec(ctx, []string{imgName}), t) + + // Look for a specific annotation + mustErr(verify(pubKeyPath, imgName, true, map[string]interface{}{"foo": "bar"}, "", false), t) +} + +func TestAttestationDownload(t *testing.T) { + repo, stop := reg(t) + defer stop() + td := t.TempDir() + + imgName := path.Join(repo, "cosign-attest-download-e2e") + + _, _, cleanup := mkimage(t, imgName) + defer cleanup() + + _, privKeyPath, _ := keypair(t, td) + ko := options.KeyOpts{KeyRef: privKeyPath, PassFunc: passFunc} + + ctx := context.Background() + + slsaAttestation := `{ "buildType": "x", "builder": { "id": "2" }, "recipe": {} }` + slsaAttestationPath := filepath.Join(td, "attestation.slsa.json") + if err := os.WriteFile(slsaAttestationPath, []byte(slsaAttestation), 0o600); err != nil { + t.Fatal(err) + } + + vulnAttestation := ` + { + "invocation": { "parameters": null, "uri": "invocation.example.com/cosign-testing", "event_id": "", @@ -1011,7 +1656,7 @@ func TestAttestationDownload(t *testing.T) { } ` vulnAttestationPath := filepath.Join(td, "attestation.vuln.json") - if err := os.WriteFile(vulnAttestationPath, []byte(vulnAttestation), 0600); err != nil { + if err := os.WriteFile(vulnAttestationPath, []byte(vulnAttestation), 0o600); err != nil { t.Fatal(err) } @@ -1049,7 +1694,7 @@ func TestAttestationDownload(t *testing.T) { // Call download.AttestationCmd() to ensure success attOpts := options.AttestationDownloadOptions{} - must(download.AttestationCmd(ctx, regOpts, attOpts, imgName), t) + must(download.AttestationCmd(ctx, regOpts, attOpts, imgName, os.Stdout), t) attestations, err := cosign.FetchAttestationsForReference(ctx, ref, attOpts.PredicateType, ociremoteOpts...) if err != nil { @@ -1077,7 +1722,7 @@ func TestAttestationDownloadWithPredicateType(t *testing.T) { slsaAttestation := `{ "buildType": "x", "builder": { "id": "2" }, "recipe": {} }` slsaAttestationPath := filepath.Join(td, "attestation.slsa.json") - if err := os.WriteFile(slsaAttestationPath, []byte(slsaAttestation), 0600); err != nil { + if err := os.WriteFile(slsaAttestationPath, []byte(slsaAttestation), 0o600); err != nil { t.Fatal(err) } @@ -1105,7 +1750,7 @@ func TestAttestationDownloadWithPredicateType(t *testing.T) { } ` vulnAttestationPath := filepath.Join(td, "attestation.vuln.json") - if err := os.WriteFile(vulnAttestationPath, []byte(vulnAttestation), 0600); err != nil { + if err := os.WriteFile(vulnAttestationPath, []byte(vulnAttestation), 0o600); err != nil { t.Fatal(err) } @@ -1145,7 +1790,7 @@ func TestAttestationDownloadWithPredicateType(t *testing.T) { attOpts := options.AttestationDownloadOptions{ PredicateType: "vuln", } - must(download.AttestationCmd(ctx, regOpts, attOpts, imgName), t) + must(download.AttestationCmd(ctx, regOpts, attOpts, imgName, os.Stdout), t) predicateType, _ := options.ParsePredicateType(attOpts.PredicateType) attestations, err := cosign.FetchAttestationsForReference(ctx, ref, predicateType, ociremoteOpts...) @@ -1174,7 +1819,7 @@ func TestAttestationDownloadWithBadPredicateType(t *testing.T) { slsaAttestation := `{ "buildType": "x", "builder": { "id": "2" }, "recipe": {} }` slsaAttestationPath := filepath.Join(td, "attestation.slsa.json") - if err := os.WriteFile(slsaAttestationPath, []byte(slsaAttestation), 0600); err != nil { + if err := os.WriteFile(slsaAttestationPath, []byte(slsaAttestation), 0o600); err != nil { t.Fatal(err) } @@ -1195,7 +1840,7 @@ func TestAttestationDownloadWithBadPredicateType(t *testing.T) { attOpts := options.AttestationDownloadOptions{ PredicateType: "vuln", } - mustErr(download.AttestationCmd(ctx, regOpts, attOpts, imgName), t) + mustErr(download.AttestationCmd(ctx, regOpts, attOpts, imgName, os.Stdout), t) } func TestAttestationReplaceCreate(t *testing.T) { @@ -1215,7 +1860,7 @@ func TestAttestationReplaceCreate(t *testing.T) { slsaAttestation := `{ "buildType": "x", "builder": { "id": "2" }, "recipe": {} }` slsaAttestationPath := filepath.Join(td, "attestation.slsa.json") - if err := os.WriteFile(slsaAttestationPath, []byte(slsaAttestation), 0600); err != nil { + if err := os.WriteFile(slsaAttestationPath, []byte(slsaAttestation), 0o600); err != nil { t.Fatal(err) } @@ -1268,7 +1913,7 @@ func TestAttestationReplace(t *testing.T) { slsaAttestation := `{ "buildType": "x", "builder": { "id": "2" }, "recipe": {} }` slsaAttestationPath := filepath.Join(td, "attestation.slsa.json") - if err := os.WriteFile(slsaAttestationPath, []byte(slsaAttestation), 0600); err != nil { + if err := os.WriteFile(slsaAttestationPath, []byte(slsaAttestation), 0o600); err != nil { t.Fatal(err) } @@ -1313,7 +1958,6 @@ func TestAttestationReplace(t *testing.T) { } must(attestCommand.Exec(ctx, imgName), t) attestations, err = cosign.FetchAttestationsForReference(ctx, ref, attOpts.PredicateType, ociremoteOpts...) - // Download and count the attestations if err != nil { t.Fatal(err) @@ -1367,7 +2011,7 @@ func TestAttestationRFC3161Timestamp(t *testing.T) { slsaAttestation := `{ "buildType": "x", "builder": { "id": "2" }, "recipe": {} }` slsaAttestationPath := filepath.Join(td, "attestation.slsa.json") - if err := os.WriteFile(slsaAttestationPath, []byte(slsaAttestation), 0600); err != nil { + if err := os.WriteFile(slsaAttestationPath, []byte(slsaAttestation), 0o600); err != nil { t.Fatal(err) } @@ -1432,6 +2076,10 @@ func TestAttestationRFC3161Timestamp(t *testing.T) { } must(verifyAttestation.Exec(ctx, []string{imgName}), t) + + // Ensure it verifies if you default to the new protobuf bundle format + verifyAttestation.NewBundleFormat = true + must(verifyAttestation.Exec(ctx, []string{imgName}), t) } func TestAttestationBlobRFC3161Timestamp(t *testing.T) { @@ -1452,12 +2100,12 @@ func TestAttestationBlobRFC3161Timestamp(t *testing.T) { }) bp := filepath.Join(td, blob) - if err := os.WriteFile(bp, []byte(blob), 0600); err != nil { + if err := os.WriteFile(bp, []byte(blob), 0o600); err != nil { t.Fatal(err) } predicatePath := filepath.Join(td, "predicate") - if err := os.WriteFile(predicatePath, []byte(predicate), 0600); err != nil { + if err := os.WriteFile(predicatePath, []byte(predicate), 0o600); err != nil { t.Fatal(err) } @@ -1521,7 +2169,7 @@ func TestAttestationBlobRFC3161Timestamp(t *testing.T) { if err != nil { t.Error(err) } - if err := os.WriteFile(trustedRootPath, trustedRootBytes, 0600); err != nil { + if err := os.WriteFile(trustedRootPath, trustedRootBytes, 0o600); err != nil { t.Fatal(err) } @@ -1562,22 +2210,22 @@ func TestVerifyWithCARoots(t *testing.T) { b := bytes.Buffer{} blobRef := filepath.Join(td, blob) - if err := os.WriteFile(blobRef, []byte(blob), 0644); err != nil { + if err := os.WriteFile(blobRef, []byte(blob), 0o644); err != nil { t.Fatal(err) } must(generate.GenerateCmd(context.Background(), options.RegistryOptions{}, imgName, nil, &b), t) - rootCert, rootKey, _ := GenerateRootCa() - subCert, subKey, _ := GenerateSubordinateCa(rootCert, rootKey) - leafCert, privKey, _ := GenerateLeafCert("subject@mail.com", "oidc-issuer", subCert, subKey) + rootCert, rootKey, _ := cert_test.GenerateRootCa() + subCert, subKey, _ := cert_test.GenerateSubordinateCa(rootCert, rootKey) + leafCert, privKey, _ := cert_test.GenerateLeafCert("subject@mail.com", "oidc-issuer", subCert, subKey) privKeyRef := importECDSAPrivateKey(t, privKey, td, "cosign-test-key.pem") pemRoot := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: rootCert.Raw}) pemSub := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: subCert.Raw}) pemLeaf := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: leafCert.Raw}) - rootCert02, rootKey02, _ := GenerateRootCa() - subCert02, subKey02, _ := GenerateSubordinateCa(rootCert02, rootKey02) - leafCert02, _, _ := GenerateLeafCert("subject02@mail.com", "oidc-issuer02", subCert02, subKey02) + rootCert02, rootKey02, _ := cert_test.GenerateRootCa() + subCert02, subKey02, _ := cert_test.GenerateSubordinateCa(rootCert02, rootKey02) + leafCert02, _, _ := cert_test.GenerateLeafCert("subject02@mail.com", "oidc-issuer02", subCert02, subKey02) pemRoot02 := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: rootCert02.Raw}) pemSub02 := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: subCert02.Raw}) pemLeaf02 := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: leafCert02.Raw}) @@ -1639,7 +2287,7 @@ func TestVerifyWithCARoots(t *testing.T) { KeyRef: privKeyRef, PassFunc: passFunc, } - blobSig, err := sign.SignBlobCmd(ro, ko, blobRef, true, "", "", false) + blobSig, err := sign.SignBlobCmd(ctx, ro, ko, blobRef, "", "", true, "", "", false) if err != nil { t.Fatal(err) } @@ -1811,7 +2459,7 @@ func TestRekorBundle(t *testing.T) { } // Sign the image - must(sign.SignCmd(ro, ko, so, []string{imgName}), t) + must(sign.SignCmd(t.Context(), ro, ko, so, []string{imgName}), t) // Make sure verify works must(verify(pubKeyPath, imgName, true, nil, "", false), t) @@ -1849,7 +2497,7 @@ func TestRekorOutput(t *testing.T) { } // Sign the image - must(sign.SignCmd(ro, ko, so, []string{imgName}), t) + must(sign.SignCmd(t.Context(), ro, ko, so, []string{imgName}), t) // Make sure verify works must(verify(pubKeyPath, imgName, true, nil, "", false), t) @@ -1896,7 +2544,7 @@ func TestFulcioBundle(t *testing.T) { } // Sign the image - must(sign.SignCmd(ro, ko, so, []string{imgName}), t) + must(sign.SignCmd(t.Context(), ro, ko, so, []string{imgName}), t) // Make sure verify works must(verify(pubKeyPath, imgName, true, nil, "", false), t) @@ -1955,7 +2603,7 @@ func TestRFC3161Timestamp(t *testing.T) { } // Sign the image - must(sign.SignCmd(ro, ko, so, []string{imgName}), t) + must(sign.SignCmd(t.Context(), ro, ko, so, []string{imgName}), t) // Make sure verify works against the TSA server must(verifyTSA(pubKeyPath, imgName, true, nil, "", file.Name(), true), t) } @@ -2017,7 +2665,7 @@ func TestRekorBundleAndRFC3161Timestamp(t *testing.T) { } // Sign the image - must(sign.SignCmd(ro, ko, so, []string{imgName}), t) + must(sign.SignCmd(t.Context(), ro, ko, so, []string{imgName}), t) // Make sure verify works against the Rekor and TSA clients must(verifyTSA(pubKeyPath, imgName, true, nil, "", file.Name(), false), t) } @@ -2043,7 +2691,7 @@ func TestDuplicateSign(t *testing.T) { // Verify should fail at first mustErr(verify(pubKeyPath, imgName, true, nil, "", true), t) // So should download - mustErr(download.SignatureCmd(ctx, options.RegistryOptions{}, imgName), t) + mustErr(download.SignatureCmd(ctx, options.RegistryOptions{}, imgName, os.Stdout), t) // Now sign the image ko := options.KeyOpts{ @@ -2053,15 +2701,15 @@ func TestDuplicateSign(t *testing.T) { so := options.SignOptions{ Upload: true, } - must(sign.SignCmd(ro, ko, so, []string{imgName}), t) + must(sign.SignCmd(ctx, ro, ko, so, []string{imgName}), t) // Now verify and download should work! // Ignore the tlog, because uploading to the tlog causes new signatures with new timestamp entries to be appended. must(verify(pubKeyPath, imgName, true, nil, "", true), t) - must(download.SignatureCmd(ctx, options.RegistryOptions{}, imgName), t) + must(download.SignatureCmd(ctx, options.RegistryOptions{}, imgName, os.Stdout), t) // Signing again should work just fine... - must(sign.SignCmd(ro, ko, so, []string{imgName}), t) + must(sign.SignCmd(ctx, ro, ko, so, []string{imgName}), t) se, err := ociremote.SignedEntity(ref, ociremote.WithRemoteOptions(registryClientOpts(ctx)...)) must(err, t) @@ -2091,7 +2739,7 @@ func TestGenerateKeyPairEnvVar(t *testing.T) { if err != nil { t.Fatal(err) } - if _, err := cosign.LoadPrivateKey(keys.PrivateBytes, []byte("foo")); err != nil { + if _, err := cosign.LoadPrivateKey(keys.PrivateBytes, []byte("foo"), nil); err != nil { t.Fatal(err) } } @@ -2177,14 +2825,14 @@ func TestMultipleSignatures(t *testing.T) { Upload: true, TlogUpload: true, } - must(sign.SignCmd(ro, ko, so, []string{imgName}), t) + must(sign.SignCmd(t.Context(), ro, ko, so, []string{imgName}), t) // Now verify should work with that one, but not the other must(verify(pub1, imgName, true, nil, "", false), t) mustErr(verify(pub2, imgName, true, nil, "", false), t) // Now sign with the other key too ko.KeyRef = priv2 - must(sign.SignCmd(ro, ko, so, []string{imgName}), t) + must(sign.SignCmd(t.Context(), ro, ko, so, []string{imgName}), t) // Now verify should work with both must(verify(pub1, imgName, true, nil, "", false), t) @@ -2202,7 +2850,7 @@ func TestSignBlob(t *testing.T) { td2 := t.TempDir() bp := filepath.Join(td1, blob) - if err := os.WriteFile(bp, []byte(blob), 0644); err != nil { + if err := os.WriteFile(bp, []byte(blob), 0o644); err != nil { t.Fatal(err) } @@ -2236,7 +2884,7 @@ func TestSignBlob(t *testing.T) { KeyRef: privKeyPath1, PassFunc: passFunc, } - sig, err := sign.SignBlobCmd(ro, ko, bp, true, "", "", false) + sig, err := sign.SignBlobCmd(ctx, ro, ko, bp, "", "", true, "", "", false) if err != nil { t.Fatal(err) } @@ -2253,7 +2901,7 @@ func TestSignBlobBundle(t *testing.T) { bp := filepath.Join(td1, blob) bundlePath := filepath.Join(td1, "bundle.sig") - if err := os.WriteFile(bp, []byte(blob), 0644); err != nil { + if err := os.WriteFile(bp, []byte(blob), 0o644); err != nil { t.Fatal(err) } @@ -2285,14 +2933,14 @@ func TestSignBlobBundle(t *testing.T) { RekorURL: rekorURL, SkipConfirmation: true, } - if _, err := sign.SignBlobCmd(ro, ko, bp, true, "", "", false); err != nil { + if _, err := sign.SignBlobCmd(ctx, ro, ko, bp, "", "", true, "", "", false); err != nil { t.Fatal(err) } // Now verify should work must(verifyBlobCmd.Exec(ctx, bp), t) // Now we turn on the tlog and sign again - if _, err := sign.SignBlobCmd(ro, ko, bp, true, "", "", true); err != nil { + if _, err := sign.SignBlobCmd(ctx, ro, ko, bp, "", "", true, "", "", true); err != nil { t.Fatal(err) } @@ -2307,7 +2955,7 @@ func TestSignBlobNewBundle(t *testing.T) { blob := "someblob" blobPath := filepath.Join(td1, blob) - if err := os.WriteFile(blobPath, []byte(blob), 0644); err != nil { + if err := os.WriteFile(blobPath, []byte(blob), 0o644); err != nil { t.Fatal(err) } @@ -2338,7 +2986,7 @@ func TestSignBlobNewBundle(t *testing.T) { NewBundleFormat: true, } - if _, err := sign.SignBlobCmd(ro, ko, blobPath, true, "", "", false); err != nil { + if _, err := sign.SignBlobCmd(ctx, ro, ko, blobPath, "", "", true, "", "", false); err != nil { t.Fatal(err) } @@ -2346,6 +2994,164 @@ func TestSignBlobNewBundle(t *testing.T) { must(verifyBlobCmd.Exec(ctx, blobPath), t) } +func TestSignBlobNewBundleNonSHA256(t *testing.T) { + td1 := t.TempDir() + + blob := "someblob" + blobPath := filepath.Join(td1, blob) + if err := os.WriteFile(blobPath, []byte(blob), 0o644); err != nil { + t.Fatal(err) + } + + bundlePath := filepath.Join(td1, "bundle.sigstore.json") + + ctx := context.Background() + + // Generate ecdsa-p521 key + _, privKeyPath, pubKeyPath := keypairWithAlgorithm(t, td1, v1.PublicKeyDetails_PKIX_ECDSA_P521_SHA_512) + + ko := options.KeyOpts{ + KeyRef: privKeyPath, + PassFunc: passFunc, + BundlePath: bundlePath, + NewBundleFormat: true, + } + if _, err := sign.SignBlobCmd(ctx, ro, ko, blobPath, "", "", true, "", "", false); err != nil { + t.Fatal(err) + } + + ko1 := options.KeyOpts{ + KeyRef: pubKeyPath, + BundlePath: bundlePath, + NewBundleFormat: true, + } + verifyBlobCmd := cliverify.VerifyBlobCmd{ + KeyOpts: ko1, + IgnoreTlog: true, + HashAlgorithm: crypto.SHA512, + } + must(verifyBlobCmd.Exec(ctx, blobPath), t) +} + +func TestSignBlobNewBundleNonDefaultAlgorithm(t *testing.T) { + tts := []struct { + algo v1.PublicKeyDetails + }{ + {v1.PublicKeyDetails_PKIX_ECDSA_P384_SHA_384}, + {v1.PublicKeyDetails_PKIX_ECDSA_P521_SHA_512}, + {v1.PublicKeyDetails_PKIX_RSA_PKCS1V15_2048_SHA256}, + {v1.PublicKeyDetails_PKIX_RSA_PKCS1V15_3072_SHA256}, + {v1.PublicKeyDetails_PKIX_RSA_PKCS1V15_4096_SHA256}, + // ed25519 and ed25519ph aren't supported for the default flow. + // By default, we sign using the prehash variant for a ed25519 key. + // Rekor supports ed25519ph for a hashedrekord, but Fulcio doesn't. + } + + td := t.TempDir() + + // set up SIGSTORE_ variables to point to keys for the local instances + err := setLocalEnv(t, td) + if err != nil { + t.Fatal(err) + } + + err = fulcioroots.ReInit() + if err != nil { + t.Fatal(err) + } + + identityToken, err := getOIDCToken() + if err != nil { + t.Fatal(err) + } + + // Use the CreateCmd approach to create a trusted root + rootFile := os.Getenv("SIGSTORE_ROOT_FILE") + ctfePubKey := os.Getenv("SIGSTORE_CT_LOG_PUBLIC_KEY_FILE") + rekorPubKey := os.Getenv("SIGSTORE_REKOR_PUBLIC_KEY") + // Create a temporary file for the trusted root JSON + trustedRootPath := filepath.Join(td, "trustedroot.json") + + // Create a CreateCmd instance + createCmd := trustedroot.CreateCmd{ + CertChain: []string{rootFile}, + Out: trustedRootPath, + RekorKeyPath: []string{rekorPubKey}, + CtfeKeyPath: []string{ctfePubKey}, + } + + // Execute the command to create the trusted root + if err := createCmd.Exec(context.Background()); err != nil { + t.Fatal(err) + } + + for _, tt := range tts { + t.Run(tt.algo.String(), func(t *testing.T) { + td1 := t.TempDir() + + blob := "someblob" + blobPath := filepath.Join(td1, blob) + if err := os.WriteFile(blobPath, []byte(blob), 0o644); err != nil { + t.Fatal(err) + } + + bundlePath := filepath.Join(td1, "bundle.sigstore.json") + + ctx := context.Background() + _, privKeyPath, _ := keypairWithAlgorithm(t, td1, tt.algo) + + verifyBlobCmd := cliverify.VerifyBlobCmd{ + TrustedRootPath: trustedRootPath, + KeyOpts: options.KeyOpts{ + FulcioURL: fulcioURL, + RekorURL: rekorURL, + PassFunc: passFunc, + BundlePath: bundlePath, + NewBundleFormat: true, + SkipConfirmation: true, + }, + CertVerifyOptions: options.CertVerifyOptions{ + CertOidcIssuerRegexp: ".*", + CertIdentityRegexp: ".*", + }, + } + + // Verify should fail before bundle is written + mustErr(verifyBlobCmd.Exec(ctx, blobPath), t) + + // Produce signed bundle + ko := options.KeyOpts{ + FulcioURL: fulcioURL, + RekorURL: rekorURL, + IDToken: identityToken, + KeyRef: privKeyPath, + PassFunc: passFunc, + BundlePath: bundlePath, + NewBundleFormat: true, + IssueCertificateForExistingKey: true, + SkipConfirmation: true, + } + + if _, err := sign.SignBlobCmd(ctx, ro, ko, blobPath, "", "", true, "", "", true); err != nil { + t.Fatal(err) + } + + // Copy bundle to /tmp with test name + bundleBytes, err := os.ReadFile(bundlePath) + if err != nil { + t.Fatal(err) + } + tmpBundlePath := filepath.Join("/tmp", fmt.Sprintf("bundle-%s", tt.algo)) + if err := os.WriteFile(tmpBundlePath, bundleBytes, 0o644); err != nil { + t.Fatal(err) + } + + // Verify should succeed now that bundle is written + must(verifyBlobCmd.Exec(ctx, blobPath), t) + }) + } +} + func TestSignBlobRFC3161TimestampBundle(t *testing.T) { td := t.TempDir() err := downloadAndSetEnv(t, rekorURL+"/api/v1/log/publicKey", env.VariableSigstoreRekorPublicKey.String(), td) @@ -2364,7 +3170,7 @@ func TestSignBlobRFC3161TimestampBundle(t *testing.T) { bundlePath := filepath.Join(td, "bundle.sig") tsPath := filepath.Join(td, "rfc3161Timestamp.json") - if err := os.WriteFile(bp, []byte(blob), 0644); err != nil { + if err := os.WriteFile(bp, []byte(blob), 0o644); err != nil { t.Fatal(err) } @@ -2415,14 +3221,14 @@ func TestSignBlobRFC3161TimestampBundle(t *testing.T) { RekorURL: rekorURL, SkipConfirmation: true, } - if _, err := sign.SignBlobCmd(ro, ko, bp, true, "", "", false); err != nil { + if _, err := sign.SignBlobCmd(ctx, ro, ko, bp, "", "", true, "", "", false); err != nil { t.Fatal(err) } // Now verify should work must(verifyBlobCmd.Exec(ctx, bp), t) // Now we turn on the tlog and sign again - if _, err := sign.SignBlobCmd(ro, ko, bp, true, "", "", true); err != nil { + if _, err := sign.SignBlobCmd(ctx, ro, ko, bp, "", "", true, "", "", true); err != nil { t.Fatal(err) } // Point to a fake rekor server to make sure offline verification of the tlog entry works @@ -2466,14 +3272,22 @@ func TestSaveLoad(t *testing.T) { tests := []struct { description string getSignedEntity func(t *testing.T, n string) (name.Reference, *remote.Descriptor, func()) + newBundle bool }{ { description: "save and load an image", getSignedEntity: mkimage, + newBundle: false, + }, + { + description: "save and load an image bundle", + getSignedEntity: mkimage, + newBundle: true, }, { description: "save and load an image index", getSignedEntity: mkimageindex, + newBundle: false, }, } for i, test := range tests { @@ -2498,23 +3312,45 @@ func TestSaveLoad(t *testing.T) { SkipConfirmation: true, } so := options.SignOptions{ - Upload: true, - TlogUpload: true, + Upload: true, + TlogUpload: true, + NewBundleFormat: test.newBundle, + } + must(sign.SignCmd(ctx, ro, ko, so, []string{imgName}), t) + trustedRootPath := prepareTrustedRoot(t, "") + bundleVerifyCmd := cliverify.VerifyCommand{ + CommonVerifyOptions: options.CommonVerifyOptions{ + TrustedRootPath: trustedRootPath, + }, + KeyRef: pubKeyPath, + NewBundleFormat: true, + UseSignedTimestamps: false, + } + + if test.newBundle { + must(bundleVerifyCmd.Exec(ctx, []string{imgName}), t) + } else { + must(verify(pubKeyPath, imgName, true, nil, "", false), t) } - must(sign.SignCmd(ro, ko, so, []string{imgName}), t) - must(verify(pubKeyPath, imgName, true, nil, "", false), t) // save the image to a temp dir imageDir := t.TempDir() must(cli.SaveCmd(ctx, options.SaveOptions{Directory: imageDir}, imgName), t) // verify the local image using a local key - must(verifyLocal(pubKeyPath, imageDir, true, nil, ""), t) + // if we are not using protobuf bundle format + if !test.newBundle { + must(verifyLocal(pubKeyPath, imageDir, true, nil, ""), t) + } // load the image from the temp dir into a new image and verify the new image imgName2 := path.Join(repo, fmt.Sprintf("save-load-%d-2", i)) must(cli.LoadCmd(ctx, options.LoadOptions{Directory: imageDir}, imgName2), t) - must(verify(pubKeyPath, imgName2, true, nil, "", false), t) + if test.newBundle { + must(bundleVerifyCmd.Exec(ctx, []string{imgName2}), t) + } else { + must(verify(pubKeyPath, imgName2, true, nil, "", false), t) + } }) } } @@ -2548,53 +3384,151 @@ func TestSaveLoadAttestation(t *testing.T) { Upload: true, TlogUpload: true, } - must(sign.SignCmd(ro, ko, so, []string{imgName}), t) + must(sign.SignCmd(ctx, ro, ko, so, []string{imgName}), t) must(verify(pubKeyPath, imgName, true, nil, "", false), t) // now, append an attestation to the image slsaAttestation := `{ "buildType": "x", "builder": { "id": "2" }, "recipe": {} }` slsaAttestationPath := filepath.Join(td, "attestation.slsa.json") - if err := os.WriteFile(slsaAttestationPath, []byte(slsaAttestation), 0600); err != nil { + if err := os.WriteFile(slsaAttestationPath, []byte(slsaAttestation), 0o600); err != nil { t.Fatal(err) } - // Now attest the image - ko = options.KeyOpts{KeyRef: privKeyPath, PassFunc: passFunc} - attestCommand := attest.AttestCommand{ - KeyOpts: ko, - PredicatePath: slsaAttestationPath, - PredicateType: "slsaprovenance", - Timeout: 30 * time.Second, - RekorEntryType: "dsse", - } - must(attestCommand.Exec(ctx, imgName), t) + // Now attest the image + ko = options.KeyOpts{KeyRef: privKeyPath, PassFunc: passFunc} + attestCommand := attest.AttestCommand{ + KeyOpts: ko, + PredicatePath: slsaAttestationPath, + PredicateType: "slsaprovenance", + Timeout: 30 * time.Second, + RekorEntryType: "dsse", + } + must(attestCommand.Exec(ctx, imgName), t) + + // save the image to a temp dir + imageDir := t.TempDir() + must(cli.SaveCmd(ctx, options.SaveOptions{Directory: imageDir}, imgName), t) + + // load the image from the temp dir into a new image and verify the new image + imgName2 := path.Join(repo, "save-load-2") + must(cli.LoadCmd(ctx, options.LoadOptions{Directory: imageDir}, imgName2), t) + must(verify(pubKeyPath, imgName2, true, nil, "", false), t) + // Use cue to verify attestation on the new image + policyPath := filepath.Join(td, "policy.cue") + verifyAttestation := cliverify.VerifyAttestationCommand{ + KeyRef: pubKeyPath, + IgnoreTlog: true, + MaxWorkers: 10, + } + verifyAttestation.PredicateType = "slsaprovenance" + verifyAttestation.Policies = []string{policyPath} + // Success case (remote) + cuePolicy := `predicate: builder: id: "2"` + if err := os.WriteFile(policyPath, []byte(cuePolicy), 0o600); err != nil { + t.Fatal(err) + } + must(verifyAttestation.Exec(ctx, []string{imgName2}), t) + // Success case (local) + verifyAttestation.LocalImage = true + must(verifyAttestation.Exec(ctx, []string{imageDir}), t) +} + +func TestAttestDownloadAttachNewBundle(t *testing.T) { + repo, stop := reg(t) + defer stop() + + imgName := path.Join(repo, "attest-new-bundle") + _, _, cleanup := mkimage(t, imgName) + defer cleanup() + + // Download should fail before attesting + ctx := context.Background() + regOpts := options.RegistryOptions{} + attOpts := options.AttestationDownloadOptions{} + mustErr(download.AttestationCmd(ctx, regOpts, attOpts, imgName, os.Stdout), t) + + // Attest first image + td := t.TempDir() + _, privKeyPath, _ := keypair(t, td) + ko := options.KeyOpts{KeyRef: privKeyPath, PassFunc: passFunc, NewBundleFormat: true} + + slsaAttestation := `{ "buildType": "x", "builder": { "id": "2" }, "recipe": {} }` + slsaAttestationPath := filepath.Join(td, "attestation.slsa.json") + if err := os.WriteFile(slsaAttestationPath, []byte(slsaAttestation), 0o600); err != nil { + t.Fatal(err) + } + + attestCommand := attest.AttestCommand{ + KeyOpts: ko, + PredicatePath: slsaAttestationPath, + PredicateType: "slsaprovenance", + RekorEntryType: "dsse", + } + + must(attestCommand.Exec(ctx, imgName), t) + + // Download should now succeed - redirect stdout to use with attach + out := bytes.Buffer{} + must(download.AttestationCmd(ctx, regOpts, attOpts, imgName, &out), t) + + // Create a new image to attach to + img2Name := path.Join(repo, "attest-new-bundle-2") + _, _, cleanup = mkimage(t, img2Name) + defer cleanup() + + bundlePath := filepath.Join(td, "downloaded-bundle.sigstore.json") + if err := os.WriteFile(bundlePath, out.Bytes(), 0o600); err != nil { + t.Fatal(err) + } + + must(attach.AttestationCmd(ctx, regOpts, []string{bundlePath}, img2Name), t) + + // Download should succeed on second image + must(download.AttestationCmd(ctx, regOpts, attOpts, img2Name, os.Stdout), t) +} + +func TestSignDownloadAttachNewBundle(t *testing.T) { + repo, stop := reg(t) + defer stop() + + imgName := path.Join(repo, "sign-new-bundle") + _, _, cleanup := mkimage(t, imgName) + defer cleanup() + + // Download should fail before attesting + ctx := context.Background() + regOpts := options.RegistryOptions{} + mustErr(download.SignatureCmd(ctx, regOpts, imgName, os.Stdout), t) + + // Sign first image + td := t.TempDir() + _, privKeyPath, _ := keypair(t, td) + ko := options.KeyOpts{KeyRef: privKeyPath, PassFunc: passFunc} + so := options.SignOptions{ + NewBundleFormat: true, + Upload: true, + } + + must(sign.SignCmd(ctx, ro, ko, so, []string{imgName}), t) - // save the image to a temp dir - imageDir := t.TempDir() - must(cli.SaveCmd(ctx, options.SaveOptions{Directory: imageDir}, imgName), t) + // Download should now succeed - redirect stdout to use with attach + out := bytes.Buffer{} + must(download.SignatureCmd(ctx, regOpts, imgName, &out), t) - // load the image from the temp dir into a new image and verify the new image - imgName2 := path.Join(repo, "save-load-2") - must(cli.LoadCmd(ctx, options.LoadOptions{Directory: imageDir}, imgName2), t) - must(verify(pubKeyPath, imgName2, true, nil, "", false), t) - // Use cue to verify attestation on the new image - policyPath := filepath.Join(td, "policy.cue") - verifyAttestation := cliverify.VerifyAttestationCommand{ - KeyRef: pubKeyPath, - IgnoreTlog: true, - MaxWorkers: 10, - } - verifyAttestation.PredicateType = "slsaprovenance" - verifyAttestation.Policies = []string{policyPath} - // Success case (remote) - cuePolicy := `predicate: builder: id: "2"` - if err := os.WriteFile(policyPath, []byte(cuePolicy), 0600); err != nil { + // Create a new image to attach to + img2Name := path.Join(repo, "sign-new-bundle-2") + _, _, cleanup = mkimage(t, img2Name) + defer cleanup() + + bundlePath := filepath.Join(td, "downloaded-bundle.sigstore.json") + if err := os.WriteFile(bundlePath, out.Bytes(), 0o600); err != nil { t.Fatal(err) } - must(verifyAttestation.Exec(ctx, []string{imgName2}), t) - // Success case (local) - verifyAttestation.LocalImage = true - must(verifyAttestation.Exec(ctx, []string{imageDir}), t) + + must(attach.SignatureCmd(ctx, regOpts, "", bundlePath, "", "", "", "", img2Name), t) + + // Download should succeed on second image + must(download.SignatureCmd(ctx, regOpts, img2Name, os.Stdout), t) } func TestAttachSBOM(t *testing.T) { @@ -2665,7 +3599,7 @@ func TestAttachSBOM(t *testing.T) { TlogUpload: true, Attachment: "sbom", } - must(sign.SignCmd(ro, ko1, so, []string{imgName}), t) + must(sign.SignCmd(ctx, ro, ko1, so, []string{imgName}), t) // Now verify should work with that one, but not the other must(verify(pubKeyPath1, imgName, true, nil, "sbom", false), t) @@ -2696,7 +3630,7 @@ func TestNoTlog(t *testing.T) { so := options.SignOptions{ Upload: true, } - must(sign.SignCmd(ro, ko, so, []string{imgName}), t) + must(sign.SignCmd(t.Context(), ro, ko, so, []string{imgName}), t) // Now verify should work! must(verify(pubKeyPath, imgName, true, nil, "", true), t) @@ -2709,7 +3643,7 @@ func TestGetPublicKeyCustomOut(t *testing.T) { outFile := "output.pub" outPath := filepath.Join(td, outFile) - outWriter, err := os.OpenFile(outPath, os.O_WRONLY|os.O_CREATE, 0600) + outWriter, err := os.OpenFile(outPath, os.O_WRONLY|os.O_CREATE, 0o600) must(err, t) pk := publickey.Pkopts{ @@ -2756,7 +3690,7 @@ func TestInvalidBundle(t *testing.T) { TlogUpload: true, SkipConfirmation: true, } - must(sign.SignCmd(ro, ko, so, []string{img1}), t) + must(sign.SignCmd(ctx, ro, ko, so, []string{img1}), t) // verify image1 must(verify(pubKeyPath, img1, true, nil, "", false), t) // extract the bundle from image1 @@ -2784,7 +3718,7 @@ func TestInvalidBundle(t *testing.T) { Upload: true, TlogUpload: false, } - must(sign.SignCmd(ro, ko, so, []string{img2}), t) + must(sign.SignCmd(ctx, ro, ko, so, []string{img2}), t) must(verify(pubKeyPath, img2, true, nil, "", true), t) si2, err := ociremote.SignedEntity(imgRef2, remoteOpts) @@ -2835,7 +3769,7 @@ func TestAttestBlobSignVerify(t *testing.T) { blob := "someblob" predicate := `{ "buildType": "x", "builder": { "id": "2" }, "recipe": {} }` predicateType := "slsaprovenance" - statement := `{"_type":"https://in-toto.io/Statement/v1","subject":[{"name":"someblob","digest":{"alg":"123"}}],"predicateType":"something","predicate":{}}` + statement := `{"_type":"https://in-toto.io/Statement/v1","subject":[{"name":"someblob","digest":{"alg":"7e9b6e7ba2842c91cf49f3e214d04a7a496f8214356f41d81a6e6dcad11f11e3"}}],"predicateType":"something","predicate":{}}` td1 := t.TempDir() t.Cleanup(func() { @@ -2843,22 +3777,22 @@ func TestAttestBlobSignVerify(t *testing.T) { }) bp := filepath.Join(td1, blob) - if err := os.WriteFile(bp, []byte(blob), 0644); err != nil { + if err := os.WriteFile(bp, []byte(blob), 0o644); err != nil { t.Fatal(err) } anotherBlob := filepath.Join(td1, "another-blob") - if err := os.WriteFile(anotherBlob, []byte("another-blob"), 0644); err != nil { + if err := os.WriteFile(anotherBlob, []byte("another-blob"), 0o644); err != nil { t.Fatal(err) } predicatePath := filepath.Join(td1, "predicate") - if err := os.WriteFile(predicatePath, []byte(predicate), 0644); err != nil { + if err := os.WriteFile(predicatePath, []byte(predicate), 0o644); err != nil { t.Fatal(err) } statementPath := filepath.Join(td1, "statement") - if err := os.WriteFile(statementPath, []byte(statement), 0644); err != nil { + if err := os.WriteFile(statementPath, []byte(statement), 0o644); err != nil { t.Fatal(err) } @@ -2920,7 +3854,7 @@ func TestAttestBlobSignVerify(t *testing.T) { } blobVerifyAttestationCmd = cliverify.VerifyBlobAttestationCommand{ KeyOpts: ko, - Digest: "123", + Digest: "7e9b6e7ba2842c91cf49f3e214d04a7a496f8214356f41d81a6e6dcad11f11e3", DigestAlg: "alg", SignaturePath: outputSignature, IgnoreTlog: true, @@ -2955,7 +3889,7 @@ func TestOffline(t *testing.T) { TlogUpload: true, SkipConfirmation: true, } - must(sign.SignCmd(ro, ko, so, []string{img1}), t) + must(sign.SignCmd(ctx, ro, ko, so, []string{img1}), t) // verify image1 online and offline must(verify(pubKeyPath, img1, true, nil, "", false), t) verifyCmd := &cliverify.VerifyCommand{ @@ -3051,8 +3985,8 @@ func TestDockerfileVerify(t *testing.T) { SkipConfirmation: true, } ctx := context.Background() - must(sign.SignCmd(ro, ko, so, []string{signedImg1}), t) - must(sign.SignCmd(ro, ko, so, []string{signedImg2}), t) + must(sign.SignCmd(ctx, ro, ko, so, []string{signedImg1}), t) + must(sign.SignCmd(ctx, ro, ko, so, []string{signedImg2}), t) // create the dockerfiles singleStageDockerfileContents := fmt.Sprintf(` @@ -3197,7 +4131,7 @@ func TestManifestVerify(t *testing.T) { SkipConfirmation: true, } ctx := context.Background() - must(sign.SignCmd(ro, ko, so, []string{signedImg}), t) + must(sign.SignCmd(ctx, ro, ko, so, []string{signedImg}), t) // create the manifests manifestTemplate := ` @@ -3267,3 +4201,379 @@ func getOIDCToken() (string, error) { } return string(body), nil } + +func TestSignVerifyWithRepoOverride(t *testing.T) { + cosignRepo := env.Getenv(env.VariableRepository) + if cosignRepo == "" { + t.Skip("Skipping COSIGN_REPOSITORY test because a second repository and COSIGN_REPOSITORY must be set up") + } + td := t.TempDir() + err := downloadAndSetEnv(t, rekorURL+"/api/v1/log/publicKey", env.VariableSigstoreRekorPublicKey.String(), td) + if err != nil { + t.Fatal(err) + } + + repo, stop := reg(t) + defer stop() + + imgName := path.Join(repo, "cosign-e2e") + + name, _, cleanup := mkimage(t, imgName) + defer cleanup() + + digest, err := crane.Digest(name.String()) + must(err, t) + + _, privKeyPath, pubKeyPath := keypair(t, td) + + // Verify should fail at first + mustErr(verify(pubKeyPath, imgName, true, nil, "", false), t) + + // No artifacts yet in the second registry + _, err = crane.ListTags(cosignRepo) + mustErr(err, t) + + // Only one tag in the first registry + tags, err := crane.ListTags(name.String()) + must(err, t) + assert.Len(t, tags, 1, "expected 1 tag in the first repo") + assert.Equal(t, tags[0], "latest", "expected tag name to be 'latest'") + + // Now sign the image + + ko := options.KeyOpts{ + KeyRef: privKeyPath, + PassFunc: passFunc, + RekorURL: rekorURL, + SkipConfirmation: true, + } + + so := options.SignOptions{ + Upload: true, + TlogUpload: true, + } + + must(sign.SignCmd(t.Context(), ro, ko, so, []string{imgName}), t) + + // Bundle should appear in the second repo + tags, err = crane.ListTags(cosignRepo) + must(err, t) + assert.Len(t, tags, 1, "expected 1 signature tag in the second repo") + expectedTagName := fmt.Sprintf("%s.sig", strings.ReplaceAll(digest, ":", "-")) + assert.Equal(t, tags[0], expectedTagName, "expected signature tag to match sha256-.sig") + // but not in the first repo + tags, err = crane.ListTags(name.String()) + must(err, t) + assert.Len(t, tags, 1, "expected no extra tags in the first repo") + assert.Equal(t, tags[0], "latest", "expected tag name to be 'latest'") + + // Now verify and download should work! + must(verify(pubKeyPath, imgName, true, nil, "", false), t) + + // Sign another image with the new protobuf bundle format + so.NewBundleFormat = true + must(sign.SignCmd(t.Context(), ro, ko, so, []string{name.String()}), t) + + // The new bundle should appear under a new tag for the second repo + tags, err = crane.ListTags(cosignRepo) + must(err, t) + assert.Len(t, tags, 2, "expected new tag in the second repo") + expectedTagName = strings.ReplaceAll(digest, ":", "-") + assert.Equal(t, tags[0], expectedTagName, "expected new tag to match referrers format") + // but not in the first repo + tags, err = crane.ListTags(name.String()) + must(err, t) + assert.Len(t, tags, 1, "expected no extra tags in the first repo") + assert.Equal(t, tags[0], "latest", "expected tag name to be 'latest'") + + // Verify should work with new bundle format + cmd := cliverify.VerifyCommand{ + KeyRef: pubKeyPath, + RekorURL: rekorURL, + NewBundleFormat: true, + } + + ctx := context.Background() + must(cmd.Exec(ctx, []string{imgName}), t) +} + +func TestSignVerifyMultipleIdentities(t *testing.T) { + td := t.TempDir() + err := downloadAndSetEnv(t, rekorURL+"/api/v1/log/publicKey", env.VariableSigstoreRekorPublicKey.String(), td) + if err != nil { + t.Fatal(err) + } + + repo, stop := reg(t) + defer stop() + + imgName := path.Join(repo, "cosign-e2e") + + _, _, cleanup := mkimage(t, imgName) + defer cleanup() + + _, privKeyPath, pubKeyPath := keypair(t, td) + + // Verify should fail at first + mustErr(verify(pubKeyPath, imgName, true, nil, "", false), t) + + // Now sign the image with multiple container identities + ko := options.KeyOpts{ + KeyRef: privKeyPath, + PassFunc: passFunc, + RekorURL: rekorURL, + SkipConfirmation: true, + } + so := options.SignOptions{ + Upload: true, + TlogUpload: true, + SignContainerIdentities: []string{"registry/cosign-e2e:tag1", "registry/cosign-e2e:tag2"}, + } + must(sign.SignCmd(t.Context(), ro, ko, so, []string{imgName}), t) + + // Now verify should work + must(verify(pubKeyPath, imgName, true, nil, "", false), t) +} + +func TestTree(t *testing.T) { + repo, stop := reg(t) + defer stop() + + imgName := path.Join(repo, "tree") + _, _, cleanup := mkimage(t, imgName) + defer cleanup() + + // Test out tree command before + ctx := context.Background() + regOpts := options.RegistryOptions{} + regExpOpts := options.RegistryExperimentalOptions{} + out := bytes.Buffer{} + + must(cli.TreeCmd(ctx, regOpts, regExpOpts, true, imgName, &out), t) + assert.False(t, strings.Contains(out.String(), "https://sigstore.dev/cosign/sign/v1")) + + // Sign the image + td := t.TempDir() + _, privKeyPath, _ := keypair(t, td) + ko := options.KeyOpts{KeyRef: privKeyPath, PassFunc: passFunc} + so := options.SignOptions{ + NewBundleFormat: true, + Upload: true, + } + + must(sign.SignCmd(t.Context(), ro, ko, so, []string{imgName}), t) + + // Test out tree command after sign + out.Reset() + must(cli.TreeCmd(ctx, regOpts, regExpOpts, true, imgName, &out), t) + assert.True(t, strings.Contains(out.String(), "https://sigstore.dev/cosign/sign/v1")) +} + +func TestSignVerifyUploadFalse(t *testing.T) { + td := t.TempDir() + ctx := context.Background() + + repo, stop := reg(t) + defer stop() + + imgName := path.Join(repo, "cosign-e2e-no-upload") + name, desc, cleanup := mkimage(t, imgName) + defer cleanup() + + _, privKeyPath, _ := keypair(t, td) + + regOpts := options.RegistryOptions{} + regExpOpts := options.RegistryExperimentalOptions{} + out := bytes.Buffer{} + + // There should be no signatures yet + must(cli.TreeCmd(ctx, regOpts, regExpOpts, true, imgName, &out), t) + assert.Contains(t, out.String(), "No Supply Chain Security Related Artifacts found for image") + + // Now sign the image with Upload: false + ko := options.KeyOpts{ + KeyRef: privKeyPath, + PassFunc: passFunc, + SkipConfirmation: true, + } + so := options.SignOptions{ + Upload: false, + } + must(sign.SignCmd(t.Context(), ro, ko, so, []string{imgName}), t) + + // There should still be no signatures + out.Reset() + must(cli.TreeCmd(ctx, regOpts, regExpOpts, true, imgName, &out), t) + assert.Contains(t, out.String(), "No Supply Chain Security Related Artifacts found for image") + + // Now with Upload: true + so.Upload = true + must(sign.SignCmd(t.Context(), ro, ko, so, []string{imgName}), t) + + // Now there should be signatures + out.Reset() + must(cli.TreeCmd(ctx, regOpts, regExpOpts, true, imgName, &out), t) + assert.Contains(t, out.String(), fmt.Sprintf("Signatures for an image tag: %s:%s-%s.sig", name, desc.Digest.Algorithm, desc.Digest.Hex)) + + // Try on a new image with new bundle format + imgName = path.Join(repo, "cosign-e2e-no-upload-bundle") + name2, _, cleanup2 := mkimage(t, imgName) + defer cleanup2() + + // There should be no signatures yet + out.Reset() + must(cli.TreeCmd(ctx, regOpts, regExpOpts, true, imgName, &out), t) + assert.Contains(t, out.String(), "No Supply Chain Security Related Artifacts found for image") + + // Now sign the image with Upload: false + so.Upload = false + so.NewBundleFormat = true + so.BundlePath = path.Join(td, "output.bundle") + must(sign.SignCmd(t.Context(), ro, ko, so, []string{imgName}), t) + assert.FileExists(t, so.BundlePath) + + // There should still be no signatures + out.Reset() + must(cli.TreeCmd(ctx, regOpts, regExpOpts, true, imgName, &out), t) + assert.Contains(t, out.String(), "No Supply Chain Security Related Artifacts found for image") + + // Now with Upload: true + so.Upload = true + must(sign.SignCmd(t.Context(), ro, ko, so, []string{imgName}), t) + + // Now there should be signatures + out.Reset() + must(cli.TreeCmd(ctx, regOpts, regExpOpts, true, imgName, &out), t) + assert.Regexp(t, regexp.MustCompile(fmt.Sprintf("https://sigstore.dev/cosign/sign/v1 artifacts via OCI referrer: %s@sha256:[a-z0-9]*\n", name2)), out.String()) + assert.FileExists(t, so.BundlePath) + f, err := os.Open(so.BundlePath) + must(err, t) + defer f.Close() + h := sha256.New() + _, err = io.Copy(h, f) + must(err, t) + assert.Contains(t, out.String(), fmt.Sprintf("sha256:%s", hex.EncodeToString(h.Sum(nil)))) +} + +func TestAttestVerifyUploadFalse(t *testing.T) { + td := t.TempDir() + ctx := context.Background() + + repo, stop := reg(t) + defer stop() + + imgName := path.Join(repo, "cosign-e2e-no-upload") + name, desc, cleanup := mkimage(t, imgName) + defer cleanup() + + _, privKeyPath, _ := keypair(t, td) + + regOpts := options.RegistryOptions{} + regExpOpts := options.RegistryExperimentalOptions{} + out := bytes.Buffer{} + + // There should be no attestations yet + must(cli.TreeCmd(ctx, regOpts, regExpOpts, true, imgName, &out), t) + assert.Contains(t, out.String(), "No Supply Chain Security Related Artifacts found for image") + + // Now attest the image with NoUpload: true + ko := options.KeyOpts{ + KeyRef: privKeyPath, + PassFunc: passFunc, + SkipConfirmation: true, + } + predicate := `{ "buildType": "x", "builder": { "id": "2" }, "recipe": {} }` + predicatePath := filepath.Join(t.TempDir(), "predicate.json") + if err := os.WriteFile(predicatePath, []byte(predicate), 0o644); err != nil { + t.Fatal(err) + } + attestCmd := attest.AttestCommand{ + KeyOpts: ko, + PredicatePath: predicatePath, + PredicateType: "slsaprovenance", + RekorEntryType: "dsse", + NoUpload: true, + } + must(attestCmd.Exec(ctx, imgName), t) + + // There should still be no attestations + out.Reset() + must(cli.TreeCmd(ctx, regOpts, regExpOpts, true, imgName, &out), t) + assert.Contains(t, out.String(), "No Supply Chain Security Related Artifacts found for image") + + // Now with NoUpload: false + attestCmd.NoUpload = false + must(attestCmd.Exec(ctx, imgName), t) + + // Now there should be attestations + out.Reset() + must(cli.TreeCmd(ctx, regOpts, regExpOpts, true, imgName, &out), t) + assert.Contains(t, out.String(), fmt.Sprintf("Attestations for an image tag: %s:%s-%s.att", name, desc.Digest.Algorithm, desc.Digest.Hex)) + + // Try on a new image with new bundle format + imgName = path.Join(repo, "cosign-e2e-no-upload-bundle") + name2, _, cleanup2 := mkimage(t, imgName) + defer cleanup2() + + // There should be no attestations yet + out.Reset() + must(cli.TreeCmd(ctx, regOpts, regExpOpts, true, imgName, &out), t) + assert.Contains(t, out.String(), "No Supply Chain Security Related Artifacts found for image") + + // Now attest the image with NoUpload: true + attestCmd.NoUpload = true + attestCmd.NewBundleFormat = true + attestCmd.BundlePath = path.Join(td, "output.bundle") + must(attestCmd.Exec(ctx, imgName), t) + assert.FileExists(t, attestCmd.BundlePath) + + // There should still be no attestations + out.Reset() + must(cli.TreeCmd(ctx, regOpts, regExpOpts, true, imgName, &out), t) + assert.Contains(t, out.String(), "No Supply Chain Security Related Artifacts found for image") + + // Now with NoUpload: true + attestCmd.NoUpload = false + must(attestCmd.Exec(ctx, imgName), t) + + // Now there should be attestations + out.Reset() + must(cli.TreeCmd(ctx, regOpts, regExpOpts, true, imgName, &out), t) + assert.Regexp(t, regexp.MustCompile(fmt.Sprintf("https://slsa.dev/provenance/v0.2 artifacts via OCI referrer: %s@sha256:[a-z0-9]*\n", name2)), out.String()) + assert.FileExists(t, attestCmd.BundlePath) + f, err := os.Open(attestCmd.BundlePath) + must(err, t) + defer f.Close() + h := sha256.New() + _, err = io.Copy(h, f) + must(err, t) + assert.Contains(t, out.String(), fmt.Sprintf("sha256:%s", hex.EncodeToString(h.Sum(nil)))) +} + +func selfSignedCertificate() (*x509.Certificate, *ecdsa.PrivateKey, error) { + priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + return nil, nil, err + } + ct := &x509.Certificate{ + SerialNumber: big.NewInt(1), + Subject: pkix.Name{ + CommonName: "self.signed.cert", + Organization: []string{"dev"}, + }, + EmailAddresses: []string{"foo@bar.com"}, + NotBefore: time.Now().Add(-1 * time.Minute), + NotAfter: time.Now().Add(24 * time.Hour), + KeyUsage: x509.KeyUsageDigitalSignature, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageCodeSigning}, + } + certBytes, err := x509.CreateCertificate(rand.Reader, ct, ct, &priv.PublicKey, priv) + if err != nil { + return nil, nil, err + } + cert, err := x509.ParseCertificate(certBytes) + if err != nil { + return nil, nil, err + } + return cert, priv, nil +} diff --git a/test/e2e_test.ps1 b/test/e2e_test.ps1 index 66e4c30edd7..4228d769a29 100644 --- a/test/e2e_test.ps1 +++ b/test/e2e_test.ps1 @@ -34,9 +34,9 @@ Write-Output $pass | .\cosign.exe generate-key-pair $signing_key = "cosign.key" $verification_key = "cosign.pub" -$test_img = "ghcr.io/distroless/static" -Write-Output $pass | .\cosign.exe sign --key $signing_key --output-signature interactive.sig --output-payload interactive.payload --tlog-upload=false $test_img -.\cosign.exe verify --key $verification_key --signature interactive.sig --payload interactive.payload --insecure-ignore-tlog=true $test_img +Write-Output "hello world" | Out-File -FilePath "hello_world.txt" +Write-Output $pass | .\cosign.exe sign-blob --key $signing_key --bundle test.sigstore.json --use-signing-config=false --tlog-upload=false hello_world.txt +.\cosign.exe verify-blob --key $verification_key --bundle test.sigstore.json --insecure-ignore-tlog=true hello_world.txt Pop-Location diff --git a/test/e2e_test.sh b/test/e2e_test.sh index 32c45566456..d3ccd5bb34e 100755 --- a/test/e2e_test.sh +++ b/test/e2e_test.sh @@ -111,15 +111,25 @@ go test -tags=e2e -v -race ./test/... # Test on a private registry echo "testing sign/verify/clean on private registry" -cleanup() { +cleanup_registry() { cleanup_services docker rm -f registry } -trap cleanup EXIT +trap cleanup_registry EXIT docker run -d -p 5000:5000 --restart always -e REGISTRY_STORAGE_DELETE_ENABLED=true --name registry registry:latest export COSIGN_TEST_REPO=localhost:5000 go test -tags=e2e -v ./test/... -run TestSignVerifyClean +# Test with signature in separate registry +cleanup() { + cleanup_registry + docker rm -f registry-2 +} +trap cleanup EXIT +docker run -d -p 5001:5000 --restart always -e REGISTRY_STORAGE_DELETE_ENABLED=true --name registry-2 registry:latest +export COSIGN_REPOSITORY=localhost:5001/hello +go test -tags=e2e -v ./test/... -run TestSignVerifyWithRepoOverride + # Run the built container to make sure it doesn't crash make ko-local img="ko.local/cosign:$(git rev-parse HEAD)" diff --git a/test/e2e_test_pkcs11.sh b/test/e2e_test_pkcs11.sh index 703ce7c7beb..03f980f9327 100755 --- a/test/e2e_test_pkcs11.sh +++ b/test/e2e_test_pkcs11.sh @@ -36,7 +36,7 @@ apk add go@edge cd /root/cosign softhsm2-util --init-token --free --label "My Token" --pin 1234 --so-pin 1234 -go test -v -cover -coverprofile=./cover.out -tags=softhsm,pkcs11key -coverpkg github.com/sigstore/cosign/v2/pkg/cosign/pkcs11key test/pkcs11_test.go +go test -v -cover -coverprofile=./cover.out -tags=softhsm,pkcs11key -coverpkg github.com/sigstore/cosign/v3/pkg/cosign/pkcs11key test/pkcs11_test.go EOF diff --git a/test/e2e_tsa_test.go b/test/e2e_tsa_test.go index acd873a601c..7b352034856 100644 --- a/test/e2e_tsa_test.go +++ b/test/e2e_tsa_test.go @@ -27,12 +27,13 @@ import ( "time" "github.com/secure-systems-lab/go-securesystemslib/encrypted" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/sign" - cliverify "github.com/sigstore/cosign/v2/cmd/cosign/cli/verify" - "github.com/sigstore/cosign/v2/pkg/cosign" - tsaclient "github.com/sigstore/timestamp-authority/pkg/client" - tsaserver "github.com/sigstore/timestamp-authority/pkg/server" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/sign" + cliverify "github.com/sigstore/cosign/v3/cmd/cosign/cli/verify" + cert_test "github.com/sigstore/cosign/v3/internal/test" + "github.com/sigstore/cosign/v3/pkg/cosign" + tsaclient "github.com/sigstore/timestamp-authority/v2/pkg/client" + tsaserver "github.com/sigstore/timestamp-authority/v2/pkg/server" "github.com/spf13/viper" ) @@ -68,7 +69,7 @@ func TestTSAMTLS(t *testing.T) { Cert: pemLeafRef, CertChain: pemRootRef, } - must(sign.SignCmd(ro, ko, so, []string{imgName}), t) + must(sign.SignCmd(t.Context(), ro, ko, so, []string{imgName}), t) verifyCmd := cliverify.VerifyCommand{ IgnoreTlog: true, @@ -109,7 +110,7 @@ func TestSignBlobTSAMTLS(t *testing.T) { RFC3161TimestampPath: timestampPath, BundlePath: bundlePath, } - sig, err := sign.SignBlobCmd(ro, signingKO, blobPath, true, "", "", false) + sig, err := sign.SignBlobCmd(t.Context(), ro, signingKO, blobPath, "", "", true, "", "", false) must(err, t) verifyKO := options.KeyOpts{ @@ -132,11 +133,11 @@ func TestSignBlobTSAMTLS(t *testing.T) { } func generateSigningKeys(t *testing.T, td string) (string, string, string) { - rootCert, rootKey, _ := GenerateRootCa() + rootCert, rootKey, _ := cert_test.GenerateRootCa() pemRoot := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: rootCert.Raw}) pemRootRef := mkfile(string(pemRoot), td, t) - leafCert, privKey, _ := GenerateLeafCert("xyz@nosuchprovider.com", "oidc-issuer", rootCert, rootKey) + leafCert, privKey, _ := cert_test.GenerateLeafCert("xyz@nosuchprovider.com", "oidc-issuer", rootCert, rootKey) pemLeaf := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: leafCert.Raw}) pemLeafRef := mkfile(string(pemLeaf), td, t) @@ -144,33 +145,36 @@ func generateSigningKeys(t *testing.T, td string) (string, string, string) { encBytes, _ := encrypted.Encrypt(x509Encoded, keyPass) keyPem := pem.EncodeToMemory(&pem.Block{ Type: cosign.CosignPrivateKeyPemType, - Bytes: encBytes}) + Bytes: encBytes, + }) pemKeyRef := mkfile(string(keyPem), td, t) return pemRootRef, pemLeafRef, pemKeyRef } func generateMTLSKeys(t *testing.T, td string) (string, string, string, string, string) { - rootCert, rootKey, _ := GenerateRootCa() + rootCert, rootKey, _ := cert_test.GenerateRootCa() pemRoot := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: rootCert.Raw}) pemRootRef := mkfile(string(pemRoot), td, t) - serverLeafCert, serverPrivKey, _ := GenerateLeafCertWithSubjectAlternateNames([]string{"server.example.com"}, nil, nil, nil, "oidc-issuer", rootCert, rootKey) + serverLeafCert, serverPrivKey, _ := cert_test.GenerateLeafCertWithSubjectAlternateNames([]string{"server.example.com"}, nil, nil, nil, "oidc-issuer", rootCert, rootKey) serverPemLeaf := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: serverLeafCert.Raw}) serverPemLeafRef := mkfile(string(serverPemLeaf), td, t) serverX509Encoded, _ := x509.MarshalPKCS8PrivateKey(serverPrivKey) serverKeyPem := pem.EncodeToMemory(&pem.Block{ Type: cosign.ECPrivateKeyPemType, - Bytes: serverX509Encoded}) + Bytes: serverX509Encoded, + }) serverPemKeyRef := mkfile(string(serverKeyPem), td, t) - clientLeafCert, clientPrivKey, _ := GenerateLeafCert("tsa-mtls-client", "oidc-issuer", rootCert, rootKey) + clientLeafCert, clientPrivKey, _ := cert_test.GenerateLeafCert("tsa-mtls-client", "oidc-issuer", rootCert, rootKey) clientPemLeaf := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: clientLeafCert.Raw}) clientPemLeafRef := mkfile(string(clientPemLeaf), td, t) clientX509Encoded, _ := x509.MarshalPKCS8PrivateKey(clientPrivKey) clientKeyPem := pem.EncodeToMemory(&pem.Block{ Type: cosign.ECPrivateKeyPemType, - Bytes: clientX509Encoded}) + Bytes: clientX509Encoded, + }) clientPemKeyRef := mkfile(string(clientKeyPem), td, t) return pemRootRef, serverPemLeafRef, serverPemKeyRef, clientPemLeafRef, clientPemKeyRef } diff --git a/test/fakeoidc/go.mod b/test/fakeoidc/go.mod index 0b7bc6d3239..8678ec46645 100644 --- a/test/fakeoidc/go.mod +++ b/test/fakeoidc/go.mod @@ -1,7 +1,7 @@ module github.com/sigstore/cosign/test/fakeoidc -go 1.23.4 +go 1.24.0 require github.com/go-jose/go-jose/v4 v4.0.5 -require golang.org/x/crypto v0.35.0 // indirect +require golang.org/x/crypto v0.45.0 // indirect diff --git a/test/fakeoidc/go.sum b/test/fakeoidc/go.sum index 3bb8cc15339..9df61cd64db 100644 --- a/test/fakeoidc/go.sum +++ b/test/fakeoidc/go.sum @@ -8,7 +8,7 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs= -golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ= +golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= +golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/test/fuzz/oss_fuzz_build.sh b/test/fuzz/oss_fuzz_build.sh index 0c0c949fd5c..d74b4aafc96 100755 --- a/test/fuzz/oss_fuzz_build.sh +++ b/test/fuzz/oss_fuzz_build.sh @@ -14,15 +14,14 @@ # See the License for the specific language governing permissions and # limitations under the License. -go get github.com/AdamKorcz/go-118-fuzz-build/testing - mv ./pkg/cosign/keys_test.go ./pkg/cosign/keys_test_keep_in_fuzz_scope.go -compile_native_go_fuzzer github.com/sigstore/cosign/v2/pkg/cosign/attestation FuzzGenerateStatement FuzzGenerateStatement -compile_native_go_fuzzer github.com/sigstore/cosign/v2/pkg/cosign/cue FuzzValidateJSON FuzzValidateJSON_cue -compile_native_go_fuzzer github.com/sigstore/cosign/v2/pkg/cosign/rego FuzzValidateJSON FuzzValidateJSON_rego -compile_native_go_fuzzer github.com/sigstore/cosign/v2/pkg/cosign FuzzImportKeyPairLoadPrivateKey FuzzImportKeyPairLoadPrivateKey -compile_native_go_fuzzer github.com/sigstore/cosign/v2/pkg/cosign FuzzSigVerify FuzzSigVerify -compile_native_go_fuzzer github.com/sigstore/cosign/v2/pkg/policy FuzzEvaluatePolicyAgainstJSON FuzzEvaluatePolicyAgainstJSON +rm ./pkg/cosign/verify_bundle_test.go +compile_native_go_fuzzer_v2 github.com/sigstore/cosign/v3/pkg/cosign/attestation FuzzGenerateStatement FuzzGenerateStatement +compile_native_go_fuzzer_v2 github.com/sigstore/cosign/v3/pkg/cosign/cue FuzzValidateJSON FuzzValidateJSON_cue +compile_native_go_fuzzer_v2 github.com/sigstore/cosign/v3/pkg/cosign/rego FuzzValidateJSON FuzzValidateJSON_rego +compile_native_go_fuzzer_v2 github.com/sigstore/cosign/v3/pkg/cosign FuzzImportKeyPairLoadPrivateKey FuzzImportKeyPairLoadPrivateKey +compile_native_go_fuzzer_v2 github.com/sigstore/cosign/v3/pkg/cosign FuzzSigVerify FuzzSigVerify +compile_native_go_fuzzer_v2 github.com/sigstore/cosign/v3/pkg/policy FuzzEvaluatePolicyAgainstJSON FuzzEvaluatePolicyAgainstJSON zip -j $OUT/FuzzEvaluatePolicyAgainstJSON_seed_corpus.zip test/fuzz/seeds/FuzzEvaluatePolicyAgainstJSON_seed* zip -j $OUT/FuzzEvaluatePolicyAgainstJSON_seed_corpus.zip $SRC/go-fuzz-corpus/json/corpus/* diff --git a/test/helpers.go b/test/helpers.go index 393366eedc2..46ed4291b3b 100644 --- a/test/helpers.go +++ b/test/helpers.go @@ -52,12 +52,14 @@ import ( // Initialize all known client auth plugins _ "k8s.io/client-go/plugin/pkg/client/auth" - "github.com/sigstore/cosign/v2/cmd/cosign/cli/options" - cliverify "github.com/sigstore/cosign/v2/cmd/cosign/cli/verify" - "github.com/sigstore/cosign/v2/pkg/cosign" - "github.com/sigstore/cosign/v2/pkg/cosign/env" - ociremote "github.com/sigstore/cosign/v2/pkg/oci/remote" - sigs "github.com/sigstore/cosign/v2/pkg/signature" + "github.com/sigstore/cosign/v3/cmd/cosign/cli/options" + cliverify "github.com/sigstore/cosign/v3/cmd/cosign/cli/verify" + "github.com/sigstore/cosign/v3/pkg/cosign" + "github.com/sigstore/cosign/v3/pkg/cosign/env" + ociremote "github.com/sigstore/cosign/v3/pkg/oci/remote" + sigs "github.com/sigstore/cosign/v3/pkg/signature" + v1 "github.com/sigstore/protobuf-specs/gen/pb-go/common/v1" + "github.com/sigstore/sigstore/pkg/signature" ) const ( @@ -256,7 +258,11 @@ var verifyOffline = func(keyRef, imageRef string, checkClaims bool, annotations var ro = &options.RootOptions{Timeout: options.DefaultTimeout} -func keypair(t *testing.T, td string) (*cosign.KeysBytes, string, string) { +func keypairWithAlgorithm(t *testing.T, td string, publicKeyDetails v1.PublicKeyDetails) (*cosign.KeysBytes, string, string) { + algo, err := signature.GetAlgorithmDetails(publicKeyDetails) + if err != nil { + t.Fatal(err) + } wd, err := os.Getwd() if err != nil { t.Fatal(err) @@ -267,7 +273,7 @@ func keypair(t *testing.T, td string) (*cosign.KeysBytes, string, string) { defer func() { _ = os.Chdir(wd) }() - keys, err := cosign.GenerateKeyPair(passFunc) + keys, err := cosign.GenerateKeyPairWithAlgorithm(&algo, passFunc) if err != nil { t.Fatal(err) } @@ -284,6 +290,10 @@ func keypair(t *testing.T, td string) (*cosign.KeysBytes, string, string) { return keys, privKeyPath, pubKeyPath } +func keypair(t *testing.T, td string) (*cosign.KeysBytes, string, string) { + return keypairWithAlgorithm(t, td, v1.PublicKeyDetails_PKIX_ECDSA_P256_SHA_256) +} + // convert the given ecdsa.PrivateKey to a PEM encoded string, import into sigstore format, // and write to the given file path. Returns the path to the imported key (/) func importECDSAPrivateKey(t *testing.T, privKey *ecdsa.PrivateKey, td, fname string) string { diff --git a/test/piv_test.go b/test/piv_test.go index eb482e4318c..80d25b37dec 100644 --- a/test/piv_test.go +++ b/test/piv_test.go @@ -29,7 +29,7 @@ import ( "testing" // Import the functions directly for testing. - . "github.com/sigstore/cosign/v2/cmd/cosign/cli/pivcli" + . "github.com/sigstore/cosign/v3/cmd/cosign/cli/pivcli" ) func TestSetManagementKeyCmd(t *testing.T) { diff --git a/test/pkcs11_test.go b/test/pkcs11_test.go index bfe031b9d1c..4b232b6a99b 100644 --- a/test/pkcs11_test.go +++ b/test/pkcs11_test.go @@ -54,8 +54,8 @@ import ( // Import the functions directly for testing. "github.com/miekg/pkcs11" - . "github.com/sigstore/cosign/v2/cmd/cosign/cli/pkcs11cli" - "github.com/sigstore/cosign/v2/pkg/cosign/pkcs11key" + . "github.com/sigstore/cosign/v3/cmd/cosign/cli/pkcs11cli" + "github.com/sigstore/cosign/v3/pkg/cosign/pkcs11key" "github.com/stretchr/testify/require" )