diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 6ef005106..bb6ea1b9e 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -20,15 +20,34 @@ updates: directory: "/" # Location of package manifests schedule: interval: "weekly" + groups: + all: + update-types: + - "patch" - package-ecosystem: "gomod" directory: "./hack/tools" schedule: interval: "weekly" + groups: + all: + update-types: + - "minor" + - "patch" - package-ecosystem: "github-actions" directory: "/" schedule: interval: "weekly" + groups: + all: + update-types: + - "minor" + - "patch" - package-ecosystem: "docker" directory: "/" schedule: interval: "weekly" + groups: + all: + update-types: + - "minor" + - "patch" diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index db002861d..cb6398e21 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -39,13 +39,17 @@ jobs: language: [ 'go' ] steps: - name: Checkout repository - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - - name: Extract version of Go to use - run: echo "GOVERSION=$(cat Dockerfile|grep golang | awk ' { print $2 } ' | cut -d '@' -f 1 | cut -d ':' -f 2 | uniq)" >> $GITHUB_ENV - - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 + # TODO: uncomment when we bump to go1.22 in go.mod + # - name: Extract version of Go to use + # run: echo "GOVERSION=$(cat Dockerfile|grep golang | awk ' { print $2 } ' | cut -d '@' -f 1 | cut -d ':' -f 2 | uniq)" >> $GITHUB_ENV + + - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: - go-version: ${{ env.GOVERSION }} + go-version: '1.22' + check-latest: true + - uses: arduino/setup-protoc@c65c819552d16ad3c9b72d9dfd5ba5237b9c906b # v3.0.0 name: Install protobuf with: diff --git a/.github/workflows/container-build.yml b/.github/workflows/container-build.yml index 616ccf83b..8f77d8f88 100644 --- a/.github/workflows/container-build.yml +++ b/.github/workflows/container-build.yml @@ -26,28 +26,32 @@ jobs: name: build runs-on: ubuntu-latest + if: github.repository == 'sigstore/fulcio' + permissions: id-token: write contents: read steps: - - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - - uses: sigstore/cosign-installer@e1523de7571e31dbe865fd2e80c5c7c23ae71eb4 # v3.4.0 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: sigstore/cosign-installer@59acb6260d9c0ba8f4a2f9d9b48431a222b68e20 # v3.5.0 - - name: Extract version of Go to use - run: echo "GOVERSION=$(cat Dockerfile|grep golang | awk ' { print $2 } ' | cut -d '@' -f 1 | cut -d ':' -f 2 | uniq)" >> $GITHUB_ENV + # TODO: uncomment when we bump to go1.22 in go.mod + # - name: Extract version of Go to use + # run: echo "GOVERSION=$(cat Dockerfile|grep golang | awk ' { print $2 } ' | cut -d '@' -f 1 | cut -d ':' -f 2 | uniq)" >> $GITHUB_ENV - - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 + - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: - go-version: ${{ env.GOVERSION }} + go-version: '1.22' + check-latest: true - name: deps run: sudo apt-get update && sudo apt-get install -yq libpcsclite-dev - - uses: ko-build/setup-ko@ace48d793556083a76f1e3e6068850c1f4a369aa # v0.6 + - uses: ko-build/setup-ko@3aebd0597dc1e9d1a26bcfdb7cbeb19c131d3037 # v0.7 - name: Set up Cloud SDK - uses: google-github-actions/auth@55bd3a7c6e2ae7cf1877fd1ccb9d54c0503c457c # v2.1.2 + uses: google-github-actions/auth@71fee32a0bb7e97b4d33d548e7d957010649d8fa # v2.1.3 with: workload_identity_provider: 'projects/498091336538/locations/global/workloadIdentityPools/githubactions/providers/sigstore-fulcio' service_account: 'github-actions-fulcio@projectsigstore.iam.gserviceaccount.com' diff --git a/.github/workflows/cut-release.yml b/.github/workflows/cut-release.yml index 11180e5ae..32e509ad9 100644 --- a/.github/workflows/cut-release.yml +++ b/.github/workflows/cut-release.yml @@ -21,7 +21,7 @@ concurrency: cut-release jobs: cut-release: name: Cut release - uses: sigstore/sigstore/.github/workflows/reusable-release.yml@main + uses: sigstore/community/.github/workflows/reusable-release.yml@main permissions: id-token: write contents: read diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e6d463385..8b65fb8b8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -29,23 +29,31 @@ jobs: runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - - name: Extract version of Go to use - run: echo "GOVERSION=$(cat Dockerfile|grep golang | awk ' { print $2 } ' | cut -d '@' -f 1 | cut -d ':' -f 2 | uniq)" >> $GITHUB_ENV - - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + + # TODO: uncomment when we bump to go1.22 in go.mod + # - name: Extract version of Go to use + # run: echo "GOVERSION=$(cat Dockerfile|grep golang | awk ' { print $2 } ' | cut -d '@' -f 1 | cut -d ':' -f 2 | uniq)" >> $GITHUB_ENV + + - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: - go-version: ${{ env.GOVERSION }} + go-version: '1.22' + check-latest: true + - uses: arduino/setup-protoc@c65c819552d16ad3c9b72d9dfd5ba5237b9c906b # v3.0.0 name: Install protobuf with: - version: '25.1' + version: '27.2' repo-token: ${{ secrets.GITHUB_TOKEN }} - name: Build run: make -C $GITHUB_WORKSPACE all + - name: Test run: go test -v -coverprofile=coverage.txt -covermode=atomic ./... + - name: Upload Coverage Report - uses: codecov/codecov-action@c16abc29c95fcf9174b58eb7e1abf4c866893bc8 # v4.1.1 + uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # v4.5.0 + - name: Ensure no files were modified as a result of the build run: git update-index --refresh && git diff-index --quiet -I"^\/\/\s+(-\s+)?protoc(-gen-go)?\s+v[0-9]+\.[0-9]+\.[0-9]+$" HEAD -- || git diff -I"^\/\/\s+(-\s+)?protoc(-gen-go)?\s+v[0-9]+\.[0-9]+\.[0-9]+$" --exit-code diff --git a/.github/workflows/protoc-dependabot-hack.yml b/.github/workflows/protoc-dependabot-hack.yml index 02c781cca..7fcc9ed52 100644 --- a/.github/workflows/protoc-dependabot-hack.yml +++ b/.github/workflows/protoc-dependabot-hack.yml @@ -11,9 +11,9 @@ jobs: dependabot_hack: name: Ensure dependabot version checks - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: # update the version in these places manually when Dependabot proposes a change to it here: # 1. the version in main.yml used to install protoc - - uses: protocolbuffers/protobuf@v26.1 + - uses: protocolbuffers/protobuf@v27.3 diff --git a/.github/workflows/scorecard_action.yml b/.github/workflows/scorecard_action.yml index 35cd9ac43..3b5d9e0a1 100644 --- a/.github/workflows/scorecard_action.yml +++ b/.github/workflows/scorecard_action.yml @@ -23,12 +23,12 @@ jobs: id-token: write steps: - name: "Checkout code" - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 with: persist-credentials: false - name: "Run analysis" - uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1 + uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0 with: results_file: results.sarif results_format: sarif @@ -44,7 +44,7 @@ jobs: # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF # format to the repository Actions tab. - name: "Upload artifact" - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 + uses: actions/upload-artifact@89ef406dd8d7e03cfd12d9e0a4a378f454709029 # v4.3.5 with: name: SARIF file path: results.sarif diff --git a/.github/workflows/validate-release.yml b/.github/workflows/validate-release.yml index 6b9b69ca2..759353986 100644 --- a/.github/workflows/validate-release.yml +++ b/.github/workflows/validate-release.yml @@ -28,14 +28,14 @@ jobs: check-signature: runs-on: ubuntu-latest container: - image: gcr.io/projectsigstore/cosign:v2.2.3-dev@sha256:0d795fa145b03026b7bc2a35e33068cdb75e1c1f974e604c17408bf7bd174967 + image: gcr.io/projectsigstore/cosign:v2.2.4-dev@sha256:13efd4c62710d75f07d12d8aad36a8657eeffd4f5f3a40bcbc207d8aafa67d41 steps: - name: Check Signature run: | - cosign verify ghcr.io/gythialy/golang-cross:v1.21.8-0@sha256:9c86fc6c6763cd5cd9a07f25083fc5a87f3525b5f8d7ff886822e2153f0c8405 \ + cosign verify ghcr.io/gythialy/golang-cross:v1.22.5-0@sha256:5cf8fca7fe80392c8d1597fe89d291d49120507390f25507746f73d4b7f8a8f2 \ --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.21.8-0" + --certificate-identity "https://github.com/gythialy/golang-cross/.github/workflows/release-golang-cross.yml@refs/tags/v1.22.5-0" env: TUF_ROOT: /tmp @@ -44,10 +44,10 @@ jobs: needs: - check-signature container: - image: ghcr.io/gythialy/golang-cross:v1.21.8-0@sha256:9c86fc6c6763cd5cd9a07f25083fc5a87f3525b5f8d7ff886822e2153f0c8405 + image: ghcr.io/gythialy/golang-cross:v1.22.5-0@sha256:5cf8fca7fe80392c8d1597fe89d291d49120507390f25507746f73d4b7f8a8f2 steps: - - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 # Error: fatal: detected dubious ownership in repository at '/__w/fulcio/fulcio' # To add an exception for this directory, call: diff --git a/.github/workflows/verify-k8s.yml b/.github/workflows/verify-k8s.yml index 6ce6d292d..e86859d01 100644 --- a/.github/workflows/verify-k8s.yml +++ b/.github/workflows/verify-k8s.yml @@ -25,14 +25,20 @@ jobs: name: k8s manifest check runs-on: ubuntu-latest steps: - - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - - name: Extract version of Go to use - run: echo "GOVERSION=$(cat Dockerfile|grep golang | awk ' { print $2 } ' | cut -d '@' -f 1 | cut -d ':' -f 2 | uniq)" >> $GITHUB_ENV - - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + + # TODO: uncomment when we bump to go1.22 in go.mod + # - name: Extract version of Go to use + # run: echo "GOVERSION=$(cat Dockerfile|grep golang | awk ' { print $2 } ' | cut -d '@' -f 1 | cut -d ':' -f 2 | uniq)" >> $GITHUB_ENV + + - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: go-version: ${{ env.GOVERSION }} + check-latest: true + - name: Install kubeval run: go install github.com/instrumenta/kubeval@v0.16.1 + - run: kubeval config/*.yaml verify-k8s-deployment: @@ -46,12 +52,11 @@ jobs: include: - issuer: "OIDC Issuer" - issuer-config: | - "OIDCIssuers": {"https://kubernetes.default.svc": {"IssuerURL": "https://kubernetes.default.svc","ClientID": "sigstore","Type": "kubernetes"}} + issuer-config: + "oidc-issuers:\n https://kubernetes.default.svc:\n issuer-url: \"https://kubernetes.default.svc\"\n client-id: \"sigstore\"\n type: \"kubernetes\"" - issuer: "Meta Issuer" - issuer-config: | - "MetaIssuers": {"https://kubernetes.*.svc": {"ClientID": "sigstore","Type": "kubernetes"}} - + issuer-config: + "meta-issuers:\n https://kubernetes.*.svc: \n client-id: \"sigstore\"\n type: \"kubernetes\"" env: # https://github.com/google/go-containerregistry/pull/125 allows insecure registry for # '*.local' hostnames. This works both for `ko` and our own tag-to-digest resolution logic, @@ -63,14 +68,18 @@ jobs: GIT_VERSION: test steps: - - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - - name: Extract version of Go to use - run: echo "GOVERSION=$(cat Dockerfile|grep golang | awk ' { print $2 } ' | cut -d '@' -f 1 | cut -d ':' -f 2 | uniq)" >> $GITHUB_ENV - - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + + # TODO: uncomment when we bump to go1.22 in go.mod + # - name: Extract version of Go to use + # run: echo "GOVERSION=$(cat Dockerfile|grep golang | awk ' { print $2 } ' | cut -d '@' -f 1 | cut -d ':' -f 2 | uniq)" >> $GITHUB_ENV + + - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: - go-version: ${{ env.GOVERSION }} + go-version: '1.22' + check-latest: true - - uses: ko-build/setup-ko@ace48d793556083a76f1e3e6068850c1f4a369aa # v0.6 + - uses: ko-build/setup-ko@3aebd0597dc1e9d1a26bcfdb7cbeb19c131d3037 # v0.7 - name: Setup Cluster uses: chainguard-dev/actions/setup-kind@f94883c3bd16936401291899070258f855b5d849 # main @@ -114,10 +123,8 @@ jobs: name: fulcio-config namespace: fulcio-system data: - config.json: |- - { - ${{ matrix.issuer-config }} - } + config.yaml: |- + ${{ matrix.issuer-config }} server.yaml: |- host: 0.0.0.0 port: 5555 @@ -129,7 +136,6 @@ jobs: ct-log-url: "" log_type: prod EOF - # Create secret needed to use fileca cat < config/fulcio-secret.yaml apiVersion: v1 diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index 892a6068f..11d71f277 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -15,7 +15,11 @@ name: Verify -on: [push, pull_request] +on: + push: + branches: + - main + pull_request: permissions: contents: read @@ -25,14 +29,20 @@ jobs: name: license boilerplate check runs-on: ubuntu-latest steps: - - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - - name: Extract version of Go to use - run: echo "GOVERSION=$(cat Dockerfile|grep golang | awk ' { print $2 } ' | cut -d '@' -f 1 | cut -d ':' -f 2 | uniq)" >> $GITHUB_ENV - - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + + # TODO: uncomment when we bump to go1.22 in go.mod + # - name: Extract version of Go to use + # run: echo "GOVERSION=$(cat Dockerfile|grep golang | awk ' { print $2 } ' | cut -d '@' -f 1 | cut -d ':' -f 2 | uniq)" >> $GITHUB_ENV + + - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: - go-version: ${{ env.GOVERSION }} + go-version: '1.22' + check-latest: true + - name: Install addlicense run: go install github.com/google/addlicense@v1.0.0 + - name: Check license headers run: | set -e @@ -43,32 +53,42 @@ jobs: name: golangci-lint runs-on: ubuntu-latest steps: - - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - name: deps run: sudo apt-get update && sudo apt-get install -yq libpcsclite-dev - - name: Extract version of Go to use - run: echo "GOVERSION=$(cat Dockerfile|grep golang | awk ' { print $2 } ' | cut -d '@' -f 1 | cut -d ':' -f 2 | uniq)" >> $GITHUB_ENV - - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 + + # TODO: uncomment when we bump to go1.22 in go.mod + # - name: Extract version of Go to use + # run: echo "GOVERSION=$(cat Dockerfile|grep golang | awk ' { print $2 } ' | cut -d '@' -f 1 | cut -d ':' -f 2 | uniq)" >> $GITHUB_ENV + + - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: - go-version: ${{ env.GOVERSION }} + go-version: '1.22' + check-latest: true + - name: golangci-lint - uses: golangci/golangci-lint-action@3cfe3a4abbb849e10058ce4af15d205b6da42804 # v4.0.0 - timeout-minutes: 5 + uses: golangci/golangci-lint-action@aaa42aa0628b4ae2578232a66b541047968fac86 # v6.1.0 + timeout-minutes: 10 with: - version: v1.55 + version: v1.59 oidc-config: name: oidc-config runs-on: ubuntu-latest steps: - - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 - - name: Extract version of Go to use - run: echo "GOVERSION=$(cat Dockerfile|grep golang | awk ' { print $2 } ' | cut -d '@' -f 1 | cut -d ':' -f 2 | uniq)" >> $GITHUB_ENV - - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + + # TODO: uncomment when we bump to go1.22 in go.mod + # - name: Extract version of Go to use + # run: echo "GOVERSION=$(cat Dockerfile|grep golang | awk ' { print $2 } ' | cut -d '@' -f 1 | cut -d ':' -f 2 | uniq)" >> $GITHUB_ENV + + - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: - go-version: ${{ env.GOVERSION }} + go-version: '1.22' + check-latest: true + - name: check-config run: | set -e - go run federation/main.go - git diff --exit-code + go test -timeout 30s -run ^TestLoadFulcioConfig$ github.com/sigstore/fulcio/pkg/config diff --git a/.goreleaser.yml b/.goreleaser.yml index 9a55fb619..1e863edcb 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -1,4 +1,5 @@ project_name: fulcio +version: 2 env: - GO111MODULE=on diff --git a/.tekton/fulcio-pull-request.yaml b/.tekton/fulcio-pull-request.yaml index 4e5f82e10..c4dce8d2e 100644 --- a/.tekton/fulcio-pull-request.yaml +++ b/.tekton/fulcio-pull-request.yaml @@ -8,7 +8,7 @@ metadata: build.appstudio.redhat.com/target_branch: '{{target_branch}}' pipelinesascode.tekton.dev/max-keep-runs: "3" pipelinesascode.tekton.dev/on-cel-expression: event == "pull_request" && target_branch == "main" - pipelinesascode.tekton.dev/task: "[.tekton/fulcio-unit-test.yaml]" + # pipelinesascode.tekton.dev/task: "[.tekton/fulcio-unit-test.yaml]" creationTimestamp: null labels: appstudio.openshift.io/application: fulcio @@ -30,10 +30,6 @@ spec: value: . - name: revision value: '{{revision}}' - - name: prefetch-input - value: '{"type": "gomod", "path": "."}' - - name: hermetic - value: "true" - name: build-source-image value: "true" pipelineSpec: @@ -341,26 +337,26 @@ spec: operator: in values: - "false" - - name: run-unit-test - runAfter: - - prefetch-dependencies - taskRef: - name: go-unit-test - params: - - name: SOURCE_ARTIFACT - value: $(tasks.prefetch-dependencies.results.SOURCE_ARTIFACT) - - name: CACHI2_ARTIFACT - value: $(tasks.prefetch-dependencies.results.CACHI2_ARTIFACT) + # - name: run-unit-test + # runAfter: + # - prefetch-dependencies + # taskRef: + # name: go-unit-test + # params: + # - name: SOURCE_ARTIFACT + # value: $(tasks.prefetch-dependencies.results.SOURCE_ARTIFACT) + # - name: CACHI2_ARTIFACT + # value: $(tasks.prefetch-dependencies.results.CACHI2_ARTIFACT) workspaces: - name: git-auth optional: true taskRunTemplate: {} taskRunSpecs: - - pipelineTaskName: run-unit-test - serviceAccountName: appstudio-pipeline - podTemplate: - imagePullSecrets: - - name: brew-registry-pull-secret + # - pipelineTaskName: run-unit-test + # serviceAccountName: appstudio-pipeline + # podTemplate: + # imagePullSecrets: + # - name: brew-registry-pull-secret workspaces: - name: git-auth secret: diff --git a/.tekton/fulcio-push.yaml b/.tekton/fulcio-push.yaml index e21db95e1..0d1dcd435 100644 --- a/.tekton/fulcio-push.yaml +++ b/.tekton/fulcio-push.yaml @@ -7,7 +7,7 @@ metadata: build.appstudio.redhat.com/target_branch: '{{target_branch}}' pipelinesascode.tekton.dev/max-keep-runs: "3" pipelinesascode.tekton.dev/on-cel-expression: event == "push" && target_branch == "main" - pipelinesascode.tekton.dev/task: "[.tekton/fulcio-unit-test.yaml]" + # pipelinesascode.tekton.dev/task: "[.tekton/fulcio-unit-test.yaml]" build.appstudio.openshift.io/build-nudge-files: "controllers/constants/*" creationTimestamp: null labels: @@ -28,10 +28,6 @@ spec: value: . - name: revision value: '{{revision}}' - - name: prefetch-input - value: '{"type": "gomod", "path": "."}' - - name: hermetic - value: "true" - name: build-source-image value: "true" pipelineSpec: @@ -339,16 +335,16 @@ spec: operator: in values: - "false" - - name: run-unit-test - runAfter: - - prefetch-dependencies - taskRef: - name: go-unit-test - params: - - name: SOURCE_ARTIFACT - value: $(tasks.prefetch-dependencies.results.SOURCE_ARTIFACT) - - name: CACHI2_ARTIFACT - value: $(tasks.prefetch-dependencies.results.CACHI2_ARTIFACT) + # - name: run-unit-test + # runAfter: + # - prefetch-dependencies + # taskRef: + # name: go-unit-test + # params: + # - name: SOURCE_ARTIFACT + # value: $(tasks.prefetch-dependencies.results.SOURCE_ARTIFACT) + # - name: CACHI2_ARTIFACT + # value: $(tasks.prefetch-dependencies.results.CACHI2_ARTIFACT) workspaces: - name: git-auth optional: true diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ac83d4d2..4b452e5cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,70 @@ +# v1.6.0 + +v1.6.0 adds support for onboarding CI identity providers via configuration +rather than code changes, which should greatly simplify the onboarding process. + +## Features + +* CiProvider as a new OIDCIssuer type (#1729) +* Add TLS support for CTLog (#1718) +* Added support for email\_verified being a string or bool (#1744) + +## Documentation + +* Update IDP requirements (#1742) + +## Public Good Instance Configuration + +* Move codefresh and buildkite to ci-provider identity (#1743) +* Move gitlab to ci-provider (#1740) +* Migrate github to ci provider flow (#1738) +* add Hellō provider (#1739) +* Move configuration to yaml format (#1720) +* Removes identity providers federation (#1736) + +## Contributors + +* Andrew Block +* cpanato +* Dick Hardt +* Firas Ghanmi +* Hayden B +* Javan Lacerda +* Matt Moore + +# v1.5.1 + +## Bug Fixes + +* Surface the right `Name()` from our principal. (#1726) + +## Contributors + +* Matt Moore + +# v1.5.0 + +## Features + +* Add Chainguard OIDC provider. (#1703) +* Adding support for configuration from yaml file (#1687) +* Upgrade go to 1.22 (#1625) + +## Documentation + +* oid-info: fix table render (#1662) +* docs: Fix extensions for digest values requiring a type prefix (#1661) + +## Contributors + +* Bob Callaway +* Carlos Tadeu Panato Junior +* Facundo Tuesca +* Javan Lacerda +* Matt Moore +* Tomas Turek +* William Woodruff + # v1.4.5 ## Features diff --git a/README.md b/README.md index 4a1eccf00..f834f5402 100644 --- a/README.md +++ b/README.md @@ -118,7 +118,7 @@ process](https://github.com/sigstore/.github/blob/main/SECURITY.md). Fulcio is developed as part of the [`sigstore`](https://sigstore.dev) project. We also use a [slack channel](https://sigstore.slack.com)! -Click [here](https://links.sigstore.dev/slack-invite) for the invite link. +To check more information about Slack and other communication channels please check the [community repository](https://github.com/sigstore/community?tab=readme-ov-file#slack) ## Additional Documentation diff --git a/cmd/app/grpc.go b/cmd/app/grpc.go index e1d59c8c0..c2f5358f6 100644 --- a/cmd/app/grpc.go +++ b/cmd/app/grpc.go @@ -60,7 +60,7 @@ type grpcServer struct { } func PassFulcioConfigThruContext(cfg *config.FulcioConfig) grpc.UnaryServerInterceptor { - return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { + return func(ctx context.Context, req interface{}, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { // For each request, infuse context with our snapshot of the FulcioConfig. // TODO(mattmoor): Consider periodically (every minute?) refreshing the ConfigMap // from disk, so that we don't need to cycle pods to pick up config updates. diff --git a/cmd/app/serve.go b/cmd/app/serve.go index 3ad4ef2ba..499de9085 100644 --- a/cmd/app/serve.go +++ b/cmd/app/serve.go @@ -88,7 +88,7 @@ func newServeCmd() *cobra.Command { cmd.Flags().String("hsm-caroot-id", "", "HSM ID for Root CA (only used with --ca pkcs11ca)") cmd.Flags().String("ct-log-url", "http://localhost:6962/test", "host and path (with log prefix at the end) to the ct log") cmd.Flags().String("ct-log-public-key-path", "", "Path to a PEM-encoded public key of the CT log, used to verify SCTs") - cmd.Flags().String("config-path", "/etc/fulcio-config/config.json", "path to fulcio config json") + cmd.Flags().String("config-path", "/etc/fulcio-config/config.yaml", "path to fulcio config yaml") cmd.Flags().String("pkcs11-config-path", "config/crypto11.conf", "path to fulcio pkcs11 config file") cmd.Flags().String("fileca-cert", "", "Path to CA certificate") cmd.Flags().String("fileca-key", "", "Path to CA encrypted private key") @@ -112,7 +112,7 @@ func newServeCmd() *cobra.Command { cmd.Flags().String("ct-log.tls-ca-cert", "", "Path to TLS CA certificate used to connect to ct-log") // convert "http-host" flag to "host" and "http-port" flag to be "port" - cmd.Flags().SetNormalizeFunc(func(f *pflag.FlagSet, name string) pflag.NormalizedName { + cmd.Flags().SetNormalizeFunc(func(_ *pflag.FlagSet, name string) pflag.NormalizedName { switch name { case "http-port": name = "port" diff --git a/cmd/fetch_ca_cert/fetch_ca_cert.go b/cmd/fetch_ca_cert/fetch_ca_cert.go index b22d6c277..914ce5dd0 100644 --- a/cmd/fetch_ca_cert/fetch_ca_cert.go +++ b/cmd/fetch_ca_cert/fetch_ca_cert.go @@ -73,7 +73,7 @@ func fetchCACertificate(ctx context.Context, parent, kmsKey, tinkKeysetPath, tin if err != nil { return nil, err } - signer, _, err = kmsSigner.CryptoSigner(ctx, func(err error) {}) + signer, _, err = kmsSigner.CryptoSigner(ctx, func(_ error) {}) if err != nil { return nil, err } diff --git a/config/config.jsn b/config/config.jsn deleted file mode 100644 index 8e66be79e..000000000 --- a/config/config.jsn +++ /dev/null @@ -1,30 +0,0 @@ -{ - "OIDCIssuers": { - "https://accounts.google.com": { - "IssuerURL": "https://accounts.google.com", - "ClientID": "sigstore", - "Type": "email" - }, - "https://oauth2.sigstore.dev/auth": { - "IssuerURL": "https://oauth2.sigstore.dev/auth", - "ClientID": "sigstore", - "Type": "email" - }, - "http://dex-idp:8888/auth": { - "IssuerURL": "http://dex-idp:8888/auth", - "ClientID": "fulcio", - "IssuerClaim": "$.federated_claims.connector_id", - "Type": "email" - }, - "https://token.actions.githubusercontent.com": { - "IssuerURL": "https://token.actions.githubusercontent.com", - "ClientID": "sigstore", - "Type": "github-workflow" - }, - "https://oidc.codefresh.io": { - "IssuerURL": "https://oidc.codefresh.io", - "ClientID": "sigstore", - "Type": "codefresh-workflow" - } - } -} diff --git a/config/fulcio-config.yaml b/config/fulcio-config.yaml deleted file mode 100644 index 44a7107bb..000000000 --- a/config/fulcio-config.yaml +++ /dev/null @@ -1,116 +0,0 @@ -# -# 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. -apiVersion: v1 -data: - config.json: |- - { - "OIDCIssuers": { - "https://accounts.google.com": { - "IssuerURL": "https://accounts.google.com", - "ClientID": "sigstore", - "Type": "email" - }, - "https://agent.buildkite.com": { - "IssuerURL": "https://agent.buildkite.com", - "ClientID": "sigstore", - "Type": "buildkite-job" - }, - "https://allow.pub": { - "IssuerURL": "https://allow.pub", - "ClientID": "sigstore", - "Type": "spiffe", - "SPIFFETrustDomain": "allow.pub" - }, - "https://auth-staging.eclipse.org/realms/sigstore": { - "IssuerURL": "https://auth-staging.eclipse.org/realms/sigstore", - "ClientID": "sigstore", - "Type": "email" - }, - "https://auth.eclipse.org/auth/realms/sigstore": { - "IssuerURL": "https://auth.eclipse.org/auth/realms/sigstore", - "ClientID": "sigstore", - "Type": "email" - }, - "https://dev.gitlab.org": { - "IssuerURL": "https://dev.gitlab.org", - "ClientID": "sigstore", - "Type": "gitlab-pipeline" - }, - "https://gitlab.archlinux.org": { - "IssuerURL": "https://gitlab.archlinux.org", - "ClientID": "sigstore", - "Type": "gitlab-pipeline" - }, - "https://gitlab.com": { - "IssuerURL": "https://gitlab.com", - "ClientID": "sigstore", - "Type": "gitlab-pipeline" - }, - "https://oauth2.sigstore.dev/auth": { - "IssuerURL": "https://oauth2.sigstore.dev/auth", - "ClientID": "sigstore", - "Type": "email", - "IssuerClaim": "$.federated_claims.connector_id" - }, - "https://oidc.codefresh.io": { - "IssuerURL": "https://oidc.codefresh.io", - "ClientID": "sigstore", - "Type": "codefresh-workflow" - }, - "https://ops.gitlab.net": { - "IssuerURL": "https://ops.gitlab.net", - "ClientID": "sigstore", - "Type": "gitlab-pipeline" - }, - "https://token.actions.githubusercontent.com": { - "IssuerURL": "https://token.actions.githubusercontent.com", - "ClientID": "sigstore", - "Type": "github-workflow" - } - }, - "MetaIssuers": { - "https://*.oic.prod-aks.azure.com/*": { - "ClientID": "sigstore", - "Type": "kubernetes" - }, - "https://container.googleapis.com/v1/projects/*/locations/*/clusters/*": { - "ClientID": "sigstore", - "Type": "kubernetes" - }, - "https://oidc.eks.*.amazonaws.com/id/*": { - "ClientID": "sigstore", - "Type": "kubernetes" - }, - "https://oidc.prod-aks.azure.com/*": { - "ClientID": "sigstore", - "Type": "kubernetes" - }, - "https://token.actions.githubusercontent.com/*": { - "ClientID": "sigstore", - "Type": "github-workflow" - } - } - } - server.yaml: |- - host: 0.0.0.0 - port: 5555 - grpc-port: 5554 - ca: googleca - ct-log-url: http://ct-log/test - log_type: prod -kind: ConfigMap -metadata: - name: fulcio-config - namespace: fulcio-system diff --git a/config/identity/config.yaml b/config/identity/config.yaml new file mode 100644 index 000000000..1c7685cf6 --- /dev/null +++ b/config/identity/config.yaml @@ -0,0 +1,237 @@ +# Copyright 2024 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. + +define: + - &github-type "github-workflow" + - &gitlab-type "gitlab-pipeline" + - &codefresh-type "codefresh-workflow" + - &buildkite-type "buildkite-job" +oidc-issuers: + https://accounts.google.com: + issuer-url: https://accounts.google.com + client-id: sigstore + type: email + contact: tac@sigstore.dev + description: "Google OIDC auth" + https://agent.buildkite.com: + issuer-url: https://agent.buildkite.com + client-id: sigstore + type: ci-provider + ci-provider: *buildkite-type + contact: support@buildkite.com + description: "Buildkite Agent OIDC tokens for job identity" + https://allow.pub: + issuer-url: https://allow.pub + client-id: sigstore + type: spiffe + spiffe-trust-domain: allow.pub + contact: evan@phx.io + description: "Server side signing support for the OCI registry vcr.pub" + https://auth.eclipse.org/auth/realms/sigstore: + issuer-url: https://auth.eclipse.org/auth/realms/sigstore + client-id: sigstore + type: email + contact: security@eclipse-foundation.org + description: "Eclipse Foundation Production OIDC provider" + https://dev.gitlab.org: + issuer-url: https://dev.gitlab.org + client-id: sigstore + type: ci-provider + ci-provider: *gitlab-type + contact: distribution-be@gitlab.com + description: "GitLab OIDC tokens for job identity" + https://gitlab.archlinux.org: + issuer-url: https://gitlab.archlinux.org + client-id: sigstore + type: ci-provider + ci-provider: *gitlab-type + contact: sigstore@archlinux.org + description: "GitLab OIDC tokens for job identity" + https://gitlab.com: + issuer-url: https://gitlab.com + client-id: sigstore + type: ci-provider + ci-provider: *gitlab-type + contact: support@gitlab.com + description: "GitLab OIDC tokens for job identity" + https://issuer.enforce.dev: + issuer-url: https://issuer.enforce.dev + client-id: sigstore + type: chainguard-identity + contact: mattmoor@chainguard.dev + description: "Chainguard identity tokens" + https://issuer.hello.coop: + issuer-url: https://issuer.hello.coop + client-id: sigstore + type: email + contact: contact@hello.coop + description: "Hellō OIDC auth" + https://oauth2.sigstore.dev/auth: + issuer-url: https://oauth2.sigstore.dev/auth + client-id: sigstore + type: email + issuer-claim: $.federated_claims.connector_id + contact: tac@sigstore.dev + description: "dex address for fulcio" + https://oidc.codefresh.io: + issuer-url: https://oidc.codefresh.io + client-id: sigstore + type: ci-provider + ci-provider: *codefresh-type + contact: support@codefresh.io + description: "Codefresh OIDC tokens for job identity" + https://ops.gitlab.net: + issuer-url: https://ops.gitlab.net + client-id: sigstore + type: ci-provider + ci-provider: *gitlab-type + contact: distribution-be@gitlab.com + description: "GitLab OIDC tokens for job identity" + https://token.actions.githubusercontent.com: + issuer-url: https://token.actions.githubusercontent.com + client-id: sigstore + type: ci-provider + ci-provider: *github-type + contact: tac@sigstore.dev + description: "GitHub Actions OIDC auth" +meta-issuers: + https://*.oic.prod-aks.azure.com/*: + client-id: sigstore + type: kubernetes + https://container.googleapis.com/v1/projects/*/locations/*/clusters/*: + client-id: sigstore + type: kubernetes + https://oidc.eks.*.amazonaws.com/id/*: + client-id: sigstore + type: kubernetes + https://oidc.prod-aks.azure.com/*: + client-id: sigstore + type: kubernetes + https://token.actions.githubusercontent.com/*: + client-id: sigstore + type: ci-provider + ci-provider: *github-type +ci-issuer-metadata: + *github-type: + default-template-values: + # url: URL of issuer, https://github.com + url: "https://github.com" + extension-templates: + # event_name: Event that triggered this workflow run. E.g "push", "tag" + github-workflow-trigger: "event_name" + # sha: Commit SHA being built + github-workflow-sha: "sha" + # workflow (Deprecated): Name of workflow that is running (mutable) + github-workflow-name: "workflow" + # repository: Name of repository being built + github-workflow-repository: "repository" + # ref: Git ref being built + github-workflow-ref: "ref" + # job_workflow_ref: Specific build instructions (i.e. reusable workflow) + build-signer-uri: "{{ .url }}/{{ .job_workflow_ref }}" + # job_workflow_sha: Commit SHA to specific build instructions + build-signer-digest: "job_workflow_sha" + # runner_environment: Whether the build took place in cloud or self-hosted infrastructure + runner-environment: "runner_environment" + # repository: Name of repository being built + source-repository-uri: "{{ .url }}/{{ .repository }}" + source-repository-digest: "sha" + source-repository-ref: "ref" + # repository_id: ID to the source repo + source-repository-identifier: "repository_id" + # repository_owner: Owner of the source repo (mutable) + source-repository-owner-uri: "{{ .url }}/{{ .repository_owner }}" + # repository_owner_id: ID of the source repo + source-repository-owner-identifier: "repository_owner_id" + # workflow_ref: Ref of top-level workflow that is running + build-config-uri: "{{ .url }}/{{ .workflow_ref }}" + # workflow_sha: Commit SHA of top-level workflow that is running + build-config-digest: "workflow_sha" + build-trigger: "event_name" + # run_id: ID of workflow run + # run_attempt: Attempt number of workflow run + run-invocation-uri: "{{ .url }}/{{ .repository }}/actions/runs/{{ .run_id }}/attempts/{{ .run_attempt }}" + # repository_visibility: Visibility of the source repo + source-repository-visibility-at-signing: "repository_visibility" + subject-alternative-name-template: "{{ .url }}/{{ .job_workflow_ref }}" + *gitlab-type: + default-template-values: + url: "https://gitlab.com" + extension-templates: + # url: The URL of the GitLab instance. https://gitlab.com + # ci_config_ref_uri: Ref of top-level pipeline definition. + # E.g. gitlab.com/my-group/my-project//.gitlab-ci.yml@refs/heads/main + build-signer-uri: "https://{{ .ci_config_ref_uri }}" + # ci_config_sha: Commit sha of top-level pipeline definition, and is + # only populated when `ciConfigRefURI` is local to the GitLab instance + build-signer-digest: "ci_config_sha" + # runner_environment: The type of runner used by the job. May be one of gitlab-hosted or self-hosted. + runner-environment: "runner_environment" + # repository: Repository building built + source-repository-uri: "{{ .url }}/{{ .repository }}" + # sha: Commit SHA being built + source-repository-digest: "sha" + # ref_type: The type of the ref + # E.g. "branch", "tag" + # ref: Git ref being built + source-repository-ref: refs/{{if eq .ref_type "branch"}}heads/{{ else }}tags/{{end}}/{{ .ref }} + # project_id: ID to the source repo + source-repository-identifier: "project_id" + # namespace_path: Owner of the source repo (mutable) + source-repository-owner-uri: "{{ .url }}/{{ .namespace_path }}" + # namespace_id: ID of the source repo + source-repository-owner-identifier: "namespace_id" + build-config-uri: "https://{{ .ci_config_ref_uri }}" + build-config-digest: "ci_config_sha" + # pipeline_source: Event that triggered this workflow run. E.g "push", "tag" etc + build-trigger: "pipeline_source" + # project_path: Repository building built + # job_id: job ID + run-invocation-uri: "{{ .url }}/{{ .project_path }}/-/jobs/{{ .job_id }}" + # project_visibility: Visibility of the source project + source-repository-visibility-at-signing: "project_visibility" + subject-alternative-name-template: "https://{{ .ci_config_ref_uri }}" + *codefresh-type: + default-template-values: + # We are setting the default value for "platform_url" as the ci-provider + # principal gives priority to the claimed value over the default + # when they have the same name. Then it will use the default "platform_url" value + # for cases that the claimed data doesn't exist. + # platform_url: Codefresh platform url + platform_url: "https://g.codefresh.io" + extension-templates: + # workflow_id: The ID of the specific workflow authorized in the claim. + # For example, 64f447c02199f903000gh20. + build-signer-uri: "{{.platform_url}}/build/{{ .workflow_id }}" + # runner_environment: Whether the build took place in cloud or self-hosted infrastructure + runner-environment: "runner_environment" + # scm_repo_url: Applies to Git push, PR, and manual Git trigger types. + # The SCM URL specifying the Git repository’s location. + # For example, https://github.com/codefresh-user/oidc-test + source-repository-uri: "scm_repo_url" + # scm_ref: Applies to Git push, PR, and manual Git trigger types. + # The SCM name of the branch or tag within the Git repository + # for which the workflow should execute. For example, main or v1.0.0. + source-repository-ref: "scm_ref" + # pipeline_id: Codefresh Pipeline id + build-config-uri: "{{.platform_url}}/api/pipelines/{{ .pipeline_id }}" + # account_name: Codefresh account name + # pipeline_name: Codefresh pipline name (project/pipeline) + # account_id: Codefresh account id + run-invocation-uri: "{{.platform_url}}/build/{{ .workflow_id }}" + subject-alternative-name-template: "{{.platform_url}}/{{.account_name}}/{{.pipeline_name}}:{{.account_id}}/{{.pipeline_id}}" + *buildkite-type: + default-template-values: + url: "https://buildkite.com" + subject-alternative-name-template: "{{.url}}/{{.organization_slug}}/{{.pipeline_slug}}" diff --git a/docs/new-idp-requirements.md b/docs/new-idp-requirements.md index 007789f1e..37189c4a9 100644 --- a/docs/new-idp-requirements.md +++ b/docs/new-idp-requirements.md @@ -2,16 +2,41 @@ ## Summary -This document describes the minimum requirements for adding a new IDP (Identity Provider) to the Sigstore Public Good Deployment. +This document describes the minimum requirements for adding a new IDP (Identity Provider) to the Sigstore Public Good Instance. -Adding a new IDP option to Fulcio helps drive adoption of signing and verification for software artifacts using Sigstore Public Good. Because identity is a critical component of the system, it's important that new IDPs meet the minimum set of requirements to ensure the security and reliability of the ecosystem and users. +Adding a new IDP option to Fulcio helps drive adoption of signing and verification for software artifacts using Sigstore's Public Good Instance. Because identity is a critical component of the system, it's important that new IDPs meet the minimum set of requirements to ensure the security and reliability of the ecosystem and users. You should also reference the [Fulcio - ODIC.md](https://github.com/sigstore/fulcio/blob/main/docs/oidc.md) documentation for additional requirements for the type of IDP you're looking to integrate. The current two likely types of IDPs are: - `Email` - Email-based OIDC providers use the user's email or the machine identity for service accounts as the subject of the certificate. - `Workflow` - Workflow-based OIDC providers are used with systems such as CI/CD pipelines, such as GitHub Actions or GitLab CI. These providers will require more onboarding and you should [file an issue](https://github.com/sigstore/fulcio/issues) to discuss the requirements for a specific system. -## Requirements +## Onboarding Request + +Identity providers should [file an issue](https://github.com/sigstore/fulcio/issues) before creating a PR. Fulcio and Public Good Instance maintainers +will verify with the requester that the IDP meets the Technical and Security requirements outlined in this document. + +### Community Interest + +New identity providers must demonstrate that there is either a gap that will be filled by including this identity provider +(e.g. support for a new CI platform) or there is significant community interest. For any newer IDP, we would like to see +additional demand for it beyond the IDP maintainer. We recognize that this adds a barrier for smaller IDPs, but we want to +make sure that Sigstore's Public Good Instance is associated with high-quality, trusted providers. + +### Preference for Automated Signing Integrations + +As outlined in Sigstore's [roadmap](https://github.com/sigstore/community/blob/main/ROADMAP.md), Sigstore is focused +on simplifying signing workflows through the use of automated signing with workload identity, e.g. CI providers. Sigstore +will strongly prefer identity providers that support non-interactive signing. Additional scrutiny will be applied to +providers that only offer developer-based interactive signing. + +### Removal due to Inactivity + +If the IDP is found to be infrequently used (e.g. a certificate issued once every few months), Sigstore reserves the right +to remove the IDP from the Public Good Instance. We also request that you notify Sigstore maintainers if you will no longer +be maintaining the IDP so that it may be removed. + +## Technical and Security Requirements > The Sigstore Project reserves the right to remove your identity provider from the deployment if it is found to cause technical issues, does not meet the requirements outlined in this document, or if it is deemed to be a security risk to the system. diff --git a/docs/oid-info.md b/docs/oid-info.md index f171f0e92..1d85f272a 100644 --- a/docs/oid-info.md +++ b/docs/oid-info.md @@ -189,27 +189,27 @@ that Sigstore operates. ## Mapping OIDC token claims to Fulcio OIDs -| GitHub [(docs)][github-oidc-doc] | GitLab [(docs)](https://docs.gitlab.com/ee/ci/secrets/id_token_authentication.html#token-payload) | CircleCI | Buildkite | Codefresh [(docs)](https://codefresh.io/docs/docs/integrations/oidc-pipelines/) | Fulcio Certificate Extension | Why / Notes / Questions | -|--------------------|--------|----------|-----------|-----------|------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| aud | aud | aud | aud | aud | N/A | Only used to validate the JWT. | -| iss | iss | iss | iss | iss | Issuer | This already exists. For example: https://token.actions.githubusercontent.com | -| exp | exp | exp | exp | exp | N/A | Only used to validate the JWT. | -| nbf | nbf | nbf | nbf | nbf | N/A | Only used to validate the JWT. Optional, as per the OIDC spec | -| iat | iat | iat | iat | iat | N/A | Only used to validate the JWT. | -| server_url + job_workflow_ref | ci_config_ref_uri ([WIP][gitlab-wip-cliams]) | ?? | ?? | platform_url + /build/ + workflow_id | Build Signer URI | Reference to specific build instructions that are responsible for signing. Can be the same as Build Config URI. For example a reusable workflow in GitHub Actions or a Circle CI Orbs. | -| job_workflow_sha | ci_config_sha ([WIP][gitlab-wip-cliams]) | ?? | ?? | N/A | Build Signer Digest | An immutable reference to the specific version of the build instructions that is responsible for signing. Should include the digest type followed by the digest, e.g. `sha1:abc123`. | -| runner_environment | runner_environment | ?? | ?? | runner_environment | Runner Environment | For platforms to specify whether the build took place in platform-hosted cloud infrastructure or customer-hosted infrastructure. For example: `platform-hosted` and `self-hosted`. | -| server_url + repository | server_url + project_path | ?? | ?? | scm_repo_url | Source Repository URI | Should include a fully qualified repository URL. | -| sha | sha | ?? | build_commit | N/A | Source Repository Digest | An immutable reference to a specific version of the source code. Should include the digest type followed by the digest, e.g. `sha1:abc123`. | -| ref | ref | ?? | build_branch | scm_ref | Source Repository Ref | The source ref that the build run was based upon. For example: refs/head/main. | -| repository_id | project_id | ?? | ?? | N/A | Source Repository Identifier | Stable identifier for the owner of the source repository. | -| server_url + repository_owner | server_url + namespace_path | ?? | ?? | N/A | Source Repository Owner URI | Fully qualified URL for the owner of the source repository. | -| repository_owner_id | namespace_id | ?? | ?? | N/A | Source Repository Owner Identifier | Stable identifier for the owner of the source repository. | -| server_url + workflow_ref | ci_config_ref_uri ([WIP][gitlab-wip-cliams]) | ?? | ?? | platform_url + /api/pipelines/ + pipeline_id | Build Config URI | A reference to the initiating build instructions. | -| workflow_sha | ci_config_sha ([WIP][gitlab-wip-cliams]) | ?? | ?? | N/A | Build Config Digest | An immutable reference to the specific version of the top-level build instructions. Should include the digest type followed by the digest, e.g. `sha1:abc123`. | -| event_name | pipeline_source | ?? | ?? | N/A | Build Trigger | The event or action that triggered the build. | -| server_url + repository + "/actions/runs/" + run_id + "/attempts/" + run_attempt | server_url + project_path + /-/jobs/ + job_id | ?? | ?? | platform_url + /build/ + workflow_id | Run Invocation URI | An immutable identifier that can uniquely identify the build execution | -| repository_visibility | project_visibility | ?? | ?? | N/A | Source Repository Visibility At Signing | Source repository visibility at the time of signing the certificate | +| GitHub [(docs)][github-oidc-doc] | GitLab [(docs)](https://docs.gitlab.com/ee/ci/secrets/id_token_authentication.html#token-payload) | CircleCI | Buildkite | Codefresh [(docs)](https://codefresh.io/docs/docs/integrations/oidc-pipelines/) | Fulcio Certificate Extension | Why / Notes / Questions | +|----------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------|----------|--------------|---------------------------------------------------------------------------------|-----------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| aud | aud | aud | aud | aud | N/A | Only used to validate the JWT. | +| iss | iss | iss | iss | iss | Issuer | This already exists. For example: https://token.actions.githubusercontent.com | +| exp | exp | exp | exp | exp | N/A | Only used to validate the JWT. | +| nbf | nbf | nbf | nbf | nbf | N/A | Only used to validate the JWT. Optional, as per the OIDC spec | +| iat | iat | iat | iat | iat | N/A | Only used to validate the JWT. | +| server_url + job_workflow_ref | ci_config_ref_uri ([WIP][gitlab-wip-cliams]) | ?? | ?? | platform_url + /build/ + workflow_id | Build Signer URI | Reference to specific build instructions that are responsible for signing. Can be the same as Build Config URI. For example a reusable workflow in GitHub Actions or a Circle CI Orbs. | +| job_workflow_sha | ci_config_sha ([WIP][gitlab-wip-cliams]) | ?? | ?? | N/A | Build Signer Digest | An immutable reference to the specific version of the build instructions that is responsible for signing. May include the digest type followed by the digest, e.g. `sha1:abc123`. | +| runner_environment | runner_environment | ?? | ?? | runner_environment | Runner Environment | For platforms to specify whether the build took place in platform-hosted cloud infrastructure or customer-hosted infrastructure. For example: `platform-hosted` and `self-hosted`. | +| server_url + repository | server_url + project_path | ?? | ?? | scm_repo_url | Source Repository URI | Should include a fully qualified repository URL. | +| sha | sha | ?? | build_commit | N/A | Source Repository Digest | An immutable reference to a specific version of the source code. May include the digest type followed by the digest, e.g. `sha1:abc123`. | +| ref | ref | ?? | build_branch | scm_ref | Source Repository Ref | The source ref that the build run was based upon. For example: refs/head/main. | +| repository_id | project_id | ?? | ?? | N/A | Source Repository Identifier | Stable identifier for the owner of the source repository. | +| server_url + repository_owner | server_url + namespace_path | ?? | ?? | N/A | Source Repository Owner URI | Fully qualified URL for the owner of the source repository. | +| repository_owner_id | namespace_id | ?? | ?? | N/A | Source Repository Owner Identifier | Stable identifier for the owner of the source repository. | +| server_url + workflow_ref | ci_config_ref_uri ([WIP][gitlab-wip-cliams]) | ?? | ?? | platform_url + /api/pipelines/ + pipeline_id | Build Config URI | A reference to the initiating build instructions. | +| workflow_sha | ci_config_sha ([WIP][gitlab-wip-cliams]) | ?? | ?? | N/A | Build Config Digest | An immutable reference to the specific version of the top-level build instructions. May include the digest type followed by the digest, e.g. `sha1:abc123`. | +| event_name | pipeline_source | ?? | ?? | N/A | Build Trigger | The event or action that triggered the build. | +| server_url + repository + "/actions/runs/" + run_id + "/attempts/" + run_attempt | server_url + project_path + /-/jobs/ + job_id | ?? | ?? | platform_url + /build/ + workflow_id | Run Invocation URI | An immutable identifier that can uniquely identify the build execution | +| repository_visibility | project_visibility | ?? | ?? | N/A | Source Repository Visibility At Signing | Source repository visibility at the time of signing the certificate | [github-oidc-doc]: https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect#understanding-the-oidc-token [oid-link]: http://oid-info.com/get/1.3.6.1.4.1.57264 diff --git a/docs/oidc.md b/docs/oidc.md index d0907bfc9..61b354e44 100644 --- a/docs/oidc.md +++ b/docs/oidc.md @@ -10,15 +10,18 @@ Sigstore runs a federated OIDC identity provider, Dex. Users authenticate to the To add a new OIDC issuer: -* Add a file under the [`federation` folder](https://github.com/sigstore/fulcio/tree/main/federation) with the URL, new issuer type name, and contact ([example](https://github.com/sigstore/fulcio/blob/8975dfd/federation/agent.buildkite.com/config.yaml)) -* Add the new issuer to the [configuration](https://github.com/sigstore/fulcio/blob/main/config/fulcio-config.yaml) by running `go run federation/main.go` -* Add the new issuer to the [`identity` folder](https://github.com/sigstore/fulcio/tree/main/pkg/identity) ([example](https://github.com/sigstore/fulcio/tree/main/pkg/identity/buildkite)). You will define an `Issuer` type and a way to map the token to the certificate extensions. -* Define a constant with the issuer type name in the [configuration](https://github.com/sigstore/fulcio/blob/afeadb3b7d11f704489637cabc4e150dea3e00ed/pkg/config/config.go#L213-L221), add update the [tests](https://github.com/sigstore/fulcio/blob/afeadb3b7d11f704489637cabc4e150dea3e00ed/pkg/config/config_test.go#L473-L503) -* Map the issuer type to the token claim that will be signed over when requesting a token [here](https://github.com/sigstore/fulcio/blob/afeadb3b7d11f704489637cabc4e150dea3e00ed/pkg/config/config.go#L464-L486). You can likely just use `sub`. -* Add a case statement to map the issuer constant to the issuer type you created [here](https://github.com/sigstore/fulcio/blob/4d9d96a/pkg/server/issuer_pool.go#L40-L62) -* Update the end-to-end gRPC tests: - * Update the [configuration test](https://github.com/sigstore/fulcio/blob/572b7c8496c29a04721f608dd0307ba08773c60c/pkg/server/grpc_server_test.go#L175) - * Add a test for the new issuer ([example](https://github.com/sigstore/fulcio/blob/572b7c8496c29a04721f608dd0307ba08773c60c/pkg/server/grpc_server_test.go#L331)) +* Add the new issuer to the [configuration](https://github.com/sigstore/fulcio/blob/main/config/identity/config.yaml). + * Attention: If your issuer is for a CI provider, you should set the `type` as `ci-provider` and set the field `ci-provider` with the name of your provider. You should also fill the `ci-issuer-metadata` with the `default-template-values`, `extension-templates` and `subject-alternative-name-template`, following the pattern defined on the example ([example](tbd after migrating the github to ci-provider)). + * Important notes: The `extension-templates` and the `subject-alternative-name-template` follows the templates [pattern](https://pkg.go.dev/text/template). The name used to fill the `ci-provider` field has to be the same used as key for `ci-issuer-metadata`, we suggest to use a variable for this. If you set a `default-template-value` with the same name of a claim key, the claimed value will have priority over the default one. +* If your issuer is not for a CI provider, you need to follow the next steps: + * Add the new issuer to the [`identity` folder](https://github.com/sigstore/fulcio/tree/main/pkg/identity) ([example](https://github.com/sigstore/fulcio/tree/main/pkg/identity/email)). You will define an `Issuer` type and a way to map the token to the certificate extensions. + * Define a constant with the issuer type name in the [configuration](https://github.com/sigstore/fulcio/blob/afeadb3b7d11f704489637cabc4e150dea3e00ed/pkg/config/config.go#L213-L221), add update the [tests](https://github.com/sigstore/fulcio/blob/afeadb3b7d11f704489637cabc4e150dea3e00ed/pkg/config/config_test.go#L473-L503) + * Map the issuer type to the token claim that will be signed over when requesting a token [here](https://github.com/sigstore/fulcio/blob/afeadb3b7d11f704489637cabc4e150dea3e00ed/pkg/config/config.go#L464-L486). You can likely just use `sub`. + * Add a case statement to map the issuer constant to the issuer type you created [here](https://github.com/sigstore/fulcio/blob/4d9d96a/pkg/server/issuer_pool.go#L40-L62) +* These next steps are required only for non-ci issuers, as it is already tested for generically. Although, you are welcome to add tests for your provider if you want to. + * Update the end-to-end gRPC tests: + * Update the [configuration test](https://github.com/sigstore/fulcio/blob/572b7c8496c29a04721f608dd0307ba08773c60c/pkg/server/grpc_server_test.go#L175) + * Add a test for the new issuer ([example](https://github.com/sigstore/fulcio/blob/572b7c8496c29a04721f608dd0307ba08773c60c/pkg/server/grpc_server_test.go#L331)) See [this example](https://github.com/sigstore/fulcio/pull/890), although it is out of date as you'll now need to create an issuer type. diff --git a/federation/README.md b/federation/README.md deleted file mode 100644 index 3d9e575cd..000000000 --- a/federation/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# OIDC Federation Configs - -This directory contains configurations for individual OIDC endpoints that the public good instance of Fulcio should accept identity tokens from. - -## Usage - -To update the k8s `ConfigMap`, run `go run federation/main.go` from the root directory of this repository. - -## Adding New Entries - -We'll happily accept new entries here in the form of a pull request! -Open one up with your endpoint, filling in a directory and a `config.yaml` with the following structure: - -```yaml -url: -contact: -description: -type: -``` - -You'll then have to regenerate the ConfigMap with `go run federation/main.go`, and then send your PR. - -We'll discuss your use-case with you over the pull request, and merge! diff --git a/federation/accounts.google.com/config.yaml b/federation/accounts.google.com/config.yaml deleted file mode 100644 index b21c89a31..000000000 --- a/federation/accounts.google.com/config.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# 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. - -url: https://accounts.google.com -contact: tac@sigstore.dev -description: "Google OIDC auth" -type: "email" diff --git a/federation/agent.buildkite.com/config.yaml b/federation/agent.buildkite.com/config.yaml deleted file mode 100644 index bc1d46425..000000000 --- a/federation/agent.buildkite.com/config.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright 2023 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. - -url: https://agent.buildkite.com -contact: support@buildkite.com -description: "Buildkite Agent OIDC tokens for job identity" -type: "buildkite-job" diff --git a/federation/auth-staging.eclipse.org/config.yaml b/federation/auth-staging.eclipse.org/config.yaml deleted file mode 100644 index 11c0f91cb..000000000 --- a/federation/auth-staging.eclipse.org/config.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright 2023 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. - -url: https://auth-staging.eclipse.org/realms/sigstore -contact: security@eclipse-foundation.org -description: "Eclipse Foundation Staging OIDC provider" -type: "email" diff --git a/federation/auth.eclipse.org/config.yaml b/federation/auth.eclipse.org/config.yaml deleted file mode 100644 index be7a4b2d5..000000000 --- a/federation/auth.eclipse.org/config.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright 2023 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. - -url: https://auth.eclipse.org/auth/realms/sigstore -contact: security@eclipse-foundation.org -description: "Eclipse Foundation Production OIDC provider" -type: "email" diff --git a/federation/dev.gitlab.org/config.yaml b/federation/dev.gitlab.org/config.yaml deleted file mode 100644 index 1fe70bccc..000000000 --- a/federation/dev.gitlab.org/config.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright 2023 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. - -url: https://dev.gitlab.org -contact: distribution-be@gitlab.com -description: "GitLab OIDC tokens for job identity" -type: "gitlab-pipeline" diff --git a/federation/external/allow.pub/config.yaml b/federation/external/allow.pub/config.yaml deleted file mode 100644 index 69b164896..000000000 --- a/federation/external/allow.pub/config.yaml +++ /dev/null @@ -1,19 +0,0 @@ -# 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. - -url: https://allow.pub -contact: evan@phx.io -description: "Server side signing support for the OCI registry vcr.pub" -type: "spiffe" -spiffetrustdomain: "allow.pub" diff --git a/federation/gitlab.archlinux.org/config.yaml b/federation/gitlab.archlinux.org/config.yaml deleted file mode 100644 index e7796b0b0..000000000 --- a/federation/gitlab.archlinux.org/config.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright 2023 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. - -url: https://gitlab.archlinux.org -contact: sigstore@archlinux.org -description: "GitLab OIDC tokens for job identity" -type: "gitlab-pipeline" diff --git a/federation/gitlab.com/config.yaml b/federation/gitlab.com/config.yaml deleted file mode 100644 index 8fb05c85b..000000000 --- a/federation/gitlab.com/config.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright 2023 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. - -url: https://gitlab.com -contact: support@gitlab.com -description: "GitLab OIDC tokens for job identity" -type: "gitlab-pipeline" diff --git a/federation/main.go b/federation/main.go deleted file mode 100644 index 7926f772a..000000000 --- a/federation/main.go +++ /dev/null @@ -1,140 +0,0 @@ -// 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 main - -import ( - "encoding/json" - "os" - "path/filepath" - - "github.com/sigstore/fulcio/pkg/config" - "gopkg.in/yaml.v3" -) - -var rootPaths = []string{"federation", "federation/external"} -var boilerPlate = `# -# 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. -` - -type federationConfig struct { - URL string - Type string - IssuerClaim string - SpiffeTrustDomain string -} - -func main() { - matches := []string{} - for _, rp := range rootPaths { - glob := filepath.Join(rp, "*/config.yaml") - globs, err := filepath.Glob(glob) - if err != nil { - panic(err) - } - matches = append(matches, globs...) - } - fulcioConfig := &config.FulcioConfig{ - OIDCIssuers: map[string]config.OIDCIssuer{}, - MetaIssuers: map[string]config.OIDCIssuer{ - // EKS Cluster OIDC issuers - "https://oidc.eks.*.amazonaws.com/id/*": { - ClientID: "sigstore", - Type: "kubernetes", - }, - // GKE Cluster OIDC issuers - "https://container.googleapis.com/v1/projects/*/locations/*/clusters/*": { - ClientID: "sigstore", - Type: "kubernetes", - }, - // AKS Cluster OIDC issuers - "https://oidc.prod-aks.azure.com/*": { - ClientID: "sigstore", - Type: "kubernetes", - }, - "https://*.oic.prod-aks.azure.com/*": { - ClientID: "sigstore", - Type: "kubernetes", - }, - // GitHub Actions OIDC unique enterprise issuers - "https://token.actions.githubusercontent.com/*": { - ClientID: "sigstore", - Type: "github-workflow", - }, - }, - } - for _, m := range matches { - b, err := os.ReadFile(m) - if err != nil { - panic(err) - } - cfg := federationConfig{} - if err := yaml.Unmarshal(b, &cfg); err != nil { - panic(err) - } - - fulcioCfg := config.OIDCIssuer{ - IssuerURL: cfg.URL, - ClientID: "sigstore", - Type: config.IssuerType(cfg.Type), - IssuerClaim: cfg.IssuerClaim, - } - if fulcioCfg.Type == config.IssuerTypeSpiffe { - fulcioCfg.SPIFFETrustDomain = cfg.SpiffeTrustDomain - } - fulcioConfig.OIDCIssuers[cfg.URL] = fulcioCfg - } - - m, err := json.MarshalIndent(fulcioConfig, "", " ") - if err != nil { - panic(err) - } - - // Update the yaml - yb, err := os.ReadFile("config/fulcio-config.yaml") - if err != nil { - panic(err) - } - - cm := map[string]interface{}{} - if err := yaml.Unmarshal(yb, &cm); err != nil { - panic(err) - } - data := cm["data"].(map[string]interface{}) - data["config.json"] = string(m) - - newYaml, err := yaml.Marshal(cm) - if err != nil { - panic(err) - } - - yamlWithBoilerplate := boilerPlate + string(newYaml) - - if err := os.WriteFile("config/fulcio-config.yaml", []byte(yamlWithBoilerplate), 0600); err != nil { - panic(err) - } -} diff --git a/federation/oauth2.sigstore.dev/config.yaml b/federation/oauth2.sigstore.dev/config.yaml deleted file mode 100644 index a5782a26c..000000000 --- a/federation/oauth2.sigstore.dev/config.yaml +++ /dev/null @@ -1,19 +0,0 @@ -# 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. - -url: https://oauth2.sigstore.dev/auth -issuerclaim: $.federated_claims.connector_id -contact: tac@sigstore.dev -description: "dex address for fulcio" -type: "email" diff --git a/federation/oidc.codefresh.io/config.yaml b/federation/oidc.codefresh.io/config.yaml deleted file mode 100644 index 8d51a8adb..000000000 --- a/federation/oidc.codefresh.io/config.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright 2023 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. - -url: https://oidc.codefresh.io -contact: support@codefresh.io -description: "Codefresh OIDC tokens for job identity" -type: "codefresh-workflow" diff --git a/federation/ops.gitlab.net/config.yaml b/federation/ops.gitlab.net/config.yaml deleted file mode 100644 index 7984c576f..000000000 --- a/federation/ops.gitlab.net/config.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright 2023 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. - -url: https://ops.gitlab.net -contact: distribution-be@gitlab.com -description: "GitLab OIDC tokens for job identity" -type: "gitlab-pipeline" diff --git a/federation/token.actions.githubusercontent.com/config.yaml b/federation/token.actions.githubusercontent.com/config.yaml deleted file mode 100644 index a8208db01..000000000 --- a/federation/token.actions.githubusercontent.com/config.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# 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. - -url: https://token.actions.githubusercontent.com -contact: tac@sigstore.dev -description: "GitHub Actions OIDC auth" -type: "github-workflow" diff --git a/go.mod b/go.mod index 4a7ed11ec..f3a67de3b 100644 --- a/go.mod +++ b/go.mod @@ -1,19 +1,19 @@ module github.com/sigstore/fulcio -go 1.21.2 +go 1.23.0 -toolchain go1.21.12 - -// toolchain go1.21.3 +toolchain go1.23.1 require ( chainguard.dev/go-grpc-kit v0.17.5 - cloud.google.com/go/security v1.17.0 + chainguard.dev/sdk v0.1.24 + cloud.google.com/go/security v1.17.4 github.com/PaesslerAG/jsonpath v0.1.1 github.com/ThalesIgnite/crypto11 v1.2.5 github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d - github.com/coreos/go-oidc/v3 v3.10.0 + github.com/coreos/go-oidc/v3 v3.11.0 github.com/fsnotify/fsnotify v1.7.0 + github.com/go-jose/go-jose/v4 v4.0.4 github.com/goadesign/goa v2.2.5+incompatible github.com/golang/protobuf v1.5.4 github.com/google/certificate-transparency-go v1.1.8 @@ -21,14 +21,14 @@ require ( github.com/google/tink/go v1.7.0 github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20210315223345-82c243799c99 - github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 + github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 github.com/hashicorp/golang-lru v1.0.2 github.com/magiconair/properties v1.8.7 - github.com/prometheus/client_golang v1.19.1 + github.com/prometheus/client_golang v1.20.2 github.com/prometheus/client_model v0.6.1 - github.com/prometheus/common v0.54.0 + github.com/prometheus/common v0.55.0 github.com/rs/cors v1.11.0 - github.com/sigstore/sigstore v1.8.4 + github.com/sigstore/sigstore v1.8.8 github.com/sigstore/sigstore/pkg/signature/kms/aws v1.8.4 github.com/sigstore/sigstore/pkg/signature/kms/azure v1.8.4 github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.8.4 @@ -39,23 +39,22 @@ require ( github.com/spiffe/go-spiffe/v2 v2.1.7 go.step.sm/crypto v0.44.2 go.uber.org/zap v1.27.0 - google.golang.org/api v0.181.0 - google.golang.org/genproto/googleapis/api v0.0.0-20240520151616-dc85e6b867a5 - google.golang.org/grpc v1.64.0 + google.golang.org/api v0.194.0 + google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd + google.golang.org/grpc v1.66.0 google.golang.org/protobuf v1.34.2 - gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/yaml.v3 v3.0.1 sigs.k8s.io/release-utils v0.7.7 ) require ( - cloud.google.com/go v0.113.0 // indirect - cloud.google.com/go/auth v0.4.1 // indirect - cloud.google.com/go/auth/oauth2adapt v0.2.2 // indirect - cloud.google.com/go/compute/metadata v0.3.0 // indirect - cloud.google.com/go/iam v1.1.8 // indirect - cloud.google.com/go/kms v1.17.1 // indirect - cloud.google.com/go/longrunning v0.5.7 // indirect + cloud.google.com/go v0.115.1 // indirect + cloud.google.com/go/auth v0.9.1 // indirect + cloud.google.com/go/auth/oauth2adapt v0.2.4 // indirect + cloud.google.com/go/compute/metadata v0.5.0 // indirect + cloud.google.com/go/iam v1.1.12 // indirect + cloud.google.com/go/kms v1.18.4 // indirect + cloud.google.com/go/longrunning v0.5.11 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.2 // indirect @@ -65,38 +64,37 @@ require ( github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect github.com/PaesslerAG/gval v1.0.0 // indirect github.com/aws/aws-sdk-go v1.53.10 // indirect - github.com/aws/aws-sdk-go-v2 v1.27.0 // indirect - github.com/aws/aws-sdk-go-v2/config v1.27.16 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.17.16 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.3 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.7 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.7 // indirect + github.com/aws/aws-sdk-go-v2 v1.30.4 // indirect + github.com/aws/aws-sdk-go-v2/config v1.27.18 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.17.18 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.5 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.9 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.9 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.9 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.11 // indirect github.com/aws/aws-sdk-go-v2/service/kms v1.32.1 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.20.9 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.24.3 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.28.10 // indirect - github.com/aws/smithy-go v1.20.2 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.20.11 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.24.5 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.28.12 // indirect + github.com/aws/smithy-go v1.20.4 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cenkalti/backoff/v3 v3.2.2 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/chainguard-dev/slogctx v1.2.2 // indirect github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/go-jose/go-jose/v3 v3.0.3 // indirect - github.com/go-jose/go-jose/v4 v4.0.1 // indirect - github.com/go-logr/logr v1.4.1 // indirect + github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/golang-jwt/jwt/v5 v5.2.1 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/google/go-containerregistry v0.19.1 // indirect - github.com/google/s2a-go v0.1.7 // indirect + github.com/google/go-containerregistry v0.20.1 // indirect + github.com/google/s2a-go v0.1.8 // indirect github.com/google/uuid v1.6.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect - github.com/googleapis/gax-go/v2 v2.12.4 // indirect + github.com/googleapis/gax-go/v2 v2.13.0 // 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 @@ -110,16 +108,18 @@ require ( github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jellydator/ttlcache/v3 v3.2.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect + github.com/klauspost/compress v1.17.9 // indirect github.com/kylelemons/godebug v1.1.0 // indirect - github.com/letsencrypt/boulder v0.0.0-20230907030200-6d76a0f91e1e // indirect + github.com/letsencrypt/boulder v0.0.0-20240620165639-de9c06129bec // indirect github.com/miekg/pkcs11 v1.1.1 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/pelletier/go-toml/v2 v2.1.0 // indirect github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/prometheus/procfs v0.12.0 // indirect + github.com/prometheus/procfs v0.15.1 // indirect github.com/ryanuber/go-glob v1.0.0 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect @@ -133,29 +133,28 @@ require ( github.com/thales-e-security/pool v0.0.2 // indirect github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.52.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect - go.opentelemetry.io/otel v1.27.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect + go.opentelemetry.io/otel v1.29.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.27.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 // indirect - go.opentelemetry.io/otel/metric v1.27.0 // indirect + go.opentelemetry.io/otel/metric v1.29.0 // indirect go.opentelemetry.io/otel/sdk v1.27.0 // indirect - go.opentelemetry.io/otel/trace v1.27.0 // indirect + go.opentelemetry.io/otel/trace v1.29.0 // indirect go.opentelemetry.io/proto/otlp v1.2.0 // indirect go.uber.org/multierr v1.11.0 // indirect goa.design/goa v2.2.5+incompatible // indirect - golang.org/x/crypto v0.23.0 // indirect - golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect - golang.org/x/net v0.25.0 // indirect - golang.org/x/oauth2 v0.20.0 // indirect - golang.org/x/sync v0.7.0 // indirect - golang.org/x/sys v0.20.0 // indirect - golang.org/x/term v0.20.0 // indirect - golang.org/x/text v0.15.0 // indirect - golang.org/x/time v0.5.0 // indirect - google.golang.org/genproto v0.0.0-20240401170217-c3f982113cda // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240520151616-dc85e6b867a5 // indirect - gopkg.in/go-jose/go-jose.v2 v2.6.3 // indirect + golang.org/x/crypto v0.26.0 // indirect + golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa // indirect + golang.org/x/net v0.28.0 // indirect + golang.org/x/oauth2 v0.22.0 // indirect + golang.org/x/sync v0.8.0 // indirect + golang.org/x/sys v0.24.0 // indirect + golang.org/x/term v0.23.0 // indirect + golang.org/x/text v0.17.0 // indirect + golang.org/x/time v0.6.0 // indirect + google.golang.org/genproto v0.0.0-20240814211410-ddb44dafa142 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd // indirect gopkg.in/ini.v1 v1.67.0 // indirect k8s.io/klog/v2 v2.120.1 // indirect ) diff --git a/go.sum b/go.sum index 97205a680..edf71c141 100644 --- a/go.sum +++ b/go.sum @@ -1,22 +1,24 @@ chainguard.dev/go-grpc-kit v0.17.5 h1:y0MHgqm3v0LKKQfxPJV57wkXxa8uMSpNTjhtHbNh1DY= chainguard.dev/go-grpc-kit v0.17.5/go.mod h1:vQGcwZiX6jXwhyLPCZwVMvjITD+XcrSmQzuCTW/XcVc= +chainguard.dev/sdk v0.1.24 h1:J+AdvW5obfSZlrBIlgfOttS0VU7m2yLQpI3KCCtjUr4= +chainguard.dev/sdk v0.1.24/go.mod h1:LJYP/iD6G9Rfz/9G8koKxxvM36ofaFfv/pYus0W+X98= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.113.0 h1:g3C70mn3lWfckKBiCVsAshabrDg01pQ0pnX1MNtnMkA= -cloud.google.com/go v0.113.0/go.mod h1:glEqlogERKYeePz6ZdkcLJ28Q2I6aERgDDErBg9GzO8= -cloud.google.com/go/auth v0.4.1 h1:Z7YNIhlWRtrnKlZke7z3GMqzvuYzdc2z98F9D1NV5Hg= -cloud.google.com/go/auth v0.4.1/go.mod h1:QVBuVEKpCn4Zp58hzRGvL0tjRGU0YqdRTdCHM1IHnro= -cloud.google.com/go/auth/oauth2adapt v0.2.2 h1:+TTV8aXpjeChS9M+aTtN/TjdQnzJvmzKFt//oWu7HX4= -cloud.google.com/go/auth/oauth2adapt v0.2.2/go.mod h1:wcYjgpZI9+Yu7LyYBg4pqSiaRkfEK3GQcpb7C/uyF1Q= -cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= -cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= -cloud.google.com/go/iam v1.1.8 h1:r7umDwhj+BQyz0ScZMp4QrGXjSTI3ZINnpgU2nlB/K0= -cloud.google.com/go/iam v1.1.8/go.mod h1:GvE6lyMmfxXauzNq8NbgJbeVQNspG+tcdL/W8QO1+zE= -cloud.google.com/go/kms v1.17.1 h1:5k0wXqkxL+YcXd4viQzTqCgzzVKKxzgrK+rCZJytEQs= -cloud.google.com/go/kms v1.17.1/go.mod h1:DCMnCF/apA6fZk5Cj4XsD979OyHAqFasPuA5Sd0kGlQ= -cloud.google.com/go/longrunning v0.5.7 h1:WLbHekDbjK1fVFD3ibpFFVoyizlLRl73I7YKuAKilhU= -cloud.google.com/go/longrunning v0.5.7/go.mod h1:8GClkudohy1Fxm3owmBGid8W0pSgodEMwEAztp38Xng= -cloud.google.com/go/security v1.17.0 h1:u4RCnEQPvlrrnFRFinU0T3WsjtrsQErkWBfqTM5oUQI= -cloud.google.com/go/security v1.17.0/go.mod h1:eSuFs0SlBv1gWg7gHIoF0hYOvcSwJCek/GFXtgO6aA0= +cloud.google.com/go v0.115.1 h1:Jo0SM9cQnSkYfp44+v+NQXHpcHqlnRJk2qxh6yvxxxQ= +cloud.google.com/go v0.115.1/go.mod h1:DuujITeaufu3gL68/lOFIirVNJwQeyf5UXyi+Wbgknc= +cloud.google.com/go/auth v0.9.1 h1:+pMtLEV2k0AXKvs/tGZojuj6QaioxfUjOpMsG5Gtx+w= +cloud.google.com/go/auth v0.9.1/go.mod h1:Sw8ocT5mhhXxFklyhT12Eiy0ed6tTrPMCJjSI8KhYLk= +cloud.google.com/go/auth/oauth2adapt v0.2.4 h1:0GWE/FUsXhf6C+jAkWgYm7X9tK8cuEIfy19DBn6B6bY= +cloud.google.com/go/auth/oauth2adapt v0.2.4/go.mod h1:jC/jOpwFP6JBxhB3P5Rr0a9HLMC/Pe3eaL4NmdvqPtc= +cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY= +cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY= +cloud.google.com/go/iam v1.1.12 h1:JixGLimRrNGcxvJEQ8+clfLxPlbeZA6MuRJ+qJNQ5Xw= +cloud.google.com/go/iam v1.1.12/go.mod h1:9LDX8J7dN5YRyzVHxwQzrQs9opFFqn0Mxs9nAeB+Hhg= +cloud.google.com/go/kms v1.18.4 h1:dYN3OCsQ6wJLLtOnI8DGUwQ5shMusXsWCCC+s09ATsk= +cloud.google.com/go/kms v1.18.4/go.mod h1:SG1bgQ3UWW6/KdPo9uuJnzELXY5YTTMJtDYvajiQ22g= +cloud.google.com/go/longrunning v0.5.11 h1:Havn1kGjz3whCfoD8dxMLP73Ph5w+ODyZB9RUsDxtGk= +cloud.google.com/go/longrunning v0.5.11/go.mod h1:rDn7//lmlfWV1Dx6IB4RatCPenTwwmqXuiP0/RgoEO4= +cloud.google.com/go/security v1.17.4 h1:ERhxAa02mnMEIIAXvzje+qJ+yWniP6l5uOX+k9ELCaA= +cloud.google.com/go/security v1.17.4/go.mod h1:KMuDJH+sEB3KTODd/tLJ7kZK+u2PQt+Cfu0oAxzIhgo= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1 h1:E+OJmp2tPvt1W+amx48v1eqbjDYsgN+RzP4q16yV5eM= @@ -44,34 +46,34 @@ github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/aws/aws-sdk-go v1.53.10 h1:3enP5l5WtezT9Ql+XZqs56JBf5YUd/FEzTCg///OIGY= github.com/aws/aws-sdk-go v1.53.10/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= -github.com/aws/aws-sdk-go-v2 v1.27.0 h1:7bZWKoXhzI+mMR/HjdMx8ZCC5+6fY0lS5tr0bbgiLlo= -github.com/aws/aws-sdk-go-v2 v1.27.0/go.mod h1:ffIFB97e2yNsv4aTSGkqtHnppsIJzw7G7BReUZ3jCXM= -github.com/aws/aws-sdk-go-v2/config v1.27.16 h1:knpCuH7laFVGYTNd99Ns5t+8PuRjDn4HnnZK48csipM= -github.com/aws/aws-sdk-go-v2/config v1.27.16/go.mod h1:vutqgRhDUktwSge3hrC3nkuirzkJ4E/mLj5GvI0BQas= -github.com/aws/aws-sdk-go-v2/credentials v1.17.16 h1:7d2QxY83uYl0l58ceyiSpxg9bSbStqBC6BeEeHEchwo= -github.com/aws/aws-sdk-go-v2/credentials v1.17.16/go.mod h1:Ae6li/6Yc6eMzysRL2BXlPYvnrLLBg3D11/AmOjw50k= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.3 h1:dQLK4TjtnlRGb0czOht2CevZ5l6RSyRWAnKeGd7VAFE= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.3/go.mod h1:TL79f2P6+8Q7dTsILpiVST+AL9lkF6PPGI167Ny0Cjw= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.7 h1:lf/8VTF2cM+N4SLzaYJERKEWAXq8MOMpZfU6wEPWsPk= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.7/go.mod h1:4SjkU7QiqK2M9oozyMzfZ/23LmUY+h3oFqhdeP5OMiI= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.7 h1:4OYVp0705xu8yjdyoWix0r9wPIRXnIzzOoUpQVHIJ/g= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.7/go.mod h1:vd7ESTEvI76T2Na050gODNmNU7+OyKrIKroYTu4ABiI= +github.com/aws/aws-sdk-go-v2 v1.30.4 h1:frhcagrVNrzmT95RJImMHgabt99vkXGslubDaDagTk8= +github.com/aws/aws-sdk-go-v2 v1.30.4/go.mod h1:CT+ZPWXbYrci8chcARI3OmI/qgd+f6WtuLOoaIA8PR0= +github.com/aws/aws-sdk-go-v2/config v1.27.18 h1:wFvAnwOKKe7QAyIxziwSKjmer9JBMH1vzIL6W+fYuKk= +github.com/aws/aws-sdk-go-v2/config v1.27.18/go.mod h1:0xz6cgdX55+kmppvPm2IaKzIXOheGJhAufacPJaXZ7c= +github.com/aws/aws-sdk-go-v2/credentials v1.17.18 h1:D/ALDWqK4JdY3OFgA2thcPO1c9aYTT5STS/CvnkqY1c= +github.com/aws/aws-sdk-go-v2/credentials v1.17.18/go.mod h1:JuitCWq+F5QGUrmMPsk945rop6bB57jdscu+Glozdnc= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.5 h1:dDgptDO9dxeFkXy+tEgVkzSClHZje/6JkPW5aZyEvrQ= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.5/go.mod h1:gjvE2KBUgUQhcv89jqxrIxH9GaKs1JbZzWejj/DaHGA= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.9 h1:cy8ahBJuhtM8GTTSyOkfy6WVPV1IE+SS5/wfXUYuulw= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.9/go.mod h1:CZBXGLaJnEZI6EVNcPd7a6B5IC5cA/GkRWtu9fp3S6Y= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.9 h1:A4SYk07ef04+vxZToz9LWvAXl9LW0NClpPpMsi31cz0= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.9/go.mod h1:5jJcHuwDagxN+ErjQ3PU3ocf6Ylc/p9x+BLO/+X4iXw= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 h1:Ji0DY1xUsUr3I8cHps0G+XM3WWU16lP6yG8qu1GAZAs= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2/go.mod h1:5CsjAbs3NlGQyZNFACh+zztPDI7fU6eW9QsxjfnuBKg= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.9 h1:Wx0rlZoEJR7JwlSZcHnEa7CNjrSIyVxMFWGAaXy4fJY= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.9/go.mod h1:aVMHdE0aHO3v+f/iw01fmXV/5DbfQ3Bi9nN7nd9bE9Y= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.11 h1:o4T+fKxA3gTMcluBNZZXE9DNaMkJuUL1O3mffCUjoJo= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.11/go.mod h1:84oZdJ+VjuJKs9v1UTC9NaodRZRseOXCTgku+vQJWR8= github.com/aws/aws-sdk-go-v2/service/kms v1.32.1 h1:FARrQLRQXpCFYylIUVF1dRij6YbPCmtwudq9NBk4kFc= github.com/aws/aws-sdk-go-v2/service/kms v1.32.1/go.mod h1:8lETO9lelSG2B6KMXFh2OwPPqGV6WQM3RqLAEjP1xaU= -github.com/aws/aws-sdk-go-v2/service/sso v1.20.9 h1:aD7AGQhvPuAxlSUfo0CWU7s6FpkbyykMhGYMvlqTjVs= -github.com/aws/aws-sdk-go-v2/service/sso v1.20.9/go.mod h1:c1qtZUWtygI6ZdvKppzCSXsDOq5I4luJPZ0Ud3juFCA= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.24.3 h1:Pav5q3cA260Zqez42T9UhIlsd9QeypszRPwC9LdSSsQ= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.24.3/go.mod h1:9lmoVDVLz/yUZwLaQ676TK02fhCu4+PgRSmMaKR1ozk= -github.com/aws/aws-sdk-go-v2/service/sts v1.28.10 h1:69tpbPED7jKPyzMcrwSvhWcJ9bPnZsZs18NT40JwM0g= -github.com/aws/aws-sdk-go-v2/service/sts v1.28.10/go.mod h1:0Aqn1MnEuitqfsCNyKsdKLhDUOr4txD/g19EfiUqgws= -github.com/aws/smithy-go v1.20.2 h1:tbp628ireGtzcHDDmLT/6ADHidqnwgF57XOXZe6tp4Q= -github.com/aws/smithy-go v1.20.2/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E= +github.com/aws/aws-sdk-go-v2/service/sso v1.20.11 h1:gEYM2GSpr4YNWc6hCd5nod4+d4kd9vWIAWrmGuLdlMw= +github.com/aws/aws-sdk-go-v2/service/sso v1.20.11/go.mod h1:gVvwPdPNYehHSP9Rs7q27U1EU+3Or2ZpXvzAYJNh63w= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.24.5 h1:iXjh3uaH3vsVcnyZX7MqCoCfcyxIrVE9iOQruRaWPrQ= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.24.5/go.mod h1:5ZXesEuy/QcO0WUnt+4sDkxhdXRHTu2yG0uCSH8B6os= +github.com/aws/aws-sdk-go-v2/service/sts v1.28.12 h1:M/1u4HBpwLuMtjlxuI2y6HoVLzF5e2mfxHCg7ZVMYmk= +github.com/aws/aws-sdk-go-v2/service/sts v1.28.12/go.mod h1:kcfd+eTdEi/40FIbLq4Hif3XMXnl5b/+t/KTfLt9xIk= +github.com/aws/smithy-go v1.20.4 h1:2HK1zBdPgRbjFOHlfeQZfpC4r72MOb9bZkiFwggKO+4= +github.com/aws/smithy-go v1.20.4/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -82,16 +84,16 @@ github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4r github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chainguard-dev/slogctx v1.2.2 h1:aDfTjasw/ApX0By8Nicl0C02oV/bXzBD8Dh7AG014ZM= github.com/chainguard-dev/slogctx v1.2.2/go.mod h1:+/TwogApSQPC+Umn9LF/T6my0KDml1XDAgpuSN/nwU4= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be h1:J5BL2kskAlV9ckgEsNQXscjIaLiOYiZ75d4e94E6dcQ= github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be/go.mod h1:mk5IQ+Y0ZeO87b858TlA645sVcEcbiX6YqP98kt+7+w= -github.com/coreos/go-oidc/v3 v3.10.0 h1:tDnXHnLyiTVyT/2zLDGj09pFPkhND8Gl8lnTRhoEaJU= -github.com/coreos/go-oidc/v3 v3.10.0/go.mod h1:5j11xcw0D3+SGxn6Z/WFADsgcWVMyNAlSQupk0KK3ac= +github.com/coreos/go-oidc/v3 v3.11.0 h1:Ia3MxdwpSw702YW0xgfmP1GVCMA9aEFWu12XUZ3/OtI= +github.com/coreos/go-oidc/v3 v3.11.0/go.mod h1:gE3LgjOgFoHi9a4ce4/tJczr0Ai2/BoDhf0r5lltWI0= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= 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= @@ -114,20 +116,20 @@ github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nos github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k= github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= -github.com/go-jose/go-jose/v4 v4.0.1 h1:QVEPDE3OluqXBQZDcnNvQrInro2h0e4eqNbnZSWqS6U= -github.com/go-jose/go-jose/v4 v4.0.1/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY= +github.com/go-jose/go-jose/v4 v4.0.4 h1:VsjPI33J0SB9vQM6PLmNjoHqMQNGPiZ0rHL7Ni7Q6/E= +github.com/go-jose/go-jose/v4 v4.0.4/go.mod h1:NKb5HO1EZccyMpiZNbdUw/14tiXNyUJh188dfnMCAfc= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= -github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/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-rod/rod v0.116.0 h1:ypRryjTys3EnqHskJ/TdgodFMvXV0EHvmy4bSkKZgHM= -github.com/go-rod/rod v0.116.0/go.mod h1:aiedSEFg5DwG/fnNbUOTPMTTWX3MRj6vIs/a684Mthw= +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-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= -github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= +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/goadesign/goa v2.2.5+incompatible h1:SLgzk0V+QfFs7MVz9sbDHelbTDI9B/d4W7Hl5udTynY= github.com/goadesign/goa v2.2.5+incompatible/go.mod h1:d/9lpuZBK7HFi/7O0oXfwvdoIl+nx2bwKqctZe/lQao= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= @@ -162,10 +164,10 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-containerregistry v0.19.1 h1:yMQ62Al6/V0Z7CqIrrS1iYoA5/oQCm88DeNujc7C1KY= -github.com/google/go-containerregistry v0.19.1/go.mod h1:YCMFNQeeXeLF+dnhhWkqDItx/JSkH01j1Kis4PsjzFI= -github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= -github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= +github.com/google/go-containerregistry v0.20.1 h1:eTgx9QNYugV4DN5mz4U8hiAGTi1ybXn0TPi4Smd8du0= +github.com/google/go-containerregistry v0.20.1/go.mod h1:YCMFNQeeXeLF+dnhhWkqDItx/JSkH01j1Kis4PsjzFI= +github.com/google/s2a-go v0.1.8 h1:zZDs9gcbt9ZPLV0ndSyQk6Kacx2g/X+SKYovpnz3SMM= +github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA= github.com/google/tink/go v1.7.0 h1:6Eox8zONGebBFcCBqkVmt60LaWZa6xg1cl/DwAh/J1w= github.com/google/tink/go v1.7.0/go.mod h1:GAUOd+QE3pgj9q8VKIGTCP33c/B7eb4NhxLcgTJZStM= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -173,14 +175,14 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= -github.com/googleapis/gax-go/v2 v2.12.4 h1:9gWcmF85Wvq4ryPFvGFaOgPIs1AQX0d0bcbGw4Z96qg= -github.com/googleapis/gax-go/v2 v2.12.4/go.mod h1:KYEYLorsnIGDi/rPC8b5TdlB9kbKoFubselGIoBMCwI= +github.com/googleapis/gax-go/v2 v2.13.0 h1:yitjD5f7jQHhyDsnhKEBU52NdvvdSeGzlAnDPT0hH1s= +github.com/googleapis/gax-go/v2 v2.13.0/go.mod h1:Z/fvTZXF8/uw7Xu5GuslPw+bplx6SS338j1Is2S+B7A= 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/go-grpc-prometheus v1.2.1-0.20210315223345-82c243799c99 h1:JYghRBlGCZyCF2wNUJ8W0cwaQdtpcssJ4CgC406g+WU= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20210315223345-82c243799c99/go.mod h1:3bDW6wMZJB7tiONtC/1Xpicra6Wp5GgbTbQWCbI5fkc= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I= 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= @@ -220,6 +222,8 @@ 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/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -230,8 +234,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/letsencrypt/boulder v0.0.0-20230907030200-6d76a0f91e1e h1:RLTpX495BXToqxpM90Ws4hXEo4Wfh81jr9DX1n/4WOo= -github.com/letsencrypt/boulder v0.0.0-20230907030200-6d76a0f91e1e/go.mod h1:EAuqr9VFWxBi9nD5jc/EA2MT1RFty9288TF6zdtYoCU= +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/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= @@ -251,6 +255,8 @@ github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUb github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= @@ -266,19 +272,19 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= -github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= -github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= +github.com/prometheus/client_golang v1.20.2 h1:5ctymQzZlyOON1666svgwn3s6IKWgfbjsejTMiXIyjg= +github.com/prometheus/client_golang v1.20.2/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.54.0 h1:ZlZy0BgJhTwVZUn7dLOkwCZHUkrAqd3WYtcFCWnM1D8= -github.com/prometheus/common v0.54.0/go.mod h1:/TQgMJP5CuVYveyT7n/0Ix8yLNNXy9yRSkhnLTHPDIQ= +github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= +github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= -github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= +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/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/rs/cors v1.11.0 h1:0B9GE/r9Bc2UxRMMtymBkHTenPkHDv0CW4Y98GBY+po= @@ -295,8 +301,8 @@ github.com/secure-systems-lab/go-securesystemslib v0.8.0 h1:mr5An6X45Kb2nddcFlbm github.com/secure-systems-lab/go-securesystemslib v0.8.0/go.mod h1:UH2VZVuJfCYR8WgMlCU1uFsOUU+KeyrTWcSS73NBOzU= github.com/segmentio/ksuid v1.0.4 h1:sBo2BdShXjmcugAMwjugoGUdUV0pcxY5mW4xKRn3v4c= github.com/segmentio/ksuid v1.0.4/go.mod h1:/XUiZBD3kVx5SmUOl55voK5yeAbBNNIed+2O73XgrPE= -github.com/sigstore/sigstore v1.8.4 h1:g4ICNpiENFnWxjmBzBDWUn62rNFeny/P77HUC8da32w= -github.com/sigstore/sigstore v1.8.4/go.mod h1:1jIKtkTFEeISen7en+ZPWdDHazqhxco/+v9CNjc7oNg= +github.com/sigstore/sigstore v1.8.8 h1:B6ZQPBKK7Z7tO3bjLNnlCMG+H66tO4E/+qAphX8T/hg= +github.com/sigstore/sigstore v1.8.8/go.mod h1:GW0GgJSCTBJY3fUOuGDHeFWcD++c4G8Y9K015pwcpDI= github.com/sigstore/sigstore/pkg/signature/kms/aws v1.8.4 h1:okxaVlaTrQowE1FA4UQ3rw54f7BUjdnzERIxbZTBZuc= github.com/sigstore/sigstore/pkg/signature/kms/aws v1.8.4/go.mod h1:jkcPErmnCECuSJajUaUq5pwCMOeBF19VzQo6bv4l1D0= github.com/sigstore/sigstore/pkg/signature/kms/azure v1.8.4 h1:1G6uLTZaqvu867DbgH7p75L6Y7Tu8LLnYJGZnWsTUu8= @@ -348,33 +354,33 @@ github.com/ysmood/fetchup v0.2.3 h1:ulX+SonA0Vma5zUFXtv52Kzip/xe7aj4vqT5AJwQ+ZQ= github.com/ysmood/fetchup v0.2.3/go.mod h1:xhibcRKziSvol0H1/pj33dnKrYyI2ebIvz5cOOkYGns= github.com/ysmood/goob v0.4.0 h1:HsxXhyLBeGzWXnqVKtmT9qM7EuVs/XOgkX7T6r1o1AQ= github.com/ysmood/goob v0.4.0/go.mod h1:u6yx7ZhS4Exf2MwciFr6nIM8knHQIE22lFpWHnfql18= -github.com/ysmood/got v0.34.1 h1:IrV2uWLs45VXNvZqhJ6g2nIhY+pgIG1CUoOcqfXFl1s= -github.com/ysmood/got v0.34.1/go.mod h1:yddyjq/PmAf08RMLSwDjPyCvHvYed+WjHnQxpH851LM= +github.com/ysmood/got v0.40.0 h1:ZQk1B55zIvS7zflRrkGfPDrPG3d7+JOza1ZkNxcc74Q= +github.com/ysmood/got v0.40.0/go.mod h1:W7DdpuX6skL3NszLmAsC5hT7JAhuLZhByVzHTq874Qg= github.com/ysmood/gson v0.7.3 h1:QFkWbTH8MxyUTKPkVWAENJhxqdBa4lYTQWqZCiLG6kE= github.com/ysmood/gson v0.7.3/go.mod h1:3Kzs5zDl21g5F/BlLTNcuAGAYLKt2lV5G8D1zF3RNmg= -github.com/ysmood/leakless v0.8.0 h1:BzLrVoiwxikpgEQR0Lk8NyBN5Cit2b1z+u0mgL4ZJak= -github.com/ysmood/leakless v0.8.0/go.mod h1:R8iAXPRaG97QJwqxs74RdwzcRHT1SWCGTNqY8q0JvMQ= +github.com/ysmood/leakless v0.9.0 h1:qxCG5VirSBvmi3uynXFkcnLMzkphdh3xx5FtrORwDCU= +github.com/ysmood/leakless v0.9.0/go.mod h1:R8iAXPRaG97QJwqxs74RdwzcRHT1SWCGTNqY8q0JvMQ= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.52.0 h1:vS1Ao/R55RNV4O7TA2Qopok8yN+X0LIP6RVWLFkprck= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.52.0/go.mod h1:BMsdeOxN04K0L5FNUBfjFdvwWGNe/rkmSwH4Aelu/X0= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= -go.opentelemetry.io/otel v1.27.0 h1:9BZoF3yMK/O1AafMiQTVu0YDj5Ea4hPhxCs7sGva+cg= -go.opentelemetry.io/otel v1.27.0/go.mod h1:DMpAK8fzYRzs+bi3rS5REupisuqTheUlSZJ1WnZaPAQ= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 h1:r6I7RJCN86bpD/FQwedZ0vSixDpwuWREjW9oRMsmqDc= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0/go.mod h1:B9yO6b04uB80CzjedvewuqDhxJxi11s7/GtiGa8bAjI= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8= +go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw= +go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.27.0 h1:R9DE4kQ4k+YtfLI2ULwX82VtNQ2J8yZmA7ZIF/D+7Mc= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.27.0/go.mod h1:OQFyQVrDlbe+R7xrEyDr/2Wr67Ol0hRUgsfA+V5A95s= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 h1:qFffATk0X+HD+f1Z8lswGiOQYKHRlzfmdJm0wEaVrFA= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0/go.mod h1:MOiCmryaYtc+V0Ei+Tx9o5S1ZjA7kzLucuVuyzBZloQ= -go.opentelemetry.io/otel/metric v1.27.0 h1:hvj3vdEKyeCi4YaYfNjv2NUje8FqKqUY8IlF0FxV/ik= -go.opentelemetry.io/otel/metric v1.27.0/go.mod h1:mVFgmRlhljgBiuk/MP/oKylr4hs85GZAylncepAX/ak= +go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc= +go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8= go.opentelemetry.io/otel/sdk v1.27.0 h1:mlk+/Y1gLPLn84U4tI8d3GNJmGT/eXe3ZuOXN9kTWmI= go.opentelemetry.io/otel/sdk v1.27.0/go.mod h1:Ha9vbLwJE6W86YstIywK2xFfPjbWlCuwPtMkKdz/Y4A= -go.opentelemetry.io/otel/trace v1.27.0 h1:IqYb813p7cmbHk0a5y6pD5JPakbVfftRXABGt5/Rscw= -go.opentelemetry.io/otel/trace v1.27.0/go.mod h1:6RiD1hkAprV4/q+yd2ln1HG9GoPx39SuvvstaLBl+l4= +go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4= +go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ= go.opentelemetry.io/proto/otlp v1.2.0 h1:pVeZGk7nXDC9O2hncA6nHldxEjm6LByfA2aN8IOkz94= go.opentelemetry.io/proto/otlp v1.2.0/go.mod h1:gGpR8txAl5M03pDhMC79G6SdqNV26naRm/KDsgaHD8A= go.step.sm/crypto v0.44.2 h1:t3p3uQ7raP2jp2ha9P6xkQF85TJZh+87xmjSLaib+jk= @@ -396,11 +402,11 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= -golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= -golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= +golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= -golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= +golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa h1:ELnwvuAXPNtPk1TJRuGkI9fDTwym6AYBu0qzT8AcHdI= +golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -423,11 +429,11 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= -golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= +golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.20.0 h1:4mQdhULixXKP1rwYBW0vAijoXnkTG0BLCDRzfe1idMo= -golang.org/x/oauth2 v0.20.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA= +golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -435,8 +441,8 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= -golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -452,25 +458,25 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= +golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= -golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= -golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= +golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= +golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= -golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= -golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= +golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= +golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/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= @@ -487,20 +493,20 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.181.0 h1:rPdjwnWgiPPOJx3IcSAQ2III5aX5tCer6wMpa/xmZi4= -google.golang.org/api v0.181.0/go.mod h1:MnQ+M0CFsfUwA5beZ+g/vCBCPXvtmZwRz2qzZk8ih1k= +google.golang.org/api v0.194.0 h1:dztZKG9HgtIpbI35FhfuSNR/zmaMVdxNlntHj1sIS4s= +google.golang.org/api v0.194.0/go.mod h1:AgvUFdojGANh3vI+P7EVnxj3AISHllxGCJSFmggmnd0= 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/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20240401170217-c3f982113cda h1:wu/KJm9KJwpfHWhkkZGohVC6KRrc1oJNr4jwtQMOQXw= -google.golang.org/genproto v0.0.0-20240401170217-c3f982113cda/go.mod h1:g2LLCvCeCSir/JJSWosk19BR4NVxGqHUC6rxIRsd7Aw= -google.golang.org/genproto/googleapis/api v0.0.0-20240520151616-dc85e6b867a5 h1:P8OJ/WCl/Xo4E4zoe4/bifHpSmmKwARqyqE4nW6J2GQ= -google.golang.org/genproto/googleapis/api v0.0.0-20240520151616-dc85e6b867a5/go.mod h1:RGnPtTG7r4i8sPlNyDeikXF99hMM+hN6QMm4ooG9g2g= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240520151616-dc85e6b867a5 h1:Q2RxlXqh1cgzzUgV261vBO2jI5R/3DD1J2pM0nI4NhU= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240520151616-dc85e6b867a5/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0= +google.golang.org/genproto v0.0.0-20240814211410-ddb44dafa142 h1:oLiyxGgE+rt22duwci1+TG7bg2/L1LQsXwfjPlmuJA0= +google.golang.org/genproto v0.0.0-20240814211410-ddb44dafa142/go.mod h1:G11eXq53iI5Q+kyNOmCvnzBaxEA2Q/Ik5Tj7nqBE8j4= +google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd h1:BBOTEWLuuEGQy9n1y9MhVJ9Qt0BDu21X8qZs71/uPZo= +google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd/go.mod h1:fO8wJzT2zbQbAjbIoos1285VfEIYKDDY+Dt+WpTkh6g= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd h1:6TEm2ZxXoQmFWFlt1vNxvVOa1Q0dXFQD1m/rYjXmS0E= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= @@ -508,8 +514,8 @@ google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQ google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= -google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= +google.golang.org/grpc v1.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c= +google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -525,12 +531,8 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/go-jose/go-jose.v2 v2.6.3 h1:nt80fvSDlhKWQgSWyHyy5CfmlQr+asih51R8PTWNKKs= -gopkg.in/go-jose/go-jose.v2 v2.6.3/go.mod h1:zzZDPkNNw/c9IE7Z9jr11mBZQhKQTMzoEEIoEdZlFBI= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= -gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= diff --git a/hack/tools/go.mod b/hack/tools/go.mod index 16a7d0a77..3fbdde536 100644 --- a/hack/tools/go.mod +++ b/hack/tools/go.mod @@ -1,35 +1,34 @@ module github.com/sigstore/fulcio/hack/tools -go 1.20 +go 1.22.5 require ( - github.com/googleapis/api-linter v1.64.0 - github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 - google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0 - google.golang.org/protobuf v1.33.0 + github.com/googleapis/api-linter v1.67.1 + github.com/grpc-ecosystem/grpc-gateway/v2 v2.21.0 + google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1 + google.golang.org/protobuf v1.34.2 ) require ( bitbucket.org/creachadair/stringset v0.0.12 // indirect - cloud.google.com/go/longrunning v0.5.5 // indirect + cloud.google.com/go/longrunning v0.5.7 // indirect github.com/bmatcuk/doublestar/v4 v4.6.1 // indirect - github.com/bufbuild/protocompile v0.8.0 // indirect + github.com/bufbuild/protocompile v0.10.0 // indirect github.com/gertd/go-pluralize v0.2.1 // indirect - github.com/golang/protobuf v1.5.3 // indirect - github.com/jhump/protoreflect v1.15.6 // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/jhump/protoreflect v1.16.0 // indirect github.com/kr/text v0.2.0 // indirect github.com/mattn/go-runewidth v0.0.9 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/stoewer/go-strcase v1.3.0 // indirect - golang.org/x/net v0.20.0 // indirect - golang.org/x/sync v0.6.0 // indirect - golang.org/x/sys v0.16.0 // indirect - golang.org/x/text v0.14.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240304212257-790db918fca8 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240228224816-df926f6c8641 // indirect - google.golang.org/grpc v1.62.0 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect + golang.org/x/net v0.26.0 // indirect + golang.org/x/sync v0.7.0 // indirect + golang.org/x/sys v0.21.0 // indirect + golang.org/x/text v0.16.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240723171418-e6d459c13d2a // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240723171418-e6d459c13d2a // indirect + google.golang.org/grpc v1.65.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/hack/tools/go.sum b/hack/tools/go.sum index f23d30c18..92e7416e5 100644 --- a/hack/tools/go.sum +++ b/hack/tools/go.sum @@ -1,32 +1,33 @@ bitbucket.org/creachadair/stringset v0.0.12 h1:APD8dIoAzGv70a6p1oasPDjPwkp+ajszdgKyWUcNqo0= bitbucket.org/creachadair/stringset v0.0.12/go.mod h1:KtNk2s0hRO1T0r78lv9Zq/S/Lp0du2zI0Fj5j5Y4LDo= -cloud.google.com/go/longrunning v0.5.5 h1:GOE6pZFdSrTb4KAiKnXsJBtlE6mEyaW44oKyMILWnOg= -cloud.google.com/go/longrunning v0.5.5/go.mod h1:WV2LAxD8/rg5Z1cNW6FJ/ZpX4E4VnDnoTk0yawPBB7s= +cloud.google.com/go/longrunning v0.5.7 h1:WLbHekDbjK1fVFD3ibpFFVoyizlLRl73I7YKuAKilhU= +cloud.google.com/go/longrunning v0.5.7/go.mod h1:8GClkudohy1Fxm3owmBGid8W0pSgodEMwEAztp38Xng= github.com/bmatcuk/doublestar/v4 v4.6.1 h1:FH9SifrbvJhnlQpztAx++wlkk70QBf0iBWDwNy7PA4I= github.com/bmatcuk/doublestar/v4 v4.6.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= -github.com/bufbuild/protocompile v0.8.0 h1:9Kp1q6OkS9L4nM3FYbr8vlJnEwtbpDPQlQOVXfR+78s= -github.com/bufbuild/protocompile v0.8.0/go.mod h1:+Etjg4guZoAqzVk2czwEQP12yaxLJ8DxuqCJ9qHdH94= +github.com/bufbuild/protocompile v0.10.0 h1:+jW/wnLMLxaCEG8AX9lD0bQ5v9h1RUiMKOBOT5ll9dM= +github.com/bufbuild/protocompile v0.10.0/go.mod h1:G9qQIQo0xZ6Uyj6CMNz0saGmx2so+KONo8/KrELABiY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/gertd/go-pluralize v0.2.1 h1:M3uASbVjMnTsPb0PNqg+E/24Vwigyo/tvyMTtAlLgiA= github.com/gertd/go-pluralize v0.2.1/go.mod h1:rbYaKDbsXxmRfr8uygAEKhOWsjyrrqrkHVpZvoOp8zk= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/googleapis/api-linter v1.64.0 h1:wOFNNOPRCo/0m3wwFKBRgR428mq7pl/S6b3O1XWZ/9Y= -github.com/googleapis/api-linter v1.64.0/go.mod h1:GoZrlogORqrkj65vzv878o10FghKeLan2j6eRA+HQz0= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 h1:/c3QmbOGMGTOumP2iT/rCwB7b0QDGLKzqOmktBjT+Is= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1/go.mod h1:5SN9VR2LTsRFsrEC6FHgRbTWrTHu6tqPeKxEQv15giM= -github.com/jhump/protoreflect v1.15.6 h1:WMYJbw2Wo+KOWwZFvgY0jMoVHM6i4XIvRs2RcBj5VmI= -github.com/jhump/protoreflect v1.15.6/go.mod h1:jCHoyYQIJnaabEYnbGwyo9hUqfyUMTbJw/tAut5t97E= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/googleapis/api-linter v1.67.1 h1:4w5XrUGU/yGHJtk1J+DsHFtVshbRISvVHhB1ZjdZ2Qg= +github.com/googleapis/api-linter v1.67.1/go.mod h1:FXkj1Z78//S3ydG9T9fUnw3F6wdFo/V5RUiAxhJfAvw= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.21.0 h1:CWyXh/jylQWp2dtiV33mY4iSSp6yf4lmn+c7/tN+ObI= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.21.0/go.mod h1:nCLIt0w3Ept2NwF8ThLmrppXsfT07oC8k0XNDxd8sVU= +github.com/jhump/protoreflect v1.16.0 h1:54fZg+49widqXYQ0b+usAFHbMkBGR4PpXrsHc8+TBDg= +github.com/jhump/protoreflect v1.16.0/go.mod h1:oYPd7nPvcBw/5wlDfm/AVmU9zH9BgqGCI469pGxfj/8= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lithammer/dedent v1.1.0 h1:VNzHMVCBNG1j0fh3OrsFRkVUwStdDArbgBWoPAffktY= +github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc= github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= @@ -45,33 +46,31 @@ github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpE github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= -golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= -golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= -golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= -golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 h1:9+tzLLstTlPTRyJTh+ah5wIMsBW5c4tQwGTN3thOW9Y= -google.golang.org/genproto/googleapis/api v0.0.0-20240304212257-790db918fca8 h1:8eadJkXbwDEMNwcB5O0s5Y5eCfyuCLdvaiOIaGTrWmQ= -google.golang.org/genproto/googleapis/api v0.0.0-20240304212257-790db918fca8/go.mod h1:O1cOfN1Cy6QEYr7VxtjOyP5AdAuR0aJ/MYZaaof623Y= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240228224816-df926f6c8641 h1:DKU1r6Tj5s1vlU/moGhuGz7E3xRfwjdAfDzbsaQJtEY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240228224816-df926f6c8641/go.mod h1:UCOku4NytXMJuLQE5VuqA5lX3PcHCBo8pxNyvkf4xBs= -google.golang.org/grpc v1.62.0 h1:HQKZ/fa1bXkX1oFOvSjmZEUL8wLSaZTjCcLAlmZRtdk= -google.golang.org/grpc v1.62.0/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0 h1:rNBFJjBCOgVr9pWD7rs/knKL4FRTKgpZmsRfV214zcA= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0/go.mod h1:Dk1tviKTvMCz5tvh7t+fh94dhmQVHuCt2OzJB3CTW9Y= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= +golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +google.golang.org/genproto v0.0.0-20240521202816-d264139d666e h1:axIBUGXSVho2zB+3tJj8l9Qvm/El5vVYPYqhGA5PmJM= +google.golang.org/genproto v0.0.0-20240521202816-d264139d666e/go.mod h1:gOvX/2dWTqh+u3+IHjFeCxinlz5AZ5qhOufbQPub/dE= +google.golang.org/genproto/googleapis/api v0.0.0-20240723171418-e6d459c13d2a h1:YIa/rzVqMEokBkPtydCkx1VLmv3An1Uw7w1P1m6EhOY= +google.golang.org/genproto/googleapis/api v0.0.0-20240723171418-e6d459c13d2a/go.mod h1:AHT0dDg3SoMOgZGnZk29b5xTbPHMoEC8qthmBLJCpys= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240723171418-e6d459c13d2a h1:hqK4+jJZXCU4pW7jsAdGOVFIfLHQeV7LaizZKnZ84HI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240723171418-e6d459c13d2a/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= +google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= +google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1 h1:F29+wU6Ee6qgu9TddPgooOdaqsxTMunOoj8KA5yuS5A= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1/go.mod h1:5KF+wpkbTSbGcR9zteSqZV6fqFOWBl4Yde8En8MryZA= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/pkg/api/client_test.go b/pkg/api/client_test.go index 5a77d428a..0a568441b 100644 --- a/pkg/api/client_test.go +++ b/pkg/api/client_test.go @@ -23,7 +23,7 @@ import ( ) func TestUserAgentOption(t *testing.T) { - ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + ts := httptest.NewServer(http.HandlerFunc(func(_ http.ResponseWriter, r *http.Request) { if r.Header.Get("User-Agent") != "foo" { t.Error(`expected user-agent to be set to "foo"`) } @@ -42,7 +42,7 @@ func TestUserAgentOption(t *testing.T) { } func TestTimeoutOption(t *testing.T) { - ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + ts := httptest.NewServer(http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) { time.Sleep(10 * time.Second) })) diff --git a/pkg/ca/common_test.go b/pkg/ca/common_test.go index 30723b3ec..4deef68d1 100644 --- a/pkg/ca/common_test.go +++ b/pkg/ca/common_test.go @@ -127,12 +127,12 @@ func TestVerifyCertChain(t *testing.T) { // Failure: Weak key weakSubCert, weakSubKey, _ := test.GenerateWeakSubordinateCA(rootCert, rootKey) err = VerifyCertChain([]*x509.Certificate{weakSubCert, rootCert}, weakSubKey) - if err == nil || !strings.Contains(err.Error(), "unsupported ec curve") { + if err == nil || !strings.Contains(err.Error(), "ECDSA curve P-224 not allowed") { t.Fatalf("expected error verifying weak cert chain: %v", err) } // Failure: Empty chain - err = VerifyCertChain([]*x509.Certificate{}, weakSubKey) + err = VerifyCertChain([]*x509.Certificate{}, subKey) if err == nil || !strings.Contains(err.Error(), "certificate chain must contain at least one certificate") { t.Fatalf("expected error verifying with empty chain: %v", err) } diff --git a/pkg/ca/kmsca/kmsca.go b/pkg/ca/kmsca/kmsca.go index 7de391e97..057e68ee2 100644 --- a/pkg/ca/kmsca/kmsca.go +++ b/pkg/ca/kmsca/kmsca.go @@ -43,7 +43,7 @@ func NewKMSCA(ctx context.Context, kmsKey string, certs []*x509.Certificate, opt if err != nil { return nil, err } - signer, _, err := kmsSigner.CryptoSigner(ctx, func(err error) {}) + signer, _, err := kmsSigner.CryptoSigner(ctx, func(_ error) {}) if err != nil { return nil, err } diff --git a/pkg/certificate/extensions.go b/pkg/certificate/extensions.go index 38f80d5ae..584aac971 100644 --- a/pkg/certificate/extensions.go +++ b/pkg/certificate/extensions.go @@ -69,69 +69,69 @@ type Extensions struct { // Deprecated // Triggering event of the Github Workflow. Matches the `event_name` claim of ID // tokens from Github Actions - GithubWorkflowTrigger string // OID 1.3.6.1.4.1.57264.1.2 + GithubWorkflowTrigger string `json:"GithubWorkflowTrigger,omitempty" yaml:"github-workflow-trigger,omitempty"` // OID 1.3.6.1.4.1.57264.1.2 // Deprecated // SHA of git commit being built in Github Actions. Matches the `sha` claim of ID // tokens from Github Actions - GithubWorkflowSHA string // OID 1.3.6.1.4.1.57264.1.3 + GithubWorkflowSHA string `json:"GithubWorkflowSHA,omitempty" yaml:"github-workflow-sha,omitempty"` // OID 1.3.6.1.4.1.57264.1.3 // Deprecated // Name of Github Actions Workflow. Matches the `workflow` claim of the ID // tokens from Github Actions - GithubWorkflowName string // OID 1.3.6.1.4.1.57264.1.4 + GithubWorkflowName string `json:"GithubWorkflowName,omitempty" yaml:"github-workflow-name,omitempty"` // OID 1.3.6.1.4.1.57264.1.4 // Deprecated // Repository of the Github Actions Workflow. Matches the `repository` claim of the ID // tokens from Github Actions - GithubWorkflowRepository string // OID 1.3.6.1.4.1.57264.1.5 + GithubWorkflowRepository string `json:"GithubWorkflowRepository,omitempty" yaml:"github-workflow-repository,omitempty"` // OID 1.3.6.1.4.1.57264.1.5 // Deprecated // Git Ref of the Github Actions Workflow. Matches the `ref` claim of the ID tokens // from Github Actions - GithubWorkflowRef string // 1.3.6.1.4.1.57264.1.6 + GithubWorkflowRef string `json:"GithubWorkflowRef,omitempty" yaml:"github-workflow-ref,omitempty"` // 1.3.6.1.4.1.57264.1.6 // Reference to specific build instructions that are responsible for signing. - BuildSignerURI string // 1.3.6.1.4.1.57264.1.9 + BuildSignerURI string `json:"BuildSignerURI,omitempty" yaml:"build-signer-uri,omitempty"` // 1.3.6.1.4.1.57264.1.9 // Immutable reference to the specific version of the build instructions that is responsible for signing. - BuildSignerDigest string // 1.3.6.1.4.1.57264.1.10 + BuildSignerDigest string `json:"BuildSignerDigest,omitempty" yaml:"build-signer-digest,omitempty"` // 1.3.6.1.4.1.57264.1.10 // Specifies whether the build took place in platform-hosted cloud infrastructure or customer/self-hosted infrastructure. - RunnerEnvironment string // 1.3.6.1.4.1.57264.1.11 + RunnerEnvironment string `json:"RunnerEnvironment,omitempty" yaml:"runner-environment,omitempty"` // 1.3.6.1.4.1.57264.1.11 // Source repository URL that the build was based on. - SourceRepositoryURI string // 1.3.6.1.4.1.57264.1.12 + SourceRepositoryURI string `json:"SourceRepositoryURI,omitempty" yaml:"source-repository-uri,omitempty"` // 1.3.6.1.4.1.57264.1.12 // Immutable reference to a specific version of the source code that the build was based upon. - SourceRepositoryDigest string // 1.3.6.1.4.1.57264.1.13 + SourceRepositoryDigest string `json:"SourceRepositoryDigest,omitempty" yaml:"source-repository-digest,omitempty"` // 1.3.6.1.4.1.57264.1.13 // Source Repository Ref that the build run was based upon. - SourceRepositoryRef string // 1.3.6.1.4.1.57264.1.14 + SourceRepositoryRef string `json:"SourceRepositoryRef,omitempty" yaml:"source-repository-ref,omitempty"` // 1.3.6.1.4.1.57264.1.14 // Immutable identifier for the source repository the workflow was based upon. - SourceRepositoryIdentifier string // 1.3.6.1.4.1.57264.1.15 + SourceRepositoryIdentifier string `json:"SourceRepositoryIdentifier,omitempty" yaml:"source-repository-identifier,omitempty"` // 1.3.6.1.4.1.57264.1.15 // Source repository owner URL of the owner of the source repository that the build was based on. - SourceRepositoryOwnerURI string // 1.3.6.1.4.1.57264.1.16 + SourceRepositoryOwnerURI string `json:"SourceRepositoryOwnerURI,omitempty" yaml:"source-repository-owner-uri,omitempty"` // 1.3.6.1.4.1.57264.1.16 // Immutable identifier for the owner of the source repository that the workflow was based upon. - SourceRepositoryOwnerIdentifier string // 1.3.6.1.4.1.57264.1.17 + SourceRepositoryOwnerIdentifier string `json:"SourceRepositoryOwnerIdentifier,omitempty" yaml:"source-repository-owner-identifier,omitempty"` // 1.3.6.1.4.1.57264.1.17 // Build Config URL to the top-level/initiating build instructions. - BuildConfigURI string // 1.3.6.1.4.1.57264.1.18 + BuildConfigURI string `json:"BuildConfigURI,omitempty" yaml:"build-config-uri,omitempty"` // 1.3.6.1.4.1.57264.1.18 // Immutable reference to the specific version of the top-level/initiating build instructions. - BuildConfigDigest string // 1.3.6.1.4.1.57264.1.19 + BuildConfigDigest string `json:"BuildConfigDigest,omitempty" yaml:"build-config-digest,omitempty"` // 1.3.6.1.4.1.57264.1.19 // Event or action that initiated the build. - BuildTrigger string // 1.3.6.1.4.1.57264.1.20 + BuildTrigger string `json:"BuildTrigger,omitempty" yaml:"build-trigger,omitempty"` // 1.3.6.1.4.1.57264.1.20 // Run Invocation URL to uniquely identify the build execution. - RunInvocationURI string // 1.3.6.1.4.1.57264.1.21 + RunInvocationURI string `json:"RunInvocationURI,omitempty" yaml:"run-invocation-uri,omitempty"` // 1.3.6.1.4.1.57264.1.21 // Source repository visibility at the time of signing the certificate. - SourceRepositoryVisibilityAtSigning string // 1.3.6.1.4.1.57264.1.22 + SourceRepositoryVisibilityAtSigning string `json:"SourceRepositoryVisibilityAtSigning,omitempty" yaml:"source-repository-visibility-at-signing,omitempty"` // 1.3.6.1.4.1.57264.1.22 } func (e Extensions) Render() ([]pkix.Extension, error) { diff --git a/pkg/challenges/challenges.go b/pkg/challenges/challenges.go index dda3298ff..143fdaab9 100644 --- a/pkg/challenges/challenges.go +++ b/pkg/challenges/challenges.go @@ -27,6 +27,7 @@ import ( "github.com/sigstore/fulcio/pkg/config" "github.com/sigstore/fulcio/pkg/identity" "github.com/sigstore/fulcio/pkg/identity/buildkite" + "github.com/sigstore/fulcio/pkg/identity/ciprovider" "github.com/sigstore/fulcio/pkg/identity/email" "github.com/sigstore/fulcio/pkg/identity/github" "github.com/sigstore/fulcio/pkg/identity/gitlabcom" @@ -75,6 +76,8 @@ func PrincipalFromIDToken(ctx context.Context, tok *oidc.IDToken) (identity.Prin principal, err = uri.PrincipalFromIDToken(ctx, tok) case config.IssuerTypeUsername: principal, err = username.PrincipalFromIDToken(ctx, tok) + case config.IssuerTypeCIProvider: + principal, err = ciprovider.WorkflowPrincipalFromIDToken(ctx, tok) default: return nil, fmt.Errorf("unsupported issuer: %s", iss.Type) } diff --git a/pkg/config/config.go b/pkg/config/config.go index c0eaf2a27..a2296147e 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -21,6 +21,7 @@ import ( "encoding/json" "errors" "fmt" + "html/template" "net/http" "net/url" "os" @@ -31,9 +32,11 @@ import ( "github.com/coreos/go-oidc/v3/oidc" lru "github.com/hashicorp/golang-lru" + "github.com/sigstore/fulcio/pkg/certificate" fulciogrpc "github.com/sigstore/fulcio/pkg/generated/protobuf" "github.com/sigstore/fulcio/pkg/log" "github.com/spiffe/go-spiffe/v2/spiffeid" + "gopkg.in/yaml.v3" ) const defaultOIDCDiscoveryTimeout = 10 * time.Second @@ -48,7 +51,7 @@ type verifierWithConfig struct { } type FulcioConfig struct { - OIDCIssuers map[string]OIDCIssuer `json:"OIDCIssuers,omitempty"` + OIDCIssuers map[string]OIDCIssuer `json:"OIDCIssuers,omitempty" yaml:"oidc-issuers,omitempty"` // A meta issuer has a templated URL of the form: // https://oidc.eks.*.amazonaws.com/id/* @@ -57,7 +60,13 @@ type FulcioConfig struct { // other special characters) Some examples we want to match: // * https://oidc.eks.us-west-2.amazonaws.com/id/B02C93B6A2D30341AD01E1B6D48164CB // * https://container.googleapis.com/v1/projects/mattmoor-credit/locations/us-west1-b/clusters/tenant-cluster - MetaIssuers map[string]OIDCIssuer `json:"MetaIssuers,omitempty"` + MetaIssuers map[string]OIDCIssuer `json:"MetaIssuers,omitempty" yaml:"meta-issuers,omitempty"` + + // It defines metadata to be used for the CIProvider identity provider principal. + // The CI provider has a generic logic for ci providers, this metadata is used + // to define the right behavior for each ci provider that is defined + // on the configuration file + CIIssuerMetadata map[string]IssuerMetadata `json:"CIIssuerMetadata,omitempty" yaml:"ci-issuer-metadata,omitempty"` // verifiers is a fixed mapping from our OIDCIssuers to their OIDC verifiers. verifiers map[string][]*verifierWithConfig @@ -65,26 +74,48 @@ type FulcioConfig struct { lru *lru.TwoQueueCache } +type IssuerMetadata struct { + // Defaults contains key-value pairs that can be used for filling the templates from ExtensionTemplates + // If a key cannot be found on the token claims, the template will use the defaults + DefaultTemplateValues map[string]string `json:"DefaultTemplateValues,omitempty" yaml:"default-template-values,omitempty"` + // ExtensionTemplates contains a mapping between certificate extension and token claim + // Provide either strings following https://pkg.go.dev/text/template syntax, + // e.g "{{ .url }}/{{ .repository }}" + // or non-templated strings with token claim keys to be replaced, + // e.g "job_workflow_sha" + ExtensionTemplates certificate.Extensions `json:"ExtensionTemplates,omitempty" yaml:"extension-templates,omitempty"` + // Template for the Subject Alternative Name extension + // It's typically the same value as Build Signer URI + SubjectAlternativeNameTemplate string `json:"SubjectAlternativeNameTemplate,omitempty" yaml:"subject-alternative-name-template,omitempty"` +} + type OIDCIssuer struct { // The expected issuer of an OIDC token - IssuerURL string `json:"IssuerURL,omitempty"` + IssuerURL string `json:"IssuerURL,omitempty" yaml:"issuer-url,omitempty"` // The expected client ID of the OIDC token - ClientID string `json:"ClientID"` + ClientID string `json:"ClientID" yaml:"client-id,omitempty"` // Used to determine the subject of the certificate and if additional // certificate values are needed - Type IssuerType `json:"Type"` + Type IssuerType `json:"Type" yaml:"type,omitempty"` + // CIProvider is an optional configuration to map token claims to extensions for CI workflows + CIProvider string `json:"CIProvider,omitempty" yaml:"ci-provider,omitempty"` // Optional, if the issuer is in a different claim in the OIDC token - IssuerClaim string `json:"IssuerClaim,omitempty"` + IssuerClaim string `json:"IssuerClaim,omitempty" yaml:"issuer-claim,omitempty"` // The domain that must be present in the subject for 'uri' issuer types // Also used to create an email for 'username' issuer types - SubjectDomain string `json:"SubjectDomain,omitempty"` + SubjectDomain string `json:"SubjectDomain,omitempty" yaml:"subject-domain,omitempty"` // SPIFFETrustDomain specifies the trust domain that 'spiffe' issuer types // issue ID tokens for. Tokens with a different trust domain will be // rejected. - SPIFFETrustDomain string `json:"SPIFFETrustDomain,omitempty"` + SPIFFETrustDomain string `json:"SPIFFETrustDomain,omitempty" yaml:"spiffe-trust-domain,omitempty"` // Optional, the challenge claim expected for the issuer // Set if using a custom issuer - ChallengeClaim string `json:"ChallengeClaim,omitempty"` + ChallengeClaim string `json:"ChallengeClaim,omitempty" yaml:"challenge-claim,omitempty"` + // Optional, the description for the issuer + Description string `json:"Description,omitempty" yaml:"description,omitempty"` + // Optional, the contact for the issuer team + // Usually it is a email + Contact string `json:"Contact,omitempty" yaml:"contact,omitempty"` } func metaRegex(issuer string) (*regexp.Regexp, error) { @@ -278,16 +309,20 @@ const ( IssuerTypeGithubWorkflow = "github-workflow" IssuerTypeCodefreshWorkflow = "codefresh-workflow" IssuerTypeGitLabPipeline = "gitlab-pipeline" + IssuerTypeChainguard = "chainguard-identity" IssuerTypeKubernetes = "kubernetes" IssuerTypeSpiffe = "spiffe" IssuerTypeURI = "uri" IssuerTypeUsername = "username" + IssuerTypeCIProvider = "ci-provider" ) func parseConfig(b []byte) (cfg *FulcioConfig, err error) { cfg = &FulcioConfig{} if err := json.Unmarshal(b, cfg); err != nil { - return nil, fmt.Errorf("unmarshal: %w", err) + if err = yaml.Unmarshal(b, cfg); err != nil { + return nil, fmt.Errorf("unmarshal: %w", err) + } } return cfg, nil @@ -387,7 +422,7 @@ func validateConfig(conf *FulcioConfig) error { } } - return nil + return validateCIIssuerMetadata(conf) } var DefaultConfig = &FulcioConfig{ @@ -428,6 +463,34 @@ func FromContext(ctx context.Context) *FulcioConfig { return untyped.(*FulcioConfig) } +// It checks that the templates defined are parseable +// We should check it during the service bootstrap to avoid errors further +func validateCIIssuerMetadata(fulcioConfig *FulcioConfig) error { + + checkParse := func(temp string) error { + t := template.New("").Option("missingkey=error") + _, err := t.Parse(temp) + return err + } + + for _, ciIssuerMetadata := range fulcioConfig.CIIssuerMetadata { + v := reflect.ValueOf(ciIssuerMetadata.ExtensionTemplates) + for i := 0; i < v.NumField(); i++ { + s := v.Field(i).String() + err := checkParse(s) + if err != nil { + return err + } + } + + err := checkParse(ciIssuerMetadata.SubjectAlternativeNameTemplate) + if err != nil { + return err + } + } + return nil +} + // Load a config from disk, or use defaults func Load(configPath string) (*FulcioConfig, error) { if _, err := os.Stat(configPath); os.IsNotExist(err) { @@ -512,8 +575,12 @@ func issuerToChallengeClaim(issType IssuerType, challengeClaim string) string { return "email" case IssuerTypeGithubWorkflow: return "sub" + case IssuerTypeCIProvider: + return "sub" case IssuerTypeCodefreshWorkflow: return "sub" + case IssuerTypeChainguard: + return "sub" case IssuerTypeKubernetes: return "sub" case IssuerTypeSpiffe: diff --git a/pkg/config/config_network_test.go b/pkg/config/config_network_test.go index 52808181a..00f139824 100644 --- a/pkg/config/config_network_test.go +++ b/pkg/config/config_network_test.go @@ -25,12 +25,54 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" + "github.com/sigstore/fulcio/pkg/certificate" ) -func TestLoad(t *testing.T) { +func TestLoadYamlConfig(t *testing.T) { + td := t.TempDir() + cfgPath := filepath.Join(td, "config.yaml") + if err := os.WriteFile(cfgPath, []byte(validYamlCfg), 0644); err != nil { + t.Fatal(err) + } + + cfg, err := Load(cfgPath) + if err != nil { + t.Fatal(err) + } + got, ok := cfg.GetIssuer("https://accounts.google.com") + if !ok { + t.Error("expected true, got false") + } + if got.ClientID != "foo" { + t.Errorf("expected foo, got %s", got.ClientID) + } + if got.IssuerURL != "https://accounts.google.com" { + t.Errorf("expected https://accounts.google.com, got %s", got.IssuerURL) + } + if got := len(cfg.OIDCIssuers); got != 1 { + t.Errorf("expected 1 issuer, got %d", got) + } + + got, ok = cfg.GetIssuer("https://oidc.eks.fantasy-land.amazonaws.com/id/CLUSTERIDENTIFIER") + if !ok { + t.Error("expected true, got false") + } + if got.ClientID != "bar" { + t.Errorf("expected bar, got %s", got.ClientID) + } + if got.IssuerURL != "https://oidc.eks.fantasy-land.amazonaws.com/id/CLUSTERIDENTIFIER" { + t.Errorf("expected https://oidc.eks.fantasy-land.amazonaws.com/id/CLUSTERIDENTIFIER, got %s", got.IssuerURL) + } + + if _, ok := cfg.GetIssuer("not_an_issuer"); ok { + t.Error("no error returned from an unconfigured issuer") + } +} + +func TestLoadJsonConfig(t *testing.T) { td := t.TempDir() cfgPath := filepath.Join(td, "config.json") - if err := os.WriteFile(cfgPath, []byte(validCfg), 0644); err != nil { + if err := os.WriteFile(cfgPath, []byte(validJSONCfg), 0644); err != nil { t.Fatal(err) } @@ -68,11 +110,66 @@ func TestLoad(t *testing.T) { } } +func TestParseTemplate(t *testing.T) { + + validTemplate := "{{.foobar}}" + invalidTemplate := "{{.foobar}" + ciissuerMetadata := make(map[string]IssuerMetadata) + ciissuerMetadata["github"] = IssuerMetadata{ + ExtensionTemplates: certificate.Extensions{ + BuildTrigger: invalidTemplate, + }, + } + fulcioConfig := &FulcioConfig{ + CIIssuerMetadata: ciissuerMetadata, + } + // BuildTrigger as a invalid template should raise an error + err := validateCIIssuerMetadata(fulcioConfig) + if err == nil { + t.Error("invalid template should raise an error") + } + ciissuerMetadata["github"] = IssuerMetadata{ + ExtensionTemplates: certificate.Extensions{ + BuildTrigger: validTemplate, + }, + } + fulcioConfig = &FulcioConfig{ + CIIssuerMetadata: ciissuerMetadata, + } + // BuildTrigger as a valid template shouldn't raise an error + err = validateCIIssuerMetadata(fulcioConfig) + if err != nil { + t.Error("valid template shouldn't raise an error, error: %w", err) + } + ciissuerMetadata["github"] = IssuerMetadata{ + SubjectAlternativeNameTemplate: invalidTemplate, + } + fulcioConfig = &FulcioConfig{ + CIIssuerMetadata: ciissuerMetadata, + } + // A SAN as a invalid template should raise an error + err = validateCIIssuerMetadata(fulcioConfig) + if err == nil { + t.Error("invalid SAN should raise an error") + } + ciissuerMetadata["github"] = IssuerMetadata{ + SubjectAlternativeNameTemplate: invalidTemplate, + } + fulcioConfig = &FulcioConfig{ + CIIssuerMetadata: ciissuerMetadata, + } + // A SAN as a valid template should raise an error + err = validateCIIssuerMetadata(fulcioConfig) + if err == nil { + t.Error("valid SAN shouldn't raise an error") + } +} + func TestLoadDefaults(t *testing.T) { td := t.TempDir() // Don't put anything here! - cfgPath := filepath.Join(td, "config.json") + cfgPath := filepath.Join(td, "config.yaml") cfg, err := Load(cfgPath) if err != nil { t.Fatal(err) diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index 1c926a044..042fe9b8f 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -27,7 +27,20 @@ import ( "github.com/sigstore/fulcio/pkg/generated/protobuf" ) -var validCfg = ` +var validYamlCfg = ` +oidc-issuers: + https://accounts.google.com: + issuer-url: https://accounts.google.com + client-id: foo + type: email + challenge-claim: email +meta-issuers: + https://oidc.eks.*.amazonaws.com/id/*: + client-id: bar + type: kubernetes +` + +var validJSONCfg = ` { "OIDCIssuers": { "https://accounts.google.com": { @@ -492,12 +505,18 @@ func Test_issuerToChallengeClaim(t *testing.T) { if claim := issuerToChallengeClaim(IssuerTypeGithubWorkflow, ""); claim != "sub" { t.Fatalf("expected sub subject claim for GitHub issuer, got %s", claim) } + if claim := issuerToChallengeClaim(IssuerTypeCIProvider, ""); claim != "sub" { + t.Fatalf("expected sub subject claim for CI issuer, got %s", claim) + } if claim := issuerToChallengeClaim(IssuerTypeGitLabPipeline, ""); claim != "sub" { t.Fatalf("expected sub subject claim for GitLab issuer, got %s", claim) } if claim := issuerToChallengeClaim(IssuerTypeCodefreshWorkflow, ""); claim != "sub" { t.Fatalf("expected sub subject claim for Codefresh issuer, got %s", claim) } + if claim := issuerToChallengeClaim(IssuerTypeChainguard, ""); claim != "sub" { + t.Fatalf("expected sub subject claim for Chainguard issuer, got %s", claim) + } if claim := issuerToChallengeClaim(IssuerTypeKubernetes, ""); claim != "sub" { t.Fatalf("expected sub subject claim for K8S issuer, got %s", claim) } diff --git a/pkg/config/fulcio_config_test.go b/pkg/config/fulcio_config_test.go new file mode 100644 index 000000000..e32bd0455 --- /dev/null +++ b/pkg/config/fulcio_config_test.go @@ -0,0 +1,76 @@ +// Copyright 2024 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. +// + +//go:build !hermetic + +package config + +import ( + "os" + "path/filepath" + "runtime" + "testing" +) + +// The config/identity/config.yaml is a config file that is reflected directly +// to the public good instance. +// This test checks that the config.yaml is valid and can be properly used +// on the public good instance. +func TestLoadFulcioConfig(t *testing.T) { + _, path, _, _ := runtime.Caller(0) + basepath := filepath.Dir(path) + b, err := os.ReadFile(basepath + "/../../config/identity/config.yaml") + if err != nil { + t.Errorf("read file: %v", err) + } + + fulcioConfig, err := Read(b) + if err != nil { + t.Fatal(err) + } + + for issuerURL := range fulcioConfig.OIDCIssuers { + got, ok := fulcioConfig.GetIssuer(issuerURL) + if !ok { + t.Error("expected true, got false") + } + if got.ClientID != "sigstore" { + t.Errorf("expected sigstore, got %s", got.ClientID) + } + if got.IssuerURL != issuerURL { + t.Errorf("expected %s, got %s", issuerURL, got.IssuerURL) + } + if string(got.Type) == "" { + t.Errorf("issuer Type should not be empty") + } + if got.Type == IssuerTypeCIProvider { + if got.CIProvider == "" { + t.Errorf("issuer that is CIProvider field shouldn't be empty when Type is ci-provider") + } + if _, ok := fulcioConfig.CIIssuerMetadata[got.CIProvider]; !ok { + t.Error("issuer with type ci-provider should have the same CI provider name as key for CIIssuerMetadata") + } + } + if _, ok := fulcioConfig.GetIssuer("not_an_issuer"); ok { + t.Error("no error returned from an unconfigured issuer") + } + } + + for _, metaIssuer := range fulcioConfig.MetaIssuers { + if metaIssuer.ClientID != "sigstore" { + t.Errorf("expected sigstore, got %s", metaIssuer.ClientID) + } + } +} diff --git a/pkg/generated/protobuf/fulcio.pb.go b/pkg/generated/protobuf/fulcio.pb.go index d1e1c7f90..f8c21ad97 100644 --- a/pkg/generated/protobuf/fulcio.pb.go +++ b/pkg/generated/protobuf/fulcio.pb.go @@ -15,8 +15,8 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.32.0 -// protoc v4.25.1 +// protoc-gen-go v1.34.2 +// protoc v4.23.1 // source: fulcio.proto package protobuf @@ -927,171 +927,171 @@ var file_fulcio_proto_rawDesc = []byte{ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x9a, 0x02, 0x0a, 0x1f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x9d, 0x02, 0x0a, 0x1f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, - 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4a, 0x0a, 0x0b, 0x63, 0x72, 0x65, + 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4b, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x61, 0x6c, 0x73, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x52, 0x0b, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x61, 0x6c, 0x73, 0x12, 0x5d, 0x0a, 0x12, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, - 0x6b, 0x65, 0x79, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x28, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, - 0x2e, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x76, 0x32, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, - 0x63, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x42, 0x03, 0xe0, 0x41, 0x02, - 0x48, 0x00, 0x52, 0x10, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x45, 0x0a, 0x1b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, - 0x61, 0x74, 0x65, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x72, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x03, 0xe0, 0x41, 0x02, 0x48, 0x00, - 0x52, 0x19, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x53, 0x69, 0x67, - 0x6e, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x42, 0x05, 0x0a, 0x03, 0x6b, - 0x65, 0x79, 0x22, 0x4e, 0x0a, 0x0b, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, - 0x73, 0x12, 0x30, 0x0a, 0x13, 0x6f, 0x69, 0x64, 0x63, 0x5f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x74, 0x79, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, - 0x52, 0x11, 0x6f, 0x69, 0x64, 0x63, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x54, 0x6f, - 0x6b, 0x65, 0x6e, 0x42, 0x0d, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, - 0x6c, 0x73, 0x22, 0x8e, 0x01, 0x0a, 0x10, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x45, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, - 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x64, 0x65, - 0x76, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x66, 0x75, 0x6c, 0x63, 0x69, - 0x6f, 0x2e, 0x76, 0x32, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x42, 0x03, - 0xe0, 0x41, 0x02, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x33, - 0x0a, 0x13, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x5f, 0x6f, 0x66, 0x5f, 0x70, 0x6f, 0x73, 0x73, 0x65, - 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x03, 0xe0, 0x41, 0x02, - 0x52, 0x11, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x4f, 0x66, 0x50, 0x6f, 0x73, 0x73, 0x65, 0x73, 0x73, - 0x69, 0x6f, 0x6e, 0x22, 0x74, 0x0a, 0x09, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, - 0x12, 0x48, 0x0a, 0x09, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0e, 0x32, 0x2a, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, - 0x72, 0x65, 0x2e, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x76, 0x32, 0x2e, 0x50, 0x75, 0x62, - 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x41, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x52, - 0x09, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x12, 0x1d, 0x0a, 0x07, 0x63, 0x6f, - 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x03, 0xe0, 0x41, 0x02, - 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0xa3, 0x02, 0x0a, 0x12, 0x53, 0x69, - 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, - 0x12, 0x7e, 0x0a, 0x1f, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x69, - 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x64, 0x65, 0x74, 0x61, 0x63, 0x68, 0x65, 0x64, 0x5f, - 0x73, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x64, 0x65, 0x76, 0x2e, + 0x61, 0x6c, 0x73, 0x42, 0x04, 0xe2, 0x41, 0x01, 0x02, 0x52, 0x0b, 0x63, 0x72, 0x65, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x12, 0x5e, 0x0a, 0x12, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, + 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, + 0x65, 0x2e, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x76, 0x32, 0x2e, 0x50, 0x75, 0x62, 0x6c, + 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x42, 0x04, 0xe2, 0x41, + 0x01, 0x02, 0x48, 0x00, 0x52, 0x10, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x46, 0x0a, 0x1b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x72, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x04, 0xe2, 0x41, 0x01, + 0x02, 0x48, 0x00, 0x52, 0x19, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, + 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x42, 0x05, + 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x22, 0x4e, 0x0a, 0x0b, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x61, 0x6c, 0x73, 0x12, 0x30, 0x0a, 0x13, 0x6f, 0x69, 0x64, 0x63, 0x5f, 0x69, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x48, 0x00, 0x52, 0x11, 0x6f, 0x69, 0x64, 0x63, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, + 0x79, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x42, 0x0d, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x61, 0x6c, 0x73, 0x22, 0x90, 0x01, 0x0a, 0x10, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, + 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x46, 0x0a, 0x0a, 0x70, 0x75, + 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, + 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x66, 0x75, + 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x76, 0x32, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, + 0x79, 0x42, 0x04, 0xe2, 0x41, 0x01, 0x02, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, + 0x65, 0x79, 0x12, 0x34, 0x0a, 0x13, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x5f, 0x6f, 0x66, 0x5f, 0x70, + 0x6f, 0x73, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x42, + 0x04, 0xe2, 0x41, 0x01, 0x02, 0x52, 0x11, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x4f, 0x66, 0x50, 0x6f, + 0x73, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x75, 0x0a, 0x09, 0x50, 0x75, 0x62, 0x6c, + 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x48, 0x0a, 0x09, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, + 0x68, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2a, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x73, + 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x76, + 0x32, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x41, 0x6c, 0x67, 0x6f, 0x72, + 0x69, 0x74, 0x68, 0x6d, 0x52, 0x09, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x12, + 0x1e, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x42, 0x04, 0xe2, 0x41, 0x01, 0x02, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, + 0xa3, 0x02, 0x0a, 0x12, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x43, 0x65, 0x72, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x7e, 0x0a, 0x1f, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, + 0x5f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x64, 0x65, 0x74, + 0x61, 0x63, 0x68, 0x65, 0x64, 0x5f, 0x73, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x35, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x66, + 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x44, 0x65, 0x74, 0x61, 0x63, + 0x68, 0x65, 0x64, 0x53, 0x43, 0x54, 0x48, 0x00, 0x52, 0x1c, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x44, 0x65, 0x74, 0x61, 0x63, + 0x68, 0x65, 0x64, 0x53, 0x63, 0x74, 0x12, 0x7e, 0x0a, 0x1f, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, + 0x5f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x65, 0x6d, 0x62, + 0x65, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x73, 0x63, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x35, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x66, + 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x45, 0x6d, 0x62, 0x65, 0x64, + 0x64, 0x65, 0x64, 0x53, 0x43, 0x54, 0x48, 0x00, 0x52, 0x1c, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x45, 0x6d, 0x62, 0x65, 0x64, + 0x64, 0x65, 0x64, 0x53, 0x63, 0x74, 0x42, 0x0d, 0x0a, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x65, 0x22, 0xa1, 0x01, 0x0a, 0x1d, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, + 0x67, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x44, 0x65, 0x74, 0x61, + 0x63, 0x68, 0x65, 0x64, 0x53, 0x43, 0x54, 0x12, 0x3e, 0x0a, 0x05, 0x63, 0x68, 0x61, 0x69, 0x6e, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x73, 0x69, 0x67, + 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x76, 0x32, 0x2e, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x69, 0x6e, + 0x52, 0x05, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x12, 0x40, 0x0a, 0x1c, 0x73, 0x69, 0x67, 0x6e, 0x65, + 0x64, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x1a, 0x73, + 0x69, 0x67, 0x6e, 0x65, 0x64, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, + 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x5f, 0x0a, 0x1d, 0x53, 0x69, 0x67, + 0x6e, 0x69, 0x6e, 0x67, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x45, + 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x53, 0x43, 0x54, 0x12, 0x3e, 0x0a, 0x05, 0x63, 0x68, + 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, - 0x76, 0x32, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, - 0x69, 0x63, 0x61, 0x74, 0x65, 0x44, 0x65, 0x74, 0x61, 0x63, 0x68, 0x65, 0x64, 0x53, 0x43, 0x54, - 0x48, 0x00, 0x52, 0x1c, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, - 0x69, 0x63, 0x61, 0x74, 0x65, 0x44, 0x65, 0x74, 0x61, 0x63, 0x68, 0x65, 0x64, 0x53, 0x63, 0x74, - 0x12, 0x7e, 0x0a, 0x1f, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x69, - 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x65, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x5f, - 0x73, 0x63, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x64, 0x65, 0x76, 0x2e, + 0x76, 0x32, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x43, 0x68, + 0x61, 0x69, 0x6e, 0x52, 0x05, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x22, 0x17, 0x0a, 0x15, 0x47, 0x65, + 0x74, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x22, 0x4f, 0x0a, 0x0b, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, + 0x6c, 0x65, 0x12, 0x40, 0x0a, 0x06, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, + 0x65, 0x2e, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x65, 0x72, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x52, 0x06, 0x63, 0x68, + 0x61, 0x69, 0x6e, 0x73, 0x22, 0x36, 0x0a, 0x10, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x65, 0x72, 0x74, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, + 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x22, 0x19, 0x0a, 0x17, + 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x4d, 0x0a, 0x0d, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3c, 0x0a, 0x07, 0x69, 0x73, 0x73, 0x75, + 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, - 0x76, 0x32, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, - 0x69, 0x63, 0x61, 0x74, 0x65, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x53, 0x43, 0x54, - 0x48, 0x00, 0x52, 0x1c, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, - 0x69, 0x63, 0x61, 0x74, 0x65, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, 0x64, 0x53, 0x63, 0x74, - 0x42, 0x0d, 0x0a, 0x0b, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x22, - 0xa1, 0x01, 0x0a, 0x1d, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x43, 0x65, 0x72, 0x74, 0x69, - 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x44, 0x65, 0x74, 0x61, 0x63, 0x68, 0x65, 0x64, 0x53, 0x43, - 0x54, 0x12, 0x3e, 0x0a, 0x05, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x28, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, - 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, - 0x69, 0x63, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x52, 0x05, 0x63, 0x68, 0x61, 0x69, - 0x6e, 0x12, 0x40, 0x0a, 0x1c, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x63, 0x65, 0x72, 0x74, - 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x1a, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x43, - 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x22, 0x5f, 0x0a, 0x1d, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x43, 0x65, - 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x45, 0x6d, 0x62, 0x65, 0x64, 0x64, 0x65, - 0x64, 0x53, 0x43, 0x54, 0x12, 0x3e, 0x0a, 0x05, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, - 0x72, 0x65, 0x2e, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x65, 0x72, - 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x52, 0x05, 0x63, - 0x68, 0x61, 0x69, 0x6e, 0x22, 0x17, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x54, 0x72, 0x75, 0x73, 0x74, - 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x4f, 0x0a, - 0x0b, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x12, 0x40, 0x0a, 0x06, - 0x63, 0x68, 0x61, 0x69, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x64, + 0x76, 0x32, 0x2e, 0x4f, 0x49, 0x44, 0x43, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x52, 0x07, 0x69, + 0x73, 0x73, 0x75, 0x65, 0x72, 0x73, 0x22, 0xde, 0x01, 0x0a, 0x0a, 0x4f, 0x49, 0x44, 0x43, 0x49, + 0x73, 0x73, 0x75, 0x65, 0x72, 0x12, 0x1f, 0x0a, 0x0a, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x5f, + 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x09, 0x69, 0x73, 0x73, + 0x75, 0x65, 0x72, 0x55, 0x72, 0x6c, 0x12, 0x30, 0x0a, 0x13, 0x77, 0x69, 0x6c, 0x64, 0x63, 0x61, + 0x72, 0x64, 0x5f, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x11, 0x77, 0x69, 0x6c, 0x64, 0x63, 0x61, 0x72, 0x64, 0x49, + 0x73, 0x73, 0x75, 0x65, 0x72, 0x55, 0x72, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x75, 0x64, 0x69, + 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x61, 0x75, 0x64, 0x69, + 0x65, 0x6e, 0x63, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, + 0x65, 0x5f, 0x63, 0x6c, 0x61, 0x69, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, + 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x12, 0x2e, 0x0a, + 0x13, 0x73, 0x70, 0x69, 0x66, 0x66, 0x65, 0x5f, 0x74, 0x72, 0x75, 0x73, 0x74, 0x5f, 0x64, 0x6f, + 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x73, 0x70, 0x69, 0x66, + 0x66, 0x65, 0x54, 0x72, 0x75, 0x73, 0x74, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x42, 0x08, 0x0a, + 0x06, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x2a, 0x5f, 0x0a, 0x12, 0x50, 0x75, 0x62, 0x6c, 0x69, + 0x63, 0x4b, 0x65, 0x79, 0x41, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x12, 0x24, 0x0a, + 0x20, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x41, 0x4c, 0x47, 0x4f, + 0x52, 0x49, 0x54, 0x48, 0x4d, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, + 0x44, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x52, 0x53, 0x41, 0x5f, 0x50, 0x53, 0x53, 0x10, 0x01, + 0x12, 0x09, 0x0a, 0x05, 0x45, 0x43, 0x44, 0x53, 0x41, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x45, + 0x44, 0x32, 0x35, 0x35, 0x31, 0x39, 0x10, 0x03, 0x32, 0xb6, 0x03, 0x0a, 0x02, 0x43, 0x41, 0x12, + 0x9f, 0x01, 0x0a, 0x18, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, + 0x67, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x37, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x66, 0x75, 0x6c, 0x63, - 0x69, 0x6f, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, - 0x65, 0x43, 0x68, 0x61, 0x69, 0x6e, 0x52, 0x06, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x73, 0x22, 0x36, - 0x0a, 0x10, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, - 0x69, 0x6e, 0x12, 0x22, 0x0a, 0x0c, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, - 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, - 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x22, 0x19, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x22, 0x4d, 0x0a, 0x0d, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x12, 0x3c, 0x0a, 0x07, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, - 0x72, 0x65, 0x2e, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x76, 0x32, 0x2e, 0x4f, 0x49, 0x44, - 0x43, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x52, 0x07, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x73, - 0x22, 0xde, 0x01, 0x0a, 0x0a, 0x4f, 0x49, 0x44, 0x43, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x12, - 0x1f, 0x0a, 0x0a, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x09, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x55, 0x72, 0x6c, - 0x12, 0x30, 0x0a, 0x13, 0x77, 0x69, 0x6c, 0x64, 0x63, 0x61, 0x72, 0x64, 0x5f, 0x69, 0x73, 0x73, - 0x75, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, - 0x11, 0x77, 0x69, 0x6c, 0x64, 0x63, 0x61, 0x72, 0x64, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x55, - 0x72, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x75, 0x64, 0x69, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x61, 0x75, 0x64, 0x69, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x27, - 0x0a, 0x0f, 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x5f, 0x63, 0x6c, 0x61, 0x69, - 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, - 0x67, 0x65, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x12, 0x2e, 0x0a, 0x13, 0x73, 0x70, 0x69, 0x66, 0x66, - 0x65, 0x5f, 0x74, 0x72, 0x75, 0x73, 0x74, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x73, 0x70, 0x69, 0x66, 0x66, 0x65, 0x54, 0x72, 0x75, 0x73, - 0x74, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x42, 0x08, 0x0a, 0x06, 0x69, 0x73, 0x73, 0x75, 0x65, - 0x72, 0x2a, 0x5f, 0x0a, 0x12, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x41, 0x6c, - 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x12, 0x24, 0x0a, 0x20, 0x50, 0x55, 0x42, 0x4c, 0x49, - 0x43, 0x5f, 0x4b, 0x45, 0x59, 0x5f, 0x41, 0x4c, 0x47, 0x4f, 0x52, 0x49, 0x54, 0x48, 0x4d, 0x5f, - 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0b, 0x0a, - 0x07, 0x52, 0x53, 0x41, 0x5f, 0x50, 0x53, 0x53, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x43, - 0x44, 0x53, 0x41, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x45, 0x44, 0x32, 0x35, 0x35, 0x31, 0x39, - 0x10, 0x03, 0x32, 0xb6, 0x03, 0x0a, 0x02, 0x43, 0x41, 0x12, 0x9f, 0x01, 0x0a, 0x18, 0x43, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x43, 0x65, 0x72, 0x74, 0x69, - 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x37, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x73, 0x69, 0x67, - 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x76, 0x32, 0x2e, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x43, 0x65, 0x72, - 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x2a, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x66, - 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x76, 0x32, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, - 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x22, 0x1e, 0x82, 0xd3, 0xe4, - 0x93, 0x02, 0x18, 0x3a, 0x01, 0x2a, 0x22, 0x13, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x2f, - 0x73, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x43, 0x65, 0x72, 0x74, 0x12, 0x81, 0x01, 0x0a, 0x0e, - 0x47, 0x65, 0x74, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x12, 0x2d, - 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x66, 0x75, - 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x72, 0x75, 0x73, 0x74, - 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, - 0x64, 0x65, 0x76, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x66, 0x75, 0x6c, - 0x63, 0x69, 0x6f, 0x2e, 0x76, 0x32, 0x2e, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, - 0x6c, 0x65, 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x12, 0x13, 0x2f, 0x61, 0x70, 0x69, - 0x2f, 0x76, 0x32, 0x2f, 0x74, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x12, - 0x89, 0x01, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2f, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, + 0x69, 0x6f, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x69, 0x67, 0x6e, + 0x69, 0x6e, 0x67, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2a, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x73, 0x69, 0x67, 0x73, + 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x76, 0x32, 0x2e, 0x53, + 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x65, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x3a, 0x01, 0x2a, 0x22, 0x13, 0x2f, 0x61, + 0x70, 0x69, 0x2f, 0x76, 0x32, 0x2f, 0x73, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x43, 0x65, 0x72, + 0x74, 0x12, 0x81, 0x01, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, + 0x6e, 0x64, 0x6c, 0x65, 0x12, 0x2d, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65, - 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x73, 0x69, 0x67, 0x73, - 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x76, 0x32, 0x2e, 0x43, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x1d, 0x82, 0xd3, - 0xe4, 0x93, 0x02, 0x17, 0x12, 0x15, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x2f, 0x63, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x8f, 0x03, 0x92, 0x41, - 0xb1, 0x02, 0x12, 0xb9, 0x01, 0x0a, 0x06, 0x46, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x22, 0x5c, 0x0a, - 0x17, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x46, 0x75, 0x6c, 0x63, 0x69, 0x6f, - 0x20, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x22, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, - 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x69, 0x67, - 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x1a, 0x1d, 0x73, 0x69, - 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2d, 0x64, 0x65, 0x76, 0x40, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2a, 0x4a, 0x0a, 0x12, 0x41, - 0x70, 0x61, 0x63, 0x68, 0x65, 0x20, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x20, 0x32, 0x2e, - 0x30, 0x12, 0x34, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, - 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x66, - 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2f, 0x62, 0x6c, 0x6f, 0x62, 0x2f, 0x6d, 0x61, 0x69, 0x6e, 0x2f, - 0x4c, 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45, 0x32, 0x05, 0x32, 0x2e, 0x30, 0x2e, 0x30, 0x1a, 0x13, - 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, - 0x64, 0x65, 0x76, 0x2a, 0x01, 0x01, 0x32, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x3a, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x72, 0x37, 0x0a, 0x11, 0x4d, 0x6f, - 0x72, 0x65, 0x20, 0x61, 0x62, 0x6f, 0x75, 0x74, 0x20, 0x46, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x12, - 0x22, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, - 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x66, 0x75, 0x6c, - 0x63, 0x69, 0x6f, 0x0a, 0x16, 0x64, 0x65, 0x76, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, - 0x65, 0x2e, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x76, 0x32, 0x42, 0x0b, 0x46, 0x75, 0x6c, - 0x63, 0x69, 0x6f, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x31, 0x67, 0x69, 0x74, 0x68, - 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, - 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x67, 0x65, 0x6e, 0x65, 0x72, - 0x61, 0x74, 0x65, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x74, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, + 0x72, 0x65, 0x2e, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x76, 0x32, 0x2e, 0x54, 0x72, 0x75, + 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, + 0x12, 0x13, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x32, 0x2f, 0x74, 0x72, 0x75, 0x73, 0x74, 0x42, + 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x12, 0x89, 0x01, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2f, 0x2e, 0x64, 0x65, 0x76, + 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, + 0x2e, 0x76, 0x32, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x64, 0x65, + 0x76, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x66, 0x75, 0x6c, 0x63, 0x69, + 0x6f, 0x2e, 0x76, 0x32, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x12, 0x15, 0x2f, 0x61, 0x70, 0x69, + 0x2f, 0x76, 0x32, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x42, 0x8f, 0x03, 0x92, 0x41, 0xb1, 0x02, 0x12, 0xb9, 0x01, 0x0a, 0x06, 0x46, 0x75, 0x6c, + 0x63, 0x69, 0x6f, 0x22, 0x5c, 0x0a, 0x17, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x20, + 0x46, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x20, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x22, + 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x66, 0x75, 0x6c, 0x63, + 0x69, 0x6f, 0x1a, 0x1d, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2d, 0x64, 0x65, 0x76, + 0x40, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x2e, 0x63, 0x6f, + 0x6d, 0x2a, 0x4a, 0x0a, 0x12, 0x41, 0x70, 0x61, 0x63, 0x68, 0x65, 0x20, 0x4c, 0x69, 0x63, 0x65, + 0x6e, 0x73, 0x65, 0x20, 0x32, 0x2e, 0x30, 0x12, 0x34, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, + 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x69, 0x67, 0x73, + 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2f, 0x62, 0x6c, 0x6f, 0x62, + 0x2f, 0x6d, 0x61, 0x69, 0x6e, 0x2f, 0x4c, 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45, 0x32, 0x05, 0x32, + 0x2e, 0x30, 0x2e, 0x30, 0x1a, 0x13, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x73, 0x69, 0x67, + 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x64, 0x65, 0x76, 0x2a, 0x01, 0x01, 0x32, 0x10, 0x61, 0x70, + 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x3a, 0x10, + 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, + 0x72, 0x37, 0x0a, 0x11, 0x4d, 0x6f, 0x72, 0x65, 0x20, 0x61, 0x62, 0x6f, 0x75, 0x74, 0x20, 0x46, + 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x12, 0x22, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, + 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, + 0x72, 0x65, 0x2f, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x0a, 0x16, 0x64, 0x65, 0x76, 0x2e, 0x73, + 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x76, + 0x32, 0x42, 0x0b, 0x46, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, + 0x5a, 0x31, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x69, 0x67, + 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2f, 0x70, 0x6b, 0x67, + 0x2f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1108,7 +1108,7 @@ func file_fulcio_proto_rawDescGZIP() []byte { var file_fulcio_proto_enumTypes = make([]protoimpl.EnumInfo, 1) var file_fulcio_proto_msgTypes = make([]protoimpl.MessageInfo, 13) -var file_fulcio_proto_goTypes = []interface{}{ +var file_fulcio_proto_goTypes = []any{ (PublicKeyAlgorithm)(0), // 0: dev.sigstore.fulcio.v2.PublicKeyAlgorithm (*CreateSigningCertificateRequest)(nil), // 1: dev.sigstore.fulcio.v2.CreateSigningCertificateRequest (*Credentials)(nil), // 2: dev.sigstore.fulcio.v2.Credentials @@ -1154,7 +1154,7 @@ func file_fulcio_proto_init() { return } if !protoimpl.UnsafeEnabled { - file_fulcio_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_fulcio_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*CreateSigningCertificateRequest); i { case 0: return &v.state @@ -1166,7 +1166,7 @@ func file_fulcio_proto_init() { return nil } } - file_fulcio_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + file_fulcio_proto_msgTypes[1].Exporter = func(v any, i int) any { switch v := v.(*Credentials); i { case 0: return &v.state @@ -1178,7 +1178,7 @@ func file_fulcio_proto_init() { return nil } } - file_fulcio_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + file_fulcio_proto_msgTypes[2].Exporter = func(v any, i int) any { switch v := v.(*PublicKeyRequest); i { case 0: return &v.state @@ -1190,7 +1190,7 @@ func file_fulcio_proto_init() { return nil } } - file_fulcio_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + file_fulcio_proto_msgTypes[3].Exporter = func(v any, i int) any { switch v := v.(*PublicKey); i { case 0: return &v.state @@ -1202,7 +1202,7 @@ func file_fulcio_proto_init() { return nil } } - file_fulcio_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + file_fulcio_proto_msgTypes[4].Exporter = func(v any, i int) any { switch v := v.(*SigningCertificate); i { case 0: return &v.state @@ -1214,7 +1214,7 @@ func file_fulcio_proto_init() { return nil } } - file_fulcio_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + file_fulcio_proto_msgTypes[5].Exporter = func(v any, i int) any { switch v := v.(*SigningCertificateDetachedSCT); i { case 0: return &v.state @@ -1226,7 +1226,7 @@ func file_fulcio_proto_init() { return nil } } - file_fulcio_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + file_fulcio_proto_msgTypes[6].Exporter = func(v any, i int) any { switch v := v.(*SigningCertificateEmbeddedSCT); i { case 0: return &v.state @@ -1238,7 +1238,7 @@ func file_fulcio_proto_init() { return nil } } - file_fulcio_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + file_fulcio_proto_msgTypes[7].Exporter = func(v any, i int) any { switch v := v.(*GetTrustBundleRequest); i { case 0: return &v.state @@ -1250,7 +1250,7 @@ func file_fulcio_proto_init() { return nil } } - file_fulcio_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + file_fulcio_proto_msgTypes[8].Exporter = func(v any, i int) any { switch v := v.(*TrustBundle); i { case 0: return &v.state @@ -1262,7 +1262,7 @@ func file_fulcio_proto_init() { return nil } } - file_fulcio_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + file_fulcio_proto_msgTypes[9].Exporter = func(v any, i int) any { switch v := v.(*CertificateChain); i { case 0: return &v.state @@ -1274,7 +1274,7 @@ func file_fulcio_proto_init() { return nil } } - file_fulcio_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + file_fulcio_proto_msgTypes[10].Exporter = func(v any, i int) any { switch v := v.(*GetConfigurationRequest); i { case 0: return &v.state @@ -1286,7 +1286,7 @@ func file_fulcio_proto_init() { return nil } } - file_fulcio_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + file_fulcio_proto_msgTypes[11].Exporter = func(v any, i int) any { switch v := v.(*Configuration); i { case 0: return &v.state @@ -1298,7 +1298,7 @@ func file_fulcio_proto_init() { return nil } } - file_fulcio_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + file_fulcio_proto_msgTypes[12].Exporter = func(v any, i int) any { switch v := v.(*OIDCIssuer); i { case 0: return &v.state @@ -1311,18 +1311,18 @@ func file_fulcio_proto_init() { } } } - file_fulcio_proto_msgTypes[0].OneofWrappers = []interface{}{ + file_fulcio_proto_msgTypes[0].OneofWrappers = []any{ (*CreateSigningCertificateRequest_PublicKeyRequest)(nil), (*CreateSigningCertificateRequest_CertificateSigningRequest)(nil), } - file_fulcio_proto_msgTypes[1].OneofWrappers = []interface{}{ + file_fulcio_proto_msgTypes[1].OneofWrappers = []any{ (*Credentials_OidcIdentityToken)(nil), } - file_fulcio_proto_msgTypes[4].OneofWrappers = []interface{}{ + file_fulcio_proto_msgTypes[4].OneofWrappers = []any{ (*SigningCertificate_SignedCertificateDetachedSct)(nil), (*SigningCertificate_SignedCertificateEmbeddedSct)(nil), } - file_fulcio_proto_msgTypes[12].OneofWrappers = []interface{}{ + file_fulcio_proto_msgTypes[12].OneofWrappers = []any{ (*OIDCIssuer_IssuerUrl)(nil), (*OIDCIssuer_WildcardIssuerUrl)(nil), } diff --git a/pkg/generated/protobuf/fulcio.pb.gw.go b/pkg/generated/protobuf/fulcio.pb.gw.go index 93ad4f54e..2500e0c87 100644 --- a/pkg/generated/protobuf/fulcio.pb.gw.go +++ b/pkg/generated/protobuf/fulcio.pb.gw.go @@ -97,6 +97,7 @@ func local_request_CA_GetConfiguration_0(ctx context.Context, marshaler runtime. // UnaryRPC :call CAServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. // Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterCAHandlerFromEndpoint instead. +// GRPC interceptors will not work for this type of registration. To use interceptors, you must use the "runtime.WithMiddlewares" option in the "runtime.NewServeMux" call. func RegisterCAHandlerServer(ctx context.Context, mux *runtime.ServeMux, server CAServer) error { mux.Handle("POST", pattern_CA_CreateSigningCertificate_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { @@ -180,21 +181,21 @@ func RegisterCAHandlerServer(ctx context.Context, mux *runtime.ServeMux, server // RegisterCAHandlerFromEndpoint is same as RegisterCAHandler but // automatically dials to "endpoint" and closes the connection when "ctx" gets done. func RegisterCAHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { - conn, err := grpc.DialContext(ctx, endpoint, opts...) + conn, err := grpc.NewClient(endpoint, opts...) if err != nil { return err } defer func() { if err != nil { if cerr := conn.Close(); cerr != nil { - grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + grpclog.Errorf("Failed to close conn to %s: %v", endpoint, cerr) } return } go func() { <-ctx.Done() if cerr := conn.Close(); cerr != nil { - grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + grpclog.Errorf("Failed to close conn to %s: %v", endpoint, cerr) } }() }() @@ -212,7 +213,7 @@ func RegisterCAHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.Cl // to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "CAClient". // Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "CAClient" // doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in -// "CAClient" to call the correct interceptors. +// "CAClient" to call the correct interceptors. This client ignores the HTTP middlewares. func RegisterCAHandlerClient(ctx context.Context, mux *runtime.ServeMux, client CAClient) error { mux.Handle("POST", pattern_CA_CreateSigningCertificate_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { diff --git a/pkg/generated/protobuf/fulcio_grpc.pb.go b/pkg/generated/protobuf/fulcio_grpc.pb.go index 986ee6e60..96f6e1b89 100644 --- a/pkg/generated/protobuf/fulcio_grpc.pb.go +++ b/pkg/generated/protobuf/fulcio_grpc.pb.go @@ -15,8 +15,8 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.3.0 -// - protoc v4.25.1 +// - protoc-gen-go-grpc v1.5.1 +// - protoc v4.23.1 // source: fulcio.proto package protobuf @@ -30,8 +30,8 @@ import ( // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 const ( CA_CreateSigningCertificate_FullMethodName = "/dev.sigstore.fulcio.v2.CA/CreateSigningCertificate" @@ -63,8 +63,9 @@ func NewCAClient(cc grpc.ClientConnInterface) CAClient { } func (c *cAClient) CreateSigningCertificate(ctx context.Context, in *CreateSigningCertificateRequest, opts ...grpc.CallOption) (*SigningCertificate, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(SigningCertificate) - err := c.cc.Invoke(ctx, CA_CreateSigningCertificate_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, CA_CreateSigningCertificate_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -72,8 +73,9 @@ func (c *cAClient) CreateSigningCertificate(ctx context.Context, in *CreateSigni } func (c *cAClient) GetTrustBundle(ctx context.Context, in *GetTrustBundleRequest, opts ...grpc.CallOption) (*TrustBundle, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(TrustBundle) - err := c.cc.Invoke(ctx, CA_GetTrustBundle_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, CA_GetTrustBundle_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -81,8 +83,9 @@ func (c *cAClient) GetTrustBundle(ctx context.Context, in *GetTrustBundleRequest } func (c *cAClient) GetConfiguration(ctx context.Context, in *GetConfigurationRequest, opts ...grpc.CallOption) (*Configuration, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Configuration) - err := c.cc.Invoke(ctx, CA_GetConfiguration_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, CA_GetConfiguration_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -91,7 +94,7 @@ func (c *cAClient) GetConfiguration(ctx context.Context, in *GetConfigurationReq // CAServer is the server API for CA service. // All implementations must embed UnimplementedCAServer -// for forward compatibility +// for forward compatibility. type CAServer interface { // * // Returns an X.509 certificate created by the Fulcio certificate authority for the given request parameters @@ -105,9 +108,12 @@ type CAServer interface { mustEmbedUnimplementedCAServer() } -// UnimplementedCAServer must be embedded to have forward compatible implementations. -type UnimplementedCAServer struct { -} +// UnimplementedCAServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedCAServer struct{} func (UnimplementedCAServer) CreateSigningCertificate(context.Context, *CreateSigningCertificateRequest) (*SigningCertificate, error) { return nil, status.Errorf(codes.Unimplemented, "method CreateSigningCertificate not implemented") @@ -119,6 +125,7 @@ func (UnimplementedCAServer) GetConfiguration(context.Context, *GetConfiguration return nil, status.Errorf(codes.Unimplemented, "method GetConfiguration not implemented") } func (UnimplementedCAServer) mustEmbedUnimplementedCAServer() {} +func (UnimplementedCAServer) testEmbeddedByValue() {} // UnsafeCAServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to CAServer will @@ -128,6 +135,13 @@ type UnsafeCAServer interface { } func RegisterCAServer(s grpc.ServiceRegistrar, srv CAServer) { + // If the following call pancis, it indicates UnimplementedCAServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&CA_ServiceDesc, srv) } diff --git a/pkg/generated/protobuf/legacy/fulcio_legacy.pb.go b/pkg/generated/protobuf/legacy/fulcio_legacy.pb.go index 4970f61ed..c0ab3e4fd 100644 --- a/pkg/generated/protobuf/legacy/fulcio_legacy.pb.go +++ b/pkg/generated/protobuf/legacy/fulcio_legacy.pb.go @@ -15,8 +15,8 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.32.0 -// protoc v4.25.1 +// protoc-gen-go v1.34.2 +// protoc v4.23.1 // source: fulcio_legacy.proto package legacy @@ -201,69 +201,69 @@ var file_fulcio_legacy_proto_rawDesc = []byte{ 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xe9, 0x01, 0x0a, 0x1f, 0x43, 0x72, 0x65, + 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xec, 0x01, 0x0a, 0x1f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, - 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4a, 0x0a, 0x09, + 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4b, 0x0a, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x2e, 0x50, 0x75, 0x62, - 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x42, 0x05, 0xe0, 0x41, 0x01, 0x18, 0x01, 0x52, 0x09, 0x70, - 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x35, 0x0a, 0x12, 0x73, 0x69, 0x67, 0x6e, - 0x65, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0c, 0x42, 0x05, 0xe0, 0x41, 0x01, 0x18, 0x01, 0x52, 0x12, 0x73, 0x69, 0x67, - 0x6e, 0x65, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, - 0x43, 0x0a, 0x19, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x53, 0x69, - 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0c, 0x42, 0x05, 0xe0, 0x41, 0x01, 0x18, 0x01, 0x52, 0x19, 0x63, 0x65, 0x72, 0x74, 0x69, - 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x22, 0x4e, 0x0a, 0x09, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, - 0x79, 0x12, 0x20, 0x0a, 0x09, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x09, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, - 0x74, 0x68, 0x6d, 0x12, 0x1f, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0c, 0x42, 0x05, 0xe0, 0x41, 0x02, 0x18, 0x01, 0x52, 0x07, 0x63, 0x6f, 0x6e, - 0x74, 0x65, 0x6e, 0x74, 0x32, 0xf8, 0x01, 0x0a, 0x02, 0x43, 0x41, 0x12, 0x90, 0x01, 0x0a, 0x18, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x43, 0x65, 0x72, - 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x3b, 0x2e, 0x64, 0x65, 0x76, 0x2e, 0x73, - 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x76, - 0x31, 0x62, 0x65, 0x74, 0x61, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x69, 0x67, 0x6e, - 0x69, 0x6e, 0x67, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, - 0x70, 0x69, 0x2e, 0x48, 0x74, 0x74, 0x70, 0x42, 0x6f, 0x64, 0x79, 0x22, 0x21, 0x82, 0xd3, 0xe4, - 0x93, 0x02, 0x18, 0x3a, 0x01, 0x2a, 0x22, 0x13, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, - 0x73, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x43, 0x65, 0x72, 0x74, 0x88, 0x02, 0x01, 0x12, 0x5f, - 0x0a, 0x12, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x6f, 0x74, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, - 0x63, 0x61, 0x74, 0x65, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x14, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x48, 0x74, 0x74, 0x70, 0x42, 0x6f, - 0x64, 0x79, 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x12, 0x10, 0x2f, 0x61, 0x70, 0x69, - 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x6f, 0x6f, 0x74, 0x43, 0x65, 0x72, 0x74, 0x88, 0x02, 0x01, 0x42, - 0xa1, 0x03, 0x92, 0x41, 0xb8, 0x02, 0x12, 0xc0, 0x01, 0x0a, 0x0d, 0x46, 0x75, 0x6c, 0x63, 0x69, - 0x6f, 0x20, 0x4c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x22, 0x5c, 0x0a, 0x17, 0x73, 0x69, 0x67, 0x73, - 0x74, 0x6f, 0x72, 0x65, 0x20, 0x46, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x20, 0x70, 0x72, 0x6f, 0x6a, - 0x65, 0x63, 0x74, 0x12, 0x22, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, - 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, - 0x2f, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x1a, 0x1d, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, - 0x65, 0x2d, 0x64, 0x65, 0x76, 0x40, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x67, 0x72, 0x6f, 0x75, - 0x70, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2a, 0x4a, 0x0a, 0x12, 0x41, 0x70, 0x61, 0x63, 0x68, 0x65, - 0x20, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x20, 0x32, 0x2e, 0x30, 0x12, 0x34, 0x68, 0x74, - 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, - 0x2f, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, - 0x2f, 0x62, 0x6c, 0x6f, 0x62, 0x2f, 0x6d, 0x61, 0x69, 0x6e, 0x2f, 0x4c, 0x49, 0x43, 0x45, 0x4e, - 0x53, 0x45, 0x32, 0x05, 0x31, 0x2e, 0x30, 0x2e, 0x30, 0x1a, 0x13, 0x66, 0x75, 0x6c, 0x63, 0x69, - 0x6f, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x64, 0x65, 0x76, 0x2a, 0x01, - 0x01, 0x32, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6a, - 0x73, 0x6f, 0x6e, 0x3a, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x72, 0x37, 0x0a, 0x11, 0x4d, 0x6f, 0x72, 0x65, 0x20, 0x61, 0x62, - 0x6f, 0x75, 0x74, 0x20, 0x46, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x12, 0x22, 0x68, 0x74, 0x74, 0x70, - 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, - 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x0a, 0x1a, - 0x64, 0x65, 0x76, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x66, 0x75, 0x6c, - 0x63, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x42, 0x0b, 0x46, 0x75, 0x6c, 0x63, - 0x69, 0x6f, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x38, 0x67, 0x69, 0x74, 0x68, 0x75, - 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x66, - 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, - 0x74, 0x65, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x6c, 0x65, 0x67, - 0x61, 0x63, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x42, 0x06, 0xe2, 0x41, 0x01, 0x01, 0x18, 0x01, 0x52, 0x09, + 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x36, 0x0a, 0x12, 0x73, 0x69, 0x67, + 0x6e, 0x65, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0xe2, 0x41, 0x01, 0x01, 0x18, 0x01, 0x52, 0x12, 0x73, + 0x69, 0x67, 0x6e, 0x65, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x12, 0x44, 0x0a, 0x19, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, + 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0xe2, 0x41, 0x01, 0x01, 0x18, 0x01, 0x52, 0x19, 0x63, 0x65, + 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x4f, 0x0a, 0x09, 0x50, 0x75, 0x62, 0x6c, 0x69, + 0x63, 0x4b, 0x65, 0x79, 0x12, 0x20, 0x0a, 0x09, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, + 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x09, 0x61, 0x6c, 0x67, + 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x12, 0x20, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0xe2, 0x41, 0x01, 0x02, 0x18, 0x01, 0x52, + 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x32, 0xf8, 0x01, 0x0a, 0x02, 0x43, 0x41, 0x12, + 0x90, 0x01, 0x0a, 0x18, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, + 0x67, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x3b, 0x2e, 0x64, + 0x65, 0x76, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x66, 0x75, 0x6c, 0x63, + 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x48, 0x74, 0x74, 0x70, 0x42, 0x6f, 0x64, 0x79, 0x22, + 0x21, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x3a, 0x01, 0x2a, 0x22, 0x13, 0x2f, 0x61, 0x70, 0x69, + 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x43, 0x65, 0x72, 0x74, 0x88, + 0x02, 0x01, 0x12, 0x5f, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x6f, 0x74, 0x43, 0x65, 0x72, + 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, + 0x1a, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x48, 0x74, + 0x74, 0x70, 0x42, 0x6f, 0x64, 0x79, 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x12, 0x10, + 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x72, 0x6f, 0x6f, 0x74, 0x43, 0x65, 0x72, 0x74, + 0x88, 0x02, 0x01, 0x42, 0xa1, 0x03, 0x92, 0x41, 0xb8, 0x02, 0x12, 0xc0, 0x01, 0x0a, 0x0d, 0x46, + 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x20, 0x4c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x22, 0x5c, 0x0a, 0x17, + 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x46, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x20, + 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x22, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, + 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x69, 0x67, 0x73, + 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x1a, 0x1d, 0x73, 0x69, 0x67, + 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2d, 0x64, 0x65, 0x76, 0x40, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2a, 0x4a, 0x0a, 0x12, 0x41, 0x70, + 0x61, 0x63, 0x68, 0x65, 0x20, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x20, 0x32, 0x2e, 0x30, + 0x12, 0x34, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x66, 0x75, + 0x6c, 0x63, 0x69, 0x6f, 0x2f, 0x62, 0x6c, 0x6f, 0x62, 0x2f, 0x6d, 0x61, 0x69, 0x6e, 0x2f, 0x4c, + 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45, 0x32, 0x05, 0x31, 0x2e, 0x30, 0x2e, 0x30, 0x1a, 0x13, 0x66, + 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x64, + 0x65, 0x76, 0x2a, 0x01, 0x01, 0x32, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x3a, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x72, 0x37, 0x0a, 0x11, 0x4d, 0x6f, 0x72, + 0x65, 0x20, 0x61, 0x62, 0x6f, 0x75, 0x74, 0x20, 0x46, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x12, 0x22, + 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x66, 0x75, 0x6c, 0x63, + 0x69, 0x6f, 0x0a, 0x1a, 0x64, 0x65, 0x76, 0x2e, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, 0x72, 0x65, + 0x2e, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x42, 0x0b, + 0x46, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x38, 0x67, + 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x69, 0x67, 0x73, 0x74, 0x6f, + 0x72, 0x65, 0x2f, 0x66, 0x75, 0x6c, 0x63, 0x69, 0x6f, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x67, 0x65, + 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2f, 0x6c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -279,7 +279,7 @@ func file_fulcio_legacy_proto_rawDescGZIP() []byte { } var file_fulcio_legacy_proto_msgTypes = make([]protoimpl.MessageInfo, 2) -var file_fulcio_legacy_proto_goTypes = []interface{}{ +var file_fulcio_legacy_proto_goTypes = []any{ (*CreateSigningCertificateRequest)(nil), // 0: dev.sigstore.fulcio.v1beta.CreateSigningCertificateRequest (*PublicKey)(nil), // 1: dev.sigstore.fulcio.v1beta.PublicKey (*emptypb.Empty)(nil), // 2: google.protobuf.Empty @@ -304,7 +304,7 @@ func file_fulcio_legacy_proto_init() { return } if !protoimpl.UnsafeEnabled { - file_fulcio_legacy_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_fulcio_legacy_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*CreateSigningCertificateRequest); i { case 0: return &v.state @@ -316,7 +316,7 @@ func file_fulcio_legacy_proto_init() { return nil } } - file_fulcio_legacy_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + file_fulcio_legacy_proto_msgTypes[1].Exporter = func(v any, i int) any { switch v := v.(*PublicKey); i { case 0: return &v.state diff --git a/pkg/generated/protobuf/legacy/fulcio_legacy.pb.gw.go b/pkg/generated/protobuf/legacy/fulcio_legacy.pb.gw.go index 62ea4deba..91a24cdf7 100644 --- a/pkg/generated/protobuf/legacy/fulcio_legacy.pb.gw.go +++ b/pkg/generated/protobuf/legacy/fulcio_legacy.pb.gw.go @@ -80,6 +80,7 @@ func local_request_CA_GetRootCertificate_0(ctx context.Context, marshaler runtim // UnaryRPC :call CAServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. // Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterCAHandlerFromEndpoint instead. +// GRPC interceptors will not work for this type of registration. To use interceptors, you must use the "runtime.WithMiddlewares" option in the "runtime.NewServeMux" call. func RegisterCAHandlerServer(ctx context.Context, mux *runtime.ServeMux, server CAServer) error { mux.Handle("POST", pattern_CA_CreateSigningCertificate_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { @@ -138,21 +139,21 @@ func RegisterCAHandlerServer(ctx context.Context, mux *runtime.ServeMux, server // RegisterCAHandlerFromEndpoint is same as RegisterCAHandler but // automatically dials to "endpoint" and closes the connection when "ctx" gets done. func RegisterCAHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { - conn, err := grpc.DialContext(ctx, endpoint, opts...) + conn, err := grpc.NewClient(endpoint, opts...) if err != nil { return err } defer func() { if err != nil { if cerr := conn.Close(); cerr != nil { - grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + grpclog.Errorf("Failed to close conn to %s: %v", endpoint, cerr) } return } go func() { <-ctx.Done() if cerr := conn.Close(); cerr != nil { - grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + grpclog.Errorf("Failed to close conn to %s: %v", endpoint, cerr) } }() }() @@ -170,7 +171,7 @@ func RegisterCAHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.Cl // to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "CAClient". // Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "CAClient" // doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in -// "CAClient" to call the correct interceptors. +// "CAClient" to call the correct interceptors. This client ignores the HTTP middlewares. func RegisterCAHandlerClient(ctx context.Context, mux *runtime.ServeMux, client CAClient) error { mux.Handle("POST", pattern_CA_CreateSigningCertificate_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { diff --git a/pkg/generated/protobuf/legacy/fulcio_legacy_grpc.pb.go b/pkg/generated/protobuf/legacy/fulcio_legacy_grpc.pb.go index 05b94adcc..3a251afbb 100644 --- a/pkg/generated/protobuf/legacy/fulcio_legacy_grpc.pb.go +++ b/pkg/generated/protobuf/legacy/fulcio_legacy_grpc.pb.go @@ -15,8 +15,8 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.3.0 -// - protoc v4.25.1 +// - protoc-gen-go-grpc v1.5.1 +// - protoc v4.23.1 // source: fulcio_legacy.proto package legacy @@ -32,8 +32,8 @@ import ( // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 const ( CA_CreateSigningCertificate_FullMethodName = "/dev.sigstore.fulcio.v1beta.CA/CreateSigningCertificate" @@ -43,6 +43,9 @@ const ( // CAClient is the client API for CA service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// This implements the pre-GA HTTP-based Fulcio API. +// This interface is deprecated and will only receive backports of security-related features - clients should prefer the GA GRPC interface! type CAClient interface { // Deprecated: Do not use. // @@ -64,8 +67,9 @@ func NewCAClient(cc grpc.ClientConnInterface) CAClient { // Deprecated: Do not use. func (c *cAClient) CreateSigningCertificate(ctx context.Context, in *CreateSigningCertificateRequest, opts ...grpc.CallOption) (*httpbody.HttpBody, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(httpbody.HttpBody) - err := c.cc.Invoke(ctx, CA_CreateSigningCertificate_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, CA_CreateSigningCertificate_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -74,8 +78,9 @@ func (c *cAClient) CreateSigningCertificate(ctx context.Context, in *CreateSigni // Deprecated: Do not use. func (c *cAClient) GetRootCertificate(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*httpbody.HttpBody, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(httpbody.HttpBody) - err := c.cc.Invoke(ctx, CA_GetRootCertificate_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, CA_GetRootCertificate_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } @@ -84,7 +89,10 @@ func (c *cAClient) GetRootCertificate(ctx context.Context, in *emptypb.Empty, op // CAServer is the server API for CA service. // All implementations must embed UnimplementedCAServer -// for forward compatibility +// for forward compatibility. +// +// This implements the pre-GA HTTP-based Fulcio API. +// This interface is deprecated and will only receive backports of security-related features - clients should prefer the GA GRPC interface! type CAServer interface { // Deprecated: Do not use. // @@ -97,9 +105,12 @@ type CAServer interface { mustEmbedUnimplementedCAServer() } -// UnimplementedCAServer must be embedded to have forward compatible implementations. -type UnimplementedCAServer struct { -} +// UnimplementedCAServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedCAServer struct{} func (UnimplementedCAServer) CreateSigningCertificate(context.Context, *CreateSigningCertificateRequest) (*httpbody.HttpBody, error) { return nil, status.Errorf(codes.Unimplemented, "method CreateSigningCertificate not implemented") @@ -108,6 +119,7 @@ func (UnimplementedCAServer) GetRootCertificate(context.Context, *emptypb.Empty) return nil, status.Errorf(codes.Unimplemented, "method GetRootCertificate not implemented") } func (UnimplementedCAServer) mustEmbedUnimplementedCAServer() {} +func (UnimplementedCAServer) testEmbeddedByValue() {} // UnsafeCAServer may be embedded to opt out of forward compatibility for this service. // Use of this interface is not recommended, as added methods to CAServer will @@ -117,6 +129,13 @@ type UnsafeCAServer interface { } func RegisterCAServer(s grpc.ServiceRegistrar, srv CAServer) { + // If the following call pancis, it indicates UnimplementedCAServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } s.RegisterService(&CA_ServiceDesc, srv) } diff --git a/pkg/identity/chainguard/issuer.go b/pkg/identity/chainguard/issuer.go new file mode 100644 index 000000000..41df8c4b0 --- /dev/null +++ b/pkg/identity/chainguard/issuer.go @@ -0,0 +1,40 @@ +// Copyright 2024 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 chainguard + +import ( + "context" + "fmt" + + "github.com/sigstore/fulcio/pkg/config" + "github.com/sigstore/fulcio/pkg/identity" + "github.com/sigstore/fulcio/pkg/identity/base" +) + +type issuer struct { + identity.Issuer +} + +func Issuer(issuerURL string) identity.Issuer { + return &issuer{base.Issuer(issuerURL)} +} + +func (e *issuer) Authenticate(ctx context.Context, token string, opts ...config.InsecureOIDCConfigOption) (identity.Principal, error) { + idtoken, err := identity.Authorize(ctx, token, opts...) + if err != nil { + return nil, fmt.Errorf("authorizing chainguard issuer: %w", err) + } + return PrincipalFromIDToken(ctx, idtoken) +} diff --git a/pkg/identity/chainguard/issuer_test.go b/pkg/identity/chainguard/issuer_test.go new file mode 100644 index 000000000..6e3412a26 --- /dev/null +++ b/pkg/identity/chainguard/issuer_test.go @@ -0,0 +1,97 @@ +// Copyright 2024 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 chainguard + +import ( + "context" + "encoding/json" + "fmt" + "reflect" + "testing" + "unsafe" + + "chainguard.dev/sdk/uidp" + "github.com/coreos/go-oidc/v3/oidc" + "github.com/sigstore/fulcio/pkg/config" + "github.com/sigstore/fulcio/pkg/identity" +) + +func TestIssuer(t *testing.T) { + ctx := context.Background() + url := "test-issuer-url" + issuer := Issuer(url) + + // test the Match function + t.Run("match", func(t *testing.T) { + if matches := issuer.Match(ctx, url); !matches { + t.Fatal("expected url to match but it doesn't") + } + if matches := issuer.Match(ctx, "some-other-url"); matches { + t.Fatal("expected match to fail but it didn't") + } + }) + + t.Run("authenticate", func(t *testing.T) { + group := uidp.NewUIDP("") + id := group.NewChild() + + token := &oidc.IDToken{ + Issuer: "https://iss.example.com", + Subject: id.String(), + } + claims, err := json.Marshal(map[string]interface{}{ + "iss": "https://iss.example.com", + "sub": id.String(), + + // Actor claims track the identity that was used to assume the + // Chainguard identity. In this case, it is the Catalog Syncer + // service principal. + "act": map[string]string{ + "iss": "https://iss.example.com/", + "sub": fmt.Sprintf("catalog-syncer:%s", group.String()), + "aud": "chainguard", + }, + "internal": map[string]interface{}{ + "service-principal": "CATALOG_SYNCER", + }, + }) + if err != nil { + t.Fatal(err) + } + withClaims(token, claims) + + identity.Authorize = func(_ context.Context, _ string, _ ...config.InsecureOIDCConfigOption) (*oidc.IDToken, error) { + return token, nil + } + principal, err := issuer.Authenticate(ctx, "token") + if err != nil { + t.Fatal(err) + } + + if principal.Name(ctx) != id.String() { + t.Fatalf("got unexpected name %s", principal.Name(ctx)) + } + }) +} + +// reflect hack because "claims" field is unexported by oidc IDToken +// https://github.com/coreos/go-oidc/pull/329 +func withClaims(token *oidc.IDToken, data []byte) { + val := reflect.Indirect(reflect.ValueOf(token)) + member := val.FieldByName("claims") + pointer := unsafe.Pointer(member.UnsafeAddr()) + realPointer := (*[]byte)(pointer) + *realPointer = data +} diff --git a/pkg/identity/chainguard/principal.go b/pkg/identity/chainguard/principal.go new file mode 100644 index 000000000..194b89924 --- /dev/null +++ b/pkg/identity/chainguard/principal.go @@ -0,0 +1,92 @@ +// Copyright 2024 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 chainguard + +import ( + "context" + "crypto/x509" + "net/url" + + "github.com/coreos/go-oidc/v3/oidc" + "github.com/sigstore/fulcio/pkg/certificate" + "github.com/sigstore/fulcio/pkg/identity" + "github.com/sigstore/sigstore/pkg/oauthflow" +) + +type workflowPrincipal struct { + issuer string + subject string + name string + + actor map[string]string + servicePrincipal string +} + +var _ identity.Principal = (*workflowPrincipal)(nil) + +func (w workflowPrincipal) Name(_ context.Context) string { + return w.name +} + +func PrincipalFromIDToken(_ context.Context, token *oidc.IDToken) (identity.Principal, error) { + var claims struct { + Actor map[string]string `json:"act"` + Internal struct { + ServicePrincipal string `json:"service-principal,omitempty"` + } `json:"internal"` + } + + if err := token.Claims(&claims); err != nil { + return nil, err + } + + // This is the exact function that cosign uses to extract the "subject" + // (misnomer) from the token in order to establish "proof of possession". + // We MUST use this to implement Name() or tokens that embed an email claim + // will fail to sign because of this divergent logic. + name, err := oauthflow.SubjectFromToken(token) + if err != nil { + return nil, err + } + + return &workflowPrincipal{ + issuer: token.Issuer, + subject: token.Subject, + name: name, + actor: claims.Actor, + servicePrincipal: claims.Internal.ServicePrincipal, + }, nil +} + +func (w workflowPrincipal) Embed(_ context.Context, cert *x509.Certificate) error { + baseURL, err := url.Parse(w.issuer) + if err != nil { + return err + } + + // Set SAN to the / + cert.URIs = []*url.URL{baseURL.JoinPath(w.subject)} + + cert.ExtraExtensions, err = certificate.Extensions{ + Issuer: w.issuer, + + // TODO(mattmoor): Embed more of the Chainguard token structure via OIDs. + }.Render() + if err != nil { + return err + } + + return nil +} diff --git a/pkg/identity/chainguard/principal_test.go b/pkg/identity/chainguard/principal_test.go new file mode 100644 index 000000000..cd666aab0 --- /dev/null +++ b/pkg/identity/chainguard/principal_test.go @@ -0,0 +1,261 @@ +// Copyright 2024 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 chainguard + +import ( + "context" + "crypto/x509" + "encoding/asn1" + "encoding/json" + "errors" + "fmt" + "net/url" + "reflect" + "strings" + "testing" + + "chainguard.dev/sdk/uidp" + "github.com/coreos/go-oidc/v3/oidc" + "github.com/sigstore/fulcio/pkg/identity" +) + +func TestJobPrincipalFromIDToken(t *testing.T) { + group := uidp.NewUIDP("") + id := group.NewChild() + + tests := map[string]struct { + Claims map[string]interface{} + ExpectPrincipal workflowPrincipal + WantErr bool + ErrContains string + }{ + `Service principal token`: { + Claims: map[string]interface{}{ + "iss": "https://issuer.enforce.dev", + "sub": id.String(), + // Actor claims track the identity that was used to assume the + // Chainguard identity. In this case, it is the Catalog Syncer + // service principal. + "act": map[string]string{ + "iss": "https://iss.example.com/", + "sub": fmt.Sprintf("catalog-syncer:%s", group.String()), + "aud": "chainguard", + }, + "internal": map[string]interface{}{ + "service-principal": "CATALOG_SYNCER", + }, + }, + ExpectPrincipal: workflowPrincipal{ + issuer: "https://issuer.enforce.dev", + subject: id.String(), + name: id.String(), + actor: map[string]string{ + "iss": "https://iss.example.com/", + "sub": fmt.Sprintf("catalog-syncer:%s", group.String()), + "aud": "chainguard", + }, + servicePrincipal: "CATALOG_SYNCER", + }, + WantErr: false, + }, + `Human SSO token`: { + Claims: map[string]interface{}{ + "iss": "https://issuer.enforce.dev", + "sub": group.String(), + // Actor claims track the identity that was used to assume the + // Chainguard identity. In this case, it is the Catalog Syncer + // service principal. + "act": map[string]string{ + "iss": "https://auth.chainguard.dev/", + "sub": "google-oauth2|1234567890", + "aud": "fdsaldfkjhasldf", + }, + }, + ExpectPrincipal: workflowPrincipal{ + issuer: "https://issuer.enforce.dev", + subject: group.String(), + name: group.String(), + actor: map[string]string{ + "iss": "https://auth.chainguard.dev/", + "sub": "google-oauth2|1234567890", + "aud": "fdsaldfkjhasldf", + }, + }, + WantErr: false, + }, + `Human SSO token (with email)`: { + Claims: map[string]interface{}{ + "iss": "https://issuer.enforce.dev", + "sub": group.String(), + "email": "jane@doe.dev", + "email_verified": true, + // Actor claims track the identity that was used to assume the + // Chainguard identity. In this case, it is the Catalog Syncer + // service principal. + "act": map[string]string{ + "iss": "https://auth.chainguard.dev/", + "sub": "google-oauth2|1234567890", + "aud": "fdsaldfkjhasldf", + }, + }, + ExpectPrincipal: workflowPrincipal{ + issuer: "https://issuer.enforce.dev", + subject: group.String(), + name: "jane@doe.dev", + actor: map[string]string{ + "iss": "https://auth.chainguard.dev/", + "sub": "google-oauth2|1234567890", + "aud": "fdsaldfkjhasldf", + }, + }, + WantErr: false, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + token := &oidc.IDToken{ + Issuer: test.Claims["iss"].(string), + Subject: test.Claims["sub"].(string), + } + claims, err := json.Marshal(test.Claims) + if err != nil { + t.Fatal(err) + } + withClaims(token, claims) + + untyped, err := PrincipalFromIDToken(context.TODO(), token) + if err != nil { + if !test.WantErr { + t.Fatal("didn't expect error", err) + } + if !strings.Contains(err.Error(), test.ErrContains) { + t.Fatalf("expected error %s to contain %s", err, test.ErrContains) + } + return + } + if err == nil && test.WantErr { + t.Fatal("expected error but got none") + } + + principal, ok := untyped.(*workflowPrincipal) + if !ok { + t.Errorf("Got wrong principal type %v", untyped) + } + if !reflect.DeepEqual(*principal, test.ExpectPrincipal) { + t.Errorf("got %v principal and expected %v", *principal, test.ExpectPrincipal) + } + }) + } +} + +func TestEmbed(t *testing.T) { + group := uidp.NewUIDP("") + id := group.NewChild() + + tests := map[string]struct { + Principal identity.Principal + WantErr bool + WantFacts map[string]func(x509.Certificate) error + }{ + `Chainguard Service Principal`: { + Principal: &workflowPrincipal{ + issuer: "https://issuer.enforce.dev", + subject: id.String(), + actor: map[string]string{ + "iss": "https://iss.example.com/", + "sub": fmt.Sprintf("catalog-syncer:%s", group.String()), + "aud": "chainguard", + }, + servicePrincipal: "CATALOG_SYNCER", + }, + WantErr: false, + WantFacts: map[string]func(x509.Certificate) error{ + `Certificate SAN has correct value`: factSanURIIs(fmt.Sprintf("https://issuer.enforce.dev/%s", id.String())), + `Certificate has correct issuer (v2) extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 8}, "https://issuer.enforce.dev"), + }, + }, + `Chainguard Human SSO`: { + Principal: &workflowPrincipal{ + issuer: "https://issuer.enforce.dev", + subject: group.String(), + actor: map[string]string{ + "iss": "https://auth.chainguard.dev/", + "sub": "google-oauth2|1234567890", + "aud": "fdsaldfkjhasldf", + }, + }, + WantErr: false, + WantFacts: map[string]func(x509.Certificate) error{ + `Certificate SAN has correct value`: factSanURIIs(fmt.Sprintf("https://issuer.enforce.dev/%s", group.String())), + `Certificate has correct issuer (v2) extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 8}, "https://issuer.enforce.dev"), + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + var cert x509.Certificate + err := test.Principal.Embed(context.TODO(), &cert) + if err != nil { + if !test.WantErr { + t.Error(err) + } + return + } else if test.WantErr { + t.Error("expected error") + } + for factName, fact := range test.WantFacts { + t.Run(factName, func(t *testing.T) { + if err := fact(cert); err != nil { + t.Error(err) + } + }) + } + }) + } +} + +func factExtensionIs(oid asn1.ObjectIdentifier, value string) func(x509.Certificate) error { + return func(cert x509.Certificate) error { + for _, ext := range cert.ExtraExtensions { + if ext.Id.Equal(oid) { + var strVal string + _, _ = asn1.Unmarshal(ext.Value, &strVal) + if value != strVal { + return fmt.Errorf("expected oid %v to be %s, but got %s", oid, value, strVal) + } + return nil + } + } + return errors.New("extension not set") + } +} + +func factSanURIIs(value string) func(x509.Certificate) error { + return func(cert x509.Certificate) error { + url, err := url.Parse(value) + + if err != nil { + return err + } + + if cert.URIs[0].String() != url.String() { + return fmt.Errorf("expected SAN o be %s, but got %s", value, cert.URIs[0].String()) + } + + return nil + } +} diff --git a/pkg/identity/ciprovider/issuer.go b/pkg/identity/ciprovider/issuer.go new file mode 100644 index 000000000..ce82d3558 --- /dev/null +++ b/pkg/identity/ciprovider/issuer.go @@ -0,0 +1,39 @@ +// Copyright 2024 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 ciprovider + +import ( + "context" + + "github.com/sigstore/fulcio/pkg/config" + "github.com/sigstore/fulcio/pkg/identity" + "github.com/sigstore/fulcio/pkg/identity/base" +) + +type ciProviderIssuer struct { + identity.Issuer +} + +func Issuer(issuerURL string) identity.Issuer { + return &ciProviderIssuer{base.Issuer(issuerURL)} +} + +func (e *ciProviderIssuer) Authenticate(ctx context.Context, token string, opts ...config.InsecureOIDCConfigOption) (identity.Principal, error) { + idtoken, err := identity.Authorize(ctx, token, opts...) + if err != nil { + return nil, err + } + return WorkflowPrincipalFromIDToken(ctx, idtoken) +} diff --git a/pkg/identity/ciprovider/issuer_test.go b/pkg/identity/ciprovider/issuer_test.go new file mode 100644 index 000000000..1d8e605e3 --- /dev/null +++ b/pkg/identity/ciprovider/issuer_test.go @@ -0,0 +1,100 @@ +// Copyright 2024 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 ciprovider + +import ( + "context" + "encoding/json" + "testing" + + "github.com/coreos/go-oidc/v3/oidc" + "github.com/sigstore/fulcio/pkg/config" + "github.com/sigstore/fulcio/pkg/identity" +) + +func TestIssuer(t *testing.T) { + ctx := context.Background() + url := "test-issuer-url" + issuer := Issuer(url) + + // test the Match function + t.Run("match", func(t *testing.T) { + if matches := issuer.Match(ctx, url); !matches { + t.Fatal("expected url to match but it doesn't") + } + if matches := issuer.Match(ctx, "some-other-url"); matches { + t.Fatal("expected match to fail but it didn't") + } + }) + + t.Run("authenticate", func(t *testing.T) { + token := &oidc.IDToken{ + Issuer: "https://iss.example.com", + Subject: "repo:sigstore/fulcio:ref:refs/heads/main", + } + claims, err := json.Marshal(map[string]interface{}{ + "aud": "sigstore", + "event_name": "push", + "exp": 0, + "iss": "https://token.actions.githubusercontent.com", + "job_workflow_ref": "sigstore/fulcio/.github/workflows/foo.yaml@refs/heads/main", + "job_workflow_sha": "example-sha", + "ref": "refs/heads/main", + "repository": "sigstore/fulcio", + "repository_id": "12345", + "repository_owner": "username", + "repository_owner_id": "345", + "repository_visibility": "public", + "run_attempt": "1", + "run_id": "42", + "runner_environment": "cloud-hosted", + "sha": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "sub": "repo:sigstore/fulcio:ref:refs/heads/main", + "workflow": "foo", + "workflow_ref": "sigstore/other/.github/workflows/foo.yaml@refs/heads/main", + "workflow_sha": "example-sha-other", + }) + if err != nil { + t.Fatal(err) + } + + withClaims(token, claims) + ctx := context.TODO() + OIDCIssuers := + map[string]config.OIDCIssuer{ + token.Issuer: { + IssuerURL: token.Issuer, + Type: config.IssuerTypeCIProvider, + CIProvider: "github-workflow", + ClientID: "sigstore", + }, + } + cfg := &config.FulcioConfig{ + OIDCIssuers: OIDCIssuers, + } + ctx = config.With(ctx, cfg) + identity.Authorize = func(_ context.Context, _ string, _ ...config.InsecureOIDCConfigOption) (*oidc.IDToken, error) { + return token, nil + } + principal, err := issuer.Authenticate(ctx, "token") + if err != nil { + t.Fatal(err) + } + + if principal.Name(ctx) != "repo:sigstore/fulcio:ref:refs/heads/main" { + t.Fatalf("got unexpected name %s", principal.Name(ctx)) + } + }) +} diff --git a/pkg/identity/ciprovider/principal.go b/pkg/identity/ciprovider/principal.go new file mode 100644 index 000000000..dce9227cb --- /dev/null +++ b/pkg/identity/ciprovider/principal.go @@ -0,0 +1,157 @@ +// Copyright 2024 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 ciprovider + +import ( + "bytes" + "context" + "crypto/x509" + "fmt" + "html/template" + "net/url" + "reflect" + "strings" + + "github.com/coreos/go-oidc/v3/oidc" + "github.com/sigstore/fulcio/pkg/config" + "github.com/sigstore/fulcio/pkg/identity" +) + +func mapValuesToString(claims map[string]interface{}) map[string]string { + newMap := make(map[string]string) + for k, v := range claims { + newMap[k] = fmt.Sprintf("%s", v) + } + return newMap +} + +func getTokenClaims(token *oidc.IDToken) (map[string]string, error) { + var tokenClaims map[string]interface{} + if err := token.Claims(&tokenClaims); err != nil { + return nil, err + } + return mapValuesToString(tokenClaims), nil +} + +// It makes string interpolation for a given string by using the +// templates syntax https://pkg.go.dev/text/template +func applyTemplateOrReplace(extValueTemplate string, tokenClaims map[string]string, issuerMetadata map[string]string) (string, error) { + + // Here we merge the data from was claimed by the id token with the + // default data provided by the yaml file. + // The order here matter because we want to override the claimed data + // with the default data. + // The claimed data will have priority over the default data. + mergedData := make(map[string]string) + for k, v := range issuerMetadata { + mergedData[k] = v + } + for k, v := range tokenClaims { + mergedData[k] = v + } + + if strings.Contains(extValueTemplate, "{{") { + var doc bytes.Buffer + // This option forces to having the claim that is required + // for the template + t := template.New("").Option("missingkey=error") + // It shouldn't raise error since we already checked all + // templates in validateCIIssuerMetadata functions in config.go + p, err := t.Parse(extValueTemplate) + if err != nil { + return "", err + } + err = p.Execute(&doc, mergedData) + if err != nil { + return "", err + } + return doc.String(), nil + } + claimValue, ok := mergedData[extValueTemplate] + if !ok { + return "", fmt.Errorf("value <%s> not present in either claims or defaults", extValueTemplate) + } + return claimValue, nil +} + +type ciPrincipal struct { + Token *oidc.IDToken + ClaimsMetadata config.IssuerMetadata +} + +func WorkflowPrincipalFromIDToken(ctx context.Context, token *oidc.IDToken) (identity.Principal, error) { + cfg := config.FromContext(ctx) + issuerCfg, ok := cfg.GetIssuer(token.Issuer) + if !ok { + return nil, fmt.Errorf("configuration can not be loaded for issuer %v", token.Issuer) + } + return ciPrincipal{ + token, + cfg.CIIssuerMetadata[issuerCfg.CIProvider], + }, nil +} + +func (principal ciPrincipal) Name(_ context.Context) string { + return principal.Token.Subject +} + +func (principal ciPrincipal) Embed(_ context.Context, cert *x509.Certificate) error { + + claimsTemplates := principal.ClaimsMetadata.ExtensionTemplates + defaults := principal.ClaimsMetadata.DefaultTemplateValues + claims, err := getTokenClaims(principal.Token) + if err != nil { + return err + } + subjectAlternativeName, err := applyTemplateOrReplace(principal.ClaimsMetadata.SubjectAlternativeNameTemplate, claims, defaults) + if err != nil { + return err + } + sanURL, err := url.Parse(subjectAlternativeName) + if err != nil { + return err + } + uris := []*url.URL{sanURL} + cert.URIs = uris + // We should use value.Elem() here as we need a + // addressable reference of the templates for applying the SetString(). + v := reflect.ValueOf(&claimsTemplates).Elem() + // Type of the reflect value is needed as it is necessary + // for getting the field name. + vType := v.Type() + for i := 0; i < v.NumField(); i++ { + s := v.Field(i).String() // value of each field, e.g the template string + // We check the field name to avoid to apply the template for the Issuer + // Issuer field should always come from the token issuer + if s == "" || vType.Field(i).Name == "Issuer" { + continue + } + extValue, err := applyTemplateOrReplace(s, claims, defaults) + if err != nil { + return err + } + v.Field(i).SetString(extValue) + } + + // Guarantees to set the extension issuer as the token issuer + // regardless of whether this field has been set before + claimsTemplates.Issuer = principal.Token.Issuer + // Embed additional information into custom extensions + cert.ExtraExtensions, err = claimsTemplates.Render() + if err != nil { + return err + } + return nil +} diff --git a/pkg/identity/ciprovider/principal_test.go b/pkg/identity/ciprovider/principal_test.go new file mode 100644 index 000000000..4e51d06dc --- /dev/null +++ b/pkg/identity/ciprovider/principal_test.go @@ -0,0 +1,454 @@ +// Copyright 2024 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 ciprovider + +import ( + "bytes" + "context" + "crypto/x509" + "encoding/asn1" + "encoding/json" + "errors" + "fmt" + "reflect" + "testing" + "unsafe" + + "github.com/coreos/go-oidc/v3/oidc" + "github.com/sigstore/fulcio/pkg/certificate" + "github.com/sigstore/fulcio/pkg/config" +) + +func TestWorkflowPrincipalFromIDToken(t *testing.T) { + tests := map[string]struct { + ExpectedPrincipal ciPrincipal + }{ + `Github workflow challenge should have all Github workflow extensions and issuer set`: { + ExpectedPrincipal: ciPrincipal{ + ClaimsMetadata: config.IssuerMetadata{ + ExtensionTemplates: certificate.Extensions{ + Issuer: "issuer", + GithubWorkflowTrigger: "event_name", + GithubWorkflowSHA: "sha", + GithubWorkflowName: "workflow", + GithubWorkflowRepository: "repository", + GithubWorkflowRef: "ref", + BuildSignerURI: "{{ .url }}/{{ .job_workflow_ref }}", + BuildSignerDigest: "job_workflow_sha", + RunnerEnvironment: "runner_environment", + SourceRepositoryURI: "{{ .url }}/{{ .repository }}", + SourceRepositoryDigest: "sha", + SourceRepositoryRef: "ref", + SourceRepositoryIdentifier: "repository_id", + SourceRepositoryOwnerURI: "{{ .url }}/{{ .repository_owner }}", + SourceRepositoryOwnerIdentifier: "repository_owner_id", + BuildConfigURI: "{{ .url }}/{{ .workflow_ref }}", + BuildConfigDigest: "workflow_sha", + BuildTrigger: "event_name", + RunInvocationURI: "{{ .url }}/{{ .repository }}/actions/runs/{{ .run_id }}/attempts/{{ .run_attempt }}", + SourceRepositoryVisibilityAtSigning: "repository_visibility", + }, + DefaultTemplateValues: map[string]string{ + "url": "https://github.com", + }, + SubjectAlternativeNameTemplate: "{{.url}}/{{.job_workflow_ref}}", + }, + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + claims, err := json.Marshal(map[string]interface{}{ + "issuer": "https://token.actions.githubusercontent.com", + "event_name": "trigger", + "sha": "sha", + "workflow": "workflowname", + "repository": "repository", + "ref": "ref", + "job_workflow_sha": "jobWorkflowSha", + "job_workflow_ref": "jobWorkflowRef", + "runner_environment": "runnerEnv", + "repository_id": "repoID", + "repository_owner": "repoOwner", + "repository_owner_id": "repoOwnerID", + "workflow_ref": "workflowRef", + "workflow_sha": "workflowSHA", + "run_id": "runID", + "run_attempt": "runAttempt", + "repository_visibility": "public", + }) + if err != nil { + t.Fatal(err) + } + token := &oidc.IDToken{} + withClaims(token, claims) + + test.ExpectedPrincipal.Token = token + ctx := context.TODO() + OIDCIssuers := + map[string]config.OIDCIssuer{ + token.Issuer: { + IssuerURL: token.Issuer, + Type: config.IssuerTypeCIProvider, + CIProvider: "github-workflow", + ClientID: "sigstore", + }, + } + meta := make(map[string]config.IssuerMetadata) + meta["github-workflow"] = test.ExpectedPrincipal.ClaimsMetadata + cfg := &config.FulcioConfig{ + OIDCIssuers: OIDCIssuers, + CIIssuerMetadata: meta, + } + ctx = config.With(ctx, cfg) + principal, err := WorkflowPrincipalFromIDToken(ctx, token) + if err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(principal, test.ExpectedPrincipal) { + t.Error("Principals should be equals") + } + }) + } + +} + +// reflect hack because "claims" field is unexported by oidc IDToken +// https://github.com/coreos/go-oidc/pull/329 +func withClaims(token *oidc.IDToken, data []byte) { + val := reflect.Indirect(reflect.ValueOf(token)) + member := val.FieldByName("claims") + pointer := unsafe.Pointer(member.UnsafeAddr()) + realPointer := (*[]byte)(pointer) + *realPointer = data +} + +func TestName(t *testing.T) { + tests := map[string]struct { + Claims map[string]interface{} + ExpectName string + }{ + `Valid token authenticates with correct claims`: { + Claims: map[string]interface{}{ + "aud": "sigstore", + "event_name": "push", + "exp": "0", + "iss": "https://token.actions.githubusercontent.com", + "job_workflow_ref": "sigstore/fulcio/.github/workflows/foo.yaml@refs/heads/main", + "job_workflow_sha": "example-sha", + "ref": "refs/heads/main", + "repository": "sigstore/fulcio", + "repository_id": "12345", + "repository_owner": "username", + "repository_owner_id": "345", + "repository_visibility": "public", + "run_attempt": "1", + "run_id": "42", + "runner_environment": "cloud-hosted", + "sha": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "sub": "repo:sigstore/fulcio:ref:refs/heads/main", + "workflow": "foo", + "workflow_ref": "sigstore/other/.github/workflows/foo.yaml@refs/heads/main", + "workflow_sha": "example-sha-other", + }, + ExpectName: "repo:sigstore/fulcio:ref:refs/heads/main", + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + token := &oidc.IDToken{ + Issuer: test.Claims["iss"].(string), + Subject: test.Claims["sub"].(string), + } + claims, err := json.Marshal(test.Claims) + if err != nil { + t.Fatal(err) + } + withClaims(token, claims) + ctx := context.TODO() + OIDCIssuers := + map[string]config.OIDCIssuer{ + token.Issuer: { + IssuerURL: token.Issuer, + Type: config.IssuerTypeCIProvider, + CIProvider: "ci-provider", + ClientID: "sigstore", + }, + } + cfg := &config.FulcioConfig{ + OIDCIssuers: OIDCIssuers, + } + ctx = config.With(ctx, cfg) + principal, err := WorkflowPrincipalFromIDToken(ctx, token) + if err != nil { + t.Fatal(err) + } + + gotName := principal.Name(context.TODO()) + if gotName != test.ExpectName { + t.Error("name should match sub claim") + } + }) + } +} + +func TestApplyTemplateOrReplace(t *testing.T) { + + tokenClaims := map[string]string{ + "aud": "sigstore", + "event_name": "push", + "exp": "0", + "iss": "https://token.actions.githubusercontent.com", + "job_workflow_ref": "sigstore/fulcio/.github/workflows/foo.yaml@refs/heads/main", + "job_workflow_sha": "example-sha", + "ref": "refs/heads/main", + "repository": "sigstore/fulcio", + "repository_id": "12345", + "repository_owner": "username", + "repository_owner_id": "345", + "repository_visibility": "public", + "run_attempt": "1", + "run_id": "42", + "runner_environment": "cloud-hosted", + "sha": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "sub": "repo:sigstore/fulcio:ref:refs/heads/main", + "workflow": "foo", + "workflow_ref": "sigstore/other/.github/workflows/foo.yaml@refs/heads/main", + "workflow_sha": "example-sha-other", + "ref_type": "branch", + "ref_gitlab": "main", + "ref_type_tag": "tag", + "ref_tag": "1.0.0", + "claim_foo": "bar", + } + issuerMetadata := map[string]string{ + "url": "https://github.com", + "claim_foo": "default", + "default_foo": "default_bar", + } + + tests := map[string]struct { + Template string + ExpectedResult string + ExpectErr bool + }{ + `Valid template`: { + Template: "{{ .url }}/{{ .repository }}/actions/runs/{{ .run_id }}/attempts/{{ .run_attempt }}", + ExpectedResult: "https://github.com/sigstore/fulcio/actions/runs/42/attempts/1", + ExpectErr: false, + }, + `Empty template`: { + Template: "{{}}", + ExpectedResult: "", + ExpectErr: true, + }, + `Missing key for template`: { + Template: "{{ .foo }}", + ExpectedResult: "", + ExpectErr: true, + }, + `Empty string`: { + Template: "", + ExpectedResult: "", + ExpectErr: true, + }, + `Replaceable string`: { + Template: "job_workflow_ref", + ExpectedResult: "sigstore/fulcio/.github/workflows/foo.yaml@refs/heads/main", + ExpectErr: false, + }, + `Missing string`: { + Template: "bar", + ExpectedResult: "", + ExpectErr: true, + }, + `If else template`: { + Template: `refs/{{if eq .ref_type "branch"}}heads/{{ else }}tags/{{end}}{{ .ref_gitlab }}`, + ExpectedResult: "refs/heads/main", + ExpectErr: false, + }, + `If else template using else condition`: { + Template: `refs/{{if eq .ref_type_tag "branch"}}heads/{{ else }}tags/{{end}}{{ .ref_tag }}`, + ExpectedResult: "refs/tags/1.0.0", + ExpectErr: false, + }, + `Raise error for empty key in comparison`: { + Template: `{{if eq . ""}}foo{{else}}bar{{end}}`, + ExpectedResult: "", + ExpectErr: true, + }, + `Should use default when claim doesn't exist`: { + Template: "default_foo", + ExpectedResult: "default_bar", + ExpectErr: false, + }, + `Should prior claims over defaults when they has the same name`: { + Template: "claim_foo", + ExpectedResult: "bar", + ExpectErr: false, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + res, err := applyTemplateOrReplace(test.Template, tokenClaims, issuerMetadata) + if res != test.ExpectedResult { + t.Errorf("expected result don't matches: Expected %s, received: %s, error: %v", + test.ExpectedResult, res, err) + } + if (err != nil) != test.ExpectErr { + t.Errorf("should raise an error don't matches: Expected %v, received: %v, error: %v", + test.ExpectErr, err != nil, err) + } + }) + } +} + +func TestEmbed(t *testing.T) { + tests := map[string]struct { + WantFacts map[string]func(x509.Certificate) error + Principal ciPrincipal + }{ + `Github workflow challenge should have all Github workflow extensions and issuer set`: { + WantFacts: map[string]func(x509.Certificate) error{ + `Certifificate should have correct issuer`: factDeprecatedExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 1}, "https://token.actions.githubusercontent.com"), + `Certificate has correct trigger extension`: factDeprecatedExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 2}, "trigger"), + `Certificate has correct SHA extension`: factDeprecatedExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 3}, "sha"), + `Certificate has correct workflow extension`: factDeprecatedExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 4}, "workflowname"), + `Certificate has correct repository extension`: factDeprecatedExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 5}, "repository"), + `Certificate has correct ref extension`: factDeprecatedExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 6}, "ref"), + `Certificate has correct issuer (v2) extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 8}, "https://token.actions.githubusercontent.com"), + `Certificate has correct builder signer URI extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 9}, "https://github.com/jobWorkflowRef"), + `Certificate has correct builder signer digest extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 10}, "jobWorkflowSha"), + `Certificate has correct runner environment extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 11}, "runnerEnv"), + `Certificate has correct source repo URI extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 12}, "https://github.com/repository"), + `Certificate has correct source repo digest extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 13}, "sha"), + `Certificate has correct source repo ref extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 14}, "ref"), + `Certificate has correct source repo ID extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 15}, "repoID"), + `Certificate has correct source repo owner URI extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 16}, "https://github.com/repoOwner"), + `Certificate has correct source repo owner ID extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 17}, "repoOwnerID"), + `Certificate has correct build config URI extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 18}, "https://github.com/workflowRef"), + `Certificate has correct build config digest extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 19}, "workflowSHA"), + `Certificate has correct build trigger extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 20}, "trigger"), + `Certificate has correct run invocation ID extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 21}, "https://github.com/repository/actions/runs/runID/attempts/runAttempt"), + `Certificate has correct source repository visibility extension`: factExtensionIs(asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 22}, "public"), + }, + Principal: ciPrincipal{ + ClaimsMetadata: config.IssuerMetadata{ + ExtensionTemplates: certificate.Extensions{ + GithubWorkflowTrigger: "event_name", + GithubWorkflowSHA: "sha", + GithubWorkflowName: "workflow", + GithubWorkflowRepository: "repository", + GithubWorkflowRef: "ref", + BuildSignerURI: "{{ .url }}/{{ .job_workflow_ref }}", + BuildSignerDigest: "job_workflow_sha", + RunnerEnvironment: "runner_environment", + SourceRepositoryURI: "{{ .url }}/{{ .repository }}", + SourceRepositoryDigest: "sha", + SourceRepositoryRef: "ref", + SourceRepositoryIdentifier: "repository_id", + SourceRepositoryOwnerURI: "{{ .url }}/{{ .repository_owner }}", + SourceRepositoryOwnerIdentifier: "repository_owner_id", + BuildConfigURI: "{{ .url }}/{{ .workflow_ref }}", + BuildConfigDigest: "workflow_sha", + BuildTrigger: "event_name", + RunInvocationURI: "{{ .url }}/{{ .repository }}/actions/runs/{{ .run_id }}/attempts/{{ .run_attempt }}", + SourceRepositoryVisibilityAtSigning: "repository_visibility", + }, + DefaultTemplateValues: map[string]string{ + "url": "https://github.com", + }, + SubjectAlternativeNameTemplate: "{{.url}}/{{.job_workflow_ref}}", + }, + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + var cert x509.Certificate + claims, err := json.Marshal(map[string]interface{}{ + "event_name": "trigger", + "sha": "sha", + "workflow": "workflowname", + "repository": "repository", + "ref": "ref", + "job_workflow_sha": "jobWorkflowSha", + "job_workflow_ref": "jobWorkflowRef", + "runner_environment": "runnerEnv", + "repository_id": "repoID", + "repository_owner": "repoOwner", + "repository_owner_id": "repoOwnerID", + "workflow_ref": "workflowRef", + "workflow_sha": "workflowSHA", + "run_id": "runID", + "run_attempt": "runAttempt", + "repository_visibility": "public", + }) + if err != nil { + t.Fatal(err) + } + token := &oidc.IDToken{} + token.Issuer = "https://token.actions.githubusercontent.com" + withClaims(token, claims) + + test.Principal.Token = token + err = test.Principal.Embed(context.TODO(), &cert) + if err != nil { + t.Error(err) + } + for factName, fact := range test.WantFacts { + t.Run(factName, func(t *testing.T) { + if err := fact(cert); err != nil { + t.Error(err) + } + }) + } + }) + } +} + +func factExtensionIs(oid asn1.ObjectIdentifier, value string) func(x509.Certificate) error { + return func(cert x509.Certificate) error { + for _, ext := range cert.ExtraExtensions { + if ext.Id.Equal(oid) { + var strVal string + _, _ = asn1.Unmarshal(ext.Value, &strVal) + if value != strVal { + return fmt.Errorf("expected oid %v to be %s, but got %s", oid, value, strVal) + } + return nil + } + } + return errors.New("extension not set") + } +} + +func factDeprecatedExtensionIs(oid asn1.ObjectIdentifier, value string) func(x509.Certificate) error { + return func(cert x509.Certificate) error { + for _, ext := range cert.ExtraExtensions { + if ext.Id.Equal(oid) { + if !bytes.Equal(ext.Value, []byte(value)) { + return fmt.Errorf("expected oid %v to be %s, but got %s", oid, value, ext.Value) + } + return nil + } + } + return errors.New("extension not set") + } +} diff --git a/pkg/identity/email/principal_test.go b/pkg/identity/email/principal_test.go index 980ef3879..ea12b0f15 100644 --- a/pkg/identity/email/principal_test.go +++ b/pkg/identity/email/principal_test.go @@ -87,6 +87,33 @@ func TestPrincipalFromIDToken(t *testing.T) { }, WantErr: false, }, + `String email verified value`: { + Claims: map[string]interface{}{ + "aud": "sigstore", + "iss": "https://dex.other.com", + "sub": "doesntmatter", + "email": "alice@example.com", + "email_verified": "true", + "federated": map[string]string{ + "issuer": "https://example.com", + }, + }, + Config: config.FulcioConfig{ + OIDCIssuers: map[string]config.OIDCIssuer{ + "https://dex.other.com": { + IssuerURL: "https://dex.other.com", + IssuerClaim: "$.federated.issuer", + Type: config.IssuerTypeEmail, + ClientID: "sigstore", + }, + }, + }, + ExpectedPrincipal: principal{ + issuer: "https://example.com", + address: "alice@example.com", + }, + WantErr: false, + }, `Custom issuer claim missing`: { Claims: map[string]interface{}{ "aud": "sigstore", diff --git a/pkg/log/log.go b/pkg/log/log.go index 1e9eabbd0..aa9155874 100644 --- a/pkg/log/log.go +++ b/pkg/log/log.go @@ -90,12 +90,12 @@ func ContextLogger(ctx context.Context) *zap.SugaredLogger { func SetupGRPCLogging() (*zap.Logger, []grpc_zap.Option) { var options []grpc_zap.Option - options = append(options, grpc_zap.WithDecider(func(methodName string, err error) bool { + options = append(options, grpc_zap.WithDecider(func(_ string, _ error) bool { // TODO: implement filters to eliminate health check log statements return true })) options = append(options, grpc_zap.WithMessageProducer( - func(ctx context.Context, msg string, level zapcore.Level, code codes.Code, err error, duration zapcore.Field) { + func(ctx context.Context, msg string, _ zapcore.Level, code codes.Code, err error, duration zapcore.Field) { var requestID zap.Field if md, ok := metadata.FromIncomingContext(ctx); ok { val := md.Get(string(requestIDMetadataKey)) diff --git a/pkg/oauthflow/oidc.go b/pkg/oauthflow/oidc.go index 34845ea2a..583674bc8 100644 --- a/pkg/oauthflow/oidc.go +++ b/pkg/oauthflow/oidc.go @@ -23,11 +23,25 @@ import ( "github.com/coreos/go-oidc/v3/oidc" ) +type stringAsBool bool + +func (sb *stringAsBool) UnmarshalJSON(b []byte) error { + switch string(b) { + case "true", `"true"`, "True", `"True"`: + *sb = true + case "false", `"false"`, "False", `"False"`: + *sb = false + default: + return errors.New("invalid value for boolean") + } + return nil +} + func EmailFromIDToken(token *oidc.IDToken) (string, bool, error) { // Extract custom claims var claims struct { - Email string `json:"email"` - Verified bool `json:"email_verified"` + Email string `json:"email"` + Verified stringAsBool `json:"email_verified"` } if err := token.Claims(&claims); err != nil { return "", false, err @@ -36,7 +50,7 @@ func EmailFromIDToken(token *oidc.IDToken) (string, bool, error) { return "", false, errors.New("token missing email claim") } - return claims.Email, claims.Verified, nil + return claims.Email, bool(claims.Verified), nil } func IssuerFromIDToken(token *oidc.IDToken, claimJSONPath string) (string, error) { diff --git a/pkg/server/grpc_server.go b/pkg/server/grpc_server.go index 73e8b4072..9b0cb5991 100644 --- a/pkg/server/grpc_server.go +++ b/pkg/server/grpc_server.go @@ -22,9 +22,13 @@ import ( "errors" "fmt" + ctclient "github.com/google/certificate-transparency-go/client" health "google.golang.org/grpc/health/grpc_health_v1" - ctclient "github.com/google/certificate-transparency-go/client" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" + certauth "github.com/sigstore/fulcio/pkg/ca" "github.com/sigstore/fulcio/pkg/challenges" "github.com/sigstore/fulcio/pkg/config" @@ -33,9 +37,6 @@ import ( "github.com/sigstore/fulcio/pkg/identity" "github.com/sigstore/fulcio/pkg/log" "github.com/sigstore/sigstore/pkg/cryptoutils" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/metadata" - "google.golang.org/grpc/status" ) type GRPCCAServer interface { diff --git a/pkg/server/grpc_server_test.go b/pkg/server/grpc_server_test.go index 943094959..24321edf3 100644 --- a/pkg/server/grpc_server_test.go +++ b/pkg/server/grpc_server_test.go @@ -39,22 +39,25 @@ import ( "testing" "time" + "chainguard.dev/sdk/uidp" + "github.com/go-jose/go-jose/v4" + "github.com/go-jose/go-jose/v4/jwt" ctclient "github.com/google/certificate-transparency-go/client" "github.com/google/certificate-transparency-go/jsonclient" + + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/grpc/status" + "google.golang.org/grpc/test/bufconn" + "github.com/sigstore/fulcio/pkg/ca" "github.com/sigstore/fulcio/pkg/ca/ephemeralca" + "github.com/sigstore/fulcio/pkg/certificate" "github.com/sigstore/fulcio/pkg/config" "github.com/sigstore/fulcio/pkg/generated/protobuf" "github.com/sigstore/fulcio/pkg/identity" "github.com/sigstore/sigstore/pkg/cryptoutils" - "google.golang.org/grpc" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/credentials/insecure" - "google.golang.org/grpc/resolver" - "google.golang.org/grpc/status" - "google.golang.org/grpc/test/bufconn" - "gopkg.in/square/go-jose.v2" - "gopkg.in/square/go-jose.v2/jwt" ) const ( @@ -70,7 +73,7 @@ func init() { var lis *bufconn.Listener func passFulcioConfigThruContext(cfg *config.FulcioConfig) grpc.UnaryServerInterceptor { - return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { + return func(ctx context.Context, req interface{}, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { // For each request, infuse context with our snapshot of the FulcioConfig. // TODO(mattmoor): Consider periodically (every minute?) refreshing the ConfigMap // from disk, so that we don't need to cycle pods to pick up config updates. @@ -195,6 +198,8 @@ func TestGetConfiguration(t *testing.T) { _, gitHubIssuer := newOIDCIssuer(t) _, gitLabIssuer := newOIDCIssuer(t) _, codefreshIssuer := newOIDCIssuer(t) + _, chainguardIssuer := newOIDCIssuer(t) + _, ciProviderIssuer := newOIDCIssuer(t) issuerDomain, err := url.Parse(usernameIssuer) if err != nil { @@ -245,6 +250,16 @@ func TestGetConfiguration(t *testing.T) { "IssuerURL": %q, "ClientID": "sigstore", "Type": "codefresh-workflow" + }, + %q: { + "IssuerURL": %q, + "ClientID": "sigstore", + "Type": "chainguard-identity" + }, + %q: { + "IssuerURL": %q, + "ClientID": "sigstore", + "Type": "ci-provider" } }, "MetaIssuers": { @@ -261,6 +276,8 @@ func TestGetConfiguration(t *testing.T) { gitHubIssuer, gitHubIssuer, gitLabIssuer, gitLabIssuer, codefreshIssuer, codefreshIssuer, + chainguardIssuer, chainguardIssuer, + ciProviderIssuer, ciProviderIssuer, k8sIssuer))) if err != nil { t.Fatalf("config.Read() = %v", err) @@ -281,6 +298,147 @@ func TestGetConfiguration(t *testing.T) { t.Fatal("GetConfiguration failed", err) } + if got, want := len(config.Issuers), 11; got != want { + t.Fatalf("expected %d issuers, got %d", want, got) + } + + expectedIssuers := map[string]bool{ + emailIssuer: true, spiffeIssuer: true, uriIssuer: true, + usernameIssuer: true, k8sIssuer: true, gitHubIssuer: true, + buildkiteIssuer: true, gitLabIssuer: true, codefreshIssuer: true, + chainguardIssuer: true, ciProviderIssuer: true, + } + for _, iss := range config.Issuers { + var issURL string + switch { + case expectedIssuers[iss.GetIssuerUrl()]: + delete(expectedIssuers, iss.GetIssuerUrl()) + issURL = iss.GetIssuerUrl() + case expectedIssuers[iss.GetWildcardIssuerUrl()]: + delete(expectedIssuers, iss.GetWildcardIssuerUrl()) + issURL = iss.GetWildcardIssuerUrl() + default: + t.Fatal("issuer missing from expected issuers") + } + + if iss.Audience != "sigstore" { + t.Fatalf("expected audience to be sigstore, got %v", iss.Audience) + } + + if issURL == emailIssuer { + if iss.ChallengeClaim != "email" { + t.Fatalf("expected email claim for email PoP challenge, got %v", iss.ChallengeClaim) + } + } else { + if iss.ChallengeClaim != "sub" { + t.Fatalf("expected sub claim for non-email PoP challenge, got %v", iss.ChallengeClaim) + } + } + + if issURL == spiffeIssuer { + if iss.SpiffeTrustDomain != "example.com" { + t.Fatalf("expected SPIFFE trust domain example.com, got %v", iss.SpiffeTrustDomain) + } + } else { + if iss.SpiffeTrustDomain != "" { + t.Fatalf("expected no SPIFFE trust domain, got %v", iss.SpiffeTrustDomain) + } + } + } + + if len(expectedIssuers) != 0 { + t.Fatal("not all issuers were found in configuration") + } +} + +// Tests GetConfigurationFromYaml API +func TestGetConfigurationFromYaml(t *testing.T) { + _, emailIssuer := newOIDCIssuer(t) + _, spiffeIssuer := newOIDCIssuer(t) + _, uriIssuer := newOIDCIssuer(t) + _, usernameIssuer := newOIDCIssuer(t) + _, k8sIssuer := newOIDCIssuer(t) + _, buildkiteIssuer := newOIDCIssuer(t) + _, gitHubIssuer := newOIDCIssuer(t) + _, gitLabIssuer := newOIDCIssuer(t) + _, codefreshIssuer := newOIDCIssuer(t) + + issuerDomain, err := url.Parse(usernameIssuer) + if err != nil { + t.Fatal("issuer URL could not be parsed", err) + } + + yamlBytes := []byte(fmt.Sprintf(` + oidc-issuers: + %v: + issuer-url: %q + client-id: sigstore + type: spiffe + spiffe-trust-domain: example.com + %v: + issuer-url: %q + client-id: sigstore + type: uri + subject-domain: %q + %v: + issuer-url: %q + client-id: sigstore + type: email + %v: + issuer-url: %q + client-id: sigstore + type: username + subject-domain: %q + %v: + issuer-url: %q + client-id: sigstore + type: buildkite-job + %v: + issuer-url: %q + client-id: sigstore + type: github-workflow + %v: + issuer-url: %q + client-id: sigstore + type: gitlab-pipeline + %v: + issuer-url: %q + client-id: sigstore + type: codefresh-workflow + meta-issuers: + %v: + client-id: sigstore + type: kubernetes`, + spiffeIssuer, spiffeIssuer, + uriIssuer, uriIssuer, uriIssuer, + emailIssuer, emailIssuer, + usernameIssuer, usernameIssuer, issuerDomain.Hostname(), + buildkiteIssuer, buildkiteIssuer, + gitHubIssuer, gitHubIssuer, + gitLabIssuer, gitLabIssuer, + codefreshIssuer, codefreshIssuer, + k8sIssuer)) + + cfg, err := config.Read(yamlBytes) + if err != nil { + t.Fatalf("config.Read() = %v", err) + } + + ctClient, eca := createCA(cfg, t) + ctx := context.Background() + server, conn := setupGRPCForTest(t, cfg, ctClient, eca) + defer func() { + server.Stop() + conn.Close() + }() + + client := protobuf.NewCAClient(conn) + + config, err := client.GetConfiguration(ctx, &protobuf.GetConfigurationRequest{}) + if err != nil { + t.Fatal("GetConfiguration failed", err) + } + if len(config.Issuers) != 9 { t.Fatalf("expected 9 issuers, got %v", len(config.Issuers)) } @@ -381,9 +539,9 @@ func TestAPIWithEmail(t *testing.T) { Expiry: jwt.NewNumericDate(time.Now().Add(30 * time.Minute)), Subject: c.Subject, Audience: jwt.Audience{"sigstore"}, - }).Claims(customClaims{Email: c.Subject, EmailVerified: true}).CompactSerialize() + }).Claims(customClaims{Email: c.Subject, EmailVerified: true}).Serialize() if err != nil { - t.Fatalf("CompactSerialize() = %v", err) + t.Fatalf("Serialize() = %v", err) } ctClient, eca := createCA(cfg, t) @@ -470,9 +628,9 @@ func TestAPIWithUsername(t *testing.T) { Expiry: jwt.NewNumericDate(time.Now().Add(30 * time.Minute)), Subject: c.Subject, Audience: jwt.Audience{"sigstore"}, - }).Claims(customClaims{Email: c.Subject, EmailVerified: true}).CompactSerialize() + }).Claims(customClaims{Email: c.Subject, EmailVerified: true}).Serialize() if err != nil { - t.Fatalf("CompactSerialize() = %v", err) + t.Fatalf("Serialize() = %v", err) } ctClient, eca := createCA(cfg, t) @@ -568,9 +726,9 @@ func TestAPIWithUriSubject(t *testing.T) { Expiry: jwt.NewNumericDate(time.Now().Add(30 * time.Minute)), Subject: c.Subject, Audience: jwt.Audience{"sigstore"}, - }).CompactSerialize() + }).Serialize() if err != nil { - t.Fatalf("CompactSerialize() = %v", err) + t.Fatalf("Serialize() = %v", err) } ctClient, eca := createCA(cfg, t) @@ -661,9 +819,9 @@ func TestAPIWithKubernetes(t *testing.T) { Expiry: jwt.NewNumericDate(time.Now().Add(30 * time.Minute)), Subject: k8sSubject, Audience: jwt.Audience{"sigstore"}, - }).Claims(&claims).CompactSerialize() + }).Claims(&claims).Serialize() if err != nil { - t.Fatalf("CompactSerialize() = %v", err) + t.Fatalf("Serialize() = %v", err) } ctClient, eca := createCA(cfg, t) @@ -750,9 +908,9 @@ func TestAPIWithBuildkite(t *testing.T) { Expiry: jwt.NewNumericDate(time.Now().Add(30 * time.Minute)), Subject: buildkiteSubject, Audience: jwt.Audience{"sigstore"}, - }).Claims(&claims).CompactSerialize() + }).Claims(&claims).Serialize() if err != nil { - t.Fatalf("CompactSerialize() = %v", err) + t.Fatalf("Serialize() = %v", err) } ctClient, eca := createCA(cfg, t) @@ -868,9 +1026,9 @@ func TestAPIWithGitHub(t *testing.T) { Expiry: jwt.NewNumericDate(time.Now().Add(30 * time.Minute)), Subject: githubSubject, Audience: jwt.Audience{"sigstore"}, - }).Claims(&claims).CompactSerialize() + }).Claims(&claims).Serialize() if err != nil { - t.Fatalf("CompactSerialize() = %v", err) + t.Fatalf("Serialize() = %v", err) } ctClient, eca := createCA(cfg, t) @@ -972,6 +1130,178 @@ func TestAPIWithGitHub(t *testing.T) { } } +// Tests API for CiProvider subject types +func TestAPIWithCiProvider(t *testing.T) { + ciProviderSigner, ciProviderIssuer := newOIDCIssuer(t) + // Create a FulcioConfig that supports these issuers. + cfg, err := config.Read([]byte(fmt.Sprintf(`{ + "OIDCIssuers": { + %q: { + "IssuerURL": %q, + "ClientID": "sigstore", + "Type": "ci-provider", + "CIProvider": "github-workflow" + } + } + }`, ciProviderIssuer, ciProviderIssuer))) + if err != nil { + t.Fatalf("config.Read() = %v", err) + } + claims := githubClaims{ + JobWorkflowRef: "job/workflow/ref", + Sha: "sha", + EventName: "trigger", + Repository: "sigstore/fulcio", + Workflow: "workflow", + Ref: "refs/heads/main", + JobWorkflowSha: "example-sha", + RunnerEnvironment: "cloud-hosted", + RepositoryID: "12345", + RepositoryOwner: "username", + RepositoryOwnerID: "345", + RepositoryVisibility: "public", + WorkflowRef: "sigstore/other/.github/workflows/foo.yaml@refs/heads/main", + WorkflowSha: "example-sha-other", + RunID: "42", + RunAttempt: "1", + } + githubSubject := fmt.Sprintf("repo:%s:ref:%s", claims.Repository, claims.Ref) + // Create an OIDC token using this issuer's signer. + tok, err := jwt.Signed(ciProviderSigner).Claims(jwt.Claims{ + Issuer: ciProviderIssuer, + IssuedAt: jwt.NewNumericDate(time.Now()), + Expiry: jwt.NewNumericDate(time.Now().Add(30 * time.Minute)), + Subject: githubSubject, + Audience: jwt.Audience{"sigstore"}, + }).Claims(&claims).Serialize() + if err != nil { + t.Fatalf("Serialize() = %v", err) + } + + ctClient, eca := createCA(cfg, t) + ctx := context.Background() + cfg.CIIssuerMetadata = make(map[string]config.IssuerMetadata) + cfg.CIIssuerMetadata["github-workflow"] = config.IssuerMetadata{ + ExtensionTemplates: certificate.Extensions{ + Issuer: "issuer", + GithubWorkflowTrigger: "event_name", + GithubWorkflowSHA: "sha", + GithubWorkflowName: "workflow", + GithubWorkflowRepository: "repository", + GithubWorkflowRef: "ref", + BuildSignerURI: "{{ .url }}/{{ .job_workflow_ref }}", + BuildSignerDigest: "job_workflow_sha", + RunnerEnvironment: "runner_environment", + SourceRepositoryURI: "{{ .url }}/{{ .repository }}", + SourceRepositoryDigest: "sha", + SourceRepositoryRef: "ref", + SourceRepositoryIdentifier: "repository_id", + SourceRepositoryOwnerURI: "{{ .url }}/{{ .repository_owner }}", + SourceRepositoryOwnerIdentifier: "repository_owner_id", + BuildConfigURI: "{{ .url }}/{{ .workflow_ref }}", + BuildConfigDigest: "workflow_sha", + BuildTrigger: "event_name", + RunInvocationURI: "{{ .url }}/{{ .repository }}/actions/runs/{{ .run_id }}/attempts/{{ .run_attempt }}", + SourceRepositoryVisibilityAtSigning: "repository_visibility", + }, + DefaultTemplateValues: map[string]string{ + "url": "https://github.com", + }, + SubjectAlternativeNameTemplate: "{{.url}}/{{.job_workflow_ref}}", + } + + server, conn := setupGRPCForTest(t, cfg, ctClient, eca) + defer func() { + server.Stop() + conn.Close() + }() + client := protobuf.NewCAClient(conn) + pubBytes, proof := generateKeyAndProof(githubSubject, t) + // Hit the API to have it sign our certificate. + resp, err := client.CreateSigningCertificate(ctx, &protobuf.CreateSigningCertificateRequest{ + Credentials: &protobuf.Credentials{ + Credentials: &protobuf.Credentials_OidcIdentityToken{ + OidcIdentityToken: tok, + }, + }, + Key: &protobuf.CreateSigningCertificateRequest_PublicKeyRequest{ + PublicKeyRequest: &protobuf.PublicKeyRequest{ + PublicKey: &protobuf.PublicKey{ + Content: pubBytes, + }, + ProofOfPossession: proof, + }, + }, + }) + if err != nil { + t.Fatalf("SigningCert() = %v", err) + } + leafCert := verifyResponse(resp, eca, ciProviderIssuer, t) + // Expect URI values + if len(leafCert.URIs) != 1 { + t.Fatalf("unexpected length of leaf certificate URIs, expected 1, got %d", len(leafCert.URIs)) + } + githubURL := fmt.Sprintf("https://github.com/%s", claims.JobWorkflowRef) + githubURI, err := url.Parse(githubURL) + if err != nil { + t.Fatalf("failed to parse expected url") + } + if *leafCert.URIs[0] != *githubURI { + t.Fatalf("URIs do not match: Expected %v, got %v", githubURI, leafCert.URIs[0]) + } + // Verify custom OID values + deprecatedExpectedExts := map[int]string{ + 2: claims.EventName, + 3: claims.Sha, + 4: claims.Workflow, + 5: claims.Repository, + 6: claims.Ref, + } + for o, value := range deprecatedExpectedExts { + ext, found := findCustomExtension(leafCert, asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, o}) + if !found { + t.Fatalf("expected extension in custom OID 1.3.6.1.4.1.57264.1.%d", o) + } + if string(ext.Value) != value { + t.Fatalf("unexpected extension value, expected %s, got %s", value, ext.Value) + } + } + url := "https://github.com/" + expectedExts := map[int]string{ + 9: url + claims.JobWorkflowRef, + 10: claims.JobWorkflowSha, + 11: claims.RunnerEnvironment, + 12: url + claims.Repository, + 13: claims.Sha, + 14: claims.Ref, + 15: claims.RepositoryID, + 16: url + claims.RepositoryOwner, + 17: claims.RepositoryOwnerID, + 18: url + claims.WorkflowRef, + 19: claims.WorkflowSha, + 20: claims.EventName, + 21: url + claims.Repository + "/actions/runs/" + claims.RunID + "/attempts/" + claims.RunAttempt, + 22: claims.RepositoryVisibility, + } + for o, value := range expectedExts { + ext, found := findCustomExtension(leafCert, asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, o}) + if !found { + t.Fatalf("expected extension in custom OID 1.3.6.1.4.1.57264.1.%d", o) + } + var extValue string + rest, err := asn1.Unmarshal(ext.Value, &extValue) + if err != nil { + t.Fatalf("error unmarshalling extension: :%v", err) + } + if len(rest) != 0 { + t.Fatal("error unmarshalling extension, rest is not 0") + } + if string(extValue) != value { + t.Fatalf("unexpected extension value, expected %s, got %s", value, extValue) + } + } +} + // gitlabClaims holds the additional JWT claims for GitLab OIDC tokens type gitlabClaims struct { ProjectPath string `json:"project_path"` @@ -1036,9 +1366,9 @@ func TestAPIWithGitLab(t *testing.T) { Expiry: jwt.NewNumericDate(time.Now().Add(30 * time.Minute)), Subject: gitLabSubject, Audience: jwt.Audience{"sigstore"}, - }).Claims(&claims).CompactSerialize() + }).Claims(&claims).Serialize() if err != nil { - t.Fatalf("CompactSerialize() = %v", err) + t.Fatalf("Serialize() = %v", err) } ctClient, eca := createCA(cfg, t) @@ -1179,9 +1509,9 @@ func TestAPIWithCodefresh(t *testing.T) { Expiry: jwt.NewNumericDate(time.Now().Add(30 * time.Minute)), Subject: codefreshSubject, Audience: jwt.Audience{"sigstore"}, - }).Claims(&claims).CompactSerialize() + }).Claims(&claims).Serialize() if err != nil { - t.Fatalf("CompactSerialize() = %v", err) + t.Fatalf("Serialize() = %v", err) } ctClient, eca := createCA(cfg, t) @@ -1258,6 +1588,130 @@ func TestAPIWithCodefresh(t *testing.T) { } } +// chainguardClaims holds the additional JWT claims for Chainguard OIDC tokens +type chainguardClaims struct { + Actor map[string]string `json:"act"` + Internal struct { + ServicePrincipal string `json:"service-principal,omitempty"` + } `json:"internal"` +} + +// Tests API for Chainguard subject types +func TestAPIWithChainguard(t *testing.T) { + chainguardSigner, chainguardIssuer := newOIDCIssuer(t) + + // Create a FulcioConfig that supports these issuers. + cfg, err := config.Read([]byte(fmt.Sprintf(`{ + "OIDCIssuers": { + %q: { + "IssuerURL": %q, + "ClientID": "sigstore", + "Type": "chainguard-identity" + } + } + }`, chainguardIssuer, chainguardIssuer))) + if err != nil { + t.Fatalf("config.Read() = %v", err) + } + + group := uidp.NewUIDP("") + chainguardSubject := group.NewChild() + claims := chainguardClaims{ + Actor: map[string]string{ + "iss": chainguardIssuer, + "sub": fmt.Sprintf("catalog-syncer:%s", group.String()), + "aud": "chainguard", + }, + Internal: struct { + ServicePrincipal string `json:"service-principal,omitempty"` + }{ + ServicePrincipal: "CATALOG_SYNCER", + }, + } + + // Create an OIDC token using this issuer's signer. + tok, err := jwt.Signed(chainguardSigner).Claims(jwt.Claims{ + Issuer: chainguardIssuer, + IssuedAt: jwt.NewNumericDate(time.Now()), + Expiry: jwt.NewNumericDate(time.Now().Add(30 * time.Minute)), + Subject: chainguardSubject.String(), + Audience: jwt.Audience{"sigstore"}, + }).Claims(&claims).Serialize() + if err != nil { + t.Fatalf("CompactSerialize() = %v", err) + } + + ctClient, eca := createCA(cfg, t) + ctx := context.Background() + server, conn := setupGRPCForTest(t, cfg, ctClient, eca) + defer func() { + server.Stop() + conn.Close() + }() + + client := protobuf.NewCAClient(conn) + + pubBytes, proof := generateKeyAndProof(chainguardSubject.String(), t) + + // Hit the API to have it sign our certificate. + resp, err := client.CreateSigningCertificate(ctx, &protobuf.CreateSigningCertificateRequest{ + Credentials: &protobuf.Credentials{ + Credentials: &protobuf.Credentials_OidcIdentityToken{ + OidcIdentityToken: tok, + }, + }, + Key: &protobuf.CreateSigningCertificateRequest_PublicKeyRequest{ + PublicKeyRequest: &protobuf.PublicKeyRequest{ + PublicKey: &protobuf.PublicKey{ + Content: pubBytes, + }, + ProofOfPossession: proof, + }, + }, + }) + if err != nil { + t.Fatalf("SigningCert() = %v", err) + } + + leafCert := verifyResponse(resp, eca, chainguardIssuer, t) + + // Expect URI values + if len(leafCert.URIs) != 1 { + t.Fatalf("unexpected length of leaf certificate URIs, expected 1, got %d", len(leafCert.URIs)) + } + chainguardURL := fmt.Sprintf("%s/%s", chainguardIssuer, chainguardSubject) + chainguardURI, err := url.Parse(chainguardURL) + if err != nil { + t.Fatalf("failed to parse expected url") + } + if *leafCert.URIs[0] != *chainguardURI { + t.Fatalf("URIs do not match: Expected %v, got %v", chainguardURI, leafCert.URIs[0]) + } + + expectedExts := map[int]string{ + 8: chainguardIssuer, + + // TODO(mattmoor): Embed more of the Chainguard token structure via OIDs. + } + for o, value := range expectedExts { + ext, found := findCustomExtension(leafCert, asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, o}) + if !found { + t.Fatalf("expected extension in custom OID 1.3.6.1.4.1.57264.1.%d", o) + } + var extValue string + rest, err := asn1.Unmarshal(ext.Value, &extValue) + if err != nil { + t.Fatalf("error unmarshalling extension: :%v", err) + } + if len(rest) != 0 { + t.Fatal("error unmarshalling extension, rest is not 0") + } + if string(extValue) != value { + t.Fatalf("unexpected extension value, expected %s, got %s", value, extValue) + } + } +} + // Tests API with issuer claim in different field in the OIDC token func TestAPIWithIssuerClaimConfig(t *testing.T) { emailSigner, emailIssuer := newOIDCIssuer(t) @@ -1287,9 +1741,9 @@ func TestAPIWithIssuerClaimConfig(t *testing.T) { Expiry: jwt.NewNumericDate(time.Now().Add(30 * time.Minute)), Subject: emailSubject, Audience: jwt.Audience{"sigstore"}, - }).Claims(customClaims{Email: emailSubject, EmailVerified: true, OtherIssuer: otherIssuerVal}).CompactSerialize() + }).Claims(customClaims{Email: emailSubject, EmailVerified: true, OtherIssuer: otherIssuerVal}).Serialize() if err != nil { - t.Fatalf("CompactSerialize() = %v", err) + t.Fatalf("Serialize() = %v", err) } ctClient, eca := createCA(cfg, t) @@ -1363,9 +1817,9 @@ func TestAPIWithCSRChallenge(t *testing.T) { Expiry: jwt.NewNumericDate(time.Now().Add(30 * time.Minute)), Subject: emailSubject, Audience: jwt.Audience{"sigstore"}, - }).Claims(customClaims{Email: emailSubject, EmailVerified: true}).CompactSerialize() + }).Claims(customClaims{Email: emailSubject, EmailVerified: true}).Serialize() if err != nil { - t.Fatalf("CompactSerialize() = %v", err) + t.Fatalf("Serialize() = %v", err) } ctClient, eca := createCA(cfg, t) @@ -1445,9 +1899,9 @@ func TestAPIWithInsecurePublicKey(t *testing.T) { Expiry: jwt.NewNumericDate(time.Now().Add(30 * time.Minute)), Subject: emailSubject, Audience: jwt.Audience{"sigstore"}, - }).Claims(customClaims{Email: emailSubject, EmailVerified: true}).CompactSerialize() + }).Claims(customClaims{Email: emailSubject, EmailVerified: true}).Serialize() if err != nil { - t.Fatalf("CompactSerialize() = %v", err) + t.Fatalf("Serialize() = %v", err) } ctClient, eca := createCA(cfg, t) @@ -1520,9 +1974,9 @@ func TestAPIWithoutPublicKey(t *testing.T) { Expiry: jwt.NewNumericDate(time.Now().Add(30 * time.Minute)), Subject: emailSubject, Audience: jwt.Audience{"sigstore"}, - }).Claims(customClaims{Email: emailSubject, EmailVerified: true}).CompactSerialize() + }).Claims(customClaims{Email: emailSubject, EmailVerified: true}).Serialize() if err != nil { - t.Fatalf("CompactSerialize() = %v", err) + t.Fatalf("Serialize() = %v", err) } ctClient, eca := createCA(cfg, t) @@ -1596,9 +2050,9 @@ func TestAPIWithInvalidChallenge(t *testing.T) { Expiry: jwt.NewNumericDate(time.Now().Add(30 * time.Minute)), Subject: emailSubject, Audience: jwt.Audience{"sigstore"}, - }).Claims(customClaims{Email: emailSubject, EmailVerified: true}).CompactSerialize() + }).Claims(customClaims{Email: emailSubject, EmailVerified: true}).Serialize() if err != nil { - t.Fatalf("CompactSerialize() = %v", err) + t.Fatalf("Serialize() = %v", err) } ctClient, eca := createCA(cfg, t) @@ -1664,9 +2118,9 @@ func TestAPIWithInvalidCSR(t *testing.T) { Expiry: jwt.NewNumericDate(time.Now().Add(30 * time.Minute)), Subject: emailSubject, Audience: jwt.Audience{"sigstore"}, - }).Claims(customClaims{Email: emailSubject, EmailVerified: true}).CompactSerialize() + }).Claims(customClaims{Email: emailSubject, EmailVerified: true}).Serialize() if err != nil { - t.Fatalf("CompactSerialize() = %v", err) + t.Fatalf("Serialize() = %v", err) } ctClient, eca := createCA(cfg, t) @@ -1725,9 +2179,9 @@ func TestAPIWithInvalidCSRSignature(t *testing.T) { Expiry: jwt.NewNumericDate(time.Now().Add(30 * time.Minute)), Subject: emailSubject, Audience: jwt.Audience{"sigstore"}, - }).Claims(customClaims{Email: emailSubject, EmailVerified: true}).CompactSerialize() + }).Claims(customClaims{Email: emailSubject, EmailVerified: true}).Serialize() if err != nil { - t.Fatalf("CompactSerialize() = %v", err) + t.Fatalf("Serialize() = %v", err) } ctClient, eca := createCA(cfg, t) @@ -1801,7 +2255,7 @@ func newOIDCIssuer(t *testing.T) (jose.Signer, string) { oidcMux := http.NewServeMux() - oidcMux.HandleFunc("/.well-known/openid-configuration", func(w http.ResponseWriter, r *http.Request) { + oidcMux.HandleFunc("/.well-known/openid-configuration", func(w http.ResponseWriter, _ *http.Request) { t.Log("Handling request for openid-configuration.") if err := json.NewEncoder(w).Encode(struct { Issuer string `json:"issuer"` @@ -1814,7 +2268,7 @@ func newOIDCIssuer(t *testing.T) (jose.Signer, string) { } }) - oidcMux.HandleFunc("/keys", func(w http.ResponseWriter, r *http.Request) { + oidcMux.HandleFunc("/keys", func(w http.ResponseWriter, _ *http.Request) { t.Log("Handling request for jwks.") if err := json.NewEncoder(w).Encode(jose.JSONWebKeySet{ Keys: []jose.JSONWebKey{ diff --git a/pkg/server/issuer_pool.go b/pkg/server/issuer_pool.go index 9905df5cb..61e05fa34 100644 --- a/pkg/server/issuer_pool.go +++ b/pkg/server/issuer_pool.go @@ -18,6 +18,8 @@ import ( "github.com/sigstore/fulcio/pkg/config" "github.com/sigstore/fulcio/pkg/identity" "github.com/sigstore/fulcio/pkg/identity/buildkite" + "github.com/sigstore/fulcio/pkg/identity/chainguard" + "github.com/sigstore/fulcio/pkg/identity/ciprovider" "github.com/sigstore/fulcio/pkg/identity/codefresh" "github.com/sigstore/fulcio/pkg/identity/email" "github.com/sigstore/fulcio/pkg/identity/github" @@ -56,12 +58,16 @@ func getIssuer(meta string, i config.OIDCIssuer) identity.Issuer { return email.Issuer(issuerURL) case config.IssuerTypeGithubWorkflow: return github.Issuer(issuerURL) + case config.IssuerTypeCIProvider: + return ciprovider.Issuer(issuerURL) case config.IssuerTypeGitLabPipeline: return gitlabcom.Issuer(issuerURL) case config.IssuerTypeBuildkiteJob: return buildkite.Issuer(issuerURL) case config.IssuerTypeCodefreshWorkflow: return codefresh.Issuer(issuerURL) + case config.IssuerTypeChainguard: + return chainguard.Issuer(issuerURL) case config.IssuerTypeKubernetes: return kubernetes.Issuer(issuerURL) case config.IssuerTypeSpiffe: diff --git a/release/cloudbuild.yaml b/release/cloudbuild.yaml index 92ffe08f1..86bfbe3ac 100644 --- a/release/cloudbuild.yaml +++ b/release/cloudbuild.yaml @@ -32,19 +32,19 @@ steps: echo "Checking out ${_GIT_TAG}" git checkout ${_GIT_TAG} - - name: 'gcr.io/projectsigstore/cosign:v2.2.3-dev@sha256:0d795fa145b03026b7bc2a35e33068cdb75e1c1f974e604c17408bf7bd174967' + - name: 'gcr.io/projectsigstore/cosign:v2.2.4-dev@sha256:13efd4c62710d75f07d12d8aad36a8657eeffd4f5f3a40bcbc207d8aafa67d41' dir: "go/src/sigstore/fulcio" env: - TUF_ROOT=/tmp args: - 'verify' - - 'ghcr.io/gythialy/golang-cross:v1.21.8-0@sha256:9c86fc6c6763cd5cd9a07f25083fc5a87f3525b5f8d7ff886822e2153f0c8405' + - 'ghcr.io/gythialy/golang-cross:v1.22.5-0@sha256:5cf8fca7fe80392c8d1597fe89d291d49120507390f25507746f73d4b7f8a8f2' - '--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.21.8-0" + - "https://github.com/gythialy/golang-cross/.github/workflows/release-golang-cross.yml@refs/tags/v1.22.5-0" - - name: ghcr.io/gythialy/golang-cross:v1.21.8-0@sha256:9c86fc6c6763cd5cd9a07f25083fc5a87f3525b5f8d7ff886822e2153f0c8405 + - name: ghcr.io/gythialy/golang-cross:v1.22.5-0@sha256:5cf8fca7fe80392c8d1597fe89d291d49120507390f25507746f73d4b7f8a8f2 entrypoint: /bin/sh dir: "go/src/sigstore/fulcio" env: @@ -67,7 +67,7 @@ steps: gcloud auth configure-docker \ && make release - - name: ghcr.io/gythialy/golang-cross:v1.21.8-0@sha256:9c86fc6c6763cd5cd9a07f25083fc5a87f3525b5f8d7ff886822e2153f0c8405 + - name: ghcr.io/gythialy/golang-cross:v1.22.5-0@sha256:5cf8fca7fe80392c8d1597fe89d291d49120507390f25507746f73d4b7f8a8f2 entrypoint: 'bash' dir: "go/src/sigstore/fulcio" env: diff --git a/release/release.mk b/release/release.mk index 93bd1bf19..4c96953b5 100644 --- a/release/release.mk +++ b/release/release.mk @@ -10,7 +10,7 @@ release: # used when need to validate the goreleaser .PHONY: snapshot snapshot: - LDFLAGS="$(LDFLAGS)" goreleaser release --skip-sign --skip-publish --snapshot --rm-dist + LDFLAGS="$(LDFLAGS)" goreleaser release --skip=sign,publish --snapshot --clean ################## diff --git a/tools/loadtest/README.md b/tools/loadtest/README.md index 0e2af9930..1a5d7f014 100644 --- a/tools/loadtest/README.md +++ b/tools/loadtest/README.md @@ -24,7 +24,7 @@ Confirm a successful install with `locust -V`, which should print the version. Y ### Fetching identity token -To fetch a certificate, you will need an OIDC token from one of the [OIDC issuers](https://github.com/sigstore/fulcio/blob/main/config/fulcio-config.yaml). One way is to fetch a token from Google. Note that you will need to install [`gcloud`](https://cloud.google.com/sdk/gcloud) and create a service account. A service account is necessary for the `--include-email` flag, which is needed to get an OIDC token with the correct format for Fulcio. +To fetch a certificate, you will need an OIDC token from one of the [OIDC issuers](https://github.com/sigstore/fulcio/blob/main/config/identity/config.yaml). One way is to fetch a token from Google. Note that you will need to install [`gcloud`](https://cloud.google.com/sdk/gcloud) and create a service account. A service account is necessary for the `--include-email` flag, which is needed to get an OIDC token with the correct format for Fulcio. Run the following command, and record the output: