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..123bd2b8456 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@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false - - uses: sigstore/cosign-installer@d58896d6a1865668819e1d91763c7751a165e159 # v3.9.2 + - uses: sigstore/cosign-installer@d7543c93d881b35a8faa02e8e3605f69b7a1ce62 # v3.10.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@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.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..d347ee21eb7 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@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.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@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.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..4567022e695 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@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.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@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.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..a3e47c1af95 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@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.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@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.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@244638a7a138ae9f6106cfe2d44a698eccd3bef7 # v0.0.21 with: entrypoint: ${{ github.workspace }}/conformance diff --git a/.github/workflows/donotsubmit.yaml b/.github/workflows/donotsubmit.yaml index 43cdb3a4975..c0b211bc1cd 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@08c6903cd8c0fde910a37f88322edcfb5dd907a8 #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@1b32103f5aa389c31ab0be75a8edc38d7e4750d8 # v1.5.7 diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index b8ceccc4247..e7707c6032a 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@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.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@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.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@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.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@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.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@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.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@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.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@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.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@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.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@1b32103f5aa389c31ab0be75a8edc38d7e4750d8 # v1.5.7 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@1b32103f5aa389c31ab0be75a8edc38d7e4750d8 # v1.5.7 diff --git a/.github/workflows/e2e-with-binary.yml b/.github/workflows/e2e-with-binary.yml index ccb4ae7cc4f..220afe70229 100644 --- a/.github/workflows/e2e-with-binary.yml +++ b/.github/workflows/e2e-with-binary.yml @@ -48,35 +48,25 @@ jobs: COSIGN_YES: "true" steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.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@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.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..0178bbcd394 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@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.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@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.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..720581ebbde 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@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.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@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.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 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@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.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@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.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 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..216c8e36028 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@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.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@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.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@0ecdce24e83f0fa127940334be98c86b07b0c488 # v4.48.1 - 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@1b32103f5aa389c31ab0be75a8edc38d7e4750d8 # v1.5.7 - 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..52d86722d0c 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@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.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 diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index d87b0bfd58b..ed3a3fc3ec8 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@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.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,24 @@ 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@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.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 +90,7 @@ jobs: contents: read steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false # Related to https://github.com/sigstore/cosign/issues/3149 @@ -138,7 +147,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 +162,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@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.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 +184,7 @@ jobs: - name: Collect diagnostics if: ${{ failure() }} - uses: chainguard-dev/actions/kind-diag@708219d4822f33611ac1a2653815cc10e1ab54a6 # v1.4.7 + uses: chainguard-dev/actions/kind-diag@1b32103f5aa389c31ab0be75a8edc38d7e4750d8 # v1.5.7 e2e-windows-powershell-tests: name: Run PowerShell E2E tests @@ -177,16 +192,21 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.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@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.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 +227,22 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.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@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.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..d92d5f2a86e 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:v2.6.1-dev@sha256:40523fa4ca7ba0d9930154f0f6e1730b7a57bee61cadc9612730dfc992bc8abc 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.3-0@sha256:5f7e91a9e3c2411fe1973d9a5ab2f34eddd166251a95654b66c1171128f013c6 \ --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.3-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.3-0@sha256:5f7e91a9e3c2411fe1973d9a5ab2f34eddd166251a95654b66c1171128f013c6 volumes: - /usr:/host_usr - /opt:/host_opt @@ -51,7 +51,7 @@ jobs: permissions: {} steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false diff --git a/.github/workflows/verify-docgen.yaml b/.github/workflows/verify-docgen.yaml index 79d81f15d87..e231d875a11 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@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.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@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.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..3acbcd924c3 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@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: persist-credentials: false - - uses: chainguard-dev/actions/trailing-space@708219d4822f33611ac1a2653815cc10e1ab54a6 # v1.4.7 + - uses: chainguard-dev/actions/trailing-space@1b32103f5aa389c31ab0be75a8edc38d7e4750d8 # v1.5.7 if: ${{ always() }} - - uses: chainguard-dev/actions/eof-newline@708219d4822f33611ac1a2653815cc10e1ab54a6 # v1.4.7 + - uses: chainguard-dev/actions/eof-newline@1b32103f5aa389c31ab0be75a8edc38d7e4750d8 # v1.5.7 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..ab38fe593d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,109 @@ +# 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..eb59fd6f167 --- /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.3 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..81b59f07b78 100644 --- a/README.md +++ b/README.md @@ -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. @@ -761,8 +769,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..971d4bed45c 100644 --- a/cmd/cosign/cli/attach/attach.go +++ b/cmd/cosign/cli/attach/attach.go @@ -22,12 +22,12 @@ 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" ) func AttestationCmd(ctx context.Context, regOpts options.RegistryOptions, signedPayloads []string, imageRef string) error { 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..41418b01e63 100644 --- a/cmd/cosign/cli/attach/sig.go +++ b/cmd/cosign/cli/attach/sig.go @@ -24,12 +24,12 @@ 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" ) func SignatureCmd(ctx context.Context, regOpts options.RegistryOptions, sigRef, payloadRef, certRef, certChainRef, timeStampedSigRef, rekorBundleRef, imageRef string) error { diff --git a/cmd/cosign/cli/attest.go b/cmd/cosign/cli/attest.go index f9ac6a85c55..ffb20be7059 100644 --- a/cmd/cosign/cli/attest.go +++ b/cmd/cosign/cli/attest.go @@ -19,12 +19,13 @@ 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/internal/ui" + "github.com/sigstore/cosign/v3/pkg/cosign" + "github.com/sigstore/cosign/v3/pkg/cosign/env" + "github.com/sigstore/sigstore-go/pkg/root" "github.com/spf13/cobra" ) @@ -78,35 +79,71 @@ 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 a signing config is used, then service URLs cannot be specified + if (o.UseSigningConfig || o.SigningConfigPath != "") && + ((o.Rekor.URL != "" && o.Rekor.URL != options.DefaultRekorURL) || + (o.Fulcio.URL != "" && o.Fulcio.URL != options.DefaultFulcioURL) || + (o.OIDC.Issuer != "" && o.OIDC.Issuer != options.DefaultOIDCIssuerURL) || + o.TSAServerURL != "") { + return fmt.Errorf("cannot specify service URLs and use signing config") + } + // Signing config requires a bundle as output for verification materials since sigstore-go is used + if (o.UseSigningConfig || o.SigningConfigPath != "") && !o.NewBundleFormat { + return fmt.Errorf("must provide --new-bundle-format 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 (o.Key == "" && env.Getenv(env.VariableSigstoreCTLogPublicKeyFile) == "") || + (o.UseSigningConfig || o.SigningConfigPath != "") { + if o.TrustedRootPath != "" { + ko.TrustedMaterial, err = root.NewTrustedRootFromPath(o.TrustedRootPath) + if err != nil { + return fmt.Errorf("loading trusted root: %w", err) + } + } else { + ko.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) + } + } + } + if o.SigningConfigPath != "" { + ko.SigningConfig, err = root.NewSigningConfigFromPath(o.SigningConfigPath) 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) + return fmt.Errorf("error reading signing config from file: %w", err) + } + } else if o.UseSigningConfig { + ko.SigningConfig, err = cosign.SigningConfig() + if err != nil { + return fmt.Errorf("error getting signing config from TUF: %w", err) } - ko.TrustedMaterial = trustedMaterial } + 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..454a02b9523 100644 --- a/cmd/cosign/cli/attest_blob.go +++ b/cmd/cosign/cli/attest_blob.go @@ -16,13 +16,15 @@ 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/internal/ui" + "github.com/sigstore/cosign/v3/pkg/cosign" + "github.com/sigstore/cosign/v3/pkg/cosign/env" + "github.com/sigstore/sigstore-go/pkg/root" "github.com/spf13/cobra" ) @@ -63,37 +65,72 @@ 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 a signing config is used, then service URLs cannot be specified + if (o.UseSigningConfig || o.SigningConfigPath != "") && + ((o.Rekor.URL != "" && o.Rekor.URL != options.DefaultRekorURL) || + (o.Fulcio.URL != "" && o.Fulcio.URL != options.DefaultFulcioURL) || + (o.OIDC.Issuer != "" && o.OIDC.Issuer != options.DefaultOIDCIssuerURL) || + o.TSAServerURL != "") { + return fmt.Errorf("cannot specify service URLs and use signing config") + } + // Signing config requires a bundle as output for verification materials since sigstore-go is used + if (o.UseSigningConfig || o.SigningConfigPath != "") && o.BundlePath == "" { + return fmt.Errorf("must provide --bundle 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 (o.Key == "" && env.Getenv(env.VariableSigstoreCTLogPublicKeyFile) == "") || + (o.UseSigningConfig || o.SigningConfigPath != "") { + if o.TrustedRootPath != "" { + ko.TrustedMaterial, err = root.NewTrustedRootFromPath(o.TrustedRootPath) + if err != nil { + return fmt.Errorf("loading trusted root: %w", err) + } + } else { + ko.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) + } + } + } + if o.SigningConfigPath != "" { + ko.SigningConfig, err = root.NewSigningConfigFromPath(o.SigningConfigPath) 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) + return fmt.Errorf("error reading signing config from file: %w", err) + } + } else if o.UseSigningConfig { + ko.SigningConfig, err = cosign.SigningConfig() + if err != nil { + return fmt.Errorf("error getting signing config from TUF: %w", err) } - ko.TrustedMaterial = trustedMaterial } + 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..a9debf808ee 100644 --- a/cmd/cosign/cli/clean.go +++ b/cmd/cosign/cli/clean.go @@ -25,9 +25,9 @@ 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" + ociremote "github.com/sigstore/cosign/v3/pkg/oci/remote" "github.com/spf13/cobra" ) 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..687fedb7084 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" ) diff --git a/cmd/cosign/cli/download/attestation.go b/cmd/cosign/cli/download/attestation.go index 152e934103d..814021eacff 100644 --- a/cmd/cosign/cli/download/attestation.go +++ b/cmd/cosign/cli/download/attestation.go @@ -22,10 +22,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/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 { 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..67fb9b87e77 100644 --- a/cmd/cosign/cli/download/signature.go +++ b/cmd/cosign/cli/download/signature.go @@ -21,8 +21,8 @@ import ( "fmt" "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 { 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..7bf407d4620 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,10 +39,10 @@ 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 with an out-of-band root key file, using the default mirror. diff --git a/cmd/cosign/cli/initialize/init.go b/cmd/cosign/cli/initialize/init.go index fc726cd0d59..29fcbb9221a 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" @@ -86,6 +85,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..b2075291116 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" ) 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..e0aac3fb85b 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" ) diff --git a/cmd/cosign/cli/options/attest.go b/cmd/cosign/cli/options/attest.go index 7b67e4ee563..d1791889730 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 @@ -107,5 +112,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..4d906605c2e 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) @@ -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) @@ -130,4 +145,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/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/key.go b/cmd/cosign/cli/options/key.go index 2cae8d5cdbe..b62dc65fefd 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,16 @@ 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 } 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..23eb93cab49 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 @@ -133,8 +142,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..4d4b505cfb2 100644 --- a/cmd/cosign/cli/options/signblob.go +++ b/cmd/cosign/cli/options/signblob.go @@ -43,6 +43,10 @@ type SignBlobOptions struct { TSAServerURL string RFC3161TimestampPath string IssueCertificate bool + + UseSigningConfig bool + SigningConfigPath string + TrustedRootPath string } var _ Interface = (*SignBlobOptions)(nil) @@ -77,10 +81,20 @@ 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") 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..0df169b3bda 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") } @@ -137,6 +137,7 @@ type VerifyAttestationOptions struct { CertVerify CertVerifyOptions Registry RegistryOptions Predicate PredicateRemoteOptions + SignatureDigest SignatureDigestOptions Policies []string LocalImage bool } @@ -151,6 +152,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") @@ -178,6 +180,7 @@ type VerifyBlobOptions struct { CertVerify CertVerifyOptions Rekor RekorOptions CommonVerifyOptions CommonVerifyOptions + SignatureDigest SignatureDigestOptions RFC3161TimestampPath string } @@ -190,6 +193,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 +237,7 @@ type VerifyBlobAttestationOptions struct { CertVerify CertVerifyOptions Rekor RekorOptions CommonVerifyOptions CommonVerifyOptions + SignatureDigest SignatureDigestOptions RFC3161TimestampPath string @@ -249,6 +254,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..6c95c2059b9 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" ) diff --git a/cmd/cosign/cli/sign.go b/cmd/cosign/cli/sign.go index 24a659bc828..b10034cbb09 100644 --- a/cmd/cosign/cli/sign.go +++ b/cmd/cosign/cli/sign.go @@ -20,12 +20,13 @@ import ( "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/internal/ui" + "github.com/sigstore/cosign/v3/pkg/cosign" + "github.com/sigstore/cosign/v3/pkg/cosign/env" + "github.com/sigstore/sigstore-go/pkg/root" "github.com/spf13/cobra" ) @@ -131,13 +132,47 @@ 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 a signing config is used, then service URLs cannot be specified + if (o.UseSigningConfig || o.SigningConfigPath != "") && + ((o.Rekor.URL != "" && o.Rekor.URL != options.DefaultRekorURL) || + (o.Fulcio.URL != "" && o.Fulcio.URL != options.DefaultFulcioURL) || + (o.OIDC.Issuer != "" && o.OIDC.Issuer != options.DefaultOIDCIssuerURL) || + o.TSAServerURL != "") { + return fmt.Errorf("cannot specify service URLs and use signing config") + } + // Signing config requires a bundle as output for verification materials since sigstore-go is used + if (o.UseSigningConfig || o.SigningConfigPath != "") && !o.NewBundleFormat { + return fmt.Errorf("must provide --new-bundle-format 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 ((o.Key == "" || o.IssueCertificate) && env.Getenv(env.VariableSigstoreCTLogPublicKeyFile) == "") || + (o.UseSigningConfig || o.SigningConfigPath != "") { + if o.TrustedRootPath != "" { + ko.TrustedMaterial, err = root.NewTrustedRootFromPath(o.TrustedRootPath) + if err != nil { + return fmt.Errorf("loading trusted root: %w", err) + } + } else { + ko.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) + } + } + } + if o.SigningConfigPath != "" { + ko.SigningConfig, err = root.NewSigningConfigFromPath(o.SigningConfigPath) 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) + return fmt.Errorf("error reading signing config from file: %w", err) + } + } else if o.UseSigningConfig { + ko.SigningConfig, err = cosign.SigningConfig() + if err != nil { + return fmt.Errorf("error getting signing config from TUF: %w", err) } - ko.TrustedMaterial = trustedMaterial } + if err := sign.SignCmd(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..5ad44b746f5 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,31 @@ 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" // 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,18 +62,6 @@ 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 { if options.NOf(ko.KeyRef, ko.Sk) > 1 { @@ -136,14 +71,8 @@ func SignCmd(ro *options.RootOptions, ko options.KeyOpts, signOpts options.SignO ctx, cancel := context.WithTimeout(context.Background(), 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 +97,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 +113,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) + } else { + err = signDigest(ctx, digest, staticPayload, ko, signOpts, annotations, se) + } if err != nil { return fmt.Errorf("signing digest: %w", err) } @@ -203,7 +136,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) + } else { + err = signDigest(ctx, digest, staticPayload, ko, signOpts, annotations, se) + } if err != nil { return fmt.Errorf("signing digest: %w", err) } @@ -216,22 +153,91 @@ 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) error { + digestParts := strings.Split(digest.DigestStr(), ":") + if len(digestParts) != 2 { + return fmt.Errorf("unable to parse digest %s", digest.DigestStr()) + } + + subject := intotov1.ResourceDescriptor{ + Digest: map[string]string{digestParts[0]: digestParts[1]}, + } + + 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 +256,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 +268,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 +291,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 +301,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 +320,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 +344,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 +376,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..a3e462a1bae 100644 --- a/cmd/cosign/cli/sign/sign_blob.go +++ b/cmd/cosign/cli/sign/sign_blob.go @@ -17,31 +17,46 @@ 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) { var payload internal.HashReader @@ -49,23 +64,74 @@ func SignBlobCmd(ro *options.RootOptions, ko options.KeyOpts, payloadPath string ctx, cancel := context.WithTimeout(context.Background(), 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)) + shouldUpload, err := signcommon.ShouldUploadToTlog(ctx, ko, nil, tlogUpload) + if err != nil { + return nil, fmt.Errorf("upload to tlog: %w", err) + } + + if !shouldUpload { + // 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{} + } + + if ko.SigningConfig != nil { + keypair, idToken, err := signcommon.GetKeypairAndToken(ctx, ko, "", "") if err != nil { - return nil, err + return nil, fmt.Errorf("getting keypair and token: %w", err) + } + + payload, closePayload, err := getPayload(ctx, payloadPath, protoHashAlgoToHash(keypair.GetHashAlgorithm())) + if err != nil { + return nil, fmt.Errorf("getting payload: %w", err) + } + defer closePayload() + data, err := io.ReadAll(&payload) + if err != nil { + return nil, fmt.Errorf("reading payload: %w", err) + } + content := &sign.PlainData{ + Data: data, + } + + bundle, err := cbundle.SignData(ctx, content, keypair, idToken, 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, closeSV, err := signcommon.GetSignerVerifier(ctx, "", "", ko) + if err != nil { + return nil, fmt.Errorf("getting signer: %w", err) + } + defer closeSV() + + hashFunction, err := getHashFunction(sv, ko.DefaultLoadOptions) + if err != nil { + return nil, 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 + } } - defer f.Close() - payload = internal.NewHashReader(f, sha256.New()) + ui.Infof(ctx, "Continuing with non SHA256 hash function and old bundle format") } - sv, err := SignerFromKeyOpts(ctx, "", "", ko) + payload, closePayload, err := getPayload(ctx, payloadPath, hashFunction) if err != nil { return nil, err } - defer sv.Close() + defer closePayload() sig, err := sv.SignMessage(&payload, signatureoptions.WithContext(ctx)) if err != nil { @@ -74,68 +140,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 +168,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 +192,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 +264,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 +276,45 @@ func extractCertificate(ctx context.Context, sv *SignerVerifier) ([]byte, error) } return nil, nil } + +func getHashFunction(sv *signcommon.SignerVerifier, defaultLoadOptions *[]signature.LoadOption) (crypto.Hash, error) { + pubKey, err := sv.PublicKey() + if err != nil { + return crypto.Hash(0), fmt.Errorf("error getting public key: %w", err) + } + + defaultLoadOptions = cosign.GetDefaultLoadOptions(defaultLoadOptions) + + // TODO: Ideally the SignerVerifier should have a method to get the hash function + algo, err := signature.GetDefaultAlgorithmDetails(pubKey, *defaultLoadOptions...) + if err != nil { + return crypto.Hash(0), fmt.Errorf("error getting default algorithm details: %w", err) + } + return algo.GetHashType(), 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..10880c711a0 100644 --- a/cmd/cosign/cli/sign/sign_blob_test.go +++ b/cmd/cosign/cli/sign/sign_blob_test.go @@ -19,8 +19,8 @@ import ( "path/filepath" "testing" - "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 TestSignBlobCmd(t *testing.T) { diff --git a/cmd/cosign/cli/sign/sign_test.go b/cmd/cosign/cli/sign/sign_test.go index 0d9de73f790..a8be500276f 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) { @@ -128,104 +43,3 @@ func TestSignCmdLocalKeyAndSk(t *testing.T) { } } } - -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..5ad293030c1 100644 --- a/cmd/cosign/cli/signblob.go +++ b/cmd/cosign/cli/signblob.go @@ -20,12 +20,13 @@ import ( "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/internal/ui" + "github.com/sigstore/cosign/v3/pkg/cosign" + "github.com/sigstore/cosign/v3/pkg/cosign/env" + "github.com/sigstore/sigstore-go/pkg/root" "github.com/spf13/cobra" "github.com/spf13/viper" ) @@ -99,12 +100,45 @@ func SignBlob() *cobra.Command { RFC3161TimestampPath: o.RFC3161TimestampPath, IssueCertificateForExistingKey: o.IssueCertificate, } - if (o.Key == "" || o.IssueCertificate) && env.Getenv(env.VariableSigstoreCTLogPublicKeyFile) == "" { - trustedMaterial, err := cosign.TrustedRoot() + // If a signing config is used, then service URLs cannot be specified + if (o.UseSigningConfig || o.SigningConfigPath != "") && + ((o.Rekor.URL != "" && o.Rekor.URL != options.DefaultRekorURL) || + (o.Fulcio.URL != "" && o.Fulcio.URL != options.DefaultFulcioURL) || + (o.OIDC.Issuer != "" && o.OIDC.Issuer != options.DefaultOIDCIssuerURL) || + o.TSAServerURL != "") { + return fmt.Errorf("cannot specify service URLs and use signing config") + } + // Signing config requires a bundle as output for verification materials since sigstore-go is used + if (o.UseSigningConfig || o.SigningConfigPath != "") && o.BundlePath == "" { + return fmt.Errorf("must provide --bundle 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 ((o.Key == "" || o.IssueCertificate) && env.Getenv(env.VariableSigstoreCTLogPublicKeyFile) == "") || + (o.UseSigningConfig || o.SigningConfigPath != "") { + if o.TrustedRootPath != "" { + ko.TrustedMaterial, err = root.NewTrustedRootFromPath(o.TrustedRootPath) + if err != nil { + return fmt.Errorf("loading trusted root: %w", err) + } + } else { + ko.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) + } + } + } + if o.SigningConfigPath != "" { + ko.SigningConfig, err = root.NewSigningConfigFromPath(o.SigningConfigPath) + if err != nil { + return fmt.Errorf("error reading signing config from file: %w", err) + } + } else if o.UseSigningConfig { + ko.SigningConfig, err = cosign.SigningConfig() 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) + return fmt.Errorf("error getting signing config from TUF: %w", err) } - ko.TrustedMaterial = trustedMaterial } for _, blob := range args { diff --git a/cmd/cosign/cli/signcommon/common.go b/cmd/cosign/cli/signcommon/common.go new file mode 100644 index 00000000000..9e70b17695a --- /dev/null +++ b/cmd/cosign/cli/signcommon/common.go @@ -0,0 +1,604 @@ +// 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" + "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/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" + 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, string, error) { + var keypair sign.Keypair + var ephemeralKeypair bool + var idToken string + var sv *SignerVerifier + var err error + + if ko.Sk || ko.Slot != "" || ko.KeyRef != "" || cert != "" { + sv, _, err = signerFromKeyOpts(ctx, cert, certChain, ko) + if err != nil { + return nil, "", fmt.Errorf("getting signer: %w", err) + } + keypair, err = key.NewSignerVerifierKeypair(sv, ko.DefaultLoadOptions) + if err != nil { + return nil, "", fmt.Errorf("creating signerverifier keypair: %w", err) + } + } else { + keypair, err = sign.NewEphemeralKeypair(nil) + if err != nil { + return nil, "", fmt.Errorf("generating keypair: %w", err) + } + ephemeralKeypair = true + } + defer func() { + if sv != nil { + sv.Close() + } + }() + + if ephemeralKeypair || ko.IssueCertificateForExistingKey { + 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, "", fmt.Errorf("retrieving ID token: %w", err) + } + } + + return keypair, 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() + } + 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() (*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 +} + +// 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, 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, 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 +} 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..9f8427863aa 100644 --- a/cmd/cosign/cli/verify/verify.go +++ b/cmd/cosign/cli/verify/verify.go @@ -16,35 +16,24 @@ 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" + "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 +74,7 @@ type VerifyCommand struct { IgnoreTlog bool MaxWorkers int ExperimentalOCI11 bool + NewBundleFormat bool } // Exec runs the verification command @@ -119,6 +109,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 +133,50 @@ 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, 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 { + 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 +187,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 +209,87 @@ 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 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 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 != "" { - 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 + verifiedOutput, err := transformOutput(verified, ref.Name()) + if err == nil { + verified = verifiedOutput } - - if githubWorkflowRepository := ce.GetCertExtensionGithubWorkflowRepository(); githubWorkflowRepository != "" { - ss.Optional[cosign.CertExtensionMap[cosign.CertExtensionGithubWorkflowRepository]] = githubWorkflowRepository - ss.Optional[cosign.CertExtensionGithubWorkflowRepository] = 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 != "" { - 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{}) + verified, bundleVerified, err = cosign.VerifyImageSignatures(ctx, ref, co) + if err != nil { + return cosignError.WrapError(err) } - 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 + PrintVerificationHeader(ctx, ref.Name(), co, bundleVerified, fulcioVerified) + PrintVerification(ctx, verified, c.Output) } - - 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 + return nil } -// 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) +func transformOutput(verified []oci.Signature, name string) (verifiedOutput []oci.Signature, err error) { + for _, v := range verified { + dssePayload, err := v.Payload() 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) - } + var dsseEnvelope dsse.Envelope + err = json.Unmarshal(dssePayload, &dsseEnvelope) + if err != nil { + return nil, err } - case caRootsFile != "": - caRoots, err := loadCertChainFromFileOrURL(caRootsFile) + if dsseEnvelope.PayloadType != in_toto.PayloadType { + return nil, fmt.Errorf("unable to understand payload type %s", dsseEnvelope.PayloadType) + } + var intotoStatement in_toto.StatementHeader + err = json.Unmarshal(dsseEnvelope.Payload, &intotoStatement) 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(intotoStatement.Subject) < 1 || len(intotoStatement.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() + + sci := payload.SimpleContainerImage{ + Critical: payload.Critical{ + Identity: payload.Identity{ + DockerReference: name, + }, + Image: payload.Image{ + DockerManifestDigest: digest, + }, + Type: intotoStatement.PredicateType, + }, + } + 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..781626f202b 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, 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..24dddcdf872 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" @@ -701,9 +701,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 +723,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..0882a978847 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,52 @@ 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" } } + ], + "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") +} 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_attest-blob.md b/doc/cosign_attest-blob.md index 3a46e1fbafd..126f3f1444d 100644 --- a/doc/cosign_attest-blob.md +++ b/doc/cosign_attest-blob.md @@ -42,8 +42,9 @@ cosign attest-blob [flags] -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. @@ -66,7 +68,9 @@ cosign attest-blob [flags] --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..57601462a3a 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. @@ -89,7 +92,9 @@ cosign attest [flags] --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_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..e36930e67c7 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,9 +25,9 @@ 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 with an out-of-band root key file, using the default mirror. 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..4135f3aac22 100644 --- a/doc/cosign_sign-blob.md +++ b/doc/cosign_sign-blob.md @@ -45,7 +45,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 +57,7 @@ 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-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 @@ -65,6 +66,8 @@ cosign sign-blob [flags] --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..8973b53aee8 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 @@ -117,7 +120,9 @@ cosign sign [flags] --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..b31e371cb85 100644 --- a/go.mod +++ b/go.mod @@ -1,21 +1,22 @@ -module github.com/sigstore/cosign/v2 +module github.com/sigstore/cosign/v3 -go 1.24.3 +go 1.24.6 require ( - cuelang.org/go v0.12.1 + cuelang.org/go v0.14.2 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.10.1 + github.com/buildkite/agent/v3 v3.110.0 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.0 + github.com/go-openapi/strfmt v0.24.0 + github.com/go-openapi/swag v0.25.1 + github.com/go-openapi/swag/conv v0.25.1 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 @@ -30,62 +31,62 @@ 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/open-policy-agent/opa v1.9.0 + github.com/secure-systems-lab/go-securesystemslib v0.9.1 github.com/sigstore/fulcio v1.7.1 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/rekor v1.4.2 + github.com/sigstore/rekor-tiles/v2 v2.0.0 + github.com/sigstore/sigstore v1.9.6-0.20250729224751-181c5d3339b3 + github.com/sigstore/sigstore-go v1.1.3 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/gcp v1.9.6-0.20250729224751-181c5d3339b3 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/timestamp-authority v1.2.9 + github.com/spf13/cobra v1.10.1 + 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.2.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.157.0 + golang.org/x/crypto v0.43.0 + golang.org/x/oauth2 v0.32.0 + golang.org/x/sync v0.17.0 + golang.org/x/term v0.36.0 + google.golang.org/api v0.252.0 + google.golang.org/protobuf v1.36.10 + k8s.io/api v0.34.1 + k8s.io/apimachinery v0.34.1 + k8s.io/client-go v0.34.1 + 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/compute/metadata v0.9.0 // indirect cloud.google.com/go/iam v1.5.2 // indirect - cloud.google.com/go/kms v1.22.0 // indirect + cloud.google.com/go/kms v1.23.0 // 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 + cloud.google.com/go/spanner v1.86.0 // indirect + cloud.google.com/go/storage v1.57.0 // indirect + cuelabs.dev/go/oci/ociregistry v0.0.0-20250715075730-49cab49c8e9d // 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.19.1 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.0 // 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 +96,11 @@ 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.5.0 // indirect + github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp v1.5.3 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.29.0 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.54.0 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.54.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 +115,93 @@ 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.39.3 // indirect + github.com/aws/aws-sdk-go-v2/config v1.31.13 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.18.17 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.10 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.10 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.10 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 // indirect + github.com/aws/aws-sdk-go-v2/service/ecr v1.45.1 // indirect + github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.33.2 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.2 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.10 // indirect + github.com/aws/aws-sdk-go-v2/service/kms v1.46.0 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.29.7 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.2 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.38.7 // indirect + github.com/aws/smithy-go v1.23.1 // 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/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 // 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/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/distribution v2.8.3+incompatible // indirect github.com/docker/docker-credential-helpers v0.9.3 // 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/emicklei/go-restful/v3 v3.12.2 // indirect + github.com/emicklei/proto v1.14.2 // indirect github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect github.com/envoyproxy/protoc-gen-validate v1.2.1 // 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.0 // indirect + github.com/go-openapi/errors v0.22.3 // indirect + github.com/go-openapi/jsonpointer v0.22.1 // indirect + github.com/go-openapi/jsonreference v0.21.2 // indirect + github.com/go-openapi/loads v0.23.1 // indirect + github.com/go-openapi/spec v0.22.0 // indirect + github.com/go-openapi/swag/cmdutils v0.25.1 // indirect + github.com/go-openapi/swag/fileutils v0.25.1 // indirect + github.com/go-openapi/swag/jsonname v0.25.1 // indirect + github.com/go-openapi/swag/jsonutils v0.25.1 // indirect + github.com/go-openapi/swag/loading v0.25.1 // indirect + github.com/go-openapi/swag/mangling v0.25.1 // indirect + github.com/go-openapi/swag/netutils v0.25.1 // indirect + github.com/go-openapi/swag/stringutils v0.25.1 // indirect + github.com/go-openapi/swag/typeutils v0.25.1 // indirect + github.com/go-openapi/swag/yamlutils v0.25.1 // indirect + github.com/go-openapi/validate v0.25.0 // 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-jwt/jwt/v5 v5.3.0 // indirect github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // 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/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 @@ -209,52 +219,59 @@ require ( 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/kylelemons/godebug v1.1.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.0.0-20240620165639-de9c06129bec // indirect - github.com/mailru/easyjson v0.9.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/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.66.1 // indirect + github.com/prometheus/procfs v0.17.0 // indirect + github.com/protocolbuffers/txtpbfmt v0.0.0-20250627152318-f293424e46b5 // 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/asm v1.2.0 // indirect github.com/segmentio/ksuid v1.0.4 // indirect github.com/shibumi/go-pathspec v1.3.0 // indirect - github.com/sirupsen/logrus v1.9.3 // indirect + github.com/sigstore/rekor-tiles v0.1.11 // indirect + github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af // 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/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 @@ -264,48 +281,50 @@ require ( 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/tessera v1.0.0 // indirect github.com/urfave/negroni v1.0.0 // indirect + github.com/valyala/fastjson v1.6.4 // indirect github.com/vbatts/tar-split v0.12.1 // indirect - github.com/vektah/gqlparser/v2 v2.5.28 // 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.mongodb.org/mongo-driver v1.17.4 // 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.opentelemetry.io/auto/sdk v1.2.1 // indirect + go.opentelemetry.io/contrib/detectors/gcp v1.38.0 // 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/sdk/metric v1.38.0 // indirect + go.opentelemetry.io/otel/trace v1.38.0 // indirect + go.step.sm/crypto v0.70.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.yaml.in/yaml/v2 v2.4.2 // 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.28.0 // indirect + golang.org/x/net v0.46.0 // indirect + golang.org/x/sys v0.37.0 // indirect + golang.org/x/text v0.30.0 // indirect + golang.org/x/time v0.13.0 // indirect + golang.org/x/tools v0.37.0 // indirect + google.golang.org/genproto v0.0.0-20250922171735-9219d122eba9 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250929231259-57b25ae835d4 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797 // indirect + google.golang.org/grpc v1.75.1 // 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..c34b4436127 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -al.essio.dev/pkg/shellescape v1.5.1 h1:86HrALUujYS/h+GtqoB26SBEdkWfmMI6FubjXlsXyho= -al.essio.dev/pkg/shellescape v1.5.1/go.mod h1:6sIqp7X2P6mThCQ7twERpZTuigpr6KbZWtls1U8I890= +al.essio.dev/pkg/shellescape v1.6.0 h1:NxFcEqzFSEVCGN2yq7Huv/9hyCEGVa/TncnOOBBeXHA= +al.essio.dev/pkg/shellescape v1.6.0/go.mod h1:6sIqp7X2P6mThCQ7twERpZTuigpr6KbZWtls1U8I890= cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY= cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= @@ -40,8 +40,8 @@ cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRY 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 v0.121.6 h1:waZiuajrI28iAf40cWgycWNgaXPO06dupuS+sgibK6c= +cloud.google.com/go v0.121.6/go.mod h1:coChdst4Ea5vUpiALcYKXEpR1S9ZgXbhEzzMcMR66vI= 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= @@ -103,8 +103,8 @@ cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVo 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/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= @@ -186,8 +186,8 @@ cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZ 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/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs= +cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10= 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= @@ -342,8 +342,8 @@ cloud.google.com/go/kms v1.8.0/go.mod h1:4xFEhYFqvW+4VMELtZyxomGSYtSQKzM178ylFW4 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/kms v1.23.0 h1:WaqAZsUptyHwOo9II8rFC1Kd2I+yvNsNP2IJ14H2sUw= +cloud.google.com/go/kms v1.23.0/go.mod h1:rZ5kK0I7Kn9W4erhYVoIRPtpizjunlrfU4fUkumUp8g= 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= @@ -532,8 +532,8 @@ cloud.google.com/go/shell v1.6.0/go.mod h1:oHO8QACS90luWgxP3N9iZVuEiSF84zNyLytb+ 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/spanner v1.86.0 h1:jlNWusBol1Jxa9PmYGknUBzLwvD1cebuEenzqebZ9xs= +cloud.google.com/go/spanner v1.86.0/go.mod h1:bbwCXbM+zljwSPLZ44wZOdzcdmy89hbUGmM/r9sD0ws= 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= @@ -551,8 +551,8 @@ cloud.google.com/go/storage v1.23.0/go.mod h1:vOEEDNFnciUMhBeT6hsJIn3ieU5cFRmzeL 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/storage v1.57.0 h1:4g7NB7Ta7KetVbOMpCqy89C+Vg5VE8scqlSHUPm7Rds= +cloud.google.com/go/storage v1.57.0/go.mod h1:329cwlpzALLgJuu8beyJ/uvQznDHpa2U5lGjWednkzg= 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= @@ -620,10 +620,10 @@ cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoIS 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= +cuelabs.dev/go/oci/ociregistry v0.0.0-20250715075730-49cab49c8e9d h1:lX0EawyoAu4kgMJJfy7MmNkIHioBcdBGFRSKDZ+CWo0= +cuelabs.dev/go/oci/ociregistry v0.0.0-20250715075730-49cab49c8e9d/go.mod h1:4WWeZNxUO1vRoZWAHIG0KZOd6dA25ypyWuwD3ti0Tdc= +cuelang.org/go v0.14.2 h1:LDlMXbfp0/AHjNbmuDYSGBbHDekaXei/RhAOCihpSgg= +cuelang.org/go v0.14.2/go.mod h1:53oOiowh5oAlniD+ynbHPaHxHFO5qc3QkzlUiB/9kps= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= @@ -635,18 +635,18 @@ github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/provider v0.14.0 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.19.1 h1:5YTBM8QDVIBN3sxBil89WfdAAqDZbyJTgh688DSxX5w= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.19.1/go.mod h1:YD5h/ldMsG0XiIw7PdyNhLxaM317eFh5yNLccNfGdyw= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.0 h1:KpMC6LFL7mqpExyMC9jVOYRiVhLmamjeZfRsUpB7l4s= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.0/go.mod h1:J7MUC/wtRpfGVbQ5sIItY5/FuVWmvzlY21WAOfQnq/I= 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,22 +674,22 @@ 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.5.0 h1:XkkQbfMyuH2jTSjQjSoihryI8GINRcs4xp8lNawg0FI= +github.com/AzureAD/microsoft-authentication-library-for-go v1.5.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/GoogleCloudPlatform/grpc-gcp-go/grpcgcp v1.5.3 h1:2afWGsMzkIcN8Qm4mgPJKZWyroE5QBszMiDMYEBrnfw= +github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp v1.5.3/go.mod h1:dppbR7CwXD4pgtV9t3wD1812RaLDcBjtblcDF5f1vI0= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.29.0 h1:UQUsRi8WTzhZntp5313l+CHIAT95ojUI2lpP/ExlZa4= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.29.0/go.mod h1:Cz6ft6Dkn3Et6l2v2a9/RpN7epQ1GtDlO6lj8bEcOvw= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.54.0 h1:lhhYARPUu3LmHysQ/igznQphfzynnqI3D75oUyw1HXk= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.54.0/go.mod h1:l9rva3ApbBpEJxSNYnwT9N4CDLrWgtq3u8736C5hyJw= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.54.0 h1:xfK3bbi6F2RDtaZFtUdKO3osOBIhNb+xTs8lFW6yx9o= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.54.0/go.mod h1:vB2GH9GAYYJTO3mEn8oYwzEdhlayZIdQz6zdzgUIRvA= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.54.0 h1:s0WlVbf9qpvkh1c/uDAPElam0WrL7fHRIidgZJ7UqZI= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.54.0/go.mod h1:Mf6O40IAyB9zR/1J8nGDDPirZQQPbYJni8Yisy7NTMc= 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= @@ -755,64 +755,62 @@ github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= -github.com/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.39.3 h1:h7xSsanJ4EQJXG5iuW4UqgP7qBopLpj84mpkNx3wPjM= +github.com/aws/aws-sdk-go-v2 v1.39.3/go.mod h1:yWSxrnioGUZ4WVv9TgMrNUeLV3PFESn/v+6T/Su8gnM= +github.com/aws/aws-sdk-go-v2/config v1.31.13 h1:wcqQB3B0PgRPUF5ZE/QL1JVOyB0mbPevHFoAMpemR9k= +github.com/aws/aws-sdk-go-v2/config v1.31.13/go.mod h1:ySB5D5ybwqGbT6c3GszZ+u+3KvrlYCUQNo62+hkKOFk= +github.com/aws/aws-sdk-go-v2/credentials v1.18.17 h1:skpEwzN/+H8cdrrtT8y+rvWJGiWWv0DeNAe+4VTf+Vs= +github.com/aws/aws-sdk-go-v2/credentials v1.18.17/go.mod h1:Ed+nXsaYa5uBINovJhcAWkALvXw2ZLk36opcuiSZfJM= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.10 h1:UuGVOX48oP4vgQ36oiKmW9RuSeT8jlgQgBFQD+HUiHY= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.10/go.mod h1:vM/Ini41PzvudT4YkQyE/+WiQJiQ6jzeDyU8pQKwCac= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.10 h1:mj/bdWleWEh81DtpdHKkw41IrS+r3uw1J/VQtbwYYp8= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.10/go.mod h1:7+oEMxAZWP8gZCyjcm9VicI0M61Sx4DJtcGfKYv2yKQ= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.10 h1:wh+/mn57yhUrFtLIxyFPh2RgxgQz/u+Yrf7hiHGHqKY= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.10/go.mod h1:7zirD+ryp5gitJJ2m1BBux56ai8RIRDykXZrJSp540w= +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.45.1 h1:Bwzh202Aq7/MYnAjXA9VawCf6u+hjwMdoYmZ4HYsdf8= +github.com/aws/aws-sdk-go-v2/service/ecr v1.45.1/go.mod h1:xZzWl9AXYa6zsLLH41HBFW8KRKJRIzlGmvSM0mVMIX4= +github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.33.2 h1:XJ/AEFYj9VFPJdF+VFi4SUPEDfz1akHwxxm07JfZJcs= +github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.33.2/go.mod h1:JUBHdhvKbbKmhaHjLsKJAWnQL80T6nURmhB/LEprV+4= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.2 h1:xtuxji5CS0JknaXoACOunXOYOQzgfTvGAc9s2QdCJA4= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.2/go.mod h1:zxwi0DIR0rcRcgdbl7E2MSOvxDyyXGBlScvBkARFaLQ= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.10 h1:DRND0dkCKtJzCj4Xl4OpVbXZgfttY5q712H9Zj7qc/0= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.10/go.mod h1:tGGNmJKOTernmR2+VJ0fCzQRurcPZj9ut60Zu5Fi6us= +github.com/aws/aws-sdk-go-v2/service/kms v1.46.0 h1:vSXYridw+tT3AHuK1PWdJto2qEc30/wG/fm8dmCHHis= +github.com/aws/aws-sdk-go-v2/service/kms v1.46.0/go.mod h1:YXPskkMuiMgp6qUG96NSTl7UpideOQT/Kx0u9Y1MKn0= +github.com/aws/aws-sdk-go-v2/service/sso v1.29.7 h1:fspVFg6qMx0svs40YgRmE7LZXh9VRZvTT35PfdQR6FM= +github.com/aws/aws-sdk-go-v2/service/sso v1.29.7/go.mod h1:BQTKL3uMECaLaUV3Zc2L4Qybv8C6BIXjuu1dOPyxTQs= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.2 h1:scVnW+NLXasGOhy7HhkdT9AGb6kjgW7fJ5xYkUaqHs0= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.2/go.mod h1:FRNCY3zTEWZXBKm2h5UBUPvCVDOecTad9KhynDyGBc0= +github.com/aws/aws-sdk-go-v2/service/sts v1.38.7 h1:VEO5dqFkMsl8QZ2yHsFDJAIZLAkEbaYDB+xdKi0Feic= +github.com/aws/aws-sdk-go-v2/service/sts v1.38.7/go.mod h1:L1xxV3zAdB+qVrVW/pBIrIAnHFWHo6FBbFe4xOGsG/o= +github.com/aws/smithy-go v1.23.1 h1:sLvcH6dfAFwGkHLZ7dGiYF7aK6mg4CgKA/iDKjLDt9M= +github.com/aws/smithy-go v1.23.1/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0= +github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.10.1 h1:6lMw4/QGLFPvbKQ0eri/9Oh3YX5Nm6BPrUlZR8yuJHg= +github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.10.1/go.mod h1:EVJOSYOVeoD3VFFZ/dWCAzWJp5wZr9lTOCjW8ejAmO0= 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.110.0 h1:fcNbcaIRnC8Q4545mXqFSmQCWUxZCNUJrvbyHgYUOz0= +github.com/buildkite/agent/v3 v3.110.0/go.mod h1:ynBDBI5OcKElHKHtsxEVeHctG54MKxUZ9dRHqXI+6Jk= +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/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/v3 v3.0.2 h1:3uZCA/BLTIu+DqCfguByNMJa2HVHpXvjfy0Dy7g6fuA= github.com/bytecodealliance/wasmtime-go/v3 v3.0.2/go.mod h1:RnUjnIXxEJcL6BgCvNyzCCRzZcxCgsZCi+RNlvYor5Q= github.com/cenkalti/backoff/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= @@ -849,8 +847,8 @@ github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWH 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-20250501225837-2ac532fd4443 h1:aQ3y1lwWyqYPiWZThqv1aFbZMiM9vblcSArJRf2Irls= +github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= 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= @@ -869,20 +867,20 @@ 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= @@ -904,10 +902,10 @@ github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3 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= @@ -948,13 +946,13 @@ 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/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/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/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-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-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= @@ -965,10 +963,8 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= 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-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-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-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= @@ -976,26 +972,50 @@ 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-openapi/analysis v0.24.0 h1:vE/VFFkICKyYuTWYnplQ+aVr45vlG6NcZKC7BdIXhsA= +github.com/go-openapi/analysis v0.24.0/go.mod h1:GLyoJA+bvmGGaHgpfeDh8ldpGo69fAJg7eeMDMRCIrw= +github.com/go-openapi/errors v0.22.3 h1:k6Hxa5Jg1TUyZnOwV2Lh81j8ayNw5VVYLvKrp4zFKFs= +github.com/go-openapi/errors v0.22.3/go.mod h1:+WvbaBBULWCOna//9B9TbLNGSFOfF8lY9dw4hGiEiKQ= +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.2 h1:Wxjda4M/BBQllegefXrY/9aq1fxBA8sI5M/lFU6tSWU= +github.com/go-openapi/jsonreference v0.21.2/go.mod h1:pp3PEjIsJ9CZDGCNOyXIQxsNuroxm8FAJ/+quA0yKzQ= +github.com/go-openapi/loads v0.23.1 h1:H8A0dX2KDHxDzc797h0+uiCZ5kwE2+VojaQVaTlXvS0= +github.com/go-openapi/loads v0.23.1/go.mod h1:hZSXkyACCWzWPQqizAv/Ye0yhi2zzHwMmoXQ6YQml44= +github.com/go-openapi/runtime v0.29.0 h1:Y7iDTFarS9XaFQ+fA+lBLngMwH6nYfqig1G+pHxMRO0= +github.com/go-openapi/runtime v0.29.0/go.mod h1:52HOkEmLL/fE4Pg3Kf9nxc9fYQn0UsIWyGjGIJE9dkg= +github.com/go-openapi/spec v0.22.0 h1:xT/EsX4frL3U09QviRIZXvkh80yibxQmtoEvyqug0Tw= +github.com/go-openapi/spec v0.22.0/go.mod h1:K0FhKxkez8YNS94XzF8YKEMULbFrRw4m15i2YUht4L0= +github.com/go-openapi/strfmt v0.24.0 h1:dDsopqbI3wrrlIzeXRbqMihRNnjzGC+ez4NQaAAJLuc= +github.com/go-openapi/strfmt v0.24.0/go.mod h1:Lnn1Bk9rZjXxU9VMADbEEOo7D7CDyKGLsSKekhFr7s4= +github.com/go-openapi/swag v0.25.1 h1:6uwVsx+/OuvFVPqfQmOOPsqTcm5/GkBhNwLqIR916n8= +github.com/go-openapi/swag v0.25.1/go.mod h1:bzONdGlT0fkStgGPd3bhZf1MnuPkf2YAys6h+jZipOo= +github.com/go-openapi/swag/cmdutils v0.25.1 h1:nDke3nAFDArAa631aitksFGj2omusks88GF1VwdYqPY= +github.com/go-openapi/swag/cmdutils v0.25.1/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0= +github.com/go-openapi/swag/conv v0.25.1 h1:+9o8YUg6QuqqBM5X6rYL/p1dpWeZRhoIt9x7CCP+he0= +github.com/go-openapi/swag/conv v0.25.1/go.mod h1:Z1mFEGPfyIKPu0806khI3zF+/EUXde+fdeksUl2NiDs= +github.com/go-openapi/swag/fileutils v0.25.1 h1:rSRXapjQequt7kqalKXdcpIegIShhTPXx7yw0kek2uU= +github.com/go-openapi/swag/fileutils v0.25.1/go.mod h1:+NXtt5xNZZqmpIpjqcujqojGFek9/w55b3ecmOdtg8M= +github.com/go-openapi/swag/jsonname v0.25.1 h1:Sgx+qbwa4ej6AomWC6pEfXrA6uP2RkaNjA9BR8a1RJU= +github.com/go-openapi/swag/jsonname v0.25.1/go.mod h1:71Tekow6UOLBD3wS7XhdT98g5J5GR13NOTQ9/6Q11Zo= +github.com/go-openapi/swag/jsonutils v0.25.1 h1:AihLHaD0brrkJoMqEZOBNzTLnk81Kg9cWr+SPtxtgl8= +github.com/go-openapi/swag/jsonutils v0.25.1/go.mod h1:JpEkAjxQXpiaHmRO04N1zE4qbUEg3b7Udll7AMGTNOo= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.1 h1:DSQGcdB6G0N9c/KhtpYc71PzzGEIc/fZ1no35x4/XBY= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.1/go.mod h1:kjmweouyPwRUEYMSrbAidoLMGeJ5p6zdHi9BgZiqmsg= +github.com/go-openapi/swag/loading v0.25.1 h1:6OruqzjWoJyanZOim58iG2vj934TysYVptyaoXS24kw= +github.com/go-openapi/swag/loading v0.25.1/go.mod h1:xoIe2EG32NOYYbqxvXgPzne989bWvSNoWoyQVWEZicc= +github.com/go-openapi/swag/mangling v0.25.1 h1:XzILnLzhZPZNtmxKaz/2xIGPQsBsvmCjrJOWGNz/ync= +github.com/go-openapi/swag/mangling v0.25.1/go.mod h1:CdiMQ6pnfAgyQGSOIYnZkXvqhnnwOn997uXZMAd/7mQ= +github.com/go-openapi/swag/netutils v0.25.1 h1:2wFLYahe40tDUHfKT1GRC4rfa5T1B4GWZ+msEFA4Fl4= +github.com/go-openapi/swag/netutils v0.25.1/go.mod h1:CAkkvqnUJX8NV96tNhEQvKz8SQo2KF0f7LleiJwIeRE= +github.com/go-openapi/swag/stringutils v0.25.1 h1:Xasqgjvk30eUe8VKdmyzKtjkVjeiXx1Iz0zDfMNpPbw= +github.com/go-openapi/swag/stringutils v0.25.1/go.mod h1:JLdSAq5169HaiDUbTvArA2yQxmgn4D6h4A+4HqVvAYg= +github.com/go-openapi/swag/typeutils v0.25.1 h1:rD/9HsEQieewNt6/k+JBwkxuAHktFtH3I3ysiFZqukA= +github.com/go-openapi/swag/typeutils v0.25.1/go.mod h1:9McMC/oCdS4BKwk2shEB7x17P6HmMmA6dQRtAkSnNb8= +github.com/go-openapi/swag/yamlutils v0.25.1 h1:mry5ez8joJwzvMbaTGLhw8pXUnhDK91oSJLDPF1bmGk= +github.com/go-openapi/swag/yamlutils v0.25.1/go.mod h1:cm9ywbzncy3y6uPm/97ysW8+wZ09qsks+9RS8fLWKqg= +github.com/go-openapi/validate v0.25.0 h1:JD9eGX81hDTjoY3WOzh6WqxVBVl7xjsLnvDo1GL5WPU= +github.com/go-openapi/validate v0.25.0/go.mod h1:SUY7vKrN5FiwK6LyvSwKjDfLNirSfWwHNgxd2l29Mmw= 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-piv/piv-go/v2 v2.4.0 h1:xamQ/fR4MJiw/Ndbk6yi7MVwhjrwlnDAPuaH9zcGb+I= @@ -1004,19 +1024,21 @@ github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7 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,8 +1048,8 @@ 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-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/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= 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= @@ -1078,8 +1100,8 @@ github.com/google/certificate-transparency-go v1.3.2/go.mod h1:H5FpMUaGa5Ab2+KCY 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= @@ -1130,8 +1152,8 @@ github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLe 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/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/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM= @@ -1166,11 +1188,13 @@ github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+ 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/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 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/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= @@ -1220,16 +1244,14 @@ 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= @@ -1262,6 +1284,22 @@ 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/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.0.0-20240620165639-de9c06129bec h1:2tTW6cDth2TSgRbAhD7yjZzTQmcN25sDRPEeinR51yQ= github.com/letsencrypt/boulder v0.0.0-20240620165639-de9c06129bec/go.mod h1:TmwEoGCwIti7BCeJ9hescZgRtatxRE+A72pCoPfmcfk= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= @@ -1269,8 +1307,6 @@ 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= @@ -1300,8 +1336,9 @@ 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= @@ -1319,7 +1356,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,16 +1366,14 @@ 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.9.0 h1:QWFNwbcc29IRy0xwD3hRrMc/RtSersLY1Z6TaID3vgI= +github.com/open-policy-agent/opa v1.9.0/go.mod h1:72+lKmTda0O48m1VKAxxYl7MjP/EWFZu9fxHQK2xihs= 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= @@ -1361,23 +1395,21 @@ github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1 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/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs= +github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA= +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-20250627152318-f293424e46b5 h1:WWs1ZFnGobK5ZXNu+N9If+8PDNVB9xAqrib/stUXsV4= +github.com/protocolbuffers/txtpbfmt v0.0.0-20250627152318-f293424e46b5/go.mod h1:BnHogPTyzYAReeQLZrOxyxzS739DaTNtTvohVdbENmA= +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/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= @@ -1393,69 +1425,72 @@ github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfF 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/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/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/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/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/rekor v1.4.2 h1:Lx2xby7loviFYdg2C9pB1mESk2QU/LqcYSGsqqZwmg8= +github.com/sigstore/rekor v1.4.2/go.mod h1:nX/OYaLqpTeCOuMEt7ELE0+5cVjZWFnFKM+cZ+3hQRA= +github.com/sigstore/rekor-tiles v0.1.11 h1:0NAJ2EhD1r6DH95FUuDTqUDd+c31LSKzoXGW5ZCzFq0= +github.com/sigstore/rekor-tiles v0.1.11/go.mod h1:eGIeqASh52pgWpmp/j5KZDjmKdVwob7eTYskVVRCu5k= +github.com/sigstore/rekor-tiles/v2 v2.0.0 h1:RDi03W/k7TOB+1StMOVdUaufKqtFImrh0KpOEPwsiV0= +github.com/sigstore/rekor-tiles/v2 v2.0.0/go.mod h1:1HyDsS2pQg36OoEZ0SeGmQIGflxK5W3nWW1Z+G6IWA8= +github.com/sigstore/sigstore v1.9.6-0.20250729224751-181c5d3339b3 h1:IEhSeWfhTd0kaBpHUXniWU2Tl5K5OUACN69mi1WGd+8= +github.com/sigstore/sigstore v1.9.6-0.20250729224751-181c5d3339b3/go.mod h1:JuqyPRJYnkNl6OTnQiG503EUnKih4P5EV6FUw+1B0iA= +github.com/sigstore/sigstore-go v1.1.3 h1:5lKcbXZa5JC7wb/UVywyCulccfYTUju1D5h4tkn+fXE= +github.com/sigstore/sigstore-go v1.1.3/go.mod h1:3jKC4IDh7TEVtCSJCjx0lpq5YfJbDJmfp65WsMvY2mg= 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/gcp v1.9.6-0.20250729224751-181c5d3339b3 h1:a7Yz8C0aBa/LjeiTa9ZLYi9B74GNhFRnUIUdvN6ddVk= +github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.9.6-0.20250729224751-181c5d3339b3/go.mod h1:tRtJzSZ48MXJV9bmS8pkb3mP36PCad/Cs+BmVJ3Z4O4= 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/sigstore/timestamp-authority v1.2.9 h1:L9Fj070/EbMC8qUk8BchkrYCS1BT5i93Bl6McwydkFs= +github.com/sigstore/timestamp-authority v1.2.9/go.mod h1:QyRnZchz4o+xdHyK5rvCWacCHxWmpX+mgvJwB1OXcLY= +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/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/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/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/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/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.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s= +github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0= +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= @@ -1474,20 +1509,20 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO 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.2.0 h1:Hmb+Azgd7IKOZeNJFT2C91y+YZ+F+TeloSIvQIaXCQw= +github.com/theupdateframework/go-tuf/v2 v2.2.0/go.mod h1:CubcJiJlBHQ2YkA5j9hlBO4B+tHFlLjRbWCJCT7EIKU= 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= @@ -1505,14 +1540,16 @@ github.com/transparency-dev/formats v0.0.0-20250421220931-bb8ad4d07c26 h1:YTbkeF github.com/transparency-dev/formats v0.0.0-20250421220931-bb8ad4d07c26/go.mod h1:ODywn0gGarHMMdSkWT56ULoK8Hk71luOyRseKek9COw= 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/transparency-dev/tessera v1.0.0 h1:4OT1V9xJLa5NnYlFWWlCdZkCm18/o12rdd+bCTje7XE= +github.com/transparency-dev/tessera v1.0.0/go.mod h1:TLvfjlkbmsmKVEJUtzO2eb9Q2IBnK3EJ0dI4G0oxEOU= 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/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.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/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= @@ -1544,13 +1581,11 @@ github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5t 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= +gitlab.com/gitlab-org/api/client-go v0.157.0 h1:B+/Ku1ek3V/MInR/SmvL4FOqE0YYx51u7lBVYIHC2ic= +gitlab.com/gitlab-org/api/client-go v0.157.0/go.mod h1:CQVoxjEswJZeXft4Mi+H+OF1MVrpNVF6m4xvlPTQ2J4= +go.mongodb.org/mongo-driver v1.17.4 h1:jUorfmVzljjr0FLzYQsGP8cgN/qzzxlY9Vh0C9KFXVw= +go.mongodb.org/mongo-driver v1.17.4/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ= 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= @@ -1560,45 +1595,49 @@ 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/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/detectors/gcp v1.38.0 h1:ZoYbqX7OaA/TAikspPl3ozPI6iY6LiIY9I8cUfm+pJs= +go.opentelemetry.io/contrib/detectors/gcp v1.38.0/go.mod h1:SU+iU7nu5ud4oCb3LQOhIZ3nRLj6FNVrKgtflbaf2ts= +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/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/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 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= +go.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4= +go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE= +go.step.sm/crypto v0.70.0 h1:Q9Ft7N637mucyZcHZd1+0VVQJVwDCKqcb9CYcYi7cds= +go.step.sm/crypto v0.70.0/go.mod h1:pzfUhS5/ue7ev64PLlEgXvhx1opwbhFCjkvlhsxVds0= 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.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI= +go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU= +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= @@ -1616,9 +1655,8 @@ golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0 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/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04= +golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0= 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/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1634,8 +1672,8 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0 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/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/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= @@ -1678,8 +1716,8 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91 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.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U= +golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI= 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= @@ -1745,8 +1783,8 @@ 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.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= +golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= 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= @@ -1776,8 +1814,8 @@ 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.32.0 h1:jsCblLleRMDrxMN29H3z/k1KliIvpLgCkE6R8FXXNgY= +golang.org/x/oauth2 v0.32.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= @@ -1795,8 +1833,8 @@ golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJ 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.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= +golang.org/x/sync v0.17.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= @@ -1827,7 +1865,6 @@ golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7w 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= @@ -1888,9 +1925,8 @@ 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.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= +golang.org/x/sys v0.37.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= @@ -1902,9 +1938,8 @@ 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/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q= +golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 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= @@ -1923,17 +1958,16 @@ 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/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= +golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= 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/time v0.13.0 h1:eUlYslOIt32DgYD6utsuUeHs4d7AsEYLuIAdg7FlYgI= +golang.org/x/time v0.13.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 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= @@ -2000,8 +2034,8 @@ 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.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE= +golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w= 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= @@ -2014,6 +2048,8 @@ gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJ 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/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= +gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= 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= @@ -2075,8 +2111,8 @@ google.golang.org/api v0.108.0/go.mod h1:2Ts0XTHNVWxypznxWOYUeI4g3WdP9Pk2Qk58+a/ 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= +google.golang.org/api v0.252.0 h1:xfKJeAJaMwb8OC9fesr369rjciQ704AjU/psjkKURSI= +google.golang.org/api v0.252.0/go.mod h1:dnHOv81x5RAmumZ7BWLShB/u7JZNeyalImxHmtTHxqw= 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= @@ -2216,12 +2252,12 @@ google.golang.org/genproto v0.0.0-20230323212658-478b75c54725/go.mod h1:UUQDJDOl 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-20250929231259-57b25ae835d4 h1:8XJ4pajGwOlasW+L13MnEGA8W4115jJySQtVfS2/IBU= +google.golang.org/genproto/googleapis/api v0.0.0-20250929231259-57b25ae835d4/go.mod h1:NnuHhy+bxcg30o7FnVAZbXsPHUDQ9qKWAQKCD7VxFtk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797 h1:CirRxTOwnRWVLKzDNrs0CXAaVozJoR4G9xvdRecrdpk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251002232023-7c0ddcbb5797/go.mod h1:HSkG/KdJWusxU1F6CNrwNDjBMgisKxGnc5dAZfT0mjQ= 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= @@ -2263,8 +2299,8 @@ google.golang.org/grpc v1.52.3/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5v 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 v1.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI= +google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= 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= @@ -2283,8 +2319,8 @@ google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw 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= @@ -2321,18 +2357,18 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt 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.1 h1:jC+153630BMdlFukegoEL8E/yT7aLyQkIVuwhmwDgJM= +k8s.io/api v0.34.1/go.mod h1:SB80FxFtXn5/gwzCoN6QCtPD7Vbu5w2n1S0J5gFfTYk= +k8s.io/apimachinery v0.34.1 h1:dTlxFls/eikpJxmAC7MVE8oOeP1zryV7iRyIjB0gky4= +k8s.io/apimachinery v0.34.1/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw= +k8s.io/client-go v0.34.1 h1:ZUPJKgXsnKwVwmKKdPfw4tB58+7/Ik3CrjOEhsiZ7mY= +k8s.io/client-go v0.34.1/go.mod h1:kA8v0FP+tk6sZA0yKLRG67LWjqufAoSHA2xVGKw9Of8= 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= +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= 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= @@ -2371,16 +2407,15 @@ 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= +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..ccb9a0598b9 100644 --- a/internal/pkg/cosign/tsa/mock/mock_tsa_client.go +++ b/internal/pkg/cosign/tsa/mock/mock_tsa_client.go @@ -24,7 +24,7 @@ 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" 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..e1f39584ad6 100644 --- a/pkg/cosign/bundle/protobundle.go +++ b/pkg/cosign/bundle/protobundle.go @@ -15,11 +15,22 @@ 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" @@ -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..2b944d9ead6 --- /dev/null +++ b/pkg/cosign/bundle/sign.go @@ -0,0 +1,132 @@ +// 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, signingConfig *root.SigningConfig, trustedMaterial root.TrustedMaterial) ([]byte, error) { + var opts sign.BundleOptions + + if trustedMaterial != nil { + opts.TrustedRoot = trustedMaterial + } + + if 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, + } + } else { + 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) +} 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..26d7ed49059 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` @@ -31,9 +30,11 @@ import ( "path/filepath" "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/signature" + "github.com/sigstore/sigstore/pkg/signature/options" ) const ( @@ -70,7 +71,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 @@ -194,6 +236,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 +264,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 +282,18 @@ 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 } 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..391a05b796b 100644 --- a/pkg/cosign/verifiers.go +++ b/pkg/cosign/verifiers.go @@ -25,7 +25,7 @@ import ( "github.com/in-toto/in-toto-golang/in_toto" "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" ) 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..f4755934d53 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" @@ -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 @@ -997,13 +1013,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 +1097,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,7 +1621,7 @@ 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, co *CheckOpts, 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...) @@ -1625,7 +1644,7 @@ func getBundles(_ context.Context, signedImgRef name.Reference, co *CheckOpts) ( } 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 } @@ -1648,8 +1667,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, nameOpts...) if err != nil { return nil, false, 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..f9d44b7c379 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, &CheckOpts{}) 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, &CheckOpts{}) 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, &CheckOpts{}) 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, &CheckOpts{}) 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..4329dedb305 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" @@ -1648,6 +1648,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 +1695,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 +1717,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..c612759212c 100644 --- a/pkg/oci/remote/write.go +++ b/pkg/oci/remote/write.go @@ -27,12 +27,14 @@ import ( "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/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 @@ -146,7 +148,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 +163,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 +178,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 +210,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,7 +226,9 @@ func (taggable taggableManifest) MediaType() (types.MediaType, error) { return taggable.mediaType, nil } -func WriteAttestationNewBundleFormat(d name.Digest, bundleBytes []byte, predicateType string, opts ...Option) error { +// 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() @@ -232,7 +236,7 @@ func WriteAttestationNewBundleFormat(d name.Digest, bundleBytes []byte, predicat if err != nil { return err } - desc, err := remote.Head(ref, o.ROpt...) + desc, err := remoteHead(ref, o.ROpt...) if err != nil { return err } @@ -247,32 +251,35 @@ func WriteAttestationNewBundleFormat(d name.Digest, bundleBytes []byte, predicat if err != nil { return 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) } - // 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)) - blobDigest, err := layer.Digest() - if err != nil { - return fmt.Errorf("failed to calculate digest: %w", err) - } - - blobSize, err := layer.Size() - if err != nil { - return fmt.Errorf("failed to calculate size: %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 = remote.WriteLayer(d.Repository, layer, o.ROpt...) - if err != nil { - return fmt.Errorf("failed to upload layer: %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 +288,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 +372,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 +382,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..6882f7ae3fc 100644 --- a/release/cloudbuild.yaml +++ b/release/cloudbuild.yaml @@ -32,20 +32,20 @@ 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:v2.6.1-dev@sha256:40523fa4ca7ba0d9930154f0f6e1730b7a57bee61cadc9612730dfc992bc8abc' 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.3-0@sha256:5f7e91a9e3c2411fe1973d9a5ab2f34eddd166251a95654b66c1171128f013c6' - '--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.3-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.3-0@sha256:5f7e91a9e3c2411fe1973d9a5ab2f34eddd166251a95654b66c1171128f013c6 entrypoint: /bin/sh dir: "go/src/sigstore/cosign" env: @@ -68,7 +68,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.3-0@sha256:5f7e91a9e3c2411fe1973d9a5ab2f34eddd166251a95654b66c1171128f013c6 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..e07bd9ca59e 100644 --- a/test/e2e_attach_test.go +++ b/test/e2e_attach_test.go @@ -38,16 +38,17 @@ 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" + "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/pkg/client" "github.com/sigstore/timestamp-authority/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..26f546ecaf0 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,13 +74,19 @@ 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) so.Registry = options.RegistryOptions{ - AllowInsecure: true, + AllowInsecure: true, + AllowHTTPRegistry: true, } if useOCI11 { so.RegistryExperimental = options.RegistryExperimentalOptions{ @@ -83,17 +99,105 @@ func TestInsecureRegistry(t *testing.T) { 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(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), 0600); 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..9337c97320f 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" ) diff --git a/test/e2e_test.go b/test/e2e_test.go index a57d197b99f..95714bc34d7 100644 --- a/test/e2e_test.go +++ b/test/e2e_test.go @@ -26,6 +26,7 @@ import ( "crypto/sha256" "crypto/x509" "encoding/base64" + "encoding/hex" "encoding/json" "encoding/pem" "fmt" @@ -36,41 +37,47 @@ import ( "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" + 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" @@ -121,6 +128,14 @@ func TestSignVerify(t *testing.T) { must(verify(pubKeyPath, imgName, true, nil, "", false), t) must(download.SignatureCmd(ctx, options.RegistryOptions{}, imgName), 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) @@ -572,17 +587,19 @@ 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} } must(cmd.Exec(context.TODO()), t) return out @@ -834,6 +851,447 @@ func TestSignVerifyWithTUFMirror(t *testing.T) { } } +func prepareSigningConfig(t *testing.T, fulcioURL, rekorURL, oidcURL, tsaURL string) string { + 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 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") + + _, 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) + } + + 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 + + // Sign a blob + blob := "someblob" + blobDir := t.TempDir() + bp := filepath.Join(blobDir, blob) + if err := os.WriteFile(bp, []byte(blob), 0644); err != nil { + t.Fatal(err) + } + bundlePath := filepath.Join(blobDir, "bundle.json") + ko.NewBundleFormat = true + ko.BundlePath = bundlePath + + _, err = sign.SignBlobCmd(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) + + // 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), 0644); err != nil { + t.Fatal(err) + } + attBundlePath := filepath.Join(attestDir, "attest.bundle.json") + ko.NewBundleFormat = true + ko.BundlePath = attBundlePath + + attestBlobCmd := attest.AttestBlobCommand{ + KeyOpts: ko, + RekorEntryType: "dsse", + StatementPath: statementPath, + } + 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 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() + imgName := path.Join(repo, "cosign-e2e") + + _, _, cleanup := mkimage(t, imgName) + defer cleanup() + + 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) + } + + 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 + + // Sign image with identity token in bundle format + so := options.SignOptions{ + Upload: true, + NewBundleFormat: true, + TlogUpload: true, + } + must(sign.SignCmd(ro, ko, so, []string{imgName}), t) + + // 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) + + // Attest image + predicate := `{ "buildType": "x", "builder": { "id": "2" }, "recipe": {} }` + predicatePath := filepath.Join(t.TempDir(), "predicate.json") + if err := os.WriteFile(predicatePath, []byte(predicate), 0644); err != nil { + t.Fatal(err) + } + attestCmd := attest.AttestCommand{ + KeyOpts: ko, + PredicatePath: predicatePath, + PredicateType: "slsaprovenance", + Timeout: 30 * time.Second, + RekorEntryType: "dsse", + } + must(attestCmd.Exec(ctx, imgName), t) + + // 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) +} + +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), 0644); err != nil { + t.Fatal(err) + } + bundlePath := filepath.Join(blobDir, "bundle.json") + ko.NewBundleFormat = true + ko.BundlePath = bundlePath + ko.KeyRef = privKeyPath + + _, err = sign.SignBlobCmd(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), 0644); 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, + } + 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(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(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(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) +} + func TestAttestVerify(t *testing.T) { for _, newBundleFormat := range []bool{false, true} { attestVerify(t, @@ -1432,6 +1890,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) { @@ -1567,17 +2029,17 @@ func TestVerifyWithCARoots(t *testing.T) { } 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}) @@ -2091,7 +2553,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) } } @@ -2327,23 +2789,181 @@ func TestSignBlobNewBundle(t *testing.T) { IgnoreTlog: true, } - // Verify should fail before bundle is written - mustErr(verifyBlobCmd.Exec(ctx, blobPath), t) + // Verify should fail before bundle is written + mustErr(verifyBlobCmd.Exec(ctx, blobPath), t) + + // Produce signed bundle + ko := options.KeyOpts{ + KeyRef: privKeyPath, + PassFunc: passFunc, + BundlePath: bundlePath, + NewBundleFormat: true, + } + + if _, err := sign.SignBlobCmd(ro, ko, blobPath, true, "", "", false); err != nil { + t.Fatal(err) + } + + // Verify should succeed now that bundle is written + 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), 0644); 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(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") - // Produce signed bundle - ko := options.KeyOpts{ - KeyRef: privKeyPath, - PassFunc: passFunc, - BundlePath: bundlePath, - NewBundleFormat: true, + // Create a CreateCmd instance + createCmd := trustedroot.CreateCmd{ + CertChain: []string{rootFile}, + Out: trustedRootPath, + RekorKeyPath: []string{rekorPubKey}, + CtfeKeyPath: []string{ctfePubKey}, } - if _, err := sign.SignBlobCmd(ro, ko, blobPath, true, "", "", false); err != nil { + // Execute the command to create the trusted root + if err := createCmd.Exec(context.Background()); err != nil { t.Fatal(err) } - // Verify should succeed now that bundle is written - must(verifyBlobCmd.Exec(ctx, blobPath), t) + 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), 0644); 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(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, 0644); err != nil { + t.Fatal(err) + } + + // Verify should succeed now that bundle is written + must(verifyBlobCmd.Exec(ctx, blobPath), t) + }) + } } func TestSignBlobRFC3161TimestampBundle(t *testing.T) { @@ -2835,7 +3455,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() { @@ -2920,7 +3540,7 @@ func TestAttestBlobSignVerify(t *testing.T) { } blobVerifyAttestationCmd = cliverify.VerifyBlobAttestationCommand{ KeyOpts: ko, - Digest: "123", + Digest: "7e9b6e7ba2842c91cf49f3e214d04a7a496f8214356f41d81a6e6dcad11f11e3", DigestAlg: "alg", SignaturePath: outputSignature, IgnoreTlog: true, @@ -3267,3 +3887,351 @@ 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(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(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(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(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(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(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(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(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), 0644); 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)))) +} diff --git a/test/e2e_test.ps1 b/test/e2e_test.ps1 index 66e4c30edd7..dd6736f6321 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 --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..cd23d26199e 100644 --- a/test/e2e_tsa_test.go +++ b/test/e2e_tsa_test.go @@ -27,10 +27,11 @@ 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" + "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/pkg/client" tsaserver "github.com/sigstore/timestamp-authority/pkg/server" "github.com/spf13/viper" @@ -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) @@ -151,11 +152,11 @@ func generateSigningKeys(t *testing.T, td string) (string, string, string) { } 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) @@ -164,7 +165,7 @@ func generateMTLSKeys(t *testing.T, td string) (string, string, string, string, 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) 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" )