diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index da086cba8..a6bb8547b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -34,23 +34,23 @@ jobs: contents: read steps: - - uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b # v3.2.0 - - uses: sigstore/cosign-installer@9becc617647dfa20ae7b1151972e9b3a2c338a2b # v2.8.1 + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + - uses: sigstore/cosign-installer@11086d25041f77fe8fe7b9ea4e48e3b9192b8f19 # v3.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@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0 + - uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 with: go-version: ${{ env.GOVERSION }} - name: deps run: sudo apt-get update && sudo apt-get install -yq libpcsclite-dev - - uses: imjasonh/setup-ko@ace48d793556083a76f1e3e6068850c1f4a369aa # v0.6 + - uses: ko-build/setup-ko@ace48d793556083a76f1e3e6068850c1f4a369aa # v0.6 - name: Set up Cloud SDK - uses: google-github-actions/auth@ef5d53e30bbcd8d0836f4288f5e50ff3e086997d # v1.0.0 + uses: google-github-actions/auth@35b0e87d162680511bf346c299f71c9c5c379033 # v1.1.1 with: workload_identity_provider: 'projects/498091336538/locations/global/workloadIdentityPools/githubactions/providers/sigstore-rekor' service_account: 'github-actions-rekor@projectsigstore.iam.gserviceaccount.com' @@ -61,4 +61,4 @@ jobs: - name: container run: KO_PREFIX=gcr.io/projectsigstore/rekor/ci/rekor make sign-keyless-ci env: - COSIGN_EXPERIMENTAL: true + COSIGN_YES: true diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index f541f6508..930998714 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -42,16 +42,16 @@ jobs: language: [ 'go' ] steps: - name: Checkout repository - uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b # v3.2.0 + uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@959cbb7472c4d4ad70cdfe6f4976053fe48ab394 # v2.1.37 + uses: github/codeql-action/init@cdcdbb579706841c47f7063dda365e292e5cad7a # v2.13.4 with: languages: ${{ matrix.language }} - name: Autobuild - uses: github/codeql-action/autobuild@959cbb7472c4d4ad70cdfe6f4976053fe48ab394 # v2.1.37 + uses: github/codeql-action/autobuild@cdcdbb579706841c47f7063dda365e292e5cad7a # v2.13.4 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@959cbb7472c4d4ad70cdfe6f4976053fe48ab394 # v2.1.37 + uses: github/codeql-action/analyze@cdcdbb579706841c47f7063dda365e292e5cad7a # v2.13.4 diff --git a/.github/workflows/cosign.key b/.github/workflows/cosign.key deleted file mode 100644 index 48cf0abe5..000000000 --- a/.github/workflows/cosign.key +++ /dev/null @@ -1,11 +0,0 @@ ------BEGIN ENCRYPTED COSIGN PRIVATE KEY----- -eyJrZGYiOnsibmFtZSI6InNjcnlwdCIsInBhcmFtcyI6eyJOIjozMjc2OCwiciI6 -OCwicCI6MX0sInNhbHQiOiJxM1c0U29HL0JhNGY5YUZWbXZlYWNFelJjTmU4amRq -Qlo5MXFZR0lGK2EwPSJ9LCJjaXBoZXIiOnsibmFtZSI6Im5hY2wvc2VjcmV0Ym94 -Iiwibm9uY2UiOiJEa2JGQ2hwUE84b0krRzVxQ01lRE5TaDhUOUJETGpZUSJ9LCJj -aXBoZXJ0ZXh0IjoiYTl4YkdDUnJRUnVrTWNvZmh1QWFXOUo3UDEvazBzemgvUjJM -QWNVTVdrT1B5QkVKQndMSEYzaEZLWlFxOHIwRVcyQ0d4VmJyd1FxaG1Zd0NXUmg2 -RlBuSUdBbVFZbmc3MmNSaUZmTEZZVUg3czl5bnFhcWYzOFQzc1dTUGhhcTlZRHJU -d0k3Q2djR1Yyc0pzUUZRd2hFZVAwV2p1SGFXdWVyeDJRdDBKdEl2K2llbG0rb0gy -UUI5L2NJb0w4T2grUE0xN3NzOXRCMUdwQkE9PSJ9 ------END ENCRYPTED COSIGN PRIVATE KEY----- diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 98eb6d5d2..afa880583 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -30,13 +30,13 @@ permissions: jobs: build: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - - uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b # v3.2.0 + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.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 - - uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0 + - uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 with: go-version: ${{ env.GOVERSION }} @@ -47,23 +47,23 @@ jobs: - name: Test run: go test -v -coverprofile=coverage.txt -covermode=atomic ./... - name: Upload Coverage Report - uses: codecov/codecov-action@d9f34f8cd5cb3b3eb79b3e4b5dae3a16df499a70 # v3.1.1 + uses: codecov/codecov-action@eaaf4bedf32dbdc6b720b63067d99c4d77d6047d # v3.1.4 with: flags: unittests - name: Ensure no files were modified as a result of the build run: git update-index --refresh && git diff-index --quiet HEAD -- || git diff --exit-code container-build: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - - uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b # v3.2.0 + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.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 - - uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0 + - uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 with: go-version: ${{ env.GOVERSION }} - - uses: imjasonh/setup-ko@ace48d793556083a76f1e3e6068850c1f4a369aa # v0.6 + - uses: ko-build/setup-ko@ace48d793556083a76f1e3e6068850c1f4a369aa # v0.6 - name: container run: | @@ -73,16 +73,18 @@ jobs: docker run --rm $(cat redisImagerefs) --version e2e: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest needs: build steps: - name: download minisign - run: sudo add-apt-repository ppa:dysfunctionalprogramming/minisign && sudo apt-get update && sudo apt-get install minisign - - uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b # v3.2.0 + # run: sudo add-apt-repository ppa:dysfunctionalprogramming/minisign && sudo apt-get update && sudo apt-get install minisign + run: sudo add-apt-repository ppa:savoury1/minisign && sudo apt-get update && sudo apt-get install minisign + + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.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 - - uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0 + - uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 with: go-version: ${{ env.GOVERSION }} - name: install gocovmerge @@ -93,82 +95,83 @@ jobs: - name: Refactor-e2e # this will a WIP to move all the tests to respective packages run: ./e2e-test.sh - name: Upload logs if they exist - uses: actions/upload-artifact@83fd05a356d7e2593de66fc9913b3002723633cb # v3.1.1 + uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 if: failure() with: name: E2E Docker Compose logs path: /tmp/docker-compose.log - name: Upload Coverage Report - uses: codecov/codecov-action@81cd2dc8148241f03f5839d295e000b8f761e378 # v3.1.1 + uses: codecov/codecov-action@eaaf4bedf32dbdc6b720b63067d99c4d77d6047d # v3.1.4 with: files: /tmp/rekor-merged.cov,/tmp/pkg-rekor-merged.cov flags: e2etests sharding-e2e: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest needs: build steps: - name: download minisign - run: sudo add-apt-repository ppa:dysfunctionalprogramming/minisign && sudo apt-get update && sudo apt-get install minisign - - uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b # v3.2.0 + # run: sudo add-apt-repository ppa:dysfunctionalprogramming/minisign && sudo apt-get update && sudo apt-get install minisign + run: sudo add-apt-repository ppa:savoury1/minisign && sudo apt-get update && sudo apt-get install minisign + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 - name: Docker Build run: docker-compose build - 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@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0 + - uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 with: go-version: ${{ env.GOVERSION }} - name: Sharding Test run: ./tests/sharding-e2e-test.sh - name: Upload logs if they exist - uses: actions/upload-artifact@83fd05a356d7e2593de66fc9913b3002723633cb # v3.1.1 + uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 if: failure() with: name: Sharding E2E Docker Compose logs path: /tmp/docker-compose.log issue-872-e2e: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest needs: build steps: - - uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b # v3.2.0 + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 - name: Docker Build run: docker-compose build - 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@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0 + - uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 with: go-version: ${{ env.GOVERSION }} - name: Test for Attestation begin returned that was previously persisted in tlog run: ./tests/issue-872-e2e-test.sh - name: Upload logs if they exist - uses: actions/upload-artifact@83fd05a356d7e2593de66fc9913b3002723633cb # v3.1.1 + uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 if: failure() with: name: Docker Compose logs path: /tmp/*docker-compose.log harness: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest needs: build steps: - - uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b # v3.2.0 + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 - name: Create git branch run: git switch -c harness-test-branch - 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@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0 + - uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 with: go-version: ${{ env.GOVERSION }} - name: Run test harness run: ./tests/rekor-harness.sh - name: Upload logs if they exist - uses: actions/upload-artifact@83fd05a356d7e2593de66fc9913b3002723633cb # v3.1.1 + uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 if: failure() with: name: E2E Docker Compose logs diff --git a/.github/workflows/milestone.yml b/.github/workflows/milestone.yml index 91a32961a..d7d864cae 100644 --- a/.github/workflows/milestone.yml +++ b/.github/workflows/milestone.yml @@ -24,7 +24,7 @@ jobs: statuses: none steps: - - uses: actions/github-script@d556feaca394842dc55e4734bf3bb9f685482fa0 # v6.3.3 + - uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # v6.4.1 with: script: | if (!context.payload.pull_request.merged) { diff --git a/.github/workflows/scorecard_action.yml b/.github/workflows/scorecard_action.yml index 7c5c6ae0b..b3f3bdfac 100644 --- a/.github/workflows/scorecard_action.yml +++ b/.github/workflows/scorecard_action.yml @@ -10,50 +10,22 @@ on: - main - 'release-**' -# Declare default permissions as read only. -permissions: read-all +# Declare default permissions as none. +permissions: {} jobs: analysis: - name: Scorecards analysis - runs-on: ubuntu-latest + name: Scorecard analysis permissions: # Needed to upload the results to code-scanning dashboard. security-events: write - actions: read - contents: read + # Needed to publish results and get a badge (see publish_results below). id-token: write - steps: - - name: "Checkout code" - uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b # v3.2.0 - with: - persist-credentials: false + uses: sigstore/community/.github/workflows/reusable-scorecard.yml@d0c95c8803672313d0bf72e1a44021be5b583c24 # main + # (Optional) Disable publish results: + # with: + # publish_results: false - - name: "Run analysis" - uses: ossf/scorecard-action@e38b1902ae4f44df626f11ba0734b14fb91f8f86 # v2.1.2 - with: - results_file: results.sarif - results_format: sarif - # Read-only PAT token. To create it, - # follow the steps in https://github.com/ossf/scorecard-action#pat-token-creation. - repo_token: ${{ secrets.SCORECARD_TOKEN }} - # Publish the results for public repositories to enable scorecard badges. For more details, see - # https://github.com/ossf/scorecard-action#publishing-results. - # For private repositories, `publish_results` will automatically be set to `false`, regardless - # of the value entered here. - publish_results: true - - # 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@83fd05a356d7e2593de66fc9913b3002723633cb # v3.1.1 - with: - name: SARIF file - path: results.sarif - retention-days: 5 - - # Upload the results to GitHub's code scanning dashboard. - - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@959cbb7472c4d4ad70cdfe6f4976053fe48ab394 # v2.1.37 - with: - sarif_file: results.sarif + # (Optional) Enable Branch-Protection check: + secrets: + scorecard_token: ${{ secrets.SCORECARD_TOKEN }} diff --git a/.github/workflows/validate-release.yml b/.github/workflows/validate-release.yml index 19f2cbbed..84e9822c0 100644 --- a/.github/workflows/validate-release.yml +++ b/.github/workflows/validate-release.yml @@ -22,50 +22,45 @@ on: - 'release-**' pull_request: +permissions: {} + jobs: - validate-release-job: + check-signature: runs-on: ubuntu-latest + container: + image: gcr.io/projectsigstore/cosign:v2.2.0@sha256:280b47054876d415f66a279e666e35157cae6881f3538599710290c70bb75369 - permissions: - actions: none - checks: none - contents: none - deployments: none - issues: none - packages: none - pull-requests: none - repository-projects: none - security-events: none - statuses: none + steps: + - name: Check Signature + run: | + cosign verify ghcr.io/gythialy/golang-cross:v1.21.1-0@sha256:7864d898e45db9d749f14180051edb46ff61bf42914e3b8ecddec5a36813aa6c \ + --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.1-0" + env: + TUF_ROOT: /tmp - env: - CROSS_BUILDER_IMAGE: ghcr.io/gythialy/golang-cross:v1.19.4-0@sha256:53ee894818ac14377996a6fe7c8fe6156d018a20f82aaf69f2519fc45d897bec - COSIGN_IMAGE: gcr.io/projectsigstore/cosign:v1.13.1@sha256:fd5b09be23ef1027e1bdd490ce78dcc65d2b15902e1f4ba8e04f3b4019cc1057 + validate-release-job: + runs-on: ubuntu-latest + needs: + - check-signature + container: + image: ghcr.io/gythialy/golang-cross:v1.21.1-0@sha256:7864d898e45db9d749f14180051edb46ff61bf42914e3b8ecddec5a36813aa6c steps: - - uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b # v3.2.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 - - uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0 - with: - go-version: ${{ env.GOVERSION }} - - - uses: anchore/sbom-action/download-syft@06e109483e6aa305a2b2395eabae554e51530e1d # v0.13.1 - - name: Install GoReleaser - uses: goreleaser/goreleaser-action@8f67e590f2d095516493f017008adc464e63adb1 # v4.1.0 - with: - install-only: true + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 - - name: Check Signature - run: | - docker run --rm \ - -e COSIGN_EXPERIMENTAL=true \ - -e TUF_ROOT=/tmp \ - $COSIGN_IMAGE \ - verify \ - $CROSS_BUILDER_IMAGE + # Error: fatal: detected dubious ownership in repository at '/__w/rekor/rekor' + # To add an exception for this directory, call: + # git config --system --add safe.directory /__w/rekor/rekor + # Reason: Recent versions of git require the .git folder to be owned + # by the same user (see https://github.blog/2022-04-12-git-security-vulnerability-announced/). + # Related + # - https://github.com/actions/runner/issues/2033 + # - https://github.com/actions/checkout/issues/1048 + # - https://github.com/actions/runner-images/issues/6775 + - run: git config --system --add safe.directory /__w/rekor/rekor - - name: snaphot + - name: goreleaser snapshot run: make snapshot env: PROJECT_ID: honk-fake-project diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index 8e9f20be2..3d6f6ff91 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -29,10 +29,10 @@ jobs: name: license boilerplate check runs-on: ubuntu-latest steps: - - uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b # v3.2.0 + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.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 - - uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0 + - uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 with: go-version: ${{ env.GOVERSION }} @@ -48,15 +48,15 @@ jobs: name: lint runs-on: ubuntu-latest steps: - - uses: actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b # v3.2.0 + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.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 - - uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0 + - uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 with: go-version: ${{ env.GOVERSION }} - name: golangci-lint - uses: golangci/golangci-lint-action@0ad9a0988b3973e851ab0a07adf248ec2e100376 # v3.3.1 + uses: golangci/golangci-lint-action@3a919529898de77ec3da873e3063ca4b10e7f5cc # v3.7.0 timeout-minutes: 5 with: - version: v1.49 + version: v1.54 diff --git a/.goreleaser.yml b/.goreleaser.yml index 40bee8674..94d0630a7 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -4,7 +4,7 @@ env: - GO111MODULE=on - CGO_ENABLED=0 - DOCKER_CLI_EXPERIMENTAL=enabled - - COSIGN_EXPERIMENTAL=true + - COSIGN_YES=true # Prevents parallel builds from stepping on eachothers toes downloading modules before: @@ -20,7 +20,7 @@ gomod: proxy: true sboms: -- artifacts: binary + - artifacts: binary builds: - id: rekor-server-linux diff --git a/.ko.yaml b/.ko.yaml index 18c35c779..18b4c9d2c 100644 --- a/.ko.yaml +++ b/.ko.yaml @@ -13,8 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -# We need a shell for a lot of redirection/piping to work -defaultBaseImage: gcr.io/distroless/base:debug-nonroot +defaultBaseImage: gcr.io/distroless/static-debian12:nonroot builds: - id: rekor-server diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a45fbb26..180f1eec4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,210 @@ +# v1.3.0 + +## New Features +* feat: Support publishing new log entries to Pub/Sub topics (#1580) +* Change values of Identity.Raw, add fingerprints (#1628) +* Extract all subjects from SANs for x509 verifier (#1632) +* Fix type comment for Identity struct (#1619) +* Refactor Identities API (#1611) +* Refactor Verifiers to return multiple keys (#1601) + +## Quality Enhancements +* set min go version to 1.21 (#1651) +* Upgrade to go1.21 (#1636) + +## Bug Fixes +* Update openapi.yaml (#1655) +* pass transient errors through retrieveLogEntry (#1653) +* return full entryID on HTTP 409 responses (#1650) +* Update checkpoint link (#1597) +* Use correct log index in inclusion proof (#1599) +* remove instrumentation library (#1595) +* pki: clean up fuzzer (#1594) +* alpine: add max metadata size to fuzzer (#1571) + +## Contributors +* AdamKorcz +* Appu +* Bob Callaway +* Carlos Tadeu Panato Junior +* Ceridwen Coghlan +* Hayden B +* James Alseth + +# v1.2.2 + +## Quality Enhancements +* swap killswitch for 'docker-compose restart' (#1562) +* pass treeSize and rootHash to avoid trillian import (#1513) +* Move github.com/sigstore/protobuf-specs users into a separate subpackage (#1511) + +## Bug Fixes +* pass down error with message instead of nil (#1560) + +## Contributors +* Bob Callaway +* Carlos Tadeu Panato Junior +* Eng Zer Jun +* Miloslav Trmač + +# v1.2.1 + +## Bug Fixes +* run go mod tidy in hack/tools (#1510) + +## Contributors +* Bob Callaway + +# v1.2.0 + +## Functional Enhancements +* add client method to generate TLE struct (#1498) +* add dsse type (#1487) +* support other KMS providers (AWS, Azure, Hashicorp) in addition to GCP (#1488) +* Add concurrency to backfill-redis (#1504) +* omit informational message if machine-parseable output has been requested (#1486) +* Publish stable checkpoint periodically to Redis (#1461) +* Add intoto v0.0.2 to backfill script (#1500) +* add new method to test insertability of proposed entries into log (#1410) + +## Quality Enhancements +* use t.Skip() in fuzzers (#1506) +* improve fuzzing coverage (#1499) +* Remove watcher script (#1484) + +## Bug Fixes +* Merge pull request from GHSA-frqx-jfcm-6jjr +* Remove requirement of PayloadHash for intoto 0.0.1 (#1490) +* fix lint errors, bump linter up to 1.52 (#1485) +* Remove dependencies from pkg/util (#1469) + +## Contributors +* Bob Callaway +* Carlos Tadeu Panato Junior +* Ceridwen Coghlan +* Cody Soyland +* Hayden B +* Miloslav Trmač + +# v1.1.1 + +## Functional Enhancements +* Refactor Trillian client with exported methods (#1454) +* Switch to official redis-go client (#1459) +* Remove replace in go.mod (#1444) +* Add Rekor OID info. (#1390) + +## Quality Enhancements +* remove legacy encrypted cosign key (#1446) +* swap cjson dependency (#1441) +* Update release readme (#1456) + +## Bug Fixes +* Merge pull request from GHSA-2h5h-59f5-c5x9 + +## Contributors +* Billy Lynch +* Bob Callaway +* Carlos Tadeu Panato Junior +* Ceridwen Coghlan +* Hayden B + +# v1.1.0 + +## Functional Enhancements +* improve validation on intoto v0.0.2 type (#1351) +* add feature to limit HTTP request body length to process (#1334) +* add information about the file size limit (#1313) +* Add script to backfill Redis from Rekor (#1163) +* Feature: add search support for sha512 (#1142) + +## Quality Enhancements +* fuzzing: refactor OSS-Fuzz build script (#1377) +* Update cloudbuild for cosign 2.0 (#1375) +* Tests - Additional sharding tests (#1180) +* jar type: add fuzzer for 3rd-party dep (#1360) +* update cosign to 2.0.0 and builder image and also cosign flags (#1368) +* fuzzing: move alpine utils to fuzz utils (#1335) +* fuzzing: add seed for alpine fuzzer (#1342) +* jar: add v001 fuzzer (#1327) +* fuzzing: open writer later in fuzz utils (#1326) +* fuzzing: remove tar operations in alpine fuzzer (#1322) +* alpine: add v001 fuzzer (#1316) +* hashedrekord: add v001 fuzzer (#1315) +* fuzzing: add call to IndexKeys in multiple fuzzers (#1302) +* fuzzing: improve cose fuzzer (#1300) +* fuzzing: improve fuzz utils (#1298) +* fuzzing: improve alpine fuzzer (#1273) +* fuzzing: go mod edit go-fuzz-headers (#1272) +* fuzzing: add .options file (#1271) +* fuzzing: build helm fuzzer from correct dir (#1264) +* types: refactor multiple fuzzers (#1258) +* helm: add fuzzer for provenance unmarshalling (#1243) +* pki: add fuzzer (#1256) +* Fuzzing: Add more bug detectors (#1253) +* Refactor e2e - part 5 (#1236) +* Removed unused tool/deps (#1244) +* Fixed the invalid path (#1245) +* Run latest fuzzers in OSS-Fuzz (#1221) +* Fuzz tests - hashedrekord (#1224) +* Update builder (#1228) +* Revamping rekor e2e - part 4 of N (#1218) +* types: add fuzzers (#1225) +* jar type: add fuzzer (#1215) +* Revamping rekor e2e - part 3 of N (#1177) +* modify OSS-Fuzz build script (#1214) +* move over oss-fuzz build script (#1204) +* wrap redis client errors to aid debugging (#1176) +* don't test release candidate builds in harness (#1183) +* types/alpine: add fuzzer (#1200) +* logging tweaks to improve usability (#1235) +* Add backfill-redis to the release artifacts (#1174) +* ensure jobs run on release branches (#1181) +* update builder image and cosign (#1165) +* Refactor e2e tests - x509 apk (#1152) +* Sharding - Additional tests (#1156) +* Ran gofmt and cleaned up (#1157) +* Fuzz - Fuzz tests for sharding (#1147) +* Revamping rekor e2e - part 1 of N (#1089) + +## Bug Fixes +* remove goroutine usage from SearchLogQuery (#1407) +* drop log messages regarding attestation storage to debug (#1408) +* fix ko-local build (#1381) +* disable blocking checks (#1353) +* fix validation for proposed vs committed log entries for intoto v0.0.1 (#1309) +* fix: fix regex for multi-digit counts (#1321) +* return NotFound if treesize is 0 rather than calling trillian (#1311) +* enumerate slice to get sugared logs (#1312) +* put a reasonable size limit on ssh key reader (#1288) +* CLIENT: Fix Custom Host and Path Issue (#1306) +* do not persist local state if log is empty; fail consistency proofs from 0 size (#1290) +* correctly handle invalid or missing pki format (#1281) +* Add Verifier to get public key/cert and identities for entry type (#1210) +* fix goroutine leak in client; add insecure TLS option (#1238) +* Fix - Remove the force-recreate flag (#1179) +* trim whitespace around public keys before parsing (#1175) +* stop inserting envelope hash for intoto:0.0.2 types into index (#1171) +* Revert "remove double encoding of payload and signature fields for intoto (#1150)" (#1158) +* remove double encoding of payload and signature fields for intoto (#1150) +* fix SearchLogQuery behavior to conform to openapi spec (#1145) +* Remove pem-certificate-chain from client (#1138) +* fix flag type for operator in search (#1136) +* use sigstore/community dep review (#1132) + +## Contributors +* AdamKorcz +* Batuhan Apaydın +* Bob Callaway +* Carlos Tadeu Panato Junior +* Fabian Kammel +* Fredrik Skogman +* Hayden B +* Joyce +* Naveen +* Noah Kreiger +* Priya Wadhwa + # v1.0.1 ## Enhancements diff --git a/Dockerfile b/Dockerfile index ef769a1b4..067c23897 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,7 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -FROM golang:1.19.4@sha256:660f138b4477001d65324a51fa158c1b868651b44e43f0953bf062e9f38b72f3 AS builder +FROM golang:1.21.1@sha256:c416ceeec1cdf037b80baef1ccb402c230ab83a9134b34c0902c542eb4539c82 AS builder ENV APP_ROOT=/opt/app-root ENV GOPATH=$APP_ROOT @@ -31,7 +31,7 @@ RUN CGO_ENABLED=0 go build -gcflags "all=-N -l" -ldflags "${SERVER_LDFLAGS}" -o RUN go test -c -ldflags "${SERVER_LDFLAGS}" -cover -covermode=count -coverpkg=./... -o rekor-server_test ./cmd/rekor-server # Multi-Stage production build -FROM golang:1.19.4@sha256:660f138b4477001d65324a51fa158c1b868651b44e43f0953bf062e9f38b72f3 as deploy +FROM golang:1.21.1@sha256:c416ceeec1cdf037b80baef1ccb402c230ab83a9134b34c0902c542eb4539c82 as deploy # Retrieve the binary from the previous stage COPY --from=builder /opt/app-root/src/rekor-server /usr/local/bin/rekor-server @@ -41,7 +41,7 @@ CMD ["rekor-server", "serve"] # debug compile options & debugger FROM deploy as debug -RUN go install github.com/go-delve/delve/cmd/dlv@v1.8.0 +RUN go install github.com/go-delve/delve/cmd/dlv@v1.21.0 # overwrite server and include debugger COPY --from=builder /opt/app-root/src/rekor-server_debug /usr/local/bin/rekor-server diff --git a/Dockerfile.pubsub-emulator b/Dockerfile.pubsub-emulator new file mode 100644 index 000000000..81f4f9bf0 --- /dev/null +++ b/Dockerfile.pubsub-emulator @@ -0,0 +1,3 @@ +# gcloud sdk for pubsub emulator with netcat added for the startup health check +FROM google/cloud-sdk:447.0.0@sha256:e2db260427a55fc74c5ab1a51d0bafb51ff7719229c83088fffa258add6378ab +RUN apt-get install -y netcat diff --git a/Makefile b/Makefile index 987e8c31f..4904ad9a6 100644 --- a/Makefile +++ b/Makefile @@ -13,7 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -.PHONY: all test clean clean-gen lint gosec ko ko-local sign-container cross-cli gocovmerge +.PHONY: all test clean clean-gen lint gosec ko ko-local cross-cli gocovmerge all: rekor-cli rekor-server @@ -65,8 +65,8 @@ SERVER_LDFLAGS=$(REKOR_LDFLAGS) Makefile.swagger: $(SWAGGER) $(OPENAPIDEPS) $(SWAGGER) validate openapi.yaml - $(SWAGGER) generate client -f openapi.yaml -q -r COPYRIGHT.txt -t pkg/generated --additional-initialism=TUF - $(SWAGGER) generate server -f openapi.yaml -q -r COPYRIGHT.txt -t pkg/generated --exclude-main -A rekor_server --flag-strategy=pflag --default-produces application/json --additional-initialism=TUF + $(SWAGGER) generate client -f openapi.yaml -q -r COPYRIGHT.txt -t pkg/generated --additional-initialism=TUF --additional-initialism=DSSE + $(SWAGGER) generate server -f openapi.yaml -q -r COPYRIGHT.txt -t pkg/generated --exclude-main -A rekor_server --flag-strategy=pflag --default-produces application/json --additional-initialism=TUF --additional-initialism=DSSE @echo "# This file is generated after swagger runs as part of the build; do not edit!" > Makefile.swagger @echo "SWAGGER_GEN=`find pkg/generated/client pkg/generated/models pkg/generated/restapi -iname '*.go' | grep -v 'configure_rekor_server' | sort -d | tr '\n' ' ' | sed 's/ $$//'`" >> Makefile.swagger; @@ -83,7 +83,7 @@ rekor-server: $(SRCS) CGO_ENABLED=0 go build -trimpath -ldflags "$(SERVER_LDFLAGS)" -o rekor-server ./cmd/rekor-server backfill-redis: $(SRCS) - CGO_ENABLED=0 go build -trimpath -ldflags "$(SERVER_LDFLAGS)" -o rekor-server ./cmd/backfill-redis + CGO_ENABLED=0 go build -trimpath -ldflags "$(SERVER_LDFLAGS)" -o backfill-redis ./cmd/backfill-redis test: go test ./... @@ -135,30 +135,26 @@ e2e: go test -c -tags=e2e ./pkg/pki/tuf go test -c -tags=e2e ./pkg/types/rekord -sign-container: ko - cosign sign --key .github/workflows/cosign.key -a GIT_HASH=$(GIT_HASH) $(KO_DOCKER_REPO)/rekor-server:$(GIT_HASH) - cosign sign --key .github/workflows/cosign.key -a GIT_HASH=$(GIT_HASH) $(KO_DOCKER_REPO)/rekor-cli:$(GIT_HASH) - .PHONY: sign-keyless-ci sign-keyless-ci: ko - cosign sign --force -a GIT_HASH=$(GIT_HASH) $(KO_DOCKER_REPO)/rekor-server:$(GIT_HASH) - cosign sign --force -a GIT_HASH=$(GIT_HASH) $(KO_DOCKER_REPO)/rekor-cli:$(GIT_HASH) + cosign sign --yes -a GIT_HASH=$(GIT_HASH) $(KO_DOCKER_REPO)/rekor-server:$(GIT_HASH) + cosign sign --yes -a GIT_HASH=$(GIT_HASH) $(KO_DOCKER_REPO)/rekor-cli:$(GIT_HASH) .PHONY: ko-local ko-local: - LDFLAGS="$(SERVER_LDFLAGS)" GIT_HASH=$(GIT_HASH) GIT_VERSION=$(GIT_VERSION) \ + KO_DOCKER_REPO=ko.local LDFLAGS="$(SERVER_LDFLAGS)" GIT_HASH=$(GIT_HASH) GIT_VERSION=$(GIT_VERSION) \ ko publish --base-import-paths \ - --tags $(GIT_VERSION) --tags $(GIT_HASH) --local --image-refs rekorImagerefs \ + --tags $(GIT_VERSION) --tags $(GIT_HASH) --image-refs rekorImagerefs \ github.com/sigstore/rekor/cmd/rekor-server - LDFLAGS="$(CLI_LDFLAGS)" GIT_HASH=$(GIT_HASH) GIT_VERSION=$(GIT_VERSION) \ + KO_DOCKER_REPO=ko.local LDFLAGS="$(CLI_LDFLAGS)" GIT_HASH=$(GIT_HASH) GIT_VERSION=$(GIT_VERSION) \ ko publish --base-import-paths \ - --tags $(GIT_VERSION) --tags $(GIT_HASH) --local --image-refs cliImagerefs \ + --tags $(GIT_VERSION) --tags $(GIT_HASH) --image-refs cliImagerefs \ github.com/sigstore/rekor/cmd/rekor-cli - LDFLAGS="$(SERVER_LDFLAGS)" GIT_HASH=$(GIT_HASH) GIT_VERSION=$(GIT_VERSION) \ + KO_DOCKER_REPO=ko.local LDFLAGS="$(SERVER_LDFLAGS)" GIT_HASH=$(GIT_HASH) GIT_VERSION=$(GIT_VERSION) \ ko publish --base-import-paths \ - --tags $(GIT_VERSION) --tags $(GIT_HASH) --local --image-refs redisImagerefs \ + --tags $(GIT_VERSION) --tags $(GIT_HASH) --image-refs redisImagerefs \ github.com/sigstore/rekor/cmd/backfill-redis # This builds the trillian containers we rely on using ko for cross platform support diff --git a/Makefile.swagger b/Makefile.swagger index 54f211391..8d03c3093 100644 --- a/Makefile.swagger +++ b/Makefile.swagger @@ -1,2 +1,2 @@ # This file is generated after swagger runs as part of the build; do not edit! -SWAGGER_GEN=pkg/generated/client/entries/create_log_entry_parameters.go pkg/generated/client/entries/create_log_entry_responses.go pkg/generated/client/entries/entries_client.go pkg/generated/client/entries/get_log_entry_by_index_parameters.go pkg/generated/client/entries/get_log_entry_by_index_responses.go pkg/generated/client/entries/get_log_entry_by_uuid_parameters.go pkg/generated/client/entries/get_log_entry_by_uuid_responses.go pkg/generated/client/entries/search_log_query_parameters.go pkg/generated/client/entries/search_log_query_responses.go pkg/generated/client/index/index_client.go pkg/generated/client/index/search_index_parameters.go pkg/generated/client/index/search_index_responses.go pkg/generated/client/pubkey/get_public_key_parameters.go pkg/generated/client/pubkey/get_public_key_responses.go pkg/generated/client/pubkey/pubkey_client.go pkg/generated/client/rekor_client.go pkg/generated/client/tlog/get_log_info_parameters.go pkg/generated/client/tlog/get_log_info_responses.go pkg/generated/client/tlog/get_log_proof_parameters.go pkg/generated/client/tlog/get_log_proof_responses.go pkg/generated/client/tlog/tlog_client.go pkg/generated/models/alpine.go pkg/generated/models/alpine_schema.go pkg/generated/models/alpine_v001_schema.go pkg/generated/models/consistency_proof.go pkg/generated/models/cose.go pkg/generated/models/cose_schema.go pkg/generated/models/cose_v001_schema.go pkg/generated/models/error.go pkg/generated/models/hashedrekord.go pkg/generated/models/hashedrekord_schema.go pkg/generated/models/hashedrekord_v001_schema.go pkg/generated/models/helm.go pkg/generated/models/helm_schema.go pkg/generated/models/helm_v001_schema.go pkg/generated/models/inactive_shard_log_info.go pkg/generated/models/inclusion_proof.go pkg/generated/models/intoto.go pkg/generated/models/intoto_schema.go pkg/generated/models/intoto_v001_schema.go pkg/generated/models/intoto_v002_schema.go pkg/generated/models/jar.go pkg/generated/models/jar_schema.go pkg/generated/models/jar_v001_schema.go pkg/generated/models/log_entry.go pkg/generated/models/log_info.go pkg/generated/models/proposed_entry.go pkg/generated/models/rekord.go pkg/generated/models/rekord_schema.go pkg/generated/models/rekord_v001_schema.go pkg/generated/models/rfc3161.go pkg/generated/models/rfc3161_schema.go pkg/generated/models/rfc3161_v001_schema.go pkg/generated/models/rpm.go pkg/generated/models/rpm_schema.go pkg/generated/models/rpm_v001_schema.go pkg/generated/models/search_index.go pkg/generated/models/search_log_query.go pkg/generated/models/tuf.go pkg/generated/models/tuf_schema.go pkg/generated/models/tuf_v001_schema.go pkg/generated/restapi/doc.go pkg/generated/restapi/embedded_spec.go pkg/generated/restapi/operations/entries/create_log_entry.go pkg/generated/restapi/operations/entries/create_log_entry_parameters.go pkg/generated/restapi/operations/entries/create_log_entry_responses.go pkg/generated/restapi/operations/entries/create_log_entry_urlbuilder.go pkg/generated/restapi/operations/entries/get_log_entry_by_index.go pkg/generated/restapi/operations/entries/get_log_entry_by_index_parameters.go pkg/generated/restapi/operations/entries/get_log_entry_by_index_responses.go pkg/generated/restapi/operations/entries/get_log_entry_by_index_urlbuilder.go pkg/generated/restapi/operations/entries/get_log_entry_by_uuid.go pkg/generated/restapi/operations/entries/get_log_entry_by_uuid_parameters.go pkg/generated/restapi/operations/entries/get_log_entry_by_uuid_responses.go pkg/generated/restapi/operations/entries/get_log_entry_by_uuid_urlbuilder.go pkg/generated/restapi/operations/entries/search_log_query.go pkg/generated/restapi/operations/entries/search_log_query_parameters.go pkg/generated/restapi/operations/entries/search_log_query_responses.go pkg/generated/restapi/operations/entries/search_log_query_urlbuilder.go pkg/generated/restapi/operations/index/search_index.go pkg/generated/restapi/operations/index/search_index_parameters.go pkg/generated/restapi/operations/index/search_index_responses.go pkg/generated/restapi/operations/index/search_index_urlbuilder.go pkg/generated/restapi/operations/pubkey/get_public_key.go pkg/generated/restapi/operations/pubkey/get_public_key_parameters.go pkg/generated/restapi/operations/pubkey/get_public_key_responses.go pkg/generated/restapi/operations/pubkey/get_public_key_urlbuilder.go pkg/generated/restapi/operations/rekor_server_api.go pkg/generated/restapi/operations/tlog/get_log_info.go pkg/generated/restapi/operations/tlog/get_log_info_parameters.go pkg/generated/restapi/operations/tlog/get_log_info_responses.go pkg/generated/restapi/operations/tlog/get_log_info_urlbuilder.go pkg/generated/restapi/operations/tlog/get_log_proof.go pkg/generated/restapi/operations/tlog/get_log_proof_parameters.go pkg/generated/restapi/operations/tlog/get_log_proof_responses.go pkg/generated/restapi/operations/tlog/get_log_proof_urlbuilder.go pkg/generated/restapi/server.go +SWAGGER_GEN=pkg/generated/client/entries/create_log_entry_parameters.go pkg/generated/client/entries/create_log_entry_responses.go pkg/generated/client/entries/entries_client.go pkg/generated/client/entries/get_log_entry_by_index_parameters.go pkg/generated/client/entries/get_log_entry_by_index_responses.go pkg/generated/client/entries/get_log_entry_by_uuid_parameters.go pkg/generated/client/entries/get_log_entry_by_uuid_responses.go pkg/generated/client/entries/search_log_query_parameters.go pkg/generated/client/entries/search_log_query_responses.go pkg/generated/client/index/index_client.go pkg/generated/client/index/search_index_parameters.go pkg/generated/client/index/search_index_responses.go pkg/generated/client/pubkey/get_public_key_parameters.go pkg/generated/client/pubkey/get_public_key_responses.go pkg/generated/client/pubkey/pubkey_client.go pkg/generated/client/rekor_client.go pkg/generated/client/tlog/get_log_info_parameters.go pkg/generated/client/tlog/get_log_info_responses.go pkg/generated/client/tlog/get_log_proof_parameters.go pkg/generated/client/tlog/get_log_proof_responses.go pkg/generated/client/tlog/tlog_client.go pkg/generated/models/alpine.go pkg/generated/models/alpine_schema.go pkg/generated/models/alpine_v001_schema.go pkg/generated/models/consistency_proof.go pkg/generated/models/cose.go pkg/generated/models/cose_schema.go pkg/generated/models/cose_v001_schema.go pkg/generated/models/dsse.go pkg/generated/models/dsse_schema.go pkg/generated/models/dsse_v001_schema.go pkg/generated/models/error.go pkg/generated/models/hashedrekord.go pkg/generated/models/hashedrekord_schema.go pkg/generated/models/hashedrekord_v001_schema.go pkg/generated/models/helm.go pkg/generated/models/helm_schema.go pkg/generated/models/helm_v001_schema.go pkg/generated/models/inactive_shard_log_info.go pkg/generated/models/inclusion_proof.go pkg/generated/models/intoto.go pkg/generated/models/intoto_schema.go pkg/generated/models/intoto_v001_schema.go pkg/generated/models/intoto_v002_schema.go pkg/generated/models/jar.go pkg/generated/models/jar_schema.go pkg/generated/models/jar_v001_schema.go pkg/generated/models/log_entry.go pkg/generated/models/log_info.go pkg/generated/models/proposed_entry.go pkg/generated/models/rekord.go pkg/generated/models/rekord_schema.go pkg/generated/models/rekord_v001_schema.go pkg/generated/models/rfc3161.go pkg/generated/models/rfc3161_schema.go pkg/generated/models/rfc3161_v001_schema.go pkg/generated/models/rpm.go pkg/generated/models/rpm_schema.go pkg/generated/models/rpm_v001_schema.go pkg/generated/models/search_index.go pkg/generated/models/search_log_query.go pkg/generated/models/tuf.go pkg/generated/models/tuf_schema.go pkg/generated/models/tuf_v001_schema.go pkg/generated/restapi/doc.go pkg/generated/restapi/embedded_spec.go pkg/generated/restapi/operations/entries/create_log_entry.go pkg/generated/restapi/operations/entries/create_log_entry_parameters.go pkg/generated/restapi/operations/entries/create_log_entry_responses.go pkg/generated/restapi/operations/entries/create_log_entry_urlbuilder.go pkg/generated/restapi/operations/entries/get_log_entry_by_index.go pkg/generated/restapi/operations/entries/get_log_entry_by_index_parameters.go pkg/generated/restapi/operations/entries/get_log_entry_by_index_responses.go pkg/generated/restapi/operations/entries/get_log_entry_by_index_urlbuilder.go pkg/generated/restapi/operations/entries/get_log_entry_by_uuid.go pkg/generated/restapi/operations/entries/get_log_entry_by_uuid_parameters.go pkg/generated/restapi/operations/entries/get_log_entry_by_uuid_responses.go pkg/generated/restapi/operations/entries/get_log_entry_by_uuid_urlbuilder.go pkg/generated/restapi/operations/entries/search_log_query.go pkg/generated/restapi/operations/entries/search_log_query_parameters.go pkg/generated/restapi/operations/entries/search_log_query_responses.go pkg/generated/restapi/operations/entries/search_log_query_urlbuilder.go pkg/generated/restapi/operations/index/search_index.go pkg/generated/restapi/operations/index/search_index_parameters.go pkg/generated/restapi/operations/index/search_index_responses.go pkg/generated/restapi/operations/index/search_index_urlbuilder.go pkg/generated/restapi/operations/pubkey/get_public_key.go pkg/generated/restapi/operations/pubkey/get_public_key_parameters.go pkg/generated/restapi/operations/pubkey/get_public_key_responses.go pkg/generated/restapi/operations/pubkey/get_public_key_urlbuilder.go pkg/generated/restapi/operations/rekor_server_api.go pkg/generated/restapi/operations/tlog/get_log_info.go pkg/generated/restapi/operations/tlog/get_log_info_parameters.go pkg/generated/restapi/operations/tlog/get_log_info_responses.go pkg/generated/restapi/operations/tlog/get_log_info_urlbuilder.go pkg/generated/restapi/operations/tlog/get_log_proof.go pkg/generated/restapi/operations/tlog/get_log_proof_parameters.go pkg/generated/restapi/operations/tlog/get_log_proof_responses.go pkg/generated/restapi/operations/tlog/get_log_proof_urlbuilder.go pkg/generated/restapi/server.go diff --git a/README.md b/README.md index 01070119b..0b5e083d2 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,8 @@ For uptime data on the Rekor public instance, see [https://status.sigstore.dev]( More details on the public instance can be found at [docs.sigstore.dev](https://docs.sigstore.dev/rekor/public-instance). +The attestation size limit for uploads to the public instance is [100KB](https://github.com/sigstore/rekor/blob/18c81d9f4def67c72f630c5406e26d5e568bc83b/cmd/rekor-server/app/root.go#L104). If you need to upload larger files, please run your own instance of Rekor. You can find instructions for doing so in the [installation](https://docs.sigstore.dev/rekor/overview#usage-and-installation) documentation. + ### Installation Please see the [installation](https://docs.sigstore.dev/rekor/overview#usage-and-installation) page for details on how to install the rekor CLI and set up / run @@ -53,7 +55,7 @@ Rekor allows customized manifests (which term them as types), [type customizatio ### API -If you're interesting in integration with Rekor, we have an [OpenAPI swagger editor](https://sigstore.dev/swagger/) +If you're interested in integration with Rekor, we have an [OpenAPI swagger editor](https://sigstore.dev/swagger/) ## Security @@ -61,5 +63,4 @@ Should you discover any security issues, please refer to sigstore's [security pr ## Contributions -We welcome contributions from anyone and are especially interested to hear from -users of Rekor. +We welcome contributions from anyone and are especially interested to hear from users of Rekor. diff --git a/cmd/backfill-redis/main.go b/cmd/backfill-redis/main.go index 58f3c1797..14e127a3b 100644 --- a/cmd/backfill-redis/main.go +++ b/cmd/backfill-redis/main.go @@ -20,8 +20,8 @@ To run: go run cmd/backfill-redis/main.go --rekor-address
\ - --hostname --port - --start --end + --hostname --port --concurrency \ + --start --end [--dry-run] */ package main @@ -30,13 +30,17 @@ import ( "bytes" "context" "encoding/base64" + "errors" "flag" "fmt" "log" "os" + "os/signal" + "syscall" "github.com/go-openapi/runtime" - radix "github.com/mediocregopher/radix/v4" + "github.com/redis/go-redis/v9" + "golang.org/x/sync/errgroup" "sigs.k8s.io/release-utils/version" "github.com/sigstore/rekor/pkg/client" @@ -47,12 +51,11 @@ import ( // these imports are to call the packages' init methods _ "github.com/sigstore/rekor/pkg/types/alpine/v0.0.1" _ "github.com/sigstore/rekor/pkg/types/cose/v0.0.1" + _ "github.com/sigstore/rekor/pkg/types/dsse/v0.0.1" _ "github.com/sigstore/rekor/pkg/types/hashedrekord/v0.0.1" _ "github.com/sigstore/rekor/pkg/types/helm/v0.0.1" _ "github.com/sigstore/rekor/pkg/types/intoto/v0.0.1" - - // remove 0.0.2 intoto type due to bugs - // _ "github.com/sigstore/rekor/pkg/types/intoto/v0.0.2" + _ "github.com/sigstore/rekor/pkg/types/intoto/v0.0.2" _ "github.com/sigstore/rekor/pkg/types/jar/v0.0.1" _ "github.com/sigstore/rekor/pkg/types/rekord/v0.0.1" _ "github.com/sigstore/rekor/pkg/types/rfc3161/v0.0.1" @@ -67,6 +70,8 @@ var ( endIndex = flag.Int("end", -1, "Last index to backfill") rekorAddress = flag.String("rekor-address", "", "Address for Rekor, e.g. https://rekor.sigstore.dev") versionFlag = flag.Bool("version", false, "Print the current version of Backfill Redis") + concurrency = flag.Int("concurrency", 1, "Number of workers to use for backfill") + dryRun = flag.Bool("dry-run", false, "Dry run - don't actually insert into Redis") ) func main() { @@ -96,56 +101,110 @@ func main() { log.Printf("running backfill redis Version: %s GitCommit: %s BuildDate: %s", versionInfo.GitVersion, versionInfo.GitCommit, versionInfo.BuildDate) - cfg := radix.PoolConfig{} - redisClient, err := cfg.New(context.Background(), "tcp", fmt.Sprintf("%s:%s", *redisHostname, *redisPort)) - if err != nil { - log.Fatal(err) - } + redisClient := redis.NewClient(&redis.Options{ + Addr: fmt.Sprintf("%s:%s", *redisHostname, *redisPort), + Network: "tcp", + DB: 0, // default DB + }) rekorClient, err := client.GetRekorClient(*rekorAddress) if err != nil { log.Fatalf("creating rekor client: %v", err) } - for i := *startIndex; i <= *endIndex; i++ { - params := entries.NewGetLogEntryByIndexParamsWithContext(context.Background()) - params.SetLogIndex(int64(i)) - resp, err := rekorClient.Entries.GetLogEntryByIndex(params) - if err != nil { - log.Fatalf("retrieving log uuid by index: %v", err) + ctx, _ := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) + group, ctx := errgroup.WithContext(ctx) + group.SetLimit(*concurrency) + + type result struct { + index int + parseErrs []error + insertErrs []error + } + var resultChan = make(chan result) + parseErrs := make([]int, 0) + insertErrs := make([]int, 0) + + go func() { + for r := range resultChan { + if len(r.parseErrs) > 0 { + parseErrs = append(parseErrs, r.index) + } + if len(r.insertErrs) > 0 { + insertErrs = append(insertErrs, r.index) + } } - var insertErrs []error - for uuid, entry := range resp.Payload { - // uuid is the global UUID - tree ID and entry UUID - e, _, _, err := unmarshalEntryImpl(entry.Body.(string)) + }() + + for i := *startIndex; i <= *endIndex; i++ { + index := i // capture loop variable for closure + group.Go(func() error { + params := entries.NewGetLogEntryByIndexParamsWithContext(ctx) + params.SetLogIndex(int64(index)) + resp, err := rekorClient.Entries.GetLogEntryByIndex(params) if err != nil { - insertErrs = append(insertErrs, fmt.Errorf("error unmarshalling entry for %s: %v", uuid, err)) - continue + // in case of sigterm, just return to exit gracefully + if errors.Is(err, context.Canceled) { + return nil + } + log.Fatalf("retrieving log uuid by index: %v", err) } - keys, err := e.IndexKeys() - if err != nil { - insertErrs = append(insertErrs, fmt.Errorf("error building index keys for %s: %v", uuid, err)) - continue + var parseErrs []error + var insertErrs []error + for uuid, entry := range resp.Payload { + // uuid is the global UUID - tree ID and entry UUID + e, _, _, err := unmarshalEntryImpl(entry.Body.(string)) + if err != nil { + parseErrs = append(parseErrs, fmt.Errorf("error unmarshalling entry for %s: %v", uuid, err)) + continue + } + keys, err := e.IndexKeys() + if err != nil { + parseErrs = append(parseErrs, fmt.Errorf("error building index keys for %s: %v", uuid, err)) + continue + } + for _, key := range keys { + // remove the key-value pair from the index in case it already exists + if err := removeFromIndex(ctx, redisClient, key, uuid); err != nil { + insertErrs = append(insertErrs, fmt.Errorf("error removing UUID %s with key %s: %v", uuid, key, err)) + } + if err := addToIndex(ctx, redisClient, key, uuid); err != nil { + insertErrs = append(insertErrs, fmt.Errorf("error inserting UUID %s with key %s: %v", uuid, key, err)) + } + fmt.Printf("Uploaded Redis entry %s, index %d, key %s\n", uuid, index, key) + } } - for _, key := range keys { - // remove the key-value pair from the index in case it already exists - if err := removeFromIndex(context.Background(), redisClient, key, uuid); err != nil { - insertErrs = append(insertErrs, fmt.Errorf("error removing UUID %s with key %s: %v", uuid, key, err)) + if len(insertErrs) != 0 || len(parseErrs) != 0 { + fmt.Printf("Errors with log index %d:\n", index) + for _, e := range insertErrs { + fmt.Println(e) } - if err := addToIndex(context.Background(), redisClient, key, uuid); err != nil { - insertErrs = append(insertErrs, fmt.Errorf("error inserting UUID %s with key %s: %v", uuid, key, err)) + for _, e := range parseErrs { + fmt.Println(e) } - fmt.Printf("Uploaded Redis entry %s, index %d, key %s\n", uuid, i, key) + } else { + fmt.Printf("Completed log index %d\n", index) } - } - if len(insertErrs) != 0 { - fmt.Printf("Errors with log index %d:\n", i) - for _, e := range insertErrs { - fmt.Println(e) + resultChan <- result{ + index: index, + parseErrs: parseErrs, + insertErrs: insertErrs, } - } else { - fmt.Printf("Completed log index %d\n", i) - } + + return nil + }) + } + err = group.Wait() + if err != nil { + log.Fatalf("error running backfill: %v", err) + } + close(resultChan) + fmt.Println("Backfill complete") + if len(parseErrs) > 0 { + fmt.Printf("Failed to parse %d entries: %v\n", len(parseErrs), parseErrs) + } + if len(insertErrs) > 0 { + fmt.Printf("Failed to insert/remove %d entries: %v\n", len(insertErrs), insertErrs) } } @@ -171,11 +230,19 @@ func unmarshalEntryImpl(e string) (types.EntryImpl, string, string, error) { // removeFromIndex removes all occurrences of a value from a given key. This guards against // multiple invocations of backfilling creating duplicates. -func removeFromIndex(ctx context.Context, redisClient radix.Client, key, value string) error { - return redisClient.Do(ctx, radix.Cmd(nil, "LREM", key, "0", value)) +func removeFromIndex(ctx context.Context, redisClient *redis.Client, key, value string) error { + if *dryRun { + return nil + } + _, err := redisClient.LRem(ctx, key, 0, value).Result() + return err } // addToIndex pushes a value onto a key of type list. -func addToIndex(ctx context.Context, redisClient radix.Client, key, value string) error { - return redisClient.Do(ctx, radix.Cmd(nil, "LPUSH", key, value)) +func addToIndex(ctx context.Context, redisClient *redis.Client, key, value string) error { + if *dryRun { + return nil + } + _, err := redisClient.LPush(ctx, key, value).Result() + return err } diff --git a/cmd/rekor-cli/app/format/wrap.go b/cmd/rekor-cli/app/format/wrap.go index 5e81c37f6..53df9f65e 100644 --- a/cmd/rekor-cli/app/format/wrap.go +++ b/cmd/rekor-cli/app/format/wrap.go @@ -19,7 +19,10 @@ import ( "encoding/json" "fmt" + rekor_pb "github.com/sigstore/protobuf-specs/gen/pb-go/rekor/v1" + "github.com/sigstore/rekor/pkg/log" + tleutils "github.com/sigstore/rekor/pkg/tle" "github.com/spf13/cobra" "github.com/spf13/viper" ) @@ -46,6 +49,16 @@ func WrapCmd(f formatCmd) CobraCmd { } case "json": fmt.Println(toJSON(obj)) + case "tle": + if tle, ok := obj.(*rekor_pb.TransparencyLogEntry); ok { + json, err := tleutils.MarshalTLEToJSON(tle) + if err != nil { + log.CliLogger.Fatalf("error converting to transparency log entry: %v", err) + } + fmt.Println(string(json)) + } else { + log.CliLogger.Fatal("unable to print transparency log entry") + } } } } diff --git a/cmd/rekor-cli/app/get.go b/cmd/rekor-cli/app/get.go index 6a6181341..d10d63f99 100644 --- a/cmd/rekor-cli/app/get.go +++ b/cmd/rekor-cli/app/get.go @@ -35,6 +35,7 @@ import ( "github.com/sigstore/rekor/pkg/generated/models" "github.com/sigstore/rekor/pkg/log" "github.com/sigstore/rekor/pkg/sharding" + "github.com/sigstore/rekor/pkg/tle" "github.com/sigstore/rekor/pkg/types" "github.com/sigstore/rekor/pkg/verify" ) @@ -203,6 +204,10 @@ func compareEntryUUIDs(requestEntryUUID string, responseEntryUUID string) error } func parseEntry(uuid string, e models.LogEntryAnon) (interface{}, error) { + if viper.GetString("format") == "tle" { + return tle.GenerateTransparencyLogEntry(e) + } + b, err := base64.StdEncoding.DecodeString(e.Body.(string)) if err != nil { return nil, err diff --git a/cmd/rekor-cli/app/pflags.go b/cmd/rekor-cli/app/pflags.go index ad56b43a3..62f4a6cdf 100644 --- a/cmd/rekor-cli/app/pflags.go +++ b/cmd/rekor-cli/app/pflags.go @@ -25,7 +25,6 @@ import ( "github.com/sigstore/rekor/pkg/pki" "github.com/sigstore/rekor/pkg/sharding" - "github.com/sigstore/rekor/pkg/util" "github.com/spf13/pflag" @@ -112,7 +111,7 @@ func initializePFlagMap() { }, formatFlag: func() pflag.Value { // this validates the output format requested - return valueFactory(formatFlag, validateString("required,oneof=json default"), "") + return valueFactory(formatFlag, validateString("required,oneof=json default tle"), "") }, timeoutFlag: func() pflag.Value { // this validates the timeout is >= 0 @@ -224,17 +223,17 @@ func isURL(v string) bool { // [sha1:]<40 hexadecimal characters> // where [sha256:] and [sha1:] are optional func validateSHAValue(v string) error { - err := util.ValidateSHA1Value(v) + err := validateSHA1Value(v) if err == nil { return nil } - err = util.ValidateSHA256Value(v) + err = validateSHA256Value(v) if err == nil { return nil } - err = util.ValidateSHA512Value(v) + err = validateSHA512Value(v) if err == nil { return nil } diff --git a/cmd/rekor-cli/app/root.go b/cmd/rekor-cli/app/root.go index f4db87462..4dc81b778 100644 --- a/cmd/rekor-cli/app/root.go +++ b/cmd/rekor-cli/app/root.go @@ -30,6 +30,7 @@ import ( // these imports are to call the packages' init methods _ "github.com/sigstore/rekor/pkg/types/alpine/v0.0.1" _ "github.com/sigstore/rekor/pkg/types/cose/v0.0.1" + _ "github.com/sigstore/rekor/pkg/types/dsse/v0.0.1" _ "github.com/sigstore/rekor/pkg/types/hashedrekord/v0.0.1" _ "github.com/sigstore/rekor/pkg/types/helm/v0.0.1" _ "github.com/sigstore/rekor/pkg/types/intoto/v0.0.1" diff --git a/cmd/rekor-cli/app/search.go b/cmd/rekor-cli/app/search.go index 4552a1c3f..2b1e89d17 100644 --- a/cmd/rekor-cli/app/search.go +++ b/cmd/rekor-cli/app/search.go @@ -201,7 +201,9 @@ var searchCmd = &cobra.Command{ return nil, fmt.Errorf("no matching entries found") } - fmt.Fprintln(os.Stderr, "Found matching entries (listed by UUID):") + if viper.GetString("format") != "json" { + fmt.Fprintln(os.Stderr, "Found matching entries (listed by UUID):") + } return &searchCmdOutput{ UUIDs: resp.GetPayload(), diff --git a/cmd/rekor-cli/app/state/state.go b/cmd/rekor-cli/app/state/state.go index 39ec59dd7..1985b81d1 100644 --- a/cmd/rekor-cli/app/state/state.go +++ b/cmd/rekor-cli/app/state/state.go @@ -17,6 +17,7 @@ package state import ( "encoding/json" + "errors" "os" "path/filepath" @@ -27,6 +28,9 @@ import ( type persistedState map[string]*util.SignedCheckpoint func Dump(key string, sth *util.SignedCheckpoint) error { + if sth.Size == 0 { + return errors.New("do not persist state for empty logs") + } rekorDir, err := getRekorDir() if err != nil { return err @@ -43,10 +47,7 @@ func Dump(key string, sth *util.SignedCheckpoint) error { if err != nil { return err } - if err := os.WriteFile(statePath, b, 0600); err != nil { - return err - } - return nil + return os.WriteFile(statePath, b, 0600) } func loadStateFile() persistedState { diff --git a/cmd/rekor-cli/app/upload.go b/cmd/rekor-cli/app/upload.go index aedc6da93..040ab4ea3 100644 --- a/cmd/rekor-cli/app/upload.go +++ b/cmd/rekor-cli/app/upload.go @@ -61,10 +61,7 @@ var uploadCmd = &cobra.Command{ if err := viper.BindPFlags(cmd.Flags()); err != nil { return err } - if err := validateArtifactPFlags(false, false); err != nil { - return err - } - return nil + return validateArtifactPFlags(false, false) }, Long: `This command takes the public key, signature and URL of the release artifact and uploads it to the rekor server.`, Run: format.WrapCmd(func(args []string) (interface{}, error) { diff --git a/pkg/util/validate.go b/cmd/rekor-cli/app/validate.go similarity index 93% rename from pkg/util/validate.go rename to cmd/rekor-cli/app/validate.go index f8f015fbd..9ff932585 100644 --- a/pkg/util/validate.go +++ b/cmd/rekor-cli/app/validate.go @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package util +package app import ( "strings" @@ -24,7 +24,7 @@ import ( // validateSHA512Value ensures that the supplied string matches the // following format: [sha512:]<128 hexadecimal characters> // where [sha512:] is optional -func ValidateSHA512Value(v string) error { +func validateSHA512Value(v string) error { var prefix, hash string split := strings.SplitN(v, ":", 2) @@ -48,7 +48,7 @@ func ValidateSHA512Value(v string) error { // validateSHA256Value ensures that the supplied string matches the following format: // [sha256:]<64 hexadecimal characters> // where [sha256:] is optional -func ValidateSHA256Value(v string) error { +func validateSHA256Value(v string) error { var prefix, hash string split := strings.SplitN(v, ":", 2) @@ -69,7 +69,7 @@ func ValidateSHA256Value(v string) error { return validate.Struct(s) } -func ValidateSHA1Value(v string) error { +func validateSHA1Value(v string) error { var prefix, hash string split := strings.SplitN(v, ":", 2) diff --git a/pkg/util/validate_test.go b/cmd/rekor-cli/app/validate_test.go similarity index 96% rename from pkg/util/validate_test.go rename to cmd/rekor-cli/app/validate_test.go index efe34cc11..633251593 100644 --- a/pkg/util/validate_test.go +++ b/cmd/rekor-cli/app/validate_test.go @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package util +package app import ( "testing" @@ -54,7 +54,7 @@ func TestSHA1(t *testing.T) { } for _, tr := range tests { - err := ValidateSHA1Value(tr.value) + err := validateSHA1Value(tr.value) if tr.expectFail == (err == nil) { t.Errorf("Failure validating '%s': %s", tr.value, err) } @@ -96,7 +96,7 @@ func TestSHA256(t *testing.T) { } for _, tr := range tests { - err := ValidateSHA256Value(tr.value) + err := validateSHA256Value(tr.value) if tr.expectFail == (err == nil) { t.Errorf("Failure validating '%s': %s", tr.value, err) } @@ -138,7 +138,7 @@ func TestSHA512(t *testing.T) { } for _, tr := range tests { - err := ValidateSHA512Value(tr.value) + err := validateSHA512Value(tr.value) if tr.expectFail == (err == nil) { t.Errorf("Failure validating '%s': %s", tr.value, err) } diff --git a/cmd/rekor-cli/app/verify.go b/cmd/rekor-cli/app/verify.go index 1d4d86fca..cffd81b9d 100644 --- a/cmd/rekor-cli/app/verify.go +++ b/cmd/rekor-cli/app/verify.go @@ -85,10 +85,7 @@ var verifyCmd = &cobra.Command{ if err := viper.BindPFlags(cmd.Flags()); err != nil { return fmt.Errorf("error initializing cmd line args: %s", err) } - if err := validateArtifactPFlags(true, true); err != nil { - return err - } - return nil + return validateArtifactPFlags(true, true) }, Run: format.WrapCmd(func(args []string) (interface{}, error) { ctx := context.Background() diff --git a/pkg/types/rpm/fuzz_test.go b/cmd/rekor-cli/logproof_e2e_test.go similarity index 51% rename from pkg/types/rpm/fuzz_test.go rename to cmd/rekor-cli/logproof_e2e_test.go index df72c7286..9ce628556 100644 --- a/pkg/types/rpm/fuzz_test.go +++ b/cmd/rekor-cli/logproof_e2e_test.go @@ -1,5 +1,5 @@ // -// Copyright 2022 The Sigstore Authors. +// 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. @@ -13,30 +13,18 @@ // See the License for the specific language governing permissions and // limitations under the License. -package rpm +//go:build e2e + +package main import ( - "context" "testing" - fuzz "github.com/AdaLogics/go-fuzz-headers" - - "github.com/sigstore/rekor/pkg/types" + "github.com/sigstore/rekor/pkg/util" ) -func FuzzRpmCreateProposedEntry(f *testing.F) { - f.Fuzz(func(t *testing.T, version string, propsData []byte) { - ff := fuzz.NewConsumer(propsData) - props := types.ArtifactProperties{} - ff.GenerateStruct(&props) - it := New() - entry, err := it.CreateProposedEntry(context.Background(), version, props) - if err != nil { - t.Skip() - } - _, err = it.UnmarshalEntry(entry) - if err != nil { - t.Skip() - } - }) +// TestLogProofLastSizeBiggerThanCurrentLog tests that asking for a consistency proof for a size greater than the current log +func TestLogProofLastSizeBiggerThanCurrentLog(t *testing.T) { + out := util.RunCliErr(t, "logproof", "--last-size", "14212414124124124") + util.OutputContains(t, out, "400") } diff --git a/cmd/rekor-cli/main_test.go b/cmd/rekor-cli/main_test.go index 6a11ccbb1..fd8902753 100644 --- a/cmd/rekor-cli/main_test.go +++ b/cmd/rekor-cli/main_test.go @@ -21,6 +21,6 @@ import ( "github.com/sigstore/rekor/cmd/rekor-cli/app" ) -func TestCover(t *testing.T) { +func TestCover(_ *testing.T) { app.Execute() } diff --git a/cmd/rekor-server/app/root.go b/cmd/rekor-server/app/root.go index e258c2aa5..04a47fcd9 100644 --- a/cmd/rekor-server/app/root.go +++ b/cmd/rekor-server/app/root.go @@ -72,14 +72,15 @@ func init() { rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.rekor-server.yaml)") rootCmd.PersistentFlags().StringVar(&logType, "log_type", "dev", "logger type to use (dev/prod)") rootCmd.PersistentFlags().BoolVar(&enablePprof, "enable_pprof", false, "enable pprof for profiling on port 6060") - rootCmd.PersistentFlags().Bool("enable_killswitch", false, "enable killswitch for TESTING ONLY on port 2345") - _ = rootCmd.PersistentFlags().MarkHidden("enable_killswitch") rootCmd.PersistentFlags().String("trillian_log_server.address", "127.0.0.1", "Trillian log server address") rootCmd.PersistentFlags().Uint16("trillian_log_server.port", 8090, "Trillian log server port") rootCmd.PersistentFlags().Uint("trillian_log_server.tlog_id", 0, "Trillian tree id") rootCmd.PersistentFlags().String("trillian_log_server.sharding_config", "", "path to config file for inactive shards, in JSON or YAML") + rootCmd.PersistentFlags().Bool("enable_stable_checkpoint", true, "publish stable checkpoints to Redis. When disabled, gossiping may not be possible if the log checkpoint updates too frequently") + rootCmd.PersistentFlags().Uint("publish_frequency", 5, "how often to publish a new checkpoint, in minutes") + hostname, err := os.Hostname() if err != nil { hostname = "localhost" @@ -92,6 +93,10 @@ func init() { Memory and file-based signers should only be used for testing.`) rootCmd.PersistentFlags().String("rekor_server.signer-passwd", "", "Password to decrypt signer private key") + rootCmd.PersistentFlags().String("rekor_server.new_entry_publisher", "", "URL for pub/sub queue to send messages to when new entries are added to the log. Ignored if not set. Supported providers: [gcppubsub]") + rootCmd.PersistentFlags().Bool("rekor_server.publish_events_protobuf", false, "Whether to publish events in Protobuf wire format. Applies to all enabled event types.") + rootCmd.PersistentFlags().Bool("rekor_server.publish_events_json", false, "Whether to publish events in CloudEvents JSON format. Applies to all enabled event types.") + rootCmd.PersistentFlags().Uint16("port", 3000, "Port to bind to") rootCmd.PersistentFlags().Bool("enable_retrieve_api", true, "enables Redis-based index API endpoint") @@ -105,6 +110,10 @@ Memory and file-based signers should only be used for testing.`) rootCmd.PersistentFlags().StringSlice("enabled_api_endpoints", operationIds, "list of API endpoints to enable using operationId from openapi.yaml") + rootCmd.PersistentFlags().Uint64("max_request_body_size", 0, "maximum size for HTTP request body, in bytes; set to 0 for unlimited") + rootCmd.PersistentFlags().Uint64("max_jar_metadata_size", 1048576, "maximum permitted size for jar META-INF/ files, in bytes; set to 0 for unlimited") + rootCmd.PersistentFlags().Uint64("max_apk_metadata_size", 1048576, "maximum permitted size for apk .SIGN and .PKGINFO files, in bytes; set to 0 for unlimited") + if err := viper.BindPFlags(rootCmd.PersistentFlags()); err != nil { log.Logger.Fatal(err) } diff --git a/cmd/rekor-server/app/serve.go b/cmd/rekor-server/app/serve.go index b7628aea1..fa396a065 100644 --- a/cmd/rekor-server/app/serve.go +++ b/cmd/rekor-server/app/serve.go @@ -34,6 +34,8 @@ import ( alpine_v001 "github.com/sigstore/rekor/pkg/types/alpine/v0.0.1" "github.com/sigstore/rekor/pkg/types/cose" cose_v001 "github.com/sigstore/rekor/pkg/types/cose/v0.0.1" + "github.com/sigstore/rekor/pkg/types/dsse" + dsse_v001 "github.com/sigstore/rekor/pkg/types/dsse/v0.0.1" hashedrekord "github.com/sigstore/rekor/pkg/types/hashedrekord" hashedrekord_v001 "github.com/sigstore/rekor/pkg/types/hashedrekord/v0.0.1" "github.com/sigstore/rekor/pkg/types/helm" @@ -59,7 +61,6 @@ var serveCmd = &cobra.Command{ Short: "start http server with configured api", Long: `Starts a http server and serves the configured api`, Run: func(cmd *cobra.Command, args []string) { - // Setup the logger to dev/prod log.ConfigureLogger(viper.GetString("log_type")) @@ -81,7 +82,6 @@ var serveCmd = &cobra.Command{ log.Logger.Error(err) } }() - //TODO: make this a config option for server to load via viper field //TODO: add command line option to print versions supported in binary @@ -97,8 +97,8 @@ var serveCmd = &cobra.Command{ helm.KIND: {helm_v001.APIVERSION}, tuf.KIND: {tuf_v001.APIVERSION}, hashedrekord.KIND: {hashedrekord_v001.APIVERSION}, + dsse.KIND: {dsse_v001.APIVERSION}, } - for k, v := range pluggableTypeMap { log.Logger.Infof("Loading support for pluggable type '%v'", k) log.Logger.Infof("Loading version '%v' for pluggable type '%v'", v, k) @@ -123,27 +123,6 @@ var serveCmd = &cobra.Command{ _ = srv.ListenAndServe() }() - if viper.GetBool("enable_killswitch") { - go func() { - mux := http.NewServeMux() - mux.Handle("/kill", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if err := server.Shutdown(); err != nil { - log.Logger.Error(err) - } - w.WriteHeader(http.StatusOK) - })) - - srv := &http.Server{ - Addr: ":2345", - ReadTimeout: 10 * time.Second, - WriteTimeout: 10 * time.Second, - Handler: mux, - } - - _ = srv.ListenAndServe() - }() - } - if err := server.Serve(); err != nil { log.Logger.Fatal(err) } diff --git a/cmd/rekor-server/app/watch.go b/cmd/rekor-server/app/watch.go deleted file mode 100644 index 563a29e4f..000000000 --- a/cmd/rekor-server/app/watch.go +++ /dev/null @@ -1,178 +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 app - -import ( - "context" - "crypto" - "crypto/x509" - "encoding/json" - "encoding/pem" - "errors" - "flag" - "fmt" - "os" - "time" - - _ "gocloud.dev/blob/fileblob" // fileblob - _ "gocloud.dev/blob/gcsblob" - - "github.com/spf13/cobra" - "github.com/spf13/viper" - "gocloud.dev/blob" - - "github.com/sigstore/rekor/pkg/client" - genclient "github.com/sigstore/rekor/pkg/generated/client" - "github.com/sigstore/rekor/pkg/log" - "github.com/sigstore/rekor/pkg/util" - "github.com/sigstore/sigstore/pkg/signature" -) - -const rekorSthBucketEnv = "REKOR_STH_BUCKET" - -// watchCmd represents the serve command -var watchCmd = &cobra.Command{ - Use: "watch", - Short: "Start a process to watch and record STH's from Rekor", - Long: `Start a process to watch and record STH's from Rekor`, - PreRun: func(cmd *cobra.Command, args []string) { - // these are bound here so that they are not overwritten by other commands - if err := viper.BindPFlags(cmd.Flags()); err != nil { - log.Logger.Fatal("Error initializing cmd line args: ", err) - } - }, - RunE: func(cmd *cobra.Command, args []string) error { - - // Setup the logger to dev/prod - log.ConfigureLogger(viper.GetString("log_type")) - - // workaround for https://github.com/sigstore/rekor/issues/68 - // from https://github.com/golang/glog/commit/fca8c8854093a154ff1eb580aae10276ad6b1b5f - _ = flag.CommandLine.Parse([]string{}) - - host := viper.GetString("rekor_server.address") - port := viper.GetUint("port") - interval := viper.GetDuration("interval") - url := fmt.Sprintf("http://%s:%d", host, port) - c, err := client.GetRekorClient(url) - if err != nil { - return err - } - - keyResp, err := c.Pubkey.GetPublicKey(nil) - if err != nil { - return err - } - publicKey := keyResp.Payload - block, _ := pem.Decode([]byte(publicKey)) - if block == nil { - return errors.New("failed to decode public key of server") - } - - pub, err := x509.ParsePKIXPublicKey(block.Bytes) - if err != nil { - return err - } - - ctx := context.Background() - bucketURL := os.Getenv(rekorSthBucketEnv) - if bucketURL == "" { - log.CliLogger.Fatalf("%s env var must be set", rekorSthBucketEnv) - } - bucket, err := blob.OpenBucket(ctx, bucketURL) - if err != nil { - return err - } - defer bucket.Close() - tick := time.NewTicker(interval) - var last *SignedAndUnsignedLogRoot - - for { - <-tick.C - log.Logger.Info("performing check") - lr, err := doCheck(c, pub) - if err != nil { - log.Logger.Warnf("error verifiying tree: %s", err) - continue - } - log.Logger.Infof("Found and verified state at %d", lr.VerifiedLogRoot.Size) - if last != nil && last.VerifiedLogRoot.Size == lr.VerifiedLogRoot.Size { - log.Logger.Infof("Last tree size is the same as the current one: %d %d", - last.VerifiedLogRoot.Size, lr.VerifiedLogRoot.Size) - // If it's the same, it shouldn't have changed but we'll still upload anyway - // in case that failed. - } - - if err := uploadToBlobStorage(ctx, bucket, lr); err != nil { - log.Logger.Warnf("error uploading result: %s", err) - continue - } - last = lr - } - }, -} - -func init() { - watchCmd.Flags().Duration("interval", 1*time.Minute, "Polling interval") - rootCmd.AddCommand(watchCmd) -} - -func doCheck(c *genclient.Rekor, pub crypto.PublicKey) (*SignedAndUnsignedLogRoot, error) { - li, err := c.Tlog.GetLogInfo(nil) - if err != nil { - return nil, fmt.Errorf("getting log info: %w", err) - } - sth := util.SignedCheckpoint{} - if err := sth.UnmarshalText([]byte(*li.Payload.SignedTreeHead)); err != nil { - return nil, fmt.Errorf("unmarshalling tree head: %w", err) - } - - verifier, err := signature.LoadVerifier(pub, crypto.SHA256) - if err != nil { - return nil, err - } - - if !sth.Verify(verifier) { - return nil, fmt.Errorf("signed tree head failed verification: %w", err) - } - - return &SignedAndUnsignedLogRoot{ - VerifiedLogRoot: &sth, - }, nil -} - -func uploadToBlobStorage(ctx context.Context, bucket *blob.Bucket, lr *SignedAndUnsignedLogRoot) error { - b, err := json.Marshal(lr) - if err != nil { - return err - } - - objName := fmt.Sprintf("sth-%d.json", lr.VerifiedLogRoot.Size) - w, err := bucket.NewWriter(ctx, objName, nil) - if err != nil { - return err - } - defer w.Close() - if _, err := w.Write(b); err != nil { - return err - } - return nil -} - -// For JSON marshalling -type SignedAndUnsignedLogRoot struct { - VerifiedLogRoot *util.SignedCheckpoint -} diff --git a/cmd/rekor-server/e2e_test.go b/cmd/rekor-server/e2e_test.go index a17d09537..e41aa68fc 100644 --- a/cmd/rekor-server/e2e_test.go +++ b/cmd/rekor-server/e2e_test.go @@ -20,6 +20,7 @@ package main import ( "bufio" "bytes" + "context" "crypto" "crypto/ecdsa" "crypto/sha256" @@ -30,7 +31,9 @@ import ( "encoding/pem" "errors" "fmt" + "io" "io/ioutil" + "math/rand" "net/http" "os" "path/filepath" @@ -121,9 +124,10 @@ func TestMetricsCounts(t *testing.T) { t.Error("rekor_qps_by_api did not increment") } } + func getRekorMetricCount(metricLine string, t *testing.T) (int, error) { t.Helper() - re, err := regexp.Compile(fmt.Sprintf("^%s.*([0-9]+)$", regexp.QuoteMeta(metricLine))) + re, err := regexp.Compile(fmt.Sprintf("^%s\\s*([0-9]+)$", regexp.QuoteMeta(metricLine))) if err != nil { return 0, err } @@ -143,19 +147,21 @@ func getRekorMetricCount(metricLine string, t *testing.T) (int, error) { result, err := strconv.Atoi(match[1]) if err != nil { - return 0, nil + return 0, err } t.Log("Matched metric line: " + scanner.Text()) return result, nil } return 0, nil } + func TestEnvVariableValidation(t *testing.T) { os.Setenv("REKOR_FORMAT", "bogus") defer os.Unsetenv("REKOR_FORMAT") util.RunCliErr(t, "loginfo") } + func TestGetCLI(t *testing.T) { // Create something and add it to the log artifactPath := filepath.Join(t.TempDir(), "artifact") @@ -223,6 +229,7 @@ func TestGetCLI(t *testing.T) { } out = util.RunCli(t, "get", "--format=json", "--uuid", entryID.ReturnEntryIDString()) } + func getTreeID(t *testing.T) int64 { t.Helper() out := util.RunCli(t, "loginfo") @@ -234,9 +241,11 @@ func getTreeID(t *testing.T) int64 { t.Log("Tree ID:", tid) return tid } + func TestSearchNoEntriesRC1(t *testing.T) { util.RunCliErr(t, "search", "--email", "noone@internetz.com") } + func TestHostnameInSTH(t *testing.T) { // get ID of container rekorContainerID := strings.Trim(util.Run(t, "", "docker", "ps", "-q", "-f", "name=rekor-server"), "\n") @@ -258,12 +267,14 @@ func TestHostnameInSTH(t *testing.T) { t.Errorf("logInfo contains rekor.sigstore.dev which should not be set by default") } } + func rekorServer() string { if s := os.Getenv("REKOR_SERVER"); s != "" { return s } return "http://localhost:3000" } + func TestSearchSHA512(t *testing.T) { sha512 := "c7694a1112ea1404a3c5852bdda04c2cc224b3567ef6ceb8204dbf2b382daacfc6837ee2ed9d5b82c90b880a3c7289778dbd5a8c2c08193459bcf7bd44581ed0" var out string @@ -276,6 +287,7 @@ func TestSearchSHA512(t *testing.T) { out = util.RunCli(t, "search", "--sha", fmt.Sprintf("sha512:%s", sha512)) util.OutputContains(t, out, uuid) } + func TestVerifyNonExistentUUID(t *testing.T) { // this uuid is extremely likely to not exist out := util.RunCliErr(t, "verify", "--uuid", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff") @@ -304,6 +316,7 @@ func TestVerifyNonExistentUUID(t *testing.T) { t.Fatalf("expected empty JSON array as response, got %s instead", string(c)) } } + func TestSearchQueryLimit(t *testing.T) { tests := []struct { description string @@ -344,6 +357,7 @@ func TestSearchQueryLimit(t *testing.T) { }) } } + func getBody(t *testing.T, limit int) []byte { t.Helper() s := fmt.Sprintf("{\"logIndexes\": [%d", limit) @@ -353,6 +367,7 @@ func getBody(t *testing.T, limit int) []byte { s += "]}" return []byte(s) } + func TestSearchQueryMalformedEntry(t *testing.T) { wd, err := os.Getwd() if err != nil { @@ -373,6 +388,7 @@ func TestSearchQueryMalformedEntry(t *testing.T) { t.Fatalf("expected status 400, got %d instead", resp.StatusCode) } } + func entryID(t *testing.T, uuid string) string { t.Helper() if sharding.ValidateEntryID(uuid) == nil { @@ -389,6 +405,7 @@ func entryID(t *testing.T, uuid string) string { } return ts + uuid } + func TestHarnessGetAllEntriesUUID(t *testing.T) { if util.RekorCLIIncompatible() { t.Skipf("Skipping getting entries by UUID, old rekor-cli version %s is incompatible with server version %s", os.Getenv("CLI_VERSION"), os.Getenv("SERVER_VERSION")) @@ -544,7 +561,7 @@ func TestHarnessAddIntoto(t *testing.T) { t.Fatal(err) } - env, err := signer.SignPayload("application/vnd.in-toto+json", b) + env, err := signer.SignPayload(context.Background(), "application/vnd.in-toto+json", b) if err != nil { t.Fatal(err) } @@ -636,3 +653,23 @@ func saveEntry(t *testing.T, logIndex int, entry StoredEntry) { t.Fatal(err) } } + +func TestHTTPMaxRequestBodySize(t *testing.T) { + // default value is 32Mb so let's try to propose something bigger + pipeR, pipeW := io.Pipe() + go func() { + _, _ = io.CopyN(base64.NewEncoder(base64.StdEncoding, pipeW), rand.New(rand.NewSource(123)), 33*1024768) + pipeW.Close() + }() + // json parsing will hit first so we need to make sure this is valid JSON + bodyReader := io.MultiReader(strings.NewReader("{ \"key\": \""), pipeR, strings.NewReader("\"}")) + resp, err := http.Post(fmt.Sprintf("%s/api/v1/log/entries/retrieve", rekorServer()), + "application/json", + bodyReader) + if err != nil { + t.Fatal(err) + } + if resp.StatusCode != http.StatusRequestEntityTooLarge { + t.Fatalf("expected status %d, got %d instead", http.StatusRequestEntityTooLarge, resp.StatusCode) + } +} diff --git a/cmd/rekor-server/main_test.go b/cmd/rekor-server/main_test.go index 8fa9c4e13..5c151b829 100644 --- a/cmd/rekor-server/main_test.go +++ b/cmd/rekor-server/main_test.go @@ -21,6 +21,6 @@ import ( "github.com/sigstore/rekor/cmd/rekor-server/app" ) -func TestCover(t *testing.T) { +func TestCover(_ *testing.T) { app.Execute() } diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 000000000..c0287fa88 --- /dev/null +++ b/codecov.yml @@ -0,0 +1,18 @@ +# 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. + +coverage: + status: + project: off + patch: off diff --git a/config/watcher.yaml b/config/watcher.yaml deleted file mode 100644 index 659ad098d..000000000 --- a/config/watcher.yaml +++ /dev/null @@ -1,62 +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: apps/v1 -kind: Deployment -metadata: - namespace: rekor-system - name: rekor-watcher - labels: - app: rekor-watcher -spec: - replicas: 1 - selector: - matchLabels: - app: rekor-watcher - template: - metadata: - labels: - app: rekor-watcher - annotations: - prometheus.io/scrape: "true" - prometheus.io/path: /metrics - prometheus.io/port: "2112" - spec: - containers: - - name: rekor-watcher - image: ko://github.com/sigstore/rekor/cmd/rekor-server - command: ["/ko-app/rekor-server"] - ports: - - containerPort: 3000 - - containerPort: 2112 # metrics - args: [ - "watch", - "--rekor_server.address=rekor-server", - "--port=80", - "--log_type=prod", - ] - env: - - name: REKOR_STH_BUCKET - value: "gs://rekor-sth" - resources: - requests: - memory: "1G" - cpu: ".5" - securityContext: - readOnlyRootFilesystem: true - runAsNonRoot: true - capabilities: - drop: - - all diff --git a/docker-compose.test.yml b/docker-compose.test.yml index 6a0b780c4..f1b8d712d 100644 --- a/docker-compose.test.yml +++ b/docker-compose.test.yml @@ -19,6 +19,9 @@ services: build: context: . target: "test" + environment: + TMPDIR: /var/run/attestations # workaround for https://github.com/google/go-cloud/issues/3294 + PUBSUB_EMULATOR_HOST: gcp-pubsub-emulator:8085 command: [ "rekor-server", "-test.coverprofile=rekor-server.cov", @@ -31,9 +34,30 @@ services: "--rekor_server.signer=memory", "--enable_attestation_storage", "--attestation_storage_bucket=file:///var/run/attestations", - "--enable_killswitch", + "--max_request_body_size=32792576", + "--rekor_server.new_entry_publisher=gcppubsub://projects/test-project/topics/new-entry", + "--rekor_server.publish_events_json=true", ] ports: - "3000:3000" - "2112:2112" - - "2345:2345" + depends_on: + - gcp-pubsub-emulator + gcp-pubsub-emulator: + image: gcp-pubsub-emulator + ports: + - "8085:8085" + command: + - gcloud + - beta + - emulators + - pubsub + - start + - --host-port=0.0.0.0:8085 + - --project=test-project + healthcheck: + test: ["CMD", "nc", "-zv", "localhost", "8085"] + interval: 10s + timeout: 3s + retries: 3 + start_period: 10s diff --git a/docker-compose.yml b/docker-compose.yml index 69d6b0bc1..d5bb5afd4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -50,6 +50,7 @@ services: trillian-log-server: image: gcr.io/projectsigstore/trillian_log_server@sha256:f850a0defd089ea844822030c67ae05bc93c91168a7dd4aceb0b6648c39f696b command: [ + "--quota_system=noop", "--storage_system=mysql", "--mysql_uri=test:zaphod@tcp(mysql:3306)/test", "--rpc_endpoint=0.0.0.0:8090", @@ -65,6 +66,7 @@ services: trillian-log-signer: image: gcr.io/projectsigstore/trillian_log_signer@sha256:fe90d523f6617974f70878918e4b31d49b2b46a86024bb2d6b01d2bbfed8edbf command: [ + "--quota_system=noop", "--storage_system=mysql", "--mysql_uri=test:zaphod@tcp(mysql:3306)/test", "--rpc_endpoint=0.0.0.0:8090", @@ -81,6 +83,8 @@ services: build: context: . target: "deploy" + environment: + - TMPDIR=/var/run/attestations # workaround for https://github.com/google/go-cloud/issues/3294 command: [ "rekor-server", "serve", @@ -92,6 +96,7 @@ services: "--rekor_server.signer=memory", "--enable_attestation_storage", "--attestation_storage_bucket=file:///var/run/attestations", + "--enable_stable_checkpoint", # Uncomment this for production logging # "--log_type=prod", ] @@ -111,4 +116,3 @@ services: timeout: 3s retries: 3 start_period: 5s - diff --git a/e2e-test.sh b/e2e-test.sh index 5d494e7a6..19232da04 100755 --- a/e2e-test.sh +++ b/e2e-test.sh @@ -62,8 +62,7 @@ if docker-compose logs --no-color | grep -q "panic: runtime error:" ; then fi echo "generating code coverage" -curl -X GET 0.0.0.0:2345/kill -sleep 5 +docker-compose restart rekor-server if ! docker cp $(docker ps -aqf "name=rekor_rekor-server"):go/rekor-server.cov /tmp/pkg-rekor-server.cov ; then # failed to copy code coverage report from server diff --git a/go.mod b/go.mod index c8bfd901d..644216d6a 100644 --- a/go.mod +++ b/go.mod @@ -1,145 +1,192 @@ module github.com/sigstore/rekor -go 1.18 +go 1.21 require ( - github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d + github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 github.com/blang/semver v3.5.1+incompatible github.com/cavaliercoder/go-rpm v0.0.0-20200122174316-8cb9fd9c31a8 - github.com/cyberphone/json-canonicalization v0.0.0-20210303052042-6bc126869bf4 - github.com/ghodss/yaml v1.0.0 github.com/go-chi/chi v4.1.2+incompatible - github.com/go-openapi/errors v0.20.3 + github.com/go-openapi/errors v0.20.4 github.com/go-openapi/loads v0.21.2 - github.com/go-openapi/runtime v0.25.0 - github.com/go-openapi/spec v0.20.7 - github.com/go-openapi/strfmt v0.21.3 - github.com/go-openapi/swag v0.22.3 - github.com/go-openapi/validate v0.22.0 - github.com/go-playground/validator/v10 v10.11.1 + github.com/go-openapi/runtime v0.26.0 + github.com/go-openapi/spec v0.20.9 + github.com/go-openapi/strfmt v0.21.7 + github.com/go-openapi/swag v0.22.4 + github.com/go-openapi/validate v0.22.1 + github.com/go-playground/validator/v10 v10.15.4 github.com/google/go-cmp v0.5.9 - github.com/google/rpmpack v0.0.0-20210518075352-dc539ef4f2ea - github.com/google/trillian v1.5.1 - github.com/in-toto/in-toto-golang v0.3.4-0.20211211042327-af1f9fb822bf + github.com/google/rpmpack v0.5.0 + github.com/google/trillian v1.5.2 + github.com/in-toto/in-toto-golang v0.9.0 github.com/jedisct1/go-minisign v0.0.0-20211028175153-1c139d1cc84b - github.com/mediocregopher/radix/v4 v4.1.1 github.com/mitchellh/go-homedir v1.1.0 github.com/mitchellh/mapstructure v1.5.0 github.com/pkg/errors v0.9.1 // indirect - github.com/prometheus/client_golang v1.14.0 - github.com/rs/cors v1.8.3 - github.com/sassoftware/relic v0.0.0-20210427151427-dfb082b79b74 - github.com/secure-systems-lab/go-securesystemslib v0.4.0 - github.com/sigstore/sigstore v1.5.0 - github.com/spf13/cobra v1.6.1 + github.com/prometheus/client_golang v1.16.0 + github.com/rs/cors v1.10.0 + github.com/sassoftware/relic v7.2.1+incompatible + github.com/secure-systems-lab/go-securesystemslib v0.7.0 + github.com/sigstore/sigstore v1.7.3 + github.com/spf13/cobra v1.7.0 github.com/spf13/pflag v1.0.5 - github.com/spf13/viper v1.14.0 - github.com/tent/canonical-json-go v0.0.0-20130607151641-96e4ba3a7613 - github.com/theupdateframework/go-tuf v0.5.2-0.20220930112810-3890c1e7ace4 - github.com/transparency-dev/merkle v0.0.1 - github.com/veraison/go-cose v1.0.0-rc.2 - github.com/zalando/go-keyring v0.1.1 // indirect - go.uber.org/goleak v1.2.0 - go.uber.org/zap v1.24.0 - gocloud.dev v0.24.1-0.20211119014450-028788aaaa4c - golang.org/x/crypto v0.4.0 - golang.org/x/mod v0.7.0 - golang.org/x/net v0.4.0 - golang.org/x/sync v0.1.0 - google.golang.org/genproto v0.0.0-20221206210731-b1a01be3a5f6 - google.golang.org/grpc v1.51.0 - google.golang.org/protobuf v1.28.1 + github.com/spf13/viper v1.16.0 + github.com/theupdateframework/go-tuf v0.6.1 + github.com/transparency-dev/merkle v0.0.2 + github.com/veraison/go-cose v1.2.0 + github.com/zalando/go-keyring v0.2.2 // indirect + go.uber.org/goleak v1.2.1 + go.uber.org/zap v1.26.0 + gocloud.dev v0.34.0 + golang.org/x/crypto v0.13.0 + golang.org/x/mod v0.12.0 + golang.org/x/net v0.15.0 + golang.org/x/sync v0.3.0 + google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5 // indirect + google.golang.org/grpc v1.58.2 + google.golang.org/protobuf v1.31.0 gopkg.in/ini.v1 v1.67.0 - sigs.k8s.io/release-utils v0.7.3 + sigs.k8s.io/release-utils v0.7.4 + sigs.k8s.io/yaml v1.3.0 ) require ( - github.com/AdaLogics/go-fuzz-headers v0.0.0-20221103172237-443f56ff4ba8 + cloud.google.com/go/pubsub v1.33.0 + github.com/AdamKorcz/go-fuzz-headers-1 v0.0.0-20230618160516-e936619f9f18 + github.com/cyberphone/json-canonicalization v0.0.0-20220623050100-57a0ce2678a7 + github.com/go-redis/redismock/v9 v9.0.3 + github.com/golang/mock v1.6.0 github.com/hashicorp/go-cleanhttp v0.5.2 - github.com/hashicorp/go-retryablehttp v0.7.1 - golang.org/x/exp v0.0.0-20220823124025-807a23277127 + github.com/hashicorp/go-retryablehttp v0.7.4 + github.com/redis/go-redis/v9 v9.1.0 + github.com/sassoftware/relic/v7 v7.6.1 + github.com/sigstore/protobuf-specs v0.2.1 + github.com/sigstore/sigstore/pkg/signature/kms/aws v1.7.3 + github.com/sigstore/sigstore/pkg/signature/kms/azure v1.7.3 + github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.7.3 + github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.7.3 + golang.org/x/exp v0.0.0-20230321023759-10a507213a29 + google.golang.org/genproto/googleapis/rpc v0.0.0-20230913181813-007df8e322eb ) require ( - cloud.google.com/go/compute/metadata v0.2.2 // indirect + cloud.google.com/go/compute/metadata v0.2.3 // indirect filippo.io/edwards25519 v1.0.0 // indirect - github.com/cyphar/filepath-securejoin v0.2.3 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.2 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.1 // indirect + github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.1 // indirect + github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0 // indirect + github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1 // indirect + github.com/alessio/shellescape v1.4.1 // indirect + github.com/aws/aws-sdk-go-v2 v1.21.0 // indirect + github.com/aws/aws-sdk-go-v2/config v1.18.37 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.13.35 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.11 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.41 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.35 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.3.42 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.35 // indirect + github.com/aws/aws-sdk-go-v2/service/kms v1.24.5 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.13.5 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.5 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.21.5 // indirect + github.com/aws/smithy-go v1.14.2 // indirect + github.com/cavaliergopher/cpio v1.0.1 // indirect + github.com/cenkalti/backoff/v3 v3.2.2 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/gabriel-vasile/mimetype v1.4.2 // indirect + github.com/go-jose/go-jose/v3 v3.0.0 // indirect github.com/go-logr/logr v1.2.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect - go.opentelemetry.io/otel v1.11.1 // indirect - go.opentelemetry.io/otel/trace v1.11.1 // indirect - k8s.io/klog/v2 v2.80.1 // indirect + github.com/golang-jwt/jwt/v5 v5.0.0 // indirect + github.com/google/s2a-go v0.1.7 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-rootcerts v1.0.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/vault/api v1.9.2 // indirect + github.com/jellydator/ttlcache/v3 v3.1.0 // indirect + github.com/klauspost/compress v1.16.6 // indirect + github.com/klauspost/pgzip v1.2.6 // indirect + github.com/kylelemons/godebug v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + go.opentelemetry.io/otel v1.14.0 // indirect + go.opentelemetry.io/otel/trace v1.14.0 // indirect + golang.org/x/time v0.3.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20230803162519-f966b187b2e5 // indirect + k8s.io/klog/v2 v2.100.1 // indirect + software.sslmate.com/src/go-pkcs12 v0.2.0 // indirect ) require ( - cloud.google.com/go v0.107.0 // indirect - cloud.google.com/go/compute v1.13.0 // indirect - cloud.google.com/go/iam v0.8.0 // indirect - cloud.google.com/go/kms v1.7.0 // indirect - cloud.google.com/go/storage v1.27.0 // indirect + cloud.google.com/go v0.110.7 // indirect + cloud.google.com/go/compute v1.23.0 // indirect + cloud.google.com/go/iam v1.1.1 // indirect + cloud.google.com/go/kms v1.15.2 // indirect + cloud.google.com/go/storage v1.31.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cavaliercoder/badio v0.0.0-20160213150051-ce5280129e9e // indirect - github.com/cavaliercoder/go-cpio v0.0.0-20180626203310-925f9528c45e // indirect - github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be // indirect - github.com/danieljoos/wincred v1.1.1 // indirect + github.com/danieljoos/wincred v1.1.2 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/fxamacker/cbor/v2 v2.4.0 // indirect github.com/go-openapi/analysis v0.21.4 // indirect - github.com/go-openapi/jsonpointer v0.19.5 // indirect - github.com/go-openapi/jsonreference v0.20.0 // indirect - github.com/go-playground/locales v0.14.0 // indirect - github.com/go-playground/universal-translator v0.18.0 // indirect - github.com/godbus/dbus/v5 v5.0.4 // indirect + github.com/go-openapi/jsonpointer v0.19.6 // indirect + github.com/go-openapi/jsonreference v0.20.2 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/protobuf v1.5.2 // indirect - github.com/google/go-containerregistry v0.12.1 // indirect - github.com/google/uuid v1.3.0 // indirect + github.com/golang/protobuf v1.5.3 // indirect + github.com/google/go-containerregistry v0.16.1 // indirect + github.com/google/uuid v1.3.1 // indirect github.com/google/wire v0.5.0 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.2.0 // indirect - github.com/googleapis/gax-go/v2 v2.7.0 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.2.5 // indirect + github.com/googleapis/gax-go/v2 v2.12.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect - github.com/howeyc/gopass v0.0.0-20190910152052-7cb4b85ec19c // indirect - github.com/inconshreveable/mousetrap v1.0.1 // indirect - github.com/jellydator/ttlcache/v2 v2.11.1 // indirect + github.com/howeyc/gopass v0.0.0-20210920133722-c8aef6fb66ef // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/josharian/intern v1.0.0 // indirect - github.com/leodido/go-urn v1.2.1 // indirect + github.com/leodido/go-urn v1.2.4 // indirect github.com/letsencrypt/boulder v0.0.0-20221109233200-85aa52084eaf // indirect - github.com/magiconair/properties v1.8.6 // indirect + github.com/magiconair/properties v1.8.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/oklog/ulid v1.3.1 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect - github.com/pelletier/go-toml v1.9.5 // indirect - github.com/pelletier/go-toml/v2 v2.0.5 // indirect - github.com/prometheus/client_model v0.3.0 // indirect - github.com/prometheus/common v0.37.0 // indirect - github.com/prometheus/procfs v0.8.0 // indirect + github.com/pelletier/go-toml/v2 v2.0.8 // indirect + github.com/prometheus/client_model v0.4.0 // indirect + github.com/prometheus/common v0.42.0 // indirect + github.com/prometheus/procfs v0.10.1 // indirect github.com/shibumi/go-pathspec v1.3.0 // indirect - github.com/spf13/afero v1.9.2 // indirect - github.com/spf13/cast v1.5.0 // indirect + github.com/spf13/afero v1.9.5 // indirect + github.com/spf13/cast v1.5.1 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect - github.com/subosito/gotenv v1.4.1 // indirect + github.com/subosito/gotenv v1.4.2 // indirect github.com/tidwall/pretty v1.2.0 // indirect - github.com/tilinna/clock v1.1.0 // indirect github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect - github.com/ulikunitz/xz v0.5.10 // indirect + github.com/ulikunitz/xz v0.5.11 // indirect github.com/x448/float16 v0.8.4 // indirect - go.mongodb.org/mongo-driver v1.10.0 // indirect + go.mongodb.org/mongo-driver v1.11.3 // indirect go.opencensus.io v0.24.0 // indirect - go.step.sm/crypto v0.23.1 - go.uber.org/atomic v1.10.0 // indirect - go.uber.org/multierr v1.8.0 // indirect - golang.org/x/oauth2 v0.3.0 // indirect - golang.org/x/sys v0.3.0 // indirect - golang.org/x/term v0.3.0 // indirect - golang.org/x/text v0.5.0 // indirect + go.step.sm/crypto v0.35.1 + go.uber.org/multierr v1.11.0 // indirect + golang.org/x/oauth2 v0.12.0 // indirect + golang.org/x/sys v0.12.0 // indirect + golang.org/x/term v0.12.0 // indirect + golang.org/x/text v0.13.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect - google.golang.org/api v0.104.0 // indirect + google.golang.org/api v0.142.0 google.golang.org/appengine v1.6.7 // indirect gopkg.in/square/go-jose.v2 v2.6.0 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 121906b5b..732b62302 100644 --- a/go.sum +++ b/go.sum @@ -17,189 +17,127 @@ cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHOb cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= -cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= -cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= -cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= -cloud.google.com/go v0.82.0/go.mod h1:vlKccHJGuFBFufnAnuB08dfEH9Y3H7dzDzRECFdC2TA= -cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= -cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= -cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= -cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= -cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= -cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= -cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= -cloud.google.com/go v0.107.0 h1:qkj22L7bgkl6vIeZDlOY2po43Mx/TIa2Wsa7VR+PEww= -cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= +cloud.google.com/go v0.110.7 h1:rJyC7nWRg2jWGZ4wSJ5nY65GTdYJkg0cd/uXb+ACI6o= +cloud.google.com/go v0.110.7/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/compute v1.13.0 h1:AYrLkB8NPdDRslNp4Jxmzrhdr03fUAIDbiGFjLWowoU= -cloud.google.com/go/compute v1.13.0/go.mod h1:5aPTS0cUNMIc1CE546K+Th6weJUNQErARyZtRXDJ8GE= -cloud.google.com/go/compute/metadata v0.2.2 h1:aWKAjYaBaOSrpKl57+jnS/3fJRQnxL7TvR/u1VVbt6k= -cloud.google.com/go/compute/metadata v0.2.2/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= +cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY= +cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= +cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY= -cloud.google.com/go/iam v0.8.0 h1:E2osAkZzxI/+8pZcxVLcDtAQx/u+hZXVryUaYQ5O0Kk= -cloud.google.com/go/iam v0.8.0/go.mod h1:lga0/y3iH6CX7sYqypWJ33hf7kkfXJag67naqGESjkE= -cloud.google.com/go/kms v1.0.0/go.mod h1:nhUehi+w7zht2XrUfvTRNpxrfayBHqP4lu2NSywui/0= -cloud.google.com/go/kms v1.1.0/go.mod h1:WdbppnCDMDpOvoYBMn1+gNmOeEoZYqAv+HeuKARGCXI= -cloud.google.com/go/kms v1.7.0 h1:8FCf8C7qfOuSr6YzOQ4RGjJvswSRFeOpur3nHOlJbio= -cloud.google.com/go/kms v1.7.0/go.mod h1:k2UdVoNIHLJi/Rnng6dN0vlq7lS3jHSDiZasft+gmYE= -cloud.google.com/go/longrunning v0.3.0 h1:NjljC+FYPV3uh5/OwWT6pVU+doBqMg2x/rZlE+CamDs= -cloud.google.com/go/monitoring v1.1.0/go.mod h1:L81pzz7HKn14QCMaCs6NTQkdBnE87TElyanS95vIcl4= +cloud.google.com/go/iam v1.1.1 h1:lW7fzj15aVIXYHREOqjRBV9PsH0Z6u8Y46a1YGvQP4Y= +cloud.google.com/go/iam v1.1.1/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU= +cloud.google.com/go/kms v1.15.2 h1:lh6qra6oC4AyWe5fUUUBe/S27k12OHAleOOOw6KakdE= +cloud.google.com/go/kms v1.15.2/go.mod h1:3hopT4+7ooWRCjc2DxgnpESFxhIraaI2IpAVUEhbT/w= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/pubsub v1.17.1/go.mod h1:4qDxMr1WsM9+aQAz36ltDwCIM+R0QdlseyFjBuNvnss= -cloud.google.com/go/secretmanager v1.0.0/go.mod h1:+Qkm5qxIJ5mk74xxIXA+87fseaY1JLYBcFPQoc/GQxg= +cloud.google.com/go/pubsub v1.33.0 h1:6SPCPvWav64tj0sVX/+npCBKhUi/UjJehy9op/V3p2g= +cloud.google.com/go/pubsub v1.33.0/go.mod h1:f+w71I33OMyxf9VpMVcZbnG5KSUkCOUHYpFd5U1GdRc= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= -cloud.google.com/go/storage v1.18.2/go.mod h1:AiIj7BWXyhO5gGVmYJ+S8tbkCx3yb0IMjua8Aw4naVM= -cloud.google.com/go/storage v1.27.0 h1:YOO045NZI9RKfCj1c5A/ZtuuENUc8OAW+gHdGnDgyMQ= -cloud.google.com/go/storage v1.27.0/go.mod h1:x9DOL8TK/ygDUMieqwfhdpQryTeEkhGKMi80i/iqR2s= -cloud.google.com/go/trace v1.0.0/go.mod h1:4iErSByzxkyHWzzlAj63/Gmjz0NH1ASqhJguHpGcr6A= -contrib.go.opencensus.io/exporter/aws v0.0.0-20200617204711-c478e41e60e9/go.mod h1:uu1P0UCM/6RbsMrgPa98ll8ZcHM858i/AD06a9aLRCA= -contrib.go.opencensus.io/exporter/stackdriver v0.13.10/go.mod h1:I5htMbyta491eUxufwwZPQdcKvvgzMB4O9ni41YnIM8= -contrib.go.opencensus.io/integrations/ocsql v0.1.7/go.mod h1:8DsSdjz3F+APR+0z0WkU1aRorQCFfRxvqjUUPMbF3fE= +cloud.google.com/go/storage v1.31.0 h1:+S3LjjEN2zZ+L5hOwj4+1OkGCsLVe0NzpXKQ1pSdTCI= +cloud.google.com/go/storage v1.31.0/go.mod h1:81ams1PrhW16L4kF7qg+4mTq7SRs5HsbDTM0bWvrwJ0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek= filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= -github.com/AdaLogics/go-fuzz-headers v0.0.0-20221103172237-443f56ff4ba8 h1:d+pBUmsteW5tM87xmVXHZ4+LibHRFn40SPAoZJOg2ak= -github.com/AdaLogics/go-fuzz-headers v0.0.0-20221103172237-443f56ff4ba8/go.mod h1:i9fr2JpcEcY/IHEvzCM3qXUZYOQHgR89dt4es1CgMhc= -github.com/Azure/azure-amqp-common-go/v3 v3.2.1/go.mod h1:O6X1iYHP7s2x7NjUKsXVhkwWrQhxrd+d8/3rRadj4CI= -github.com/Azure/azure-amqp-common-go/v3 v3.2.2/go.mod h1:O6X1iYHP7s2x7NjUKsXVhkwWrQhxrd+d8/3rRadj4CI= -github.com/Azure/azure-pipeline-go v0.2.3 h1:7U9HBg1JFK3jHl5qmo4CTZKFTVgMwdFHMVtCdfBE21U= -github.com/Azure/azure-pipeline-go v0.2.3/go.mod h1:x841ezTBIMG6O3lAcl8ATHnsOPVl2bqk7S3ta6S6u4k= -github.com/Azure/azure-sdk-for-go v51.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/azure-sdk-for-go v59.3.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/azure-sdk-for-go v67.1.0+incompatible h1:oziYcaopbnIKfM69DL05wXdypiqfrUKdxUKrKpynJTw= -github.com/Azure/azure-service-bus-go v0.11.5/go.mod h1:MI6ge2CuQWBVq+ly456MY7XqNLJip5LO1iSFodbNLbU= -github.com/Azure/azure-storage-blob-go v0.14.0 h1:1BCg74AmVdYwO3dlKwtFU1V0wU2PZdREkXvAmZJRUlM= -github.com/Azure/azure-storage-blob-go v0.14.0/go.mod h1:SMqIBi+SuiQH32bvyjngEewEeXoPfKMgWlBDaYf6fck= -github.com/Azure/go-amqp v0.16.0/go.mod h1:9YJ3RhxRT1gquYnzpZO1vcYMMpAdJT+QEg6fwmw9Zlg= -github.com/Azure/go-amqp v0.16.4/go.mod h1:9YJ3RhxRT1gquYnzpZO1vcYMMpAdJT+QEg6fwmw9Zlg= -github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= -github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= -github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= -github.com/Azure/go-autorest/autorest v0.11.19/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= -github.com/Azure/go-autorest/autorest v0.11.22/go.mod h1:BAWYUWGPEtKPzjVkp0Q6an0MJcJDsoh5Z1BFAEFs4Xs= -github.com/Azure/go-autorest/autorest v0.11.28 h1:ndAExarwr5Y+GaHE6VCaY1kyS/HwwGGyuimVhWsHOEM= -github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= -github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= -github.com/Azure/go-autorest/autorest/adal v0.9.14/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= -github.com/Azure/go-autorest/autorest/adal v0.9.17/go.mod h1:XVVeme+LZwABT8K5Lc3hA4nAe8LDBVle26gTrguhhPQ= -github.com/Azure/go-autorest/autorest/adal v0.9.21 h1:jjQnVFXPfekaqb8vIsv2G1lxshoW+oGv4MDlhRtnYZk= -github.com/Azure/go-autorest/autorest/azure/auth v0.5.9/go.mod h1:hg3/1yw0Bq87O3KvvnJoAh34/0zbP7SFizX/qN5JvjU= -github.com/Azure/go-autorest/autorest/azure/auth v0.5.11 h1:P6bYXFoao05z5uhOQzbC3Qd8JqF3jUoocoTeIxkp2cA= -github.com/Azure/go-autorest/autorest/azure/cli v0.4.2/go.mod h1:7qkJkT+j6b+hIpzMOwPChJhTqS8VbsqqgULzMNRugoM= -github.com/Azure/go-autorest/autorest/azure/cli v0.4.4/go.mod h1:yAQ2b6eP/CmLPnmLvxtT1ALIY3OR1oFcCqVBi8vHiTc= -github.com/Azure/go-autorest/autorest/azure/cli v0.4.6 h1:w77/uPk80ZET2F+AfQExZyEWtn+0Rk/uw17m9fv5Ajc= -github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw= -github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= -github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= -github.com/Azure/go-autorest/autorest/to v0.4.0 h1:oXVqrxakqqV1UZdSazDOPOLvOIz+XA683u8EctwboHk= -github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcPR4o9jEImooCeWJcYV/zLE= -github.com/Azure/go-autorest/autorest/validation v0.3.1 h1:AgyqjAd94fwNAoTjl/WQXg4VvFeRFpO+UhNyRXqF1ac= -github.com/Azure/go-autorest/autorest/validation v0.3.1/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E= -github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg= -github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= -github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= -github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/AdamKorcz/go-fuzz-headers-1 v0.0.0-20230618160516-e936619f9f18 h1:rd389Q26LMy03gG4anandGFC2LW/xvjga5GezeeaxQk= +github.com/AdamKorcz/go-fuzz-headers-1 v0.0.0-20230618160516-e936619f9f18/go.mod h1:fgJuSBrJP5qZtKqaMJE0hmhS2tmRH+44IkfZvjtaf1M= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.2 h1:t5+QXLCK9SVi0PPdaY0PrFvYUo24KwA0QwxnaHRSVd4= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.7.2/go.mod h1:bjGvMhVMb+EEm3VRNQawDMUyMMjo+S5ewNjflkep/0Q= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.1 h1:LNHhpdK7hzUcx/k1LIcuh5k7k1LGIWLQfCjaneSj7Fc= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.3.1/go.mod h1:uE9zaUfEQT/nbQjVi2IblCG9iaLtZsuYZ8ne+PuQ02M= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 h1:sXr+ck84g/ZlZUOZiNELInmMgOsuGwdjjVkEIde0OtY= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.1 h1:MyVTgWR8qd/Jw1Le0NZebGBUCLbtak3bJ3z1OlqZBpw= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.1/go.mod h1:GpPjLhVR9dnUoJMyHWSPy71xY9/lcmpzIPZXmF0FCVY= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0 h1:D3occbWoio4EBLkbkevetNMAVX197GkzbUMtqjGWn80= +github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0/go.mod h1:bTSOgj05NGRuHHhQwAdPnYr9TOdNmKlZTgGLL6nyAdI= +github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1 h1:WpB/QDNLpMw72xHJc34BNNykqSOeEJDAWkhf0u12/Jk= +github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/GoogleCloudPlatform/cloudsql-proxy v1.27.0/go.mod h1:bn9iHmAjogMoIPkqBGyJ9R1m9cXGCjBE/cuhBs3oEsQ= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= -github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/alessio/shellescape v1.4.1 h1:V7yhSDDn8LP4lc4jS8pFkt0zCnzVJlG5JXy9BVKJUX0= +github.com/alessio/shellescape v1.4.1/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= -github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ= -github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= -github.com/aws/aws-sdk-go v1.15.27/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= -github.com/aws/aws-sdk-go v1.37.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= -github.com/aws/aws-sdk-go v1.42.8/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= -github.com/aws/aws-sdk-go v1.44.155 h1:PMHMuUS0atPD4LhiXuYrLasrlIm4u3lpNQBl9h+Lr2s= -github.com/aws/aws-sdk-go-v2 v1.11.0/go.mod h1:SQfA+m2ltnu1cA0soUkj4dRSsmITiVQUJvBIZjzfPyQ= -github.com/aws/aws-sdk-go-v2 v1.17.2 h1:r0yRZInwiPBNpQ4aDy/Ssh3ROWsGtKDwar2JS8Lm+N8= -github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.0.0/go.mod h1:Xn6sxgRuIDflLRJFj5Ev7UxABIkNbccFPV/p8itDReM= -github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.3 h1:S/ZBwevQkr7gv5YxONYpGQxlMFFYSRfz3RMcjsC9Qhk= -github.com/aws/aws-sdk-go-v2/config v1.10.1/go.mod h1:auIv5pIIn3jIBHNRcVQcsczn6Pfa6Dyv80Fai0ueoJU= -github.com/aws/aws-sdk-go-v2/config v1.18.4 h1:VZKhr3uAADXHStS/Gf9xSYVmmaluTUfkc0dcbPiDsKE= -github.com/aws/aws-sdk-go-v2/credentials v1.6.1/go.mod h1:QyvQk1IYTqBWSi1T6UgT/W8DMxBVa5pVuLFSRLLhGf8= -github.com/aws/aws-sdk-go-v2/credentials v1.13.4 h1:nEbHIyJy7mCvQ/kzGG7VWHSBpRB4H6sJy3bWierWUtg= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.8.0/go.mod h1:5E1J3/TTYy6z909QNR0QnXGBpfESYGDqd3O0zqONghU= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.20 h1:tpNOglTZ8kg9T38NpcGBxudqfUAwUzyUnLQ4XSd0CHE= -github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.7.1 h1:p9Dys1g2YdaqMalnp6AwCA+tpMMdJNGw5YYKP/u3sUk= -github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.7.1/go.mod h1:wN/mvkow08GauDwJ70jnzJ1e+hE+Q3Q7TwpYLXOe9oI= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.0/go.mod h1:NO3Q5ZTTQtO2xIg2+xTXYDiT7knSejfeDm7WGDaOo0U= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.26 h1:5WU31cY7m0tG+AiaXuXGoMzo2GBQ1IixtWa8Yywsgco= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.0.0/go.mod h1:anlUzBoEWglcUxUQwZA7HQOEVEnQALVZsizAapB2hq8= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.20 h1:WW0qSzDWoiWU2FS5DbKpxGilFVlCEJPwx4YtjdfI0Jw= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.0/go.mod h1:6oXGy4GLpypD3uCh8wcqztigGgmhLToMfjavgh+VySg= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.27 h1:N2eKFw2S+JWRCtTt0IhIX7uoGGQciD4p6ba+SJv4WEU= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.5 h1:tEEHn+PGAxRVqMPEhtU8oCSW/1Ge3zP5nUgPrGQNUPs= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.5.0/go.mod h1:80NaCIH9YU3rzTTs/J/ECATjXuRqzo/wB6ukO6MZ0XY= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.3 h1:4n4KCtv5SUoT5Er5XV41huuzrCqepxlW3SDI9qHQebc= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.9 h1:gVv2vXOMqJeR4ZHHV32K7LElIJIIzyw/RU1b0lSfWTQ= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.5.0/go.mod h1:Mq6AEc+oEjCUlBuLiK5YwW4shSOAKCQ3tXN0sQeYoBA= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.20 h1:jlgyHbkZQAgAc7VIxJDmtouH8eNjOk2REVAQfVhdaiQ= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.9.0/go.mod h1:xKCZ4YFSF2s4Hnb/J0TLeOsKuGzICzcElaOKNGrVnx4= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.8 h1:TlN1UC39A0LUNoD51ubO5h32haznA+oVe15jO9O4Lj0= -github.com/aws/aws-sdk-go-v2/service/kms v1.10.0/go.mod h1:ZkHWL8m5Nw1g9yMXqpCjnIJtSDToAmNbXXZ9gj0bO7s= -github.com/aws/aws-sdk-go-v2/service/kms v1.19.2 h1:pgOVfu7E6zBddKGks4TvL4YuFsL/oTpiWDIzs4WPLjY= -github.com/aws/aws-sdk-go-v2/service/s3 v1.19.0/go.mod h1:Gwz3aVctJe6mUY9T//bcALArPUaFmNAy2rTB9qN4No8= -github.com/aws/aws-sdk-go-v2/service/s3 v1.27.1 h1:OKQIQ0QhEBmGr2LfT952meIZz3ujrPYnxH+dO/5ldnI= -github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.10.0/go.mod h1:qAgsrzF3Z2vvV01j79fs7D75ofCMQe81/OKBJx0rjFY= -github.com/aws/aws-sdk-go-v2/service/sns v1.11.0/go.mod h1:LIPf3BTbSY5UeVli+x/1y2Qw1w8T9DYyp7p18Qt8Zc8= -github.com/aws/aws-sdk-go-v2/service/sqs v1.12.0/go.mod h1:TDqDmQnsbgL2ZMIGUf3z9xTzCMqFX7FP1geAgIlYqvA= -github.com/aws/aws-sdk-go-v2/service/ssm v1.15.0/go.mod h1:kJa2uHklY03rKsNSbEsToeUgWJ1PambXBtRNacorRhg= -github.com/aws/aws-sdk-go-v2/service/sso v1.6.0/go.mod h1:Q/l0ON1annSU+mc0JybDy1Gy6dnJxIcWjphO6qJPzvM= -github.com/aws/aws-sdk-go-v2/service/sso v1.11.26 h1:ActQgdTNQej/RuUJjB9uxYVLDOvRGtUreXF8L3c8wyg= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.9 h1:wihKuqYUlA2T/Rx+yu2s6NDAns8B9DgnRooB1PVhY+Q= -github.com/aws/aws-sdk-go-v2/service/sts v1.10.0/go.mod h1:jLKCFqS+1T4i7HDqCP9GM4Uk75YW1cS0o82LdxpMyOE= -github.com/aws/aws-sdk-go-v2/service/sts v1.17.6 h1:VQFOLQVL3BrKM/NLO/7FiS4vcp5bqK0mGMyk09xLoAY= -github.com/aws/smithy-go v1.9.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= -github.com/aws/smithy-go v1.13.5 h1:hgz0X/DX0dGqTYpGALqXJoRKRj5oQ7150i5FdTePzO8= -github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= -github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= -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.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/aws/aws-sdk-go v1.45.12 h1:+bKbbesGNPp+TeGrcqfrWuZoqcIEhjwKyBMHQPp80Jo= +github.com/aws/aws-sdk-go v1.45.12/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aws/aws-sdk-go-v2 v1.21.0 h1:gMT0IW+03wtYJhRqTVYn0wLzwdnK9sRMcxmtfGzRdJc= +github.com/aws/aws-sdk-go-v2 v1.21.0/go.mod h1:/RfNgGmRxI+iFOB1OeJUyxiU+9s88k3pfHvDagGEp0M= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.11 h1:/MS8AzqYNAhhRNalOmxUvYs8VEbNGifTnzhPFdcRQkQ= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.11/go.mod h1:va22++AdXht4ccO3kH2SHkHHYvZ2G9Utz+CXKmm2CaU= +github.com/aws/aws-sdk-go-v2/config v1.18.37 h1:RNAfbPqw1CstCooHaTPhScz7z1PyocQj0UL+l95CgzI= +github.com/aws/aws-sdk-go-v2/config v1.18.37/go.mod h1:8AnEFxW9/XGKCbjYDCJy7iltVNyEI9Iu9qC21UzhhgQ= +github.com/aws/aws-sdk-go-v2/credentials v1.13.35 h1:QpsNitYJu0GgvMBLUIYu9H4yryA5kMksjeIVQfgXrt8= +github.com/aws/aws-sdk-go-v2/credentials v1.13.35/go.mod h1:o7rCaLtvK0hUggAGclf76mNGGkaG5a9KWlp+d9IpcV8= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.11 h1:uDZJF1hu0EVT/4bogChk8DyjSF6fof6uL/0Y26Ma7Fg= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.11/go.mod h1:TEPP4tENqBGO99KwVpV9MlOX4NSrSLP8u3KRy2CDwA8= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.76 h1:DJ1kHj0GI9BbX+XhF0kHxlzOVjcncmDUXmCvXdbfdAE= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.76/go.mod h1:/AZCdswMSgwpB2yMSFfY5H4pVeBLnCuPehdmO/r3xSM= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.41 h1:22dGT7PneFMx4+b3pz7lMTRyN8ZKH7M2cW4GP9yUS2g= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.41/go.mod h1:CrObHAuPneJBlfEJ5T3szXOUkLEThaGfvnhTf33buas= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.35 h1:SijA0mgjV8E+8G45ltVHs0fvKpTj8xmZJ3VwhGKtUSI= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.35/go.mod h1:SJC1nEVVva1g3pHAIdCp7QsRIkMmLAgoDquQ9Rr8kYw= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.42 h1:GPUcE/Yq7Ur8YSUk6lVkoIMWnJNO0HT18GUzCWCgCI0= +github.com/aws/aws-sdk-go-v2/internal/ini v1.3.42/go.mod h1:rzfdUlfA+jdgLDmPKjd3Chq9V7LVLYo1Nz++Wb91aRo= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.1.0 h1:U5yySdwt2HPo/pnQec04DImLzWORbeWML1fJiLkKruI= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.1.0/go.mod h1:EhC/83j8/hL/UB1WmExo3gkElaja/KlmZM/gl1rTfjM= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.12 h1:uAiiHnWihGP2rVp64fHwzLDrswGjEjsPszwRYMiYQPU= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.12/go.mod h1:fUTHpOXqRQpXvEpDPSa3zxCc2fnpW6YnBoba+eQr+Bg= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.32 h1:kvN1jPHr9UffqqG3bSgZ8tx4+1zKVHz/Ktw/BwW6hX8= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.32/go.mod h1:QmMEM7es84EUkbYWcpnkx8i5EW2uERPfrTFeOch128Y= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.35 h1:CdzPW9kKitgIiLV1+MHobfR5Xg25iYnyzWZhyQuSlDI= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.35/go.mod h1:QGF2Rs33W5MaN9gYdEQOBBFPLwTZkEhRwI33f7KIG0o= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.15.0 h1:Wgjft9X4W5pMeuqgPCHIQtbZ87wsgom7S5F8obreg+c= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.15.0/go.mod h1:FWNzS4+zcWAP05IF7TDYTY1ysZAzIvogxWaDT9p8fsA= +github.com/aws/aws-sdk-go-v2/service/kms v1.24.5 h1:VNEw+EdYDUdkICYAVQ6n9WoAq8ZuZr7dXKjyaOw94/Q= +github.com/aws/aws-sdk-go-v2/service/kms v1.24.5/go.mod h1:NZEhPgq+vvmM6L9w+xl78Vf7YxqUcpVULqFdrUhHg8I= +github.com/aws/aws-sdk-go-v2/service/s3 v1.38.1 h1:mTgFVlfQT8gikc5+/HwD8UL9jnUro5MGv8n/VEYF12I= +github.com/aws/aws-sdk-go-v2/service/s3 v1.38.1/go.mod h1:6SOWLiobcZZshbmECRTADIRYliPL0etqFSigauQEeT0= +github.com/aws/aws-sdk-go-v2/service/sso v1.13.5 h1:oCvTFSDi67AX0pOX3PuPdGFewvLRU2zzFSrTsgURNo0= +github.com/aws/aws-sdk-go-v2/service/sso v1.13.5/go.mod h1:fIAwKQKBFu90pBxx07BFOMJLpRUGu8VOzLJakeY+0K4= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.5 h1:dnInJb4S0oy8aQuri1mV6ipLlnZPfnsDNB9BGO9PDNY= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.5/go.mod h1:yygr8ACQRY2PrEcy3xsUI357stq2AxnFM6DIsR9lij4= +github.com/aws/aws-sdk-go-v2/service/sts v1.21.5 h1:CQBFElb0LS8RojMJlxRSo/HXipvTZW2S44Lt9Mk2aYQ= +github.com/aws/aws-sdk-go-v2/service/sts v1.21.5/go.mod h1:VC7JDqsqiwXukYEDjoHh9U0fOJtNWh04FPQz4ct4GGU= +github.com/aws/smithy-go v1.14.2 h1:MJU9hqBGbvWZdApzpvoF2WAIJDbtjK2NDJSiJP7HblQ= +github.com/aws/smithy-go v1.14.2/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= -github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= +github.com/bsm/ginkgo/v2 v2.9.5 h1:rtVBYPs3+TC5iLUVOis1B9tjLTup7Cj5IfzosKtvTJ0= +github.com/bsm/ginkgo/v2 v2.9.5/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= +github.com/bsm/gomega v1.26.0 h1:LhQm+AFcgV2M0WyKroMASzAzCAJVpAxQXv4SaI9a69Y= +github.com/bsm/gomega v1.26.0/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= github.com/cavaliercoder/badio v0.0.0-20160213150051-ce5280129e9e h1:YYUjy5BRwO5zPtfk+aa2gw255FIIoi93zMmuy19o0bc= github.com/cavaliercoder/badio v0.0.0-20160213150051-ce5280129e9e/go.mod h1:V284PjgVwSk4ETmz84rpu9ehpGg7swlIH8npP9k2bGw= -github.com/cavaliercoder/go-cpio v0.0.0-20180626203310-925f9528c45e h1:hHg27A0RSSp2Om9lubZpiMgVbvn39bsUmW9U5h0twqc= -github.com/cavaliercoder/go-cpio v0.0.0-20180626203310-925f9528c45e/go.mod h1:oDpT4efm8tSYHXV5tHSdRvBet/b/QzxZ+XyyPehvm3A= github.com/cavaliercoder/go-rpm v0.0.0-20200122174316-8cb9fd9c31a8 h1:jP7ki8Tzx9ThnFPLDhBYAhEpI2+jOURnHQNURgsMvnY= github.com/cavaliercoder/go-rpm v0.0.0-20200122174316-8cb9fd9c31a8/go.mod h1:AZIh1CCnMrcVm6afFf96PBvE2MRpWFco91z8ObJtgDY= +github.com/cavaliergopher/cpio v1.0.1 h1:KQFSeKmZhv0cr+kawA3a0xTQCU4QxXF1vhU7P7av2KM= +github.com/cavaliergopher/cpio v1.0.1/go.mod h1:pBdaqQjnvXxdS/6CvNDwIANIFSP0xRKI16PX4xejRQc= github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M= +github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +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/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -207,42 +145,23 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= -github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb h1:EDmT6Q9Zs+SbUoc7Ik9EfrFqcylYqgPZ9ANSbTAntnE= +github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb/go.mod h1:ZjrT6AXHbDs86ZSdt/osfBi5qfexBrKUdONk989Wnk4= github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be h1:J5BL2kskAlV9ckgEsNQXscjIaLiOYiZ75d4e94E6dcQ= github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be/go.mod h1:mk5IQ+Y0ZeO87b858TlA645sVcEcbiX6YqP98kt+7+w= -github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/cyberphone/json-canonicalization v0.0.0-20210303052042-6bc126869bf4 h1:7AjYfmq7AmviXsuZjV5DcE7PuhJ4dWMi8gLllpLVDQY= -github.com/cyberphone/json-canonicalization v0.0.0-20210303052042-6bc126869bf4/go.mod h1:uzvlm1mxhHkdfqitSA92i7Se+S9ksOn3a3qmv/kyOCw= -github.com/cyphar/filepath-securejoin v0.2.3 h1:YX6ebbZCZP7VkM3scTTokDgBL2TY741X51MTk3ycuNI= -github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= -github.com/danieljoos/wincred v1.0.2/go.mod h1:SnuYRW9lp1oJrZX/dXJqr0cPK5gYXqx3EJbmjhLdK9U= -github.com/danieljoos/wincred v1.1.0/go.mod h1:XYlo+eRTsVA9aHGp7NGjFkPla4m+DCL7hqDjlFjiygg= -github.com/danieljoos/wincred v1.1.1 h1:FgOybUqUGGwgBz+ga92qD4f/ZPvuPryRjashrk/p9IA= -github.com/danieljoos/wincred v1.1.1/go.mod h1:gSBQmTx6G0VmLowygiA7ZD0p0E09HJ68vta8z/RT2d0= +github.com/cyberphone/json-canonicalization v0.0.0-20220623050100-57a0ce2678a7 h1:vU+EP9ZuFUCYE0NYLwTSob+3LNEJATzNfP/DC7SWGWI= +github.com/cyberphone/json-canonicalization v0.0.0-20220623050100-57a0ce2678a7/go.mod h1:uzvlm1mxhHkdfqitSA92i7Se+S9ksOn3a3qmv/kyOCw= +github.com/danieljoos/wincred v1.1.2 h1:QLdCxFs1/Yl4zduvBdcHB8goaYk9RARS2SgLLRuAyr0= +github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnGqR5Vl2tAx0= 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/denisenkom/go-mssqldb v0.11.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= -github.com/devigned/tab v0.1.1/go.mod h1:XG9mPq0dFghrYvoBF3xdRrJzSTX1b7IQrvaL9mzjeJY= -github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= -github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U= -github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= +github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -250,44 +169,31 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= -github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= -github.com/envoyproxy/go-control-plane v0.10.1/go.mod h1:AY7fTTXNdv/aJ2O5jwpxAPOWUZ7hQAEvzN5Pf27BkQQ= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws= github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a h1:yDWHCSQ40h88yih2JAcL6Ls/kVkSE8GFACTGVnMPruw= +github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a/go.mod h1:7Ga40egUymuWXxAe151lTNnCv97MddSOVsjpPPkityA= github.com/facebookgo/limitgroup v0.0.0-20150612190941-6abd8d71ec01 h1:IeaD1VDVBPlx3viJT9Md8if8IxxJnO+x0JCGb054heg= +github.com/facebookgo/limitgroup v0.0.0-20150612190941-6abd8d71ec01/go.mod h1:ypD5nozFk9vcGw1ATYefw6jHe/jZP++Z15/+VTMcWhc= github.com/facebookgo/muster v0.0.0-20150708232844-fd3d7953fd52 h1:a4DFiKFJiDRGFD1qIcqGLX/WlUMD9dyLSLDt+9QZgt8= +github.com/facebookgo/muster v0.0.0-20150708232844-fd3d7953fd52/go.mod h1:yIquW87NGRw1FU5p5lEkpnt/QxoH5uPAOUlOVkAUuMg= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= -github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= -github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= -github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= +github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/fxamacker/cbor/v2 v2.4.0 h1:ri0ArlOR+5XunOP8CRUowT0pSJOwhW098ZCUyskZD88= github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= -github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= -github.com/gin-gonic/gin v1.7.3/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY= +github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= +github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= github.com/go-chi/chi v4.1.2+incompatible h1:fGFk2Gmi/YKXk0OmGfBh0WgmN3XB8lVnEyNz34tQRec= github.com/go-chi/chi v4.1.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-jose/go-jose/v3 v3.0.0 h1:s6rrhirfEP/CGIoc6p+PZAeogN2SxKav6Wp7+dyMWVo= +github.com/go-jose/go-jose/v3 v3.0.0/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= @@ -300,50 +206,53 @@ github.com/go-openapi/analysis v0.21.4/go.mod h1:4zQ35W4neeZTqh3ol0rv/O8JBbka9Qy github.com/go-openapi/errors v0.19.8/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= github.com/go-openapi/errors v0.19.9/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= github.com/go-openapi/errors v0.20.2/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= -github.com/go-openapi/errors v0.20.3 h1:rz6kiC84sqNQoqrtulzaL/VERgkoCyB6WdEkc2ujzUc= -github.com/go-openapi/errors v0.20.3/go.mod h1:Z3FlZ4I8jEGxjUK+bugx3on2mIAk4txuAOhlsB1FSgk= +github.com/go-openapi/errors v0.20.4 h1:unTcVm6PispJsMECE3zWgvG4xTiKda1LIR5rCRWLG6M= +github.com/go-openapi/errors v0.20.4/go.mod h1:Z3FlZ4I8jEGxjUK+bugx3on2mIAk4txuAOhlsB1FSgk= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= +github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= -github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA= github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= +github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= +github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= github.com/go-openapi/loads v0.21.1/go.mod h1:/DtAMXXneXFjbQMGEtbamCZb+4x7eGwkvZCvBmwUG+g= github.com/go-openapi/loads v0.21.2 h1:r2a/xFIYeZ4Qd2TnGpWDIQNcP80dIaZgf704za8enro= github.com/go-openapi/loads v0.21.2/go.mod h1:Jq58Os6SSGz0rzh62ptiu8Z31I+OTHqmULx5e/gJbNw= -github.com/go-openapi/runtime v0.25.0 h1:7yQTCdRbWhX8vnIjdzU8S00tBYf7Sg71EBeorlPHvhc= -github.com/go-openapi/runtime v0.25.0/go.mod h1:Ux6fikcHXyyob6LNWxtE96hWwjBPYF0DXgVFuMTneOs= +github.com/go-openapi/runtime v0.26.0 h1:HYOFtG00FM1UvqrcxbEJg/SwvDRvYLQKGhw2zaQjTcc= +github.com/go-openapi/runtime v0.26.0/go.mod h1:QgRGeZwrUcSHdeh4Ka9Glvo0ug1LC5WyE+EV88plZrQ= github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I= github.com/go-openapi/spec v0.20.6/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= -github.com/go-openapi/spec v0.20.7 h1:1Rlu/ZrOCCob0n+JKKJAWhNWMPW8bOZRg8FJaY+0SKI= -github.com/go-openapi/spec v0.20.7/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= +github.com/go-openapi/spec v0.20.9 h1:xnlYNQAwKd2VQRRfwTEI0DcK+2cbuvI/0c7jx3gA8/8= +github.com/go-openapi/spec v0.20.9/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= github.com/go-openapi/strfmt v0.21.0/go.mod h1:ZRQ409bWMj+SOgXofQAGTIo2Ebu72Gs+WaRADcS5iNg= github.com/go-openapi/strfmt v0.21.1/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrCX/rPGuWb0k= -github.com/go-openapi/strfmt v0.21.3 h1:xwhj5X6CjXEZZHMWy1zKJxvW9AfHC9pkyUjLvHtKG7o= github.com/go-openapi/strfmt v0.21.3/go.mod h1:k+RzNO0Da+k3FrrynSNN8F7n/peCmQQqbbXjtDfvmGg= +github.com/go-openapi/strfmt v0.21.7 h1:rspiXgNWgeUzhjo1YU01do6qsahtJNByjLVbPLNHb8k= +github.com/go-openapi/strfmt v0.21.7/go.mod h1:adeGTkxE44sPyLk0JV235VQAO/ZXUr8KAzYjclFs3ew= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= -github.com/go-openapi/validate v0.22.0 h1:b0QecH6VslW/TxtpKgzpO1SNG7GU2FsaqKdP1E2T50Y= -github.com/go-openapi/validate v0.22.0/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg= -github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= -github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= -github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= -github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= -github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= -github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= -github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= -github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= -github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= -github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ= -github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= -github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= -github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc= +github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU= +github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-openapi/validate v0.22.1 h1:G+c2ub6q47kfX1sOBLwIQwzBVt8qmOAARyo/9Fqs9NU= +github.com/go-openapi/validate v0.22.1/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.15.4 h1:zMXza4EpOdooxPel5xDqXEdXG5r+WggpvnAKMsalBjs= +github.com/go-playground/validator/v10 v10.15.4/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/go-redis/redismock/v9 v9.0.3 h1:mtHQi2l51lCmXIbTRTqb1EiHYe9tL5Yk5oorlSJJqR0= +github.com/go-redis/redismock/v9 v9.0.3/go.mod h1:F6tJRfnU8R/NZ0E+Gjvoluk14MqMC5ueSZX6vVQypc0= +github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= +github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY= github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg= @@ -368,21 +277,11 @@ github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWe github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ= github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0= github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= -github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= -github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= -github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= -github.com/godbus/dbus v4.1.0+incompatible/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= -github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= -github.com/golang-jwt/jwt/v4 v4.1.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= -github.com/golang-jwt/jwt/v4 v4.4.2 h1:rcc4lwaZgFMCZ5jxF9ABolDcIHdBytAFgqFPbSJQAYs= -github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= +github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= +github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE= +github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -395,7 +294,6 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -413,13 +311,9 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +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/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -433,24 +327,23 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-containerregistry v0.12.1 h1:W1mzdNUTx4Zla4JaixCRLhORcR7G6KxE5hHl5fkPsp8= -github.com/google/go-containerregistry v0.12.1/go.mod h1:sdIK+oHQO7B93xI8UweYdl887YhuIwg9vz8BSLH3+8k= +github.com/google/go-containerregistry v0.16.1 h1:rUEt426sR6nyrL3gt+18ibRcvYpKYdpsa5ZW7MA08dQ= +github.com/google/go-containerregistry v0.16.1/go.mod h1:u0qB2l7mvtWVR5kNcbFIhFY1hLbf8eeGapA+vbFDCtQ= github.com/google/go-replayers/grpcreplay v1.1.0 h1:S5+I3zYyZ+GQz68OfbURDdt/+cSMqCK1wrvNx7WBzTE= github.com/google/go-replayers/grpcreplay v1.1.0/go.mod h1:qzAvJ8/wi57zq7gWqaE6AwLM6miiXUQwP1S+I9icmhk= -github.com/google/go-replayers/httpreplay v1.0.0 h1:8SmT8fUYM4nueF+UnXIX8LJxNTb1vpPuknXz+yTWzL4= -github.com/google/go-replayers/httpreplay v1.0.0/go.mod h1:LJhKoTwS5Wy5Ld/peq8dFFG5OfJyHEz7ft+DsTUv25M= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/go-replayers/httpreplay v1.2.0 h1:VM1wEyyjaoU53BwrOnaf9VhAyQQEEioJvFYxYcLRKzk= +github.com/google/go-replayers/httpreplay v1.2.0/go.mod h1:WahEFFZZ7a1P4VM1qEeHy+tME4bwyqPcwWbNlUI1Mcg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian v2.1.1-0.20190517191504-25dcb96d9e51+incompatible h1:xmapqc1AyLoB+ddYT6r04bD9lIjlOqGaREovi0SzFaE= -github.com/google/martian v2.1.1-0.20190517191504-25dcb96d9e51+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw= +github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= @@ -461,137 +354,111 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210506205249-923b5ab0fc1a/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/rpmpack v0.0.0-20210518075352-dc539ef4f2ea h1:Fv9Ni1vIq9+Gv4Sm0Xq+NnPYcnsMbdNhJ4Cu4rkbPBM= -github.com/google/rpmpack v0.0.0-20210518075352-dc539ef4f2ea/go.mod h1:+y9lKiqDhR4zkLl+V9h4q0rdyrYVsWWm6LLCQP33DIk= +github.com/google/rpmpack v0.5.0 h1:L16KZ3QvkFGpYhmp23iQip+mx1X39foEsqszjMNBm8A= +github.com/google/rpmpack v0.5.0/go.mod h1:uqVAUVQLq8UY2hCDfmJ/+rtO3aw7qyhc90rCVEabEfI= +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/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= -github.com/google/trillian v1.5.1 h1:2p1l13f0eWd7eOShwarwIxutYYnGzY/5S+xYewQIPkU= -github.com/google/trillian v1.5.1/go.mod h1:EcDttN8nf+EoAiyLigBAp9ebncZI6rhJPyxZ+dQ6HSo= +github.com/google/trillian v1.5.2 h1:roGP6G8aaAch7vP08+oitPkvmZzxjTfIkguozqJ04Ok= +github.com/google/trillian v1.5.2/go.mod h1:H8vOoa2dxd3xCdMzOOwt9kIz/3MSoJhcqLJGG8iRwbg= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/wire v0.5.0 h1:I7ELFeVBr3yfPIcc8+MWvrjk+3VjbcSzoXm3JVa+jD8= github.com/google/wire v0.5.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU= -github.com/googleapis/enterprise-certificate-proxy v0.2.0 h1:y8Yozv7SZtlU//QXbezB6QkpuE6jMD2/gfzk4AftXjs= -github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= +github.com/googleapis/enterprise-certificate-proxy v0.2.5 h1:UR4rDjcgpgEnqpIEvkiqTYKBCKLNmlge2eVjoZfySzM= +github.com/googleapis/enterprise-certificate-proxy v0.2.5/go.mod h1:RxW0N9901Cko1VOCW3SXCpWP+mlIEkk2tP7jnHy9a3w= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= -github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= -github.com/googleapis/gax-go/v2 v2.7.0 h1:IcsPKeInNvYi7eqSaDjiZqDDKu5rsmunY0Y1YupQSSQ= -github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= +github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= +github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= -github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/hanwen/go-fuse v1.0.0/go.mod h1:unqXarDXqzAk0rt98O2tVndEPIpUgLD9+rwFisZH3Ok= -github.com/hanwen/go-fuse/v2 v2.1.0/go.mod h1:oRyA5eK+pvJyv5otpO/DgccS8y/RvYMaO00GgRLGryc= +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/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= -github.com/hashicorp/go-hclog v1.3.1 h1:vDwF1DFNZhntP4DAjuTpOw3uEgMUpXh1pB5fW9DqHpo= -github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= +github.com/hashicorp/go-hclog v1.2.0 h1:La19f8d7WIlm4ogzNHB0JGqs5AUDAZ2UfCY4sJXcJdM= +github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= -github.com/hashicorp/go-plugin v1.4.6 h1:MDV3UrKQBM3du3G7MApDGvOsMYy3JQJ4exhSoKBAeVA= -github.com/hashicorp/go-retryablehttp v0.7.1 h1:sUiuQAnLlbvmExtFQs72iFW/HXeUn8Z1aJLQ4LJJbTQ= -github.com/hashicorp/go-retryablehttp v0.7.1/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-retryablehttp v0.7.4 h1:ZQgVdpTdAL7WpMIwLzCfbalOcSUdkDZnpUv3/+BxzFA= +github.com/hashicorp/go-retryablehttp v0.7.4/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= -github.com/hashicorp/go-secure-stdlib/mlock v0.1.2 h1:p4AKXPPS24tO8Wc8i1gLvSKdmkiSY5xuju57czJ/IJQ= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7 h1:UpiO20jno/eV1eVZcxqWnUohyKRe1g8FPV/xH1s/2qs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.7/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= -github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= -github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/vault/api v1.8.2 h1:C7OL9YtOtwQbTKI9ogB0A1wffRbCN+rH/LLCHO3d8HM= -github.com/hashicorp/vault/sdk v0.6.1 h1:sjZC1z4j5Rh2GXYbkxn5BLK05S1p7+MhW4AgdUmgRUA= -github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= +github.com/hashicorp/vault/api v1.9.2 h1:YjkZLJ7K3inKgMZ0wzCU9OHqc+UqMQyXsPXnf3Cl2as= +github.com/hashicorp/vault/api v1.9.2/go.mod h1:jo5Y/ET+hNyz+JnKDt8XLAdKs+AM0G5W0Vp1IrFI8N8= github.com/honeycombio/beeline-go v1.10.0 h1:cUDe555oqvw8oD76BQJ8alk7FP0JZ/M/zXpNvOEDLDc= +github.com/honeycombio/beeline-go v1.10.0/go.mod h1:Zz5WMeQCJzFt2Mvf8t6HC1X8RLskLVR/e8rvcmXB1G8= github.com/honeycombio/libhoney-go v1.16.0 h1:kPpqoz6vbOzgp7jC6SR7SkNj7rua7rgxvznI6M3KdHc= -github.com/howeyc/gopass v0.0.0-20190910152052-7cb4b85ec19c h1:aY2hhxLhjEAbfXOx2nRJxCXezC6CO2V/yN+OCr1srtk= -github.com/howeyc/gopass v0.0.0-20190910152052-7cb4b85ec19c/go.mod h1:lADxMC39cJJqL93Duh1xhAs4I2Zs8mKS89XWXFGp9cs= -github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= +github.com/honeycombio/libhoney-go v1.16.0/go.mod h1:izP4fbREuZ3vqC4HlCAmPrcPT9gxyxejRjGtCYpmBn0= +github.com/howeyc/gopass v0.0.0-20210920133722-c8aef6fb66ef h1:A9HsByNhogrvm9cWb28sjiS3i7tcKCkflWFEkHfuAgM= +github.com/howeyc/gopass v0.0.0-20210920133722-c8aef6fb66ef/go.mod h1:lADxMC39cJJqL93Duh1xhAs4I2Zs8mKS89XWXFGp9cs= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/in-toto/in-toto-golang v0.3.4-0.20211211042327-af1f9fb822bf h1:FU8tuL4IWx/Hq55AO4+13AZn3Kd6uk3Z44OCIZ9coTw= -github.com/in-toto/in-toto-golang v0.3.4-0.20211211042327-af1f9fb822bf/go.mod h1:twl9XmClqj6/h/HANQQYaJZVKPPW/Mz53bd2t6UXGQA= +github.com/in-toto/in-toto-golang v0.9.0 h1:tHny7ac4KgtsfrG6ybU8gVOZux2H8jN05AXJ9EBM1XU= +github.com/in-toto/in-toto-golang v0.9.0/go.mod h1:xsBVrVsHNsB61++S6Dy2vWosKhuA3lUTQd+eF9HdeMo= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= -github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jedisct1/go-minisign v0.0.0-20211028175153-1c139d1cc84b h1:ZGiXF8sz7PDk6RgkP+A/SFfUD0ZR/AgG6SpRNEDKZy8= github.com/jedisct1/go-minisign v0.0.0-20211028175153-1c139d1cc84b/go.mod h1:hQmNrgofl+IY/8L+n20H6E6PWBBTokdsv+q49j0QhsU= -github.com/jellydator/ttlcache/v2 v2.11.1 h1:AZGME43Eh2Vv3giG6GeqeLeFXxwxn1/qHItqWZl6U64= -github.com/jellydator/ttlcache/v2 v2.11.1/go.mod h1:RtE5Snf0/57e+2cLWFYWCCsLas2Hy3c5Z4n14XmSvTI= -github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jellydator/ttlcache/v3 v3.1.0 h1:0gPFG0IHHP6xyUyXq+JaD8fwkDCqgqwohXNJBcYE71g= +github.com/jellydator/ttlcache/v3 v3.1.0/go.mod h1:hi7MGFdMAwZna5n2tuvh63DvFLzVKySzCVW6+0gA2n4= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/jmhodges/clock v0.0.0-20160418191101-880ee4c33548 h1:dYTbLf4m0a5u0KLmPfB6mgxbcV7588bOCx79hxa5Sr4= +github.com/jmhodges/clock v0.0.0-20160418191101-880ee4c33548/go.mod h1:hGT6jSUVzF6no3QaDSMLGLEHtHSBSefs+MgcDWnmhmo= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= -github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= -github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.15.11 h1:Lcadnb3RKGin4FYM/orgq0qde+nc15E5Cbqg4B9Sx9c= +github.com/klauspost/compress v1.16.6 h1:91SKEy4K37vkp255cJ8QesJhjyRO0hn9i9G0GoUwLsk= +github.com/klauspost/compress v1.16.6/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU= +github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= -github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 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 v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= -github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= -github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= -github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= +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/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= +github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= github.com/letsencrypt/boulder v0.0.0-20221109233200-85aa52084eaf h1:ndns1qx/5dL43g16EQkPV/i8+b3l5bYQwLeoSBe7tS8= github.com/letsencrypt/boulder v0.0.0-20221109233200-85aa52084eaf/go.mod h1:aGkAgvWY/IUcVFfuly53REpfv5edu25oij+qHRFaraA= -github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lib/pq v1.10.3/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= -github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= -github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= @@ -599,150 +466,112 @@ github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0 github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-ieproxy v0.0.1 h1:qiyop7gCflfhwCzGyeT0gro3sF9AIg9HU98JORTkqfI= -github.com/mattn/go-ieproxy v0.0.1/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/gNWuh88E= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= -github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/mediocregopher/radix/v4 v4.1.1 h1:JkZBEp0y8pWGNZkmO3RR5oEO5huwd4zKKt4rh1C+P8s= -github.com/mediocregopher/radix/v4 v4.1.1/go.mod h1:ajchozX/6ELmydxWeWM6xCFHVpZ4+67LXHOTOVR0nCE= -github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= -github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/mapstructure v1.4.2/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/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/gomega v1.25.0 h1:Vw7br2PCDYijJHSfBOWhov+8cAnUf8MfMaIOV323l6Y= +github.com/onsi/gomega v1.25.0/go.mod h1:r+zV744Re+DiYCIPRlYOTxn0YkOLcAnW8k1xXdMPGhM= 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.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= -github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= -github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg= -github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas= -github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= +github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= +github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= +github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= -github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= -github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= -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/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= +github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= -github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= -github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= -github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= -github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= -github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/qur/ar v0.0.0-20130629153254-282534b91770/go.mod h1:SjlYv2m9lpV0UW6K7lDqVJwEIIvSjaHbGk7nIfY8Hxw= -github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= -github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= +github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= +github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= +github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= +github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg= +github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= +github.com/redis/go-redis/v9 v9.1.0 h1:137FnGdk+EQdCbye1FW+qOEcY5S+SpY9T0NiuqvtfMY= +github.com/redis/go-redis/v9 v9.1.0/go.mod h1:urWj3He21Dj5k4TK1y59xH8Uj6ATueP8AH1cY3lZl4c= github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= -github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= -github.com/rs/cors v1.8.3 h1:O+qNyWn7Z+F9M0ILBHgMVPuB1xTOucVd5gtaYyXBpRo= -github.com/rs/cors v1.8.3/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= -github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rs/cors v1.10.0 h1:62NOS1h+r8p1mW6FM0FSB0exioXLhd/sh15KpjWBZ+8= +github.com/rs/cors v1.10.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= -github.com/sassoftware/go-rpmutils v0.1.1/go.mod h1:euhXULoBpvAxqrBHEyJS4Tsu3hHxUmQWNymxoJbzgUY= -github.com/sassoftware/relic v0.0.0-20210427151427-dfb082b79b74 h1:sUNzanSKA9z/h8xXl+ZJoxIYZL0Qx306MmxqRrvUgr0= -github.com/sassoftware/relic v0.0.0-20210427151427-dfb082b79b74/go.mod h1:YlB8wFIZmFLZ1JllNBfSURzz52fBxbliNgYALk1UDmk= -github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/secure-systems-lab/go-securesystemslib v0.4.0 h1:b23VGrQhTA8cN2CbBw7/FulN9fTtqYUdS5+Oxzt+DUE= -github.com/secure-systems-lab/go-securesystemslib v0.4.0/go.mod h1:FGBZgq2tXWICsxWQW1msNf49F0Pf2Op5Htayx335Qbs= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/sassoftware/relic v7.2.1+incompatible h1:Pwyh1F3I0r4clFJXkSI8bOyJINGqpgjJU3DYAZeI05A= +github.com/sassoftware/relic v7.2.1+incompatible/go.mod h1:CWfAxv73/iLZ17rbyhIEq3K9hs5w6FpNMdUT//qR+zk= +github.com/sassoftware/relic/v7 v7.6.1 h1:O5s8ewCgq5QYNpv45dK4u6IpBmDM9RIcsbf/G1uXepQ= +github.com/sassoftware/relic/v7 v7.6.1/go.mod h1:NxwtWxWxlUa9as2qZi635Ye6bBT/tGnMALLq7dSfOOU= +github.com/secure-systems-lab/go-securesystemslib v0.7.0 h1:OwvJ5jQf9LnIAS83waAjPbcMsODrTQUpJ02eNLUoxBg= +github.com/secure-systems-lab/go-securesystemslib v0.7.0/go.mod h1:/2gYnlnHVQ6xeGtfIqFy7Do03K4cdCY0A/GlJLDKLHI= github.com/shibumi/go-pathspec v1.3.0 h1:QUyMZhFo0Md5B8zV8x2tesohbb5kfbpTi9rBnKh5dkI= github.com/shibumi/go-pathspec v1.3.0/go.mod h1:Xutfslp817l2I1cZvgcfeMQJG5QnU2lh5tVaaMCl3jE= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/sigstore/sigstore v1.5.0 h1:NqstQ6SwwhQsp6Ll0wgk/d9g5MlfmEppo14aquUjJ/8= -github.com/sigstore/sigstore v1.5.0/go.mod h1:fRAaZ9xXh7ZQ0GJqZdpmNJ3pemuHBu2PgIAngmzIFSI= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sigstore/protobuf-specs v0.2.1 h1:KIoM7E3C4uaK092q8YoSj/XSf9720f8dlsbYwwOmgEA= +github.com/sigstore/protobuf-specs v0.2.1/go.mod h1:xPqQGnH/HllKuZ4VFPz/g+78epWM/NLRGl7Fuy45UdE= +github.com/sigstore/sigstore v1.7.3 h1:HVVTfrMezJeLyl2xhJ8edzkrEGBa4KxjQZB4FlQ4JLU= +github.com/sigstore/sigstore v1.7.3/go.mod h1:cl0c7Dtg3MM3c13L8pqqrfrmBa0eM3POcdtBepjylmw= +github.com/sigstore/sigstore/pkg/signature/kms/aws v1.7.3 h1:HbtK8W1bl+BhUPPtpfh4bgkm5oXrtzqd6FTvFg+oor8= +github.com/sigstore/sigstore/pkg/signature/kms/aws v1.7.3/go.mod h1:JPLKxAUNNsuUQZUy9G3TGhfZCrUaGWa18dxJUQb2E/s= +github.com/sigstore/sigstore/pkg/signature/kms/azure v1.7.3 h1:dS0f3vtSfgJClJrIFKzfettFfSfygEWDd/yecLcH1uc= +github.com/sigstore/sigstore/pkg/signature/kms/azure v1.7.3/go.mod h1:N2GlshxHUDP3V2irRTZNgXkExAXL9y32bEK2k7jDLKo= +github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.7.3 h1:zO5OlN1DZ/f6N2Gtl72NleHv2kLudSxa9evaz1VgIKQ= +github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.7.3/go.mod h1:JVLf01VmZPBqkISIc7EDCFeTk4aFC0+uL/SXC57QhHQ= +github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.7.3 h1:IVPaj3NCCc037V2gtFISnSeebmBq1vnkKoPpNjHL3yM= +github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.7.3/go.mod h1:prbSgDAfwNix71ZKDll1Pp1EucXP7r0UGnAqQ1hcrHo= github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262 h1:unQFBIznI+VYD1/1fApl1A+9VcBk+9dcqGfnePY87LY= -github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= -github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= -github.com/spf13/afero v1.9.2 h1:j49Hj62F0n+DaZ1dDCvhABaPNSGNkt32oRFxI33IEMw= -github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= -github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= +github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262/go.mod h1:MyOHs9Po2fbM1LHej6sBUT8ozbxmMOFG+E+rx/GSGuc= +github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= +github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= +github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= +github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= -github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= -github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= +github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= -github.com/spf13/viper v1.14.0 h1:Rg7d3Lo706X9tHsJMUjdiwMpHB7W8WnSVOssIY+JElU= -github.com/spf13/viper v1.14.0/go.mod h1:WT//axPky3FdvXHzGw33dNdXXXfFQqmEalje+egj8As= -github.com/streadway/amqp v1.0.0/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/spf13/viper v1.16.0 h1:rGGH0XDZhdUOryiDWjmIvUSWpbNqisK8Wk0Vyefw8hc= +github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1FofRzQg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= -github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -754,35 +583,30 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs= -github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= -github.com/tent/canonical-json-go v0.0.0-20130607151641-96e4ba3a7613 h1:iGnD/q9160NWqKZZ5vY4p0dMiYMRknzctfSkqA4nBDw= -github.com/tent/canonical-json-go v0.0.0-20130607151641-96e4ba3a7613/go.mod h1:g6AnIpDSYMcphz193otpSIzN+11Rs+AAIIC6rm1enug= -github.com/theupdateframework/go-tuf v0.5.2-0.20220930112810-3890c1e7ace4 h1:1i/Afw3rmaR1gF3sfVkG2X6ldkikQwA9zY380LrR5YI= -github.com/theupdateframework/go-tuf v0.5.2-0.20220930112810-3890c1e7ace4/go.mod h1:vAqWV3zEs89byeFsAYoh/Q14vJTgJkHwnnRCWBBBINY= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= +github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= +github.com/theupdateframework/go-tuf v0.6.1 h1:6J89fGjQf7s0mLmTG7p7pO/MbKOg+bIXhaLyQdmbKuE= +github.com/theupdateframework/go-tuf v0.6.1/go.mod h1:LAFusuQsFNBnEyYoTuA5zZrF7iaQ4TEgBXm8lb6Vj18= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= -github.com/tilinna/clock v1.0.2/go.mod h1:ZsP7BcY7sEEz7ktc0IVy8Us6boDrK8VradlKRUGfOao= -github.com/tilinna/clock v1.1.0 h1:6IQQQCo6KoBxVudv6gwtY8o4eDfhHo8ojA5dP0MfhSs= -github.com/tilinna/clock v1.1.0/go.mod h1:ZsP7BcY7sEEz7ktc0IVy8Us6boDrK8VradlKRUGfOao= github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 h1:e/5i7d4oYZ+C1wj2THlRK+oAhjeS/TRQwMfkIuet3w0= github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399/go.mod h1:LdwHTNJT99C5fTAzDz0ud328OgXz+gierycbcIx2fRs= -github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/transparency-dev/merkle v0.0.1 h1:T9/9gYB8uZl7VOJIhdwjALeRWlxUxSfDEysjfmx+L9E= -github.com/transparency-dev/merkle v0.0.1/go.mod h1:B8FIw5LTq6DaULoHsVFRzYIUDkl8yuSwCdZnOZGKL/A= -github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= -github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= -github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= -github.com/ulikunitz/xz v0.5.7/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= -github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8= -github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= -github.com/veraison/go-cose v1.0.0-rc.2 h1:zH3QmP4N5kwpdGauceIT3aJm8iUyV9OqpUOb+7CF7rQ= -github.com/veraison/go-cose v1.0.0-rc.2/go.mod h1:7ziE85vSq4ScFTg6wyoMXjucIGOf4JkFEZi/an96Ct4= +github.com/transparency-dev/merkle v0.0.2 h1:Q9nBoQcZcgPamMkGn7ghV8XiTZ/kRxn1yCG81+twTK4= +github.com/transparency-dev/merkle v0.0.2/go.mod h1:pqSy+OXefQ1EDUVmAJ8MUhHB9TXGuzVAT58PqBoHz1A= +github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8= +github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/veraison/go-cose v1.2.0 h1:Ok0Hr3GMAf8K/1NB4sV65QGgCiukG1w1QD+H5tmt0Ow= +github.com/veraison/go-cose v1.2.0/go.mod h1:7ziE85vSq4ScFTg6wyoMXjucIGOf4JkFEZi/an96Ct4= github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU= +github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= +github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= @@ -790,83 +614,58 @@ github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+ github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= -github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/zalando/go-keyring v0.1.0/go.mod h1:RaxNwUITJaHVdQ0VC7pELPZ3tOWn13nr0gZMZEhpVU0= -github.com/zalando/go-keyring v0.1.1 h1:w2V9lcx/Uj4l+dzAf1m9s+DJ1O8ROkEHnynonHjTcYE= -github.com/zalando/go-keyring v0.1.1/go.mod h1:OIC+OZ28XbmwFxU/Rp9V7eKzZjamBJwRzC8UFJH9+L8= -go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +github.com/zalando/go-keyring v0.2.2 h1:f0xmpYiSrHtSNAVgwip93Cg8tuF45HJM6rHq/A5RI/4= +github.com/zalando/go-keyring v0.2.2/go.mod h1:sI3evg9Wvpw3+n4SqplGSJUMwtDeROfD4nsFz4z9PG0= go.mongodb.org/mongo-driver v1.7.3/go.mod h1:NqaYOwnXWr5Pm7AOpO5QFxKJ503nbMse/R79oO62zWg= go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng= -go.mongodb.org/mongo-driver v1.10.0 h1:UtV6N5k14upNp4LTduX0QCufG124fSu25Wz9tu94GLg= go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8= -go.opencensus.io v0.15.0/go.mod h1:UffZAU+4sDEINUGP/B7UfBBkq4fqLu9zXAX7ke6CHW0= +go.mongodb.org/mongo-driver v1.11.3 h1:Ql6K6qYHEzB6xvu4+AU0BoRoqf9vFPcc4o7MUIdPW8Y= +go.mongodb.org/mongo-driver v1.11.3/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5quethTUn9WM+2g= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/otel v1.11.1 h1:4WLLAmcfkmDk2ukNXJyq3/kiz/3UzCaYq6PskJsaou4= -go.opentelemetry.io/otel v1.11.1/go.mod h1:1nNhXBbWSD0nsL38H6btgnFN2k4i0sNLHNNMZMSbUGE= -go.opentelemetry.io/otel/sdk v1.11.1 h1:F7KmQgoHljhUuJyA+9BiU+EkJfyX5nVVF4wyzWZpKxs= -go.opentelemetry.io/otel/trace v1.11.1 h1:ofxdnzsNrGBYXbP7t7zpUK281+go5rF7dvdIZXF8gdQ= -go.opentelemetry.io/otel/trace v1.11.1/go.mod h1:f/Q9G7vzk5u91PhbmKbg1Qn0rzH1LJ4vbPHFGkTPtOk= -go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.step.sm/crypto v0.23.1 h1:Yr9vlzjGqIKVi88KcpZtEcNTcpDkt1nVR7tumW4h+CU= -go.step.sm/crypto v0.23.1/go.mod h1:djAhDYpNAuWF2LkzbCVcf0JDy1UWgrxR3eQ7pQ8EQ/w= -go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= -go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= -go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= -go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= -go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= -go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= -go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= -go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= -gocloud.dev v0.24.1-0.20211119014450-028788aaaa4c h1:TAqxeJMp07tXRPbBRBhwBtAs2Z8dtHq7xIuMxrnrvJ8= -gocloud.dev v0.24.1-0.20211119014450-028788aaaa4c/go.mod h1:EIJSlY7nvfeoWaV2GauF6es27gZfqtTVon47QFueoyE= +go.opentelemetry.io/otel v1.14.0 h1:/79Huy8wbf5DnIPhemGB+zEPVwnN6fuQybr/SRXa6hM= +go.opentelemetry.io/otel v1.14.0/go.mod h1:o4buv+dJzx8rohcUeRmWUZhqupFvzWis188WlggnNeU= +go.opentelemetry.io/otel/sdk v1.14.0 h1:PDCppFRDq8A1jL9v6KMI6dYesaq+DFcDZvjsoGvxGzY= +go.opentelemetry.io/otel/sdk v1.14.0/go.mod h1:bwIC5TjrNG6QDCHNWvW4HLHtUQ4I+VQDsnjhvyZCALM= +go.opentelemetry.io/otel/trace v1.14.0 h1:wp2Mmvj41tDsyAJXiWDWpfNsOiIyd38fy85pyKcFq/M= +go.opentelemetry.io/otel/trace v1.14.0/go.mod h1:8avnQLK+CG77yNLUae4ea2JDQ6iT+gozhnZjy/rw9G8= +go.step.sm/crypto v0.35.1 h1:QAZZ7Q8xaM4TdungGSAYw/zxpyH4fMYTkfaXVV9H7pY= +go.step.sm/crypto v0.35.1/go.mod h1:vn8Vkx/Mbqgoe7AG8btC0qZ995Udm3e+JySuDS1LCJA= +go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= +go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= +go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= +gocloud.dev v0.34.0 h1:LzlQY+4l2cMtuNfwT2ht4+fiXwWf/NmPTnXUlLmGif4= +gocloud.dev v0.34.0/go.mod h1:psKOachbnvY3DAOPbsFVmLIErwsbWPUG2H5i65D38vE= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200930160638-afb6bcd081ae/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20211115234514-b4de73f9ece8/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8= -golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80= +golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -877,8 +676,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20220823124025-807a23277127 h1:S4NrSKDfihhl3+4jSTgwoIevKxX9p7Iv9x++OEIptDo= -golang.org/x/exp v0.0.0-20220823124025-807a23277127/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= +golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug= +golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -892,8 +691,6 @@ golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRu golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= @@ -905,26 +702,20 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= -golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA= -golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -939,28 +730,17 @@ golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200930145003-4acb6c075d10/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= -golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211118161319-6a13c67c3ce4/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU= -golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -970,18 +750,8 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210427180440-81ed05c6b58c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.3.0 h1:6l90koy8/LaBLmLu8jpHeHexzMwEita0zFfYlggy2F8= -golang.org/x/oauth2 v0.3.0/go.mod h1:rQrIauxkUhJ6CuwEXwymO2/eh4xz2ZWF1nBkcxS+tGk= +golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4= +golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -991,16 +761,14 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200930132711-30421366ff76/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +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-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1014,13 +782,9 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191112214154-59a1497f0cea/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1032,52 +796,28 @@ golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200828194041-157a740278f4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210503080704-8803ae5d1324/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210819135213-f52c844e1c1c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= -golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI= -golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= +golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU= +golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1087,16 +827,13 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= -golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.2.0 h1:52I/1L54xyEQAYdtcSuxtiT84KGYTBGXwayxmIpNJhE= -golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -1117,7 +854,6 @@ golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -1149,14 +885,8 @@ golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210112230658-8b4aab62c064/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.4.0 h1:7mTAgkunk3fr4GAloyyCasadO6h9zSsQZbwvcaIciV4= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1182,22 +912,8 @@ google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz513 google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= -google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= -google.golang.org/api v0.46.0/go.mod h1:ceL4oozhkAiTID8XMmJBsIxID/9wMXJVVFXPg4ylg3I= -google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= -google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= -google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= -google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= -google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= -google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= -google.golang.org/api v0.58.0/go.mod h1:cAbP2FsxoGVNwtgNAmmn3y5G1TWAiVYRmg4yku3lv+E= -google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU= -google.golang.org/api v0.60.0/go.mod h1:d7rl65NZAkEQ90JFzqBjcRq1TVeG5ZoGV3sSpEnnVb4= -google.golang.org/api v0.104.0 h1:KBfmLRqdZEbwQleFlSLnzpQJwhjpmNOk4cKQIBDZ9mg= -google.golang.org/api v0.104.0/go.mod h1:JCspTXJbBxa5ySXw4UgUqVer7DfVxbvc/CTUFqAED5U= +google.golang.org/api v0.142.0 h1:mf+7EJ94fi5ZcnpPy+m0Yv2dkz8bKm+UL0snTCuwXlY= +google.golang.org/api v0.142.0/go.mod h1:zJAN5o6HRqR7O+9qJUFOWrZkYE66RH+efPBdTLA4xBA= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1229,7 +945,6 @@ google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= @@ -1242,44 +957,15 @@ google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210429181445-86c259c2b4ab/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= -google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= -google.golang.org/genproto v0.0.0-20210517163617-5e0236093d7a/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= -google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= -google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= -google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210917145530-b395a37504d4/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210921142501-181ce0d877f6/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211008145708-270636b82663/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211016002631-37fc39342514/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211018162055-cf77aa76bad2/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211019152133-63b7e35f4404/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211021150943-2b146023228c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211028162531-8db9c33dc351/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20221206210731-b1a01be3a5f6 h1:AGXp12e/9rItf6/4QymU7WsAUwCf+ICW75cuR91nJIc= -google.golang.org/genproto v0.0.0-20221206210731-b1a01be3a5f6/go.mod h1:1dOng4TWOomJrDGhpXjfCD35wQC6jnC7HpRmOFRqEV0= +google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5 h1:L6iMMGrtzgHsWofoFcihmDEMYeDR9KN/ThbPWGrh++g= +google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5/go.mod h1:oH/ZOT02u4kWEp7oYBGYFFkCdKS/uYR9Z7+0/xuuFp8= +google.golang.org/genproto/googleapis/api v0.0.0-20230803162519-f966b187b2e5 h1:nIgk/EEq3/YlnmVVXVnm14rC2oxgs1o0ong4sD/rd44= +google.golang.org/genproto/googleapis/api v0.0.0-20230803162519-f966b187b2e5/go.mod h1:5DZzOUPCLYL3mNkQ0ms0F3EuUNZ7py1Bqeq6sxzI7/Q= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230913181813-007df8e322eb h1:Isk1sSH7bovx8Rti2wZK0UZF6oraBDK74uoyLEEVFN0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230913181813-007df8e322eb/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= @@ -1291,22 +977,11 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.51.0 h1:E1eGv1FTqoLIdnBCZufiSHgKjlqG6fKFf6pPWtMTh8U= -google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= +google.golang.org/grpc v1.58.2 h1:SXUpjxeVF3FKrTYQI4f4KvbGD5u2xccdYdurwowix5I= +google.golang.org/grpc v1.58.2/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= 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= @@ -1319,31 +994,24 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= -google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alexcesaro/statsd.v2 v2.0.0 h1:FXkZSCZIH17vLCO5sO2UucTHsH9pc+17F6pl3JVCwMc= +gopkg.in/alexcesaro/statsd.v2 v2.0.0/go.mod h1:i0ubccKGzBVNBpdGV5MocxyA/XlLUJzA7SLonnE4drU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= 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.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= @@ -1359,11 +1027,14 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/klog/v2 v2.80.1 h1:atnLQ121W371wYYFawwYx1aEY2eUfs4l3J72wtgAwV4= -k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= +k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= +k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/release-utils v0.7.3 h1:6pS8x6c5RmdUgR9qcg1LO6hjUzuE4Yo9TGZ3DemrZdM= -sigs.k8s.io/release-utils v0.7.3/go.mod h1:n0mVez/1PZYZaZUTJmxewxH3RJ/Lf7JUDh7TG1CASOE= +sigs.k8s.io/release-utils v0.7.4 h1:17LmJrydpUloTCtaoWj95uKlcrUp4h2A9Sa+ZL+lV9w= +sigs.k8s.io/release-utils v0.7.4/go.mod h1:JEt2QPHItd5Pg2UKLAU8PEaSlF4bUjCZimpxFDgymVU= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= +software.sslmate.com/src/go-pkcs12 v0.2.0 h1:nlFkj7bTysH6VkC4fGphtjXRbezREPgrHuJG20hBGPE= +software.sslmate.com/src/go-pkcs12 v0.2.0/go.mod h1:23rNcYsMabIc1otwLpTkCCPwUq6kQsTyowttG/as0kQ= diff --git a/hack/tools/go.mod b/hack/tools/go.mod index fb5a35811..50e85aae2 100644 --- a/hack/tools/go.mod +++ b/hack/tools/go.mod @@ -1,66 +1,67 @@ module github.com/sigstore/rekor/hack/tools -go 1.18 +go 1.20 require ( - github.com/AdaLogics/go-fuzz-headers v0.0.0-20220708163326-82d177caec6e - github.com/go-swagger/go-swagger v0.30.3 - github.com/google/trillian v1.5.1 + github.com/AdamKorcz/go-fuzz-headers-1 v0.0.0-20230329111138-12e09aba5ebd + github.com/go-swagger/go-swagger v0.30.5 + github.com/google/trillian v1.5.2 github.com/wadey/gocovmerge v0.0.0-20160331181800-b5bfa59ec0ad ) require ( bitbucket.org/creachadair/shell v0.0.7 // indirect - cloud.google.com/go v0.107.0 // indirect - cloud.google.com/go/compute v1.13.0 // indirect - cloud.google.com/go/compute/metadata v0.2.2 // indirect - cloud.google.com/go/monitoring v1.8.0 // indirect - cloud.google.com/go/spanner v1.42.0 // indirect - cloud.google.com/go/trace v1.4.0 // indirect - contrib.go.opencensus.io/exporter/stackdriver v0.13.12 // indirect + cloud.google.com/go v0.110.0 // indirect + cloud.google.com/go/compute v1.19.0 // indirect + cloud.google.com/go/compute/metadata v0.2.3 // indirect + cloud.google.com/go/monitoring v1.13.0 // indirect + cloud.google.com/go/spanner v1.45.1 // indirect + cloud.google.com/go/trace v1.9.0 // indirect + contrib.go.opencensus.io/exporter/stackdriver v0.13.14 // indirect github.com/Masterminds/goutils v1.1.1 // indirect - github.com/Masterminds/semver/v3 v3.1.1 // indirect - github.com/Masterminds/sprig/v3 v3.2.2 // indirect - github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect - github.com/aws/aws-sdk-go v1.37.0 // indirect + github.com/Masterminds/semver/v3 v3.2.0 // indirect + github.com/Masterminds/sprig/v3 v3.2.3 // indirect + github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect + github.com/aws/aws-sdk-go v1.43.31 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/census-instrumentation/opencensus-proto v0.3.0 // indirect - github.com/cespare/xxhash/v2 v2.1.2 // indirect - github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4 // indirect - github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490 // indirect - github.com/cockroachdb/cockroach-go/v2 v2.2.19 // indirect + github.com/census-instrumentation/opencensus-proto v0.4.1 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe // indirect + github.com/cncf/xds/go v0.0.0-20230310173818-32f1caf87195 // indirect + github.com/cockroachdb/cockroach-go/v2 v2.3.3 // indirect github.com/coreos/go-semver v0.3.0 // indirect github.com/coreos/go-systemd/v22 v22.3.2 // indirect - github.com/cyphar/filepath-securejoin v0.2.3 // indirect - github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1 // indirect - github.com/envoyproxy/protoc-gen-validate v0.6.2 // indirect + github.com/cyphar/filepath-securejoin v0.2.4 // indirect + github.com/envoyproxy/go-control-plane v0.11.0 // indirect + github.com/envoyproxy/protoc-gen-validate v0.10.0 // indirect github.com/felixge/httpsnoop v1.0.3 // indirect - github.com/fsnotify/fsnotify v1.5.4 // indirect - github.com/go-logr/logr v1.2.0 // indirect + github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/go-logr/logr v1.2.3 // indirect github.com/go-openapi/analysis v0.21.4 // indirect - github.com/go-openapi/errors v0.20.3 // indirect + github.com/go-openapi/errors v0.20.4 // indirect github.com/go-openapi/inflect v0.19.0 // indirect - github.com/go-openapi/jsonpointer v0.19.5 // indirect - github.com/go-openapi/jsonreference v0.20.0 // indirect + github.com/go-openapi/jsonpointer v0.19.6 // indirect + github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/loads v0.21.2 // indirect - github.com/go-openapi/runtime v0.24.1 // indirect - github.com/go-openapi/spec v0.20.7 // indirect - github.com/go-openapi/strfmt v0.21.3 // indirect - github.com/go-openapi/swag v0.22.3 // indirect - github.com/go-openapi/validate v0.22.0 // indirect - github.com/go-sql-driver/mysql v1.7.0 // indirect + github.com/go-openapi/runtime v0.26.0 // indirect + github.com/go-openapi/spec v0.20.9 // indirect + github.com/go-openapi/strfmt v0.21.7 // indirect + github.com/go-openapi/swag v0.22.4 // indirect + github.com/go-openapi/validate v0.22.1 // indirect + github.com/go-sql-driver/mysql v1.7.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/mock v1.6.0 // indirect - github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/protobuf v1.5.3 // indirect github.com/google/go-cmp v0.5.9 // indirect + github.com/google/s2a-go v0.1.3 // indirect github.com/google/uuid v1.3.0 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.2.0 // indirect - github.com/googleapis/gax-go/v2 v2.7.0 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect + github.com/googleapis/gax-go/v2 v2.8.0 // indirect github.com/gorilla/handlers v1.5.1 // indirect - github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect + github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect - github.com/huandu/xstrings v1.3.2 // indirect + github.com/huandu/xstrings v1.3.3 // indirect github.com/imdario/mergo v0.3.12 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect github.com/jackc/pgconn v1.12.1 // indirect @@ -73,58 +74,57 @@ require ( github.com/jessevdk/go-flags v1.5.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/josharian/intern v1.0.0 // indirect - github.com/kr/pretty v0.3.0 // indirect + github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect - github.com/lib/pq v1.10.7 // indirect - github.com/magiconair/properties v1.8.6 // indirect + github.com/lib/pq v1.10.9 // indirect + github.com/magiconair/properties v1.8.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/oklog/ulid v1.3.1 // indirect - github.com/pelletier/go-toml v1.9.5 // indirect - github.com/pelletier/go-toml/v2 v2.0.1 // indirect + github.com/pelletier/go-toml/v2 v2.0.8 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/prometheus/client_golang v1.14.0 // indirect - github.com/prometheus/client_model v0.3.0 // indirect - github.com/prometheus/common v0.37.0 // indirect - github.com/prometheus/procfs v0.8.0 // indirect - github.com/prometheus/prometheus v2.5.0+incompatible // indirect + github.com/prometheus/client_golang v1.15.1 // indirect + github.com/prometheus/client_model v0.4.0 // indirect + github.com/prometheus/common v0.42.0 // indirect + github.com/prometheus/procfs v0.9.0 // indirect + github.com/prometheus/prometheus v0.35.0 // indirect github.com/rogpeppe/go-internal v1.9.0 // indirect github.com/shopspring/decimal v1.3.1 // indirect - github.com/spf13/afero v1.8.2 // indirect - github.com/spf13/cast v1.5.0 // indirect + github.com/spf13/afero v1.9.5 // indirect + github.com/spf13/cast v1.5.1 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/spf13/viper v1.12.0 // indirect - github.com/subosito/gotenv v1.3.0 // indirect + github.com/spf13/viper v1.16.0 // indirect + github.com/subosito/gotenv v1.4.2 // indirect github.com/toqueteos/webbrowser v1.2.0 // indirect - github.com/transparency-dev/merkle v0.0.1 // indirect - go.etcd.io/etcd/api/v3 v3.5.6 // indirect - go.etcd.io/etcd/client/pkg/v3 v3.5.6 // indirect - go.etcd.io/etcd/client/v3 v3.5.6 // indirect - go.mongodb.org/mongo-driver v1.10.1 // indirect + github.com/transparency-dev/merkle v0.0.2 // indirect + go.etcd.io/etcd/api/v3 v3.5.9 // indirect + go.etcd.io/etcd/client/pkg/v3 v3.5.9 // indirect + go.etcd.io/etcd/client/v3 v3.5.9 // indirect + go.mongodb.org/mongo-driver v1.11.3 // indirect go.opencensus.io v0.24.0 // indirect - go.uber.org/atomic v1.9.0 // indirect + go.uber.org/atomic v1.10.0 // indirect go.uber.org/multierr v1.8.0 // indirect go.uber.org/zap v1.21.0 // indirect - golang.org/x/crypto v0.4.0 // indirect - golang.org/x/mod v0.7.0 // indirect - golang.org/x/net v0.3.0 // indirect - golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783 // indirect - golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.3.0 // indirect - golang.org/x/text v0.5.0 // indirect - golang.org/x/tools v0.4.0 // indirect + golang.org/x/crypto v0.9.0 // indirect + golang.org/x/mod v0.10.0 // indirect + golang.org/x/net v0.10.0 // indirect + golang.org/x/oauth2 v0.8.0 // indirect + golang.org/x/sync v0.2.0 // indirect + golang.org/x/sys v0.8.0 // indirect + golang.org/x/text v0.9.0 // indirect + golang.org/x/tools v0.9.3 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect - google.golang.org/api v0.104.0 // indirect + google.golang.org/api v0.122.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20221206210731-b1a01be3a5f6 // indirect - google.golang.org/grpc v1.51.0 // indirect - google.golang.org/protobuf v1.28.1 // indirect - gopkg.in/ini.v1 v1.66.4 // indirect + google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect + google.golang.org/grpc v1.55.0 // indirect + google.golang.org/protobuf v1.30.0 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/klog/v2 v2.80.1 // indirect + k8s.io/klog/v2 v2.100.1 // indirect ) diff --git a/hack/tools/go.sum b/hack/tools/go.sum index 359712671..ebbe7a7af 100644 --- a/hack/tools/go.sum +++ b/hack/tools/go.sum @@ -1,3 +1,5 @@ +bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= +bazil.org/fuse v0.0.0-20200407214033-5883e5a4b512/go.mod h1:FbcW6z/2VytnFDhZfumh8Ss8zxHE6qpMP5sHTRe0EaM= bitbucket.org/creachadair/shell v0.0.7 h1:Z96pB6DkSb7F3Y3BBnJeOZH2gazyMTWlvecSD4vDqfk= bitbucket.org/creachadair/shell v0.0.7/go.mod h1:oqtXSSvSYr4624lnnabXHaBsYW6RD80caLi2b3hJk0U= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= @@ -29,116 +31,372 @@ cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aD cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= -cloud.google.com/go v0.107.0 h1:qkj22L7bgkl6vIeZDlOY2po43Mx/TIa2Wsa7VR+PEww= -cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= +cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= +cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= +cloud.google.com/go v0.110.0 h1:Zc8gqp3+a9/Eyph2KDmcGaPtbKRIoqq4YTlL4NMD0Ys= +cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/compute v1.13.0 h1:AYrLkB8NPdDRslNp4Jxmzrhdr03fUAIDbiGFjLWowoU= -cloud.google.com/go/compute v1.13.0/go.mod h1:5aPTS0cUNMIc1CE546K+Th6weJUNQErARyZtRXDJ8GE= -cloud.google.com/go/compute/metadata v0.2.2 h1:aWKAjYaBaOSrpKl57+jnS/3fJRQnxL7TvR/u1VVbt6k= -cloud.google.com/go/compute/metadata v0.2.2/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= +cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= +cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= +cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= +cloud.google.com/go/compute v1.19.0 h1:+9zda3WGgW1ZSTlVppLCYFIr48Pa35q1uG2N1itbCEQ= +cloud.google.com/go/compute v1.19.0/go.mod h1:rikpw2y+UMidAe9tISo04EHNOIf42RLYF/q8Bs93scU= +cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/iam v0.8.0 h1:E2osAkZzxI/+8pZcxVLcDtAQx/u+hZXVryUaYQ5O0Kk= -cloud.google.com/go/longrunning v0.3.0 h1:NjljC+FYPV3uh5/OwWT6pVU+doBqMg2x/rZlE+CamDs= -cloud.google.com/go/monitoring v1.1.0/go.mod h1:L81pzz7HKn14QCMaCs6NTQkdBnE87TElyanS95vIcl4= -cloud.google.com/go/monitoring v1.8.0 h1:c9riaGSPQ4dUKWB+M1Fl0N+iLxstMbCktdEwYSPGDvA= -cloud.google.com/go/monitoring v1.8.0/go.mod h1:E7PtoMJ1kQXWxPjB6mv2fhC5/15jInuulFdYYtlcvT4= +cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/iam v0.13.0 h1:+CmB+K0J/33d0zSQ9SlFWUeCCEn5XJA0ZMZ3pHE9u8k= +cloud.google.com/go/longrunning v0.4.1 h1:v+yFJOfKC3yZdY6ZUI933pIYdhyhV8S3NpWrXWmg7jM= +cloud.google.com/go/monitoring v1.13.0 h1:2qsrgXGVoRXpP7otZ14eE1I568zAa92sJSDPyOJvwjM= +cloud.google.com/go/monitoring v1.13.0/go.mod h1:k2yMBAB1H9JT/QETjNkgdCGD9bPF712XiLTVr+cBrpw= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/spanner v1.42.0 h1:W6RIkN4X0htp+GRNWK1rhXYYcjb5znZDuyIO2CWkoM0= -cloud.google.com/go/spanner v1.42.0/go.mod h1:KEfcH3c7wMqO6bTZqY1/BDS5DZfC1k3U0QZTlnlvW/0= +cloud.google.com/go/spanner v1.45.1 h1:vHFqBMuPdTCwA8b9+IyQbGppQoqx7xJfcSa81d7gtAk= +cloud.google.com/go/spanner v1.45.1/go.mod h1:FIws5LowYz8YAE1J8fOS7DJup8ff7xJeetWEo5REA2M= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= -cloud.google.com/go/trace v1.0.0/go.mod h1:4iErSByzxkyHWzzlAj63/Gmjz0NH1ASqhJguHpGcr6A= -cloud.google.com/go/trace v1.4.0 h1:qO9eLn2esajC9sxpqp1YKX37nXC3L4BfGnPS0Cx9dYo= -cloud.google.com/go/trace v1.4.0/go.mod h1:UG0v8UBqzusp+z63o7FK74SdFE+AXpCLdFb1rshXG+Y= -contrib.go.opencensus.io/exporter/stackdriver v0.13.12 h1:bjBKzIf7/TAkxd7L2utGaLM78bmUWlCval5K9UeElbY= -contrib.go.opencensus.io/exporter/stackdriver v0.13.12/go.mod h1:mmxnWlrvrFdpiOHOhxBaVi1rkc0WOqhgfknj4Yg0SeQ= +cloud.google.com/go/trace v1.9.0 h1:olxC0QHC59zgJVALtgqfD9tGk0lfeCP5/AGXL3Px/no= +cloud.google.com/go/trace v1.9.0/go.mod h1:lOQqpE5IaWY0Ixg7/r2SjixMuc6lfTFeO4QGM4dQWOk= +contrib.go.opencensus.io/exporter/stackdriver v0.13.14 h1:zBakwHardp9Jcb8sQHcHpXy/0+JIb1M8KjigCJzx7+4= +contrib.go.opencensus.io/exporter/stackdriver v0.13.14/go.mod h1:5pSSGY0Bhuk7waTHuDf4aQ8D2DrhgETRo9fy6k3Xlzc= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/AdaLogics/go-fuzz-headers v0.0.0-20220708163326-82d177caec6e h1:Gvv863NmqhY4a/MygkMdO0EQHB/alMtAm3qPMOkljFc= -github.com/AdaLogics/go-fuzz-headers v0.0.0-20220708163326-82d177caec6e/go.mod h1:i9fr2JpcEcY/IHEvzCM3qXUZYOQHgR89dt4es1CgMhc= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20210715213245-6c3934b029d8/go.mod h1:CzsSbkDixRphAF5hS6wbMKq0eI6ccJRb7/A0M6JBnwg= +github.com/AdamKorcz/go-fuzz-headers-1 v0.0.0-20230329111138-12e09aba5ebd h1:1tbEqR4NyQLgiod7vLXSswHteGetAVZrMGCqrJxLKRs= +github.com/AdamKorcz/go-fuzz-headers-1 v0.0.0-20230329111138-12e09aba5ebd/go.mod h1:0vOOKsOMKPThRu9lQMAxcQ8D60f8U+wHXl07SyUw0+U= +github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v63.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-ansiterm v0.0.0-20210608223527-2377c96fe795/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.11.1/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= +github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= +github.com/Azure/go-autorest/autorest v0.11.25/go.mod h1:7l8ybrIdUmGqZMTD0sRtAr8NvbHjfofbf8RSP2q7w7U= +github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= +github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= +github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= +github.com/Azure/go-autorest/autorest/adal v0.9.18/go.mod h1:XVVeme+LZwABT8K5Lc3hA4nAe8LDBVle26gTrguhhPQ= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/mocks v0.4.2/go.mod h1:Vy7OitM9Kei0i1Oj+LvyAWMXJHeKH1MVlzFugfVrmyU= +github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcPR4o9jEImooCeWJcYV/zLE= +github.com/Azure/go-autorest/autorest/validation v0.3.1/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E= +github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= -github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= -github.com/Masterminds/sprig/v3 v3.2.2 h1:17jRggJu518dr3QaafizSXOjKYp94wKfABxUmyxvxX8= -github.com/Masterminds/sprig/v3 v3.2.2/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk= +github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g= +github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= +github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA= +github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= +github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= +github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= +github.com/Microsoft/go-winio v0.4.16-0.20201130162521-d1ffc52c7331/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= +github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= +github.com/Microsoft/go-winio v0.4.17-0.20210211115548-6eac466e5fa3/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.4.17-0.20210324224401-5516f17a5958/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= +github.com/Microsoft/hcsshim v0.8.7-0.20190325164909-8abdbb8205e4/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= +github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ= +github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg38RRsjT5y8= +github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg= +github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00= +github.com/Microsoft/hcsshim v0.8.16/go.mod h1:o5/SZqmR7x9JNKsW3pu+nqHm0MF8vbA+VxGOoXdC600= +github.com/Microsoft/hcsshim v0.8.20/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4= +github.com/Microsoft/hcsshim v0.8.21/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4= +github.com/Microsoft/hcsshim v0.8.23/go.mod h1:4zegtUJth7lAvFyc6cH2gGQ5B3OFQim01nnU2M8jKDg= +github.com/Microsoft/hcsshim v0.9.2/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc= +github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU= +github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= +github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0= +github.com/alexflint/go-filemutex v1.1.0/go.mod h1:7P4iRhttt/nUvUOrYIhcpMzv2G6CY9UnI16Z+UJqRyk= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-metrics v0.3.3/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= -github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ= github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= -github.com/aws/aws-sdk-go v1.37.0 h1:GzFnhOIsrGyQ69s7VgqtrG2BG8v7X7vwB3Xpbd/DBBk= -github.com/aws/aws-sdk-go v1.37.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= +github.com/aws/aws-sdk-go v1.38.35/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.43.11/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= +github.com/aws/aws-sdk-go v1.43.31 h1:yJZIr8nMV1hXjAvvOLUFqZRJcHV7udPQBfhJqawDzI0= +github.com/aws/aws-sdk-go v1.43.31/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= +github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/cenkalti/backoff/v4 v4.1.1 h1:G2HAfAmvm/GcKan2oOQpBXOd2tT2G57ZnZGWa1PxPBQ= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= +github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= +github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= +github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= +github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= +github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= +github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= +github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= +github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= +github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= +github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/cenkalti/backoff/v4 v4.2.0 h1:HN5dHm3WBOgndBH6E8V0q2jIYIR3s9yglV8k/+MN3u4= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/census-instrumentation/opencensus-proto v0.3.0 h1:t/LhUZLVitR1Ow2YOnduCsavhwFUklBMoGVYUCqmCqk= -github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g= +github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= +github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= +github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +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/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw= +github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M= +github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg= +github.com/cilium/ebpf v0.0.0-20200702112145-1c8d4c9ef775/go.mod h1:7cR51M8ViRLIdUjrmSXlK9pkrsDlLHbO8jiB8X8JnOc= +github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= +github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= +github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= +github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4 h1:hzAQntlaYRkVSFEfj9OTWlVV1H155FMD8BTKktLv0QI= github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe h1:QQ3GSy+MqSHxm/d8nCtnAiZdYFd45cYZPs8vOOIYKfk= +github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490 h1:KwaoQzs/WeUxxJqiJsZ4euOly1Az/IgZXXSxlD/UBNk= -github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20230310173818-32f1caf87195 h1:58f1tJ1ra+zFINPlwLWvQsR9CzAKt2e+EWV2yX9oXQ4= +github.com/cncf/xds/go v0.0.0-20230310173818-32f1caf87195/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= -github.com/cockroachdb/cockroach-go/v2 v2.2.19 h1:YIHyz17jZumBeXPuoZKq/0nrITsqDoDD8/KQt3/xiyc= -github.com/cockroachdb/cockroach-go/v2 v2.2.19/go.mod h1:mzlIDDBALQfEjv/7DU12fb2AfQ/MUYTlychcMpWp9QI= +github.com/cockroachdb/cockroach-go/v2 v2.3.3 h1:fNmtG6XhoA1DhdDCIu66YyGSsNb1szj4CaAsbDxRmy4= +github.com/cockroachdb/cockroach-go/v2 v2.3.3/go.mod h1:1wNJ45eSXW9AnOc3skntW9ZUZz6gxrQK3cOj3rK+BC8= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo= +github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA= +github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= +github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE= +github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU= +github.com/containerd/aufs v0.0.0-20210316121734-20793ff83c97/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU= +github.com/containerd/aufs v1.0.0/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU= +github.com/containerd/btrfs v0.0.0-20201111183144-404b9149801e/go.mod h1:jg2QkJcsabfHugurUvvPhS3E08Oxiuh5W/g1ybB4e0E= +github.com/containerd/btrfs v0.0.0-20210316141732-918d888fb676/go.mod h1:zMcX3qkXTAi9GI50+0HOeuV8LU2ryCE/V2vG/ZBiTss= +github.com/containerd/btrfs v1.0.0/go.mod h1:zMcX3qkXTAi9GI50+0HOeuV8LU2ryCE/V2vG/ZBiTss= +github.com/containerd/cgroups v0.0.0-20190717030353-c4b9ac5c7601/go.mod h1:X9rLEHIqSf/wfK8NsPqxJmeZgW4pcfzdXITDrUSJ6uI= +github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko= +github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1pT8KYB3TCXK/ocprsh7MAkoW8bZVzPdih9snmM= +github.com/containerd/cgroups v0.0.0-20200710171044-318312a37340/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo= +github.com/containerd/cgroups v0.0.0-20200824123100-0b889c03f102/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo= +github.com/containerd/cgroups v0.0.0-20210114181951-8a68de567b68/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= +github.com/containerd/cgroups v1.0.1/go.mod h1:0SJrPIenamHDcZhEcJMNBB85rHcUsw4f25ZfBiPYRkU= +github.com/containerd/cgroups v1.0.3/go.mod h1:/ofk34relqNjSGyqPrmEULrO4Sc8LJhvJmWbUCUKqj8= +github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= +github.com/containerd/console v0.0.0-20181022165439-0650fd9eeb50/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= +github.com/containerd/console v0.0.0-20191206165004-02ecf6a7291e/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE= +github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw= +github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ= +github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= +github.com/containerd/containerd v1.2.10/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.1-0.20191213020239-082f7e3aed57/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.4.0-beta.2.0.20200729163537-40b22ef07410/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.4.1/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.4.3/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.4.9/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.5.0-beta.1/go.mod h1:5HfvG1V2FsKesEGQ17k5/T7V960Tmcumvqn8Mc+pCYQ= +github.com/containerd/containerd v1.5.0-beta.3/go.mod h1:/wr9AVtEM7x9c+n0+stptlo/uBBoBORwEx6ardVcmKU= +github.com/containerd/containerd v1.5.0-beta.4/go.mod h1:GmdgZd2zA2GYIBZ0w09ZvgqEq8EfBp/m3lcVZIvPHhI= +github.com/containerd/containerd v1.5.0-rc.0/go.mod h1:V/IXoMqNGgBlabz3tHD2TWDoTJseu1FGOKuoA4nNb2s= +github.com/containerd/containerd v1.5.1/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTVn7dJnIOwtYR4g= +github.com/containerd/containerd v1.5.7/go.mod h1:gyvv6+ugqY25TiXxcZC3L5yOeYgEw0QMhscqVp1AR9c= +github.com/containerd/containerd v1.5.8/go.mod h1:YdFSv5bTFLpG2HIYmfqDpSYYTDX+mc5qtSuYx1YUb/s= +github.com/containerd/containerd v1.6.1/go.mod h1:1nJz5xCZPusx6jJU8Frfct988y0NpumIq9ODB0kLtoE= +github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20200710164510-efbc4488d8fe/go.mod h1:cECdGN1O8G9bgKTlLhuPJimka6Xb/Gg7vYzCTNVxhvo= +github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7/go.mod h1:kR3BEg7bDFaEddKm54WSmrol1fKWDU1nKYkgrcgZT7Y= +github.com/containerd/continuity v0.0.0-20210208174643-50096c924a4e/go.mod h1:EXlVlkqNba9rJe3j7w3Xa924itAMLgZH4UD/Q4PExuQ= +github.com/containerd/continuity v0.1.0/go.mod h1:ICJu0PwR54nI0yPEnJ6jcS+J7CZAUXrLh8lPo2knzsM= +github.com/containerd/continuity v0.2.2/go.mod h1:pWygW9u7LtS1o4N/Tn0FoCFDIXZ7rxcMX7HX1Dmibvk= +github.com/containerd/fifo v0.0.0-20180307165137-3d5202aec260/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= +github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= +github.com/containerd/fifo v0.0.0-20200410184934-f15a3290365b/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0= +github.com/containerd/fifo v0.0.0-20201026212402-0724c46b320c/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0= +github.com/containerd/fifo v0.0.0-20210316144830-115abcc95a1d/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4= +github.com/containerd/fifo v1.0.0/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4= +github.com/containerd/go-cni v1.0.1/go.mod h1:+vUpYxKvAF72G9i1WoDOiPGRtQpqsNW/ZHtSlv++smU= +github.com/containerd/go-cni v1.0.2/go.mod h1:nrNABBHzu0ZwCug9Ije8hL2xBCYh/pjfMb1aZGrrohk= +github.com/containerd/go-cni v1.1.0/go.mod h1:Rflh2EJ/++BA2/vY5ao3K6WJRR/bZKsX123aPk+kUtA= +github.com/containerd/go-cni v1.1.3/go.mod h1:Rflh2EJ/++BA2/vY5ao3K6WJRR/bZKsX123aPk+kUtA= +github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= +github.com/containerd/go-runc v0.0.0-20190911050354-e029b79d8cda/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= +github.com/containerd/go-runc v0.0.0-20200220073739-7016d3ce2328/go.mod h1:PpyHrqVs8FTi9vpyHwPwiNEGaACDxT/N/pLcvMSRA9g= +github.com/containerd/go-runc v0.0.0-20201020171139-16b287bc67d0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok= +github.com/containerd/go-runc v1.0.0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok= +github.com/containerd/imgcrypt v1.0.1/go.mod h1:mdd8cEPW7TPgNG4FpuP3sGBiQ7Yi/zak9TYCG3juvb0= +github.com/containerd/imgcrypt v1.0.4-0.20210301171431-0ae5c75f59ba/go.mod h1:6TNsg0ctmizkrOgXRNQjAPFWpMYRWuiB6dSF4Pfa5SA= +github.com/containerd/imgcrypt v1.1.1-0.20210312161619-7ed62a527887/go.mod h1:5AZJNI6sLHJljKuI9IHnw1pWqo/F0nGDOuR9zgTs7ow= +github.com/containerd/imgcrypt v1.1.1/go.mod h1:xpLnwiQmEUJPvQoAapeb2SNCxz7Xr6PJrXQb0Dpc4ms= +github.com/containerd/imgcrypt v1.1.3/go.mod h1:/TPA1GIDXMzbj01yd8pIbQiLdQxed5ue1wb8bP7PQu4= +github.com/containerd/nri v0.0.0-20201007170849-eb1350a75164/go.mod h1:+2wGSDGFYfE5+So4M5syatU0N0f0LbWpuqyMi4/BE8c= +github.com/containerd/nri v0.0.0-20210316161719-dbaa18c31c14/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY= +github.com/containerd/nri v0.1.0/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY= +github.com/containerd/stargz-snapshotter/estargz v0.4.1/go.mod h1:x7Q9dg9QYb4+ELgxmo4gBUeJB0tl5dqH1Sdz0nJU1QM= +github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= +github.com/containerd/ttrpc v0.0.0-20190828172938-92c8520ef9f8/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= +github.com/containerd/ttrpc v0.0.0-20191028202541-4f1b8fe65a5c/go.mod h1:LPm1u0xBw8r8NOKoOdNMeVHSawSsltak+Ihv+etqsE8= +github.com/containerd/ttrpc v1.0.1/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= +github.com/containerd/ttrpc v1.0.2/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= +github.com/containerd/ttrpc v1.1.0/go.mod h1:XX4ZTnoOId4HklF4edwc4DcqskFZuvXB1Evzy5KFQpQ= +github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= +github.com/containerd/typeurl v0.0.0-20190911142611-5eb25027c9fd/go.mod h1:GeKYzf2pQcqv7tJ0AoCuuhtnqhva5LNU3U+OyKxxJpk= +github.com/containerd/typeurl v1.0.1/go.mod h1:TB1hUtrpaiO88KEK56ijojHS1+NeF0izUACaJW2mdXg= +github.com/containerd/typeurl v1.0.2/go.mod h1:9trJWW2sRlGub4wZJRTW83VtbOLS6hwcDZXTn6oPz9s= +github.com/containerd/zfs v0.0.0-20200918131355-0a33824f23a2/go.mod h1:8IgZOBdv8fAgXddBT4dBXJPtxyRsejFIpXoklgxgEjw= +github.com/containerd/zfs v0.0.0-20210301145711-11e8f1707f62/go.mod h1:A9zfAbMlQwE+/is6hi0Xw8ktpL+6glmqZYtevJgaB8Y= +github.com/containerd/zfs v0.0.0-20210315114300-dde8f0fda960/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY= +github.com/containerd/zfs v0.0.0-20210324211415-d5c4544f0433/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY= +github.com/containerd/zfs v1.0.0/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY= +github.com/containernetworking/cni v0.7.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= +github.com/containernetworking/cni v0.8.0/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= +github.com/containernetworking/cni v0.8.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY= +github.com/containernetworking/cni v1.0.1/go.mod h1:AKuhXbN5EzmD4yTNtfSsX3tPcmtrBI6QcRV0NiNt15Y= +github.com/containernetworking/plugins v0.8.6/go.mod h1:qnw5mN19D8fIwkqW7oHHYDHVlzhJpcY6TQxn/fUyDDM= +github.com/containernetworking/plugins v0.9.1/go.mod h1:xP/idU2ldlzN6m4p5LmGiwRDjeJr6FLK6vuiUwoH7P8= +github.com/containernetworking/plugins v1.0.1/go.mod h1:QHCfGpaTwYTbbH+nZXKVTxNBDZcxSOplJT5ico8/FLE= +github.com/containers/ocicrypt v1.0.1/go.mod h1:MeJDzk1RJHv89LjsH0Sp5KTY3ZYkjXO/C+bKAeWFIrc= +github.com/containers/ocicrypt v1.1.0/go.mod h1:b8AOe0YR67uU8OqfVNcznfFpAzu3rdgUV4GP9qXPfu4= +github.com/containers/ocicrypt v1.1.1/go.mod h1:Dm55fwWm1YZAjYRaJ94z2mfZikIyIN4B0oB3dj3jFxY= +github.com/containers/ocicrypt v1.1.2/go.mod h1:Dm55fwWm1YZAjYRaJ94z2mfZikIyIN4B0oB3dj3jFxY= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-iptables v0.4.5/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU= +github.com/coreos/go-iptables v0.5.0/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU= +github.com/coreos/go-iptables v0.6.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= +github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20161114122254-48702e0da86b/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/cyphar/filepath-securejoin v0.2.3 h1:YX6ebbZCZP7VkM3scTTokDgBL2TY741X51MTk3ycuNI= +github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= +github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= +github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= +github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ= +github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s= +github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5/go.mod h1:Eo87+Kg/IX2hfWJfwxMzLyuSZyxSoAug2nGa1G2QAi8= +github.com/d2g/hardwareaddr v0.0.0-20190221164911-e7d9fbe030e4/go.mod h1:bMl4RjIciD2oAxI7DmWRx6gbeqrkoLqv3MV0vzNad+I= 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/dennwc/varint v1.0.0/go.mod h1:hnItb35rvZvJrbTALZtY/iQfDs48JKRG1RPpgziApxA= +github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= +github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/dgryski/go-sip13 v0.0.0-20200911182023-62edffca9245/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/digitalocean/godo v1.78.0/go.mod h1:GBmu8MkjZmNARE7IXRPmkbbnocNN8+uBm0xbEVw2LCs= +github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= +github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= +github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/distribution v0.0.0-20190905152932-14b96e55d84c/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY= +github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v20.10.14+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-events v0.0.0-20170721190031-9461782956ad/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= +github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= +github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI= +github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= +github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/edsrzf/mmap-go v1.1.0/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8EIth78Q= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -147,21 +405,43 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= -github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1 h1:xvqufLtNVwAhN8NMyWklVgxnWohi+wtMGQMhtxexlm0= -github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= +github.com/envoyproxy/go-control-plane v0.10.1/go.mod h1:AY7fTTXNdv/aJ2O5jwpxAPOWUZ7hQAEvzN5Pf27BkQQ= +github.com/envoyproxy/go-control-plane v0.11.0 h1:jtLewhRR2vMRNnq2ZZUoCjUlgut+Y0+sDDWPOfwOi1o= +github.com/envoyproxy/go-control-plane v0.11.0/go.mod h1:VnHyVMpzcLvCFt9yUz1UnCwHLhwx1WguiVDV7pTG/tI= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/envoyproxy/protoc-gen-validate v0.6.2 h1:JiO+kJTpmYGjEodY7O1Zk8oZcNz1+f30UtwtXoFUPzE= -github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws= +github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo= +github.com/envoyproxy/protoc-gen-validate v0.10.0 h1:oIfnZFdC0YhpNNEX+SuIqko4cqqVZeN9IGTrhZje83Y= +github.com/envoyproxy/protoc-gen-validate v0.10.0/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= +github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/felixge/httpsnoop v1.0.2/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= -github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= -github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= +github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= +github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= +github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA= +github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= +github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= +github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= +github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= @@ -170,54 +450,85 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= -github.com/go-logr/logr v1.2.0 h1:QK40JKJyMdUDz+h+xvCsru/bJhvG0UxvePV0ufL/AcE= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.1/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/stdr v1.2.0/go.mod h1:YkVgnZu1ZjjL7xTxrfm/LLZBfkhTqSR1ydtm6jTKKwI= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-openapi/analysis v0.21.2/go.mod h1:HZwRk4RRisyG8vx2Oe6aqeSQcoxRp47Xkp3+K6q+LdY= github.com/go-openapi/analysis v0.21.4 h1:ZDFLvSNxpDaomuCueM0BlSXxpANBlFYiBvr+GXrvIHc= github.com/go-openapi/analysis v0.21.4/go.mod h1:4zQ35W4neeZTqh3ol0rv/O8JBbka9QyAgQRPp9y3pfo= github.com/go-openapi/errors v0.19.8/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= github.com/go-openapi/errors v0.19.9/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= github.com/go-openapi/errors v0.20.2/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= -github.com/go-openapi/errors v0.20.3 h1:rz6kiC84sqNQoqrtulzaL/VERgkoCyB6WdEkc2ujzUc= -github.com/go-openapi/errors v0.20.3/go.mod h1:Z3FlZ4I8jEGxjUK+bugx3on2mIAk4txuAOhlsB1FSgk= +github.com/go-openapi/errors v0.20.4 h1:unTcVm6PispJsMECE3zWgvG4xTiKda1LIR5rCRWLG6M= +github.com/go-openapi/errors v0.20.4/go.mod h1:Z3FlZ4I8jEGxjUK+bugx3on2mIAk4txuAOhlsB1FSgk= github.com/go-openapi/inflect v0.19.0 h1:9jCH9scKIbHeV9m12SmPilScz6krDxKRasNNSNPXu/4= github.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4= +github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= +github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= -github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA= github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= +github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= +github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= github.com/go-openapi/loads v0.21.1/go.mod h1:/DtAMXXneXFjbQMGEtbamCZb+4x7eGwkvZCvBmwUG+g= github.com/go-openapi/loads v0.21.2 h1:r2a/xFIYeZ4Qd2TnGpWDIQNcP80dIaZgf704za8enro= github.com/go-openapi/loads v0.21.2/go.mod h1:Jq58Os6SSGz0rzh62ptiu8Z31I+OTHqmULx5e/gJbNw= -github.com/go-openapi/runtime v0.24.1 h1:Sml5cgQKGYQHF+M7yYSHaH1eOjvTykrddTE/KtQVjqo= -github.com/go-openapi/runtime v0.24.1/go.mod h1:AKurw9fNre+h3ELZfk6ILsfvPN+bvvlaU/M9q/r9hpk= +github.com/go-openapi/runtime v0.23.1/go.mod h1:AKurw9fNre+h3ELZfk6ILsfvPN+bvvlaU/M9q/r9hpk= +github.com/go-openapi/runtime v0.26.0 h1:HYOFtG00FM1UvqrcxbEJg/SwvDRvYLQKGhw2zaQjTcc= +github.com/go-openapi/runtime v0.26.0/go.mod h1:QgRGeZwrUcSHdeh4Ka9Glvo0ug1LC5WyE+EV88plZrQ= +github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= +github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I= github.com/go-openapi/spec v0.20.6/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= -github.com/go-openapi/spec v0.20.7 h1:1Rlu/ZrOCCob0n+JKKJAWhNWMPW8bOZRg8FJaY+0SKI= -github.com/go-openapi/spec v0.20.7/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= +github.com/go-openapi/spec v0.20.9 h1:xnlYNQAwKd2VQRRfwTEI0DcK+2cbuvI/0c7jx3gA8/8= +github.com/go-openapi/spec v0.20.9/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= github.com/go-openapi/strfmt v0.21.0/go.mod h1:ZRQ409bWMj+SOgXofQAGTIo2Ebu72Gs+WaRADcS5iNg= github.com/go-openapi/strfmt v0.21.1/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrCX/rPGuWb0k= github.com/go-openapi/strfmt v0.21.2/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrCX/rPGuWb0k= -github.com/go-openapi/strfmt v0.21.3 h1:xwhj5X6CjXEZZHMWy1zKJxvW9AfHC9pkyUjLvHtKG7o= github.com/go-openapi/strfmt v0.21.3/go.mod h1:k+RzNO0Da+k3FrrynSNN8F7n/peCmQQqbbXjtDfvmGg= +github.com/go-openapi/strfmt v0.21.7 h1:rspiXgNWgeUzhjo1YU01do6qsahtJNByjLVbPLNHb8k= +github.com/go-openapi/strfmt v0.21.7/go.mod h1:adeGTkxE44sPyLk0JV235VQAO/ZXUr8KAzYjclFs3ew= +github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU= +github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-openapi/validate v0.21.0/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg= -github.com/go-openapi/validate v0.22.0 h1:b0QecH6VslW/TxtpKgzpO1SNG7GU2FsaqKdP1E2T50Y= -github.com/go-openapi/validate v0.22.0/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg= -github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= -github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc= -github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= +github.com/go-openapi/validate v0.22.1 h1:G+c2ub6q47kfX1sOBLwIQwzBVt8qmOAARyo/9Fqs9NU= +github.com/go-openapi/validate v0.22.1/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= +github.com/go-resty/resty/v2 v2.1.1-0.20191201195748-d7b97669fe48/go.mod h1:dZGr0i9PLlaaTD4H/hoZIDjQ+r6xq8mgbRzHZf7f2J8= +github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= +github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= -github.com/go-swagger/go-swagger v0.30.3 h1:HuzvdMRed/9Q8vmzVcfNBQByZVtT79DNZxZ18OprdoI= -github.com/go-swagger/go-swagger v0.30.3/go.mod h1:neDPes8r8PCz2JPvHRDj8BTULLh4VJUt7n6MpQqxhHM= +github.com/go-swagger/go-swagger v0.30.5 h1:SQ2+xSonWjjoEMOV5tcOnZJVlfyUfCBhGQGArS1b9+U= +github.com/go-swagger/go-swagger v0.30.5/go.mod h1:cWUhSyCNqV7J1wkkxfr5QmbcnCewetCdvEXqgPvbc/Q= github.com/go-swagger/scan-repo-boundary v0.0.0-20180623220736-973b3573c013 h1:l9rI6sNaZgNC0LnF3MiE+qTmyBA/tZAg1rtyrGbUMK0= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/go-zookeeper/zk v1.0.2/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw= github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY= github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg= @@ -242,17 +553,34 @@ github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWe github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ= github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0= github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= +github.com/goccy/go-yaml v1.9.5/go.mod h1:U/jl18uSupI5rdI2jmuCswEA2htH9eXfferR3KfscvA= +github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= +github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= +github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= +github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= -github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= -github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gofrs/uuid v4.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZgBrnJfGa0= +github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU= +github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= +github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= +github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-jwt/jwt/v4 v4.4.2 h1:rcc4lwaZgFMCZ5jxF9ABolDcIHdBytAFgqFPbSJQAYs= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -284,12 +612,15 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +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/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -303,9 +634,14 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-containerregistry v0.5.1/go.mod h1:Ct15B4yir3PLOP5jsy0GNeYVaIZs/MK/Jz5any1wFW0= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -325,45 +661,116 @@ github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20220318212150-b2ab0324ddda/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/trillian v1.5.1 h1:2p1l13f0eWd7eOShwarwIxutYYnGzY/5S+xYewQIPkU= -github.com/google/trillian v1.5.1/go.mod h1:EcDttN8nf+EoAiyLigBAp9ebncZI6rhJPyxZ+dQ6HSo= +github.com/google/s2a-go v0.1.3 h1:FAgZmpLl/SXurPEZyCMPBIiiYeTbqfjlbdnCNTAkbGE= +github.com/google/s2a-go v0.1.3/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= +github.com/google/trillian v1.5.2 h1:roGP6G8aaAch7vP08+oitPkvmZzxjTfIkguozqJ04Ok= +github.com/google/trillian v1.5.2/go.mod h1:H8vOoa2dxd3xCdMzOOwt9kIz/3MSoJhcqLJGG8iRwbg= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.2.0 h1:y8Yozv7SZtlU//QXbezB6QkpuE6jMD2/gfzk4AftXjs= -github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= +github.com/googleapis/enterprise-certificate-proxy v0.2.3 h1:yk9/cqRKtT9wXZSsRH9aurXEpJX+U6FLtpYTdC3R06k= +github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= -github.com/googleapis/gax-go/v2 v2.7.0 h1:IcsPKeInNvYi7eqSaDjiZqDDKu5rsmunY0Y1YupQSSQ= -github.com/googleapis/gax-go/v2 v2.7.0/go.mod h1:TEop28CZZQ2y+c0VxMUmu1lV+fQx57QpBWsYpwqHJx8= +github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= +github.com/googleapis/gax-go/v2 v2.8.0 h1:UBtEZqx1bjXtOQ5BVTkuYghXrr3N4V123VKJK67vJZc= +github.com/googleapis/gax-go/v2 v2.8.0/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= +github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= +github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/gophercloud/gophercloud v0.24.0/go.mod h1:Q8fZtyi5zZxPS/j9aj3sSxtvj41AdQMDwyo1myduD5c= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= +github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= -github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grafana/regexp v0.0.0-20220304095617-2e8d9baf4ac2/go.mod h1:M5qHK+eWfAv8VR/265dIuEpL3fNfeC21tXXp9itM24A= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= +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.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3 h1:lLT7ZLSzGLI08vc9cpd+tYmNWjdKDqyr/2L+f6U12Fk= +github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/api v1.12.0/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= +github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= +github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v0.12.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.2.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw= -github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= +github.com/hashicorp/memberlist v0.3.1/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= +github.com/hetznercloud/hcloud-go v1.33.1/go.mod h1:XX/TQub3ge0yWR2yHWmnDVIrB+MQbda1pHxkUmDlUME= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4= +github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= +github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/intel/goresctrl v0.2.0/go.mod h1:+CZdzouYFn5EsxgqAQTEzMfwKwuc0fVdMrT9FCCAVRQ= +github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA= +github.com/j-keck/arping v1.0.2/go.mod h1:aJbELhR92bSk7tp79AWM/ftfc90EfEi2bQJrbBFOsPw= github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= @@ -374,7 +781,6 @@ github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsU github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= -github.com/jackc/pgconn v1.12.0/go.mod h1:ZkhRC59Llhrq3oSfrikvwQ5NaxYExr6twkdkMLaKono= github.com/jackc/pgconn v1.12.1 h1:rsDFzIpRk7xT4B8FufgpCCeyjdNpKyghZeSefViE5W8= github.com/jackc/pgconn v1.12.1/go.mod h1:ZkhRC59Llhrq3oSfrikvwQ5NaxYExr6twkdkMLaKono= github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= @@ -406,7 +812,6 @@ github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08 github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= -github.com/jackc/pgx/v4 v4.16.0/go.mod h1:N0A9sFdWzkw/Jy1lwoiB64F2+ugFZi987zRxcPez/wI= github.com/jackc/pgx/v4 v4.16.1 h1:JzTglcal01DrghUqt+PmzWsZx/Yh7SC/CTQmSBMTd0Y= github.com/jackc/pgx/v4 v4.16.1/go.mod h1:SIhx0D5hoADaiXZVyv+3gSm3LCIIINTVO0PficsvWGQ= github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= @@ -416,82 +821,147 @@ github.com/jackc/puddle v1.2.1 h1:gI8os0wpRXFd4FiAY2dWiqRK037tjj3t7rKFeO4X5iw= github.com/jackc/puddle v1.2.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc= github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= -github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= -github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= -github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= +github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= github.com/jonboulle/clockwork v0.3.0 h1:9BSCMi8C+0qdApAp4auwX0RkLGUjs956h0EkuQymUhg= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= 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.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/kolo/xmlrpc v0.0.0-20201022064351-38db28db192b/go.mod h1:pcaDhQK0/NJZEvtCO0qQPPropqV0sJOJ6YW7X+9kRwM= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= -github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 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/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= -github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w= -github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= -github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/linode/linodego v1.4.0/go.mod h1:PVsRxSlOiJyvG4/scTszpmZDTdgS+to3X6eS8pRrWI8= +github.com/linuxkit/virtsock v0.0.0-20201010232012-f8cee7dfc7a3/go.mod h1:3r6x7q95whyfWQpmGZTu3gk3v2YkMi05HEzl7Tf7YEo= +github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= +github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= -github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= +github.com/mattn/go-shellwords v1.0.6/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= +github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= +github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= +github.com/miekg/dns v1.1.48/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= +github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= +github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.4.3/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/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= +github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= +github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= +github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= +github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= +github.com/moby/sys/signal v0.6.0/go.mod h1:GQ6ObYZfqacOwTtlXvcmh9A26dVRul/hbOZn88Kg8Tg= +github.com/moby/sys/symlink v0.1.0/go.mod h1:GGDODQmbFOjFsXvfLVn3+ZRxkch54RkSiGqsZeMYowQ= +github.com/moby/sys/symlink v0.2.0/go.mod h1:7uZVF2dqJjG/NsClqul95CqKOBRQyYSNnJ6BMgR/gFs= +github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo= +github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A= +github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -499,20 +969,85 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/onsi/ginkgo v0.0.0-20151202141238-7f8ab55aaf3b/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= +github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0= +github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0-rc1.0.20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/image-spec v1.0.2-0.20211117181255-693428a734f5/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.0-rc8.0.20190926000215-3e425f80a8c9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v1.0.0-rc93/go.mod h1:3NOsor4w32B2tC0Zbl8Knk4Wg84SM2ImC1fxBuqJ/H0= +github.com/opencontainers/runc v1.0.2/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0= +github.com/opencontainers/runc v1.1.0/go.mod h1:Tj1hFw6eFWp/o33uxGf5yF2BX5yz2Z6iptFpuvbbKqc= +github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.2-0.20190207185410-29686dbc5559/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs= +github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE= +github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo= +github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8= +github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= -github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= -github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/pelletier/go-toml/v2 v2.0.1 h1:8e3L2cCQzLFi2CR4g7vGFuFxX7Jl1kKX8gW+iV0GUKU= -github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= +github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= +github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= +github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -520,79 +1055,146 @@ github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZ github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= +github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= +github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= +github.com/prometheus/alertmanager v0.24.0/go.mod h1:r6fy/D7FRuZh5YbnX6J3MBY0eI4Pb5yPYS7/bPSXXqI= +github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= -github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= +github.com/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI= +github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk= +github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= 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.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= -github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= +github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= +github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.29.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= +github.com/prometheus/common v0.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= -github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= +github.com/prometheus/common v0.34.0/go.mod h1:gB3sOl7P0TvJabZpLY5uQMpUqRCPPCyRLCZYc7JZTNE= +github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= +github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= +github.com/prometheus/common/assets v0.1.0/go.mod h1:D17UVUE12bHbim7HzwUvtqm6gwBEaDQ0F+hIGbFbccI= +github.com/prometheus/common/sigv4 v0.1.0/go.mod h1:2Jkxxk9yYvCkE5G1sQT7GuEXm57JrvHu9k5YwTjsNtI= +github.com/prometheus/exporter-toolkit v0.7.1/go.mod h1:ZUBIj498ePooX9t/2xtDjeQYwvRpiPP2lh5u4iblj2g= +github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= -github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= -github.com/prometheus/prometheus v2.5.0+incompatible h1:7QPitgO2kOFG8ecuRn9O/4L9+10He72rVRJvMXrE9Hg= -github.com/prometheus/prometheus v2.5.0+incompatible/go.mod h1:oAIUtOny2rjMX0OWN5vPR5/q/twIROJvdqnQKDdil/s= +github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= +github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= +github.com/prometheus/prometheus v0.35.0 h1:N93oX6BrJ2iP3UuE2Uz4Lt+5BkUpaFer3L9CbADzesc= +github.com/prometheus/prometheus v0.35.0/go.mod h1:7HaLx5kEPKJ0GDgbODG0fZgXbQ8K/XjZNJXQmbmgQlY= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4= +github.com/safchain/ethtool v0.0.0-20210803160452-9aa261dae9b1/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/scaleway/scaleway-sdk-go v1.0.0-beta.9/go.mod h1:fCa7OJZ/9DRTnOKmxvT6pn+LPWUptQAmHF/SBJUGEcg= +github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= +github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= +github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= +github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= +github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= +github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= -github.com/spf13/afero v1.8.2 h1:xehSyVa0YnHWsJ49JFljMpg1HX19V6NDZ1fkm1Xznbo= -github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= +github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= +github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= -github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= +github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= +github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= +github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.12.0 h1:CZ7eSOd3kZoaYDLbXnmzgQI5RlciuXBMA+18HwHRfZQ= -github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI= +github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= +github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/spf13/viper v1.16.0 h1:rGGH0XDZhdUOryiDWjmIvUSWpbNqisK8Wk0Vyefw8hc= +github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1FofRzQg= +github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980/go.mod h1:AO3tvPzVZ/ayst6UlUKUv6rcPQInYe3IknH3jYhAKu8= +github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= +github.com/stretchr/objx v0.0.0-20180129172003-8a3f7159479f/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -601,49 +1203,100 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/subosito/gotenv v1.3.0 h1:mjC+YW8QpAdXibNi+vNWgzmgBH4+5l5dCXv8cNysBLI= -github.com/subosito/gotenv v1.3.0/go.mod h1:YzJjq/33h7nrwdY+iHMhEOEEbW0ovIz0tB6t6PwAXzs= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= +github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= +github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I= github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 h1:uruHq4dN7GR16kFc5fp3d1RIYzJW5onx8Ybykw2YQFA= +github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/toqueteos/webbrowser v1.2.0 h1:tVP/gpK69Fx+qMJKsLE7TD8LuGWPnEV71wBN9rrstGQ= github.com/toqueteos/webbrowser v1.2.0/go.mod h1:XWoZq4cyp9WeUeak7w7LXRUQf1F1ATJMir8RTqb4ayM= -github.com/transparency-dev/merkle v0.0.1 h1:T9/9gYB8uZl7VOJIhdwjALeRWlxUxSfDEysjfmx+L9E= -github.com/transparency-dev/merkle v0.0.1/go.mod h1:B8FIw5LTq6DaULoHsVFRzYIUDkl8yuSwCdZnOZGKL/A= +github.com/transparency-dev/merkle v0.0.2 h1:Q9nBoQcZcgPamMkGn7ghV8XiTZ/kRxn1yCG81+twTK4= +github.com/transparency-dev/merkle v0.0.2/go.mod h1:pqSy+OXefQ1EDUVmAJ8MUhHB9TXGuzVAT58PqBoHz1A= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c/go.mod h1:hzIxponao9Kjc7aWznkXaL4U4TWaDSs8zcsY4Ka08nM= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= +github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= +github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= +github.com/vishvananda/netlink v1.1.1-0.20210330154013-f5de75959ad5/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= +github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI= +github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= +github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= +github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/wadey/gocovmerge v0.0.0-20160331181800-b5bfa59ec0ad h1:W0LEBv82YCGEtcmPA3uNZBI33/qF//HAAs3MawDjRa0= github.com/wadey/gocovmerge v0.0.0-20160331181800-b5bfa59ec0ad/go.mod h1:Hy8o65+MXnS6EwGElrSRjUzQDLXreJlzYLlWiHtt8hM= +github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= +github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xlab/treeprint v1.1.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= +github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= +github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= -go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= -go.etcd.io/etcd/api/v3 v3.5.6 h1:Cy2qx3npLcYqTKqGJzMypnMv2tiRyifZJ17BlWIWA7A= -go.etcd.io/etcd/api/v3 v3.5.6/go.mod h1:KFtNaxGDw4Yx/BA4iPPwevUTAuqcsPxzyX8PHydchN8= -go.etcd.io/etcd/client/pkg/v3 v3.5.6 h1:TXQWYceBKqLp4sa87rcPs11SXxUA/mHwH975v+BDvLU= -go.etcd.io/etcd/client/pkg/v3 v3.5.6/go.mod h1:ggrwbk069qxpKPq8/FKkQ3Xq9y39kbFR4LnKszpRXeQ= -go.etcd.io/etcd/client/v2 v2.305.6 h1:fIDR0p4KMjw01MJMfUIDWdQbjo06PD6CeYM5z4EHLi0= -go.etcd.io/etcd/client/v3 v3.5.6 h1:coLs69PWCXE9G4FKquzNaSHrRyMCAXwF+IX1tAPVO8E= -go.etcd.io/etcd/client/v3 v3.5.6/go.mod h1:f6GRinRMCsFVv9Ht42EyY7nfsVGwrNO0WEoS2pRKzQk= -go.etcd.io/etcd/pkg/v3 v3.5.6 h1:k1GZrGrfMHy5/cg2bxNGsmLTFisatyhDYCFLRuaavWg= -go.etcd.io/etcd/raft/v3 v3.5.6 h1:tOmx6Ym6rn2GpZOrvTGJZciJHek6RnC3U/zNInzIN50= -go.etcd.io/etcd/server/v3 v3.5.6 h1:RXuwaB8AMiV62TqcqIt4O4bG8NWjsxOkDJVT3MZI5Ds= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= +go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= +go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= +go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489 h1:1JFLBqwIgdyHN1ZtgjTBwO+blA6gVOmZurpiMEsETKo= +go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg= +go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/api/v3 v3.5.9 h1:4wSsluwyTbGGmyjJktOf3wFQoTBIURXHnq9n/G/JQHs= +go.etcd.io/etcd/api/v3 v3.5.9/go.mod h1:uyAal843mC8uUVSLWz6eHa/d971iDGnCRpmKd2Z+X8k= +go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/pkg/v3 v3.5.9 h1:oidDC4+YEuSIQbsR94rY9gur91UPL6DnxDCIYd2IGsE= +go.etcd.io/etcd/client/pkg/v3 v3.5.9/go.mod h1:y+CzeSmkMpWN2Jyu1npecjB9BBnABxGM4pN8cGuJeL4= +go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= +go.etcd.io/etcd/client/v2 v2.305.8 h1:IGp9Ozt8awy3qRTXSIYJd/o/cr4oUyrm9MF1RJ2dr/c= +go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0= +go.etcd.io/etcd/client/v3 v3.5.9 h1:r5xghnU7CwbUxD/fbUtRyJGaYNfDun8sp/gTr1hew6E= +go.etcd.io/etcd/client/v3 v3.5.9/go.mod h1:i/Eo5LrZ5IKqpbtpPDuaUnDOUv471oDg8cjQaUr2MbA= +go.etcd.io/etcd/pkg/v3 v3.5.0/go.mod h1:UzJGatBQ1lXChBkQF0AuAtkRQMYnHubxAEYIrC3MSsE= +go.etcd.io/etcd/pkg/v3 v3.5.8 h1:hz6w5Cb4p7dbt642m8Y35Ts9yWPWUCymc3v4Z/aiGEU= +go.etcd.io/etcd/raft/v3 v3.5.0/go.mod h1:UFOHSIvO/nKwd4lhkwabrTD3cqW5yVyYYf/KlD00Szc= +go.etcd.io/etcd/raft/v3 v3.5.8 h1:wM4IAfiY1+vrCAkUicIOzkyjpV9MawnAul2KvxeMgy4= +go.etcd.io/etcd/server/v3 v3.5.0/go.mod h1:3Ah5ruV+M+7RZr0+Y/5mNLwC+eQlni+mQmOVdCRJoS4= +go.etcd.io/etcd/server/v3 v3.5.8 h1:eK9fU6Pd6IJD1k0u4zAq1NZsSsEOOimlP3kIkpcQrho= go.mongodb.org/mongo-driver v1.7.3/go.mod h1:NqaYOwnXWr5Pm7AOpO5QFxKJ503nbMse/R79oO62zWg= go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng= go.mongodb.org/mongo-driver v1.8.3/go.mod h1:0sQWfOeY63QTntERDJJ/0SuKK0T1uVSgKCuAROlKEPY= go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8= -go.mongodb.org/mongo-driver v1.10.1 h1:NujsPveKwHaWuKUer/ceo9DzEe7HIj1SlJ6uvXZG0S4= -go.mongodb.org/mongo-driver v1.10.1/go.mod h1:z4XpeoU6w+9Vht+jAFyLgVrD+jGSQQe0+CBWFHNiHt8= +go.mongodb.org/mongo-driver v1.11.3 h1:Ql6K6qYHEzB6xvu4+AU0BoRoqf9vFPcc4o7MUIdPW8Y= +go.mongodb.org/mongo-driver v1.11.3/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5quethTUn9WM+2g= +go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -653,23 +1306,62 @@ go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.25.0 h1:Wx7nFnvCaissIUZxPkBqDz2963Z+Cl+PkYbDKzTxDqQ= -go.opentelemetry.io/otel v1.0.1 h1:4XKyXmfqJLOQ7feyV5DB6gsBFZ0ltB8vLtp6pj4JIcc= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.0.1 h1:ofMbch7i29qIUf7VtF+r0HRF6ac0SBaPSziSsKp7wkk= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.0.1 h1:CFMFNoz+CGprjFAFy+RJFrfEe4GBia3RRm2a4fREvCA= -go.opentelemetry.io/otel/sdk v1.0.1 h1:wXxFEWGo7XfXupPwVJvTBOaPBC9FEg0wB8hMNrKk+cA= -go.opentelemetry.io/otel/trace v1.0.1 h1:StTeIH6Q3G4r0Fiw34LTokUFESZgIDUr0qIJ7mKmAfw= +go.opentelemetry.io/contrib v0.20.0 h1:ubFQUn0VCZ0gPwIoJfBJVpeBlyRMxu8Mm/huKWYd9p0= +go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.28.0 h1:Ky1MObd188aGbgb5OgNnwGuEEwI9MVIcc7rBW6zk5Ak= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.28.0/go.mod h1:vEhqr0m4eTc+DWxfsXoXue2GBgV2uUwVznkGIHW/e5w= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0/go.mod h1:2AboqHi0CiIZU0qwhtUfCYD1GeUzvvIXWNkhDt7ZMG4= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.31.0/go.mod h1:PFmBsWbldL1kiWZk9+0LBZz2brhByaGsvp6pRICMlPE= +go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo= +go.opentelemetry.io/otel v1.3.0/go.mod h1:PWIKzi6JCp7sM0k9yZ43VX+T345uNbAkDKwHVjb2PTs= +go.opentelemetry.io/otel v1.6.0/go.mod h1:bfJD2DZVw0LBxghOTlgnlI0CV3hLDu9XF/QKOUXMTQQ= +go.opentelemetry.io/otel v1.6.1/go.mod h1:blzUabWHkX6LJewxvadmzafgh/wnvBSDBdOuwkAtrWQ= +go.opentelemetry.io/otel v1.14.0 h1:/79Huy8wbf5DnIPhemGB+zEPVwnN6fuQybr/SRXa6hM= +go.opentelemetry.io/otel/exporters/otlp v0.20.0 h1:PTNgq9MRmQqqJY0REVbZFvwkYOA85vbdQU/nVfxDyqg= +go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM= +go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.3.0/go.mod h1:VpP4/RMn8bv8gNo9uK7/IMY4mtWLELsS+JIP0inH0h4= +go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.6.1 h1:T1FtMXHM2YPIUrYxSbTIAYDCvUZVpNdl7hDMDnp09cE= +go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.6.1/go.mod h1:NEu79Xo32iVb+0gVNV8PMd7GoWqnyDXRlj04yFjqz40= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.3.0/go.mod h1:hO1KLR7jcKaDDKDkvI9dP/FIhpmna5lkqPUQdEjFAM8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.6.1 h1:EvIC2jmn1+24OABwtw2Lng5yxy5eYJ8nf461UaHXTms= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.6.1/go.mod h1:YJ/JbY5ag/tSQFXzH3mtDmHqzF3aFn3DI/aB1n7pt4w= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.3.0/go.mod h1:keUU7UfnwWTWpJ+FWnyqmogPa82nuU5VUANFq49hlMY= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.6.1 h1:G45R6KdPgxe9UaZJMF4VUnsYgZpOHCSgl7FiOEV6570= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.6.1/go.mod h1:UJJXJj0rltNIemDMwkOJyggsvyMG9QHfJeFH0HS5JjM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.3.0/go.mod h1:QNX1aly8ehqqX1LEa6YniTU7VY9I6R3X/oPxhGdTceE= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.6.1/go.mod h1:DAKwdo06hFLc0U88O10x4xnb5sc7dDRDqRuiN+io8JE= +go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU= +go.opentelemetry.io/otel/metric v0.28.0/go.mod h1:TrzsfQAmQaB1PDcdhBauLMk7nyyg9hm+GoQq/ekE9Iw= +go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw= +go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc= +go.opentelemetry.io/otel/sdk v1.3.0/go.mod h1:rIo4suHNhQwBIPg9axF8V9CA72Wz2mKF1teNrup8yzs= +go.opentelemetry.io/otel/sdk v1.6.1/go.mod h1:IVYrddmFZ+eJqu2k38qD3WezFR2pymCzm8tdxyh3R4E= +go.opentelemetry.io/otel/sdk v1.14.0 h1:PDCppFRDq8A1jL9v6KMI6dYesaq+DFcDZvjsoGvxGzY= +go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE= +go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE= +go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= +go.opentelemetry.io/otel/trace v1.3.0/go.mod h1:c/VDhno8888bvQYmbYLqe41/Ldmr/KKunbvWM4/fEjk= +go.opentelemetry.io/otel/trace v1.6.0/go.mod h1:qs7BrU5cZ8dXQHBGxHMOxwME/27YH2qEp4/+tZLLwJE= +go.opentelemetry.io/otel/trace v1.6.1/go.mod h1:RkFRM1m0puWIq10oxImnGEduNBzxiN7TXluRBtE+5j0= +go.opentelemetry.io/otel/trace v1.14.0 h1:wp2Mmvj41tDsyAJXiWDWpfNsOiIyd38fy85pyKcFq/M= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.opentelemetry.io/proto/otlp v0.9.0 h1:C0g6TWmQYvjKRnljRULLWUVJGy8Uvu0NEL/5frY2/t4= +go.opentelemetry.io/proto/otlp v0.11.0/go.mod h1:QpEjXPrNQzrFDZgoTo49dgHR9RYRSrg3NAKnUGl9YpQ= +go.opentelemetry.io/proto/otlp v0.12.1/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= +go.opentelemetry.io/proto/otlp v0.19.0 h1:IVN6GR+mhC4s5yfcTbmzHYODqvWAp3ZedA2SJPI1Nnw= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= +go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= +go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/automaxprocs v1.5.1/go.mod h1:BF4eumQw0P9GtnuxxovUd06vwm1o18oMzFtK66vU6XU= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA= +go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= @@ -681,30 +1373,44 @@ go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= +go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8= go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= +golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220517005047-85d78b3ac167/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20211202192323-5770296d904e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8= -golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80= +golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= +golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= +golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -741,23 +1447,36 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= -golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA= -golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= +golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -768,28 +1487,42 @@ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.3.0 h1:VWL6FNY2bEEmsGVKabSlHu5Irp34xmMRoqb/9lF9lxk= -golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -805,10 +1538,11 @@ golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783 h1:nt+Q6cXKz4MosCSpnbMtqiQ8Oz0pxTef2B4Vca2lvfk= -golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8= +golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -821,10 +1555,15 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/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-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= -golang.org/x/sync v0.1.0/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.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= +golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +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-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -835,21 +1574,43 @@ golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190522044717-8097e1b27ff5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190812073006-9eafafc0a87e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -857,27 +1618,43 @@ golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200817155316-9781c653f443/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200922070232-aee5d888a860/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201117170446-d9b008d0a637/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201202213521-69691e467435/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -886,20 +1663,38 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210903071746-97244b99971b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220513210249-45d2b4557a2a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= -golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -909,18 +1704,30 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= -golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20220411224347-583f2d630306 h1:+gHMid33q6pen7kv9xvT+JRinntgeXO2AeZVd0AWD3w= +golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220224211638-0e9765cccd65/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/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-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= @@ -930,14 +1737,20 @@ golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -958,17 +1771,21 @@ golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjs golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20200916195026-c9a70fc28ce3/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= @@ -978,8 +1795,12 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.4.0 h1:7mTAgkunk3fr4GAloyyCasadO6h9zSsQZbwvcaIciV4= -golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= +golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= +golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.9.3 h1:Gn1I8+64MsuTb/HpH+LmQtNas23LhUVr3rYZ0eKuaMM= +golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -988,6 +1809,7 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -1017,10 +1839,14 @@ google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6 google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= -google.golang.org/api v0.58.0/go.mod h1:cAbP2FsxoGVNwtgNAmmn3y5G1TWAiVYRmg4yku3lv+E= -google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU= -google.golang.org/api v0.104.0 h1:KBfmLRqdZEbwQleFlSLnzpQJwhjpmNOk4cKQIBDZ9mg= -google.golang.org/api v0.104.0/go.mod h1:JCspTXJbBxa5ySXw4UgUqVer7DfVxbvc/CTUFqAED5U= +google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= +google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= +google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= +google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= +google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= +google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= +google.golang.org/api v0.122.0 h1:zDobeejm3E7pEG1mNHvdxvjs5XJoCMzyNH+CmwL94Es= +google.golang.org/api v0.122.0/go.mod h1:gcitW0lvnyWjSp9nKxAbdHKIZ6vF4aajGueeslZOyms= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1029,11 +1855,13 @@ google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCID google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190522204451-c2c4e71fbf69/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= @@ -1042,6 +1870,7 @@ google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvx google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200117163144-32f20d992d24/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= @@ -1056,12 +1885,15 @@ google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200527145253-8367513e4ece/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= @@ -1087,17 +1919,28 @@ google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEc google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210917145530-b395a37504d4/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210921142501-181ce0d877f6/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211008145708-270636b82663/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211018162055-cf77aa76bad2/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20221206210731-b1a01be3a5f6 h1:AGXp12e/9rItf6/4QymU7WsAUwCf+ICW75cuR91nJIc= -google.golang.org/genproto v0.0.0-20221206210731-b1a01be3a5f6/go.mod h1:1dOng4TWOomJrDGhpXjfCD35wQC6jnC7HpRmOFRqEV0= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= +google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A= +google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= +google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= @@ -1119,9 +1962,13 @@ google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQ google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k= -google.golang.org/grpc v1.51.0 h1:E1eGv1FTqoLIdnBCZufiSHgKjlqG6fKFf6pPWtMTh8U= -google.golang.org/grpc v1.51.0/go.mod h1:wgNDFcnuBGmxLKI/qn4T+m5BtEBYXJPvibbUPsAIPww= +google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag= +google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -1136,20 +1983,36 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= -google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= -gopkg.in/ini.v1 v1.66.4 h1:SsAcf+mM7mRZo2nJNGt8mZCjG8ZRaNGMURJw7BsIST4= -gopkg.in/ini.v1 v1.66.4/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +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/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/telebot.v3 v3.0.0/go.mod h1:7rExV8/0mDDNu9epSrDm/8j22KLaActH1Tbee6YjzWg= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -1165,9 +2028,9 @@ gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/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= -gorm.io/driver/postgres v1.3.5/go.mod h1:EGCWefLFQSVFrHGy4J8EtiHCWX5Q8t0yz2Jt9aKkGzU= -gorm.io/gorm v1.23.4/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= -gorm.io/gorm v1.23.5/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= +gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -1175,10 +2038,72 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/klog/v2 v2.80.1 h1:atnLQ121W371wYYFawwYx1aEY2eUfs4l3J72wtgAwV4= -k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo= +k8s.io/api v0.20.4/go.mod h1:++lNL1AJMkDymriNniQsWRkMDzRaX2Y/POTUi8yvqYQ= +k8s.io/api v0.20.6/go.mod h1:X9e8Qag6JV/bL5G6bU8sdVRltWKmdHsFUGS3eVndqE8= +k8s.io/api v0.22.5/go.mod h1:mEhXyLaSD1qTOf40rRiKXkc+2iCem09rWLlFwhCEiAs= +k8s.io/api v0.23.5/go.mod h1:Na4XuKng8PXJ2JsploYYrivXrINeTaycCGcYgF91Xm8= +k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= +k8s.io/apimachinery v0.20.4/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= +k8s.io/apimachinery v0.20.6/go.mod h1:ejZXtW1Ra6V1O5H8xPBGz+T3+4gfkTCeExAHKU57MAc= +k8s.io/apimachinery v0.22.1/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0= +k8s.io/apimachinery v0.22.5/go.mod h1:xziclGKwuuJ2RM5/rSFQSYAj0zdbci3DH8kj+WvyN0U= +k8s.io/apimachinery v0.23.5/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM= +k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU= +k8s.io/apiserver v0.20.4/go.mod h1:Mc80thBKOyy7tbvFtB4kJv1kbdD0eIH8k8vianJcbFM= +k8s.io/apiserver v0.20.6/go.mod h1:QIJXNt6i6JB+0YQRNcS0hdRHJlMhflFmsBDeSgT1r8Q= +k8s.io/apiserver v0.22.5/go.mod h1:s2WbtgZAkTKt679sYtSudEQrTGWUSQAPe6MupLnlmaQ= +k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y= +k8s.io/client-go v0.20.4/go.mod h1:LiMv25ND1gLUdBeYxBIwKpkSC5IsozMMmOOeSJboP+k= +k8s.io/client-go v0.20.6/go.mod h1:nNQMnOvEUEsOzRRFIIkdmYOjAZrC8bgq0ExboWSU1I0= +k8s.io/client-go v0.22.5/go.mod h1:cs6yf/61q2T1SdQL5Rdcjg9J1ElXSwbjSrW2vFImM4Y= +k8s.io/client-go v0.23.5/go.mod h1:flkeinTO1CirYgzMPRWxUCnV0G4Fbu2vLhYCObnt/r4= +k8s.io/code-generator v0.19.7/go.mod h1:lwEq3YnLYb/7uVXLorOJfxg+cUu2oihFhHZ0n9NIla0= +k8s.io/component-base v0.20.1/go.mod h1:guxkoJnNoh8LNrbtiQOlyp2Y2XFCZQmrcg2n/DeYNLk= +k8s.io/component-base v0.20.4/go.mod h1:t4p9EdiagbVCJKrQ1RsA5/V4rFQNDfRlevJajlGwgjI= +k8s.io/component-base v0.20.6/go.mod h1:6f1MPBAeI+mvuts3sIdtpjljHWBQ2cIy38oBIWMYnrM= +k8s.io/component-base v0.22.5/go.mod h1:VK3I+TjuF9eaa+Ln67dKxhGar5ynVbwnGrUiNF4MqCI= +k8s.io/cri-api v0.17.3/go.mod h1:X1sbHmuXhwaHs9xxYffLqJogVsnI+f6cPRcgPel7ywM= +k8s.io/cri-api v0.20.1/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI= +k8s.io/cri-api v0.20.4/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI= +k8s.io/cri-api v0.20.6/go.mod h1:ew44AjNXwyn1s0U4xCKGodU7J1HzBeZ1MpGrpa5r8Yc= +k8s.io/cri-api v0.23.1/go.mod h1:REJE3PSU0h/LOV1APBrupxrEJqnoxZC8KWzkBUHwrK4= +k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20200428234225-8167cfdcfc14/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20201113003025-83324d819ded/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= +k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/klog/v2 v2.40.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= +k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= +k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= +k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= +k8s.io/kube-openapi v0.0.0-20211109043538-20434351676c/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= +k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk= +k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= +k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.22/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= +sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs= +sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.0.3/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= +sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/hack/tools/tools.go b/hack/tools/tools.go index 5aa62ecb6..aac0d23da 100644 --- a/hack/tools/tools.go +++ b/hack/tools/tools.go @@ -20,7 +20,7 @@ package tools import ( - _ "github.com/AdaLogics/go-fuzz-headers" + _ "github.com/AdamKorcz/go-fuzz-headers-1" _ "github.com/go-swagger/go-swagger/cmd/swagger" _ "github.com/wadey/gocovmerge" diff --git a/oid-info.md b/oid-info.md new file mode 100644 index 000000000..1f2269c6c --- /dev/null +++ b/oid-info.md @@ -0,0 +1,14 @@ +# Rekor OID Information + +## Description + +This document defines Rekor +[OID values](https://github.com/sigstore/sigstore/blob/main/docs/oid-info.md). + +Rekor reserves the `1.3.6.1.4.1.57264.3` OID root for all of its values. + +## Directory + +| OID | Name | Tag Type | Description | +| --------------------- | -------------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| 1.3.6.1.4.1.57264.3.1 | TransparencyLogEntry | `UTF8STRING` | Proto serialized [TransparencyLogEntry](https://github.com/sigstore/protobuf-specs/blob/4dbf10bc287d76f1bfa68c05a78f3f5add5f56fe/protos/sigstore_rekor.proto#L89). | diff --git a/openapi.yaml b/openapi.yaml index d90503f96..1a8a7c145 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -67,6 +67,12 @@ paths: operationId: getLogInfo tags: - tlog + parameters: + - in: query + name: stable + type: boolean + default: false + description: Whether to return a stable checkpoint for the active shard responses: 200: description: A JSON object with the root hash and tree size as properties @@ -420,6 +426,23 @@ definitions: - spec additionalProperties: false + dsse: + type: object + description: DSSE envelope + allOf: + - $ref: '#/definitions/ProposedEntry' + - properties: + apiVersion: + type: string + pattern: ^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$ + spec: + type: object + $ref: 'pkg/types/dsse/dsse_schema.json' + required: + - apiVersion + - spec + additionalProperties: false + LogEntry: type: object additionalProperties: @@ -437,6 +460,7 @@ definitions: additionalProperties: true integratedTime: type: integer + description: The time the entry was added to the log as a Unix timestamp in seconds attestation: type: object properties: diff --git a/pkg/api/api.go b/pkg/api/api.go index 84ca4ac06..b033a022a 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -24,19 +24,24 @@ import ( "time" "github.com/google/trillian" - radix "github.com/mediocregopher/radix/v4" + "github.com/redis/go-redis/v9" "github.com/spf13/viper" "golang.org/x/exp/slices" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" "github.com/sigstore/rekor/pkg/log" + "github.com/sigstore/rekor/pkg/pubsub" "github.com/sigstore/rekor/pkg/sharding" "github.com/sigstore/rekor/pkg/signer" "github.com/sigstore/rekor/pkg/storage" + "github.com/sigstore/rekor/pkg/trillianclient" + "github.com/sigstore/rekor/pkg/witness" "github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/sigstore/sigstore/pkg/signature" "github.com/sigstore/sigstore/pkg/signature/options" + + _ "github.com/sigstore/rekor/pkg/pubsub/gcp" // Load GCP pubsub implementation ) func dial(ctx context.Context, rpcServer string) (*grpc.ClientConn, error) { @@ -59,6 +64,11 @@ type API struct { pubkey string // PEM encoded public key pubkeyHash string // SHA256 hash of DER-encoded public key signer signature.Signer + // stops checkpoint publishing + checkpointPublishCancel context.CancelFunc + // Publishes notifications when new entries are added to the log. May be + // nil if no publisher is configured. + newEntryPublisher pubsub.Publisher } func NewAPI(treeID uint) (*API, error) { @@ -82,7 +92,7 @@ func NewAPI(treeID uint) (*API, error) { tid := int64(treeID) if tid == 0 { log.Logger.Info("No tree ID specified, attempting to create a new tree") - t, err := createAndInitTree(ctx, logAdminClient, logClient) + t, err := trillianclient.CreateAndInitTree(ctx, logAdminClient, logClient) if err != nil { return nil, fmt.Errorf("create and init tree: %w", err) } @@ -108,6 +118,18 @@ func NewAPI(treeID uint) (*API, error) { pubkey := cryptoutils.PEMEncode(cryptoutils.PublicKeyPEMType, b) + var newEntryPublisher pubsub.Publisher + if p := viper.GetString("rekor_server.new_entry_publisher"); p != "" { + if !viper.GetBool("rekor_server.publish_events_protobuf") && !viper.GetBool("rekor_server.publish_events_json") { + return nil, fmt.Errorf("%q is configured but neither %q or %q are enabled", "new_entry_publisher", "publish_events_protobuf", "publish_events_json") + } + newEntryPublisher, err = pubsub.Get(ctx, p) + if err != nil { + return nil, fmt.Errorf("init event publisher: %w", err) + } + log.ContextLogger(ctx).Infof("Initialized new entry event publisher: %s", p) + } + return &API{ // Transparency Log Stuff logClient: logClient, @@ -117,28 +139,31 @@ func NewAPI(treeID uint) (*API, error) { pubkey: string(pubkey), pubkeyHash: hex.EncodeToString(pubkeyHashBytes[:]), signer: rekorSigner, + // Utility functionality not required for operation of the core service + newEntryPublisher: newEntryPublisher, }, nil } var ( api *API - redisClient radix.Client storageClient storage.AttestationStorage + redisClient *redis.Client ) func ConfigureAPI(treeID uint) { - cfg := radix.PoolConfig{} var err error api, err = NewAPI(treeID) if err != nil { log.Logger.Panic(err) } - if viper.GetBool("enable_retrieve_api") || slices.Contains(viper.GetStringSlice("enabled_api_endpoints"), "searchIndex") { - redisClient, err = cfg.New(context.Background(), "tcp", fmt.Sprintf("%v:%v", viper.GetString("redis_server.address"), viper.GetUint64("redis_server.port"))) - if err != nil { - log.Logger.Panic("failure connecting to redis instance: ", err) - } + if viper.GetBool("enable_retrieve_api") || viper.GetBool("enable_stable_checkpoint") || + slices.Contains(viper.GetStringSlice("enabled_api_endpoints"), "searchIndex") { + redisClient = redis.NewClient(&redis.Options{ + Addr: fmt.Sprintf("%v:%v", viper.GetString("redis_server.address"), viper.GetUint64("redis_server.port")), + Network: "tcp", + DB: 0, // default DB + }) } if viper.GetBool("enable_attestation_storage") { @@ -147,4 +172,22 @@ func ConfigureAPI(treeID uint) { log.Logger.Panic(err) } } + + if viper.GetBool("enable_stable_checkpoint") { + checkpointPublisher := witness.NewCheckpointPublisher(context.Background(), api.logClient, api.logRanges.ActiveTreeID(), + viper.GetString("rekor_server.hostname"), api.signer, redisClient, viper.GetUint("publish_frequency"), CheckpointPublishCount) + + // create context to cancel goroutine on server shutdown + ctx, cancel := context.WithCancel(context.Background()) + api.checkpointPublishCancel = cancel + checkpointPublisher.StartPublisher(ctx) + } +} + +func StopAPI() { + api.checkpointPublishCancel() + + if api.newEntryPublisher != nil { + api.newEntryPublisher.Close() + } } diff --git a/pkg/api/entries.go b/pkg/api/entries.go index 70c96f8d2..49643e4ce 100644 --- a/pkg/api/entries.go +++ b/pkg/api/entries.go @@ -33,14 +33,18 @@ import ( ttypes "github.com/google/trillian/types" "github.com/spf13/viper" "github.com/transparency-dev/merkle/rfc6962" - "golang.org/x/sync/errgroup" "google.golang.org/genproto/googleapis/rpc/code" "google.golang.org/grpc/codes" + "github.com/sigstore/rekor/pkg/events" + "github.com/sigstore/rekor/pkg/events/newentry" "github.com/sigstore/rekor/pkg/generated/models" "github.com/sigstore/rekor/pkg/generated/restapi/operations/entries" "github.com/sigstore/rekor/pkg/log" + "github.com/sigstore/rekor/pkg/pubsub" "github.com/sigstore/rekor/pkg/sharding" + "github.com/sigstore/rekor/pkg/tle" + "github.com/sigstore/rekor/pkg/trillianclient" "github.com/sigstore/rekor/pkg/types" "github.com/sigstore/rekor/pkg/util" "github.com/sigstore/sigstore/pkg/signature" @@ -68,7 +72,7 @@ func signEntry(ctx context.Context, signer signature.Signer, entry models.LogEnt } // logEntryFromLeaf creates a signed LogEntry struct from trillian structs -func logEntryFromLeaf(ctx context.Context, signer signature.Signer, tc TrillianClient, leaf *trillian.LogLeaf, +func logEntryFromLeaf(ctx context.Context, signer signature.Signer, _ trillianclient.TrillianClient, leaf *trillian.LogLeaf, signedLogRoot *trillian.SignedLogRoot, proof *trillian.Proof, tid int64, ranges sharding.LogRanges) (models.LogEntry, error) { log.ContextLogger(ctx).Debugf("log entry from leaf %d", leaf.GetLeafIndex()) @@ -94,7 +98,7 @@ func logEntryFromLeaf(ctx context.Context, signer signature.Signer, tc TrillianC return nil, fmt.Errorf("signing entry error: %w", err) } - scBytes, err := util.CreateAndSignCheckpoint(ctx, viper.GetString("rekor_server.hostname"), tc.logID, root, api.signer) + scBytes, err := util.CreateAndSignCheckpoint(ctx, viper.GetString("rekor_server.hostname"), tid, root.TreeSize, root.RootHash, api.signer) if err != nil { return nil, err } @@ -187,23 +191,30 @@ func createLogEntry(params entries.CreateLogEntryParams) (models.LogEntry, middl return nil, handleRekorAPIError(params, http.StatusInternalServerError, err, failedToGenerateCanonicalEntry) } - tc := NewTrillianClient(ctx) + tc := trillianclient.NewTrillianClient(ctx, api.logClient, api.logID) - resp := tc.addLeaf(leaf) + resp := tc.AddLeaf(leaf) // this represents overall GRPC response state (not the results of insertion into the log) - if resp.status != codes.OK { - return nil, handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("grpc error: %w", resp.err), trillianUnexpectedResult) + if resp.Status != codes.OK { + return nil, handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("grpc error: %w", resp.Err), trillianUnexpectedResult) } // this represents the results of inserting the proposed leaf into the log; status is nil in success path - insertionStatus := resp.getAddResult.QueuedLeaf.Status + insertionStatus := resp.GetAddResult.QueuedLeaf.Status if insertionStatus != nil { switch insertionStatus.Code { case int32(code.Code_OK): case int32(code.Code_ALREADY_EXISTS), int32(code.Code_FAILED_PRECONDITION): existingUUID := hex.EncodeToString(rfc6962.DefaultHasher.HashLeaf(leaf)) - err := fmt.Errorf("grpc error: %v", insertionStatus.String()) - return nil, handleRekorAPIError(params, http.StatusConflict, err, fmt.Sprintf(entryAlreadyExists, existingUUID), "entryURL", getEntryURL(*params.HTTPRequest.URL, existingUUID)) + activeTree := fmt.Sprintf("%x", api.logID) + entryIDstruct, err := sharding.CreateEntryIDFromParts(activeTree, existingUUID) + if err != nil { + err := fmt.Errorf("error creating EntryID from active treeID %v and uuid %v: %w", activeTree, existingUUID, err) + return nil, handleRekorAPIError(params, http.StatusInternalServerError, err, fmt.Sprintf(validationError, err)) + } + existingEntryID := entryIDstruct.ReturnEntryIDString() + err = fmt.Errorf("grpc error: %v", insertionStatus.String()) + return nil, handleRekorAPIError(params, http.StatusConflict, err, fmt.Sprintf(entryAlreadyExists, existingEntryID), "entryURL", getEntryURL(*params.HTTPRequest.URL, existingEntryID)) default: err := fmt.Errorf("grpc error: %v", insertionStatus.String()) return nil, handleRekorAPIError(params, http.StatusInternalServerError, err, trillianUnexpectedResult) @@ -213,10 +224,10 @@ func createLogEntry(params entries.CreateLogEntryParams) (models.LogEntry, middl // We made it this far, that means the entry was successfully added. metricNewEntries.Inc() - queuedLeaf := resp.getAddResult.QueuedLeaf.Leaf + queuedLeaf := resp.GetAddResult.QueuedLeaf.Leaf uuid := hex.EncodeToString(queuedLeaf.GetMerkleLeafHash()) - activeTree := fmt.Sprintf("%x", tc.logID) + activeTree := fmt.Sprintf("%x", api.logID) entryIDstruct, err := sharding.CreateEntryIDFromParts(activeTree, uuid) if err != nil { err := fmt.Errorf("error creating EntryID from active treeID %v and uuid %v: %w", activeTree, uuid, err) @@ -255,9 +266,9 @@ func createLogEntry(params entries.CreateLogEntryParams) (models.LogEntry, middl go func() { if err := storeAttestation(context.Background(), attKey, attVal); err != nil { // entryIDstruct.UUID - log.ContextLogger(ctx).Errorf("error storing attestation: %s", err) + log.ContextLogger(ctx).Debugf("error storing attestation: %s", err) } else { - log.ContextLogger(ctx).Infof("stored attestation for uuid %s with filename %s", entryIDstruct.UUID, attKey) + log.ContextLogger(ctx).Debugf("stored attestation for uuid %s with filename %s", entryIDstruct.UUID, attKey) } }() } else { @@ -272,15 +283,15 @@ func createLogEntry(params entries.CreateLogEntryParams) (models.LogEntry, middl } root := &ttypes.LogRootV1{} - if err := root.UnmarshalBinary(resp.getLeafAndProofResult.SignedLogRoot.LogRoot); err != nil { + if err := root.UnmarshalBinary(resp.GetLeafAndProofResult.SignedLogRoot.LogRoot); err != nil { return nil, handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("error unmarshalling log root: %v", err), sthGenerateError) } hashes := []string{} - for _, hash := range resp.getLeafAndProofResult.Proof.Hashes { + for _, hash := range resp.GetLeafAndProofResult.Proof.Hashes { hashes = append(hashes, hex.EncodeToString(hash)) } - scBytes, err := util.CreateAndSignCheckpoint(ctx, viper.GetString("rekor_server.hostname"), tc.logID, root, api.signer) + scBytes, err := util.CreateAndSignCheckpoint(ctx, viper.GetString("rekor_server.hostname"), api.logID, root.TreeSize, root.RootHash, api.signer) if err != nil { return nil, handleRekorAPIError(params, http.StatusInternalServerError, err, sthGenerateError) } @@ -290,7 +301,7 @@ func createLogEntry(params entries.CreateLogEntryParams) (models.LogEntry, middl RootHash: swag.String(hex.EncodeToString(root.RootHash)), LogIndex: swag.Int64(queuedLeaf.LeafIndex), Hashes: hashes, - Checkpoint: stringPointer(string(scBytes)), + Checkpoint: swag.String(string(scBytes)), } logEntryAnon.Verification = &models.LogEntryAnonVerification{ @@ -301,9 +312,66 @@ func createLogEntry(params entries.CreateLogEntryParams) (models.LogEntry, middl logEntry := models.LogEntry{ entryID: logEntryAnon, } + + if api.newEntryPublisher != nil { + // Publishing notifications should not block the API response. + go func() { + verifiers, err := entry.Verifiers() + if err != nil { + incPublishEvent(newentry.Name, "", false) + log.ContextLogger(ctx).Errorf("Could not get verifiers for log entry %s: %v", entryID, err) + return + } + var subjects []string + for _, v := range verifiers { + subjects = append(subjects, v.Subjects()...) + } + + pbEntry, err := tle.GenerateTransparencyLogEntry(logEntryAnon) + if err != nil { + incPublishEvent(newentry.Name, "", false) + log.ContextLogger(ctx).Error(err) + return + } + event, err := newentry.New(entryID, pbEntry, subjects) + if err != nil { + incPublishEvent(newentry.Name, "", false) + log.ContextLogger(ctx).Error(err) + return + } + if viper.GetBool("rekor_server.publish_events_protobuf") { + go publishEvent(ctx, api.newEntryPublisher, event, events.ContentTypeProtobuf) + } + if viper.GetBool("rekor_server.publish_events_json") { + go publishEvent(ctx, api.newEntryPublisher, event, events.ContentTypeJSON) + } + }() + } + return logEntry, nil } +func publishEvent(ctx context.Context, publisher pubsub.Publisher, event *events.Event, contentType events.EventContentType) { + err := publisher.Publish(context.WithoutCancel(ctx), event, contentType) + incPublishEvent(event.Type().Name(), contentType, err == nil) + if err != nil { + log.ContextLogger(ctx).Error(err) + } +} + +func incPublishEvent(event string, contentType events.EventContentType, ok bool) { + status := "SUCCESS" + if !ok { + status = "ERROR" + } + labels := map[string]string{ + "event": event, + "status": status, + "content_type": string(contentType), + } + metricPublishEvents.With(labels).Inc() +} + // CreateLogEntryHandler creates new entry into log func CreateLogEntryHandler(params entries.CreateLogEntryParams) middleware.Responder { httpReq := params.HTTPRequest @@ -342,7 +410,7 @@ func GetLogEntryByUUIDHandler(params entries.GetLogEntryByUUIDParams) middleware if _, ok := (err).(types.ValidationError); ok { return handleRekorAPIError(params, http.StatusBadRequest, err, fmt.Sprintf("incorrectly formatted uuid %s", params.EntryUUID), params.EntryUUID) } - return handleRekorAPIError(params, http.StatusInternalServerError, err, "ID %s not found in any known trees", params.EntryUUID) + return handleRekorAPIError(params, http.StatusInternalServerError, err, trillianCommunicationError) } return entries.NewGetLogEntryByUUIDOK().WithPayload(logEntry) } @@ -358,8 +426,6 @@ func SearchLogQueryHandler(params entries.SearchLogQueryParams) middleware.Respo } if len(params.Entry.EntryUUIDs) > 0 || len(params.Entry.Entries()) > 0 { - g, _ := errgroup.WithContext(httpReqCtx) - var searchHashes [][]byte for _, entryID := range params.Entry.EntryUUIDs { // if we got this far, then entryID is either a 64 or 80 character hex string @@ -389,67 +455,44 @@ func SearchLogQueryHandler(params entries.SearchLogQueryParams) middleware.Respo } entries := params.Entry.Entries() - searchHashesChan := make(chan []byte, len(entries)) for _, e := range entries { - e := e // https://golang.org/doc/faq#closures_and_goroutines - g.Go(func() error { - entry, err := types.UnmarshalEntry(e) - if err != nil { - return fmt.Errorf("unmarshalling entry: %w", err) - } - - leaf, err := types.CanonicalizeEntry(httpReqCtx, entry) - if err != nil { - return fmt.Errorf("canonicalizing entry: %w", err) - } - hasher := rfc6962.DefaultHasher - leafHash := hasher.HashLeaf(leaf) - searchHashesChan <- leafHash - return nil - }) - } + entry, err := types.UnmarshalEntry(e) + if err != nil { + return handleRekorAPIError(params, http.StatusBadRequest, fmt.Errorf("unmarshalling entry: %w", err), err.Error()) + } - if err := g.Wait(); err != nil { - return handleRekorAPIError(params, http.StatusBadRequest, err, err.Error()) - } - close(searchHashesChan) - for hash := range searchHashesChan { - searchHashes = append(searchHashes, hash) + leaf, err := types.CanonicalizeEntry(httpReqCtx, entry) + if err != nil { + return handleRekorAPIError(params, http.StatusBadRequest, fmt.Errorf("canonicalizing entry: %w", err), err.Error()) + } + hasher := rfc6962.DefaultHasher + leafHash := hasher.HashLeaf(leaf) + searchHashes = append(searchHashes, leafHash) } searchByHashResults := make([]map[int64]*trillian.GetEntryAndProofResponse, len(searchHashes)) - g, _ = errgroup.WithContext(httpReqCtx) for i, hash := range searchHashes { - i, hash := i, hash // https://golang.org/doc/faq#closures_and_goroutines - g.Go(func() error { - var results map[int64]*trillian.GetEntryAndProofResponse - for _, shard := range api.logRanges.AllShards() { - tcs := NewTrillianClientFromTreeID(httpReqCtx, shard) - resp := tcs.getLeafAndProofByHash(hash) - switch resp.status { - case codes.OK: - leafResult := resp.getLeafAndProofResult - if leafResult != nil && leafResult.Leaf != nil { - if results == nil { - results = map[int64]*trillian.GetEntryAndProofResponse{} - } - results[shard] = resp.getLeafAndProofResult + var results map[int64]*trillian.GetEntryAndProofResponse + for _, shard := range api.logRanges.AllShards() { + tcs := trillianclient.NewTrillianClient(httpReqCtx, api.logClient, shard) + resp := tcs.GetLeafAndProofByHash(hash) + switch resp.Status { + case codes.OK: + leafResult := resp.GetLeafAndProofResult + if leafResult != nil && leafResult.Leaf != nil { + if results == nil { + results = map[int64]*trillian.GetEntryAndProofResponse{} } - case codes.NotFound: - // do nothing here, do not throw 404 error - continue - default: - log.ContextLogger(httpReqCtx).Errorf("error getLeafAndProofByHash(%s): code: %v, msg %v", hex.EncodeToString(hash), resp.status, resp.err) - return fmt.Errorf(trillianCommunicationError) + results[shard] = resp.GetLeafAndProofResult } + case codes.NotFound: + // do nothing here, do not throw 404 error + continue + default: + return handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("error getLeafAndProofByHash(%s): code: %v, msg %v", hex.EncodeToString(hash), resp.Status, resp.Err), trillianCommunicationError) } - searchByHashResults[i] = results - return nil - }) - } - - if err := g.Wait(); err != nil { - return handleRekorAPIError(params, http.StatusInternalServerError, err, err.Error()) + } + searchByHashResults[i] = results } for _, hashMap := range searchByHashResults { @@ -457,7 +500,7 @@ func SearchLogQueryHandler(params entries.SearchLogQueryParams) middleware.Respo if leafResp == nil { continue } - tcs := NewTrillianClientFromTreeID(httpReqCtx, shard) + tcs := trillianclient.NewTrillianClient(httpReqCtx, api.logClient, shard) logEntry, err := logEntryFromLeaf(httpReqCtx, api.signer, tcs, leafResp.Leaf, leafResp.SignedLogRoot, leafResp.Proof, shard, api.logRanges) if err != nil { return handleRekorAPIError(params, http.StatusInternalServerError, err, err.Error()) @@ -468,28 +511,13 @@ func SearchLogQueryHandler(params entries.SearchLogQueryParams) middleware.Respo } if len(params.Entry.LogIndexes) > 0 { - g, _ := errgroup.WithContext(httpReqCtx) - resultPayloadChan := make(chan models.LogEntry, len(params.Entry.LogIndexes)) - for _, logIndex := range params.Entry.LogIndexes { - logIndex := logIndex // https://golang.org/doc/faq#closures_and_goroutines - g.Go(func() error { - logEntry, err := retrieveLogEntryByIndex(httpReqCtx, int(swag.Int64Value(logIndex))) - if err != nil && !errors.Is(err, ErrNotFound) { - return err - } else if err == nil { - resultPayloadChan <- logEntry - } - return nil - }) - } - - if err := g.Wait(); err != nil { - return handleRekorAPIError(params, http.StatusInternalServerError, err, err.Error()) - } - close(resultPayloadChan) - for result := range resultPayloadChan { - resultPayload = append(resultPayload, result) + logEntry, err := retrieveLogEntryByIndex(httpReqCtx, int(swag.Int64Value(logIndex))) + if err != nil && !errors.Is(err, ErrNotFound) { + return handleRekorAPIError(params, http.StatusInternalServerError, err, err.Error()) + } else if err == nil { + resultPayload = append(resultPayload, logEntry) + } } } @@ -502,19 +530,19 @@ func retrieveLogEntryByIndex(ctx context.Context, logIndex int) (models.LogEntry log.ContextLogger(ctx).Infof("Retrieving log entry by index %d", logIndex) tid, resolvedIndex := api.logRanges.ResolveVirtualIndex(logIndex) - tc := NewTrillianClientFromTreeID(ctx, tid) + tc := trillianclient.NewTrillianClient(ctx, api.logClient, tid) log.ContextLogger(ctx).Debugf("Retrieving resolved index %v from TreeID %v", resolvedIndex, tid) - resp := tc.getLeafAndProofByIndex(resolvedIndex) - switch resp.status { + resp := tc.GetLeafAndProofByIndex(resolvedIndex) + switch resp.Status { case codes.OK: case codes.NotFound, codes.OutOfRange, codes.InvalidArgument: return models.LogEntry{}, ErrNotFound default: - return models.LogEntry{}, fmt.Errorf("grpc err: %w: %s", resp.err, trillianCommunicationError) + return models.LogEntry{}, fmt.Errorf("grpc err: %w: %s", resp.Err, trillianCommunicationError) } - result := resp.getLeafAndProofResult + result := resp.GetLeafAndProofResult leaf := result.Leaf if leaf == nil { return models.LogEntry{}, ErrNotFound @@ -548,7 +576,10 @@ func retrieveLogEntry(ctx context.Context, entryUUID string) (models.LogEntry, e for _, t := range trees { logEntry, err := retrieveUUIDFromTree(ctx, uuid, t.TreeID) if err != nil { - continue + if errors.Is(err, ErrNotFound) { + continue + } + return nil, err } return logEntry, nil } @@ -566,35 +597,39 @@ func retrieveUUIDFromTree(ctx context.Context, uuid string, tid int64) (models.L return models.LogEntry{}, types.ValidationError(err) } - tc := NewTrillianClientFromTreeID(ctx, tid) + tc := trillianclient.NewTrillianClient(ctx, api.logClient, tid) log.ContextLogger(ctx).Debugf("Attempting to retrieve UUID %v from TreeID %v", uuid, tid) - resp := tc.getLeafAndProofByHash(hashValue) - switch resp.status { + resp := tc.GetLeafAndProofByHash(hashValue) + switch resp.Status { case codes.OK: - result := resp.getLeafAndProofResult - leaf := result.Leaf - if leaf == nil { - return models.LogEntry{}, ErrNotFound + result := resp.GetLeafAndProofResult + if resp.Err != nil { + // this shouldn't be possible since GetLeafAndProofByHash verifies the inclusion proof using a computed leaf hash + // so this is just a defensive check + if result.Leaf == nil { + return models.LogEntry{}, ErrNotFound + } + return models.LogEntry{}, err } - logEntry, err := logEntryFromLeaf(ctx, api.signer, tc, leaf, result.SignedLogRoot, result.Proof, tid, api.logRanges) + logEntry, err := logEntryFromLeaf(ctx, api.signer, tc, result.Leaf, result.SignedLogRoot, result.Proof, tid, api.logRanges) if err != nil { - return models.LogEntry{}, errors.New("could not create log entry from leaf") + return models.LogEntry{}, fmt.Errorf("could not create log entry from leaf: %w", err) } return logEntry, nil case codes.NotFound: return models.LogEntry{}, ErrNotFound default: - log.ContextLogger(ctx).Errorf("Unexpected response code while attempting to retrieve UUID %v from TreeID %v: %v", uuid, tid, resp.status) + log.ContextLogger(ctx).Errorf("Unexpected response code while attempting to retrieve UUID %v from TreeID %v: %v", uuid, tid, resp.Status) return models.LogEntry{}, errors.New("unexpected error") } } // handlers for APIs that may be disabled in a given instance -func CreateLogEntryNotImplementedHandler(params entries.CreateLogEntryParams) middleware.Responder { +func CreateLogEntryNotImplementedHandler(_ entries.CreateLogEntryParams) middleware.Responder { err := &models.Error{ Code: http.StatusNotImplemented, Message: "Create Entry API not enabled in this Rekor instance", @@ -603,7 +638,7 @@ func CreateLogEntryNotImplementedHandler(params entries.CreateLogEntryParams) mi return entries.NewCreateLogEntryDefault(http.StatusNotImplemented).WithPayload(err) } -func GetLogEntryByIndexNotImplementedHandler(params entries.GetLogEntryByIndexParams) middleware.Responder { +func GetLogEntryByIndexNotImplementedHandler(_ entries.GetLogEntryByIndexParams) middleware.Responder { err := &models.Error{ Code: http.StatusNotImplemented, Message: "Get Log Entry by Index API not enabled in this Rekor instance", @@ -612,7 +647,7 @@ func GetLogEntryByIndexNotImplementedHandler(params entries.GetLogEntryByIndexPa return entries.NewGetLogEntryByIndexDefault(http.StatusNotImplemented).WithPayload(err) } -func GetLogEntryByUUIDNotImplementedHandler(params entries.GetLogEntryByUUIDParams) middleware.Responder { +func GetLogEntryByUUIDNotImplementedHandler(_ entries.GetLogEntryByUUIDParams) middleware.Responder { err := &models.Error{ Code: http.StatusNotImplemented, Message: "Get Log Entry by UUID API not enabled in this Rekor instance", @@ -621,7 +656,7 @@ func GetLogEntryByUUIDNotImplementedHandler(params entries.GetLogEntryByUUIDPara return entries.NewGetLogEntryByUUIDDefault(http.StatusNotImplemented).WithPayload(err) } -func SearchLogQueryNotImplementedHandler(params entries.SearchLogQueryParams) middleware.Responder { +func SearchLogQueryNotImplementedHandler(_ entries.SearchLogQueryParams) middleware.Responder { err := &models.Error{ Code: http.StatusNotImplemented, Message: "Search Log Query API not enabled in this Rekor instance", diff --git a/pkg/api/error.go b/pkg/api/error.go index 63693927b..d05e9170e 100644 --- a/pkg/api/error.go +++ b/pkg/api/error.go @@ -71,9 +71,9 @@ func handleRekorAPIError(params interface{}, code int, err error, message string ctx := r.Context() fields := append([]interface{}{"handler", handler, "statusCode", code, "clientMessage", message}, fields...) if code >= 500 { - log.ContextLogger(ctx).Errorw(err.Error(), fields) + log.ContextLogger(ctx).Errorw(err.Error(), fields...) } else { - log.ContextLogger(ctx).Warnw(err.Error(), fields) + log.ContextLogger(ctx).Warnw(err.Error(), fields...) } paramsFields := map[string]interface{}{} if err := mapstructure.Decode(params, ¶msFields); err == nil { diff --git a/pkg/api/index.go b/pkg/api/index.go index afda3aa90..69f695a28 100644 --- a/pkg/api/index.go +++ b/pkg/api/index.go @@ -25,7 +25,6 @@ import ( "github.com/go-openapi/runtime/middleware" "github.com/go-openapi/swag" - radix "github.com/mediocregopher/radix/v4" "github.com/sigstore/rekor/pkg/generated/models" "github.com/sigstore/rekor/pkg/generated/restapi/operations/index" @@ -46,8 +45,8 @@ func SearchIndexHandler(params index.SearchIndexParams) middleware.Responder { if params.Query.Hash != "" { // This must be a valid hash sha := util.PrefixSHA(params.Query.Hash) - var resultUUIDs []string - if err := redisClient.Do(httpReqCtx, radix.Cmd(&resultUUIDs, "LRANGE", strings.ToLower(sha), "0", "-1")); err != nil { + resultUUIDs, err := redisClient.LRange(httpReqCtx, strings.ToLower(sha), 0, -1).Result() + if err != nil { return handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("redis client: %w", err), redisUnexpectedResult) } result.Add(resultUUIDs) @@ -73,15 +72,15 @@ func SearchIndexHandler(params index.SearchIndexParams) middleware.Responder { } keyHash := sha256.Sum256(canonicalKey) - var resultUUIDs []string - if err := redisClient.Do(httpReqCtx, radix.Cmd(&resultUUIDs, "LRANGE", strings.ToLower(hex.EncodeToString(keyHash[:])), "0", "-1")); err != nil { + resultUUIDs, err := redisClient.LRange(httpReqCtx, strings.ToLower(hex.EncodeToString(keyHash[:])), 0, -1).Result() + if err != nil { return handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("redis client: %w", err), redisUnexpectedResult) } result.Add(resultUUIDs) } if params.Query.Email != "" { - var resultUUIDs []string - if err := redisClient.Do(httpReqCtx, radix.Cmd(&resultUUIDs, "LRANGE", strings.ToLower(params.Query.Email.String()), "0", "-1")); err != nil { + resultUUIDs, err := redisClient.LRange(httpReqCtx, strings.ToLower(params.Query.Email.String()), 0, -1).Result() + if err != nil { return handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("redis client: %w", err), redisUnexpectedResult) } result.Add(resultUUIDs) @@ -90,7 +89,7 @@ func SearchIndexHandler(params index.SearchIndexParams) middleware.Responder { return index.NewSearchIndexOK().WithPayload(result.Values()) } -func SearchIndexNotImplementedHandler(params index.SearchIndexParams) middleware.Responder { +func SearchIndexNotImplementedHandler(_ index.SearchIndexParams) middleware.Responder { err := models.Error{ Code: http.StatusNotImplemented, Message: "Search Index API not enabled in this Rekor instance", @@ -101,7 +100,8 @@ func SearchIndexNotImplementedHandler(params index.SearchIndexParams) middleware } func addToIndex(ctx context.Context, key, value string) error { - if err := redisClient.Do(ctx, radix.Cmd(nil, "LPUSH", key, value)); err != nil { + _, err := redisClient.LPush(ctx, key, value).Result() + if err != nil { return fmt.Errorf("redis client: %w", err) } return nil diff --git a/pkg/api/metrics.go b/pkg/api/metrics.go index 36d0d324a..64c91b493 100644 --- a/pkg/api/metrics.go +++ b/pkg/api/metrics.go @@ -29,6 +29,11 @@ var ( Help: "The total number of new log entries", }) + metricPublishEvents = promauto.NewCounterVec(prometheus.CounterOpts{ + Name: "rekor_publish_events", + Help: "The status of publishing events to Pub/Sub", + }, []string{"event", "content_type", "status"}) + MetricLatency = promauto.NewHistogramVec(prometheus.HistogramOpts{ Name: "rekor_api_latency", Help: "Api Latency on calls", @@ -53,6 +58,11 @@ var ( Help: "Api QPS by path, method, and response code", }, []string{"path", "method", "code"}) + CheckpointPublishCount = promauto.NewCounterVec(prometheus.CounterOpts{ + Name: "rekor_checkpoint_publish", + Help: "Checkpoint publishing by shard and code", + }, []string{"shard", "code"}) + _ = promauto.NewGaugeFunc( prometheus.GaugeOpts{ Namespace: "rekor", diff --git a/pkg/api/public_key.go b/pkg/api/public_key.go index 22e0c0436..b4ff91625 100644 --- a/pkg/api/public_key.go +++ b/pkg/api/public_key.go @@ -26,10 +26,8 @@ import ( ) func GetPublicKeyHandler(params pubkey.GetPublicKeyParams) middleware.Responder { - ctx := params.HTTPRequest.Context() treeID := swag.StringValue(params.TreeID) - tc := NewTrillianClient(ctx) - pk, err := tc.ranges.PublicKey(api.pubkey, treeID) + pk, err := api.logRanges.PublicKey(api.pubkey, treeID) if err != nil { return handleRekorAPIError(params, http.StatusBadRequest, err, "") } @@ -38,7 +36,7 @@ func GetPublicKeyHandler(params pubkey.GetPublicKeyParams) middleware.Responder // handlers for APIs that may be disabled in a given instance -func GetPublicKeyNotImplementedHandler(params pubkey.GetPublicKeyParams) middleware.Responder { +func GetPublicKeyNotImplementedHandler(_ pubkey.GetPublicKeyParams) middleware.Responder { err := &models.Error{ Code: http.StatusNotImplemented, Message: "Get Public Key API not enabled in this Rekor instance", diff --git a/pkg/api/tlog.go b/pkg/api/tlog.go index e6bbdcc68..45813c23d 100644 --- a/pkg/api/tlog.go +++ b/pkg/api/tlog.go @@ -31,17 +31,18 @@ import ( "github.com/sigstore/rekor/pkg/generated/models" "github.com/sigstore/rekor/pkg/generated/restapi/operations/tlog" "github.com/sigstore/rekor/pkg/log" + "github.com/sigstore/rekor/pkg/trillianclient" "github.com/sigstore/rekor/pkg/util" ) // GetLogInfoHandler returns the current size of the tree and the STH func GetLogInfoHandler(params tlog.GetLogInfoParams) middleware.Responder { - tc := NewTrillianClient(params.HTTPRequest.Context()) + tc := trillianclient.NewTrillianClient(params.HTTPRequest.Context(), api.logClient, api.logID) // for each inactive shard, get the loginfo var inactiveShards []*models.InactiveShardLogInfo - for _, shard := range tc.ranges.GetInactive() { - if shard.TreeID == tc.ranges.ActiveTreeID() { + for _, shard := range api.logRanges.GetInactive() { + if shard.TreeID == api.logRanges.ActiveTreeID() { break } // Get details for this inactive shard @@ -52,11 +53,43 @@ func GetLogInfoHandler(params tlog.GetLogInfoParams) middleware.Responder { inactiveShards = append(inactiveShards, is) } - resp := tc.getLatest(0) - if resp.status != codes.OK { - return handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("grpc error: %w", resp.err), trillianCommunicationError) + if swag.BoolValue(params.Stable) && redisClient != nil { + // key is treeID/latest + key := fmt.Sprintf("%d/latest", api.logRanges.ActiveTreeID()) + redisResult, err := redisClient.Get(params.HTTPRequest.Context(), key).Result() + if err != nil { + return handleRekorAPIError(params, http.StatusInternalServerError, + fmt.Errorf("error getting checkpoint from redis: %w", err), "error getting checkpoint from redis") + } + // should not occur, a checkpoint should always be present + if redisResult == "" { + return handleRekorAPIError(params, http.StatusInternalServerError, + fmt.Errorf("no checkpoint found in redis: %w", err), "no checkpoint found in redis") + } + decoded, err := hex.DecodeString(redisResult) + if err != nil { + return handleRekorAPIError(params, http.StatusInternalServerError, + fmt.Errorf("error decoding checkpoint from redis: %w", err), "error decoding checkpoint from redis") + } + checkpoint := util.SignedCheckpoint{} + if err := checkpoint.UnmarshalText(decoded); err != nil { + return handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("invalid checkpoint: %w", err), "invalid checkpoint") + } + logInfo := models.LogInfo{ + RootHash: stringPointer(hex.EncodeToString(checkpoint.Hash)), + TreeSize: swag.Int64(int64(checkpoint.Size)), + SignedTreeHead: stringPointer(string(decoded)), + TreeID: stringPointer(fmt.Sprintf("%d", api.logID)), + InactiveShards: inactiveShards, + } + return tlog.NewGetLogInfoOK().WithPayload(&logInfo) + } + + resp := tc.GetLatest(0) + if resp.Status != codes.OK { + return handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("grpc error: %w", resp.Err), trillianCommunicationError) } - result := resp.getLatestResult + result := resp.GetLatestResult root := &types.LogRootV1{} if err := root.UnmarshalBinary(result.SignedLogRoot.LogRoot); err != nil { @@ -67,7 +100,7 @@ func GetLogInfoHandler(params tlog.GetLogInfoParams) middleware.Responder { treeSize := int64(root.TreeSize) scBytes, err := util.CreateAndSignCheckpoint(params.HTTPRequest.Context(), - viper.GetString("rekor_server.hostname"), tc.ranges.ActiveTreeID(), root, api.signer) + viper.GetString("rekor_server.hostname"), api.logRanges.ActiveTreeID(), root.TreeSize, root.RootHash, api.signer) if err != nil { return handleRekorAPIError(params, http.StatusInternalServerError, err, sthGenerateError) } @@ -76,7 +109,7 @@ func GetLogInfoHandler(params tlog.GetLogInfoParams) middleware.Responder { RootHash: &hashString, TreeSize: &treeSize, SignedTreeHead: stringPointer(string(scBytes)), - TreeID: stringPointer(fmt.Sprintf("%d", tc.logID)), + TreeID: stringPointer(fmt.Sprintf("%d", api.logID)), InactiveShards: inactiveShards, } @@ -92,21 +125,21 @@ func GetLogProofHandler(params tlog.GetLogProofParams) middleware.Responder { if *params.FirstSize > params.LastSize { return handleRekorAPIError(params, http.StatusBadRequest, nil, fmt.Sprintf(firstSizeLessThanLastSize, *params.FirstSize, params.LastSize)) } - tc := NewTrillianClient(params.HTTPRequest.Context()) + tc := trillianclient.NewTrillianClient(params.HTTPRequest.Context(), api.logClient, api.logID) if treeID := swag.StringValue(params.TreeID); treeID != "" { id, err := strconv.Atoi(treeID) if err != nil { log.Logger.Infof("Unable to convert %s to string, skipping initializing client with Tree ID: %v", treeID, err) } else { - tc = NewTrillianClientFromTreeID(params.HTTPRequest.Context(), int64(id)) + tc = trillianclient.NewTrillianClient(params.HTTPRequest.Context(), api.logClient, int64(id)) } } - resp := tc.getConsistencyProof(*params.FirstSize, params.LastSize) - if resp.status != codes.OK { - return handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("grpc error: %w", resp.err), trillianCommunicationError) + resp := tc.GetConsistencyProof(*params.FirstSize, params.LastSize) + if resp.Status != codes.OK { + return handleRekorAPIError(params, http.StatusInternalServerError, fmt.Errorf("grpc error: %w", resp.Err), trillianCommunicationError) } - result := resp.getConsistencyProofResult + result := resp.GetConsistencyProofResult var root types.LogRootV1 if err := root.UnmarshalBinary(result.SignedLogRoot.LogRoot); err != nil { @@ -124,7 +157,8 @@ func GetLogProofHandler(params tlog.GetLogProofParams) middleware.Responder { // The proof field may be empty if the requested tree_size was larger than that available at the server // (e.g. because there is skew between server instances, and an earlier client request was processed by // a more up-to-date instance). root.TreeSize is the maximum size currently observed - return handleRekorAPIError(params, http.StatusBadRequest, nil, fmt.Sprintf(lastSizeGreaterThanKnown, params.LastSize, root.TreeSize)) + err := fmt.Errorf(lastSizeGreaterThanKnown, params.LastSize, root.TreeSize) + return handleRekorAPIError(params, http.StatusBadRequest, err, err.Error()) } consistencyProof := models.ConsistencyProof{ @@ -136,12 +170,12 @@ func GetLogProofHandler(params tlog.GetLogProofParams) middleware.Responder { } func inactiveShardLogInfo(ctx context.Context, tid int64) (*models.InactiveShardLogInfo, error) { - tc := NewTrillianClientFromTreeID(ctx, tid) - resp := tc.getLatest(0) - if resp.status != codes.OK { - return nil, fmt.Errorf("resp code is %d", resp.status) + tc := trillianclient.NewTrillianClient(ctx, api.logClient, tid) + resp := tc.GetLatest(0) + if resp.Status != codes.OK { + return nil, fmt.Errorf("resp code is %d", resp.Status) } - result := resp.getLatestResult + result := resp.GetLatestResult root := &types.LogRootV1{} if err := root.UnmarshalBinary(result.SignedLogRoot.LogRoot); err != nil { @@ -151,7 +185,7 @@ func inactiveShardLogInfo(ctx context.Context, tid int64) (*models.InactiveShard hashString := hex.EncodeToString(root.RootHash) treeSize := int64(root.TreeSize) - scBytes, err := util.CreateAndSignCheckpoint(ctx, viper.GetString("rekor_server.hostname"), tid, root, api.signer) + scBytes, err := util.CreateAndSignCheckpoint(ctx, viper.GetString("rekor_server.hostname"), tid, root.TreeSize, root.RootHash, api.signer) if err != nil { return nil, err } @@ -167,7 +201,7 @@ func inactiveShardLogInfo(ctx context.Context, tid int64) (*models.InactiveShard // handlers for APIs that may be disabled in a given instance -func GetLogInfoNotImplementedHandler(params tlog.GetLogInfoParams) middleware.Responder { +func GetLogInfoNotImplementedHandler(_ tlog.GetLogInfoParams) middleware.Responder { err := &models.Error{ Code: http.StatusNotImplemented, Message: "Get Log Info API not enabled in this Rekor instance", @@ -176,7 +210,7 @@ func GetLogInfoNotImplementedHandler(params tlog.GetLogInfoParams) middleware.Re return tlog.NewGetLogInfoDefault(http.StatusNotImplemented).WithPayload(err) } -func GetLogProofNotImplementedHandler(params tlog.GetLogProofParams) middleware.Responder { +func GetLogProofNotImplementedHandler(_ tlog.GetLogProofParams) middleware.Responder { err := &models.Error{ Code: http.StatusNotImplemented, Message: "Get Log Proof API not enabled in this Rekor instance", diff --git a/pkg/client/rekor_client.go b/pkg/client/rekor_client.go index 1c446e533..601dd9d32 100644 --- a/pkg/client/rekor_client.go +++ b/pkg/client/rekor_client.go @@ -50,7 +50,12 @@ func GetRekorClient(rekorServerURL string, opts ...Option) (*client.Rekor, error httpClient := retryableClient.StandardClient() httpClient.Transport = createRoundTripper(httpClient.Transport, o) - rt := httptransport.NewWithClient(url.Host, client.DefaultBasePath, []string{url.Scheme}, httpClient) + // sanitize path + if url.Path == "" { + url.Path = client.DefaultBasePath + } + + rt := httptransport.NewWithClient(url.Host, url.Path, []string{url.Scheme}, httpClient) rt.Consumers["application/json"] = runtime.JSONConsumer() rt.Consumers["application/x-pem-file"] = runtime.TextConsumer() rt.Producers["application/json"] = runtime.JSONProducer() diff --git a/pkg/client/rekor_client_test.go b/pkg/client/rekor_client_test.go index b7d549b1f..f4f049c9c 100644 --- a/pkg/client/rekor_client_test.go +++ b/pkg/client/rekor_client_test.go @@ -18,6 +18,7 @@ package client import ( "net/http" "net/http/httptest" + "strings" "testing" "time" @@ -53,6 +54,33 @@ func TestGetRekorClientWithUserAgent(t *testing.T) { } } +func TestGetRekorClientWithCustomPath(t *testing.T) { + t.Parallel() + requestReceived := false + pathAdd := "/custom" + + testServer := httptest.NewServer(http.HandlerFunc( + func(w http.ResponseWriter, r *http.Request) { + requestReceived = true + if !strings.HasPrefix(r.URL.Path, pathAdd) { + t.Errorf("Expected request to be sent to /test, got %s", r.URL.Path) + } + w.WriteHeader(http.StatusOK) + })) + defer testServer.Close() + + testServer.URL += pathAdd + + client, err := GetRekorClient(testServer.URL) + if err != nil { + t.Error(err) + } + _, _ = client.Tlog.GetLogInfo(nil) + if !requestReceived { + t.Fatal("no requests were received") + } +} + func TestGetRekorClientWithRetryCount(t *testing.T) { t.Parallel() expectedCount := 2 diff --git a/pkg/events/doc.go b/pkg/events/doc.go new file mode 100644 index 000000000..42ce55fd9 --- /dev/null +++ b/pkg/events/doc.go @@ -0,0 +1,19 @@ +// 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. + +// Package events provides methods for working with CloudEvents. +package events + +// The version of the CloudEvents specification the package adheres to. +const CloudEventsSpecVersion = "1.0" diff --git a/pkg/events/events.go b/pkg/events/events.go new file mode 100644 index 000000000..0f5bff74e --- /dev/null +++ b/pkg/events/events.go @@ -0,0 +1,198 @@ +// 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. + +// Package events +package events + +import ( + "encoding/json" + "fmt" + "time" + + "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/reflect/protoreflect" + "google.golang.org/protobuf/types/known/anypb" + "google.golang.org/protobuf/types/known/timestamppb" + + pb "github.com/sigstore/protobuf-specs/gen/pb-go/events/v1" +) + +// The content type of an event. +type EventContentType string + +const ( + ContentTypeProtobuf EventContentType = "application/protobuf" + ContentTypeJSON EventContentType = "application/json" +) + +// Keys that cannot be used in the optional event attributes map due to +// collisions with mandatory fields in the CloudEvents spec. +var reservedFields = map[string]struct{}{ + "datacontenttype": {}, + "data": {}, + "id": {}, + "source": {}, + "specversion": {}, + "type": {}, +} + +// Event is an instance of a certain event type. +type Event struct { + ty *EventType + id string + msg protoreflect.ProtoMessage + attrs map[string]any +} + +// Type returns the underlying event type. +func (e Event) Type() *EventType { + return e.ty +} + +// ID returns the identifier for the event. +func (e Event) ID() string { + return e.id +} + +// Attributes returns the attributes attached to the event. These attributes +// are optional and this function may return an empty map. +func (e Event) Attributes() map[string]any { + return e.attrs +} + +// Message returns the underlying message (aka data) of the event. +func (e Event) Message() protoreflect.ProtoMessage { + return e.msg +} + +// New creates a new event of a given type. +// +// The "id" and "msg" parameters are required. The "attributes" parameter +// supports the following value types: +// - string +// - int +// - bool +// - []byte +// - time.Time +func (t *EventType) New(id string, msg protoreflect.ProtoMessage, attributes map[string]any) (*Event, error) { + if id == "" { + return nil, fmt.Errorf("id must be set") + } + if msg == nil { + return nil, fmt.Errorf("msg must be set") + } + ty := msg.ProtoReflect().Descriptor().FullName() + if tty := t.Descriptor().FullName(); ty != tty { + return nil, fmt.Errorf("msg type %q does not match expected type %q", ty, tty) + } + + for name, value := range attributes { + if _, ok := reservedFields[name]; ok { + return nil, fmt.Errorf("attribute name %q is one of the reserved CloudEvents names %v", name, reservedFields) + } + switch v := value.(type) { + case string, bool, int, []byte, time.Time: + // Allowed types are a no-op. + default: + return nil, fmt.Errorf("unsupported attribute type for %q: %T", name, v) + } + } + + return &Event{ty: t, id: id, msg: msg, attrs: attributes}, nil +} + +// MarshalJSON serializes the event to JSON, following the CloudEvents +// specification. +func (e *Event) MarshalJSON() ([]byte, error) { + data, err := protojson.Marshal(e.msg) + if err != nil { + return nil, fmt.Errorf("marshal data to JSON: %w", err) + } + + event := map[string]any{ + "specversion": CloudEventsSpecVersion, + "id": e.ID(), + "source": e.Type().Source(), + "type": e.Type().Name(), + "datacontenttype": ContentTypeJSON, + "data": string(data), + } + for k, v := range e.attrs { + event[k] = v + } + + return json.Marshal(event) +} + +// MarshalProto serializes the event to the CloudEvents Protobuf wire format. +func (e *Event) MarshalProto() ([]byte, error) { + msg, err := e.Proto() + if err != nil { + return nil, fmt.Errorf("build proto: %w", err) + } + return proto.Marshal(msg) +} + +// Proto returns the CloudEvents protobuf for the event. +func (e *Event) Proto() (*pb.CloudEvent, error) { + data, err := proto.Marshal(e.msg) + if err != nil { + return nil, fmt.Errorf("marshal data: %w", err) + } + + attrs := make(map[string]*pb.CloudEvent_CloudEventAttributeValue) + for name, value := range e.attrs { + switch v := value.(type) { + case string: + attrs[name] = &pb.CloudEvent_CloudEventAttributeValue{ + Attr: &pb.CloudEvent_CloudEventAttributeValue_CeString{CeString: v}, + } + case bool: + attrs[name] = &pb.CloudEvent_CloudEventAttributeValue{ + Attr: &pb.CloudEvent_CloudEventAttributeValue_CeBoolean{CeBoolean: v}, + } + case int: + attrs[name] = &pb.CloudEvent_CloudEventAttributeValue{ + Attr: &pb.CloudEvent_CloudEventAttributeValue_CeInteger{CeInteger: int32(v)}, + } + case time.Time: + attrs[name] = &pb.CloudEvent_CloudEventAttributeValue{ + Attr: &pb.CloudEvent_CloudEventAttributeValue_CeTimestamp{ + CeTimestamp: timestamppb.New(v), + }, + } + case []byte: + attrs[name] = &pb.CloudEvent_CloudEventAttributeValue{ + Attr: &pb.CloudEvent_CloudEventAttributeValue_CeBytes{CeBytes: v}, + } + } + } + + event := &pb.CloudEvent{ + SpecVersion: CloudEventsSpecVersion, + Id: e.ID(), + Source: e.Type().Source(), + Type: e.Type().Name(), + Attributes: attrs, + Data: &pb.CloudEvent_ProtoData{ + ProtoData: &anypb.Any{ + Value: data, + TypeUrl: string(e.Type().Descriptor().FullName()), + }, + }, + } + + return event, nil +} diff --git a/pkg/events/newentry/new_entry.go b/pkg/events/newentry/new_entry.go new file mode 100644 index 000000000..a1d19eda1 --- /dev/null +++ b/pkg/events/newentry/new_entry.go @@ -0,0 +1,47 @@ +// 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. + +package newentry + +import ( + "strings" + "time" + + "github.com/sigstore/rekor/pkg/events" + "golang.org/x/exp/slices" + + rekor_pb "github.com/sigstore/protobuf-specs/gen/pb-go/rekor/v1" +) + +const ( + Name = "dev.sigstore.rekor.events.v1.NewEntry" + Source = "/createLogEntry" +) + +var ty *events.EventType + +func init() { + empty := &rekor_pb.TransparencyLogEntry{} + ty = events.RegisterType(Name, Source, empty.ProtoReflect().Descriptor()) +} + +func New(id string, entry *rekor_pb.TransparencyLogEntry, subjects []string) (*events.Event, error) { + slices.Sort(subjects) // Must be sorted for consistency. + attrs := map[string]any{ + "time": time.Unix(entry.GetIntegratedTime(), 0), + "rekor_entry_kind": entry.GetKindVersion().GetKind(), + "rekor_signing_subjects": strings.Join(subjects, ","), + } + return ty.New(id, entry, attrs) +} diff --git a/pkg/events/newentry/new_entry_test.go b/pkg/events/newentry/new_entry_test.go new file mode 100644 index 000000000..0f528a6b7 --- /dev/null +++ b/pkg/events/newentry/new_entry_test.go @@ -0,0 +1,114 @@ +// 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. + +package newentry + +import ( + "math" + "testing" + "time" + + "github.com/google/go-cmp/cmp" + "github.com/sigstore/rekor/pkg/events" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/testing/protocmp" + "google.golang.org/protobuf/types/known/anypb" + "google.golang.org/protobuf/types/known/timestamppb" + + events_pb "github.com/sigstore/protobuf-specs/gen/pb-go/events/v1" + rekor_pb "github.com/sigstore/protobuf-specs/gen/pb-go/rekor/v1" +) + +func TestBuildNewEntryEvent(t *testing.T) { + t.Parallel() + + decamillennium := time.Date(9999, 12, 31, 24, 59, 59, math.MaxInt, time.UTC).Unix() + testEntry := &rekor_pb.TransparencyLogEntry{ + IntegratedTime: decamillennium, + KindVersion: &rekor_pb.KindVersion{ + Kind: "test_kind", + }, + } + marshalledEntry, err := proto.Marshal(testEntry) + if err != nil { + t.Fatal(err) + } + + testCases := []struct { + desc string + entryID string + subjects []string + entry *rekor_pb.TransparencyLogEntry + + wantError bool + want *events_pb.CloudEvent + }{ + { + desc: "missing ID", + subjects: []string{"test@rekor.dev"}, + entry: testEntry, + wantError: true, + }, + { + desc: "valid", + entryID: "test-id", + subjects: []string{"test@rekor.dev", "foo@bar.baz"}, // Output should be sorted. + entry: testEntry, + want: &events_pb.CloudEvent{ + SpecVersion: events.CloudEventsSpecVersion, + Id: "test-id", + Source: Source, + Type: Name, + Attributes: map[string]*events_pb.CloudEvent_CloudEventAttributeValue{ + "time": {Attr: &events_pb.CloudEvent_CloudEventAttributeValue_CeTimestamp{ + CeTimestamp: ×tamppb.Timestamp{Seconds: decamillennium}, + }}, + "rekor_entry_kind": {Attr: &events_pb.CloudEvent_CloudEventAttributeValue_CeString{ + CeString: "test_kind", + }}, + "rekor_signing_subjects": {Attr: &events_pb.CloudEvent_CloudEventAttributeValue_CeString{ + CeString: "foo@bar.baz,test@rekor.dev", + }}, + }, + Data: &events_pb.CloudEvent_ProtoData{ + ProtoData: &anypb.Any{ + Value: marshalledEntry, + TypeUrl: string(testEntry.ProtoReflect().Descriptor().FullName()), + }, + }, + }, + }, + } + for _, tc := range testCases { + tc := tc + t.Run(tc.desc, func(t *testing.T) { + t.Parallel() + event, err := New(tc.entryID, tc.entry, tc.subjects) + gotErr := err != nil + if gotErr != tc.wantError { + t.Fatalf("New() err = %v, want %v", gotErr, tc.wantError) + } + if err != nil { + return + } + msg, err := event.Proto() + if err != nil { + t.Fatal(err) + } + if diff := cmp.Diff(msg, tc.want, protocmp.Transform()); diff != "" { + t.Errorf("New() unexpected diff:\n%s", diff) + } + }) + } +} diff --git a/pkg/events/types.go b/pkg/events/types.go new file mode 100644 index 000000000..2dd13f458 --- /dev/null +++ b/pkg/events/types.go @@ -0,0 +1,100 @@ +// 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. + +package events + +import ( + "fmt" + "sync" + + "google.golang.org/protobuf/reflect/protoreflect" +) + +var ( + registeredEventTypes = map[string]*EventType{} + mu sync.Mutex +) + +// EventType describes the type of an event. +type EventType struct { + name string + source string + desc protoreflect.MessageDescriptor +} + +// Name returns the unique name for the event type. +func (t EventType) Name() string { + return t.name +} + +// Source returns the source for the event type. +func (t EventType) Source() string { + return t.source +} + +// Descriptor returns the message descriptor for messages of the event type. +func (t EventType) Descriptor() protoreflect.MessageDescriptor { + return t.desc +} + +// RegisterType registers a new event type. It is intended for use in init() +// functions for each event type. It will panic if errors are encountered. +func RegisterType(name, source string, desc protoreflect.MessageDescriptor) *EventType { + mu.Lock() + defer mu.Unlock() + + if name == "" { + panic("event name must be set") + } + if source == "" { + panic("event source must be set") + } + if desc == nil { + panic("event descriptor must be set") + } + if _, ok := registeredEventTypes[name]; ok { + panic("event has already been registered: " + name) + } + ty := &EventType{ + name: name, + source: source, + desc: desc, + } + registeredEventTypes[name] = ty + return ty +} + +// EventNotFoundError indicates that no matching PubSub provider was found. +type EventNotFoundError struct { + name string +} + +func (e *EventNotFoundError) Error() string { + return fmt.Sprintf("event type not found: %s", e.name) +} + +// Get returns an event type by name. +func Get(name string) (*EventType, error) { + v, ok := registeredEventTypes[name] + if !ok { + return nil, &EventNotFoundError{name: name} + } + return v, nil +} + +// RegisteredTypes returns a map of all registered event types. The key is the +// event type name. +func RegisteredTypes() map[string]*EventType { + return registeredEventTypes +} diff --git a/pkg/fuzz/alpine_utils.go b/pkg/fuzz/alpine_utils.go new file mode 100644 index 000000000..1bb611302 --- /dev/null +++ b/pkg/fuzz/alpine_utils.go @@ -0,0 +1,348 @@ +// +// 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. + +package fuzz + +import ( + "archive/tar" + "bytes" + "compress/gzip" + "fmt" + "os" + "strings" + + fuzz "github.com/AdamKorcz/go-fuzz-headers-1" + "github.com/sigstore/rekor/pkg/types" +) + +// Allows the fuzzer to create a .SIGN filename +func getSignFilename(ff *fuzz.ConsumeFuzzer) (string, error) { + keyName, err := ff.GetString() + if err != nil { + return "", err + } + var b strings.Builder + b.WriteString(".SIGN.RSA.") + b.WriteString(keyName) + b.WriteString(".rsa.pub") + return b.String(), nil +} + +// createPkgInfoFileContents creates a structured pkginfo file +// +// .PKGINFO files look like this: +// +// # Generated by abuild 3.9.0-r2 +// # using fakeroot version 1.25.3 +// # Wed Jul 6 19:09:49 UTC 2022 +// pkgname = busybox +// pkgver = 1.35.0-r18 +// pkgdesc = Size optimized toolbox of many common UNIX utilities +// url = https://busybox.net/ +// builddate = 1657134589 +// packager = Buildozer +// size = 958464 +// arch = x86_64 +// origin = busybox +// commit = 332d2fff53cd4537d415e15e55e8ceb6fe6eaedb +// maintainer = Sören Tempel +// provider_priority = 100 +// license = GPL-2.0-only +// replaces = busybox-initscripts +// provides = /bin/sh +// triggers = /bin /usr/bin /sbin /usr/sbin /lib/modules/* +// # automatically detected: +// provides = cmd:busybox=1.35.0-r18 +// provides = cmd:sh=1.35.0-r18 +// depend = so:libc.musl-x86_64.so.1 +// datahash = 7d3351ac6c3ebaf18182efb5390061f50d077ce5ade60a15909d91278f70ada7 +func createPkgInfoFileContents(ff *fuzz.ConsumeFuzzer) ([]byte, error) { + var b strings.Builder + noOfRows, err := ff.GetInt() + if err != nil { + return []byte(""), err + } + + // Comments at the top of the pkginfo file + header, err := ff.GetBytes() + if err != nil { + return []byte(""), err + } + b.Write(header) + + for i := 0; i < noOfRows; i++ { + key, err := ff.GetBytes() + if err != nil { + return []byte(""), err + } + value, err := ff.GetBytes() + if err != nil { + return []byte(""), err + } + b.Write(key) + b.Write([]byte(" = ")) + b.Write(value) + b.WriteString("\n") + } + return []byte(b.String()), nil +} + +// Adds a .SIGN file to tarBytes +func addSignFile(ff *fuzz.ConsumeFuzzer, tarFiles []*fuzz.TarFile) ([]*fuzz.TarFile, error) { + SIGNFileContents, err := ff.GetBytes() + if err != nil { + return tarFiles, err + } + + SIGNFileName, err := getSignFilename(ff) + if err != nil { + return tarFiles, err + } + signFile := &fuzz.TarFile{ + Body: SIGNFileContents, + Hdr: &tar.Header{ + Name: SIGNFileName, + Mode: 0644, + Size: int64(len(SIGNFileContents)), + Typeflag: tar.TypeReg, + Gid: 0, + Uid: 0, + }, + } + tarFiles = append(tarFiles, signFile) + + return tarFiles, nil +} + +// Allows the fuzzer to randomize whether a .SIGN file should +// be added to tarBytes +func shouldAddSignFile(ff *fuzz.ConsumeFuzzer, tarFiles []*fuzz.TarFile) bool { + shouldRequireSIGNFile, err := ff.GetBool() + if err != nil { + return false + } + if shouldRequireSIGNFile { + for _, tarFile := range tarFiles { + if strings.HasPrefix(tarFile.Hdr.Name, ".SIGN") { + return false + } + } + return true + } + return false +} + +// Allows the fuzzer to randomize whether a .PKGINFO file should +// be added to tarBytes +func shouldAddPkgInfoFile(ff *fuzz.ConsumeFuzzer, tarFiles []*fuzz.TarFile) bool { + shouldRequirePKGINFOFile, err := ff.GetBool() + if err != nil { + return false + } + if shouldRequirePKGINFOFile { + for _, tarFile := range tarFiles { + if strings.HasPrefix(tarFile.Hdr.Name, ".PKGINFO") { + return false + } + } + return true + } + return false +} + +// Adds the .PKGINFO file to the tar files +func addPkgInfoFile(ff *fuzz.ConsumeFuzzer, tarFiles []*fuzz.TarFile) ([]*fuzz.TarFile, error) { + tarFile := &fuzz.TarFile{} + PKGINFOFileContents, err := createPkgInfoFileContents(ff) + if err != nil { + return tarFiles, err + } + tarFile.Body = PKGINFOFileContents + tarFile.Hdr = &tar.Header{ + Name: ".PKGINFO", + Mode: 0644, + Size: int64(len(PKGINFOFileContents)), + Typeflag: tar.TypeReg, + Gid: 0, + Uid: 0, + } + + return tarFiles, nil +} + +func AlpineArtifactBytes(ff *fuzz.ConsumeFuzzer) ([]byte, error) { + var tarFiles, tarFiles2 []*fuzz.TarFile + var err error + + tarFiles, err = ff.TarFiles() + if err != nil { + return []byte(""), err + } + if shouldAddSignFile(ff, tarFiles) { + tarFiles, err = addSignFile(ff, tarFiles) + if err != nil { + return []byte(""), err + } + } + + tarFiles2, err = ff.TarFiles() + if err != nil { + return []byte(""), err + } + + if shouldAddPkgInfoFile(ff, tarFiles2) { + tarFiles2, err = addPkgInfoFile(ff, tarFiles2) + if err != nil { + return []byte(""), err + } + } + + return concatenateTarArchives(tarFiles, tarFiles2) +} + +func concatenateTarArchives(tarFiles1 []*fuzz.TarFile, tarFiles2 []*fuzz.TarFile) ([]byte, error) { + var buf1, buf2 bytes.Buffer + var err error + + tw1 := tar.NewWriter(&buf1) + for _, tf := range tarFiles1 { + err = tw1.WriteHeader(tf.Hdr) + if err != nil { + return []byte(""), err + } + _, err = tw1.Write(tf.Body) + if err != nil { + return []byte(""), err + } + } + tw1.Close() + tarBytes := buf1.Bytes() + + tw2 := tar.NewWriter(&buf2) + for _, tf := range tarFiles2 { + err = tw2.WriteHeader(tf.Hdr) + if err != nil { + return []byte(""), err + } + _, err = tw2.Write(tf.Body) + if err != nil { + return []byte(""), err + } + } + tw2.Close() + tarBytes2 := buf2.Bytes() + + var b1 bytes.Buffer + w1 := gzip.NewWriter(&b1) + defer w1.Close() + _, err = w1.Write(tarBytes) + if err != nil { + return []byte(""), err + } + w1.Close() + + var b2 bytes.Buffer + w2 := gzip.NewWriter(&b2) + defer w2.Close() + _, err = w2.Write(tarBytes2) + if err != nil { + return []byte(""), err + } + w2.Close() + concatenated := append(b1.Bytes(), b2.Bytes()...) + return concatenated, nil +} + +func setAlpineArtifactFields(ff *fuzz.ConsumeFuzzer, props *types.ArtifactProperties) (func(), error) { + cleanup := func() {} + + err := setArtifactHash(ff, props) + if err != nil { + return cleanup, err + } + + artifactBytes, err := AlpineArtifactBytes(ff) + if err != nil { + return cleanup, err + } + + shouldSetArtifactBytes, err := ff.GetBool() + if err != nil { + return cleanup, err + } + + if shouldSetArtifactBytes { + props.ArtifactBytes = artifactBytes + return func() { + // do nothing + }, nil + } + artifactFile, err := createAbsFile(ff, "ArtifactFile", artifactBytes) + cleanup = func() { + os.Remove("ArtifactFile") + } + props.ArtifactPath = artifactFile + return cleanup, err +} + +// Creates an ArtifactProperties with values determined by the fuzzer +func CreateAlpineProps(ff *fuzz.ConsumeFuzzer) (types.ArtifactProperties, func(), error) { + props := &types.ArtifactProperties{} + + cleanupArtifactFile, err := setAlpineArtifactFields(ff, props) + if err != nil { + return *props, cleanupArtifactFile, err + } + if props.ArtifactPath == nil && props.ArtifactBytes == nil { + return *props, cleanupArtifactFile, fmt.Errorf("ArtifactPath and ArtifactBytes cannot both be nil") + } + + err = setAdditionalAuthenticatedData(ff, props) + if err != nil { + return *props, cleanupArtifactFile, fmt.Errorf("Failed setting AdditionalAuthenticatedData") + } + + cleanupSignatureFile, err := setSignatureFields(ff, props) + if err != nil { + return *props, func() { + cleanupArtifactFile() + cleanupSignatureFile() + }, fmt.Errorf("failed setting signature fields: %v", err) + } + + cleanupPublicKeyFile, err := setPublicKeyFields(ff, props) + if err != nil { + return *props, func() { + cleanupArtifactFile() + cleanupSignatureFile() + cleanupPublicKeyFile() + }, fmt.Errorf("failed setting public key fields: %v", err) + } + + err = setPKIFormat(ff, props) + if err != nil { + return *props, func() { + cleanupArtifactFile() + cleanupSignatureFile() + cleanupPublicKeyFile() + }, fmt.Errorf("failed setting PKI Format: %v", err) + } + + return *props, func() { + cleanupArtifactFile() + cleanupSignatureFile() + cleanupPublicKeyFile() + }, nil +} diff --git a/pkg/fuzz/fuzz_utils.go b/pkg/fuzz/fuzz_utils.go new file mode 100644 index 000000000..6f3abd89b --- /dev/null +++ b/pkg/fuzz/fuzz_utils.go @@ -0,0 +1,286 @@ +// +// Copyright 2022 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 fuzz + +import ( + "archive/zip" + "bytes" + "fmt" + "net/url" + "os" + "path/filepath" + + "go.uber.org/zap" + "go.uber.org/zap/zapcore" + + fuzz "github.com/AdamKorcz/go-fuzz-headers-1" + + "github.com/sigstore/rekor/pkg/log" + "github.com/sigstore/rekor/pkg/types" +) + +// Sets ArtifactHash +func setArtifactHash(ff *fuzz.ConsumeFuzzer, props *types.ArtifactProperties) error { + artifactHash, err := ff.GetString() + if err != nil { + return err + } + props.ArtifactHash = artifactHash + return nil +} + +// creates a file on disk and returns the url of it. +func createAbsFile(_ *fuzz.ConsumeFuzzer, fileName string, fileContents []byte) (*url.URL, error) { + file, err := os.Create(fileName) + if err != nil { + return nil, err + } + defer file.Close() + + filePath, err := filepath.Abs(fileName) + if err != nil { + return nil, err + } + fileURL, err := url.Parse(filePath) + if err != nil { + return nil, err + } + _, err = file.Write(fileContents) + if err != nil { + return nil, err + } + return fileURL, err +} + +// Sets the signature fields of a props. +// It either sets SignatureBytes or SignaturePath +func setSignatureFields(ff *fuzz.ConsumeFuzzer, props *types.ArtifactProperties) (func(), error) { + cleanup := func() {} + shouldSetSignatureBytes, err := ff.GetBool() + if err != nil { + return cleanup, err + } + + signatureBytes, err := ff.GetBytes() + if err != nil { + return cleanup, err + } + + if shouldSetSignatureBytes { + props.SignatureBytes = signatureBytes + return cleanup, nil + } + signatureURL, err := createAbsFile(ff, "SignatureFile", signatureBytes) + + if err != nil { + os.Remove("SignatureFile") + return cleanup, err + } + props.SignaturePath = signatureURL + return func() { + os.Remove("SignatureFile") + }, nil + +} + +func setPublicKeyFields(ff *fuzz.ConsumeFuzzer, props *types.ArtifactProperties) (func(), error) { + cleanup := func() {} + + shouldSetPublicKeyBytes, err := ff.GetBool() + if err != nil { + return cleanup, err + } + + if shouldSetPublicKeyBytes { + publicKeyBytes := make([][]byte, 0) + err := ff.GenerateStruct(&publicKeyBytes) + if err != nil || len(publicKeyBytes) == 0 { + return cleanup, err + } + props.PublicKeyBytes = publicKeyBytes + return cleanup, nil + } + publicKeyBytes, err := ff.GetBytes() + if err != nil { + return cleanup, err + } + publicKeyURL, err := createAbsFile(ff, "PublicKeyFile", publicKeyBytes) + if err != nil { + os.Remove("PublicKeyFile") + return cleanup, err + } + props.PublicKeyPaths = []*url.URL{publicKeyURL} + return func() { + os.Remove("PublicKeyFile") + }, nil +} + +// Sets the "AdditionalAuthenticatedData" field of the props +func setAdditionalAuthenticatedData(ff *fuzz.ConsumeFuzzer, props *types.ArtifactProperties) error { + shouldSetAdditionalAuthenticatedData, err := ff.GetBool() + if err != nil { + return err + } + if shouldSetAdditionalAuthenticatedData { + additionalAuthenticatedData, err := ff.GetBytes() + if err != nil { + return err + } + props.AdditionalAuthenticatedData = additionalAuthenticatedData + } + return nil +} + +// Sets the PKI format if the fuzzer decides to. +func setPKIFormat(ff *fuzz.ConsumeFuzzer, props *types.ArtifactProperties) error { + shouldSetPKIFormat, err := ff.GetBool() + if err != nil { + return err + } + + if shouldSetPKIFormat { + pkiFormat, err := ff.GetString() + if err != nil { + return err + } + props.PKIFormat = pkiFormat + } + + return nil +} + +func createArtifactFiles(ff *fuzz.ConsumeFuzzer, artifactType string) ([]*fuzz.TarFile, error) { + switch artifactType { + case "jarV001": + return createJarArtifactFiles(ff) + default: + return createDefaultArtifactFiles(ff) + } +} + +func createDefaultArtifactFiles(ff *fuzz.ConsumeFuzzer) ([]*fuzz.TarFile, error) { + var files []*fuzz.TarFile + files, err := ff.TarFiles() + if err != nil { + return files, err + } + if len(files) <= 1 { + return files, err + } + for _, file := range files { + if len(file.Body) == 0 { + return files, fmt.Errorf("Created an empty file") + } + } + return files, nil +} + +// Creates an ArtifactProperties with values determined by the fuzzer +func CreateProps(ff *fuzz.ConsumeFuzzer, fuzzType string) (types.ArtifactProperties, []func(), error) { + var cleanups []func() + + props := &types.ArtifactProperties{} + + err := setArtifactHash(ff, props) + if err != nil { + return *props, cleanups, err + } + + artifactFiles, err := createArtifactFiles(ff, fuzzType) + if err != nil { + return *props, cleanups, err + } + + err = setAdditionalAuthenticatedData(ff, props) + if err != nil { + return *props, cleanups, fmt.Errorf("Failed setting AdditionalAuthenticatedData") + } + + cleanupSignatureFile, err := setSignatureFields(ff, props) + if err != nil { + return *props, cleanups, fmt.Errorf("failed setting signature fields: %v", err) + } + cleanups = append(cleanups, cleanupSignatureFile) + + cleanupPublicKeyFile, err := setPublicKeyFields(ff, props) + if err != nil { + return *props, cleanups, fmt.Errorf("failed setting public key fields: %v", err) + } + cleanups = append(cleanups, cleanupPublicKeyFile) + + err = setPKIFormat(ff, props) + if err != nil { + return *props, cleanups, fmt.Errorf("failed setting PKI Format: %v", err) + } + + artifactBytes, err := tarFilesToBytes(artifactFiles, fuzzType) + if err != nil { + return *props, cleanups, fmt.Errorf("failed converting artifact bytes: %v", err) + } + + setArtifactBytes, err := ff.GetBool() + if err != nil { + return *props, cleanups, fmt.Errorf("failed converting artifact bytes: %v", err) + } + if setArtifactBytes { + props.ArtifactBytes = artifactBytes + } else { + artifactFile, err := createAbsFile(ff, "ArtifactFile", artifactBytes) + cleanups = append(cleanups, func() { os.Remove("ArtifactFile") }) + if err != nil { + return *props, cleanups, fmt.Errorf("failed converting artifact bytes: %v", err) + } + props.ArtifactPath = artifactFile + } + + props.ArtifactBytes = artifactBytes + return *props, cleanups, nil +} + +func tarFilesToBytes(artifactFiles []*fuzz.TarFile, artifactType string) ([]byte, error) { + switch artifactType { + case "jarV001": + return tarfilesToJar(artifactFiles) + default: + return defaultTarToBytes(artifactFiles) + } +} + +func defaultTarToBytes(artifactFiles []*fuzz.TarFile) ([]byte, error) { + b := new(bytes.Buffer) + w := zip.NewWriter(b) + + for _, file := range artifactFiles { + f, err := w.Create(file.Hdr.Name) + if err != nil { + continue + } + _, _ = f.Write(file.Body) + } + + w.Close() + return b.Bytes(), nil +} + +func SetFuzzLogger() { + config := zap.NewProductionConfig() + config.Level = zap.NewAtomicLevelAt(zapcore.FatalLevel) + logger, err := config.Build() + if err != nil { + panic(err) + } + log.Logger = logger.Named("rekor-fuzz-logger").Sugar() +} diff --git a/pkg/fuzz/jar_utils.go b/pkg/fuzz/jar_utils.go new file mode 100644 index 000000000..53ebc3ea5 --- /dev/null +++ b/pkg/fuzz/jar_utils.go @@ -0,0 +1,212 @@ +// +// 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. + +package fuzz + +import ( + "archive/tar" + "archive/zip" + "bytes" + "context" + "crypto" + "crypto/rsa" + "crypto/x509" + "encoding/pem" + "fmt" + "os" + "time" + + fuzz "github.com/AdamKorcz/go-fuzz-headers-1" + + "github.com/sassoftware/relic/lib/zipslicer" + "github.com/sassoftware/relic/v7/lib/certloader" + "github.com/sassoftware/relic/v7/lib/signjar" +) + +var ( + CertPrivateKey *rsa.PrivateKey + Certificate *x509.Certificate +) + +// copy pasted from rekor/pkg/pki/x509/e2e.go +const RSACert = `-----BEGIN CERTIFICATE----- +MIIDOjCCAiKgAwIBAgIUEP925shVBKERFCsymdSqESLZFyMwDQYJKoZIhvcNAQEL +BQAwHzEdMBsGCSqGSIb3DQEJARYOdGVzdEByZWtvci5kZXYwHhcNMjEwNDIxMjAy +ODAzWhcNMjEwNTIxMjAyODAzWjAfMR0wGwYJKoZIhvcNAQkBFg50ZXN0QHJla29y +LmRldjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN8KiP08rFIik4GN +W8/sHSXxDopeDBLEQEihsyXXWesfYW/q59lFaCZrsTetlyNEzKDJ+JrpIHwoGOo4 +EwefFfvy2nkgPFs9aeIDsYZNZnIGxeB8sUfsZUYGHx+Ikm18vhM//GYzNjjuvHyq ++CWRAOS12ZISa99iah/lIhcP8IEj1gPGldAH0QFx3XpCePAdQocSU6ziVkj054/x +NJXy1bKySrVw7gvE9LxZlVO9urSOnzg7BBOla0mob8NRDVB8yN+LG365q4IMDzuI +jAEL6sLtoJ9pcemo1rIfNOhSLYlzfg7oszJ8eCjASNCCcp6EKVjhW7LRoldC8oGZ +EOrKM78CAwEAAaNuMGwwHQYDVR0OBBYEFGjs8EHKT3x1itwwptJLuQQg/hQcMB8G +A1UdIwQYMBaAFGjs8EHKT3x1itwwptJLuQQg/hQcMA8GA1UdEwEB/wQFMAMBAf8w +GQYDVR0RBBIwEIEOdGVzdEByZWtvci5kZXYwDQYJKoZIhvcNAQELBQADggEBAAHE +bYuePN3XpM7pHoCz6g4uTHu0VrezqJyK1ohysgWJmSJzzazUeISXk0xWnHPk1Zxi +kzoEuysI8b0P7yodMA8e16zbIOL6QbGe3lNXYqRIg+bl+4OPFGVMX8xHNZmeh0kD +vX1JVS+y9uyo4/z/pm0JhaSCn85ft/Y5uXMQYn1wFR5DAcJH+iWjNX4fipGxGRE9 +Cy0DjFnYJ3SRY4HPQ0oUSQmyhrwe2DiYzeqtbL2KJBXPcFQKWhkf/fupdYFljvcH +d9NNfRb0p2oFGG/J0ROg9pEcP1/aZP5k8P2pRdt3y7h1MAtmg2bgEdugZgXwAUmM +BmU8k2FeTuqV15piPCE= +-----END CERTIFICATE-----` + +// copy pasted from rekor/pkg/pki/x509/e2e.go +const RSAKey = `-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDfCoj9PKxSIpOB +jVvP7B0l8Q6KXgwSxEBIobMl11nrH2Fv6ufZRWgma7E3rZcjRMygyfia6SB8KBjq +OBMHnxX78tp5IDxbPWniA7GGTWZyBsXgfLFH7GVGBh8fiJJtfL4TP/xmMzY47rx8 +qvglkQDktdmSEmvfYmof5SIXD/CBI9YDxpXQB9EBcd16QnjwHUKHElOs4lZI9OeP +8TSV8tWyskq1cO4LxPS8WZVTvbq0jp84OwQTpWtJqG/DUQ1QfMjfixt+uauCDA87 +iIwBC+rC7aCfaXHpqNayHzToUi2Jc34O6LMyfHgowEjQgnKehClY4Vuy0aJXQvKB +mRDqyjO/AgMBAAECggEBAIHOAs3Gis8+WjRSjXVjh882DG1QsJwXZQYgPT+vpiAl +YjKdNpOHRkbd9ARgXY5kEuccxDd7p7E6MM3XFpQf7M51ltpZfWboRgAIgD+WOiHw +eSbdytr95C6tj11twTJBH+naGk1sTokxv7aaVdKfIjL49oeBexBFmVe4pW9gkmrE +1z1y1a0RohqbZ0kprYPWjz5UhsNqbCzgkdDqS7IrcOwVg6zvKYFjHnqIHqaJXVif +FgIfoNt7tz+12FTHI+6OkKoN3YCJueaxneBhITXm6RLOpQWa9qhdUPbkJ9vQNfph +Qqke4faaxKY9UDma+GpEHR016AWufZp92pd9wQkDn0kCgYEA7w/ZizAkefHoZhZ8 +Isn/fYu4fdtUaVgrnGUVZobiGxWrHRU9ikbAwR7UwbgRSfppGiJdAMq1lyH2irmb +4OHU64rjuYSlIqUWHLQHWmqUbLUvlDojH/vdmH/Zn0AbrLZaimC5UCjK3Eb7sAMq +G0tGeDX2JraQvx7KrbC6peTaaaMCgYEA7tgZBiRCQJ7+mNu+gX9x6OXtjsDCh516 +vToRLkxWc7LAbC9LKsuEHl4e3vy1PY/nyuv12Ng2dBq4WDXozAmVgz0ok7rRlIFp +w8Yj8o/9KuGZkD/7tw/pLsVc9Q3Wf0ACrnAAh7+3dAvn3yg+WHwXzqWIbrseDPt9 +ILCfUoNDpzUCgYAKFCX8y0PObFd67lm/cbq2xUw66iNN6ay1BEH5t5gSwkAbksis +ar03pyAbJrJ75vXFZ0t6fBFZ1NG7GYYr3fmHEKz3JlN7+W/MN/7TXgjx6FWgLy9J +6ul1w3YeU6qXBn0ctmU5ru6WiNuVmRyOWAcZjFTbXvkNRbQPzJKh6dsXdwKBgA1D +FIihxMf/zBVCxl48bF/JPJqbm3GaTfFp4wBWHsrH1yVqrtrOeCSTh1VMZOfpMK60 +0W7b+pIR1cCYJbgGpDWoVLN3QSHk2bGUM/TJB/60jilTVC/DA2ikbtfwj8N7E2sK +Lw1amN4ptxNOEcAqC8xepqe3XiDMahNBm2cigMQtAoGBAKwrXvss2BKz+/6poJQU +A0c7jhMN8M9Y5S2Ockw07lrQeAgfu4q+/8ztm0NeHJbk01IJvJY5Nt7bSgwgNVlo +j7vR2BMAc9U73Ju9aeTl/L6GqmZyA+Ojhl5gA5DPZYqNiqi93ydgRaI6n4+o3dI7 +5wnr40AmbuKCDvMOvN7nMybL +-----END PRIVATE KEY-----` + +// copy pasted from rekor/pkg/pki/x509/e2e.go +func init() { + p, _ := pem.Decode([]byte(RSAKey)) + priv, err := x509.ParsePKCS8PrivateKey(p.Bytes) + if err != nil { + panic(err) + } + cpk, ok := priv.(*rsa.PrivateKey) + if !ok { + panic("unsuccessful conversion") + } + CertPrivateKey = cpk + + p, _ = pem.Decode([]byte(RSACert)) + Certificate, err = x509.ParseCertificate(p.Bytes) + if err != nil { + panic(err) + } +} + +// Creates jar artifact files. +func createJarArtifactFiles(ff *fuzz.ConsumeFuzzer) ([]*fuzz.TarFile, error) { + var files []*fuzz.TarFile + files, err := ff.TarFiles() + if err != nil { + return files, err + } + if len(files) <= 1 { + return files, err + } + for _, file := range files { + if len(file.Body) == 0 { + return files, fmt.Errorf("Created an empty file") + } + } + + // add "META-INF/MANIFEST.MF" + mfContents, err := ff.GetBytes() + if err != nil { + return files, err + } + + // check the manifest early. This is an inexpensive check, + // so we want to call it before compressing. + _, err = signjar.ParseManifest(mfContents) + if err != nil { + return files, err + } + + files = append(files, &fuzz.TarFile{ + Hdr: &tar.Header{ + Name: "META-INF/MANIFEST.MF", + Size: int64(len(mfContents)), + Mode: 0o600, + ModTime: time.Unix(int64(123), int64(456)), + }, + Body: mfContents, + }) + return files, nil +} + +func tarfilesToJar(artifactFiles []*fuzz.TarFile) ([]byte, error) { + var jarBytes []byte + f, err := os.Create("artifactFile") + if err != nil { + return jarBytes, err + } + defer f.Close() + defer os.Remove("artifactFile") + zw := zip.NewWriter(f) + for _, zipFile := range artifactFiles { + jw, err := zw.Create(zipFile.Hdr.Name) + if err != nil { + zw.Close() + return jarBytes, err + } + _, err = jw.Write(zipFile.Body) + if err != nil { + continue + } + } + zw.Close() + err = f.Sync() + if err != nil { + return jarBytes, err + } + buf := bytes.Buffer{} + err = zipslicer.ZipToTar(f, &buf) + if err != nil { + return jarBytes, err + } + + jd, err := signjar.DigestJarStream(&buf, crypto.SHA256) + if err != nil { + os.Remove("artifactFile") + return jarBytes, err + } + c := certloader.Certificate{ + PrivateKey: CertPrivateKey, + Leaf: Certificate, + } + + patch, _, err := jd.Sign(context.Background(), &c, "rekor", false, true, false) + if err != nil { + return jarBytes, err + } + + if err := patch.Apply(f, "artifactFile"); err != nil { + return jarBytes, err + } + f.Close() + + artifactBytes, err := os.ReadFile("artifactFile") + if err != nil { + return jarBytes, err + } + return artifactBytes, nil +} diff --git a/pkg/generated/client/entries/create_log_entry_responses.go b/pkg/generated/client/entries/create_log_entry_responses.go index 0a6486389..68ddd71e5 100644 --- a/pkg/generated/client/entries/create_log_entry_responses.go +++ b/pkg/generated/client/entries/create_log_entry_responses.go @@ -120,6 +120,11 @@ func (o *CreateLogEntryCreated) IsCode(code int) bool { return code == 201 } +// Code gets the status code for the create log entry created response +func (o *CreateLogEntryCreated) Code() int { + return 201 +} + func (o *CreateLogEntryCreated) Error() string { return fmt.Sprintf("[POST /api/v1/log/entries][%d] createLogEntryCreated %+v", 201, o.Payload) } @@ -199,6 +204,11 @@ func (o *CreateLogEntryBadRequest) IsCode(code int) bool { return code == 400 } +// Code gets the status code for the create log entry bad request response +func (o *CreateLogEntryBadRequest) Code() int { + return 400 +} + func (o *CreateLogEntryBadRequest) Error() string { return fmt.Sprintf("[POST /api/v1/log/entries][%d] createLogEntryBadRequest %+v", 400, o.Payload) } @@ -264,6 +274,11 @@ func (o *CreateLogEntryConflict) IsCode(code int) bool { return code == 409 } +// Code gets the status code for the create log entry conflict response +func (o *CreateLogEntryConflict) Code() int { + return 409 +} + func (o *CreateLogEntryConflict) Error() string { return fmt.Sprintf("[POST /api/v1/log/entries][%d] createLogEntryConflict %+v", 409, o.Payload) } @@ -317,11 +332,6 @@ type CreateLogEntryDefault struct { Payload *models.Error } -// Code gets the status code for the create log entry default response -func (o *CreateLogEntryDefault) Code() int { - return o._statusCode -} - // IsSuccess returns true when this create log entry default response has a 2xx status code func (o *CreateLogEntryDefault) IsSuccess() bool { return o._statusCode/100 == 2 @@ -347,6 +357,11 @@ func (o *CreateLogEntryDefault) IsCode(code int) bool { return o._statusCode == code } +// Code gets the status code for the create log entry default response +func (o *CreateLogEntryDefault) Code() int { + return o._statusCode +} + func (o *CreateLogEntryDefault) Error() string { return fmt.Sprintf("[POST /api/v1/log/entries][%d] createLogEntry default %+v", o._statusCode, o.Payload) } diff --git a/pkg/generated/client/entries/get_log_entry_by_index_responses.go b/pkg/generated/client/entries/get_log_entry_by_index_responses.go index 9af719cff..52f0b85f6 100644 --- a/pkg/generated/client/entries/get_log_entry_by_index_responses.go +++ b/pkg/generated/client/entries/get_log_entry_by_index_responses.go @@ -102,6 +102,11 @@ func (o *GetLogEntryByIndexOK) IsCode(code int) bool { return code == 200 } +// Code gets the status code for the get log entry by index o k response +func (o *GetLogEntryByIndexOK) Code() int { + return 200 +} + func (o *GetLogEntryByIndexOK) Error() string { return fmt.Sprintf("[GET /api/v1/log/entries][%d] getLogEntryByIndexOK %+v", 200, o.Payload) } @@ -162,6 +167,11 @@ func (o *GetLogEntryByIndexNotFound) IsCode(code int) bool { return code == 404 } +// Code gets the status code for the get log entry by index not found response +func (o *GetLogEntryByIndexNotFound) Code() int { + return 404 +} + func (o *GetLogEntryByIndexNotFound) Error() string { return fmt.Sprintf("[GET /api/v1/log/entries][%d] getLogEntryByIndexNotFound ", 404) } @@ -193,11 +203,6 @@ type GetLogEntryByIndexDefault struct { Payload *models.Error } -// Code gets the status code for the get log entry by index default response -func (o *GetLogEntryByIndexDefault) Code() int { - return o._statusCode -} - // IsSuccess returns true when this get log entry by index default response has a 2xx status code func (o *GetLogEntryByIndexDefault) IsSuccess() bool { return o._statusCode/100 == 2 @@ -223,6 +228,11 @@ func (o *GetLogEntryByIndexDefault) IsCode(code int) bool { return o._statusCode == code } +// Code gets the status code for the get log entry by index default response +func (o *GetLogEntryByIndexDefault) Code() int { + return o._statusCode +} + func (o *GetLogEntryByIndexDefault) Error() string { return fmt.Sprintf("[GET /api/v1/log/entries][%d] getLogEntryByIndex default %+v", o._statusCode, o.Payload) } diff --git a/pkg/generated/client/entries/get_log_entry_by_uuid_responses.go b/pkg/generated/client/entries/get_log_entry_by_uuid_responses.go index 2200b71d0..e33a3a422 100644 --- a/pkg/generated/client/entries/get_log_entry_by_uuid_responses.go +++ b/pkg/generated/client/entries/get_log_entry_by_uuid_responses.go @@ -102,6 +102,11 @@ func (o *GetLogEntryByUUIDOK) IsCode(code int) bool { return code == 200 } +// Code gets the status code for the get log entry by Uuid o k response +func (o *GetLogEntryByUUIDOK) Code() int { + return 200 +} + func (o *GetLogEntryByUUIDOK) Error() string { return fmt.Sprintf("[GET /api/v1/log/entries/{entryUUID}][%d] getLogEntryByUuidOK %+v", 200, o.Payload) } @@ -162,6 +167,11 @@ func (o *GetLogEntryByUUIDNotFound) IsCode(code int) bool { return code == 404 } +// Code gets the status code for the get log entry by Uuid not found response +func (o *GetLogEntryByUUIDNotFound) Code() int { + return 404 +} + func (o *GetLogEntryByUUIDNotFound) Error() string { return fmt.Sprintf("[GET /api/v1/log/entries/{entryUUID}][%d] getLogEntryByUuidNotFound ", 404) } @@ -193,11 +203,6 @@ type GetLogEntryByUUIDDefault struct { Payload *models.Error } -// Code gets the status code for the get log entry by UUID default response -func (o *GetLogEntryByUUIDDefault) Code() int { - return o._statusCode -} - // IsSuccess returns true when this get log entry by UUID default response has a 2xx status code func (o *GetLogEntryByUUIDDefault) IsSuccess() bool { return o._statusCode/100 == 2 @@ -223,6 +228,11 @@ func (o *GetLogEntryByUUIDDefault) IsCode(code int) bool { return o._statusCode == code } +// Code gets the status code for the get log entry by UUID default response +func (o *GetLogEntryByUUIDDefault) Code() int { + return o._statusCode +} + func (o *GetLogEntryByUUIDDefault) Error() string { return fmt.Sprintf("[GET /api/v1/log/entries/{entryUUID}][%d] getLogEntryByUUID default %+v", o._statusCode, o.Payload) } diff --git a/pkg/generated/client/entries/search_log_query_responses.go b/pkg/generated/client/entries/search_log_query_responses.go index 34013fd69..5be4e3d24 100644 --- a/pkg/generated/client/entries/search_log_query_responses.go +++ b/pkg/generated/client/entries/search_log_query_responses.go @@ -108,6 +108,11 @@ func (o *SearchLogQueryOK) IsCode(code int) bool { return code == 200 } +// Code gets the status code for the search log query o k response +func (o *SearchLogQueryOK) Code() int { + return 200 +} + func (o *SearchLogQueryOK) Error() string { return fmt.Sprintf("[POST /api/v1/log/entries/retrieve][%d] searchLogQueryOK %+v", 200, o.Payload) } @@ -169,6 +174,11 @@ func (o *SearchLogQueryBadRequest) IsCode(code int) bool { return code == 400 } +// Code gets the status code for the search log query bad request response +func (o *SearchLogQueryBadRequest) Code() int { + return 400 +} + func (o *SearchLogQueryBadRequest) Error() string { return fmt.Sprintf("[POST /api/v1/log/entries/retrieve][%d] searchLogQueryBadRequest %+v", 400, o.Payload) } @@ -232,6 +242,11 @@ func (o *SearchLogQueryUnprocessableEntity) IsCode(code int) bool { return code == 422 } +// Code gets the status code for the search log query unprocessable entity response +func (o *SearchLogQueryUnprocessableEntity) Code() int { + return 422 +} + func (o *SearchLogQueryUnprocessableEntity) Error() string { return fmt.Sprintf("[POST /api/v1/log/entries/retrieve][%d] searchLogQueryUnprocessableEntity %+v", 422, o.Payload) } @@ -274,11 +289,6 @@ type SearchLogQueryDefault struct { Payload *models.Error } -// Code gets the status code for the search log query default response -func (o *SearchLogQueryDefault) Code() int { - return o._statusCode -} - // IsSuccess returns true when this search log query default response has a 2xx status code func (o *SearchLogQueryDefault) IsSuccess() bool { return o._statusCode/100 == 2 @@ -304,6 +314,11 @@ func (o *SearchLogQueryDefault) IsCode(code int) bool { return o._statusCode == code } +// Code gets the status code for the search log query default response +func (o *SearchLogQueryDefault) Code() int { + return o._statusCode +} + func (o *SearchLogQueryDefault) Error() string { return fmt.Sprintf("[POST /api/v1/log/entries/retrieve][%d] searchLogQuery default %+v", o._statusCode, o.Payload) } diff --git a/pkg/generated/client/index/search_index_responses.go b/pkg/generated/client/index/search_index_responses.go index 9893d9427..c9205a15c 100644 --- a/pkg/generated/client/index/search_index_responses.go +++ b/pkg/generated/client/index/search_index_responses.go @@ -102,6 +102,11 @@ func (o *SearchIndexOK) IsCode(code int) bool { return code == 200 } +// Code gets the status code for the search index o k response +func (o *SearchIndexOK) Code() int { + return 200 +} + func (o *SearchIndexOK) Error() string { return fmt.Sprintf("[POST /api/v1/index/retrieve][%d] searchIndexOK %+v", 200, o.Payload) } @@ -163,6 +168,11 @@ func (o *SearchIndexBadRequest) IsCode(code int) bool { return code == 400 } +// Code gets the status code for the search index bad request response +func (o *SearchIndexBadRequest) Code() int { + return 400 +} + func (o *SearchIndexBadRequest) Error() string { return fmt.Sprintf("[POST /api/v1/index/retrieve][%d] searchIndexBadRequest %+v", 400, o.Payload) } @@ -205,11 +215,6 @@ type SearchIndexDefault struct { Payload *models.Error } -// Code gets the status code for the search index default response -func (o *SearchIndexDefault) Code() int { - return o._statusCode -} - // IsSuccess returns true when this search index default response has a 2xx status code func (o *SearchIndexDefault) IsSuccess() bool { return o._statusCode/100 == 2 @@ -235,6 +240,11 @@ func (o *SearchIndexDefault) IsCode(code int) bool { return o._statusCode == code } +// Code gets the status code for the search index default response +func (o *SearchIndexDefault) Code() int { + return o._statusCode +} + func (o *SearchIndexDefault) Error() string { return fmt.Sprintf("[POST /api/v1/index/retrieve][%d] searchIndex default %+v", o._statusCode, o.Payload) } diff --git a/pkg/generated/client/pubkey/get_public_key_responses.go b/pkg/generated/client/pubkey/get_public_key_responses.go index 0f3ad7915..9b33f6db0 100644 --- a/pkg/generated/client/pubkey/get_public_key_responses.go +++ b/pkg/generated/client/pubkey/get_public_key_responses.go @@ -96,6 +96,11 @@ func (o *GetPublicKeyOK) IsCode(code int) bool { return code == 200 } +// Code gets the status code for the get public key o k response +func (o *GetPublicKeyOK) Code() int { + return 200 +} + func (o *GetPublicKeyOK) Error() string { return fmt.Sprintf("[GET /api/v1/log/publicKey][%d] getPublicKeyOK %+v", 200, o.Payload) } @@ -136,11 +141,6 @@ type GetPublicKeyDefault struct { Payload *models.Error } -// Code gets the status code for the get public key default response -func (o *GetPublicKeyDefault) Code() int { - return o._statusCode -} - // IsSuccess returns true when this get public key default response has a 2xx status code func (o *GetPublicKeyDefault) IsSuccess() bool { return o._statusCode/100 == 2 @@ -166,6 +166,11 @@ func (o *GetPublicKeyDefault) IsCode(code int) bool { return o._statusCode == code } +// Code gets the status code for the get public key default response +func (o *GetPublicKeyDefault) Code() int { + return o._statusCode +} + func (o *GetPublicKeyDefault) Error() string { return fmt.Sprintf("[GET /api/v1/log/publicKey][%d] getPublicKey default %+v", o._statusCode, o.Payload) } diff --git a/pkg/generated/client/tlog/get_log_info_parameters.go b/pkg/generated/client/tlog/get_log_info_parameters.go index e0ae2cdd3..b2e329427 100644 --- a/pkg/generated/client/tlog/get_log_info_parameters.go +++ b/pkg/generated/client/tlog/get_log_info_parameters.go @@ -30,6 +30,7 @@ import ( "github.com/go-openapi/runtime" cr "github.com/go-openapi/runtime/client" "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" ) // NewGetLogInfoParams creates a new GetLogInfoParams object, @@ -76,6 +77,13 @@ GetLogInfoParams contains all the parameters to send to the API endpoint Typically these are written to a http.Request. */ type GetLogInfoParams struct { + + /* Stable. + + Whether to return a stable checkpoint for the active shard + */ + Stable *bool + timeout time.Duration Context context.Context HTTPClient *http.Client @@ -93,7 +101,18 @@ func (o *GetLogInfoParams) WithDefaults() *GetLogInfoParams { // // All values with no default are reset to their zero value. func (o *GetLogInfoParams) SetDefaults() { - // no default values defined for this parameter + var ( + stableDefault = bool(false) + ) + + val := GetLogInfoParams{ + Stable: &stableDefault, + } + + val.timeout = o.timeout + val.Context = o.Context + val.HTTPClient = o.HTTPClient + *o = val } // WithTimeout adds the timeout to the get log info params @@ -129,6 +148,17 @@ func (o *GetLogInfoParams) SetHTTPClient(client *http.Client) { o.HTTPClient = client } +// WithStable adds the stable to the get log info params +func (o *GetLogInfoParams) WithStable(stable *bool) *GetLogInfoParams { + o.SetStable(stable) + return o +} + +// SetStable adds the stable to the get log info params +func (o *GetLogInfoParams) SetStable(stable *bool) { + o.Stable = stable +} + // WriteToRequest writes these params to a swagger request func (o *GetLogInfoParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Registry) error { @@ -137,6 +167,23 @@ func (o *GetLogInfoParams) WriteToRequest(r runtime.ClientRequest, reg strfmt.Re } var res []error + if o.Stable != nil { + + // query param stable + var qrStable bool + + if o.Stable != nil { + qrStable = *o.Stable + } + qStable := swag.FormatBool(qrStable) + if qStable != "" { + + if err := r.SetQueryParam("stable", qStable); err != nil { + return err + } + } + } + if len(res) > 0 { return errors.CompositeValidationError(res...) } diff --git a/pkg/generated/client/tlog/get_log_info_responses.go b/pkg/generated/client/tlog/get_log_info_responses.go index 62300d684..a010a72fe 100644 --- a/pkg/generated/client/tlog/get_log_info_responses.go +++ b/pkg/generated/client/tlog/get_log_info_responses.go @@ -96,6 +96,11 @@ func (o *GetLogInfoOK) IsCode(code int) bool { return code == 200 } +// Code gets the status code for the get log info o k response +func (o *GetLogInfoOK) Code() int { + return 200 +} + func (o *GetLogInfoOK) Error() string { return fmt.Sprintf("[GET /api/v1/log][%d] getLogInfoOK %+v", 200, o.Payload) } @@ -138,11 +143,6 @@ type GetLogInfoDefault struct { Payload *models.Error } -// Code gets the status code for the get log info default response -func (o *GetLogInfoDefault) Code() int { - return o._statusCode -} - // IsSuccess returns true when this get log info default response has a 2xx status code func (o *GetLogInfoDefault) IsSuccess() bool { return o._statusCode/100 == 2 @@ -168,6 +168,11 @@ func (o *GetLogInfoDefault) IsCode(code int) bool { return o._statusCode == code } +// Code gets the status code for the get log info default response +func (o *GetLogInfoDefault) Code() int { + return o._statusCode +} + func (o *GetLogInfoDefault) Error() string { return fmt.Sprintf("[GET /api/v1/log][%d] getLogInfo default %+v", o._statusCode, o.Payload) } diff --git a/pkg/generated/client/tlog/get_log_proof_responses.go b/pkg/generated/client/tlog/get_log_proof_responses.go index b0975d8e5..f0cf747c1 100644 --- a/pkg/generated/client/tlog/get_log_proof_responses.go +++ b/pkg/generated/client/tlog/get_log_proof_responses.go @@ -102,6 +102,11 @@ func (o *GetLogProofOK) IsCode(code int) bool { return code == 200 } +// Code gets the status code for the get log proof o k response +func (o *GetLogProofOK) Code() int { + return 200 +} + func (o *GetLogProofOK) Error() string { return fmt.Sprintf("[GET /api/v1/log/proof][%d] getLogProofOK %+v", 200, o.Payload) } @@ -165,6 +170,11 @@ func (o *GetLogProofBadRequest) IsCode(code int) bool { return code == 400 } +// Code gets the status code for the get log proof bad request response +func (o *GetLogProofBadRequest) Code() int { + return 400 +} + func (o *GetLogProofBadRequest) Error() string { return fmt.Sprintf("[GET /api/v1/log/proof][%d] getLogProofBadRequest %+v", 400, o.Payload) } @@ -207,11 +217,6 @@ type GetLogProofDefault struct { Payload *models.Error } -// Code gets the status code for the get log proof default response -func (o *GetLogProofDefault) Code() int { - return o._statusCode -} - // IsSuccess returns true when this get log proof default response has a 2xx status code func (o *GetLogProofDefault) IsSuccess() bool { return o._statusCode/100 == 2 @@ -237,6 +242,11 @@ func (o *GetLogProofDefault) IsCode(code int) bool { return o._statusCode == code } +// Code gets the status code for the get log proof default response +func (o *GetLogProofDefault) Code() int { + return o._statusCode +} + func (o *GetLogProofDefault) Error() string { return fmt.Sprintf("[GET /api/v1/log/proof][%d] getLogProof default %+v", o._statusCode, o.Payload) } diff --git a/pkg/generated/models/alpine_v001_schema.go b/pkg/generated/models/alpine_v001_schema.go index 6cf1181b0..250a6125b 100644 --- a/pkg/generated/models/alpine_v001_schema.go +++ b/pkg/generated/models/alpine_v001_schema.go @@ -126,6 +126,7 @@ func (m *AlpineV001Schema) ContextValidate(ctx context.Context, formats strfmt.R func (m *AlpineV001Schema) contextValidatePackage(ctx context.Context, formats strfmt.Registry) error { if m.Package != nil { + if err := m.Package.ContextValidate(ctx, formats); err != nil { if ve, ok := err.(*errors.Validation); ok { return ve.ValidateName("package") @@ -142,6 +143,7 @@ func (m *AlpineV001Schema) contextValidatePackage(ctx context.Context, formats s func (m *AlpineV001Schema) contextValidatePublicKey(ctx context.Context, formats strfmt.Registry) error { if m.PublicKey != nil { + if err := m.PublicKey.ContextValidate(ctx, formats); err != nil { if ve, ok := err.(*errors.Validation); ok { return ve.ValidateName("publicKey") @@ -244,6 +246,11 @@ func (m *AlpineV001SchemaPackage) ContextValidate(ctx context.Context, formats s func (m *AlpineV001SchemaPackage) contextValidateHash(ctx context.Context, formats strfmt.Registry) error { if m.Hash != nil { + + if swag.IsZero(m.Hash) { // not required + return nil + } + if err := m.Hash.ContextValidate(ctx, formats); err != nil { if ve, ok := err.(*errors.Validation); ok { return ve.ValidateName("package" + "." + "hash") diff --git a/pkg/generated/models/cose_v001_schema.go b/pkg/generated/models/cose_v001_schema.go index ea7f467da..2263abd78 100644 --- a/pkg/generated/models/cose_v001_schema.go +++ b/pkg/generated/models/cose_v001_schema.go @@ -116,6 +116,7 @@ func (m *CoseV001Schema) ContextValidate(ctx context.Context, formats strfmt.Reg func (m *CoseV001Schema) contextValidateData(ctx context.Context, formats strfmt.Registry) error { if m.Data != nil { + if err := m.Data.ContextValidate(ctx, formats); err != nil { if ve, ok := err.(*errors.Validation); ok { return ve.ValidateName("data") @@ -240,6 +241,11 @@ func (m *CoseV001SchemaData) ContextValidate(ctx context.Context, formats strfmt func (m *CoseV001SchemaData) contextValidateEnvelopeHash(ctx context.Context, formats strfmt.Registry) error { if m.EnvelopeHash != nil { + + if swag.IsZero(m.EnvelopeHash) { // not required + return nil + } + if err := m.EnvelopeHash.ContextValidate(ctx, formats); err != nil { if ve, ok := err.(*errors.Validation); ok { return ve.ValidateName("data" + "." + "envelopeHash") @@ -256,6 +262,11 @@ func (m *CoseV001SchemaData) contextValidateEnvelopeHash(ctx context.Context, fo func (m *CoseV001SchemaData) contextValidatePayloadHash(ctx context.Context, formats strfmt.Registry) error { if m.PayloadHash != nil { + + if swag.IsZero(m.PayloadHash) { // not required + return nil + } + if err := m.PayloadHash.ContextValidate(ctx, formats); err != nil { if ve, ok := err.(*errors.Validation); ok { return ve.ValidateName("data" + "." + "payloadHash") diff --git a/pkg/generated/models/dsse.go b/pkg/generated/models/dsse.go new file mode 100644 index 000000000..dde562054 --- /dev/null +++ b/pkg/generated/models/dsse.go @@ -0,0 +1,210 @@ +// Code generated by go-swagger; DO NOT EDIT. + +// +// 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 models + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "bytes" + "context" + "encoding/json" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// DSSE DSSE envelope +// +// swagger:model dsse +type DSSE struct { + + // api version + // Required: true + // Pattern: ^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$ + APIVersion *string `json:"apiVersion"` + + // spec + // Required: true + Spec DSSESchema `json:"spec"` +} + +// Kind gets the kind of this subtype +func (m *DSSE) Kind() string { + return "dsse" +} + +// SetKind sets the kind of this subtype +func (m *DSSE) SetKind(val string) { +} + +// UnmarshalJSON unmarshals this object with a polymorphic type from a JSON structure +func (m *DSSE) UnmarshalJSON(raw []byte) error { + var data struct { + + // api version + // Required: true + // Pattern: ^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$ + APIVersion *string `json:"apiVersion"` + + // spec + // Required: true + Spec DSSESchema `json:"spec"` + } + buf := bytes.NewBuffer(raw) + dec := json.NewDecoder(buf) + dec.UseNumber() + + if err := dec.Decode(&data); err != nil { + return err + } + + var base struct { + /* Just the base type fields. Used for unmashalling polymorphic types.*/ + + Kind string `json:"kind"` + } + buf = bytes.NewBuffer(raw) + dec = json.NewDecoder(buf) + dec.UseNumber() + + if err := dec.Decode(&base); err != nil { + return err + } + + var result DSSE + + if base.Kind != result.Kind() { + /* Not the type we're looking for. */ + return errors.New(422, "invalid kind value: %q", base.Kind) + } + + result.APIVersion = data.APIVersion + result.Spec = data.Spec + + *m = result + + return nil +} + +// MarshalJSON marshals this object with a polymorphic type to a JSON structure +func (m DSSE) MarshalJSON() ([]byte, error) { + var b1, b2, b3 []byte + var err error + b1, err = json.Marshal(struct { + + // api version + // Required: true + // Pattern: ^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$ + APIVersion *string `json:"apiVersion"` + + // spec + // Required: true + Spec DSSESchema `json:"spec"` + }{ + + APIVersion: m.APIVersion, + + Spec: m.Spec, + }) + if err != nil { + return nil, err + } + b2, err = json.Marshal(struct { + Kind string `json:"kind"` + }{ + + Kind: m.Kind(), + }) + if err != nil { + return nil, err + } + + return swag.ConcatJSON(b1, b2, b3), nil +} + +// Validate validates this dsse +func (m *DSSE) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateAPIVersion(formats); err != nil { + res = append(res, err) + } + + if err := m.validateSpec(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *DSSE) validateAPIVersion(formats strfmt.Registry) error { + + if err := validate.Required("apiVersion", "body", m.APIVersion); err != nil { + return err + } + + if err := validate.Pattern("apiVersion", "body", *m.APIVersion, `^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$`); err != nil { + return err + } + + return nil +} + +func (m *DSSE) validateSpec(formats strfmt.Registry) error { + + if m.Spec == nil { + return errors.Required("spec", "body", nil) + } + + return nil +} + +// ContextValidate validate this dsse based on the context it is used +func (m *DSSE) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +// MarshalBinary interface implementation +func (m *DSSE) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *DSSE) UnmarshalBinary(b []byte) error { + var res DSSE + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/types/cose/fuzz_test.go b/pkg/generated/models/dsse_schema.go similarity index 60% rename from pkg/types/cose/fuzz_test.go rename to pkg/generated/models/dsse_schema.go index 5bdd8eb40..779562643 100644 --- a/pkg/types/cose/fuzz_test.go +++ b/pkg/generated/models/dsse_schema.go @@ -1,5 +1,7 @@ +// Code generated by go-swagger; DO NOT EDIT. + // -// Copyright 2022 The Sigstore Authors. +// 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. @@ -12,21 +14,16 @@ // 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 cose - -import ( - "context" - "testing" +package models - "github.com/sigstore/rekor/pkg/types" -) +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command -func FuzzCreateProposedEntry(f *testing.F) { - f.Fuzz(func(t *testing.T, version string) { - ctx := context.Background() - brt := New() - props := types.ArtifactProperties{} - _, _ = brt.CreateProposedEntry(ctx, version, props) - }) -} +// DSSESchema DSSE Schema +// +// log entry schema for dsse envelopes +// +// swagger:model dsseSchema +type DSSESchema interface{} diff --git a/pkg/generated/models/dsse_v001_schema.go b/pkg/generated/models/dsse_v001_schema.go new file mode 100644 index 000000000..ec4c32bfb --- /dev/null +++ b/pkg/generated/models/dsse_v001_schema.go @@ -0,0 +1,685 @@ +// Code generated by go-swagger; DO NOT EDIT. + +// +// 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 models + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + "encoding/json" + "strconv" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// DSSEV001Schema DSSE v0.0.1 Schema +// +// # Schema for DSSE envelopes +// +// swagger:model dsseV001Schema +type DSSEV001Schema struct { + + // envelope hash + EnvelopeHash *DSSEV001SchemaEnvelopeHash `json:"envelopeHash,omitempty"` + + // payload hash + PayloadHash *DSSEV001SchemaPayloadHash `json:"payloadHash,omitempty"` + + // proposed content + ProposedContent *DSSEV001SchemaProposedContent `json:"proposedContent,omitempty"` + + // extracted collection of all signatures of the envelope's payload; elements will be sorted by lexicographical order of the base64 encoded signature strings + // Read Only: true + // Min Items: 1 + Signatures []*DSSEV001SchemaSignaturesItems0 `json:"signatures"` +} + +// Validate validates this dsse v001 schema +func (m *DSSEV001Schema) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateEnvelopeHash(formats); err != nil { + res = append(res, err) + } + + if err := m.validatePayloadHash(formats); err != nil { + res = append(res, err) + } + + if err := m.validateProposedContent(formats); err != nil { + res = append(res, err) + } + + if err := m.validateSignatures(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *DSSEV001Schema) validateEnvelopeHash(formats strfmt.Registry) error { + if swag.IsZero(m.EnvelopeHash) { // not required + return nil + } + + if m.EnvelopeHash != nil { + if err := m.EnvelopeHash.Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("envelopeHash") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("envelopeHash") + } + return err + } + } + + return nil +} + +func (m *DSSEV001Schema) validatePayloadHash(formats strfmt.Registry) error { + if swag.IsZero(m.PayloadHash) { // not required + return nil + } + + if m.PayloadHash != nil { + if err := m.PayloadHash.Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("payloadHash") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("payloadHash") + } + return err + } + } + + return nil +} + +func (m *DSSEV001Schema) validateProposedContent(formats strfmt.Registry) error { + if swag.IsZero(m.ProposedContent) { // not required + return nil + } + + if m.ProposedContent != nil { + if err := m.ProposedContent.Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("proposedContent") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("proposedContent") + } + return err + } + } + + return nil +} + +func (m *DSSEV001Schema) validateSignatures(formats strfmt.Registry) error { + if swag.IsZero(m.Signatures) { // not required + return nil + } + + iSignaturesSize := int64(len(m.Signatures)) + + if err := validate.MinItems("signatures", "body", iSignaturesSize, 1); err != nil { + return err + } + + for i := 0; i < len(m.Signatures); i++ { + if swag.IsZero(m.Signatures[i]) { // not required + continue + } + + if m.Signatures[i] != nil { + if err := m.Signatures[i].Validate(formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("signatures" + "." + strconv.Itoa(i)) + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("signatures" + "." + strconv.Itoa(i)) + } + return err + } + } + + } + + return nil +} + +// ContextValidate validate this dsse v001 schema based on the context it is used +func (m *DSSEV001Schema) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if err := m.contextValidateEnvelopeHash(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidatePayloadHash(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateProposedContent(ctx, formats); err != nil { + res = append(res, err) + } + + if err := m.contextValidateSignatures(ctx, formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *DSSEV001Schema) contextValidateEnvelopeHash(ctx context.Context, formats strfmt.Registry) error { + + if m.EnvelopeHash != nil { + + if swag.IsZero(m.EnvelopeHash) { // not required + return nil + } + + if err := m.EnvelopeHash.ContextValidate(ctx, formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("envelopeHash") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("envelopeHash") + } + return err + } + } + + return nil +} + +func (m *DSSEV001Schema) contextValidatePayloadHash(ctx context.Context, formats strfmt.Registry) error { + + if m.PayloadHash != nil { + + if swag.IsZero(m.PayloadHash) { // not required + return nil + } + + if err := m.PayloadHash.ContextValidate(ctx, formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("payloadHash") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("payloadHash") + } + return err + } + } + + return nil +} + +func (m *DSSEV001Schema) contextValidateProposedContent(ctx context.Context, formats strfmt.Registry) error { + + if m.ProposedContent != nil { + + if swag.IsZero(m.ProposedContent) { // not required + return nil + } + + if err := m.ProposedContent.ContextValidate(ctx, formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("proposedContent") + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("proposedContent") + } + return err + } + } + + return nil +} + +func (m *DSSEV001Schema) contextValidateSignatures(ctx context.Context, formats strfmt.Registry) error { + + if err := validate.ReadOnly(ctx, "signatures", "body", []*DSSEV001SchemaSignaturesItems0(m.Signatures)); err != nil { + return err + } + + for i := 0; i < len(m.Signatures); i++ { + + if m.Signatures[i] != nil { + + if swag.IsZero(m.Signatures[i]) { // not required + return nil + } + + if err := m.Signatures[i].ContextValidate(ctx, formats); err != nil { + if ve, ok := err.(*errors.Validation); ok { + return ve.ValidateName("signatures" + "." + strconv.Itoa(i)) + } else if ce, ok := err.(*errors.CompositeError); ok { + return ce.ValidateName("signatures" + "." + strconv.Itoa(i)) + } + return err + } + } + + } + + return nil +} + +// MarshalBinary interface implementation +func (m *DSSEV001Schema) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *DSSEV001Schema) UnmarshalBinary(b []byte) error { + var res DSSEV001Schema + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} + +// DSSEV001SchemaEnvelopeHash Specifies the hash algorithm and value encompassing the entire envelope sent to Rekor +// +// swagger:model DSSEV001SchemaEnvelopeHash +type DSSEV001SchemaEnvelopeHash struct { + + // The hashing function used to compute the hash value + // Required: true + // Enum: [sha256] + Algorithm *string `json:"algorithm"` + + // The value of the computed digest over the entire envelope + // Required: true + Value *string `json:"value"` +} + +// Validate validates this DSSE v001 schema envelope hash +func (m *DSSEV001SchemaEnvelopeHash) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateAlgorithm(formats); err != nil { + res = append(res, err) + } + + if err := m.validateValue(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +var dsseV001SchemaEnvelopeHashTypeAlgorithmPropEnum []interface{} + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["sha256"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + dsseV001SchemaEnvelopeHashTypeAlgorithmPropEnum = append(dsseV001SchemaEnvelopeHashTypeAlgorithmPropEnum, v) + } +} + +const ( + + // DSSEV001SchemaEnvelopeHashAlgorithmSha256 captures enum value "sha256" + DSSEV001SchemaEnvelopeHashAlgorithmSha256 string = "sha256" +) + +// prop value enum +func (m *DSSEV001SchemaEnvelopeHash) validateAlgorithmEnum(path, location string, value string) error { + if err := validate.EnumCase(path, location, value, dsseV001SchemaEnvelopeHashTypeAlgorithmPropEnum, true); err != nil { + return err + } + return nil +} + +func (m *DSSEV001SchemaEnvelopeHash) validateAlgorithm(formats strfmt.Registry) error { + + if err := validate.Required("envelopeHash"+"."+"algorithm", "body", m.Algorithm); err != nil { + return err + } + + // value enum + if err := m.validateAlgorithmEnum("envelopeHash"+"."+"algorithm", "body", *m.Algorithm); err != nil { + return err + } + + return nil +} + +func (m *DSSEV001SchemaEnvelopeHash) validateValue(formats strfmt.Registry) error { + + if err := validate.Required("envelopeHash"+"."+"value", "body", m.Value); err != nil { + return err + } + + return nil +} + +// ContextValidate validate this DSSE v001 schema envelope hash based on the context it is used +func (m *DSSEV001SchemaEnvelopeHash) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +// MarshalBinary interface implementation +func (m *DSSEV001SchemaEnvelopeHash) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *DSSEV001SchemaEnvelopeHash) UnmarshalBinary(b []byte) error { + var res DSSEV001SchemaEnvelopeHash + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} + +// DSSEV001SchemaPayloadHash Specifies the hash algorithm and value covering the payload within the DSSE envelope +// +// swagger:model DSSEV001SchemaPayloadHash +type DSSEV001SchemaPayloadHash struct { + + // The hashing function used to compute the hash value + // Required: true + // Enum: [sha256] + Algorithm *string `json:"algorithm"` + + // The value of the computed digest over the payload within the envelope + // Required: true + Value *string `json:"value"` +} + +// Validate validates this DSSE v001 schema payload hash +func (m *DSSEV001SchemaPayloadHash) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateAlgorithm(formats); err != nil { + res = append(res, err) + } + + if err := m.validateValue(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +var dsseV001SchemaPayloadHashTypeAlgorithmPropEnum []interface{} + +func init() { + var res []string + if err := json.Unmarshal([]byte(`["sha256"]`), &res); err != nil { + panic(err) + } + for _, v := range res { + dsseV001SchemaPayloadHashTypeAlgorithmPropEnum = append(dsseV001SchemaPayloadHashTypeAlgorithmPropEnum, v) + } +} + +const ( + + // DSSEV001SchemaPayloadHashAlgorithmSha256 captures enum value "sha256" + DSSEV001SchemaPayloadHashAlgorithmSha256 string = "sha256" +) + +// prop value enum +func (m *DSSEV001SchemaPayloadHash) validateAlgorithmEnum(path, location string, value string) error { + if err := validate.EnumCase(path, location, value, dsseV001SchemaPayloadHashTypeAlgorithmPropEnum, true); err != nil { + return err + } + return nil +} + +func (m *DSSEV001SchemaPayloadHash) validateAlgorithm(formats strfmt.Registry) error { + + if err := validate.Required("payloadHash"+"."+"algorithm", "body", m.Algorithm); err != nil { + return err + } + + // value enum + if err := m.validateAlgorithmEnum("payloadHash"+"."+"algorithm", "body", *m.Algorithm); err != nil { + return err + } + + return nil +} + +func (m *DSSEV001SchemaPayloadHash) validateValue(formats strfmt.Registry) error { + + if err := validate.Required("payloadHash"+"."+"value", "body", m.Value); err != nil { + return err + } + + return nil +} + +// ContextValidate validate this DSSE v001 schema payload hash based on the context it is used +func (m *DSSEV001SchemaPayloadHash) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + var res []error + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +// MarshalBinary interface implementation +func (m *DSSEV001SchemaPayloadHash) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *DSSEV001SchemaPayloadHash) UnmarshalBinary(b []byte) error { + var res DSSEV001SchemaPayloadHash + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} + +// DSSEV001SchemaProposedContent DSSE v001 schema proposed content +// +// swagger:model DSSEV001SchemaProposedContent +type DSSEV001SchemaProposedContent struct { + + // DSSE envelope specified as a stringified JSON object + // Required: true + Envelope *string `json:"envelope"` + + // collection of all verification material (e.g. public keys or certificates) used to verify signatures over envelope's payload, specified as base64-encoded strings + // Required: true + // Min Items: 1 + Verifiers []strfmt.Base64 `json:"verifiers"` +} + +// Validate validates this DSSE v001 schema proposed content +func (m *DSSEV001SchemaProposedContent) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateEnvelope(formats); err != nil { + res = append(res, err) + } + + if err := m.validateVerifiers(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *DSSEV001SchemaProposedContent) validateEnvelope(formats strfmt.Registry) error { + + if err := validate.Required("proposedContent"+"."+"envelope", "body", m.Envelope); err != nil { + return err + } + + return nil +} + +func (m *DSSEV001SchemaProposedContent) validateVerifiers(formats strfmt.Registry) error { + + if err := validate.Required("proposedContent"+"."+"verifiers", "body", m.Verifiers); err != nil { + return err + } + + iVerifiersSize := int64(len(m.Verifiers)) + + if err := validate.MinItems("proposedContent"+"."+"verifiers", "body", iVerifiersSize, 1); err != nil { + return err + } + + return nil +} + +// ContextValidate validates this DSSE v001 schema proposed content based on context it is used +func (m *DSSEV001SchemaProposedContent) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *DSSEV001SchemaProposedContent) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *DSSEV001SchemaProposedContent) UnmarshalBinary(b []byte) error { + var res DSSEV001SchemaProposedContent + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} + +// DSSEV001SchemaSignaturesItems0 a signature of the envelope's payload along with the verification material for the signature +// +// swagger:model DSSEV001SchemaSignaturesItems0 +type DSSEV001SchemaSignaturesItems0 struct { + + // base64 encoded signature of the payload + // Required: true + // Pattern: ^(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=|[A-Za-z0-9+\/]{4})$ + Signature *string `json:"signature"` + + // verification material that was used to verify the corresponding signature, specified as a base64 encoded string + // Required: true + // Format: byte + Verifier *strfmt.Base64 `json:"verifier"` +} + +// Validate validates this DSSE v001 schema signatures items0 +func (m *DSSEV001SchemaSignaturesItems0) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateSignature(formats); err != nil { + res = append(res, err) + } + + if err := m.validateVerifier(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *DSSEV001SchemaSignaturesItems0) validateSignature(formats strfmt.Registry) error { + + if err := validate.Required("signature", "body", m.Signature); err != nil { + return err + } + + if err := validate.Pattern("signature", "body", *m.Signature, `^(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=|[A-Za-z0-9+\/]{4})$`); err != nil { + return err + } + + return nil +} + +func (m *DSSEV001SchemaSignaturesItems0) validateVerifier(formats strfmt.Registry) error { + + if err := validate.Required("verifier", "body", m.Verifier); err != nil { + return err + } + + return nil +} + +// ContextValidate validates this DSSE v001 schema signatures items0 based on context it is used +func (m *DSSEV001SchemaSignaturesItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *DSSEV001SchemaSignaturesItems0) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *DSSEV001SchemaSignaturesItems0) UnmarshalBinary(b []byte) error { + var res DSSEV001SchemaSignaturesItems0 + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/pkg/generated/models/hashedrekord_v001_schema.go b/pkg/generated/models/hashedrekord_v001_schema.go index 72937c640..f8bf233ed 100644 --- a/pkg/generated/models/hashedrekord_v001_schema.go +++ b/pkg/generated/models/hashedrekord_v001_schema.go @@ -126,6 +126,7 @@ func (m *HashedrekordV001Schema) ContextValidate(ctx context.Context, formats st func (m *HashedrekordV001Schema) contextValidateData(ctx context.Context, formats strfmt.Registry) error { if m.Data != nil { + if err := m.Data.ContextValidate(ctx, formats); err != nil { if ve, ok := err.(*errors.Validation); ok { return ve.ValidateName("data") @@ -142,6 +143,7 @@ func (m *HashedrekordV001Schema) contextValidateData(ctx context.Context, format func (m *HashedrekordV001Schema) contextValidateSignature(ctx context.Context, formats strfmt.Registry) error { if m.Signature != nil { + if err := m.Signature.ContextValidate(ctx, formats); err != nil { if ve, ok := err.(*errors.Validation); ok { return ve.ValidateName("signature") @@ -232,6 +234,11 @@ func (m *HashedrekordV001SchemaData) ContextValidate(ctx context.Context, format func (m *HashedrekordV001SchemaData) contextValidateHash(ctx context.Context, formats strfmt.Registry) error { if m.Hash != nil { + + if swag.IsZero(m.Hash) { // not required + return nil + } + if err := m.Hash.ContextValidate(ctx, formats); err != nil { if ve, ok := err.(*errors.Validation); ok { return ve.ValidateName("data" + "." + "hash") @@ -431,6 +438,11 @@ func (m *HashedrekordV001SchemaSignature) ContextValidate(ctx context.Context, f func (m *HashedrekordV001SchemaSignature) contextValidatePublicKey(ctx context.Context, formats strfmt.Registry) error { if m.PublicKey != nil { + + if swag.IsZero(m.PublicKey) { // not required + return nil + } + if err := m.PublicKey.ContextValidate(ctx, formats); err != nil { if ve, ok := err.(*errors.Validation); ok { return ve.ValidateName("signature" + "." + "publicKey") diff --git a/pkg/generated/models/helm_v001_schema.go b/pkg/generated/models/helm_v001_schema.go index e0942574b..930efc878 100644 --- a/pkg/generated/models/helm_v001_schema.go +++ b/pkg/generated/models/helm_v001_schema.go @@ -126,6 +126,7 @@ func (m *HelmV001Schema) ContextValidate(ctx context.Context, formats strfmt.Reg func (m *HelmV001Schema) contextValidateChart(ctx context.Context, formats strfmt.Registry) error { if m.Chart != nil { + if err := m.Chart.ContextValidate(ctx, formats); err != nil { if ve, ok := err.(*errors.Validation); ok { return ve.ValidateName("chart") @@ -142,6 +143,7 @@ func (m *HelmV001Schema) contextValidateChart(ctx context.Context, formats strfm func (m *HelmV001Schema) contextValidatePublicKey(ctx context.Context, formats strfmt.Registry) error { if m.PublicKey != nil { + if err := m.PublicKey.ContextValidate(ctx, formats); err != nil { if ve, ok := err.(*errors.Validation); ok { return ve.ValidateName("publicKey") @@ -264,6 +266,11 @@ func (m *HelmV001SchemaChart) ContextValidate(ctx context.Context, formats strfm func (m *HelmV001SchemaChart) contextValidateHash(ctx context.Context, formats strfmt.Registry) error { if m.Hash != nil { + + if swag.IsZero(m.Hash) { // not required + return nil + } + if err := m.Hash.ContextValidate(ctx, formats); err != nil { if ve, ok := err.(*errors.Validation); ok { return ve.ValidateName("chart" + "." + "hash") @@ -280,6 +287,7 @@ func (m *HelmV001SchemaChart) contextValidateHash(ctx context.Context, formats s func (m *HelmV001SchemaChart) contextValidateProvenance(ctx context.Context, formats strfmt.Registry) error { if m.Provenance != nil { + if err := m.Provenance.ContextValidate(ctx, formats); err != nil { if ve, ok := err.(*errors.Validation); ok { return ve.ValidateName("chart" + "." + "provenance") @@ -484,6 +492,11 @@ func (m *HelmV001SchemaChartProvenance) ContextValidate(ctx context.Context, for func (m *HelmV001SchemaChartProvenance) contextValidateSignature(ctx context.Context, formats strfmt.Registry) error { if m.Signature != nil { + + if swag.IsZero(m.Signature) { // not required + return nil + } + if err := m.Signature.ContextValidate(ctx, formats); err != nil { if ve, ok := err.(*errors.Validation); ok { return ve.ValidateName("chart" + "." + "provenance" + "." + "signature") diff --git a/pkg/generated/models/intoto_v001_schema.go b/pkg/generated/models/intoto_v001_schema.go index dffbecd33..0c299b1ca 100644 --- a/pkg/generated/models/intoto_v001_schema.go +++ b/pkg/generated/models/intoto_v001_schema.go @@ -112,6 +112,7 @@ func (m *IntotoV001Schema) ContextValidate(ctx context.Context, formats strfmt.R func (m *IntotoV001Schema) contextValidateContent(ctx context.Context, formats strfmt.Registry) error { if m.Content != nil { + if err := m.Content.ContextValidate(ctx, formats); err != nil { if ve, ok := err.(*errors.Validation); ok { return ve.ValidateName("content") @@ -235,6 +236,11 @@ func (m *IntotoV001SchemaContent) ContextValidate(ctx context.Context, formats s func (m *IntotoV001SchemaContent) contextValidateHash(ctx context.Context, formats strfmt.Registry) error { if m.Hash != nil { + + if swag.IsZero(m.Hash) { // not required + return nil + } + if err := m.Hash.ContextValidate(ctx, formats); err != nil { if ve, ok := err.(*errors.Validation); ok { return ve.ValidateName("content" + "." + "hash") @@ -251,6 +257,11 @@ func (m *IntotoV001SchemaContent) contextValidateHash(ctx context.Context, forma func (m *IntotoV001SchemaContent) contextValidatePayloadHash(ctx context.Context, formats strfmt.Registry) error { if m.PayloadHash != nil { + + if swag.IsZero(m.PayloadHash) { // not required + return nil + } + if err := m.PayloadHash.ContextValidate(ctx, formats); err != nil { if ve, ok := err.(*errors.Validation); ok { return ve.ValidateName("content" + "." + "payloadHash") @@ -282,7 +293,7 @@ func (m *IntotoV001SchemaContent) UnmarshalBinary(b []byte) error { return nil } -// IntotoV001SchemaContentHash Specifies the hash algorithm and value encompassing the entire signed envelope +// IntotoV001SchemaContentHash Specifies the hash algorithm and value encompassing the entire signed envelope; this is computed by the rekor server, client-provided values are ignored // // swagger:model IntotoV001SchemaContentHash type IntotoV001SchemaContentHash struct { @@ -392,7 +403,7 @@ func (m *IntotoV001SchemaContentHash) UnmarshalBinary(b []byte) error { return nil } -// IntotoV001SchemaContentPayloadHash Specifies the hash algorithm and value covering the payload within the DSSE envelope +// IntotoV001SchemaContentPayloadHash Specifies the hash algorithm and value covering the payload within the DSSE envelope; this is computed by the rekor server, client-provided values are ignored // // swagger:model IntotoV001SchemaContentPayloadHash type IntotoV001SchemaContentPayloadHash struct { diff --git a/pkg/generated/models/intoto_v002_schema.go b/pkg/generated/models/intoto_v002_schema.go index 86c0b47f5..c2c08ea54 100644 --- a/pkg/generated/models/intoto_v002_schema.go +++ b/pkg/generated/models/intoto_v002_schema.go @@ -95,6 +95,7 @@ func (m *IntotoV002Schema) ContextValidate(ctx context.Context, formats strfmt.R func (m *IntotoV002Schema) contextValidateContent(ctx context.Context, formats strfmt.Registry) error { if m.Content != nil { + if err := m.Content.ContextValidate(ctx, formats); err != nil { if ve, ok := err.(*errors.Validation); ok { return ve.ValidateName("content") @@ -132,7 +133,8 @@ func (m *IntotoV002Schema) UnmarshalBinary(b []byte) error { type IntotoV002SchemaContent struct { // envelope - Envelope *IntotoV002SchemaContentEnvelope `json:"envelope,omitempty"` + // Required: true + Envelope *IntotoV002SchemaContentEnvelope `json:"envelope"` // hash Hash *IntotoV002SchemaContentHash `json:"hash,omitempty"` @@ -164,8 +166,9 @@ func (m *IntotoV002SchemaContent) Validate(formats strfmt.Registry) error { } func (m *IntotoV002SchemaContent) validateEnvelope(formats strfmt.Registry) error { - if swag.IsZero(m.Envelope) { // not required - return nil + + if err := validate.Required("content"+"."+"envelope", "body", m.Envelope); err != nil { + return err } if m.Envelope != nil { @@ -245,6 +248,7 @@ func (m *IntotoV002SchemaContent) ContextValidate(ctx context.Context, formats s func (m *IntotoV002SchemaContent) contextValidateEnvelope(ctx context.Context, formats strfmt.Registry) error { if m.Envelope != nil { + if err := m.Envelope.ContextValidate(ctx, formats); err != nil { if ve, ok := err.(*errors.Validation); ok { return ve.ValidateName("content" + "." + "envelope") @@ -261,6 +265,11 @@ func (m *IntotoV002SchemaContent) contextValidateEnvelope(ctx context.Context, f func (m *IntotoV002SchemaContent) contextValidateHash(ctx context.Context, formats strfmt.Registry) error { if m.Hash != nil { + + if swag.IsZero(m.Hash) { // not required + return nil + } + if err := m.Hash.ContextValidate(ctx, formats); err != nil { if ve, ok := err.(*errors.Validation); ok { return ve.ValidateName("content" + "." + "hash") @@ -277,6 +286,11 @@ func (m *IntotoV002SchemaContent) contextValidateHash(ctx context.Context, forma func (m *IntotoV002SchemaContent) contextValidatePayloadHash(ctx context.Context, formats strfmt.Registry) error { if m.PayloadHash != nil { + + if swag.IsZero(m.PayloadHash) { // not required + return nil + } + if err := m.PayloadHash.ContextValidate(ctx, formats); err != nil { if ve, ok := err.(*errors.Validation); ok { return ve.ValidateName("content" + "." + "payloadHash") @@ -406,6 +420,11 @@ func (m *IntotoV002SchemaContentEnvelope) contextValidateSignatures(ctx context. for i := 0; i < len(m.Signatures); i++ { if m.Signatures[i] != nil { + + if swag.IsZero(m.Signatures[i]) { // not required + return nil + } + if err := m.Signatures[i].ContextValidate(ctx, formats); err != nil { if ve, ok := err.(*errors.Validation); ok { return ve.ValidateName("content" + "." + "envelope" + "." + "signatures" + "." + strconv.Itoa(i)) @@ -448,25 +467,25 @@ type IntotoV002SchemaContentEnvelopeSignaturesItems0 struct { Keyid string `json:"keyid,omitempty"` // public key that corresponds to this signature - // Read Only: true + // Required: true // Format: byte - PublicKey strfmt.Base64 `json:"publicKey,omitempty"` + PublicKey *strfmt.Base64 `json:"publicKey"` // signature of the payload + // Required: true // Format: byte - Sig strfmt.Base64 `json:"sig,omitempty"` + Sig *strfmt.Base64 `json:"sig"` } // Validate validates this intoto v002 schema content envelope signatures items0 func (m *IntotoV002SchemaContentEnvelopeSignaturesItems0) Validate(formats strfmt.Registry) error { - return nil -} - -// ContextValidate validate this intoto v002 schema content envelope signatures items0 based on the context it is used -func (m *IntotoV002SchemaContentEnvelopeSignaturesItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { var res []error - if err := m.contextValidatePublicKey(ctx, formats); err != nil { + if err := m.validatePublicKey(formats); err != nil { + res = append(res, err) + } + + if err := m.validateSig(formats); err != nil { res = append(res, err) } @@ -476,15 +495,29 @@ func (m *IntotoV002SchemaContentEnvelopeSignaturesItems0) ContextValidate(ctx co return nil } -func (m *IntotoV002SchemaContentEnvelopeSignaturesItems0) contextValidatePublicKey(ctx context.Context, formats strfmt.Registry) error { +func (m *IntotoV002SchemaContentEnvelopeSignaturesItems0) validatePublicKey(formats strfmt.Registry) error { - if err := validate.ReadOnly(ctx, "publicKey", "body", strfmt.Base64(m.PublicKey)); err != nil { + if err := validate.Required("publicKey", "body", m.PublicKey); err != nil { return err } return nil } +func (m *IntotoV002SchemaContentEnvelopeSignaturesItems0) validateSig(formats strfmt.Registry) error { + + if err := validate.Required("sig", "body", m.Sig); err != nil { + return err + } + + return nil +} + +// ContextValidate validates this intoto v002 schema content envelope signatures items0 based on context it is used +func (m *IntotoV002SchemaContentEnvelopeSignaturesItems0) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + // MarshalBinary interface implementation func (m *IntotoV002SchemaContentEnvelopeSignaturesItems0) MarshalBinary() ([]byte, error) { if m == nil { diff --git a/pkg/generated/models/jar_v001_schema.go b/pkg/generated/models/jar_v001_schema.go index 7a49b3e2e..4564964a5 100644 --- a/pkg/generated/models/jar_v001_schema.go +++ b/pkg/generated/models/jar_v001_schema.go @@ -124,6 +124,7 @@ func (m *JarV001Schema) ContextValidate(ctx context.Context, formats strfmt.Regi func (m *JarV001Schema) contextValidateArchive(ctx context.Context, formats strfmt.Registry) error { if m.Archive != nil { + if err := m.Archive.ContextValidate(ctx, formats); err != nil { if ve, ok := err.(*errors.Validation); ok { return ve.ValidateName("archive") @@ -140,6 +141,11 @@ func (m *JarV001Schema) contextValidateArchive(ctx context.Context, formats strf func (m *JarV001Schema) contextValidateSignature(ctx context.Context, formats strfmt.Registry) error { if m.Signature != nil { + + if swag.IsZero(m.Signature) { // not required + return nil + } + if err := m.Signature.ContextValidate(ctx, formats); err != nil { if ve, ok := err.(*errors.Validation); ok { return ve.ValidateName("signature") @@ -234,6 +240,11 @@ func (m *JarV001SchemaArchive) ContextValidate(ctx context.Context, formats strf func (m *JarV001SchemaArchive) contextValidateHash(ctx context.Context, formats strfmt.Registry) error { if m.Hash != nil { + + if swag.IsZero(m.Hash) { // not required + return nil + } + if err := m.Hash.ContextValidate(ctx, formats); err != nil { if ve, ok := err.(*errors.Validation); ok { return ve.ValidateName("archive" + "." + "hash") @@ -463,6 +474,7 @@ func (m *JarV001SchemaSignature) contextValidateContent(ctx context.Context, for func (m *JarV001SchemaSignature) contextValidatePublicKey(ctx context.Context, formats strfmt.Registry) error { if m.PublicKey != nil { + if err := m.PublicKey.ContextValidate(ctx, formats); err != nil { if ve, ok := err.(*errors.Validation); ok { return ve.ValidateName("signature" + "." + "publicKey") diff --git a/pkg/generated/models/log_entry.go b/pkg/generated/models/log_entry.go index 985e13b68..ee32ded41 100644 --- a/pkg/generated/models/log_entry.go +++ b/pkg/generated/models/log_entry.go @@ -95,7 +95,7 @@ type LogEntryAnon struct { // Required: true Body interface{} `json:"body"` - // integrated time + // The time the entry was added to the log as a Unix timestamp in seconds // Required: true IntegratedTime *int64 `json:"integratedTime"` @@ -250,6 +250,11 @@ func (m *LogEntryAnon) ContextValidate(ctx context.Context, formats strfmt.Regis func (m *LogEntryAnon) contextValidateAttestation(ctx context.Context, formats strfmt.Registry) error { if m.Attestation != nil { + + if swag.IsZero(m.Attestation) { // not required + return nil + } + if err := m.Attestation.ContextValidate(ctx, formats); err != nil { if ve, ok := err.(*errors.Validation); ok { return ve.ValidateName("attestation") @@ -266,6 +271,11 @@ func (m *LogEntryAnon) contextValidateAttestation(ctx context.Context, formats s func (m *LogEntryAnon) contextValidateVerification(ctx context.Context, formats strfmt.Registry) error { if m.Verification != nil { + + if swag.IsZero(m.Verification) { // not required + return nil + } + if err := m.Verification.ContextValidate(ctx, formats); err != nil { if ve, ok := err.(*errors.Validation); ok { return ve.ValidateName("verification") @@ -398,6 +408,11 @@ func (m *LogEntryAnonVerification) ContextValidate(ctx context.Context, formats func (m *LogEntryAnonVerification) contextValidateInclusionProof(ctx context.Context, formats strfmt.Registry) error { if m.InclusionProof != nil { + + if swag.IsZero(m.InclusionProof) { // not required + return nil + } + if err := m.InclusionProof.ContextValidate(ctx, formats); err != nil { if ve, ok := err.(*errors.Validation); ok { return ve.ValidateName("verification" + "." + "inclusionProof") diff --git a/pkg/generated/models/log_info.go b/pkg/generated/models/log_info.go index 33178bc56..cb57b27f5 100644 --- a/pkg/generated/models/log_info.go +++ b/pkg/generated/models/log_info.go @@ -182,6 +182,11 @@ func (m *LogInfo) contextValidateInactiveShards(ctx context.Context, formats str for i := 0; i < len(m.InactiveShards); i++ { if m.InactiveShards[i] != nil { + + if swag.IsZero(m.InactiveShards[i]) { // not required + return nil + } + if err := m.InactiveShards[i].ContextValidate(ctx, formats); err != nil { if ve, ok := err.(*errors.Validation); ok { return ve.ValidateName("inactiveShards" + "." + strconv.Itoa(i)) diff --git a/pkg/generated/models/proposed_entry.go b/pkg/generated/models/proposed_entry.go index 76b28019c..5b734a5ff 100644 --- a/pkg/generated/models/proposed_entry.go +++ b/pkg/generated/models/proposed_entry.go @@ -126,6 +126,12 @@ func unmarshalProposedEntry(data []byte, consumer runtime.Consumer) (ProposedEnt return nil, err } return &result, nil + case "dsse": + var result DSSE + if err := consumer.Consume(buf2, &result); err != nil { + return nil, err + } + return &result, nil case "hashedrekord": var result Hashedrekord if err := consumer.Consume(buf2, &result); err != nil { diff --git a/pkg/generated/models/rekord_v001_schema.go b/pkg/generated/models/rekord_v001_schema.go index 3d0446a5b..9a525717d 100644 --- a/pkg/generated/models/rekord_v001_schema.go +++ b/pkg/generated/models/rekord_v001_schema.go @@ -126,6 +126,7 @@ func (m *RekordV001Schema) ContextValidate(ctx context.Context, formats strfmt.R func (m *RekordV001Schema) contextValidateData(ctx context.Context, formats strfmt.Registry) error { if m.Data != nil { + if err := m.Data.ContextValidate(ctx, formats); err != nil { if ve, ok := err.(*errors.Validation); ok { return ve.ValidateName("data") @@ -142,6 +143,7 @@ func (m *RekordV001Schema) contextValidateData(ctx context.Context, formats strf func (m *RekordV001Schema) contextValidateSignature(ctx context.Context, formats strfmt.Registry) error { if m.Signature != nil { + if err := m.Signature.ContextValidate(ctx, formats); err != nil { if ve, ok := err.(*errors.Validation); ok { return ve.ValidateName("signature") @@ -236,6 +238,11 @@ func (m *RekordV001SchemaData) ContextValidate(ctx context.Context, formats strf func (m *RekordV001SchemaData) contextValidateHash(ctx context.Context, formats strfmt.Registry) error { if m.Hash != nil { + + if swag.IsZero(m.Hash) { // not required + return nil + } + if err := m.Hash.ContextValidate(ctx, formats); err != nil { if ve, ok := err.(*errors.Validation); ok { return ve.ValidateName("data" + "." + "hash") @@ -514,6 +521,7 @@ func (m *RekordV001SchemaSignature) ContextValidate(ctx context.Context, formats func (m *RekordV001SchemaSignature) contextValidatePublicKey(ctx context.Context, formats strfmt.Registry) error { if m.PublicKey != nil { + if err := m.PublicKey.ContextValidate(ctx, formats); err != nil { if ve, ok := err.(*errors.Validation); ok { return ve.ValidateName("signature" + "." + "publicKey") diff --git a/pkg/generated/models/rfc3161_v001_schema.go b/pkg/generated/models/rfc3161_v001_schema.go index fe668412d..c3a50c849 100644 --- a/pkg/generated/models/rfc3161_v001_schema.go +++ b/pkg/generated/models/rfc3161_v001_schema.go @@ -93,6 +93,7 @@ func (m *Rfc3161V001Schema) ContextValidate(ctx context.Context, formats strfmt. func (m *Rfc3161V001Schema) contextValidateTsr(ctx context.Context, formats strfmt.Registry) error { if m.Tsr != nil { + if err := m.Tsr.ContextValidate(ctx, formats); err != nil { if ve, ok := err.(*errors.Validation); ok { return ve.ValidateName("tsr") diff --git a/pkg/generated/models/rpm_v001_schema.go b/pkg/generated/models/rpm_v001_schema.go index 82a75c1de..80dadde7f 100644 --- a/pkg/generated/models/rpm_v001_schema.go +++ b/pkg/generated/models/rpm_v001_schema.go @@ -126,6 +126,7 @@ func (m *RpmV001Schema) ContextValidate(ctx context.Context, formats strfmt.Regi func (m *RpmV001Schema) contextValidatePackage(ctx context.Context, formats strfmt.Registry) error { if m.Package != nil { + if err := m.Package.ContextValidate(ctx, formats); err != nil { if ve, ok := err.(*errors.Validation); ok { return ve.ValidateName("package") @@ -142,6 +143,7 @@ func (m *RpmV001Schema) contextValidatePackage(ctx context.Context, formats strf func (m *RpmV001Schema) contextValidatePublicKey(ctx context.Context, formats strfmt.Registry) error { if m.PublicKey != nil { + if err := m.PublicKey.ContextValidate(ctx, formats); err != nil { if ve, ok := err.(*errors.Validation); ok { return ve.ValidateName("publicKey") @@ -244,6 +246,11 @@ func (m *RpmV001SchemaPackage) ContextValidate(ctx context.Context, formats strf func (m *RpmV001SchemaPackage) contextValidateHash(ctx context.Context, formats strfmt.Registry) error { if m.Hash != nil { + + if swag.IsZero(m.Hash) { // not required + return nil + } + if err := m.Hash.ContextValidate(ctx, formats); err != nil { if ve, ok := err.(*errors.Validation); ok { return ve.ValidateName("package" + "." + "hash") diff --git a/pkg/generated/models/search_index.go b/pkg/generated/models/search_index.go index 08bc595c3..bb1ccccc2 100644 --- a/pkg/generated/models/search_index.go +++ b/pkg/generated/models/search_index.go @@ -180,6 +180,11 @@ func (m *SearchIndex) ContextValidate(ctx context.Context, formats strfmt.Regist func (m *SearchIndex) contextValidatePublicKey(ctx context.Context, formats strfmt.Registry) error { if m.PublicKey != nil { + + if swag.IsZero(m.PublicKey) { // not required + return nil + } + if err := m.PublicKey.ContextValidate(ctx, formats); err != nil { if ve, ok := err.(*errors.Validation); ok { return ve.ValidateName("publicKey") diff --git a/pkg/generated/models/search_log_query.go b/pkg/generated/models/search_log_query.go index 6838b8a76..425ec8b34 100644 --- a/pkg/generated/models/search_log_query.go +++ b/pkg/generated/models/search_log_query.go @@ -260,6 +260,10 @@ func (m *SearchLogQuery) contextValidateEntries(ctx context.Context, formats str for i := 0; i < len(m.Entries()); i++ { + if swag.IsZero(m.entriesField[i]) { // not required + return nil + } + if err := m.entriesField[i].ContextValidate(ctx, formats); err != nil { if ve, ok := err.(*errors.Validation); ok { return ve.ValidateName("entries" + "." + strconv.Itoa(i)) diff --git a/pkg/generated/models/tuf_v001_schema.go b/pkg/generated/models/tuf_v001_schema.go index f8bf4b020..021e0ce7d 100644 --- a/pkg/generated/models/tuf_v001_schema.go +++ b/pkg/generated/models/tuf_v001_schema.go @@ -133,6 +133,7 @@ func (m *TUFV001Schema) ContextValidate(ctx context.Context, formats strfmt.Regi func (m *TUFV001Schema) contextValidateMetadata(ctx context.Context, formats strfmt.Registry) error { if m.Metadata != nil { + if err := m.Metadata.ContextValidate(ctx, formats); err != nil { if ve, ok := err.(*errors.Validation); ok { return ve.ValidateName("metadata") @@ -149,6 +150,7 @@ func (m *TUFV001Schema) contextValidateMetadata(ctx context.Context, formats str func (m *TUFV001Schema) contextValidateRoot(ctx context.Context, formats strfmt.Registry) error { if m.Root != nil { + if err := m.Root.ContextValidate(ctx, formats); err != nil { if ve, ok := err.(*errors.Validation); ok { return ve.ValidateName("root") @@ -195,11 +197,30 @@ func (m *TUFV001Schema) UnmarshalBinary(b []byte) error { type TUFV001SchemaMetadata struct { // Specifies the metadata inline within the document - Content interface{} `json:"content,omitempty"` + // Required: true + Content interface{} `json:"content"` } // Validate validates this TUF v001 schema metadata func (m *TUFV001SchemaMetadata) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateContent(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *TUFV001SchemaMetadata) validateContent(formats strfmt.Registry) error { + + if m.Content == nil { + return errors.Required("metadata"+"."+"content", "body", nil) + } + return nil } diff --git a/pkg/generated/restapi/configure_rekor_server.go b/pkg/generated/restapi/configure_rekor_server.go index 90cf05100..8aab1890f 100644 --- a/pkg/generated/restapi/configure_rekor_server.go +++ b/pkg/generated/restapi/configure_rekor_server.go @@ -20,6 +20,7 @@ package restapi import ( "context" "crypto/tls" + go_errors "errors" "fmt" "net/http" "net/http/httputil" @@ -64,7 +65,7 @@ type apiToRecord struct { path *string // Path to record in metrics, if any. } -func configureFlags(api *operations.RekorServerAPI) { +func configureFlags(_ *operations.RekorServerAPI) { // api.CommandLineOptionsGroups = []swag.CommandLineOptionsGroup{ ... } } @@ -155,13 +156,15 @@ func configureAPI(api *operations.RekorServerAPI) http.Handler { api.RegisterFormat("signedCheckpoint", &util.SignedNote{}, util.SignedCheckpointValidator) api.PreServerShutdown = func() {} - api.ServerShutdown = func() {} + api.ServerShutdown = func() { + pkgapi.StopAPI() + } return setupGlobalMiddleware(api.Serve(setupMiddlewares)) } // The TLS configuration before HTTPS server starts. -func configureTLS(tlsConfig *tls.Config) { +func configureTLS(_ *tls.Config) { // Make all necessary changes to the TLS configuration here. } @@ -169,7 +172,7 @@ func configureTLS(tlsConfig *tls.Config) { // If you need to modify a config, store server instance to stop it individually later, this is the place. // This function can be called multiple times, depending on the number of serving schemes. // scheme value will be set accordingly: "http", "https" or "unix" -func configureServer(s *http.Server, scheme, addr string) { +func configureServer(_ *http.Server, _, _ string) { } // The middleware configuration is for the handler executors. These do not apply to the swagger.json document. @@ -208,7 +211,7 @@ type zapLogEntry struct { r *http.Request } -func (z *zapLogEntry) Write(status, bytes int, header http.Header, elapsed time.Duration, extra interface{}) { +func (z *zapLogEntry) Write(status, bytes int, _ http.Header, elapsed time.Duration, extra interface{}) { var fields []interface{} // follows https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry as a convention @@ -251,6 +254,10 @@ func (l *logFormatter) NewLogEntry(r *http.Request) middleware.LogEntry { // So this is a good place to plug in a panic handling middleware, logging and metrics func setupGlobalMiddleware(handler http.Handler) http.Handler { returnHandler := recoverer(handler) + maxReqBodySize := viper.GetInt64("max_request_body_size") + if maxReqBodySize > 0 { + returnHandler = maxBodySize(maxReqBodySize, returnHandler) + } middleware.DefaultLogger = middleware.RequestLogger(&logFormatter{}) returnHandler = middleware.Logger(returnHandler) returnHandler = middleware.Heartbeat("/ping")(returnHandler) @@ -339,8 +346,18 @@ func logAndServeError(w http.ResponseWriter, r *http.Request, err error) { } else { log.ContextLogger(ctx).Error(err) } + if compErr, ok := err.(*errors.CompositeError); ok { + // iterate over composite error looking for something more specific + for _, embeddedErr := range compErr.Errors { + var maxBytesError *http.MaxBytesError + if parseErr, ok := embeddedErr.(*errors.ParseError); ok && go_errors.As(parseErr.Reason, &maxBytesError) { + err = errors.New(http.StatusRequestEntityTooLarge, http.StatusText(http.StatusRequestEntityTooLarge)) + break + } + } + } requestFields := map[string]interface{}{} - if err := mapstructure.Decode(r, &requestFields); err == nil { + if decodeErr := mapstructure.Decode(r, &requestFields); decodeErr == nil { log.ContextLogger(ctx).Debug(requestFields) } errors.ServeError(w, r, err) @@ -386,3 +403,13 @@ func recoverer(next http.Handler) http.Handler { return http.HandlerFunc(fn) } + +// maxBodySize limits the request body +func maxBodySize(maxLength int64, next http.Handler) http.Handler { + fn := func(w http.ResponseWriter, r *http.Request) { + r.Body = http.MaxBytesReader(w, r.Body, maxLength) + next.ServeHTTP(w, r) + } + + return http.HandlerFunc(fn) +} diff --git a/pkg/generated/restapi/embedded_spec.go b/pkg/generated/restapi/embedded_spec.go index 697bc220b..d1d2d89e2 100644 --- a/pkg/generated/restapi/embedded_spec.go +++ b/pkg/generated/restapi/embedded_spec.go @@ -99,6 +99,15 @@ func init() { ], "summary": "Get information about the current state of the transparency log", "operationId": "getLogInfo", + "parameters": [ + { + "type": "boolean", + "default": false, + "description": "Whether to return a stable checkpoint for the active shard", + "name": "stable", + "in": "query" + } + ], "responses": { "200": { "description": "A JSON object with the root hash and tree size as properties", @@ -476,6 +485,7 @@ func init() { "additionalProperties": true }, "integratedTime": { + "description": "The time the entry was added to the log as a Unix timestamp in seconds", "type": "integer" }, "logID": { @@ -679,6 +689,32 @@ func init() { } ] }, + "dsse": { + "description": "DSSE envelope", + "type": "object", + "allOf": [ + { + "$ref": "#/definitions/ProposedEntry" + }, + { + "required": [ + "apiVersion", + "spec" + ], + "properties": { + "apiVersion": { + "type": "string", + "pattern": "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$" + }, + "spec": { + "type": "object", + "$ref": "pkg/types/dsse/dsse_schema.json" + } + }, + "additionalProperties": false + } + ] + }, "hashedrekord": { "description": "Hashed Rekord object", "type": "object", @@ -995,6 +1031,15 @@ func init() { ], "summary": "Get information about the current state of the transparency log", "operationId": "getLogInfo", + "parameters": [ + { + "type": "boolean", + "default": false, + "description": "Whether to return a stable checkpoint for the active shard", + "name": "stable", + "in": "query" + } + ], "responses": { "200": { "description": "A JSON object with the root hash and tree size as properties", @@ -1498,6 +1543,95 @@ func init() { }, "readOnly": true }, + "DSSEV001SchemaEnvelopeHash": { + "description": "Specifies the hash algorithm and value encompassing the entire envelope sent to Rekor", + "type": "object", + "required": [ + "algorithm", + "value" + ], + "properties": { + "algorithm": { + "description": "The hashing function used to compute the hash value", + "type": "string", + "enum": [ + "sha256" + ] + }, + "value": { + "description": "The value of the computed digest over the entire envelope", + "type": "string" + } + }, + "readOnly": true + }, + "DSSEV001SchemaPayloadHash": { + "description": "Specifies the hash algorithm and value covering the payload within the DSSE envelope", + "type": "object", + "required": [ + "algorithm", + "value" + ], + "properties": { + "algorithm": { + "description": "The hashing function used to compute the hash value", + "type": "string", + "enum": [ + "sha256" + ] + }, + "value": { + "description": "The value of the computed digest over the payload within the envelope", + "type": "string" + } + }, + "readOnly": true + }, + "DSSEV001SchemaProposedContent": { + "type": "object", + "required": [ + "envelope", + "verifiers" + ], + "properties": { + "envelope": { + "description": "DSSE envelope specified as a stringified JSON object", + "type": "string", + "writeOnly": true + }, + "verifiers": { + "description": "collection of all verification material (e.g. public keys or certificates) used to verify signatures over envelope's payload, specified as base64-encoded strings", + "type": "array", + "minItems": 1, + "items": { + "type": "string", + "format": "byte" + }, + "writeOnly": true + } + }, + "writeOnly": true + }, + "DSSEV001SchemaSignaturesItems0": { + "description": "a signature of the envelope's payload along with the verification material for the signature", + "type": "object", + "required": [ + "signature", + "verifier" + ], + "properties": { + "signature": { + "description": "base64 encoded signature of the payload", + "type": "string", + "pattern": "^(?:[A-Za-z0-9+\\/]{4})*(?:[A-Za-z0-9+\\/]{2}==|[A-Za-z0-9+\\/]{3}=|[A-Za-z0-9+\\/]{4})$" + }, + "verifier": { + "description": "verification material that was used to verify the corresponding signature, specified as a base64 encoded string", + "type": "string", + "format": "byte" + } + } + }, "Error": { "type": "object", "properties": { @@ -1834,7 +1968,7 @@ func init() { "writeOnly": true }, "hash": { - "description": "Specifies the hash algorithm and value encompassing the entire signed envelope", + "description": "Specifies the hash algorithm and value encompassing the entire signed envelope; this is computed by the rekor server, client-provided values are ignored", "type": "object", "required": [ "algorithm", @@ -1856,7 +1990,7 @@ func init() { "readOnly": true }, "payloadHash": { - "description": "Specifies the hash algorithm and value covering the payload within the DSSE envelope", + "description": "Specifies the hash algorithm and value covering the payload within the DSSE envelope; this is computed by the rekor server, client-provided values are ignored", "type": "object", "required": [ "algorithm", @@ -1880,7 +2014,7 @@ func init() { } }, "IntotoV001SchemaContentHash": { - "description": "Specifies the hash algorithm and value encompassing the entire signed envelope", + "description": "Specifies the hash algorithm and value encompassing the entire signed envelope; this is computed by the rekor server, client-provided values are ignored", "type": "object", "required": [ "algorithm", @@ -1902,7 +2036,7 @@ func init() { "readOnly": true }, "IntotoV001SchemaContentPayloadHash": { - "description": "Specifies the hash algorithm and value covering the payload within the DSSE envelope", + "description": "Specifies the hash algorithm and value covering the payload within the DSSE envelope; this is computed by the rekor server, client-provided values are ignored", "type": "object", "required": [ "algorithm", @@ -1925,6 +2059,9 @@ func init() { }, "IntotoV002SchemaContent": { "type": "object", + "required": [ + "envelope" + ], "properties": { "envelope": { "description": "dsse envelope", @@ -2031,6 +2168,10 @@ func init() { "IntotoV002SchemaContentEnvelopeSignaturesItems0": { "description": "a signature of the envelope's payload along with the public key for the signature", "type": "object", + "required": [ + "sig", + "publicKey" + ], "properties": { "keyid": { "description": "optional id of the key used to create the signature", @@ -2039,8 +2180,7 @@ func init() { "publicKey": { "description": "public key that corresponds to this signature", "type": "string", - "format": "byte", - "readOnly": true + "format": "byte" }, "sig": { "description": "signature of the payload", @@ -2234,6 +2374,7 @@ func init() { "additionalProperties": true }, "integratedTime": { + "description": "The time the entry was added to the log as a Unix timestamp in seconds", "type": "integer" }, "logID": { @@ -2662,7 +2803,7 @@ func init() { "description": "TUF metadata", "type": "object", "required": [ - "metadata" + "content" ], "properties": { "content": { @@ -2921,6 +3062,144 @@ func init() { "$schema": "http://json-schema.org/draft-07/schema", "$id": "http://rekor.sigstore.dev/types/cose/cose_v0_0_1_schema.json" }, + "dsse": { + "description": "DSSE envelope", + "type": "object", + "allOf": [ + { + "$ref": "#/definitions/ProposedEntry" + }, + { + "required": [ + "apiVersion", + "spec" + ], + "properties": { + "apiVersion": { + "type": "string", + "pattern": "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$" + }, + "spec": { + "$ref": "#/definitions/dsseSchema" + } + }, + "additionalProperties": false + } + ] + }, + "dsseSchema": { + "description": "log entry schema for dsse envelopes", + "type": "object", + "title": "DSSE Schema", + "oneOf": [ + { + "$ref": "#/definitions/dsseV001Schema" + } + ], + "$schema": "http://json-schema.org/draft-07/schema", + "$id": "http://rekor.sigstore.dev/types/dsse/dsse_schema.json" + }, + "dsseV001Schema": { + "description": "Schema for DSSE envelopes", + "type": "object", + "title": "DSSE v0.0.1 Schema", + "oneOf": [ + { + "required": [ + "proposedContent" + ] + }, + { + "required": [ + "signatures", + "envelopeHash", + "payloadHash" + ] + } + ], + "properties": { + "envelopeHash": { + "description": "Specifies the hash algorithm and value encompassing the entire envelope sent to Rekor", + "type": "object", + "required": [ + "algorithm", + "value" + ], + "properties": { + "algorithm": { + "description": "The hashing function used to compute the hash value", + "type": "string", + "enum": [ + "sha256" + ] + }, + "value": { + "description": "The value of the computed digest over the entire envelope", + "type": "string" + } + }, + "readOnly": true + }, + "payloadHash": { + "description": "Specifies the hash algorithm and value covering the payload within the DSSE envelope", + "type": "object", + "required": [ + "algorithm", + "value" + ], + "properties": { + "algorithm": { + "description": "The hashing function used to compute the hash value", + "type": "string", + "enum": [ + "sha256" + ] + }, + "value": { + "description": "The value of the computed digest over the payload within the envelope", + "type": "string" + } + }, + "readOnly": true + }, + "proposedContent": { + "type": "object", + "required": [ + "envelope", + "verifiers" + ], + "properties": { + "envelope": { + "description": "DSSE envelope specified as a stringified JSON object", + "type": "string", + "writeOnly": true + }, + "verifiers": { + "description": "collection of all verification material (e.g. public keys or certificates) used to verify signatures over envelope's payload, specified as base64-encoded strings", + "type": "array", + "minItems": 1, + "items": { + "type": "string", + "format": "byte" + }, + "writeOnly": true + } + }, + "writeOnly": true + }, + "signatures": { + "description": "extracted collection of all signatures of the envelope's payload; elements will be sorted by lexicographical order of the base64 encoded signature strings", + "type": "array", + "minItems": 1, + "items": { + "$ref": "#/definitions/DSSEV001SchemaSignaturesItems0" + }, + "readOnly": true + } + }, + "$schema": "http://json-schema.org/draft-07/schema", + "$id": "http://rekor.sigstore.dev/types/dsse/dsse_v0_0_1_schema.json" + }, "hashedrekord": { "description": "Hashed Rekord object", "type": "object", @@ -3212,7 +3491,7 @@ func init() { "writeOnly": true }, "hash": { - "description": "Specifies the hash algorithm and value encompassing the entire signed envelope", + "description": "Specifies the hash algorithm and value encompassing the entire signed envelope; this is computed by the rekor server, client-provided values are ignored", "type": "object", "required": [ "algorithm", @@ -3234,7 +3513,7 @@ func init() { "readOnly": true }, "payloadHash": { - "description": "Specifies the hash algorithm and value covering the payload within the DSSE envelope", + "description": "Specifies the hash algorithm and value covering the payload within the DSSE envelope; this is computed by the rekor server, client-provided values are ignored", "type": "object", "required": [ "algorithm", @@ -3276,6 +3555,9 @@ func init() { "properties": { "content": { "type": "object", + "required": [ + "envelope" + ], "properties": { "envelope": { "description": "dsse envelope", @@ -3846,7 +4128,7 @@ func init() { "description": "TUF metadata", "type": "object", "required": [ - "metadata" + "content" ], "properties": { "content": { diff --git a/pkg/generated/restapi/operations/rekor_server_api.go b/pkg/generated/restapi/operations/rekor_server_api.go index 5898ed5e7..1fccb33bc 100644 --- a/pkg/generated/restapi/operations/rekor_server_api.go +++ b/pkg/generated/restapi/operations/rekor_server_api.go @@ -413,6 +413,6 @@ func (o *RekorServerAPI) AddMiddlewareFor(method, path string, builder middlewar } o.Init() if h, ok := o.handlers[um][path]; ok { - o.handlers[method][path] = builder(h) + o.handlers[um][path] = builder(h) } } diff --git a/pkg/generated/restapi/operations/tlog/get_log_info_parameters.go b/pkg/generated/restapi/operations/tlog/get_log_info_parameters.go index f6b7e151b..72fc76472 100644 --- a/pkg/generated/restapi/operations/tlog/get_log_info_parameters.go +++ b/pkg/generated/restapi/operations/tlog/get_log_info_parameters.go @@ -25,15 +25,25 @@ import ( "net/http" "github.com/go-openapi/errors" + "github.com/go-openapi/runtime" "github.com/go-openapi/runtime/middleware" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" ) // NewGetLogInfoParams creates a new GetLogInfoParams object -// -// There are no default values defined in the spec. +// with the default values initialized. func NewGetLogInfoParams() GetLogInfoParams { - return GetLogInfoParams{} + var ( + // initialize parameters with default values + + stableDefault = bool(false) + ) + + return GetLogInfoParams{ + Stable: &stableDefault, + } } // GetLogInfoParams contains all the bound params for the get log info operation @@ -44,6 +54,12 @@ type GetLogInfoParams struct { // HTTP Request Object HTTPRequest *http.Request `json:"-"` + + /*Whether to return a stable checkpoint for the active shard + In: query + Default: false + */ + Stable *bool } // BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface @@ -55,8 +71,38 @@ func (o *GetLogInfoParams) BindRequest(r *http.Request, route *middleware.Matche o.HTTPRequest = r + qs := runtime.Values(r.URL.Query()) + + qStable, qhkStable, _ := qs.GetOK("stable") + if err := o.bindStable(qStable, qhkStable, route.Formats); err != nil { + res = append(res, err) + } if len(res) > 0 { return errors.CompositeValidationError(res...) } return nil } + +// bindStable binds and validates parameter Stable from query. +func (o *GetLogInfoParams) bindStable(rawData []string, hasKey bool, formats strfmt.Registry) error { + var raw string + if len(rawData) > 0 { + raw = rawData[len(rawData)-1] + } + + // Required: false + // AllowEmptyValue: false + + if raw == "" { // empty values pass all other validations + // Default values have been previously initialized by NewGetLogInfoParams() + return nil + } + + value, err := swag.ConvertBool(raw) + if err != nil { + return errors.InvalidType("stable", "query", "bool", raw) + } + o.Stable = &value + + return nil +} diff --git a/pkg/generated/restapi/operations/tlog/get_log_info_urlbuilder.go b/pkg/generated/restapi/operations/tlog/get_log_info_urlbuilder.go index e344fac34..19587e476 100644 --- a/pkg/generated/restapi/operations/tlog/get_log_info_urlbuilder.go +++ b/pkg/generated/restapi/operations/tlog/get_log_info_urlbuilder.go @@ -25,11 +25,17 @@ import ( "errors" "net/url" golangswaggerpaths "path" + + "github.com/go-openapi/swag" ) // GetLogInfoURL generates an URL for the get log info operation type GetLogInfoURL struct { + Stable *bool + _basePath string + // avoid unkeyed usage + _ struct{} } // WithBasePath sets the base path for this url builder, only required when it's different from the @@ -56,6 +62,18 @@ func (o *GetLogInfoURL) Build() (*url.URL, error) { _basePath := o._basePath _result.Path = golangswaggerpaths.Join(_basePath, _path) + qs := make(url.Values) + + var stableQ string + if o.Stable != nil { + stableQ = swag.FormatBool(*o.Stable) + } + if stableQ != "" { + qs.Set("stable", stableQ) + } + + _result.RawQuery = qs.Encode() + return &_result, nil } diff --git a/pkg/pki/fuzz_test.go b/pkg/pki/fuzz_test.go new file mode 100644 index 000000000..2e8a1bc6c --- /dev/null +++ b/pkg/pki/fuzz_test.go @@ -0,0 +1,102 @@ +// +// Copyright 2022 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 pki + +import ( + "bytes" + "io" + "testing" + + "github.com/sigstore/rekor/pkg/pki/minisign" + "github.com/sigstore/rekor/pkg/pki/pgp" + "github.com/sigstore/rekor/pkg/pki/pkcs7" + "github.com/sigstore/rekor/pkg/pki/ssh" + "github.com/sigstore/rekor/pkg/pki/tuf" + "github.com/sigstore/rekor/pkg/pki/x509" +) + +var ( + fuzzArtifactFactoryMap = map[uint]pkiImpl{ + 0: { + newPubKey: func(r io.Reader) (PublicKey, error) { + return pgp.NewPublicKey(r) + }, + newSignature: func(r io.Reader) (Signature, error) { + return pgp.NewSignature(r) + }, + }, + 1: { + newPubKey: func(r io.Reader) (PublicKey, error) { + return minisign.NewPublicKey(r) + }, + newSignature: func(r io.Reader) (Signature, error) { + return minisign.NewSignature(r) + }, + }, + 2: { + newPubKey: func(r io.Reader) (PublicKey, error) { + return ssh.NewPublicKey(r) + }, + newSignature: func(r io.Reader) (Signature, error) { + return ssh.NewSignature(r) + }, + }, + 3: { + newPubKey: func(r io.Reader) (PublicKey, error) { + return x509.NewPublicKey(r) + }, + newSignature: func(r io.Reader) (Signature, error) { + return x509.NewSignature(r) + }, + }, + 4: { + newPubKey: func(r io.Reader) (PublicKey, error) { + return pkcs7.NewPublicKey(r) + }, + newSignature: func(r io.Reader) (Signature, error) { + return pkcs7.NewSignature(r) + }, + }, + 5: { + newPubKey: func(r io.Reader) (PublicKey, error) { + return tuf.NewPublicKey(r) + }, + newSignature: func(r io.Reader) (Signature, error) { + return tuf.NewSignature(r) + }, + }, + } +) + +func FuzzKeys(f *testing.F) { + f.Fuzz(func(t *testing.T, keyType uint, origSignatureData, verSignatureData, keyData []byte) { + s, err := fuzzArtifactFactoryMap[keyType%6].newSignature(bytes.NewReader(origSignatureData)) + if err == nil && s != nil { + b, err := s.CanonicalValue() + if err == nil { + _, err = fuzzArtifactFactoryMap[keyType%6].newSignature(bytes.NewReader(b)) + if err != nil { + t.Fatal("Could not create a signature from valid key data") + } + } + pub, err := fuzzArtifactFactoryMap[keyType%6].newPubKey(bytes.NewReader(keyData)) + if err != nil { + t.Skip() + } + s.Verify(bytes.NewReader(verSignatureData), pub) + } + }) +} diff --git a/pkg/pki/identity/identity.go b/pkg/pki/identity/identity.go new file mode 100644 index 000000000..4566e1ddf --- /dev/null +++ b/pkg/pki/identity/identity.go @@ -0,0 +1,38 @@ +// 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. + +package identity + +type Identity struct { + // Types include: + // - *rsa.PublicKey + // - *ecdsa.PublicKey + // - ed25519.PublicKey + // - *x509.Certificate + // - openpgp.EntityList (golang.org/x/crypto/openpgp) + // - *minisign.PublicKey (github.com/jedisct1/go-minisign) + // - ssh.PublicKey (golang.org/x/crypto/ssh) + Crypto any + // Raw key or certificate extracted from Crypto. Values include: + // - PKIX ASN.1 DER-encoded public key + // - ASN.1 DER-encoded certificate + Raw []byte + // For keys, certificates, and minisign, hex-encoded SHA-256 digest + // of the public key or certificate + // For SSH and PGP, Fingerprint is the standard for each ecosystem + // For SSH, unpadded base-64 encoded SHA-256 digest of the key + // For PGP, hex-encoded SHA-1 digest of a key, which can be either + // a primary key or subkey + Fingerprint string +} diff --git a/pkg/pki/minisign/minisign.go b/pkg/pki/minisign/minisign.go index 945db41ca..7432db3c8 100644 --- a/pkg/pki/minisign/minisign.go +++ b/pkg/pki/minisign/minisign.go @@ -17,12 +17,17 @@ package minisign import ( "bytes" + "crypto/ed25519" + "crypto/sha256" "encoding/base64" + "encoding/hex" "fmt" "io" "strings" minisign "github.com/jedisct1/go-minisign" + "github.com/sigstore/rekor/pkg/pki/identity" + "github.com/sigstore/sigstore/pkg/cryptoutils" sigsig "github.com/sigstore/sigstore/pkg/signature" "golang.org/x/crypto/blake2b" ) @@ -114,7 +119,7 @@ func (s Signature) Verify(r io.Reader, k interface{}, opts ...sigsig.VerifyOptio r = bytes.NewReader(h.Sum(nil)) } - return verifier.VerifySignature(bytes.NewReader(s.signature.Signature[:]), r) + return verifier.VerifySignature(bytes.NewReader(s.signature.Signature[:]), r, opts...) } // PublicKey Public Key that follows the minisign standard; supports signify and minisign public keys @@ -182,3 +187,18 @@ func (k PublicKey) EmailAddresses() []string { func (k PublicKey) Subjects() []string { return nil } + +// Identities implements the pki.PublicKey interface +func (k PublicKey) Identities() ([]identity.Identity, error) { + // PKIX encode ed25519 public key + pkixKey, err := cryptoutils.MarshalPublicKeyToDER(ed25519.PublicKey(k.key.PublicKey[:])) + if err != nil { + return nil, err + } + digest := sha256.Sum256(pkixKey) + return []identity.Identity{{ + Crypto: k.key, + Raw: pkixKey, + Fingerprint: hex.EncodeToString(digest[:]), + }}, nil +} diff --git a/pkg/pki/minisign/minisign_test.go b/pkg/pki/minisign/minisign_test.go index bb948c2a5..0284dcd2c 100644 --- a/pkg/pki/minisign/minisign_test.go +++ b/pkg/pki/minisign/minisign_test.go @@ -1,4 +1,3 @@ -// // Copyright 2021 The Sigstore Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,12 +16,19 @@ package minisign import ( "bytes" + "crypto/ed25519" + "crypto/sha256" + "crypto/x509" + "encoding/hex" "errors" "io" "os" + "reflect" "testing" "github.com/google/go-cmp/cmp" + minisign "github.com/jedisct1/go-minisign" + "github.com/sigstore/sigstore/pkg/cryptoutils" "go.uber.org/goleak" ) @@ -63,6 +69,31 @@ func TestReadPublicKey(t *testing.T) { if !bytes.Equal(rawGot.key.PublicKey[:], rawBytes) { t.Errorf("expected parsed keys to be equal, %v != %v", rawGot.key.PublicKey, rawBytes) } + ids, err := rawGot.Identities() + if err != nil { + t.Fatalf("unexpected error getting identities: %v", err) + } + if _, ok := ids[0].Crypto.(*minisign.PublicKey); !ok { + t.Fatalf("key is of unexpected type, expected *minisign.PublicKey, got %v", reflect.TypeOf(ids[0].Crypto)) + } + expectedDer, err := cryptoutils.MarshalPublicKeyToDER(ed25519.PublicKey(rawBytes)) + if err != nil { + t.Fatalf("unexpected error generating DER: %v", err) + } + if !reflect.DeepEqual(expectedDer, ids[0].Raw) { + t.Errorf("raw keys are not equal") + } + edKey, _ := x509.ParsePKIXPublicKey(ids[0].Raw) + if err := cryptoutils.EqualKeys(edKey, ed25519.PublicKey(rawBytes)); err != nil { + t.Errorf("public keys did not match: %v", err) + } + if len(ids[0].Fingerprint) != 64 { + t.Errorf("%v: fingerprint is not expected length of 64 (hex 32-byte sha256): %d", tc.caseDesc, len(ids[0].Fingerprint)) + } + digest := sha256.Sum256(expectedDer) + if hex.EncodeToString(digest[:]) != ids[0].Fingerprint { + t.Fatalf("fingerprints don't match") + } }) } } @@ -121,7 +152,7 @@ func TestReadSignature(t *testing.T) { type BadReader struct { } -func (br BadReader) Read(p []byte) (n int, err error) { +func (br BadReader) Read(_ []byte) (n int, err error) { return 0, errors.New("test error") } @@ -288,6 +319,33 @@ func TestCanonicalValuePublicKey(t *testing.T) { if diff := cmp.Diff(rt.key, inputKey.key); diff != "" { t.Error(diff) } + + // Identities should be equal to the canonical value for minisign + ids, err := outputKey.Identities() + if err != nil { + t.Fatalf("unexpected error getting identities: %v", err) + } + if _, ok := ids[0].Crypto.(*minisign.PublicKey); !ok { + t.Fatalf("key is of unexpected type, expected *minisign.PublicKey, got %v", reflect.TypeOf(ids[0].Crypto)) + } + expectedDer, err := cryptoutils.MarshalPublicKeyToDER(ed25519.PublicKey(rt.key.PublicKey[:])) + if err != nil { + t.Fatalf("unexpected error generating DER: %v", err) + } + if !reflect.DeepEqual(expectedDer, ids[0].Raw) { + t.Errorf("raw keys are not equal") + } + edKey, _ := x509.ParsePKIXPublicKey(ids[0].Raw) + if err := cryptoutils.EqualKeys(edKey, ed25519.PublicKey(rt.key.PublicKey[:])); err != nil { + t.Errorf("public keys did not match: %v", err) + } + if len(ids[0].Fingerprint) != 64 { + t.Errorf("%v: fingerprint is not expected length of 64 (hex 32-byte sha256): %d", tc.caseDesc, len(ids[0].Fingerprint)) + } + digest := sha256.Sum256(expectedDer) + if hex.EncodeToString(digest[:]) != ids[0].Fingerprint { + t.Fatalf("fingerprints don't match") + } } } diff --git a/pkg/pki/pgp/pgp.go b/pkg/pki/pgp/pgp.go index 79ae5f6b1..19501bc1d 100644 --- a/pkg/pki/pgp/pgp.go +++ b/pkg/pki/pgp/pgp.go @@ -19,6 +19,10 @@ import ( "bufio" "bytes" "context" + "crypto/ecdsa" + "crypto/ed25519" + "crypto/rsa" + "encoding/hex" "errors" "fmt" "io" @@ -31,6 +35,8 @@ import ( "golang.org/x/crypto/openpgp/armor" //nolint:staticcheck "golang.org/x/crypto/openpgp/packet" //nolint:staticcheck + "github.com/sigstore/rekor/pkg/pki/identity" + "github.com/sigstore/sigstore/pkg/cryptoutils" sigsig "github.com/sigstore/sigstore/pkg/signature" ) @@ -134,7 +140,7 @@ func (s Signature) CanonicalValue() ([]byte, error) { } // Verify implements the pki.Signature interface -func (s Signature) Verify(r io.Reader, k interface{}, opts ...sigsig.VerifyOption) error { +func (s Signature) Verify(r io.Reader, k interface{}, _ ...sigsig.VerifyOption) error { if len(s.signature) == 0 { return fmt.Errorf("PGP signature has not been initialized") } @@ -303,3 +309,36 @@ func (k PublicKey) EmailAddresses() []string { func (k PublicKey) Subjects() []string { return k.EmailAddresses() } + +// Identities implements the pki.PublicKey interface +func (k PublicKey) Identities() ([]identity.Identity, error) { + var ids []identity.Identity + for _, entity := range k.key { + var keys []*packet.PublicKey + keys = append(keys, entity.PrimaryKey) + for _, subKey := range entity.Subkeys { + keys = append(keys, subKey.PublicKey) + } + for _, pk := range keys { + pubKey := pk.PublicKey + // Only process supported types. Will ignore DSA + // and ElGamal keys. + // TODO: For a V2 PGP type, enforce on upload + switch pubKey.(type) { + case *rsa.PublicKey, *ecdsa.PublicKey, ed25519.PublicKey: + default: + continue + } + pkixKey, err := cryptoutils.MarshalPublicKeyToDER(pubKey) + if err != nil { + return nil, err + } + ids = append(ids, identity.Identity{ + Crypto: pubKey, + Raw: pkixKey, + Fingerprint: hex.EncodeToString(pk.Fingerprint[:]), + }) + } + } + return ids, nil +} diff --git a/pkg/pki/pgp/pgp_test.go b/pkg/pki/pgp/pgp_test.go index 063c9a9cb..9204c701d 100644 --- a/pkg/pki/pgp/pgp_test.go +++ b/pkg/pki/pgp/pgp_test.go @@ -94,7 +94,7 @@ func TestReadSignature(t *testing.T) { type BadReader struct { } -func (br BadReader) Read(p []byte) (n int, err error) { +func (br BadReader) Read(_ []byte) (n int, err error) { return 0, errors.New("test error") } @@ -347,6 +347,9 @@ func TestEmailAddresses(t *testing.T) { caseDesc string inputFile string subjects []string + // number of keys in key ring + // verified with gpg, ignoring DSA/ElGamal keys + keys int } var k PublicKey @@ -354,10 +357,10 @@ func TestEmailAddresses(t *testing.T) { t.Errorf("Subjects for unitialized key should give empty slice") } tests := []test{ - {caseDesc: "Valid armored public key", inputFile: "testdata/valid_armored_public.pgp", subjects: []string{}}, - {caseDesc: "Valid armored public key with multiple subentries", inputFile: "testdata/valid_armored_complex_public.pgp", subjects: []string{"linux-packages-keymaster@google.com", "linux-packages-keymaster@google.com"}}, - {caseDesc: "Valid binary public key", inputFile: "testdata/valid_binary_public.pgp", subjects: []string{}}, - {caseDesc: "Valid binary public key with multiple subentries", inputFile: "testdata/valid_binary_complex_public.pgp", subjects: []string{"linux-packages-keymaster@google.com", "linux-packages-keymaster@google.com"}}, + {caseDesc: "Valid armored public key", inputFile: "testdata/valid_armored_public.pgp", subjects: []string{}, keys: 2}, + {caseDesc: "Valid armored public key with multiple subentries", inputFile: "testdata/valid_armored_complex_public.pgp", subjects: []string{"linux-packages-keymaster@google.com", "linux-packages-keymaster@google.com"}, keys: 4}, + {caseDesc: "Valid binary public key", inputFile: "testdata/valid_binary_public.pgp", subjects: []string{}, keys: 2}, + {caseDesc: "Valid binary public key with multiple subentries", inputFile: "testdata/valid_binary_complex_public.pgp", subjects: []string{"linux-packages-keymaster@google.com", "linux-packages-keymaster@google.com"}, keys: 4}, } for _, tc := range tests { @@ -387,6 +390,13 @@ func TestEmailAddresses(t *testing.T) { t.Errorf("%v: Error getting subjects from keys length, got %v, expected %v", tc.caseDesc, len(subjects), len(tc.subjects)) } + ids, err := inputKey.Identities() + if err != nil { + t.Fatalf("%v: unexpected error getting identities: %v", tc.caseDesc, err) + } + if len(ids) != tc.keys { + t.Fatalf("%v: expected %d keys, got %d", tc.caseDesc, tc.keys, len(ids)) + } } } diff --git a/pkg/pki/pkcs7/pkcs7.go b/pkg/pki/pkcs7/pkcs7.go index f36095678..1701b5a53 100644 --- a/pkg/pki/pkcs7/pkcs7.go +++ b/pkg/pki/pkcs7/pkcs7.go @@ -19,8 +19,10 @@ package pkcs7 import ( "bytes" "crypto" + "crypto/sha256" "crypto/x509" "encoding/asn1" + "encoding/hex" "encoding/pem" "errors" "fmt" @@ -28,6 +30,8 @@ import ( "strings" "github.com/sassoftware/relic/lib/pkcs7" + "github.com/sigstore/rekor/pkg/pki/identity" + "github.com/sigstore/sigstore/pkg/cryptoutils" sigsig "github.com/sigstore/sigstore/pkg/signature" ) @@ -105,7 +109,7 @@ func (s Signature) CanonicalValue() ([]byte, error) { } // Verify implements the pki.Signature interface -func (s Signature) Verify(r io.Reader, k interface{}, opts ...sigsig.VerifyOption) error { +func (s Signature) Verify(r io.Reader, _ interface{}, _ ...sigsig.VerifyOption) error { if len(*s.raw) == 0 { return fmt.Errorf("PKCS7 signature has not been initialized") } @@ -211,5 +215,34 @@ func (k PublicKey) EmailAddresses() []string { // Subjects implements the pki.PublicKey interface func (k PublicKey) Subjects() []string { - return k.EmailAddresses() + // combine identities in the subject and SANs + identities := k.EmailAddresses() + cert, err := x509.ParseCertificate(k.certs[0].Raw) + if err != nil { + // This should not happen from a valid PublicKey, but fail gracefully. + return identities + } + identities = append(identities, cryptoutils.GetSubjectAlternateNames(cert)...) + return identities +} + +// Identities implements the pki.PublicKey interface +func (k PublicKey) Identities() ([]identity.Identity, error) { + // pkcs7 structure may contain both a key and certificate chain + pkixKey, err := cryptoutils.MarshalPublicKeyToDER(k.key) + if err != nil { + return nil, err + } + keyDigest := sha256.Sum256(pkixKey) + certDigest := sha256.Sum256(k.certs[0].Raw) + return []identity.Identity{{ + Crypto: k.certs[0], + Raw: k.certs[0].Raw, + Fingerprint: hex.EncodeToString(certDigest[:]), + }, { + Crypto: k.key, + Raw: pkixKey, + Fingerprint: hex.EncodeToString(keyDigest[:]), + }, + }, nil } diff --git a/pkg/pki/pkcs7/pkcs7_test.go b/pkg/pki/pkcs7/pkcs7_test.go index 9373a0e95..2937ffa2c 100644 --- a/pkg/pki/pkcs7/pkcs7_test.go +++ b/pkg/pki/pkcs7/pkcs7_test.go @@ -18,11 +18,21 @@ package pkcs7 import ( "bytes" + "crypto" + "crypto/sha256" + "crypto/x509" "encoding/base64" + "encoding/hex" + "net/url" "reflect" "sort" "strings" "testing" + + "github.com/sassoftware/relic/lib/pkcs7" + "github.com/sigstore/rekor/pkg/pki/identity" + "github.com/sigstore/rekor/pkg/pki/x509/testutils" + "github.com/sigstore/sigstore/pkg/cryptoutils" ) const pkcsECDSAPEM = `-----BEGIN PKCS7----- @@ -292,7 +302,7 @@ func TestEmailAddresses(t *testing.T) { if err != nil { t.Fatal(err) } - emails := pub.Subjects() + emails := pub.EmailAddresses() if len(emails) == len(tt.emails) { if len(emails) > 0 { @@ -308,5 +318,212 @@ func TestEmailAddresses(t *testing.T) { }) } +} + +func TestSubjects(t *testing.T) { + // dynamically generate a PKCS7 structure with multiple subjects set + url, _ := url.Parse("https://github.com/slsa-framework/slsa-github-generator/.github/workflows/builder_go_slsa3.yml@refs/tags/v1.1.1") + rootCert, rootKey, _ := testutils.GenerateRootCa() + leafCert, leafKey, _ := testutils.GenerateLeafCert("subject@example.com", "oidc-issuer", url, rootCert, rootKey) + + b := pkcs7.NewBuilder(leafKey, []*x509.Certificate{leafCert}, crypto.SHA256) + // set content to random data, only the certificate matters + err := b.SetContentData([]byte{1, 2, 3, 4}) + if err != nil { + t.Fatalf("error setting content data in pkcs7: %v", err) + } + s, err := b.Sign() + if err != nil { + t.Fatalf("error signing pkcs7: %v", err) + } + pkcs7bytes, err := s.Marshal() + if err != nil { + t.Fatalf("error marshalling pkcs7: %v", err) + } + + tests := []struct { + name string + pkcs7 string + subs []string + }{ + { + name: "ec", + pkcs7: pkcsECDSAPEM, + subs: []string{}, + }, + { + name: "email in subject", + pkcs7: pkcsPEMEmail, + subs: []string{"test@rekor.dev"}, + }, + { + name: "email and URI in subject alternative name", + pkcs7: string(pkcs7bytes), + subs: []string{"subject@example.com", "https://github.com/slsa-framework/slsa-github-generator/.github/workflows/builder_go_slsa3.yml@refs/tags/v1.1.1"}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + pub, err := NewPublicKey(strings.NewReader(tt.pkcs7)) + if err != nil { + t.Fatal(err) + } + subs := pub.Subjects() + + if len(subs) == len(tt.subs) { + if len(subs) > 0 { + sort.Strings(subs) + sort.Strings(tt.subs) + if !reflect.DeepEqual(subs, tt.subs) { + t.Errorf("%v: Error getting subjects from keys, got %v, expected %v", tt.name, subs, tt.subs) + } + } + } else { + t.Errorf("%v: Error getting subjects from keys, got %v, expected %v", tt.name, subs, tt.subs) + } + + }) + } +} + +func TestIdentities(t *testing.T) { + // dynamically generate a PKCS7 structure with multiple subjects set + url, _ := url.Parse("https://github.com/slsa-framework/slsa-github-generator/.github/workflows/builder_go_slsa3.yml@refs/tags/v1.1.1") + rootCert, rootKey, _ := testutils.GenerateRootCa() + leafCert, leafKey, _ := testutils.GenerateLeafCert("subject@example.com", "oidc-issuer", url, rootCert, rootKey) + leafPEM, _ := cryptoutils.MarshalPublicKeyToPEM(leafKey.Public()) + leafCertPEM, _ := cryptoutils.MarshalCertificateToPEM(leafCert) + b := pkcs7.NewBuilder(leafKey, []*x509.Certificate{leafCert}, crypto.SHA256) + // set content to random data, only the certificate matters + err := b.SetContentData([]byte{1, 2, 3, 4}) + if err != nil { + t.Fatalf("error setting content data in pkcs7: %v", err) + } + s, err := b.Sign() + if err != nil { + t.Fatalf("error signing pkcs7: %v", err) + } + pkcs7bytes, err := s.Marshal() + if err != nil { + t.Fatalf("error marshalling pkcs7: %v", err) + } + + pkcsECDSAPEMKey := `-----BEGIN PUBLIC KEY----- +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEtLIDsiLmT6k07xkRZjTKV6ZYOjA6Q1re +Qv4ZkTlnkZZ6Ev38D1tE0DdFuuxnmLQlxqy1pEvtKnl+n+MPl3Gpz9R1NWeW9LXp +qf7Zh+zB79C4uiVFQKtw4Tb7aIDn63N3 +-----END PUBLIC KEY----- +` + + pkcsKeyCert := `-----BEGIN CERTIFICATE----- +MIIB+DCCAX6gAwIBAgITNVkDZoCiofPDsy7dfm6geLbuhzAKBggqhkjOPQQDAzAq +MRUwEwYDVQQKEwxzaWdzdG9yZS5kZXYxETAPBgNVBAMTCHNpZ3N0b3JlMB4XDTIx +MDMwNzAzMjAyOVoXDTMxMDIyMzAzMjAyOVowKjEVMBMGA1UEChMMc2lnc3RvcmUu +ZGV2MREwDwYDVQQDEwhzaWdzdG9yZTB2MBAGByqGSM49AgEGBSuBBAAiA2IABLSy +A7Ii5k+pNO8ZEWY0ylemWDowOkNa3kL+GZE5Z5GWehL9/A9bRNA3RbrsZ5i0Jcas +taRL7Sp5fp/jD5dxqc/UdTVnlvS16an+2Yfswe/QuLolRUCrcOE2+2iA5+tzd6Nm +MGQwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE +FMjFHQBBmiQpMlEk6w2uSu1KBtPsMB8GA1UdIwQYMBaAFMjFHQBBmiQpMlEk6w2u +Su1KBtPsMAoGCCqGSM49BAMDA2gAMGUCMH8liWJfMui6vXXBhjDgY4MwslmN/TJx +Ve/83WrFomwmNf056y1X48F9c4m3a3ozXAIxAKjRay5/aj/jsKKGIkmQatjI8uup +Hr/+CxFvaJWmpYqNkLDGRU+9orzh5hI2RrcuaQ== +-----END CERTIFICATE----- +` + + pkcsPEMEmailKey := `-----BEGIN PUBLIC KEY----- +MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQATdJNkml+YiugIcPJvsF20JpeBPBh +C9KiwJQNBrvLYZYbwHDi3T8zcT5drbDO2wc06w9h+IizOJsr6U+MdjYG48gApb4V +3yUzmJu6ExXCqtJDX/CxFdn4waX3a8PcoktQ1emFh8As3N01K2SAoRoTGJ32T1bv +fe8M8nrlQUlDHjuS5qc= +-----END PUBLIC KEY----- +` + + pkcsEmailCert := `-----BEGIN CERTIFICATE----- +MIIC2TCCAjqgAwIBAgIUAL0Gw2SJvPW8PbXw+42XwmW8//owCgYIKoZIzj0EAwIw +fTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAk1BMQ8wDQYDVQQHDAZCb3N0b24xITAf +BgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEOMAwGA1UEAwwFUmVrb3Ix +HTAbBgkqhkiG9w0BCQEWDnRlc3RAcmVrb3IuZGV2MCAXDTIxMDQxOTE0MTMyMFoY +DzQ0ODUwNTMxMTQxMzIwWjB9MQswCQYDVQQGEwJVUzELMAkGA1UECAwCTUExDzAN +BgNVBAcMBkJvc3RvbjEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRk +MQ4wDAYDVQQDDAVSZWtvcjEdMBsGCSqGSIb3DQEJARYOdGVzdEByZWtvci5kZXYw +gZswEAYHKoZIzj0CAQYFK4EEACMDgYYABABN0k2SaX5iK6Ahw8m+wXbQml4E8GEL +0qLAlA0Gu8thlhvAcOLdPzNxPl2tsM7bBzTrD2H4iLM4myvpT4x2NgbjyAClvhXf +JTOYm7oTFcKq0kNf8LEV2fjBpfdrw9yiS1DV6YWHwCzc3TUrZIChGhMYnfZPVu99 +7wzyeuVBSUMeO5Lmp6NTMFEwHQYDVR0OBBYEFJPLiMMFN5Cm6/rjOTPR2HWbbO5P +MB8GA1UdIwQYMBaAFJPLiMMFN5Cm6/rjOTPR2HWbbO5PMA8GA1UdEwEB/wQFMAMB +Af8wCgYIKoZIzj0EAwIDgYwAMIGIAkIBmRqxw8sStWknjeOgdyKkd+vFehNuVaiH +AKGsz+6KG3jPG5xN5+/Ws+OMTAp7Hv6HH5ChDO3LJ6t/sCun1otdWmICQgCUqg1k +e+RjnVqVlz1rUR7CTL2SlG9Xg1kAkYH4vMn/otEuAhnKf+GWLNB1l/dTFNEyysvI +A6ydFG8HXGWcnVVIVQ== +-----END CERTIFICATE----- +` + + tests := []struct { + name string + pkcs7 string + identities []string + }{ + { + name: "ec", + pkcs7: pkcsECDSAPEM, + identities: []string{pkcsKeyCert, pkcsECDSAPEMKey}, + }, + { + name: "email in subject", + pkcs7: pkcsPEMEmail, + identities: []string{pkcsEmailCert, pkcsPEMEmailKey}, + }, + { + name: "email and URI in subject alternative name", + pkcs7: string(pkcs7bytes), + identities: []string{string(leafCertPEM), string(leafPEM)}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + pub, err := NewPublicKey(strings.NewReader(tt.pkcs7)) + if err != nil { + t.Fatal(err) + } + ids, err := pub.Identities() + if err != nil { + t.Fatalf("unexpected error getting identities: %v", err) + } + if len(ids) != 2 { + t.Fatalf("expected 2 identities, got %d", len(ids)) + } + + // compare certificate + cert, _ := cryptoutils.UnmarshalCertificatesFromPEM([]byte(tt.identities[0])) + digest := sha256.Sum256(cert[0].Raw) + expectedID := identity.Identity{Crypto: cert[0], Raw: cert[0].Raw, Fingerprint: hex.EncodeToString(digest[:])} + if !ids[0].Crypto.(*x509.Certificate).Equal(expectedID.Crypto.(*x509.Certificate)) { + t.Errorf("certificates did not match") + } + if !reflect.DeepEqual(ids[0].Raw, expectedID.Raw) { + t.Errorf("raw identities did not match, expected %v, got %v", string(expectedID.Raw), ids[0].Raw) + } + if ids[0].Fingerprint != expectedID.Fingerprint { + t.Fatalf("fingerprints did not match, expected %v, got %v", expectedID.Fingerprint, ids[0].Fingerprint) + } + + // compare public key + key, _ := cryptoutils.UnmarshalPEMToPublicKey([]byte(tt.identities[1])) + pkixKey, _ := cryptoutils.MarshalPublicKeyToDER(key) + digest = sha256.Sum256(pkixKey) + expectedID = identity.Identity{Crypto: key, Raw: pkixKey, Fingerprint: hex.EncodeToString(digest[:])} + if err := cryptoutils.EqualKeys(expectedID.Crypto, ids[1].Crypto); err != nil { + t.Errorf("%v: public keys did not match: %v", tt.name, err) + } + if !reflect.DeepEqual(ids[1].Raw, expectedID.Raw) { + t.Errorf("%v: raw key identities did not match", tt.name) + } + if ids[1].Fingerprint != expectedID.Fingerprint { + t.Fatalf("key fingerprints did not match, expected %v, got %v", expectedID.Fingerprint, ids[1].Fingerprint) + } + }) + } } diff --git a/pkg/pki/pki.go b/pkg/pki/pki.go index d6a2d2135..19688bd1b 100644 --- a/pkg/pki/pki.go +++ b/pkg/pki/pki.go @@ -18,6 +18,7 @@ package pki import ( "io" + "github.com/sigstore/rekor/pkg/pki/identity" sigsig "github.com/sigstore/sigstore/pkg/signature" ) @@ -28,6 +29,8 @@ type PublicKey interface { // also return Subject URIs present in public keys. EmailAddresses() []string Subjects() []string + // Identities returns a list of typed keys and certificates. + Identities() ([]identity.Identity, error) } // Signature Generic object representing a signature (regardless of format & algorithm) diff --git a/pkg/pki/ssh/ssh.go b/pkg/pki/ssh/ssh.go index 86696e3f4..f2caa835f 100644 --- a/pkg/pki/ssh/ssh.go +++ b/pkg/pki/ssh/ssh.go @@ -18,7 +18,11 @@ package ssh import ( "fmt" "io" + "net/http" + "github.com/asaskevich/govalidator" + "github.com/sigstore/rekor/pkg/pki/identity" + "github.com/sigstore/sigstore/pkg/cryptoutils" sigsig "github.com/sigstore/sigstore/pkg/signature" "golang.org/x/crypto/ssh" ) @@ -48,7 +52,7 @@ func (s Signature) CanonicalValue() ([]byte, error) { } // Verify implements the pki.Signature interface -func (s Signature) Verify(r io.Reader, k interface{}, opts ...sigsig.VerifyOption) error { +func (s Signature) Verify(r io.Reader, k interface{}, _ ...sigsig.VerifyOption) error { if s.signature == nil { return fmt.Errorf("ssh signature has not been initialized") } @@ -71,22 +75,28 @@ func (s Signature) Verify(r io.Reader, k interface{}, opts ...sigsig.VerifyOptio // PublicKey contains an ssh PublicKey type PublicKey struct { - key ssh.PublicKey + key ssh.PublicKey + comment string } // NewPublicKey implements the pki.PublicKey interface func NewPublicKey(r io.Reader) (*PublicKey, error) { - rawPub, err := io.ReadAll(r) + // 64K seems generous as a limit for valid SSH keys + // we use http.MaxBytesReader and pass nil for ResponseWriter to reuse stdlib + // and not reimplement this; There is a proposal for this to be fixed in 1.20 + // https://github.com/golang/go/issues/51115 + // TODO: switch this to stdlib once golang 1.20 comes out + rawPub, err := io.ReadAll(http.MaxBytesReader(nil, io.NopCloser(r), 65536)) if err != nil { return nil, err } - key, _, _, _, err := ssh.ParseAuthorizedKey(rawPub) + key, comment, _, _, err := ssh.ParseAuthorizedKey(rawPub) if err != nil { return nil, err } - return &PublicKey{key: key}, nil + return &PublicKey{key: key, comment: comment}, nil } // CanonicalValue implements the pki.PublicKey interface @@ -99,10 +109,28 @@ func (k PublicKey) CanonicalValue() ([]byte, error) { // EmailAddresses implements the pki.PublicKey interface func (k PublicKey) EmailAddresses() []string { + if govalidator.IsEmail(k.comment) { + return []string{k.comment} + } return nil } // Subjects implements the pki.PublicKey interface func (k PublicKey) Subjects() []string { - return nil + return k.EmailAddresses() +} + +// Identities implements the pki.PublicKey interface +func (k PublicKey) Identities() ([]identity.Identity, error) { + key := k.key.(ssh.CryptoPublicKey).CryptoPublicKey() + pkixKey, err := cryptoutils.MarshalPublicKeyToDER(key) + if err != nil { + return nil, err + } + fp := ssh.FingerprintSHA256(k.key) + return []identity.Identity{{ + Crypto: k.key, + Raw: pkixKey, + Fingerprint: fp, + }}, nil } diff --git a/pkg/pki/ssh/ssh_test.go b/pkg/pki/ssh/ssh_test.go new file mode 100644 index 000000000..f06d1e3fd --- /dev/null +++ b/pkg/pki/ssh/ssh_test.go @@ -0,0 +1,97 @@ +// Copyright 2022 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 ssh + +import ( + "encoding/base64" + "math/rand" + "reflect" + "strings" + "testing" + + "github.com/sigstore/sigstore/pkg/cryptoutils" + "golang.org/x/crypto/ssh" +) + +func TestIdentities(t *testing.T) { + // from ssh_e2e_test.go + publicKey := "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDXofkiahE7uavjWvxnwkUF27qMgz7pdTwzSv0XzVG6EtirOv3PDWct4YKoXE9c0EqbxnIfYEKwEextdvB7zkgwczdJSHxf/18jQumLn/FuoCmugVSk1H5Qli/qzwBpaTnOk3WuakGuoYUl8ZAokKKgOKLA0aZJ1WRQ2ZCZggA3EkwNZiY17y9Q6HqdgQcH6XN8aAMADNVJdMAJb33hSRJjjsAPTmzBTishP8lYDoGRSsSE7/8XRBCEV5E4I8mI9GElcZwV/1KJx98mpH8QvMzXM1idFcwPRtt1NTAOshwgUU0Fu1x8lU5RQIa6ZKW36qNQLvLxy/BscC7B/mdLptoDs/ot9NimUXZcgCR1a2Q3o7Wi6jIgcgJcyV10Nba81ol4RdN4qPHnVZIzuo+dBkqwG3CMtB4Rj84+Qi+7zyU01hIPreoxQDXaayiGPBUUIiAlW9gsiuRWJzNnu3cvuWDLVfQIkjh7Wug58z+v2NOJ7IMdyERillhzDcvVHaq14+U= test@rekor.dev" + expectedKey, _, _, _, _ := ssh.ParseAuthorizedKey([]byte(publicKey)) + + pub, err := NewPublicKey(strings.NewReader(publicKey)) + if err != nil { + t.Fatal(err) + } + + if !reflect.DeepEqual(pub.EmailAddresses(), []string{"test@rekor.dev"}) { + t.Fatalf("expected email address, got %v", pub.EmailAddresses()) + } + if !reflect.DeepEqual(pub.Subjects(), []string{"test@rekor.dev"}) { + t.Fatalf("expected email address as subject, got %v", pub.Subjects()) + } + + keyVal := expectedKey.(ssh.CryptoPublicKey).CryptoPublicKey() + pkixKey, err := cryptoutils.MarshalPublicKeyToDER(keyVal) + if err != nil { + t.Fatal(err) + } + ids, err := pub.Identities() + if err != nil { + t.Fatal(err) + } + if len(ids) != 1 { + t.Errorf("too many identities, expected 1, got %v", len(ids)) + } + if !reflect.DeepEqual(ids[0].Crypto.(ssh.PublicKey).Marshal(), expectedKey.Marshal()) { + t.Errorf("certificates did not match") + } + if !reflect.DeepEqual(ids[0].Raw, pkixKey) { + t.Errorf("raw identities did not match, expected %v, got %v", string(pkixKey), string(ids[0].Raw)) + } + // removing "SHA256:" prefix + fp, _ := base64.RawStdEncoding.DecodeString(ids[0].Fingerprint[7:]) + if len(fp) != 32 { + t.Errorf("fingerprint is not expected length of 32 (32-byte sha256): %d", len(fp)) + } +} + +func randomSuffix(n int) string { + const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + + b := make([]byte, n) + for i := range b { + b[i] = letterBytes[rand.Intn(len(letterBytes))] + } + return string(b) +} + +func TestPubKeyParsingLimit(t *testing.T) { + // limit on NewPublicKey should be 65536 bytes, so let's generate a short one first and then extend it to ensure it fails + publicKey := "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDXofkiahE7uavjWvxnwkUF27qMgz7pdTwzSv0XzVG6EtirOv3PDWct4YKoXE9c0EqbxnIfYEKwEextdvB7zkgwczdJSHxf/18jQumLn/FuoCmugVSk1H5Qli/qzwBpaTnOk3WuakGuoYUl8ZAokKKgOKLA0aZJ1WRQ2ZCZggA3EkwNZiY17y9Q6HqdgQcH6XN8aAMADNVJdMAJb33hSRJjjsAPTmzBTishP8lYDoGRSsSE7/8XRBCEV5E4I8mI9GElcZwV/1KJx98mpH8QvMzXM1idFcwPRtt1NTAOshwgUU0Fu1x8lU5RQIa6ZKW36qNQLvLxy/BscC7B/mdLptoDs/ot9NimUXZcgCR1a2Q3o7Wi6jIgcgJcyV10Nba81ol4RdN4qPHnVZIzuo+dBkqwG3CMtB4Rj84+Qi+7zyU01hIPreoxQDXaayiGPBUUIiAlW9gsiuRWJzNnu3cvuWDLVfQIkjh7Wug58z+v2NOJ7IMdyERillhzDcvVHaq14+U= " + randomLongComment := randomSuffix(32768) + + validKey := publicKey + randomLongComment + + if _, err := NewPublicKey(strings.NewReader(validKey)); err != nil { + t.Errorf("unexpected error parsing valid-length key: %v", err) + } + + // now we should be exceeding the length + validKey += randomLongComment + + if _, err := NewPublicKey(strings.NewReader(validKey)); err == nil { + t.Errorf("expected an error parsing invalid-length key") + } +} diff --git a/pkg/pki/tuf/testdata/1.root.json b/pkg/pki/tuf/testdata/1.root.json index d2ddcab9d..7719fb590 100644 --- a/pkg/pki/tuf/testdata/1.root.json +++ b/pkg/pki/tuf/testdata/1.root.json @@ -1,130 +1,156 @@ { - "signatures": [ - { - "keyid": "2f64fb5eac0cf94dd39bb45308b98920055e9a0d8e012a7220787834c60aef97", - "sig": "30450221008a35d51da0f845301a5eac98ad0df00a934f59b709c1eaf81c86be734d9356f80220742942325599749800f52675f6efe124345980a2a636c0dc76f9caf9fc3123b0" - }, - { - "keyid": "bdde902f5ec668179ff5ca0dabf7657109287d690bf97e230c21d65f99155c62", - "sig": "3045022100ef9157ece2a09baec1eab80adfc00b04da20b1f9a0d1b47c5dabc4506719ef2c022074f72acd57398e4ddc8c2a5040df902961e9615dca48f3fbe38cbb506e500066" - }, - { - "keyid": "eaf22372f417dd618a46f6c627dbc276e9fd30a004fc94f9be946e73f8bd090b", - "sig": "30450220420fdc9a09cd069b8b15fd8db9cedf7d0dee75871bd1cfee77c926d4120a770002210097553b5ad0d6b4a13902ed37509638bb63a9009f78230cd56c802909ffbfead7" - }, - { - "keyid": "f40f32044071a9365505da3d1e3be6561f6f22d0e60cf51df783999f6c3429cb", - "sig": "304502202aaf32e66f90752f658672b085ecfe45cc1ad31ee6cf5c9ad05f3267685f8d88022100b5df02acdaa371123db9d7a42219553fe079b230b168833e951be7ee56ded347" - }, - { - "keyid": "f505595165a177a41750a8e864ed1719b1edfccd5a426fd2c0ffda33ce7ff209", - "sig": "304402205d420c7d05c58980c1c9f7d221f53b5334aae27a447d2a91c2ceddd685269749022039ec83e51f8e1779d7f0142dfa4a5bbecfe327fc0b91b7416090fea2416fd53a" - } - ], "signed": { "_type": "root", - "consistent_snapshot": false, - "expires": "2021-12-18T13:28:12.99008-06:00", + "spec_version": "1.0", + "version": 5, + "expires": "2023-04-18T18:13:43Z", "keys": { - "2f64fb5eac0cf94dd39bb45308b98920055e9a0d8e012a7220787834c60aef97": { + "25a0eb450fd3ee2bd79218c963dce3f1cc6118badf251bf149f0bd07d5cabe99": { + "keytype": "ecdsa-sha2-nistp256", + "scheme": "ecdsa-sha2-nistp256", "keyid_hash_algorithms": [ "sha256", "sha512" ], - "keytype": "ecdsa-sha2-nistp256", "keyval": { - "public": "04cbc5cab2684160323c25cd06c3307178a6b1d1c9b949328453ae473c5ba7527e35b13f298b41633382241f3fd8526c262d43b45adee5c618fa0642c82b8a9803" - }, - "scheme": "ecdsa-sha2-nistp256" + "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEEXsz3SZXFb8jMV42j6pJlyjbjR8K\nN3Bwocexq6LMIb5qsWKOQvLN16NUefLc4HswOoumRsVVaajSpQS6fobkRw==\n-----END PUBLIC KEY-----\n" + } }, - "bdde902f5ec668179ff5ca0dabf7657109287d690bf97e230c21d65f99155c62": { + "2e61cd0cbf4a8f45809bda9f7f78c0d33ad11842ff94ae340873e2664dc843de": { + "keytype": "ecdsa-sha2-nistp256", + "scheme": "ecdsa-sha2-nistp256", "keyid_hash_algorithms": [ "sha256", "sha512" ], - "keytype": "ecdsa-sha2-nistp256", "keyval": { - "public": "04a71aacd835dc170ba6db3fa33a1a33dee751d4f8b0217b805b9bd3242921ee93672fdcfd840576c5bb0dc0ed815edf394c1ee48c2b5e02485e59bfc512f3adc7" - }, - "scheme": "ecdsa-sha2-nistp256" + "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE0ghrh92Lw1Yr3idGV5WqCtMDB8Cx\n+D8hdC4w2ZLNIplVRoVGLskYa3gheMyOjiJ8kPi15aQ2//7P+oj7UvJPGw==\n-----END PUBLIC KEY-----\n" + } }, - "eaf22372f417dd618a46f6c627dbc276e9fd30a004fc94f9be946e73f8bd090b": { + "45b283825eb184cabd582eb17b74fc8ed404f68cf452acabdad2ed6f90ce216b": { + "keytype": "ecdsa-sha2-nistp256", + "scheme": "ecdsa-sha2-nistp256", "keyid_hash_algorithms": [ "sha256", "sha512" ], - "keytype": "ecdsa-sha2-nistp256", "keyval": { - "public": "04117b33dd265715bf23315e368faa499728db8d1f0a377070a1c7b1aba2cc21be6ab1628e42f2cdd7a35479f2dce07b303a8ba646c55569a8d2a504ba7e86e447" - }, - "scheme": "ecdsa-sha2-nistp256" + "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAELrWvNt94v4R085ELeeCMxHp7PldF\n0/T1GxukUh2ODuggLGJE0pc1e8CSBf6CS91Fwo9FUOuRsjBUld+VqSyCdQ==\n-----END PUBLIC KEY-----\n" + } }, - "f40f32044071a9365505da3d1e3be6561f6f22d0e60cf51df783999f6c3429cb": { + "7f7513b25429a64473e10ce3ad2f3da372bbdd14b65d07bbaf547e7c8bbbe62b": { + "keytype": "ecdsa-sha2-nistp256", + "scheme": "ecdsa-sha2-nistp256", "keyid_hash_algorithms": [ "sha256", "sha512" ], + "keyval": { + "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEinikSsAQmYkNeH5eYq/CnIzLaacO\nxlSaawQDOwqKy/tCqxq5xxPSJc21K4WIhs9GyOkKfzueY3GILzcMJZ4cWw==\n-----END PUBLIC KEY-----\n" + } + }, + "e1863ba02070322ebc626dcecf9d881a3a38c35c3b41a83765b6ad6c37eaec2a": { "keytype": "ecdsa-sha2-nistp256", + "scheme": "ecdsa-sha2-nistp256", + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], "keyval": { - "public": "04cc1cd53a61c23e88cc54b488dfae168a257c34fac3e88811c55962b24cffbfecb724447999c54670e365883716302e49da57c79a33cd3e16f81fbc66f0bcdf48" - }, - "scheme": "ecdsa-sha2-nistp256" + "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEWRiGr5+j+3J5SsH+Ztr5nE2H2wO7\nBV+nO3s93gLca18qTOzHY1oWyAGDykMSsGTUBSt9D+An0KfKsD2mfSM42Q==\n-----END PUBLIC KEY-----\n" + } }, - "f505595165a177a41750a8e864ed1719b1edfccd5a426fd2c0ffda33ce7ff209": { + "f5312f542c21273d9485a49394386c4575804770667f2ddb59b3bf0669fddd2f": { + "keytype": "ecdsa-sha2-nistp256", + "scheme": "ecdsa-sha2-nistp256", "keyid_hash_algorithms": [ "sha256", "sha512" ], + "keyval": { + "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEzBzVOmHCPojMVLSI364WiiV8NPrD\n6IgRxVliskz/v+y3JER5mcVGcONliDcWMC5J2lfHmjPNPhb4H7xm8LzfSA==\n-----END PUBLIC KEY-----\n" + } + }, + "ff51e17fcf253119b7033f6f57512631da4a0969442afcf9fc8b141c7f2be99c": { "keytype": "ecdsa-sha2-nistp256", + "scheme": "ecdsa-sha2-nistp256", + "keyid_hash_algorithms": [ + "sha256", + "sha512" + ], "keyval": { - "public": "048a78a44ac01099890d787e5e62afc29c8ccb69a70ec6549a6b04033b0a8acbfb42ab1ab9c713d225cdb52b858886cf46c8e90a7f3b9e6371882f370c259e1c5b" - }, - "scheme": "ecdsa-sha2-nistp256" + "public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEy8XKsmhBYDI8Jc0GwzBxeKax0cm5\nSTKEU65HPFunUn41sT8pi0FjM4IkHz/YUmwmLUO0Wt7lxhj6BkLIK4qYAw==\n-----END PUBLIC KEY-----\n" + } } }, "roles": { "root": { "keyids": [ - "2f64fb5eac0cf94dd39bb45308b98920055e9a0d8e012a7220787834c60aef97", - "bdde902f5ec668179ff5ca0dabf7657109287d690bf97e230c21d65f99155c62", - "eaf22372f417dd618a46f6c627dbc276e9fd30a004fc94f9be946e73f8bd090b", - "f40f32044071a9365505da3d1e3be6561f6f22d0e60cf51df783999f6c3429cb", - "f505595165a177a41750a8e864ed1719b1edfccd5a426fd2c0ffda33ce7ff209" + "ff51e17fcf253119b7033f6f57512631da4a0969442afcf9fc8b141c7f2be99c", + "25a0eb450fd3ee2bd79218c963dce3f1cc6118badf251bf149f0bd07d5cabe99", + "f5312f542c21273d9485a49394386c4575804770667f2ddb59b3bf0669fddd2f", + "7f7513b25429a64473e10ce3ad2f3da372bbdd14b65d07bbaf547e7c8bbbe62b", + "2e61cd0cbf4a8f45809bda9f7f78c0d33ad11842ff94ae340873e2664dc843de" ], "threshold": 3 }, "snapshot": { "keyids": [ - "2f64fb5eac0cf94dd39bb45308b98920055e9a0d8e012a7220787834c60aef97", - "bdde902f5ec668179ff5ca0dabf7657109287d690bf97e230c21d65f99155c62", - "eaf22372f417dd618a46f6c627dbc276e9fd30a004fc94f9be946e73f8bd090b", - "f40f32044071a9365505da3d1e3be6561f6f22d0e60cf51df783999f6c3429cb", - "f505595165a177a41750a8e864ed1719b1edfccd5a426fd2c0ffda33ce7ff209" + "45b283825eb184cabd582eb17b74fc8ed404f68cf452acabdad2ed6f90ce216b" ], - "threshold": 3 + "threshold": 1 }, "targets": { "keyids": [ - "2f64fb5eac0cf94dd39bb45308b98920055e9a0d8e012a7220787834c60aef97", - "bdde902f5ec668179ff5ca0dabf7657109287d690bf97e230c21d65f99155c62", - "eaf22372f417dd618a46f6c627dbc276e9fd30a004fc94f9be946e73f8bd090b", - "f40f32044071a9365505da3d1e3be6561f6f22d0e60cf51df783999f6c3429cb", - "f505595165a177a41750a8e864ed1719b1edfccd5a426fd2c0ffda33ce7ff209" + "ff51e17fcf253119b7033f6f57512631da4a0969442afcf9fc8b141c7f2be99c", + "25a0eb450fd3ee2bd79218c963dce3f1cc6118badf251bf149f0bd07d5cabe99", + "f5312f542c21273d9485a49394386c4575804770667f2ddb59b3bf0669fddd2f", + "7f7513b25429a64473e10ce3ad2f3da372bbdd14b65d07bbaf547e7c8bbbe62b", + "2e61cd0cbf4a8f45809bda9f7f78c0d33ad11842ff94ae340873e2664dc843de" ], "threshold": 3 }, "timestamp": { "keyids": [ - "2f64fb5eac0cf94dd39bb45308b98920055e9a0d8e012a7220787834c60aef97", - "bdde902f5ec668179ff5ca0dabf7657109287d690bf97e230c21d65f99155c62", - "eaf22372f417dd618a46f6c627dbc276e9fd30a004fc94f9be946e73f8bd090b", - "f40f32044071a9365505da3d1e3be6561f6f22d0e60cf51df783999f6c3429cb", - "f505595165a177a41750a8e864ed1719b1edfccd5a426fd2c0ffda33ce7ff209" + "e1863ba02070322ebc626dcecf9d881a3a38c35c3b41a83765b6ad6c37eaec2a" ], - "threshold": 3 + "threshold": 1 } }, - "spec_version": "1.0", - "version": 1 - } + "consistent_snapshot": true + }, + "signatures": [ + { + "keyid": "ff51e17fcf253119b7033f6f57512631da4a0969442afcf9fc8b141c7f2be99c", + "sig": "3045022100fc1c2be509ce50ea917bbad1d9efe9d96c8c2ebea04af2717aa3d9c6fe617a75022012eef282a19f2d8bd4818aa333ef48a06489f49d4d34a20b8fe8fc867bb25a7a" + }, + { + "keyid": "25a0eb450fd3ee2bd79218c963dce3f1cc6118badf251bf149f0bd07d5cabe99", + "sig": "30450221008a4392ae5057fc00778b651e61fea244766a4ae58db84d9f1d3810720ab0f3b702207c49e59e8031318caf02252ecea1281cecc1e5986c309a9cef61f455ecf7165d" + }, + { + "keyid": "7f7513b25429a64473e10ce3ad2f3da372bbdd14b65d07bbaf547e7c8bbbe62b", + "sig": "3046022100da1b8dc5d53aaffbbfac98de3e23ee2d2ad3446a7bed09fac0f88bae19be2587022100b681c046afc3919097dfe794e0d819be891e2e850aade315bec06b0c4dea221b" + }, + { + "keyid": "2e61cd0cbf4a8f45809bda9f7f78c0d33ad11842ff94ae340873e2664dc843de", + "sig": "3046022100b534e0030e1b271133ecfbdf3ba9fbf3becb3689abea079a2150afbb63cdb7c70221008c39a718fd9495f249b4ab8788d5b9dc269f0868dbe38b272f48207359d3ded9" + }, + { + "keyid": "2f64fb5eac0cf94dd39bb45308b98920055e9a0d8e012a7220787834c60aef97", + "sig": "3045022100fc1c2be509ce50ea917bbad1d9efe9d96c8c2ebea04af2717aa3d9c6fe617a75022012eef282a19f2d8bd4818aa333ef48a06489f49d4d34a20b8fe8fc867bb25a7a" + }, + { + "keyid": "eaf22372f417dd618a46f6c627dbc276e9fd30a004fc94f9be946e73f8bd090b", + "sig": "30450221008a4392ae5057fc00778b651e61fea244766a4ae58db84d9f1d3810720ab0f3b702207c49e59e8031318caf02252ecea1281cecc1e5986c309a9cef61f455ecf7165d" + }, + { + "keyid": "f505595165a177a41750a8e864ed1719b1edfccd5a426fd2c0ffda33ce7ff209", + "sig": "3046022100da1b8dc5d53aaffbbfac98de3e23ee2d2ad3446a7bed09fac0f88bae19be2587022100b681c046afc3919097dfe794e0d819be891e2e850aade315bec06b0c4dea221b" + }, + { + "keyid": "75e867ab10e121fdef32094af634707f43ddd79c6bab8ad6c5ab9f03f4ea8c90", + "sig": "3046022100b534e0030e1b271133ecfbdf3ba9fbf3becb3689abea079a2150afbb63cdb7c70221008c39a718fd9495f249b4ab8788d5b9dc269f0868dbe38b272f48207359d3ded9" + } + ] } diff --git a/pkg/pki/tuf/testdata/reformat.1.root.json b/pkg/pki/tuf/testdata/reformat.1.root.json index e482e1157..4737c4f10 100644 --- a/pkg/pki/tuf/testdata/reformat.1.root.json +++ b/pkg/pki/tuf/testdata/reformat.1.root.json @@ -1 +1 @@ -{"signatures":[{"keyid":"2f64fb5eac0cf94dd39bb45308b98920055e9a0d8e012a7220787834c60aef97","sig":"30450221008a35d51da0f845301a5eac98ad0df00a934f59b709c1eaf81c86be734d9356f80220742942325599749800f52675f6efe124345980a2a636c0dc76f9caf9fc3123b0"},{"keyid":"bdde902f5ec668179ff5ca0dabf7657109287d690bf97e230c21d65f99155c62","sig":"3045022100ef9157ece2a09baec1eab80adfc00b04da20b1f9a0d1b47c5dabc4506719ef2c022074f72acd57398e4ddc8c2a5040df902961e9615dca48f3fbe38cbb506e500066"},{"keyid":"eaf22372f417dd618a46f6c627dbc276e9fd30a004fc94f9be946e73f8bd090b","sig":"30450220420fdc9a09cd069b8b15fd8db9cedf7d0dee75871bd1cfee77c926d4120a770002210097553b5ad0d6b4a13902ed37509638bb63a9009f78230cd56c802909ffbfead7"},{"keyid":"f40f32044071a9365505da3d1e3be6561f6f22d0e60cf51df783999f6c3429cb","sig":"304502202aaf32e66f90752f658672b085ecfe45cc1ad31ee6cf5c9ad05f3267685f8d88022100b5df02acdaa371123db9d7a42219553fe079b230b168833e951be7ee56ded347"},{"keyid":"f505595165a177a41750a8e864ed1719b1edfccd5a426fd2c0ffda33ce7ff209","sig":"304402205d420c7d05c58980c1c9f7d221f53b5334aae27a447d2a91c2ceddd685269749022039ec83e51f8e1779d7f0142dfa4a5bbecfe327fc0b91b7416090fea2416fd53a"}],"signed":{"_type":"root","consistent_snapshot":false,"expires":"2021-12-18T13:28:12.99008-06:00","keys":{"2f64fb5eac0cf94dd39bb45308b98920055e9a0d8e012a7220787834c60aef97":{"keyid_hash_algorithms":["sha256","sha512"],"keytype":"ecdsa-sha2-nistp256","keyval":{"public":"04cbc5cab2684160323c25cd06c3307178a6b1d1c9b949328453ae473c5ba7527e35b13f298b41633382241f3fd8526c262d43b45adee5c618fa0642c82b8a9803"},"scheme":"ecdsa-sha2-nistp256"},"bdde902f5ec668179ff5ca0dabf7657109287d690bf97e230c21d65f99155c62":{"keyid_hash_algorithms":["sha256","sha512"],"keytype":"ecdsa-sha2-nistp256","keyval":{"public":"04a71aacd835dc170ba6db3fa33a1a33dee751d4f8b0217b805b9bd3242921ee93672fdcfd840576c5bb0dc0ed815edf394c1ee48c2b5e02485e59bfc512f3adc7"},"scheme":"ecdsa-sha2-nistp256"},"eaf22372f417dd618a46f6c627dbc276e9fd30a004fc94f9be946e73f8bd090b":{"keyid_hash_algorithms":["sha256","sha512"],"keytype":"ecdsa-sha2-nistp256","keyval":{"public":"04117b33dd265715bf23315e368faa499728db8d1f0a377070a1c7b1aba2cc21be6ab1628e42f2cdd7a35479f2dce07b303a8ba646c55569a8d2a504ba7e86e447"},"scheme":"ecdsa-sha2-nistp256"},"f40f32044071a9365505da3d1e3be6561f6f22d0e60cf51df783999f6c3429cb":{"keyid_hash_algorithms":["sha256","sha512"],"keytype":"ecdsa-sha2-nistp256","keyval":{"public":"04cc1cd53a61c23e88cc54b488dfae168a257c34fac3e88811c55962b24cffbfecb724447999c54670e365883716302e49da57c79a33cd3e16f81fbc66f0bcdf48"},"scheme":"ecdsa-sha2-nistp256"},"f505595165a177a41750a8e864ed1719b1edfccd5a426fd2c0ffda33ce7ff209":{"keyid_hash_algorithms":["sha256","sha512"],"keytype":"ecdsa-sha2-nistp256","keyval":{"public":"048a78a44ac01099890d787e5e62afc29c8ccb69a70ec6549a6b04033b0a8acbfb42ab1ab9c713d225cdb52b858886cf46c8e90a7f3b9e6371882f370c259e1c5b"},"scheme":"ecdsa-sha2-nistp256"}},"roles":{"root":{"keyids":["2f64fb5eac0cf94dd39bb45308b98920055e9a0d8e012a7220787834c60aef97","bdde902f5ec668179ff5ca0dabf7657109287d690bf97e230c21d65f99155c62","eaf22372f417dd618a46f6c627dbc276e9fd30a004fc94f9be946e73f8bd090b","f40f32044071a9365505da3d1e3be6561f6f22d0e60cf51df783999f6c3429cb","f505595165a177a41750a8e864ed1719b1edfccd5a426fd2c0ffda33ce7ff209"],"threshold":3},"snapshot":{"keyids":["2f64fb5eac0cf94dd39bb45308b98920055e9a0d8e012a7220787834c60aef97","bdde902f5ec668179ff5ca0dabf7657109287d690bf97e230c21d65f99155c62","eaf22372f417dd618a46f6c627dbc276e9fd30a004fc94f9be946e73f8bd090b","f40f32044071a9365505da3d1e3be6561f6f22d0e60cf51df783999f6c3429cb","f505595165a177a41750a8e864ed1719b1edfccd5a426fd2c0ffda33ce7ff209"],"threshold":3},"targets":{"keyids":["2f64fb5eac0cf94dd39bb45308b98920055e9a0d8e012a7220787834c60aef97","bdde902f5ec668179ff5ca0dabf7657109287d690bf97e230c21d65f99155c62","eaf22372f417dd618a46f6c627dbc276e9fd30a004fc94f9be946e73f8bd090b","f40f32044071a9365505da3d1e3be6561f6f22d0e60cf51df783999f6c3429cb","f505595165a177a41750a8e864ed1719b1edfccd5a426fd2c0ffda33ce7ff209"],"threshold":3},"timestamp":{"keyids":["2f64fb5eac0cf94dd39bb45308b98920055e9a0d8e012a7220787834c60aef97","bdde902f5ec668179ff5ca0dabf7657109287d690bf97e230c21d65f99155c62","eaf22372f417dd618a46f6c627dbc276e9fd30a004fc94f9be946e73f8bd090b","f40f32044071a9365505da3d1e3be6561f6f22d0e60cf51df783999f6c3429cb","f505595165a177a41750a8e864ed1719b1edfccd5a426fd2c0ffda33ce7ff209"],"threshold":3}},"spec_version":"1.0","version":1}} \ No newline at end of file +{"signed":{"_type":"root","spec_version":"1.0","version":5,"expires":"2023-04-18T18:13:43Z","keys":{"25a0eb450fd3ee2bd79218c963dce3f1cc6118badf251bf149f0bd07d5cabe99":{"keytype":"ecdsa-sha2-nistp256","scheme":"ecdsa-sha2-nistp256","keyid_hash_algorithms":["sha256","sha512"],"keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEEXsz3SZXFb8jMV42j6pJlyjbjR8K\nN3Bwocexq6LMIb5qsWKOQvLN16NUefLc4HswOoumRsVVaajSpQS6fobkRw==\n-----END PUBLIC KEY-----\n"}},"2e61cd0cbf4a8f45809bda9f7f78c0d33ad11842ff94ae340873e2664dc843de":{"keytype":"ecdsa-sha2-nistp256","scheme":"ecdsa-sha2-nistp256","keyid_hash_algorithms":["sha256","sha512"],"keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE0ghrh92Lw1Yr3idGV5WqCtMDB8Cx\n+D8hdC4w2ZLNIplVRoVGLskYa3gheMyOjiJ8kPi15aQ2//7P+oj7UvJPGw==\n-----END PUBLIC KEY-----\n"}},"45b283825eb184cabd582eb17b74fc8ed404f68cf452acabdad2ed6f90ce216b":{"keytype":"ecdsa-sha2-nistp256","scheme":"ecdsa-sha2-nistp256","keyid_hash_algorithms":["sha256","sha512"],"keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAELrWvNt94v4R085ELeeCMxHp7PldF\n0/T1GxukUh2ODuggLGJE0pc1e8CSBf6CS91Fwo9FUOuRsjBUld+VqSyCdQ==\n-----END PUBLIC KEY-----\n"}},"7f7513b25429a64473e10ce3ad2f3da372bbdd14b65d07bbaf547e7c8bbbe62b":{"keytype":"ecdsa-sha2-nistp256","scheme":"ecdsa-sha2-nistp256","keyid_hash_algorithms":["sha256","sha512"],"keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEinikSsAQmYkNeH5eYq/CnIzLaacO\nxlSaawQDOwqKy/tCqxq5xxPSJc21K4WIhs9GyOkKfzueY3GILzcMJZ4cWw==\n-----END PUBLIC KEY-----\n"}},"e1863ba02070322ebc626dcecf9d881a3a38c35c3b41a83765b6ad6c37eaec2a":{"keytype":"ecdsa-sha2-nistp256","scheme":"ecdsa-sha2-nistp256","keyid_hash_algorithms":["sha256","sha512"],"keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEWRiGr5+j+3J5SsH+Ztr5nE2H2wO7\nBV+nO3s93gLca18qTOzHY1oWyAGDykMSsGTUBSt9D+An0KfKsD2mfSM42Q==\n-----END PUBLIC KEY-----\n"}},"f5312f542c21273d9485a49394386c4575804770667f2ddb59b3bf0669fddd2f":{"keytype":"ecdsa-sha2-nistp256","scheme":"ecdsa-sha2-nistp256","keyid_hash_algorithms":["sha256","sha512"],"keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEzBzVOmHCPojMVLSI364WiiV8NPrD\n6IgRxVliskz/v+y3JER5mcVGcONliDcWMC5J2lfHmjPNPhb4H7xm8LzfSA==\n-----END PUBLIC KEY-----\n"}},"ff51e17fcf253119b7033f6f57512631da4a0969442afcf9fc8b141c7f2be99c":{"keytype":"ecdsa-sha2-nistp256","scheme":"ecdsa-sha2-nistp256","keyid_hash_algorithms":["sha256","sha512"],"keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEy8XKsmhBYDI8Jc0GwzBxeKax0cm5\nSTKEU65HPFunUn41sT8pi0FjM4IkHz/YUmwmLUO0Wt7lxhj6BkLIK4qYAw==\n-----END PUBLIC KEY-----\n"}}},"roles":{"root":{"keyids":["ff51e17fcf253119b7033f6f57512631da4a0969442afcf9fc8b141c7f2be99c","25a0eb450fd3ee2bd79218c963dce3f1cc6118badf251bf149f0bd07d5cabe99","f5312f542c21273d9485a49394386c4575804770667f2ddb59b3bf0669fddd2f","7f7513b25429a64473e10ce3ad2f3da372bbdd14b65d07bbaf547e7c8bbbe62b","2e61cd0cbf4a8f45809bda9f7f78c0d33ad11842ff94ae340873e2664dc843de"],"threshold":3},"snapshot":{"keyids":["45b283825eb184cabd582eb17b74fc8ed404f68cf452acabdad2ed6f90ce216b"],"threshold":1},"targets":{"keyids":["ff51e17fcf253119b7033f6f57512631da4a0969442afcf9fc8b141c7f2be99c","25a0eb450fd3ee2bd79218c963dce3f1cc6118badf251bf149f0bd07d5cabe99","f5312f542c21273d9485a49394386c4575804770667f2ddb59b3bf0669fddd2f","7f7513b25429a64473e10ce3ad2f3da372bbdd14b65d07bbaf547e7c8bbbe62b","2e61cd0cbf4a8f45809bda9f7f78c0d33ad11842ff94ae340873e2664dc843de"],"threshold":3},"timestamp":{"keyids":["e1863ba02070322ebc626dcecf9d881a3a38c35c3b41a83765b6ad6c37eaec2a"],"threshold":1}},"consistent_snapshot":true},"signatures":[{"keyid":"ff51e17fcf253119b7033f6f57512631da4a0969442afcf9fc8b141c7f2be99c","sig":"3045022100fc1c2be509ce50ea917bbad1d9efe9d96c8c2ebea04af2717aa3d9c6fe617a75022012eef282a19f2d8bd4818aa333ef48a06489f49d4d34a20b8fe8fc867bb25a7a"},{"keyid":"25a0eb450fd3ee2bd79218c963dce3f1cc6118badf251bf149f0bd07d5cabe99","sig":"30450221008a4392ae5057fc00778b651e61fea244766a4ae58db84d9f1d3810720ab0f3b702207c49e59e8031318caf02252ecea1281cecc1e5986c309a9cef61f455ecf7165d"},{"keyid":"7f7513b25429a64473e10ce3ad2f3da372bbdd14b65d07bbaf547e7c8bbbe62b","sig":"3046022100da1b8dc5d53aaffbbfac98de3e23ee2d2ad3446a7bed09fac0f88bae19be2587022100b681c046afc3919097dfe794e0d819be891e2e850aade315bec06b0c4dea221b"},{"keyid":"2e61cd0cbf4a8f45809bda9f7f78c0d33ad11842ff94ae340873e2664dc843de","sig":"3046022100b534e0030e1b271133ecfbdf3ba9fbf3becb3689abea079a2150afbb63cdb7c70221008c39a718fd9495f249b4ab8788d5b9dc269f0868dbe38b272f48207359d3ded9"},{"keyid":"2f64fb5eac0cf94dd39bb45308b98920055e9a0d8e012a7220787834c60aef97","sig":"3045022100fc1c2be509ce50ea917bbad1d9efe9d96c8c2ebea04af2717aa3d9c6fe617a75022012eef282a19f2d8bd4818aa333ef48a06489f49d4d34a20b8fe8fc867bb25a7a"},{"keyid":"eaf22372f417dd618a46f6c627dbc276e9fd30a004fc94f9be946e73f8bd090b","sig":"30450221008a4392ae5057fc00778b651e61fea244766a4ae58db84d9f1d3810720ab0f3b702207c49e59e8031318caf02252ecea1281cecc1e5986c309a9cef61f455ecf7165d"},{"keyid":"f505595165a177a41750a8e864ed1719b1edfccd5a426fd2c0ffda33ce7ff209","sig":"3046022100da1b8dc5d53aaffbbfac98de3e23ee2d2ad3446a7bed09fac0f88bae19be2587022100b681c046afc3919097dfe794e0d819be891e2e850aade315bec06b0c4dea221b"},{"keyid":"75e867ab10e121fdef32094af634707f43ddd79c6bab8ad6c5ab9f03f4ea8c90","sig":"3046022100b534e0030e1b271133ecfbdf3ba9fbf3becb3689abea079a2150afbb63cdb7c70221008c39a718fd9495f249b4ab8788d5b9dc269f0868dbe38b272f48207359d3ded9"}]} \ No newline at end of file diff --git a/pkg/pki/tuf/testdata/timestamp.json b/pkg/pki/tuf/testdata/timestamp.json index 5bea8900a..3ff09fe94 100644 --- a/pkg/pki/tuf/testdata/timestamp.json +++ b/pkg/pki/tuf/testdata/timestamp.json @@ -1,39 +1,24 @@ { - "signatures": [ - { - "keyid": "2f64fb5eac0cf94dd39bb45308b98920055e9a0d8e012a7220787834c60aef97", - "sig": "3044022079252576532ed5ed4a19e4135997d89172101ed745a4489be6b20d04d483bbcc0220515119aab690033dc1e1650f08995dc839dcd161cab3898db0749063ca32dc86" - }, - { - "keyid": "bdde902f5ec668179ff5ca0dabf7657109287d690bf97e230c21d65f99155c62", - "sig": "3045022100c5216dd17d381c951b5174f8ee2157b315d1f26247e7f9e49c42cf975dfcf49b022048fb1751a86fddedc21129e94a3e7e0efeeb93f1238fad6636bbf0c0d39543e8" - }, - { - "keyid": "eaf22372f417dd618a46f6c627dbc276e9fd30a004fc94f9be946e73f8bd090b", - "sig": "3045022042c6b4003deee27db7db6f5aebb29ac89625fd7389dfff434fa93c65cf8aed5f022100fe6cbd036b5fce1169d7392ecfaf76e01f05fdc6c81cf9bae8c9227fc09c65d9" - }, - { - "keyid": "f40f32044071a9365505da3d1e3be6561f6f22d0e60cf51df783999f6c3429cb", - "sig": "3045022100bc431b7315c2aa657418835005692021de7496bbc7c1a2fedf2aafe8d861ca5402200cbca80a4555d8236265e1b746743532894b46257c450ff8706d0e50e659978c" - }, - { - "keyid": "f505595165a177a41750a8e864ed1719b1edfccd5a426fd2c0ffda33ce7ff209", - "sig": "3046022100c09aea2f05e94a656bd70379340c7b5f09b24bbd20adf4855be3783d7ce39482022100da93a8a1577599979d38bfc44016bde5838d9548797fc9e960780276855bbcf9" - } - ], "signed": { "_type": "timestamp", - "expires": "2021-12-18T13:28:12.99008-06:00", + "spec_version": "1.0", + "version": 53, + "expires": "2022-11-03T21:10:23Z", "meta": { "snapshot.json": { + "length": 1973, "hashes": { - "sha512": "9103503c18f7da2098dce04892948ad240c1b9965048c4ab4da0c32248f3491652d91d76fe9022be2cf15a99e68b3a3ddd1034e5293c8aac86d0446c4354716d" + "sha256": "d1eea940c4e3fff8a3ae5932a38ca35fdd789e1a85d4919f3316efd879c0e0ed", + "sha512": "d0848c412728e5db9ad0713d3d1c319f7cc2bde67082da95f79f740ef26e1fee91a32b1eb948b47bb2c06b71557f60e61605e512e40dd4b25c907ac3f4ca6e91" }, - "length": 1849, - "version": 1 + "version": 53 } - }, - "spec_version": "1.0", - "version": 1 - } + } + }, + "signatures": [ + { + "keyid": "e1863ba02070322ebc626dcecf9d881a3a38c35c3b41a83765b6ad6c37eaec2a", + "sig": "304502202bb5ce4034ea4be68a9a6c9af77b48911294f1492d7add5a763a5a77bc863f27022100d4ab20ffa8790e6a28e7f1e66495e1fc5242bed0f5222312e76ec60235270df2" + } + ] } diff --git a/pkg/pki/tuf/tuf.go b/pkg/pki/tuf/tuf.go index a4d51c81d..f2983481d 100644 --- a/pkg/pki/tuf/tuf.go +++ b/pkg/pki/tuf/tuf.go @@ -16,14 +16,21 @@ package tuf import ( + "crypto/ed25519" + "crypto/sha256" + "crypto/x509" + "encoding/hex" "encoding/json" "fmt" "io" "time" + "github.com/cyberphone/json-canonicalization/go/src/webpki.org/jsoncanonicalizer" + "github.com/sigstore/rekor/pkg/pki/identity" + "github.com/sigstore/sigstore/pkg/cryptoutils" sigsig "github.com/sigstore/sigstore/pkg/signature" - cjson "github.com/tent/canonical-json-go" "github.com/theupdateframework/go-tuf/data" + "github.com/theupdateframework/go-tuf/pkg/keys" "github.com/theupdateframework/go-tuf/verify" ) @@ -70,17 +77,15 @@ func (s Signature) CanonicalValue() ([]byte, error) { if s.signed == nil { return nil, fmt.Errorf("tuf manifest has not been initialized") } - // TODO(asraa): Should the Signed payload be canonicalized? - canonical, err := cjson.Marshal(s.signed) + marshalledBytes, err := json.Marshal(s.signed) if err != nil { - return nil, err + return nil, fmt.Errorf("marshalling signature: %w", err) } - - return canonical, nil + return jsoncanonicalizer.Transform(marshalledBytes) } // Verify implements the pki.Signature interface -func (s Signature) Verify(_ io.Reader, k interface{}, opts ...sigsig.VerifyOption) error { +func (s Signature) Verify(_ io.Reader, k interface{}, _ ...sigsig.VerifyOption) error { key, ok := k.(*PublicKey) if !ok { return fmt.Errorf("invalid public key type for: %v", k) @@ -140,16 +145,14 @@ func NewPublicKey(r io.Reader) (*PublicKey, error) { // CanonicalValue implements the pki.PublicKey interface func (k PublicKey) CanonicalValue() (encoded []byte, err error) { - // TODO(asraa): Should the Signed payload be canonicalized? if k.root == nil { return nil, fmt.Errorf("tuf root has not been initialized") } - canonical, err := cjson.Marshal(k.root) + marshalledBytes, err := json.Marshal(k.root) if err != nil { - return nil, err + return nil, fmt.Errorf("marshalling tuf root: %w", err) } - - return canonical, nil + return jsoncanonicalizer.Transform(marshalledBytes) } func (k PublicKey) SpecVersion() (string, error) { @@ -170,3 +173,58 @@ func (k PublicKey) EmailAddresses() []string { func (k PublicKey) Subjects() []string { return nil } + +// Identities implements the pki.PublicKey interface +func (k PublicKey) Identities() ([]identity.Identity, error) { + root := &data.Root{} + if err := json.Unmarshal(k.root.Signed, root); err != nil { + return nil, err + } + var ids []identity.Identity + for _, k := range root.Keys { + verifier, err := keys.GetVerifier(k) + if err != nil { + return nil, err + } + switch k.Type { + // RSA and ECDSA keys are PKIX-encoded without PEM header for the Verifier type + case data.KeyTypeRSASSA_PSS_SHA256: + fallthrough + // TODO: Update to constants once go-tuf is updated to 0.6.0 (need PR #508) + case "ecdsa-sha2-nistp256": + fallthrough + case "ecdsa": + // parse and marshal to check format is correct + pub, err := x509.ParsePKIXPublicKey([]byte(verifier.Public())) + if err != nil { + return nil, err + } + pkixKey, err := cryptoutils.MarshalPublicKeyToDER(pub) + if err != nil { + return nil, err + } + digest := sha256.Sum256(pkixKey) + ids = append(ids, identity.Identity{ + Crypto: pub, + Raw: pkixKey, + Fingerprint: hex.EncodeToString(digest[:]), + }) + case data.KeyTypeEd25519: + // key is stored as a 32-byte string + pub := ed25519.PublicKey(verifier.Public()) + pkixKey, err := cryptoutils.MarshalPublicKeyToDER(pub) + if err != nil { + return nil, err + } + digest := sha256.Sum256(pkixKey) + ids = append(ids, identity.Identity{ + Crypto: pub, + Raw: pkixKey, + Fingerprint: hex.EncodeToString(digest[:]), + }) + default: + return nil, fmt.Errorf("unsupported key type: %v", k.Type) + } + } + return ids, nil +} diff --git a/pkg/pki/tuf/tuf_test.go b/pkg/pki/tuf/tuf_test.go index ae5db65fb..93a33e6ec 100644 --- a/pkg/pki/tuf/tuf_test.go +++ b/pkg/pki/tuf/tuf_test.go @@ -17,11 +17,15 @@ package tuf import ( "bytes" + "crypto/ecdsa" + "crypto/x509" "io" "os" + "reflect" "testing" "time" + "github.com/sigstore/sigstore/pkg/cryptoutils" _ "github.com/theupdateframework/go-tuf/pkg/deprecated/set_ecdsa" "github.com/theupdateframework/go-tuf/verify" ) @@ -74,6 +78,29 @@ func TestReadPublicKey(t *testing.T) { if specVersion != tc.specVersion { t.Errorf("%v: unexpected spec version expected %v, got %v", tc.caseDesc, tc.specVersion, specVersion) } + + identities, err := got.Identities() + if err != nil { + t.Errorf("%v: error getting identities for %v: %v", tc.caseDesc, tc.inputFile, err) + } + if len(identities) != 7 { + t.Errorf("%v: expected 7 identities, got: %d", tc.caseDesc, len(identities)) + } + for _, i := range identities { + if _, ok := i.Crypto.(*ecdsa.PublicKey); !ok { + t.Errorf("%v: key was not of type *ecdsa.PublicKey: %v", tc.caseDesc, reflect.TypeOf(i.Crypto)) + } + key, err := x509.ParsePKIXPublicKey(i.Raw) + if err != nil { + t.Fatalf("%v: Raw is not in PKIX format: %v", tc.caseDesc, err) + } + if err := cryptoutils.EqualKeys(key, i.Crypto); err != nil { + t.Errorf("%v: raw key and crypto key not equal: %v", tc.caseDesc, err) + } + if len(i.Fingerprint) != 64 { + t.Errorf("%v: fingerprint is not expected length of 64 (hex 32-byte sha256): %d", tc.caseDesc, len(i.Fingerprint)) + } + } } } } @@ -151,12 +178,12 @@ func TestCanonicalValue(t *testing.T) { outputKey, err := NewPublicKey(outputFile) if err != nil { - t.Errorf("%v: Error reading input for TestCanonicalValue: %v", tc.caseDesc, err) + t.Fatalf("%v: Error reading input for TestCanonicalValue: %v", tc.caseDesc, err) } cvOutput, err := outputKey.CanonicalValue() if err != nil { - t.Errorf("%v: Error canonicalizing public key '%v': %v", tc.caseDesc, tc.input, err) + t.Fatalf("%v: Error canonicalizing public key '%v': %v", tc.caseDesc, tc.input, err) } if bytes.Equal(cvInput, cvOutput) != tc.match { diff --git a/pkg/pki/x509/e2e.go b/pkg/pki/x509/e2e.go index e15cb7c3a..62a459908 100644 --- a/pkg/pki/x509/e2e.go +++ b/pkg/pki/x509/e2e.go @@ -20,6 +20,7 @@ package x509 import ( "bytes" + "context" "crypto" "crypto/rand" "crypto/rsa" @@ -173,7 +174,7 @@ func (v *Verifier) Public() crypto.PublicKey { return v.v.PublicKey } -func (v *Verifier) Sign(data []byte) (sig []byte, err error) { +func (v *Verifier) Sign(_ context.Context, data []byte) (sig []byte, err error) { if v.S == nil { return nil, errors.New("nil signer") } @@ -184,7 +185,7 @@ func (v *Verifier) Sign(data []byte) (sig []byte, err error) { return sig, nil } -func (v *Verifier) Verify(data, sig []byte) error { +func (v *Verifier) Verify(_ context.Context, data, sig []byte) error { if v.v == nil { return errors.New("nil Verifier") } diff --git a/pkg/pki/x509/testutils/cert_test_utils.go b/pkg/pki/x509/testutils/cert_test_utils.go index c6ce32bb5..5972a65f3 100644 --- a/pkg/pki/x509/testutils/cert_test_utils.go +++ b/pkg/pki/x509/testutils/cert_test_utils.go @@ -23,6 +23,7 @@ import ( "crypto/x509/pkix" "encoding/asn1" "math/big" + "net" "net/url" "time" ) @@ -116,12 +117,46 @@ func GenerateSubordinateCa(rootTemplate *x509.Certificate, rootPriv crypto.Signe return cert, priv, nil } -func GenerateLeafCert(subject, oidcIssuer string, uri *url.URL, parentTemplate *x509.Certificate, parentPriv crypto.Signer) (*x509.Certificate, *ecdsa.PrivateKey, error) { +func GenerateLeafCert(subject, oidcIssuer string, uri *url.URL, parentTemplate *x509.Certificate, parentPriv crypto.Signer, exts ...pkix.Extension) (*x509.Certificate, *ecdsa.PrivateKey, error) { + exts = append(exts, pkix.Extension{ + // OID for OIDC Issuer extension + Id: asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 1}, + Critical: false, + Value: []byte(oidcIssuer), + }) + certTemplate := &x509.Certificate{ + SerialNumber: big.NewInt(1), + EmailAddresses: []string{subject}, + NotBefore: time.Now().Add(-1 * time.Minute), + NotAfter: time.Now().Add(time.Hour), + KeyUsage: x509.KeyUsageDigitalSignature, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageCodeSigning}, + IsCA: false, + ExtraExtensions: exts, + } + if uri != nil { + certTemplate.URIs = []*url.URL{uri} + } + + priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + return nil, nil, err + } + + cert, err := createCertificate(certTemplate, parentTemplate, &priv.PublicKey, parentPriv) + if err != nil { + return nil, nil, err + } + + return cert, priv, nil +} + +func GenerateExpiredLeafCert(subject string, oidcIssuer string, parentTemplate *x509.Certificate, parentPriv crypto.Signer) (*x509.Certificate, *ecdsa.PrivateKey, error) { certTemplate := &x509.Certificate{ SerialNumber: big.NewInt(1), EmailAddresses: []string{subject}, - NotBefore: time.Now().Add(-1 * time.Minute), - NotAfter: time.Now().Add(time.Hour), + NotBefore: time.Now().Add(-5 * time.Minute), + NotAfter: time.Now().Add(-2 * time.Minute), KeyUsage: x509.KeyUsageDigitalSignature, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageCodeSigning}, IsCA: false, @@ -132,9 +167,6 @@ func GenerateLeafCert(subject, oidcIssuer string, uri *url.URL, parentTemplate * Value: []byte(oidcIssuer), }}, } - if uri != nil { - certTemplate.URIs = []*url.URL{uri} - } priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { @@ -149,12 +181,15 @@ func GenerateLeafCert(subject, oidcIssuer string, uri *url.URL, parentTemplate * return cert, priv, nil } -func GenerateExpiredLeafCert(subject string, oidcIssuer string, parentTemplate *x509.Certificate, parentPriv crypto.Signer) (*x509.Certificate, *ecdsa.PrivateKey, error) { +func GenerateLeafCertWithSubjectAlternateNames(dnsNames []string, emailAddresses []string, ipAddresses []net.IP, uris []*url.URL, oidcIssuer string, parentTemplate *x509.Certificate, parentPriv crypto.Signer) (*x509.Certificate, *ecdsa.PrivateKey, error) { certTemplate := &x509.Certificate{ SerialNumber: big.NewInt(1), - EmailAddresses: []string{subject}, - NotBefore: time.Now().Add(-5 * time.Minute), - NotAfter: time.Now().Add(-2 * time.Minute), + EmailAddresses: emailAddresses, + DNSNames: dnsNames, + IPAddresses: ipAddresses, + URIs: uris, + NotBefore: time.Now().Add(-1 * time.Minute), + NotAfter: time.Now().Add(time.Hour), KeyUsage: x509.KeyUsageDigitalSignature, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageCodeSigning}, IsCA: false, diff --git a/pkg/pki/x509/x509.go b/pkg/pki/x509/x509.go index aefff8af6..2589849c4 100644 --- a/pkg/pki/x509/x509.go +++ b/pkg/pki/x509/x509.go @@ -18,8 +18,10 @@ package x509 import ( "bytes" "crypto" + "crypto/sha256" "crypto/x509" "encoding/asn1" + "encoding/hex" "encoding/pem" "errors" "fmt" @@ -27,6 +29,7 @@ import ( "strings" validator "github.com/go-playground/validator/v10" + "github.com/sigstore/rekor/pkg/pki/identity" "github.com/sigstore/sigstore/pkg/cryptoutils" sigsig "github.com/sigstore/sigstore/pkg/signature" ) @@ -194,7 +197,7 @@ func (k PublicKey) EmailAddresses() []string { // Subjects implements the pki.PublicKey interface func (k PublicKey) Subjects() []string { - var names []string + var subjects []string var cert *x509.Certificate if k.cert != nil { cert = k.cert.c @@ -202,19 +205,43 @@ func (k PublicKey) Subjects() []string { cert = k.certs[0] } if cert != nil { - validate := validator.New() - for _, name := range cert.EmailAddresses { - if errs := validate.Var(name, "required,email"); errs == nil { - names = append(names, strings.ToLower(name)) - } - } - for _, name := range cert.URIs { - if errs := validate.Var(name.String(), "required,uri"); errs == nil { - names = append(names, strings.ToLower(name.String())) - } + subjects = cryptoutils.GetSubjectAlternateNames(cert) + } + return subjects +} + +// Identities implements the pki.PublicKey interface +func (k PublicKey) Identities() ([]identity.Identity, error) { + // k contains either a key, a cert, or a list of certs + if k.key != nil { + pkixKey, err := cryptoutils.MarshalPublicKeyToDER(k.key) + if err != nil { + return nil, err } + digest := sha256.Sum256(pkixKey) + return []identity.Identity{{ + Crypto: k.key, + Raw: pkixKey, + Fingerprint: hex.EncodeToString(digest[:]), + }}, nil } - return names + + var cert *x509.Certificate + switch { + case k.cert != nil: + cert = k.cert.c + case len(k.certs) > 0: + cert = k.certs[0] + default: + return nil, errors.New("no key, certificate or certificate chain provided") + } + + digest := sha256.Sum256(cert.Raw) + return []identity.Identity{{ + Crypto: cert, + Raw: cert.Raw, + Fingerprint: hex.EncodeToString(digest[:]), + }}, nil } func verifyCertChain(certChain []*x509.Certificate) error { diff --git a/pkg/pki/x509/x509_test.go b/pkg/pki/x509/x509_test.go index ae580acd6..3a8b4f748 100644 --- a/pkg/pki/x509/x509_test.go +++ b/pkg/pki/x509/x509_test.go @@ -19,12 +19,18 @@ import ( "bytes" "crypto" "crypto/ecdsa" + "crypto/ed25519" + "crypto/rsa" + "crypto/sha256" "crypto/x509" + "encoding/hex" + "net" "net/url" "reflect" "strings" "testing" + "github.com/sigstore/rekor/pkg/pki/identity" "github.com/sigstore/rekor/pkg/pki/x509/testutils" "github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/sigstore/sigstore/pkg/signature" @@ -42,14 +48,16 @@ dKtM6YKBKSo47oTKQHsCIQDDKZgal50Cd3W+lOWpNO23QGZgBhJrJ70TpcPWGEsS DQIhAIDIMLnq1G1Z4B2IbRRPUP3icMtscbRlmNZ2xovsM8oLAiBluZh+w+gjEQFe hV3wBJajnf2+r2uKTvxO8WhSf/chQQIhAKzYjX2chfvPN6hRqeGeoPpRLXS8cdxC A4hZJRvZgkO3 ------END PRIVATE KEY-----` +-----END PRIVATE KEY----- +` // Extracted from above with: // openssl rsa -in myprivate.pem -pubout const pkcs1v15Pub = `-----BEGIN PUBLIC KEY----- MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKCxC+eynecPG+SwpUjPuZiW1WI+BqBV z/xsp35Opg4+2gDWFgJFO+MZI89AV9jatCE/Q8sViPGl2fAekWLW7D8CAwEAAQ== ------END PUBLIC KEY-----` +-----END PUBLIC KEY----- +` // Generated with: // openssl ecparam -genkey -name prime256v1 > ec_private.pem @@ -58,7 +66,8 @@ const priv = `-----BEGIN PRIVATE KEY----- MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgmrLtCpBdXgXLUr7o nSUPfo3oXMjmvuwTOjpTulIBKlKhRANCAATH6KSpTFe6uXFmW1qNEFXaO7fWPfZt pPZrHZ1cFykidZoURKoYXfkohJ+U/USYy8Sd8b4DMd5xDRZCnlDM0h37 ------END PRIVATE KEY-----` +-----END PRIVATE KEY----- +` // Extracted from above with: // openssl ec -in ec_private.pem -pubout @@ -72,13 +81,15 @@ baT2ax2dXBcpInWaFESqGF35KISflP1EmMvEnfG+AzHecQ0WQp5QzNId+w== // openssl genpkey -algorithm ED25519 -out edprivate.pem const ed25519Priv = `-----BEGIN PRIVATE KEY----- MC4CAQAwBQYDK2VwBCIEIKjlXfR/VFvO9qM9+CG2qbuSM54k8ciKWHhgNwKTgqpG ------END PRIVATE KEY-----` +-----END PRIVATE KEY----- +` // Extracted from above with: // openssl pkey -in edprivate.pem -pubout const ed25519Pub = `-----BEGIN PUBLIC KEY----- MCowBQYDK2VwAyEAizWek2gKgMM+bad4rVJ5nc9NsbNOba0A0BNfzOgklRs= ------END PUBLIC KEY-----` +-----END PUBLIC KEY----- +` const pubWithTrailingNewLine = `-----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEx+ikqUxXurlxZltajRBV2ju31j32 @@ -157,6 +168,43 @@ func TestSignature_Verify(t *testing.T) { if err := canonicalSig.Verify(bytes.NewReader(data), pub); err != nil { t.Errorf("Signature.Verify() error = %v", err) } + + pubKey, _ := cryptoutils.UnmarshalPEMToPublicKey([]byte(tt.pub)) + derKey, _ := cryptoutils.MarshalPublicKeyToDER(pubKey) + digest := sha256.Sum256(derKey) + expectedID := identity.Identity{Crypto: pubKey, Raw: derKey, Fingerprint: hex.EncodeToString(digest[:])} + ids, err := pub.Identities() + if err != nil { + t.Fatal(err) + } + if len(ids) != 1 { + t.Errorf("%v: too many identities, expected 1, got %v", tt.name, len(ids)) + } + switch v := ids[0].Crypto.(type) { + case *rsa.PublicKey: + if tt.name != "rsa" { + t.Fatalf("unexpected key, expected RSA, got %v", reflect.TypeOf(v)) + } + case *ecdsa.PublicKey: + if tt.name != "ec" { + t.Fatalf("unexpected key, expected RSA, got %v", reflect.TypeOf(v)) + } + case ed25519.PublicKey: + if tt.name != "ed25519" { + t.Fatalf("unexpected key, expected RSA, got %v", reflect.TypeOf(v)) + } + default: + t.Fatalf("unexpected key type, got %v", reflect.TypeOf(v)) + } + if err := cryptoutils.EqualKeys(expectedID.Crypto, ids[0].Crypto); err != nil { + t.Errorf("%v: public keys did not match: %v", tt.name, err) + } + if !reflect.DeepEqual(expectedID.Raw, ids[0].Raw) { + t.Errorf("%v: raw identities did not match, expected %v, got %v", tt.name, expectedID.Raw, ids[0].Raw) + } + if expectedID.Fingerprint != ids[0].Fingerprint { + t.Errorf("%v: fingerprints did not match, expected %v, got %v", tt.name, expectedID.Fingerprint, ids[0].Fingerprint) + } }) } } @@ -209,8 +257,9 @@ func TestSignature_VerifyFail(t *testing.T) { func TestPublicKeyWithCertChain(t *testing.T) { rootCert, rootKey, _ := testutils.GenerateRootCa() subCert, subKey, _ := testutils.GenerateSubordinateCa(rootCert, rootKey) - url, _ := url.Parse("https://github.com/slsa-framework/slsa-github-generator/.github/workflows/builder_go_slsa3.yml@refs/tags/v1.1.1") - leafCert, leafKey, _ := testutils.GenerateLeafCert("subject@example.com", "oidc-issuer", url, subCert, subKey) + subjectURL, _ := url.Parse("https://github.com/slsa-framework/slsa-github-generator/.github/workflows/builder_go_slsa3.yml@refs/tags/v1.1.1") + leafCert, leafKey, _ := testutils.GenerateLeafCertWithSubjectAlternateNames( + []string{"example.com"}, []string{"subject@example.com"}, []net.IP{{1, 1, 1, 1}}, []*url.URL{subjectURL}, "oidc-issuer", subCert, subKey) pemCertChain, err := cryptoutils.MarshalCertificatesToPEM([]*x509.Certificate{leafCert, subCert, rootCert}) if err != nil { @@ -233,12 +282,34 @@ func TestPublicKeyWithCertChain(t *testing.T) { t.Fatalf("expected matching subjects, expected %v, got %v", leafCert.EmailAddresses, pub.EmailAddresses()) } - expectedSubjects := leafCert.EmailAddresses + var expectedSubjects []string + expectedSubjects = append(expectedSubjects, leafCert.DNSNames...) + expectedSubjects = append(expectedSubjects, leafCert.EmailAddresses...) + expectedSubjects = append(expectedSubjects, leafCert.IPAddresses[0].String()) expectedSubjects = append(expectedSubjects, leafCert.URIs[0].String()) if !reflect.DeepEqual(pub.Subjects(), expectedSubjects) { t.Fatalf("expected matching subjects, expected %v, got %v", expectedSubjects, pub.Subjects()) } + digest := sha256.Sum256(leafCert.Raw) + expectedID := identity.Identity{Crypto: leafCert, Raw: leafCert.Raw, Fingerprint: hex.EncodeToString((digest[:]))} + ids, err := pub.Identities() + if err != nil { + t.Fatal(err) + } + if len(ids) != 1 { + t.Errorf("too many identities, expected 1, got %v", len(ids)) + } + if !ids[0].Crypto.(*x509.Certificate).Equal(expectedID.Crypto.(*x509.Certificate)) { + t.Errorf("certificates did not match") + } + if !reflect.DeepEqual(expectedID.Raw, ids[0].Raw) { + t.Errorf("raw identities did not match, expected %v, got %v", expectedID.Raw, ids[0].Raw) + } + if expectedID.Fingerprint != ids[0].Fingerprint { + t.Errorf("fingerprints did not match, expected %v, got %v", expectedID.Fingerprint, ids[0].Fingerprint) + } + canonicalValue, err := pub.CanonicalValue() if err != nil { t.Fatalf("unexpected error fetching canonical value: %v", err) diff --git a/pkg/pubsub/doc.go b/pkg/pubsub/doc.go new file mode 100644 index 000000000..7263e044e --- /dev/null +++ b/pkg/pubsub/doc.go @@ -0,0 +1,17 @@ +// 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. + +// Package pubsub provides an interface and implementations for publishing +// notifications for Rekor updates to a Pub/Sub system. +package pubsub diff --git a/pkg/pubsub/gcp/publisher.go b/pkg/pubsub/gcp/publisher.go new file mode 100644 index 000000000..873a9f9a9 --- /dev/null +++ b/pkg/pubsub/gcp/publisher.go @@ -0,0 +1,159 @@ +// 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. + +// Package gcp implements the pubsub.Publisher with Google Cloud Pub/Sub. +package gcp + +import ( + "context" + "encoding/base64" + "fmt" + "os" + "regexp" + "sync" + "time" + + "github.com/sigstore/rekor/pkg/events" + sigpubsub "github.com/sigstore/rekor/pkg/pubsub" + + "cloud.google.com/go/pubsub" + "google.golang.org/api/option" +) + +func init() { + sigpubsub.AddProvider(URIIdentifier, func(ctx context.Context, topicResourceID string) (sigpubsub.Publisher, error) { + return New(ctx, topicResourceID) + }) +} + +const URIIdentifier = "gcppubsub://" + +var ( + // Copied from https://github.com/google/go-cloud/blob/master/pubsub/gcppubsub/gcppubsub.go + re = regexp.MustCompile(`^gcppubsub://projects/([^/]+)/topics/([^/]+)$`) + // Minimal set of permissions needed to check if the server can publish to the configured topic. + // https://cloud.google.com/pubsub/docs/access-control#required_permissions + requiredIAMPermissions = []string{ + "pubsub.topics.get", + "pubsub.topics.publish", + } +) + +type Publisher struct { + client *pubsub.Client + topic string + wg *sync.WaitGroup +} + +func New(ctx context.Context, topicResourceID string, opts ...option.ClientOption) (*Publisher, error) { + projectID, topic, err := parseRef(topicResourceID) + if err != nil { + return nil, fmt.Errorf("parse ref: %w", err) + } + client, err := pubsub.NewClient(ctx, projectID, opts...) + if err != nil { + return nil, fmt.Errorf("create pubsub client for project %q: %w", projectID, err) + } + + // The PubSub emulator does not support IAM methods, and will block the + // server start up if they are called. If the environment variable is set, + // skip this check. + if os.Getenv("PUBSUB_EMULATOR_HOST") == "" { + if _, err := client.Topic(topic).IAM().TestPermissions(ctx, requiredIAMPermissions); err != nil { + return nil, fmt.Errorf("insufficient permissions for topic %q: %w", topic, err) + } + } + + return &Publisher{ + client: client, + topic: topic, + wg: new(sync.WaitGroup), + }, nil +} + +func (p *Publisher) Publish(ctx context.Context, event *events.Event, encoding events.EventContentType) error { + p.wg.Add(1) + defer p.wg.Done() + + var data []byte + var err error + switch encoding { + case events.ContentTypeProtobuf: + data, err = event.MarshalProto() + case events.ContentTypeJSON: + data, err = event.MarshalJSON() + default: + err = fmt.Errorf("unsupported encoding: %s", encoding) + } + if err != nil { + return fmt.Errorf("marshal event: %w", err) + } + + msg := &pubsub.Message{ + Data: data, + Attributes: gcpAttrs(event, encoding), + } + + // The Publish call does not block. + res := p.client.Topic(p.topic).Publish(ctx, msg) + + // TODO: Consider making the timeout configurable. + cctx, cancel := context.WithTimeout(ctx, pubsub.DefaultPublishSettings.Timeout) + defer cancel() + + // This Get call blocks until a response occurs, or the deadline is reached. + if _, err := res.Get(cctx); err != nil { + return fmt.Errorf("publish event %s to topic %q: %w", event.ID(), p.topic, err) + } + return nil +} + +func (p *Publisher) Close() error { + p.wg.Wait() + return p.client.Close() +} + +func parseRef(ref string) (projectID, topic string, err error) { + v := re.FindStringSubmatch(ref) + if len(v) != 3 { + err = fmt.Errorf("invalid gcppubsub format %q", ref) + return + } + projectID, topic = v[1], v[2] + return +} + +// GCP Pub/Sub attributes can be used to filter events server-side, reducing +// the processing for the client and reducing GCP costs for egress fees. +func gcpAttrs(event *events.Event, dataType events.EventContentType) map[string]string { + attrs := map[string]string{ + "source": event.Type().Source(), + "type": event.Type().Name(), + "datacontenttype": string(dataType), + } + for name, value := range event.Attributes() { + switch v := value.(type) { + case string: + attrs[name] = v + case time.Time: + attrs[name] = v.Format(time.RFC3339) + case []byte: + attrs[name] = base64.StdEncoding.EncodeToString(v) + default: + attrs[name] = fmt.Sprint(v) + } + } + + return attrs +} diff --git a/pkg/pubsub/gcp/publisher_test.go b/pkg/pubsub/gcp/publisher_test.go new file mode 100644 index 000000000..9735f3001 --- /dev/null +++ b/pkg/pubsub/gcp/publisher_test.go @@ -0,0 +1,141 @@ +// 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. + +package gcp + +import ( + "testing" + "time" + + "github.com/google/go-cmp/cmp" + + "github.com/sigstore/rekor/pkg/events" + "google.golang.org/protobuf/types/known/emptypb" +) + +func TestParseRef(t *testing.T) { + t.Parallel() + testCases := []struct { + desc string + ref string + + wantProject string + wantTopic string + wantErr bool + }{ + + { + desc: "Valid example", + ref: "gcppubsub://projects/project-foo/topics/topic-bar", + wantProject: "project-foo", + wantTopic: "topic-bar", + }, + { + desc: "Empty ref", + wantErr: true, + }, + { + desc: "Missing topic", + ref: "gcppubsub://projects/project-foo/topics/", + wantErr: true, + }, + { + desc: "Wrong scheme", + ref: "foo://projects/project-foo/topics/topic-bar", + wantErr: true, + }, + } + + for _, tc := range testCases { + tc := tc + t.Run(tc.desc, func(t *testing.T) { + t.Parallel() + project, topic, err := parseRef(tc.ref) + gotErr := err != nil + if gotErr != tc.wantErr { + t.Errorf("parseRef(%s) error = %v, wantErr %v", tc.ref, gotErr, tc.wantErr) + return + } + if project != tc.wantProject { + t.Errorf("parseRef(%s) project = %s, want %s", tc.ref, project, tc.wantProject) + } + if topic != tc.wantTopic { + t.Errorf("parseRef(%s) topic = %s, want %s", tc.ref, topic, tc.wantTopic) + } + }) + } +} + +func TestGCPAttrs(t *testing.T) { + t.Parallel() + + empty := &emptypb.Empty{} + ty := events.RegisterType("gcpAttrsTestEvent", "/source", empty.ProtoReflect().Descriptor()) + + coreEvent, err := ty.New("A123-456", &emptypb.Empty{}, nil) + if err != nil { + t.Fatal(err) + } + attrs := map[string]any{ + "attr_string": "string", + "attr_bool": true, + "attr_int": 123, + "attr_bytes": []byte("hello"), + "attr_timestamp": time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC).Add(time.Second), + } + attrsEvent, err := ty.New("A456-789", &emptypb.Empty{}, attrs) + if err != nil { + t.Fatal(err) + } + + testCases := []struct { + desc string + event *events.Event + want map[string]string + }{ + { + desc: "Core attrs only", + event: coreEvent, + want: map[string]string{ + "datacontenttype": "application/fake-test-mime", + "source": "/source", + "type": "gcpAttrsTestEvent", + }, + }, + { + desc: "With optional attrs", + event: attrsEvent, + want: map[string]string{ + "datacontenttype": "application/fake-test-mime", + "source": "/source", + "type": "gcpAttrsTestEvent", + "attr_string": "string", + "attr_int": "123", + "attr_bool": "true", + "attr_bytes": "aGVsbG8=", + "attr_timestamp": time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC).Add(time.Second).Format(time.RFC3339), + }, + }, + } + for _, tc := range testCases { + tc := tc + t.Run(tc.desc, func(t *testing.T) { + t.Parallel() + got := gcpAttrs(tc.event, "application/fake-test-mime") + if diff := cmp.Diff(got, tc.want); diff != "" { + t.Errorf("unexpected diff:\n%s", diff) + } + }) + } +} diff --git a/pkg/pubsub/publisher.go b/pkg/pubsub/publisher.go new file mode 100644 index 000000000..475c11b1b --- /dev/null +++ b/pkg/pubsub/publisher.go @@ -0,0 +1,74 @@ +// 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. + +package pubsub + +import ( + "context" + "fmt" + "strings" + + "github.com/sigstore/rekor/pkg/events" + + "golang.org/x/exp/maps" + "golang.org/x/exp/slices" +) + +// Publisher provides methods for publishing events to a Pub/Sub topic. +type Publisher interface { + // Publish publishes a CloudEvent to the configured Pub/Sub topic serialized + // using the specified encoding type. + Publish(ctx context.Context, event *events.Event, encoding events.EventContentType) error + // Close safely closes any active connections. + Close() error +} + +// ProviderNotFoundError indicates that no matching PubSub provider was found. +type ProviderNotFoundError struct { + ref string +} + +func (e *ProviderNotFoundError) Error() string { + return fmt.Sprintf("no pubsub provider found for key reference: %s", e.ref) +} + +// ProviderInit is a function that initializes provider-specific Publisher. +type ProviderInit func(ctx context.Context, topicResourceID string) (Publisher, error) + +// AddProvider adds the provider implementation into the local cache +func AddProvider(uri string, init ProviderInit) { + providersMap[uri] = init +} + +var providersMap = map[string]ProviderInit{} + +// Get returns a Publisher for the given resource string and hash function. +// If no matching provider is found, Get returns a ProviderNotFoundError. It +// also returns an error if initializing the Publisher fails. If no resource +// is supplied, it returns a nil Publisher and no error. +func Get(ctx context.Context, topicResourceID string) (Publisher, error) { + for ref, pi := range providersMap { + if strings.HasPrefix(topicResourceID, ref) { + return pi(ctx, topicResourceID) + } + } + return nil, &ProviderNotFoundError{ref: topicResourceID} +} + +// SupportedProviders returns list of initialized providers +func SupportedProviders() []string { + names := maps.Keys(providersMap) + slices.Sort(names) + return names +} diff --git a/pkg/sharding/ranges.go b/pkg/sharding/ranges.go index c5f62dc64..1bf8291c7 100644 --- a/pkg/sharding/ranges.go +++ b/pkg/sharding/ranges.go @@ -25,10 +25,10 @@ import ( "strconv" "strings" - "github.com/ghodss/yaml" "github.com/google/trillian" "github.com/google/trillian/types" "github.com/sigstore/rekor/pkg/log" + "sigs.k8s.io/yaml" ) type LogRanges struct { diff --git a/pkg/sharding/ranges_test.go b/pkg/sharding/ranges_test.go index a94a8d32c..ab020c800 100644 --- a/pkg/sharding/ranges_test.go +++ b/pkg/sharding/ranges_test.go @@ -17,13 +17,19 @@ package sharding import ( "context" + "encoding/json" + "errors" "os" "path/filepath" "reflect" "testing" + "github.com/golang/mock/gomock" + "github.com/google/trillian/testonly" + "github.com/google/trillian" "google.golang.org/grpc" + "gopkg.in/yaml.v2" ) func TestNewLogRanges(t *testing.T) { @@ -34,7 +40,7 @@ func TestNewLogRanges(t *testing.T) { - treeID: 0002 treeLength: 4` file := filepath.Join(t.TempDir(), "sharding-config") - if err := os.WriteFile(file, []byte(contents), 0644); err != nil { + if err := os.WriteFile(file, []byte(contents), 0o644); err != nil { t.Fatal(err) } treeID := uint(45) @@ -48,7 +54,8 @@ func TestNewLogRanges(t *testing.T) { }, { TreeID: 2, TreeLength: 4, - }}, + }, + }, active: int64(45), } ctx := context.Background() @@ -65,69 +72,13 @@ func TestNewLogRanges(t *testing.T) { } } -func TestLogRangesFromPath(t *testing.T) { - contents := ` -- treeID: 0001 - treeLength: 3 - encodedPublicKey: c2hhcmRpbmcK -- treeID: 0002 - treeLength: 4` - file := filepath.Join(t.TempDir(), "sharding-config") - if err := os.WriteFile(file, []byte(contents), 0644); err != nil { - t.Fatal(err) - } - expected := Ranges{ - { - TreeID: 1, - TreeLength: 3, - EncodedPublicKey: "c2hhcmRpbmcK", - }, { - TreeID: 2, - TreeLength: 4, - }, - } - - got, err := logRangesFromPath(file) - if err != nil { - t.Fatal(err) - } - if !reflect.DeepEqual(expected, got) { - t.Fatalf("expected %v got %v", expected, got) - } -} - -func TestLogRangesFromPathJSON(t *testing.T) { - contents := `[{"treeID": 0001, "treeLength": 3, "encodedPublicKey":"c2hhcmRpbmcK"}, {"treeID": 0002, "treeLength": 4}]` - file := filepath.Join(t.TempDir(), "sharding-config") - if err := os.WriteFile(file, []byte(contents), 0644); err != nil { - t.Fatal(err) - } - expected := Ranges{ - { - TreeID: 1, - TreeLength: 3, - EncodedPublicKey: "c2hhcmRpbmcK", - }, { - TreeID: 2, - TreeLength: 4, - }, - } - - got, err := logRangesFromPath(file) - if err != nil { - t.Fatal(err) - } - if !reflect.DeepEqual(expected, got) { - t.Fatalf("expected %v got %v", expected, got) - } -} - func TestLogRanges_ResolveVirtualIndex(t *testing.T) { lrs := LogRanges{ inactive: []LogRange{ {TreeID: 1, TreeLength: 17}, {TreeID: 2, TreeLength: 1}, - {TreeID: 3, TreeLength: 100}}, + {TreeID: 3, TreeLength: 100}, + }, active: 4, } @@ -388,3 +339,233 @@ func TestLogRanges_AllShards(t *testing.T) { }) } } + +func TestLogRangesFromPath(t *testing.T) { + type args struct { + path string + } + tests := []struct { + name string + args args + want Ranges + content string + wantJSON bool + wantYaml bool + wantInvalidJSON bool + wantErr bool + }{ + { + name: "empty", + args: args{ + path: "", + }, + want: Ranges{}, + wantErr: true, + }, + { + name: "empty file", + args: args{ + path: "one", + }, + want: Ranges{}, + wantErr: false, + }, + { + name: "valid json", + args: args{ + path: "one", + }, + want: Ranges{ + { + TreeID: 1, + TreeLength: 2, + }, + }, + wantJSON: true, + wantErr: false, + }, + { + name: "valid yaml", + args: args{ + path: "one", + }, + want: Ranges{ + { + TreeID: 1, + TreeLength: 2, + }, + }, + wantYaml: true, + wantErr: false, + }, + { + name: "invalid json", + args: args{ + path: "one", + }, + want: Ranges{}, + wantInvalidJSON: true, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if tt.args.path != "" { + f, err := os.CreateTemp("", tt.args.path) + if err != nil { + t.Fatalf("Failed to create temp file: %v", err) + } + switch { + case tt.wantJSON: + if err := json.NewEncoder(f).Encode(tt.want); err != nil { + t.Fatalf("Failed to encode json: %v", err) + } + case tt.wantYaml: + if err := yaml.NewEncoder(f).Encode(tt.want); err != nil { + t.Fatalf("Failed to encode yaml: %v", err) + } + case tt.wantInvalidJSON: + if _, err := f.WriteString("invalid json"); err != nil { + t.Fatalf("Failed to write invalid json: %v", err) + } + } + if _, err := f.Write([]byte(tt.content)); err != nil { + t.Fatalf("Failed to write to temp file: %v", err) + } + defer f.Close() + defer os.Remove(f.Name()) + tt.args.path = f.Name() + } + got, err := logRangesFromPath(tt.args.path) + if (err != nil) != tt.wantErr { + t.Errorf("logRangesFromPath() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("logRangesFromPath() got = %v, want %v", got, tt.want) + } + }) + } +} + +func TestUpdateRange(t *testing.T) { + type args struct { + ctx context.Context + r LogRange + } + tests := []struct { + name string + args args + want LogRange + wantErr bool + rootResponse *trillian.GetLatestSignedLogRootResponse + signedLogError error + }{ + { + name: "empty", + args: args{ + ctx: context.Background(), + r: LogRange{}, + }, + want: LogRange{}, + wantErr: true, + rootResponse: &trillian.GetLatestSignedLogRootResponse{ + SignedLogRoot: &trillian.SignedLogRoot{}, + }, + signedLogError: nil, + }, + { + name: "error in GetLatestSignedLogRoot", + args: args{ + ctx: context.Background(), + r: LogRange{}, + }, + want: LogRange{}, + wantErr: true, + rootResponse: &trillian.GetLatestSignedLogRootResponse{ + SignedLogRoot: &trillian.SignedLogRoot{}, + }, + signedLogError: errors.New("error"), + }, + } + + mockCtl := gomock.NewController(t) + defer mockCtl.Finish() + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s, fakeServer, err := testonly.NewMockServer(mockCtl) + if err != nil { + t.Fatalf("Failed to create mock server: %v", err) + } + defer fakeServer() + + s.Log.EXPECT().GetLatestSignedLogRoot( + gomock.Any(), gomock.Any()).Return(tt.rootResponse, tt.signedLogError).AnyTimes() + got, err := updateRange(tt.args.ctx, s.LogClient, tt.args.r) + + if (err != nil) != tt.wantErr { + t.Errorf("updateRange() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("updateRange() got = %v, want %v", got, tt.want) + } + }) + } +} + +func TestNewLogRangesWithMock(t *testing.T) { + type args struct { + ctx context.Context + path string + treeID uint + } + tests := []struct { + name string + args args + want LogRanges + wantErr bool + }{ + { + name: "empty path", + args: args{ + ctx: context.Background(), + path: "", + treeID: 1, + }, + want: LogRanges{}, + wantErr: false, + }, + { + name: "treeID 0", + args: args{ + ctx: context.Background(), + path: "x", + treeID: 0, + }, + want: LogRanges{}, + wantErr: true, + }, + } + + mockCtl := gomock.NewController(t) + defer mockCtl.Finish() + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + + s, fakeServer, err := testonly.NewMockServer(mockCtl) + if err != nil { + t.Fatalf("Failed to create mock server: %v", err) + } + defer fakeServer() + got, err := NewLogRanges(tt.args.ctx, s.LogClient, tt.args.path, tt.args.treeID) + if (err != nil) != tt.wantErr { + t.Errorf("NewLogRanges() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("NewLogRanges() got = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/pkg/signer/signer.go b/pkg/signer/signer.go index 481c184da..6701e8ce3 100644 --- a/pkg/signer/signer.go +++ b/pkg/signer/signer.go @@ -1,5 +1,5 @@ /* -Copyright The Rekor Authors. +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. @@ -18,16 +18,27 @@ package signer import ( "context" + "crypto" "strings" "github.com/sigstore/sigstore/pkg/signature" - "github.com/sigstore/sigstore/pkg/signature/kms/gcp" + "github.com/sigstore/sigstore/pkg/signature/kms" + "golang.org/x/exp/slices" + + // these are imported to load the providers via init() calls + _ "github.com/sigstore/sigstore/pkg/signature/kms/aws" + _ "github.com/sigstore/sigstore/pkg/signature/kms/azure" + _ "github.com/sigstore/sigstore/pkg/signature/kms/gcp" + _ "github.com/sigstore/sigstore/pkg/signature/kms/hashivault" ) func New(ctx context.Context, signer string, pass string) (signature.Signer, error) { switch { - case strings.HasPrefix(signer, gcp.ReferenceScheme): - return gcp.LoadSignerVerifier(ctx, signer) + case slices.ContainsFunc(kms.SupportedProviders(), + func(s string) bool { + return strings.HasPrefix(signer, s) + }): + return kms.Get(ctx, signer, crypto.SHA256) case signer == MemoryScheme: return NewMemory() default: diff --git a/pkg/tle/tle.go b/pkg/tle/tle.go new file mode 100644 index 000000000..2e51f5bcc --- /dev/null +++ b/pkg/tle/tle.go @@ -0,0 +1,106 @@ +// 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 tle + +import ( + "bytes" + "encoding/base64" + "encoding/hex" + "fmt" + + "github.com/go-openapi/runtime" + rekor_pb_common "github.com/sigstore/protobuf-specs/gen/pb-go/common/v1" + rekor_pb "github.com/sigstore/protobuf-specs/gen/pb-go/rekor/v1" + "github.com/sigstore/rekor/pkg/generated/models" + "github.com/sigstore/rekor/pkg/types" + "google.golang.org/protobuf/encoding/protojson" +) + +// GenerateTransparencyLogEntry returns a sigstore/protobuf-specs compliant message containing a +// TransparencyLogEntry as defined at https://github.com/sigstore/protobuf-specs/blob/main/protos/sigstore_rekor.proto +func GenerateTransparencyLogEntry(anon models.LogEntryAnon) (*rekor_pb.TransparencyLogEntry, error) { + logIDHash, err := hex.DecodeString(*anon.LogID) + if err != nil { + return nil, fmt.Errorf("decoding logID string: %w", err) + } + + rootHash, err := hex.DecodeString(*anon.Verification.InclusionProof.RootHash) + if err != nil { + return nil, fmt.Errorf("decoding inclusion proof root hash: %w", err) + } + + inclusionProofHashes := make([][]byte, len(anon.Verification.InclusionProof.Hashes)) + for i, hash := range anon.Verification.InclusionProof.Hashes { + hashBytes, err := hex.DecodeString(hash) + if err != nil { + return nil, fmt.Errorf("decoding inclusion proof hash: %w", err) + } + inclusionProofHashes[i] = hashBytes + } + + // Different call paths may supply string or []byte. If string, it is base64 encoded. + var body []byte + switch v := anon.Body.(type) { + case string: + b, err := base64.StdEncoding.DecodeString(v) + if err != nil { + return nil, fmt.Errorf("base64 decoding body: %w", err) + } + body = b + case []byte: + body = v + default: + return nil, fmt.Errorf("body is not string or []byte: (%T)%v", v, v) + } + + pe, err := models.UnmarshalProposedEntry(bytes.NewReader(body), runtime.JSONConsumer()) + if err != nil { + return nil, err + } + eimpl, err := types.UnmarshalEntry(pe) + if err != nil { + return nil, err + } + + return &rekor_pb.TransparencyLogEntry{ + LogIndex: *anon.LogIndex, // the global log index + LogId: &rekor_pb_common.LogId{ + KeyId: logIDHash, + }, + KindVersion: &rekor_pb.KindVersion{ + Kind: pe.Kind(), + Version: eimpl.APIVersion(), + }, + IntegratedTime: *anon.IntegratedTime, + InclusionPromise: &rekor_pb.InclusionPromise{ + SignedEntryTimestamp: anon.Verification.SignedEntryTimestamp, + }, + InclusionProof: &rekor_pb.InclusionProof{ + LogIndex: *anon.Verification.InclusionProof.LogIndex, // relative to the specific tree the entry is found in + RootHash: rootHash, + TreeSize: *anon.Verification.InclusionProof.TreeSize, + Hashes: inclusionProofHashes, + Checkpoint: &rekor_pb.Checkpoint{ + Envelope: *anon.Verification.InclusionProof.Checkpoint, + }, + }, + CanonicalizedBody: body, // we don't call eimpl.Canonicalize in the case that the logic is different in this caller vs when it was persisted in the log + }, nil +} + +// MarshalTLEToJSON marshals a TransparencyLogEntry message to JSON according to the protobuf JSON encoding rules +func MarshalTLEToJSON(tle *rekor_pb.TransparencyLogEntry) ([]byte, error) { + return protojson.Marshal(tle) +} diff --git a/pkg/tle/tle_test.go b/pkg/tle/tle_test.go new file mode 100644 index 000000000..64a9b5787 --- /dev/null +++ b/pkg/tle/tle_test.go @@ -0,0 +1,225 @@ +// +// 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 tle + +import ( + "encoding/base64" + "encoding/hex" + "reflect" + "testing" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + rekor_pb_common "github.com/sigstore/protobuf-specs/gen/pb-go/common/v1" + rekor_pb "github.com/sigstore/protobuf-specs/gen/pb-go/rekor/v1" + "github.com/sigstore/rekor/pkg/generated/models" + _ "github.com/sigstore/rekor/pkg/types/hashedrekord/v0.0.1" +) + +func TestGenerateTransparencyLogEntry(t *testing.T) { + type TestCase struct { + description string + expectSuccess bool + proposedEntry models.LogEntryAnon + want *rekor_pb.TransparencyLogEntry + } + + b64Body := "eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiI2MmQwOGYyOGM2OWNhZGE3YjQyYTQ1Nzk0YjQ3ZWU2YzgxYTdkZmE3MTY4NDZiMzljODhmMGFkMTljMjA2OTk3In19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FVUNJQm14U0N1TW1HSzhNQWRMd1FWZ21TZjVXKzlkdU5iQXN1cUNQNlNucUxCUkFpRUFvNGtGRVdDTG9HcTVUaysrUEhtTEgrb3N1emVTRjN4OTdBbmVicTRlbVRvPSIsInB1YmxpY0tleSI6eyJjb250ZW50IjoiTFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVUk1ha05EUVhKVFowRjNTVUpCWjBsVVRWQkRlVXdyYmxOb2MycHdaa2hZYUZkYVRVWkNUVUZIUlVSQlMwSm5aM0ZvYTJwUFVGRlJSRUY2UVhFS1RWSlZkMFYzV1VSV1VWRkxSWGQ0ZW1GWFpIcGtSemw1V2xNMWExcFlXWGhGVkVGUVFtZE9Wa0pCVFZSRFNFNXdXak5PTUdJelNteE5RalJZUkZSSmVRcE5SRWwzVFdwRmQwNUVXWGhOVm05WVJGUkplVTFFU1hkTmFrVjNUbFJaZUUxR2IzZEZla1ZTVFVFNFIwRXhWVVZEYUUxSll6SnNibU16VW5aamJWVjNDbGRVUVZSQ1oyTnhhR3RxVDFCUlNVSkNaMmR4YUd0cVQxQlJUVUpDZDA1RFFVRlVVMVJ2VEhWS2N5OTFSV05IU2tRME5VWmFiVE5wWmxKTU4yOXVRVWNLWlZaNWJuWkhVbmN6WnpKMU0wbFhTREZuU2tSamNERjRSWFI2UVZCUWJYQmhlVGRtTmxCNE1XeFpNa0ZyWnpsMGEyb3dRa1J2UTNkdk5FbENlbXBEUXdwQlkyOTNSR2RaUkZaU01GQkJVVWd2UWtGUlJFRm5aVUZOUWsxSFFURlZaRXBSVVUxTlFXOUhRME56UjBGUlZVWkNkMDFFVFVGM1IwRXhWV1JGZDBWQ0NpOTNVVU5OUVVGM1NGRlpSRlpTTUU5Q1FsbEZSazlSYTNZNVoyMVpXVFpWU0doQ1pWSnJMMWx4VlVsaU1WRldiMDFDT0VkQk1WVmtTWGRSV1UxQ1lVRUtSa1pxUVVoc0sxSlNZVlp0Y1ZoeVRXdExSMVJKZEVGeGVHTllOazFIVFVkQk1WVmtSVkZTWTAxR2NVZFhSMmd3WkVoQ2VrOXBPSFphTW13d1lVaFdhUXBNYlU1MllsTTVjbGx1VGpCTU0xSnNZMjVLYUZwdE9YbGlVekZ5WkZkS2JHTXpVbWhaTW5OMlRHMWtjR1JIYURGWmFUa3pZak5LY2xwdGVIWmtNMDEyQ21KWFJuQmlhVFUxWWxkNFFXTnRWbTFqZVRsdldsZEdhMk41T1hSWldFNHdXbGhKZDBWbldVdExkMWxDUWtGSFJIWjZRVUpCWjFGRlkwaFdlbUZFUVcwS1FtZHZja0puUlVWQldVOHZUVUZGUmtKQ2FISlpiazR3VEROU2JHTnVTbWhhYlRsNVlsTXhjbVJYU214ak0xSm9XVEp6ZDA1bldVdExkMWxDUWtGSFJBcDJla0ZDUVhkUmIxcHFSVEZPVjFGNVdXMUplRTU2V210TlZFVTFXV3BHYlU5VVNUSk9WRlV6V1hwTk5WbDZTbWxQVkdzMVdtcFNhRnBxWjNkWmVrRTFDa0puYjNKQ1owVkZRVmxQTDAxQlJVSkNRM1J2WkVoU2QyTjZiM1pNTTFKMllUSldkVXh0Um1wa1IyeDJZbTVOZFZveWJEQmhTRlpwWkZoT2JHTnRUbllLWW01U2JHSnVVWFZaTWpsMFRVSTRSME5wYzBkQlVWRkNaemM0ZDBGUldVVkZXRXBzV201TmRtRkhWbWhhU0UxMllsZEdlbVJIVm5sTlEwRkhRMmx6UndwQlVWRkNaemM0ZDBGUlVVVkZhMG94WVZkNGEwbEdVbXhqTTFGblZVaFdhV0pIYkhwaFJFRkxRbWRuY1docmFrOVFVVkZFUVhkT2IwRkVRbXhCYWtWQkNtdDJORTFLYUdGRGFFMUJaMHBWVTNWWll6bFBWRWt3WTB0bU9XTnlObU14Y1RreVYyOXFMM1ZsV0RKRFR6Z3JMMDQyU25SM1FVNTRVSElyTjNWNlpGQUtRV3BDYVhwR2NHZEVMelJzWW5aa1NuRnplWE5HYlVSeU1TdFNNSGhKWjI1S1N5c3JaWGROYmtKaVMxQkVMemd3VTNJelFYTTVMMWxxV1U5M05EVjRkUXA2ZVdzOUNpMHRMUzB0UlU1RUlFTkZVbFJKUmtsRFFWUkZMUzB0TFMwSyJ9fX19" + bodyBytes, _ := base64.RawStdEncoding.DecodeString(b64Body) + + deadbeefBytes, _ := hex.DecodeString("deadbeef") + abcdefaaBytes, _ := hex.DecodeString("abcdefaa") + + testCases := []TestCase{ + { + description: "valid entry", + expectSuccess: true, + proposedEntry: models.LogEntryAnon{ + Body: "eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiI2MmQwOGYyOGM2OWNhZGE3YjQyYTQ1Nzk0YjQ3ZWU2YzgxYTdkZmE3MTY4NDZiMzljODhmMGFkMTljMjA2OTk3In19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FVUNJQm14U0N1TW1HSzhNQWRMd1FWZ21TZjVXKzlkdU5iQXN1cUNQNlNucUxCUkFpRUFvNGtGRVdDTG9HcTVUaysrUEhtTEgrb3N1emVTRjN4OTdBbmVicTRlbVRvPSIsInB1YmxpY0tleSI6eyJjb250ZW50IjoiTFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVUk1ha05EUVhKVFowRjNTVUpCWjBsVVRWQkRlVXdyYmxOb2MycHdaa2hZYUZkYVRVWkNUVUZIUlVSQlMwSm5aM0ZvYTJwUFVGRlJSRUY2UVhFS1RWSlZkMFYzV1VSV1VWRkxSWGQ0ZW1GWFpIcGtSemw1V2xNMWExcFlXWGhGVkVGUVFtZE9Wa0pCVFZSRFNFNXdXak5PTUdJelNteE5RalJZUkZSSmVRcE5SRWwzVFdwRmQwNUVXWGhOVm05WVJGUkplVTFFU1hkTmFrVjNUbFJaZUUxR2IzZEZla1ZTVFVFNFIwRXhWVVZEYUUxSll6SnNibU16VW5aamJWVjNDbGRVUVZSQ1oyTnhhR3RxVDFCUlNVSkNaMmR4YUd0cVQxQlJUVUpDZDA1RFFVRlVVMVJ2VEhWS2N5OTFSV05IU2tRME5VWmFiVE5wWmxKTU4yOXVRVWNLWlZaNWJuWkhVbmN6WnpKMU0wbFhTREZuU2tSamNERjRSWFI2UVZCUWJYQmhlVGRtTmxCNE1XeFpNa0ZyWnpsMGEyb3dRa1J2UTNkdk5FbENlbXBEUXdwQlkyOTNSR2RaUkZaU01GQkJVVWd2UWtGUlJFRm5aVUZOUWsxSFFURlZaRXBSVVUxTlFXOUhRME56UjBGUlZVWkNkMDFFVFVGM1IwRXhWV1JGZDBWQ0NpOTNVVU5OUVVGM1NGRlpSRlpTTUU5Q1FsbEZSazlSYTNZNVoyMVpXVFpWU0doQ1pWSnJMMWx4VlVsaU1WRldiMDFDT0VkQk1WVmtTWGRSV1UxQ1lVRUtSa1pxUVVoc0sxSlNZVlp0Y1ZoeVRXdExSMVJKZEVGeGVHTllOazFIVFVkQk1WVmtSVkZTWTAxR2NVZFhSMmd3WkVoQ2VrOXBPSFphTW13d1lVaFdhUXBNYlU1MllsTTVjbGx1VGpCTU0xSnNZMjVLYUZwdE9YbGlVekZ5WkZkS2JHTXpVbWhaTW5OMlRHMWtjR1JIYURGWmFUa3pZak5LY2xwdGVIWmtNMDEyQ21KWFJuQmlhVFUxWWxkNFFXTnRWbTFqZVRsdldsZEdhMk41T1hSWldFNHdXbGhKZDBWbldVdExkMWxDUWtGSFJIWjZRVUpCWjFGRlkwaFdlbUZFUVcwS1FtZHZja0puUlVWQldVOHZUVUZGUmtKQ2FISlpiazR3VEROU2JHTnVTbWhhYlRsNVlsTXhjbVJYU214ak0xSm9XVEp6ZDA1bldVdExkMWxDUWtGSFJBcDJla0ZDUVhkUmIxcHFSVEZPVjFGNVdXMUplRTU2V210TlZFVTFXV3BHYlU5VVNUSk9WRlV6V1hwTk5WbDZTbWxQVkdzMVdtcFNhRnBxWjNkWmVrRTFDa0puYjNKQ1owVkZRVmxQTDAxQlJVSkNRM1J2WkVoU2QyTjZiM1pNTTFKMllUSldkVXh0Um1wa1IyeDJZbTVOZFZveWJEQmhTRlpwWkZoT2JHTnRUbllLWW01U2JHSnVVWFZaTWpsMFRVSTRSME5wYzBkQlVWRkNaemM0ZDBGUldVVkZXRXBzV201TmRtRkhWbWhhU0UxMllsZEdlbVJIVm5sTlEwRkhRMmx6UndwQlVWRkNaemM0ZDBGUlVVVkZhMG94WVZkNGEwbEdVbXhqTTFGblZVaFdhV0pIYkhwaFJFRkxRbWRuY1docmFrOVFVVkZFUVhkT2IwRkVRbXhCYWtWQkNtdDJORTFLYUdGRGFFMUJaMHBWVTNWWll6bFBWRWt3WTB0bU9XTnlObU14Y1RreVYyOXFMM1ZsV0RKRFR6Z3JMMDQyU25SM1FVNTRVSElyTjNWNlpGQUtRV3BDYVhwR2NHZEVMelJzWW5aa1NuRnplWE5HYlVSeU1TdFNNSGhKWjI1S1N5c3JaWGROYmtKaVMxQkVMemd3VTNJelFYTTVMMWxxV1U5M05EVjRkUXA2ZVdzOUNpMHRMUzB0UlU1RUlFTkZVbFJKUmtsRFFWUkZMUzB0TFMwSyJ9fX19", + IntegratedTime: swag.Int64(123), + LogID: swag.String("deadbeef"), + LogIndex: swag.Int64(2), + Verification: &models.LogEntryAnonVerification{ + InclusionProof: &models.InclusionProof{ + Checkpoint: swag.String("checkpoint"), + Hashes: []string{"deadbeef", "abcdefaa"}, + LogIndex: swag.Int64(1), + RootHash: swag.String("abcdefaa"), + TreeSize: swag.Int64(2), + }, + SignedEntryTimestamp: strfmt.Base64("set"), + }, + }, + want: &rekor_pb.TransparencyLogEntry{ + LogIndex: 2, + LogId: &rekor_pb_common.LogId{ + KeyId: deadbeefBytes, + }, + KindVersion: &rekor_pb.KindVersion{ + Kind: "hashedrekord", + Version: "0.0.1", + }, + IntegratedTime: 123, + InclusionPromise: &rekor_pb.InclusionPromise{ + SignedEntryTimestamp: []byte("set"), + }, + InclusionProof: &rekor_pb.InclusionProof{ + Checkpoint: &rekor_pb.Checkpoint{ + Envelope: "checkpoint", + }, + Hashes: [][]byte{deadbeefBytes, abcdefaaBytes}, + LogIndex: 1, + RootHash: abcdefaaBytes, + TreeSize: 2, + }, + CanonicalizedBody: bodyBytes, + }, + }, + { + description: "body is not valid base64", + expectSuccess: false, + proposedEntry: models.LogEntryAnon{ + Body: "not_base_64", + IntegratedTime: swag.Int64(123), + LogID: swag.String("deadbeef"), + LogIndex: swag.Int64(1), + Verification: &models.LogEntryAnonVerification{ + InclusionProof: &models.InclusionProof{ + Checkpoint: swag.String("checkpoint"), + Hashes: []string{"deadbeef", "abcdefaa"}, + LogIndex: swag.Int64(1), + RootHash: swag.String("abcdefaa"), + TreeSize: swag.Int64(2), + }, + SignedEntryTimestamp: strfmt.Base64("set"), + }, + }, + }, + { + description: "logID is not valid hex", + expectSuccess: false, + proposedEntry: models.LogEntryAnon{ + Body: "eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiI2MmQwOGYyOGM2OWNhZGE3YjQyYTQ1Nzk0YjQ3ZWU2YzgxYTdkZmE3MTY4NDZiMzljODhmMGFkMTljMjA2OTk3In19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FVUNJQm14U0N1TW1HSzhNQWRMd1FWZ21TZjVXKzlkdU5iQXN1cUNQNlNucUxCUkFpRUFvNGtGRVdDTG9HcTVUaysrUEhtTEgrb3N1emVTRjN4OTdBbmVicTRlbVRvPSIsInB1YmxpY0tleSI6eyJjb250ZW50IjoiTFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVUk1ha05EUVhKVFowRjNTVUpCWjBsVVRWQkRlVXdyYmxOb2MycHdaa2hZYUZkYVRVWkNUVUZIUlVSQlMwSm5aM0ZvYTJwUFVGRlJSRUY2UVhFS1RWSlZkMFYzV1VSV1VWRkxSWGQ0ZW1GWFpIcGtSemw1V2xNMWExcFlXWGhGVkVGUVFtZE9Wa0pCVFZSRFNFNXdXak5PTUdJelNteE5RalJZUkZSSmVRcE5SRWwzVFdwRmQwNUVXWGhOVm05WVJGUkplVTFFU1hkTmFrVjNUbFJaZUUxR2IzZEZla1ZTVFVFNFIwRXhWVVZEYUUxSll6SnNibU16VW5aamJWVjNDbGRVUVZSQ1oyTnhhR3RxVDFCUlNVSkNaMmR4YUd0cVQxQlJUVUpDZDA1RFFVRlVVMVJ2VEhWS2N5OTFSV05IU2tRME5VWmFiVE5wWmxKTU4yOXVRVWNLWlZaNWJuWkhVbmN6WnpKMU0wbFhTREZuU2tSamNERjRSWFI2UVZCUWJYQmhlVGRtTmxCNE1XeFpNa0ZyWnpsMGEyb3dRa1J2UTNkdk5FbENlbXBEUXdwQlkyOTNSR2RaUkZaU01GQkJVVWd2UWtGUlJFRm5aVUZOUWsxSFFURlZaRXBSVVUxTlFXOUhRME56UjBGUlZVWkNkMDFFVFVGM1IwRXhWV1JGZDBWQ0NpOTNVVU5OUVVGM1NGRlpSRlpTTUU5Q1FsbEZSazlSYTNZNVoyMVpXVFpWU0doQ1pWSnJMMWx4VlVsaU1WRldiMDFDT0VkQk1WVmtTWGRSV1UxQ1lVRUtSa1pxUVVoc0sxSlNZVlp0Y1ZoeVRXdExSMVJKZEVGeGVHTllOazFIVFVkQk1WVmtSVkZTWTAxR2NVZFhSMmd3WkVoQ2VrOXBPSFphTW13d1lVaFdhUXBNYlU1MllsTTVjbGx1VGpCTU0xSnNZMjVLYUZwdE9YbGlVekZ5WkZkS2JHTXpVbWhaTW5OMlRHMWtjR1JIYURGWmFUa3pZak5LY2xwdGVIWmtNMDEyQ21KWFJuQmlhVFUxWWxkNFFXTnRWbTFqZVRsdldsZEdhMk41T1hSWldFNHdXbGhKZDBWbldVdExkMWxDUWtGSFJIWjZRVUpCWjFGRlkwaFdlbUZFUVcwS1FtZHZja0puUlVWQldVOHZUVUZGUmtKQ2FISlpiazR3VEROU2JHTnVTbWhhYlRsNVlsTXhjbVJYU214ak0xSm9XVEp6ZDA1bldVdExkMWxDUWtGSFJBcDJla0ZDUVhkUmIxcHFSVEZPVjFGNVdXMUplRTU2V210TlZFVTFXV3BHYlU5VVNUSk9WRlV6V1hwTk5WbDZTbWxQVkdzMVdtcFNhRnBxWjNkWmVrRTFDa0puYjNKQ1owVkZRVmxQTDAxQlJVSkNRM1J2WkVoU2QyTjZiM1pNTTFKMllUSldkVXh0Um1wa1IyeDJZbTVOZFZveWJEQmhTRlpwWkZoT2JHTnRUbllLWW01U2JHSnVVWFZaTWpsMFRVSTRSME5wYzBkQlVWRkNaemM0ZDBGUldVVkZXRXBzV201TmRtRkhWbWhhU0UxMllsZEdlbVJIVm5sTlEwRkhRMmx6UndwQlVWRkNaemM0ZDBGUlVVVkZhMG94WVZkNGEwbEdVbXhqTTFGblZVaFdhV0pIYkhwaFJFRkxRbWRuY1docmFrOVFVVkZFUVhkT2IwRkVRbXhCYWtWQkNtdDJORTFLYUdGRGFFMUJaMHBWVTNWWll6bFBWRWt3WTB0bU9XTnlObU14Y1RreVYyOXFMM1ZsV0RKRFR6Z3JMMDQyU25SM1FVNTRVSElyTjNWNlpGQUtRV3BDYVhwR2NHZEVMelJzWW5aa1NuRnplWE5HYlVSeU1TdFNNSGhKWjI1S1N5c3JaWGROYmtKaVMxQkVMemd3VTNJelFYTTVMMWxxV1U5M05EVjRkUXA2ZVdzOUNpMHRMUzB0UlU1RUlFTkZVbFJKUmtsRFFWUkZMUzB0TFMwSyJ9fX19", + IntegratedTime: swag.Int64(123), + LogID: swag.String("not_valid_hex"), + LogIndex: swag.Int64(1), + Verification: &models.LogEntryAnonVerification{ + InclusionProof: &models.InclusionProof{ + Checkpoint: swag.String("checkpoint"), + Hashes: []string{"deadbeef", "abcdefaa"}, + LogIndex: swag.Int64(1), + RootHash: swag.String("abcdefaa"), + TreeSize: swag.Int64(2), + }, + SignedEntryTimestamp: strfmt.Base64("set"), + }, + }, + }, + { + description: "rootHash is not valid hex", + expectSuccess: false, + proposedEntry: models.LogEntryAnon{ + Body: "eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiI2MmQwOGYyOGM2OWNhZGE3YjQyYTQ1Nzk0YjQ3ZWU2YzgxYTdkZmE3MTY4NDZiMzljODhmMGFkMTljMjA2OTk3In19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FVUNJQm14U0N1TW1HSzhNQWRMd1FWZ21TZjVXKzlkdU5iQXN1cUNQNlNucUxCUkFpRUFvNGtGRVdDTG9HcTVUaysrUEhtTEgrb3N1emVTRjN4OTdBbmVicTRlbVRvPSIsInB1YmxpY0tleSI6eyJjb250ZW50IjoiTFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVUk1ha05EUVhKVFowRjNTVUpCWjBsVVRWQkRlVXdyYmxOb2MycHdaa2hZYUZkYVRVWkNUVUZIUlVSQlMwSm5aM0ZvYTJwUFVGRlJSRUY2UVhFS1RWSlZkMFYzV1VSV1VWRkxSWGQ0ZW1GWFpIcGtSemw1V2xNMWExcFlXWGhGVkVGUVFtZE9Wa0pCVFZSRFNFNXdXak5PTUdJelNteE5RalJZUkZSSmVRcE5SRWwzVFdwRmQwNUVXWGhOVm05WVJGUkplVTFFU1hkTmFrVjNUbFJaZUUxR2IzZEZla1ZTVFVFNFIwRXhWVVZEYUUxSll6SnNibU16VW5aamJWVjNDbGRVUVZSQ1oyTnhhR3RxVDFCUlNVSkNaMmR4YUd0cVQxQlJUVUpDZDA1RFFVRlVVMVJ2VEhWS2N5OTFSV05IU2tRME5VWmFiVE5wWmxKTU4yOXVRVWNLWlZaNWJuWkhVbmN6WnpKMU0wbFhTREZuU2tSamNERjRSWFI2UVZCUWJYQmhlVGRtTmxCNE1XeFpNa0ZyWnpsMGEyb3dRa1J2UTNkdk5FbENlbXBEUXdwQlkyOTNSR2RaUkZaU01GQkJVVWd2UWtGUlJFRm5aVUZOUWsxSFFURlZaRXBSVVUxTlFXOUhRME56UjBGUlZVWkNkMDFFVFVGM1IwRXhWV1JGZDBWQ0NpOTNVVU5OUVVGM1NGRlpSRlpTTUU5Q1FsbEZSazlSYTNZNVoyMVpXVFpWU0doQ1pWSnJMMWx4VlVsaU1WRldiMDFDT0VkQk1WVmtTWGRSV1UxQ1lVRUtSa1pxUVVoc0sxSlNZVlp0Y1ZoeVRXdExSMVJKZEVGeGVHTllOazFIVFVkQk1WVmtSVkZTWTAxR2NVZFhSMmd3WkVoQ2VrOXBPSFphTW13d1lVaFdhUXBNYlU1MllsTTVjbGx1VGpCTU0xSnNZMjVLYUZwdE9YbGlVekZ5WkZkS2JHTXpVbWhaTW5OMlRHMWtjR1JIYURGWmFUa3pZak5LY2xwdGVIWmtNMDEyQ21KWFJuQmlhVFUxWWxkNFFXTnRWbTFqZVRsdldsZEdhMk41T1hSWldFNHdXbGhKZDBWbldVdExkMWxDUWtGSFJIWjZRVUpCWjFGRlkwaFdlbUZFUVcwS1FtZHZja0puUlVWQldVOHZUVUZGUmtKQ2FISlpiazR3VEROU2JHTnVTbWhhYlRsNVlsTXhjbVJYU214ak0xSm9XVEp6ZDA1bldVdExkMWxDUWtGSFJBcDJla0ZDUVhkUmIxcHFSVEZPVjFGNVdXMUplRTU2V210TlZFVTFXV3BHYlU5VVNUSk9WRlV6V1hwTk5WbDZTbWxQVkdzMVdtcFNhRnBxWjNkWmVrRTFDa0puYjNKQ1owVkZRVmxQTDAxQlJVSkNRM1J2WkVoU2QyTjZiM1pNTTFKMllUSldkVXh0Um1wa1IyeDJZbTVOZFZveWJEQmhTRlpwWkZoT2JHTnRUbllLWW01U2JHSnVVWFZaTWpsMFRVSTRSME5wYzBkQlVWRkNaemM0ZDBGUldVVkZXRXBzV201TmRtRkhWbWhhU0UxMllsZEdlbVJIVm5sTlEwRkhRMmx6UndwQlVWRkNaemM0ZDBGUlVVVkZhMG94WVZkNGEwbEdVbXhqTTFGblZVaFdhV0pIYkhwaFJFRkxRbWRuY1docmFrOVFVVkZFUVhkT2IwRkVRbXhCYWtWQkNtdDJORTFLYUdGRGFFMUJaMHBWVTNWWll6bFBWRWt3WTB0bU9XTnlObU14Y1RreVYyOXFMM1ZsV0RKRFR6Z3JMMDQyU25SM1FVNTRVSElyTjNWNlpGQUtRV3BDYVhwR2NHZEVMelJzWW5aa1NuRnplWE5HYlVSeU1TdFNNSGhKWjI1S1N5c3JaWGROYmtKaVMxQkVMemd3VTNJelFYTTVMMWxxV1U5M05EVjRkUXA2ZVdzOUNpMHRMUzB0UlU1RUlFTkZVbFJKUmtsRFFWUkZMUzB0TFMwSyJ9fX19", + IntegratedTime: swag.Int64(123), + LogID: swag.String("deadbeef"), + LogIndex: swag.Int64(1), + Verification: &models.LogEntryAnonVerification{ + InclusionProof: &models.InclusionProof{ + Checkpoint: swag.String("checkpoint"), + Hashes: []string{"deadbeef", "abcdefaa"}, + LogIndex: swag.Int64(1), + RootHash: swag.String("not_hex_string"), + TreeSize: swag.Int64(2), + }, + SignedEntryTimestamp: strfmt.Base64("set"), + }, + }, + }, + { + description: "one inclusion proof hash is not valid hex", + expectSuccess: false, + proposedEntry: models.LogEntryAnon{ + Body: "eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiI2MmQwOGYyOGM2OWNhZGE3YjQyYTQ1Nzk0YjQ3ZWU2YzgxYTdkZmE3MTY4NDZiMzljODhmMGFkMTljMjA2OTk3In19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FVUNJQm14U0N1TW1HSzhNQWRMd1FWZ21TZjVXKzlkdU5iQXN1cUNQNlNucUxCUkFpRUFvNGtGRVdDTG9HcTVUaysrUEhtTEgrb3N1emVTRjN4OTdBbmVicTRlbVRvPSIsInB1YmxpY0tleSI6eyJjb250ZW50IjoiTFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVUk1ha05EUVhKVFowRjNTVUpCWjBsVVRWQkRlVXdyYmxOb2MycHdaa2hZYUZkYVRVWkNUVUZIUlVSQlMwSm5aM0ZvYTJwUFVGRlJSRUY2UVhFS1RWSlZkMFYzV1VSV1VWRkxSWGQ0ZW1GWFpIcGtSemw1V2xNMWExcFlXWGhGVkVGUVFtZE9Wa0pCVFZSRFNFNXdXak5PTUdJelNteE5RalJZUkZSSmVRcE5SRWwzVFdwRmQwNUVXWGhOVm05WVJGUkplVTFFU1hkTmFrVjNUbFJaZUUxR2IzZEZla1ZTVFVFNFIwRXhWVVZEYUUxSll6SnNibU16VW5aamJWVjNDbGRVUVZSQ1oyTnhhR3RxVDFCUlNVSkNaMmR4YUd0cVQxQlJUVUpDZDA1RFFVRlVVMVJ2VEhWS2N5OTFSV05IU2tRME5VWmFiVE5wWmxKTU4yOXVRVWNLWlZaNWJuWkhVbmN6WnpKMU0wbFhTREZuU2tSamNERjRSWFI2UVZCUWJYQmhlVGRtTmxCNE1XeFpNa0ZyWnpsMGEyb3dRa1J2UTNkdk5FbENlbXBEUXdwQlkyOTNSR2RaUkZaU01GQkJVVWd2UWtGUlJFRm5aVUZOUWsxSFFURlZaRXBSVVUxTlFXOUhRME56UjBGUlZVWkNkMDFFVFVGM1IwRXhWV1JGZDBWQ0NpOTNVVU5OUVVGM1NGRlpSRlpTTUU5Q1FsbEZSazlSYTNZNVoyMVpXVFpWU0doQ1pWSnJMMWx4VlVsaU1WRldiMDFDT0VkQk1WVmtTWGRSV1UxQ1lVRUtSa1pxUVVoc0sxSlNZVlp0Y1ZoeVRXdExSMVJKZEVGeGVHTllOazFIVFVkQk1WVmtSVkZTWTAxR2NVZFhSMmd3WkVoQ2VrOXBPSFphTW13d1lVaFdhUXBNYlU1MllsTTVjbGx1VGpCTU0xSnNZMjVLYUZwdE9YbGlVekZ5WkZkS2JHTXpVbWhaTW5OMlRHMWtjR1JIYURGWmFUa3pZak5LY2xwdGVIWmtNMDEyQ21KWFJuQmlhVFUxWWxkNFFXTnRWbTFqZVRsdldsZEdhMk41T1hSWldFNHdXbGhKZDBWbldVdExkMWxDUWtGSFJIWjZRVUpCWjFGRlkwaFdlbUZFUVcwS1FtZHZja0puUlVWQldVOHZUVUZGUmtKQ2FISlpiazR3VEROU2JHTnVTbWhhYlRsNVlsTXhjbVJYU214ak0xSm9XVEp6ZDA1bldVdExkMWxDUWtGSFJBcDJla0ZDUVhkUmIxcHFSVEZPVjFGNVdXMUplRTU2V210TlZFVTFXV3BHYlU5VVNUSk9WRlV6V1hwTk5WbDZTbWxQVkdzMVdtcFNhRnBxWjNkWmVrRTFDa0puYjNKQ1owVkZRVmxQTDAxQlJVSkNRM1J2WkVoU2QyTjZiM1pNTTFKMllUSldkVXh0Um1wa1IyeDJZbTVOZFZveWJEQmhTRlpwWkZoT2JHTnRUbllLWW01U2JHSnVVWFZaTWpsMFRVSTRSME5wYzBkQlVWRkNaemM0ZDBGUldVVkZXRXBzV201TmRtRkhWbWhhU0UxMllsZEdlbVJIVm5sTlEwRkhRMmx6UndwQlVWRkNaemM0ZDBGUlVVVkZhMG94WVZkNGEwbEdVbXhqTTFGblZVaFdhV0pIYkhwaFJFRkxRbWRuY1docmFrOVFVVkZFUVhkT2IwRkVRbXhCYWtWQkNtdDJORTFLYUdGRGFFMUJaMHBWVTNWWll6bFBWRWt3WTB0bU9XTnlObU14Y1RreVYyOXFMM1ZsV0RKRFR6Z3JMMDQyU25SM1FVNTRVSElyTjNWNlpGQUtRV3BDYVhwR2NHZEVMelJzWW5aa1NuRnplWE5HYlVSeU1TdFNNSGhKWjI1S1N5c3JaWGROYmtKaVMxQkVMemd3VTNJelFYTTVMMWxxV1U5M05EVjRkUXA2ZVdzOUNpMHRMUzB0UlU1RUlFTkZVbFJKUmtsRFFWUkZMUzB0TFMwSyJ9fX19", + IntegratedTime: swag.Int64(123), + LogID: swag.String("deadbeef"), + LogIndex: swag.Int64(1), + Verification: &models.LogEntryAnonVerification{ + InclusionProof: &models.InclusionProof{ + Checkpoint: swag.String("checkpoint"), + Hashes: []string{"invalid_hex", "abcdefaa"}, + LogIndex: swag.Int64(1), + RootHash: swag.String("abcdefaa"), + TreeSize: swag.Int64(2), + }, + SignedEntryTimestamp: strfmt.Base64("set"), + }, + }, + }, + { + description: "body is valid base64 but not valid entry", + expectSuccess: false, + proposedEntry: models.LogEntryAnon{ + Body: "aW52YWxpZF9lbnRyeQo=", // "invalid_entry" + IntegratedTime: swag.Int64(123), + LogID: swag.String("deadbeef"), + LogIndex: swag.Int64(1), + Verification: &models.LogEntryAnonVerification{ + InclusionProof: &models.InclusionProof{ + Checkpoint: swag.String("checkpoint"), + Hashes: []string{"deadbeef", "abcdefaa"}, + LogIndex: swag.Int64(1), + RootHash: swag.String("abcdefaa"), + TreeSize: swag.Int64(2), + }, + SignedEntryTimestamp: strfmt.Base64("set"), + }, + }, + }, + { + description: "kind/version are valid but spec is not schema valid", + expectSuccess: false, + proposedEntry: models.LogEntryAnon{ + Body: "eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7ImhhcyI6eyJhbGdvcml0aG0iOiJzaGEyNTYiLCJ2YWx1ZSI6IjYyZDA4ZjI4YzY5Y2FkYTdiNDJhNDU3OTRiNDdlZTZjODFhN2RmYTcxNjg0NmIzOWM4OGYwYWQxOWMyMDY5OTcifX0sInNpZ25hdHVyZSI6eyJjb250ZW50IjoiTUVVQ0lCbXhTQ3VNbUdLOE1BZEx3UVZnbVNmNVcrOWR1TmJBc3VxQ1A2U25xTEJSQWlFQW80a0ZFV0NMb0dxNVRrKytQSG1MSCtvc3V6ZVNGM3g5N0FuZWJxNGVtVG89IiwicHVibGljS2V5Ijp7ImNvbnRlbnQiOiJMUzB0TFMxQ1JVZEpUaUJEUlZKVVNVWkpRMEZVUlMwdExTMHRDazFKU1VSTWFrTkRRWEpUWjBGM1NVSkJaMGxVVFZCRGVVd3JibE5vYzJwd1praFlhRmRhVFVaQ1RVRkhSVVJCUzBKblozRm9hMnBQVUZGUlJFRjZRWEVLVFZKVmQwVjNXVVJXVVZGTFJYZDRlbUZYWkhwa1J6bDVXbE0xYTFwWVdYaEZWRUZRUW1kT1ZrSkJUVlJEU0U1d1dqTk9NR0l6U214TlFqUllSRlJKZVFwTlJFbDNUV3BGZDA1RVdYaE5WbTlZUkZSSmVVMUVTWGROYWtWM1RsUlplRTFHYjNkRmVrVlNUVUU0UjBFeFZVVkRhRTFKWXpKc2JtTXpVblpqYlZWM0NsZFVRVlJDWjJOeGFHdHFUMUJSU1VKQ1oyZHhhR3RxVDFCUlRVSkNkMDVEUVVGVVUxUnZUSFZLY3k5MVJXTkhTa1EwTlVaYWJUTnBabEpNTjI5dVFVY0taVlo1Ym5aSFVuY3paekoxTTBsWFNERm5Ta1JqY0RGNFJYUjZRVkJRYlhCaGVUZG1ObEI0TVd4Wk1rRnJaemwwYTJvd1FrUnZRM2R2TkVsQ2VtcERRd3BCWTI5M1JHZFpSRlpTTUZCQlVVZ3ZRa0ZSUkVGblpVRk5RazFIUVRGVlpFcFJVVTFOUVc5SFEwTnpSMEZSVlVaQ2QwMUVUVUYzUjBFeFZXUkZkMFZDQ2k5M1VVTk5RVUYzU0ZGWlJGWlNNRTlDUWxsRlJrOVJhM1k1WjIxWldUWlZTR2hDWlZKckwxbHhWVWxpTVZGV2IwMUNPRWRCTVZWa1NYZFJXVTFDWVVFS1JrWnFRVWhzSzFKU1lWWnRjVmh5VFd0TFIxUkpkRUZ4ZUdOWU5rMUhUVWRCTVZWa1JWRlNZMDFHY1VkWFIyZ3daRWhDZWs5cE9IWmFNbXd3WVVoV2FRcE1iVTUyWWxNNWNsbHVUakJNTTFKc1kyNUthRnB0T1hsaVV6RnlaRmRLYkdNelVtaFpNbk4yVEcxa2NHUkhhREZaYVRrellqTktjbHB0ZUhaa00wMTJDbUpYUm5CaWFUVTFZbGQ0UVdOdFZtMWplVGx2V2xkR2EyTjVPWFJaV0U0d1dsaEpkMFZuV1V0TGQxbENRa0ZIUkhaNlFVSkJaMUZGWTBoV2VtRkVRVzBLUW1kdmNrSm5SVVZCV1U4dlRVRkZSa0pDYUhKWmJrNHdURE5TYkdOdVNtaGFiVGw1WWxNeGNtUlhTbXhqTTFKb1dUSnpkMDVuV1V0TGQxbENRa0ZIUkFwMmVrRkNRWGRSYjFwcVJURk9WMUY1V1cxSmVFNTZXbXROVkVVMVdXcEdiVTlVU1RKT1ZGVXpXWHBOTlZsNlNtbFBWR3MxV21wU2FGcHFaM2RaZWtFMUNrSm5iM0pDWjBWRlFWbFBMMDFCUlVKQ1EzUnZaRWhTZDJONmIzWk1NMUoyWVRKV2RVeHRSbXBrUjJ4MlltNU5kVm95YkRCaFNGWnBaRmhPYkdOdFRuWUtZbTVTYkdKdVVYVlpNamwwVFVJNFIwTnBjMGRCVVZGQ1p6YzRkMEZSV1VWRldFcHNXbTVOZG1GSFZtaGFTRTEyWWxkR2VtUkhWbmxOUTBGSFEybHpSd3BCVVZGQ1p6YzRkMEZSVVVWRmEwb3hZVmQ0YTBsR1VteGpNMUZuVlVoV2FXSkhiSHBoUkVGTFFtZG5jV2hyYWs5UVVWRkVRWGRPYjBGRVFteEJha1ZCQ210Mk5FMUthR0ZEYUUxQlowcFZVM1ZaWXpsUFZFa3dZMHRtT1dOeU5tTXhjVGt5VjI5cUwzVmxXREpEVHpnckwwNDJTblIzUVU1NFVISXJOM1Y2WkZBS1FXcENhWHBHY0dkRUx6UnNZblprU25GemVYTkdiVVJ5TVN0U01IaEpaMjVLU3lzclpYZE5ia0ppUzFCRUx6Z3dVM0l6UVhNNUwxbHFXVTkzTkRWNGRRcDZlV3M5Q2kwdExTMHRSVTVFSUVORlVsUkpSa2xEUVZSRkxTMHRMUzBLIn19fX0K", + IntegratedTime: swag.Int64(123), + LogID: swag.String("deadbeef"), + LogIndex: swag.Int64(1), + Verification: &models.LogEntryAnonVerification{ + InclusionProof: &models.InclusionProof{ + Checkpoint: swag.String("checkpoint"), + Hashes: []string{"deadbeef", "abcdefaa"}, + LogIndex: swag.Int64(1), + RootHash: swag.String("abcdefaa"), + TreeSize: swag.Int64(2), + }, + SignedEntryTimestamp: strfmt.Base64("set"), + }, + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.description, func(t *testing.T) { + e, err := GenerateTransparencyLogEntry(tc.proposedEntry) + if (err == nil) != tc.expectSuccess { + t.Fatalf("unexpected result: %v", err) + } + + if tc.expectSuccess && !reflect.DeepEqual(e, tc.want) { + t.Errorf("unexpected value returned; got %v, wanted %v", e, tc.want) + } + }) + } +} diff --git a/pkg/api/trillian_client.go b/pkg/trillianclient/trillian_client.go similarity index 60% rename from pkg/api/trillian_client.go rename to pkg/trillianclient/trillian_client.go index 6e9278d8b..facd6bdd2 100644 --- a/pkg/api/trillian_client.go +++ b/pkg/trillianclient/trillian_client.go @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package api +package trillianclient import ( "context" @@ -22,7 +22,6 @@ import ( "time" "github.com/sigstore/rekor/pkg/log" - "github.com/sigstore/rekor/pkg/sharding" "github.com/transparency-dev/merkle/proof" "github.com/transparency-dev/merkle/rfc6962" @@ -35,38 +34,38 @@ import ( "github.com/google/trillian/types" ) +// TrillianClient provides a wrapper around the Trillian client type TrillianClient struct { client trillian.TrillianLogClient - ranges sharding.LogRanges logID int64 context context.Context } -func NewTrillianClient(ctx context.Context) TrillianClient { +// NewTrillianClient creates a TrillianClient with the given Trillian client and log/tree ID. +func NewTrillianClient(ctx context.Context, logClient trillian.TrillianLogClient, logID int64) TrillianClient { return TrillianClient{ - client: api.logClient, - ranges: api.logRanges, - logID: api.logID, - context: ctx, - } -} - -func NewTrillianClientFromTreeID(ctx context.Context, tid int64) TrillianClient { - return TrillianClient{ - client: api.logClient, - logID: tid, + client: logClient, + logID: logID, context: ctx, } } +// Response includes a status code, an optional error message, and one of the results based on the API call type Response struct { - status codes.Code - err error - getAddResult *trillian.QueueLeafResponse - getProofResult *trillian.GetInclusionProofByHashResponse - getLeafAndProofResult *trillian.GetEntryAndProofResponse - getLatestResult *trillian.GetLatestSignedLogRootResponse - getConsistencyProofResult *trillian.GetConsistencyProofResponse + // Status is the status code of the response + Status codes.Code + // Error contains an error on request or client failure + Err error + // GetAddResult contains the response from queueing a leaf in Trillian + GetAddResult *trillian.QueueLeafResponse + // GetLeafAndProofResult contains the response for fetching an inclusion proof and leaf + GetLeafAndProofResult *trillian.GetEntryAndProofResponse + // GetLatestResult contains the response for the latest checkpoint + GetLatestResult *trillian.GetLatestSignedLogRootResponse + // GetConsistencyProofResult contains the response for a consistency proof between two log sizes + GetConsistencyProofResult *trillian.GetConsistencyProofResponse + // getProofResult contains the response for an inclusion proof fetched by leaf hash + getProofResult *trillian.GetInclusionProofByHashResponse } func unmarshalLogRoot(logRoot []byte) (types.LogRootV1, error) { @@ -88,7 +87,7 @@ func (t *TrillianClient) root() (types.LogRootV1, error) { return unmarshalLogRoot(resp.SignedLogRoot.LogRoot) } -func (t *TrillianClient) addLeaf(byteValue []byte) *Response { +func (t *TrillianClient) AddLeaf(byteValue []byte) *Response { leaf := &trillian.LogLeaf{ LeafValue: byteValue, } @@ -101,18 +100,18 @@ func (t *TrillianClient) addLeaf(byteValue []byte) *Response { // check for error if err != nil || (resp.QueuedLeaf.Status != nil && resp.QueuedLeaf.Status.Code != int32(codes.OK)) { return &Response{ - status: status.Code(err), - err: err, - getAddResult: resp, + Status: status.Code(err), + Err: err, + GetAddResult: resp, } } root, err := t.root() if err != nil { return &Response{ - status: status.Code(err), - err: err, - getAddResult: resp, + Status: status.Code(err), + Err: err, + GetAddResult: resp, } } v := client.NewLogVerifier(rfc6962.DefaultHasher) @@ -123,8 +122,8 @@ func (t *TrillianClient) addLeaf(byteValue []byte) *Response { select { case <-ctx.Done(): return &Response{ - status: codes.DeadlineExceeded, - err: ctx.Err(), + Status: codes.DeadlineExceeded, + Err: ctx.Err(), } case <-time.After(logClient.MinMergeDelay): } @@ -134,7 +133,7 @@ func (t *TrillianClient) addLeaf(byteValue []byte) *Response { if root.TreeSize >= 1 { proofResp := t.getProofByHash(resp.QueuedLeaf.Leaf.MerkleLeafHash) // if this call succeeds or returns an error other than "not found", return - if proofResp.err == nil || (proofResp.err != nil && status.Code(proofResp.err) != codes.NotFound) { + if proofResp.Err == nil || (proofResp.Err != nil && status.Code(proofResp.Err) != codes.NotFound) { return proofResp } // otherwise wait for a root update before trying again @@ -142,19 +141,19 @@ func (t *TrillianClient) addLeaf(byteValue []byte) *Response { if _, err := logClient.WaitForRootUpdate(ctx); err != nil { return &Response{ - status: codes.Unknown, - err: err, + Status: codes.Unknown, + Err: err, } } } } proofResp := waitForInclusion(t.context, resp.QueuedLeaf.Leaf.MerkleLeafHash) - if proofResp.err != nil { + if proofResp.Err != nil { return &Response{ - status: status.Code(proofResp.err), - err: proofResp.err, - getAddResult: resp, + Status: status.Code(proofResp.Err), + Err: proofResp.Err, + GetAddResult: resp, } } @@ -162,41 +161,41 @@ func (t *TrillianClient) addLeaf(byteValue []byte) *Response { if len(proofs) != 1 { err := fmt.Errorf("expected 1 proof from getProofByHash for %v, found %v", hex.EncodeToString(resp.QueuedLeaf.Leaf.MerkleLeafHash), len(proofs)) return &Response{ - status: status.Code(err), - err: err, - getAddResult: resp, + Status: status.Code(err), + Err: err, + GetAddResult: resp, } } leafIndex := proofs[0].LeafIndex - leafResp := t.getLeafAndProofByIndex(leafIndex) - if leafResp.err != nil { + leafResp := t.GetLeafAndProofByIndex(leafIndex) + if leafResp.Err != nil { return &Response{ - status: status.Code(leafResp.err), - err: leafResp.err, - getAddResult: resp, + Status: status.Code(leafResp.Err), + Err: leafResp.Err, + GetAddResult: resp, } } // overwrite queued leaf that doesn't have index set - resp.QueuedLeaf.Leaf = leafResp.getLeafAndProofResult.Leaf + resp.QueuedLeaf.Leaf = leafResp.GetLeafAndProofResult.Leaf return &Response{ - status: status.Code(err), - err: err, - getAddResult: resp, + Status: status.Code(err), + Err: err, + GetAddResult: resp, // include getLeafAndProofResult for inclusion proof - getLeafAndProofResult: leafResp.getLeafAndProofResult, + GetLeafAndProofResult: leafResp.GetLeafAndProofResult, } } -func (t *TrillianClient) getLeafAndProofByHash(hash []byte) *Response { +func (t *TrillianClient) GetLeafAndProofByHash(hash []byte) *Response { // get inclusion proof for hash, extract index, then fetch leaf using index proofResp := t.getProofByHash(hash) - if proofResp.err != nil { + if proofResp.Err != nil { return &Response{ - status: status.Code(proofResp.err), - err: proofResp.err, + Status: status.Code(proofResp.Err), + Err: proofResp.Err, } } @@ -204,31 +203,31 @@ func (t *TrillianClient) getLeafAndProofByHash(hash []byte) *Response { if len(proofs) != 1 { err := fmt.Errorf("expected 1 proof from getProofByHash for %v, found %v", hex.EncodeToString(hash), len(proofs)) return &Response{ - status: status.Code(err), - err: err, + Status: status.Code(err), + Err: err, } } - return t.getLeafAndProofByIndex(proofs[0].LeafIndex) + return t.GetLeafAndProofByIndex(proofs[0].LeafIndex) } -func (t *TrillianClient) getLeafAndProofByIndex(index int64) *Response { +func (t *TrillianClient) GetLeafAndProofByIndex(index int64) *Response { ctx, cancel := context.WithTimeout(t.context, 20*time.Second) defer cancel() - rootResp := t.getLatest(0) - if rootResp.err != nil { + rootResp := t.GetLatest(0) + if rootResp.Err != nil { return &Response{ - status: status.Code(rootResp.err), - err: rootResp.err, + Status: status.Code(rootResp.Err), + Err: rootResp.Err, } } - root, err := unmarshalLogRoot(rootResp.getLatestResult.SignedLogRoot.LogRoot) + root, err := unmarshalLogRoot(rootResp.GetLatestResult.SignedLogRoot.LogRoot) if err != nil { return &Response{ - status: status.Code(rootResp.err), - err: rootResp.err, + Status: status.Code(rootResp.Err), + Err: rootResp.Err, } } @@ -242,24 +241,61 @@ func (t *TrillianClient) getLeafAndProofByIndex(index int64) *Response { if resp != nil && resp.Proof != nil { if err := proof.VerifyInclusion(rfc6962.DefaultHasher, uint64(index), root.TreeSize, resp.GetLeaf().MerkleLeafHash, resp.Proof.Hashes, root.RootHash); err != nil { return &Response{ - status: status.Code(err), - err: err, + Status: status.Code(err), + Err: err, } } return &Response{ - status: status.Code(err), - err: err, - getLeafAndProofResult: &trillian.GetEntryAndProofResponse{ + Status: status.Code(err), + Err: err, + GetLeafAndProofResult: &trillian.GetEntryAndProofResponse{ Proof: resp.Proof, Leaf: resp.Leaf, - SignedLogRoot: rootResp.getLatestResult.SignedLogRoot, + SignedLogRoot: rootResp.GetLatestResult.SignedLogRoot, }, } } return &Response{ - status: status.Code(err), - err: err, + Status: status.Code(err), + Err: err, + } +} + +func (t *TrillianClient) GetLatest(leafSizeInt int64) *Response { + + ctx, cancel := context.WithTimeout(t.context, 20*time.Second) + defer cancel() + + resp, err := t.client.GetLatestSignedLogRoot(ctx, + &trillian.GetLatestSignedLogRootRequest{ + LogId: t.logID, + FirstTreeSize: leafSizeInt, + }) + + return &Response{ + Status: status.Code(err), + Err: err, + GetLatestResult: resp, + } +} + +func (t *TrillianClient) GetConsistencyProof(firstSize, lastSize int64) *Response { + + ctx, cancel := context.WithTimeout(t.context, 20*time.Second) + defer cancel() + + resp, err := t.client.GetConsistencyProof(ctx, + &trillian.GetConsistencyProofRequest{ + LogId: t.logID, + FirstTreeSize: firstSize, + SecondTreeSize: lastSize, + }) + + return &Response{ + Status: status.Code(err), + Err: err, + GetConsistencyProofResult: resp, } } @@ -267,18 +303,26 @@ func (t *TrillianClient) getProofByHash(hashValue []byte) *Response { ctx, cancel := context.WithTimeout(t.context, 20*time.Second) defer cancel() - rootResp := t.getLatest(0) - if rootResp.err != nil { + rootResp := t.GetLatest(0) + if rootResp.Err != nil { return &Response{ - status: status.Code(rootResp.err), - err: rootResp.err, + Status: status.Code(rootResp.Err), + Err: rootResp.Err, } } - root, err := unmarshalLogRoot(rootResp.getLatestResult.SignedLogRoot.LogRoot) + root, err := unmarshalLogRoot(rootResp.GetLatestResult.SignedLogRoot.LogRoot) if err != nil { return &Response{ - status: status.Code(rootResp.err), - err: rootResp.err, + Status: status.Code(rootResp.Err), + Err: rootResp.Err, + } + } + + // issue 1308: if the tree is empty, there's no way we can return a proof + if root.TreeSize == 0 { + return &Response{ + Status: codes.NotFound, + Err: status.Error(codes.NotFound, "tree is empty"), } } @@ -294,66 +338,29 @@ func (t *TrillianClient) getProofByHash(hashValue []byte) *Response { for _, proof := range resp.Proof { if err := v.VerifyInclusionByHash(&root, hashValue, proof); err != nil { return &Response{ - status: status.Code(err), - err: err, + Status: status.Code(err), + Err: err, } } } // Return an inclusion proof response with the requested return &Response{ - status: status.Code(err), - err: err, + Status: status.Code(err), + Err: err, getProofResult: &trillian.GetInclusionProofByHashResponse{ Proof: resp.Proof, - SignedLogRoot: rootResp.getLatestResult.SignedLogRoot, + SignedLogRoot: rootResp.GetLatestResult.SignedLogRoot, }, } } return &Response{ - status: status.Code(err), - err: err, - } -} - -func (t *TrillianClient) getLatest(leafSizeInt int64) *Response { - - ctx, cancel := context.WithTimeout(t.context, 20*time.Second) - defer cancel() - - resp, err := t.client.GetLatestSignedLogRoot(ctx, - &trillian.GetLatestSignedLogRootRequest{ - LogId: t.logID, - FirstTreeSize: leafSizeInt, - }) - - return &Response{ - status: status.Code(err), - err: err, - getLatestResult: resp, - } -} - -func (t *TrillianClient) getConsistencyProof(firstSize, lastSize int64) *Response { - - ctx, cancel := context.WithTimeout(t.context, 20*time.Second) - defer cancel() - - resp, err := t.client.GetConsistencyProof(ctx, - &trillian.GetConsistencyProofRequest{ - LogId: t.logID, - FirstTreeSize: firstSize, - SecondTreeSize: lastSize, - }) - - return &Response{ - status: status.Code(err), - err: err, - getConsistencyProofResult: resp, + Status: status.Code(err), + Err: err, } } -func createAndInitTree(ctx context.Context, adminClient trillian.TrillianAdminClient, logClient trillian.TrillianLogClient) (*trillian.Tree, error) { +func CreateAndInitTree(ctx context.Context, adminClient trillian.TrillianAdminClient, logClient trillian.TrillianLogClient) (*trillian.Tree, error) { t, err := adminClient.CreateTree(ctx, &trillian.CreateTreeRequest{ Tree: &trillian.Tree{ TreeType: trillian.TreeType_LOG, diff --git a/pkg/types/README.md b/pkg/types/README.md index 81246c449..76cb36e61 100644 --- a/pkg/types/README.md +++ b/pkg/types/README.md @@ -10,12 +10,14 @@ Rekor supports pluggable types (aka different schemas) for entries stored in the - Versions: 0.0.1 - COSE Envelopes [schema](cose/cose_schema.json) - Versions: 0.0.1 +- DSSE Envelopes [schema](dsse/dsse_schema.json) + - Versions: 0.0.1 - HashedRekord [schema](hashedrekord/hashedrekord_schema.json) - Versions: 0.0.1 - Helm Provenance Files [schema](helm/helm_schema.json) - Versions: 0.0.1 - In-Toto Attestations [schema](intoto/intoto_schema.json) - - Versions: 0.0.1 + - Versions: 0.0.1, 0.0.2 - Java Archives (JAR Files) [schema](jar/jar_schema.json) - Versions: 0.0.1 - Rekord *(default type)* [schema](rekord/rekord_schema.json) diff --git a/pkg/types/alpine/alpine_test.go b/pkg/types/alpine/alpine_test.go index 1128db30d..e0c4240ba 100644 --- a/pkg/types/alpine/alpine_test.go +++ b/pkg/types/alpine/alpine_test.go @@ -22,6 +22,7 @@ import ( "github.com/go-openapi/swag" "github.com/sigstore/rekor/pkg/generated/models" + "github.com/sigstore/rekor/pkg/pki" "github.com/sigstore/rekor/pkg/types" ) @@ -38,10 +39,18 @@ func (u UnmarshalFailsTester) NewEntry() types.EntryImpl { return &UnmarshalFailsTester{} } -func (u UnmarshalFailsTester) Unmarshal(pe models.ProposedEntry) error { +func (u UnmarshalFailsTester) Unmarshal(_ models.ProposedEntry) error { return errors.New("error") } +func (u UnmarshalFailsTester) Verifiers() ([]pki.PublicKey, error) { + return nil, nil +} + +func (u UnmarshalFailsTester) Insertable() (bool, error) { + return false, nil +} + func TestAlpineType(t *testing.T) { // empty to start if VersionMap.Count() != 0 { diff --git a/pkg/types/alpine/apk.go b/pkg/types/alpine/apk.go index 51e2d61c5..5007ee4dc 100644 --- a/pkg/types/alpine/apk.go +++ b/pkg/types/alpine/apk.go @@ -33,6 +33,7 @@ import ( "github.com/sigstore/sigstore/pkg/signature" "github.com/sigstore/sigstore/pkg/signature/options" + "github.com/spf13/viper" "gopkg.in/ini.v1" ) @@ -149,6 +150,12 @@ func (p *Package) Unmarshal(pkgReader io.Reader) error { } if strings.HasPrefix(header.Name, ".SIGN") && pkg.Signature == nil { + if header.Size < 0 { + return errors.New("negative header size for .SIGN file") + } + if uint64(header.Size) > viper.GetUint64("max_apk_metadata_size") && viper.GetUint64("max_apk_metadata_size") > 0 { + return fmt.Errorf("uncompressed .SIGN file size %d exceeds max allowed size %d", header.Size, viper.GetUint64("max_apk_metadata_size")) + } sigBytes := make([]byte, header.Size) if _, err = sigReader.Read(sigBytes); err != nil && err != io.EOF { return fmt.Errorf("reading signature: %w", err) @@ -176,6 +183,12 @@ func (p *Package) Unmarshal(pkgReader io.Reader) error { } if header.Name == ".PKGINFO" { + if header.Size < 0 { + return errors.New("negative header size for .PKGINFO file") + } + if uint64(header.Size) > viper.GetUint64("max_apk_metadata_size") && viper.GetUint64("max_apk_metadata_size") > 0 { + return fmt.Errorf("uncompressed .PKGINFO file size %d exceeds max allowed size %d", header.Size, viper.GetUint64("max_apk_metadata_size")) + } pkginfoContent := make([]byte, header.Size) if _, err = ctlReader.Read(pkginfoContent); err != nil && err != io.EOF { return fmt.Errorf("reading .PKGINFO: %w", err) diff --git a/pkg/types/alpine/apk_test.go b/pkg/types/alpine/apk_test.go index 922542452..e6aba40de 100644 --- a/pkg/types/alpine/apk_test.go +++ b/pkg/types/alpine/apk_test.go @@ -17,12 +17,15 @@ package alpine import ( "os" + "strings" "testing" "github.com/sigstore/rekor/pkg/pki/x509" + "github.com/spf13/viper" ) func TestAlpinePackage(t *testing.T) { + inputArchive, err := os.Open("tests/test_alpine.apk") if err != nil { t.Fatalf("could not open archive %v", err) @@ -48,3 +51,21 @@ func TestAlpinePackage(t *testing.T) { t.Fatalf("signature verification failed: %v", err) } } + +func TestAlpineMetadataSize(t *testing.T) { + viper.Set("max_apk_metadata_size", 10) + + inputArchive, err := os.Open("tests/test_alpine.apk") + if err != nil { + t.Fatalf("could not open archive %v", err) + } + + p := Package{} + err = p.Unmarshal(inputArchive) + if err == nil { + t.Fatal("expecting metadata too large err") + } + if !strings.Contains(err.Error(), "exceeds max allowed size 10") { + t.Fatalf("unexpected error %v", err) + } +} diff --git a/pkg/types/alpine/fuzz_test.go b/pkg/types/alpine/fuzz_test.go index 3a4ca3fed..c7364f005 100644 --- a/pkg/types/alpine/fuzz_test.go +++ b/pkg/types/alpine/fuzz_test.go @@ -17,19 +17,32 @@ package alpine import ( "bytes" + "fmt" "testing" - fuzz "github.com/AdaLogics/go-fuzz-headers" + "github.com/spf13/viper" + + fuzz "github.com/AdamKorcz/go-fuzz-headers-1" + utils "github.com/sigstore/rekor/pkg/fuzz" ) +func init() { + viper.Set("max_apk_metadata_size", 60000) + if viper.GetUint64("max_apk_metadata_size") != 60000 { + panic(fmt.Sprintf("max metadata size is not defined: %d", viper.GetUint64("max_apk_metadata_size"))) + } +} + +// FuzzPackageUnmarshal implements the fuzz test func FuzzPackageUnmarshal(f *testing.F) { f.Fuzz(func(t *testing.T, data []byte) { ff := fuzz.NewConsumer(data) - tarBytes, err := ff.TarBytes() + artifactBytes, err := utils.AlpineArtifactBytes(ff) if err != nil { - return + t.Skip() } + p := &Package{} - p.Unmarshal(bytes.NewReader(tarBytes)) + p.Unmarshal(bytes.NewReader(artifactBytes)) }) } diff --git a/pkg/types/alpine/v0.0.1/entry.go b/pkg/types/alpine/v0.0.1/entry.go index be3f1336c..cd3f20bf5 100644 --- a/pkg/types/alpine/v0.0.1/entry.go +++ b/pkg/types/alpine/v0.0.1/entry.go @@ -35,6 +35,7 @@ import ( "github.com/sigstore/rekor/pkg/generated/models" "github.com/sigstore/rekor/pkg/log" + "github.com/sigstore/rekor/pkg/pki" "github.com/sigstore/rekor/pkg/pki/x509" "github.com/sigstore/rekor/pkg/types" "github.com/sigstore/rekor/pkg/types/alpine" @@ -349,3 +350,30 @@ func (v V001Entry) CreateFromArtifactProperties(ctx context.Context, props types return &returnVal, nil } + +func (v V001Entry) Verifiers() ([]pki.PublicKey, error) { + if v.AlpineModel.PublicKey == nil || v.AlpineModel.PublicKey.Content == nil { + return nil, errors.New("alpine v0.0.1 entry not initialized") + } + key, err := x509.NewPublicKey(bytes.NewReader(*v.AlpineModel.PublicKey.Content)) + if err != nil { + return nil, err + } + return []pki.PublicKey{key}, nil +} + +func (v V001Entry) Insertable() (bool, error) { + if v.AlpineModel.Package == nil { + return false, fmt.Errorf("missing package entry") + } + if len(v.AlpineModel.Package.Content) == 0 { + return false, fmt.Errorf("missing package content") + } + if v.AlpineModel.PublicKey == nil { + return false, fmt.Errorf("missing public key") + } + if v.AlpineModel.PublicKey.Content == nil || len(*v.AlpineModel.PublicKey.Content) == 0 { + return false, fmt.Errorf("missing public key content") + } + return true, nil +} diff --git a/pkg/types/alpine/v0.0.1/entry_test.go b/pkg/types/alpine/v0.0.1/entry_test.go index 95d5a621a..03fd600ae 100644 --- a/pkg/types/alpine/v0.0.1/entry_test.go +++ b/pkg/types/alpine/v0.0.1/entry_test.go @@ -48,6 +48,7 @@ func TestCrossFieldValidation(t *testing.T) { entry V001Entry expectUnmarshalSuccess bool expectCanonicalizeSuccess bool + expectedVerifierSuccess bool } keyBytes, _ := os.ReadFile("../tests/test_alpine.pub") @@ -55,9 +56,10 @@ func TestCrossFieldValidation(t *testing.T) { testCases := []TestCase{ { - caseDesc: "empty obj", - entry: V001Entry{}, - expectUnmarshalSuccess: false, + caseDesc: "empty obj", + entry: V001Entry{}, + expectUnmarshalSuccess: false, + expectedVerifierSuccess: false, }, { caseDesc: "public key without content", @@ -66,7 +68,8 @@ func TestCrossFieldValidation(t *testing.T) { PublicKey: &models.AlpineV001SchemaPublicKey{}, }, }, - expectUnmarshalSuccess: false, + expectUnmarshalSuccess: false, + expectedVerifierSuccess: false, }, { caseDesc: "public key without package", @@ -77,7 +80,8 @@ func TestCrossFieldValidation(t *testing.T) { }, }, }, - expectUnmarshalSuccess: false, + expectUnmarshalSuccess: false, + expectedVerifierSuccess: true, }, { caseDesc: "public key with empty package", @@ -89,7 +93,8 @@ func TestCrossFieldValidation(t *testing.T) { Package: &models.AlpineV001SchemaPackage{}, }, }, - expectUnmarshalSuccess: false, + expectUnmarshalSuccess: false, + expectedVerifierSuccess: true, }, { caseDesc: "public key with invalid key content & with data with content", @@ -105,6 +110,7 @@ func TestCrossFieldValidation(t *testing.T) { }, expectUnmarshalSuccess: true, expectCanonicalizeSuccess: false, + expectedVerifierSuccess: false, }, { caseDesc: "public key with key content & with data with content", @@ -120,6 +126,7 @@ func TestCrossFieldValidation(t *testing.T) { }, expectUnmarshalSuccess: true, expectCanonicalizeSuccess: true, + expectedVerifierSuccess: true, }, } @@ -144,6 +151,12 @@ func TestCrossFieldValidation(t *testing.T) { t.Errorf("unexpected result in '%v': %v", tc.caseDesc, err) } + if tc.expectUnmarshalSuccess { + if ok, err := v.Insertable(); !ok || err != nil { + t.Errorf("unexpected result in calling Insertable on valid proposed entry: %v", err) + } + } + b, err := v.Canonicalize(context.TODO()) if (err == nil) != tc.expectCanonicalizeSuccess { t.Errorf("unexpected result from Canonicalize for '%v': %v", tc.caseDesc, err) @@ -157,9 +170,141 @@ func TestCrossFieldValidation(t *testing.T) { if err != nil { t.Errorf("unexpected err from Unmarshalling canonicalized entry for '%v': %v", tc.caseDesc, err) } - if _, err := types.UnmarshalEntry(pe); err != nil { + ei, err := types.UnmarshalEntry(pe) + if err != nil { t.Errorf("unexpected err from type-specific unmarshalling for '%v': %v", tc.caseDesc, err) } + if ok, err := ei.Insertable(); ok || err == nil { + t.Errorf("unexpected success calling Insertable on entry created from canonicalized content") + } + } + + verifiers, err := v.Verifiers() + if tc.expectedVerifierSuccess { + if err != nil { + t.Errorf("%v: unexpected error, got %v", tc.caseDesc, err) + } else { + pub, _ := verifiers[0].CanonicalValue() + if !reflect.DeepEqual(pub, keyBytes) { + t.Errorf("%v: verifier and public keys do not match: %v, %v", tc.caseDesc, string(pub), string(keyBytes)) + } + } + } else { + if err == nil { + s, _ := verifiers[0].CanonicalValue() + t.Errorf("%v: expected error for %v, got %v", tc.caseDesc, string(s), err) + } } } } + +func TestInsertable(t *testing.T) { + type TestCase struct { + caseDesc string + entry V001Entry + expectSuccess bool + } + + pub := strfmt.Base64([]byte("pub")) + + testCases := []TestCase{ + { + caseDesc: "valid entry", + entry: V001Entry{ + AlpineModel: models.AlpineV001Schema{ + Package: &models.AlpineV001SchemaPackage{ + Content: strfmt.Base64("package"), + }, + PublicKey: &models.AlpineV001SchemaPublicKey{ + Content: &pub, + }, + }, + }, + expectSuccess: true, + }, + { + caseDesc: "missing key content", + entry: V001Entry{ + AlpineModel: models.AlpineV001Schema{ + Package: &models.AlpineV001SchemaPackage{ + Content: strfmt.Base64("package"), + }, + PublicKey: &models.AlpineV001SchemaPublicKey{ + //Content: &pub, + }, + }, + }, + expectSuccess: false, + }, + { + caseDesc: "missing public key", + entry: V001Entry{ + AlpineModel: models.AlpineV001Schema{ + Package: &models.AlpineV001SchemaPackage{ + Content: strfmt.Base64("package"), + }, + /* + PublicKey: &models.AlpineV001SchemaPublicKey{ + Content: &pub, + }, + */ + }, + }, + expectSuccess: false, + }, + { + caseDesc: "missing package content", + entry: V001Entry{ + AlpineModel: models.AlpineV001Schema{ + Package: &models.AlpineV001SchemaPackage{ + //Content: strfmt.Base64("package"), + }, + PublicKey: &models.AlpineV001SchemaPublicKey{ + Content: &pub, + }, + }, + }, + expectSuccess: false, + }, + { + caseDesc: "missing package", + entry: V001Entry{ + AlpineModel: models.AlpineV001Schema{ + /* + Package: &models.AlpineV001SchemaPackage{ + Content: strfmt.Base64("package"), + }, + */ + PublicKey: &models.AlpineV001SchemaPublicKey{ + Content: &pub, + }, + }, + }, + expectSuccess: false, + }, + { + caseDesc: "empty model", + entry: V001Entry{ + AlpineModel: models.AlpineV001Schema{ + /* + Package: &models.AlpineV001SchemaPackage{ + Content: strfmt.Base64("package"), + }, + PublicKey: &models.AlpineV001SchemaPublicKey{ + Content: &pub, + }, + */ + }, + }, + expectSuccess: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.caseDesc, func(t *testing.T) { + if ok, err := tc.entry.Insertable(); ok != tc.expectSuccess { + t.Errorf("unexpected result calling Insertable: %v", err) + } + }) + } +} diff --git a/pkg/types/alpine/v0.0.1/fuzz_test.go b/pkg/types/alpine/v0.0.1/fuzz_test.go new file mode 100644 index 000000000..3a269a72f --- /dev/null +++ b/pkg/types/alpine/v0.0.1/fuzz_test.go @@ -0,0 +1,97 @@ +// +// Copyright 2022 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 alpine + +import ( + "context" + "sync" + "testing" + + fuzz "github.com/AdamKorcz/go-fuzz-headers-1" + "github.com/go-openapi/swag" + + fuzzUtils "github.com/sigstore/rekor/pkg/fuzz" + "github.com/sigstore/rekor/pkg/generated/models" + "github.com/sigstore/rekor/pkg/types" + "github.com/sigstore/rekor/pkg/types/alpine" +) + +var initter sync.Once + +func FuzzAlpineCreateProposedEntry(f *testing.F) { + f.Fuzz(func(t *testing.T, propsData []byte) { + initter.Do(fuzzUtils.SetFuzzLogger) + + version := "0.0.1" + + ff := fuzz.NewConsumer(propsData) + + props, cleanup, err := fuzzUtils.CreateAlpineProps(ff) + if err != nil { + t.Skip() + } + defer cleanup() + + it := alpine.New() + entry, err := it.CreateProposedEntry(context.Background(), version, props) + if err != nil { + t.Skip() + } + + ei, err := types.CreateVersionedEntry(entry) + if err != nil { + t.Skip() + } + + if ok, err := ei.Insertable(); !ok || err != nil { + t.Errorf("entry created via CreateProposedEntry should be insertable: %v", err) + } + + if _, err := types.CanonicalizeEntry(context.Background(), ei); err != nil { + t.Errorf("valid insertable entry should be able to be canonicalized: %v", err) + } + + _, _ = ei.IndexKeys() + }) +} + +func FuzzAlpineUnmarshalAndCanonicalize(f *testing.F) { + f.Fuzz(func(t *testing.T, entryData []byte) { + initter.Do(fuzzUtils.SetFuzzLogger) + + ff := fuzz.NewConsumer(entryData) + + targetV001 := &models.AlpineV001Schema{} + + if err := ff.GenerateStruct(targetV001); err != nil { + t.Skip() + } + + targetEntry := &models.Alpine{ + APIVersion: swag.String(APIVERSION), + Spec: targetV001, + } + + ei, err := types.UnmarshalEntry(targetEntry) + if err != nil { + t.Skip() + } + + if _, err := types.CanonicalizeEntry(context.Background(), ei); err != nil { + t.Skip() + } + }) +} diff --git a/pkg/types/cose/cose_test.go b/pkg/types/cose/cose_test.go index 04290ec46..237e2329d 100644 --- a/pkg/types/cose/cose_test.go +++ b/pkg/types/cose/cose_test.go @@ -23,6 +23,7 @@ import ( "github.com/go-openapi/swag" "github.com/sigstore/rekor/pkg/generated/models" + "github.com/sigstore/rekor/pkg/pki" "github.com/sigstore/rekor/pkg/types" ) @@ -39,10 +40,18 @@ func (u UnmarshalFailsTester) NewEntry() types.EntryImpl { return &UnmarshalFailsTester{} } -func (u UnmarshalFailsTester) Unmarshal(pe models.ProposedEntry) error { +func (u UnmarshalFailsTester) Unmarshal(_ models.ProposedEntry) error { return errors.New("error") } +func (u UnmarshalFailsTester) Verifiers() ([]pki.PublicKey, error) { + return nil, nil +} + +func (u UnmarshalFailsTester) Insertable() (bool, error) { + return false, nil +} + func TestCOSEType(t *testing.T) { // empty to start if VersionMap.Count() != 0 { diff --git a/pkg/types/cose/v0.0.1/entry.go b/pkg/types/cose/v0.0.1/entry.go index ecec75c63..d5a74b422 100644 --- a/pkg/types/cose/v0.0.1/entry.go +++ b/pkg/types/cose/v0.0.1/entry.go @@ -188,7 +188,7 @@ func (v *V001Entry) Unmarshal(pe models.ProposedEntry) error { return v.validate() } -func (v *V001Entry) Canonicalize(ctx context.Context) ([]byte, error) { +func (v *V001Entry) Canonicalize(_ context.Context) ([]byte, error) { if v.keyObj == nil { return nil, errors.New("cannot canonicalze empty key") } @@ -347,3 +347,37 @@ func (v V001Entry) CreateFromArtifactProperties(_ context.Context, props types.A return &returnVal, nil } + +func (v V001Entry) Verifiers() ([]pki.PublicKey, error) { + if v.CoseObj.PublicKey == nil { + return nil, errors.New("cose v0.0.1 entry not initialized") + } + key, err := x509.NewPublicKey(bytes.NewReader(*v.CoseObj.PublicKey)) + if err != nil { + return nil, err + } + return []pki.PublicKey{key}, nil +} + +func (v V001Entry) Insertable() (bool, error) { + if len(v.CoseObj.Message) == 0 { + return false, errors.New("missing COSE Sign1 message") + } + if v.CoseObj.PublicKey == nil || len(*v.CoseObj.PublicKey) == 0 { + return false, errors.New("missing public key") + } + if v.CoseObj.Data == nil { + return false, errors.New("missing COSE data property") + } + if len(v.envelopeHash) == 0 { + return false, errors.New("envelope hash has not been computed") + } + if v.keyObj == nil { + return false, errors.New("public key has not been parsed") + } + if v.sign1Msg == nil { + return false, errors.New("signature has not been validated") + } + + return true, nil +} diff --git a/pkg/types/cose/v0.0.1/entry_test.go b/pkg/types/cose/v0.0.1/entry_test.go index 584256cbf..f6b7a4107 100644 --- a/pkg/types/cose/v0.0.1/entry_test.go +++ b/pkg/types/cose/v0.0.1/entry_test.go @@ -17,6 +17,7 @@ package cose import ( "bytes" + "context" "crypto/ecdsa" "crypto/elliptic" "crypto/rand" @@ -30,8 +31,10 @@ import ( "reflect" "testing" + "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" "github.com/sigstore/rekor/pkg/generated/models" + "github.com/sigstore/rekor/pkg/pki/identity" sigx509 "github.com/sigstore/rekor/pkg/pki/x509" "github.com/sigstore/rekor/pkg/types" "github.com/spf13/viper" @@ -88,6 +91,10 @@ func (t testPublicKey) Subjects() []string { return nil } +func (t testPublicKey) Identities() ([]identity.Identity, error) { + return nil, nil +} + func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } @@ -159,22 +166,25 @@ func TestV001Entry_Unmarshal(t *testing.T) { msgWithAAD := makeSignedCose(t, priv, []byte("hello"), []byte("external aad"), "") tests := []struct { - name string - want models.CoseV001Schema - it *models.CoseV001Schema - wantErr bool + name string + want models.CoseV001Schema + it *models.CoseV001Schema + wantErr bool + wantVerifierErr bool }{ { - name: "empty", - it: &models.CoseV001Schema{}, - wantErr: true, + name: "empty", + it: &models.CoseV001Schema{}, + wantErr: true, + wantVerifierErr: true, }, { name: "missing data", it: &models.CoseV001Schema{ PublicKey: p(pub), }, - wantErr: true, + wantErr: true, + wantVerifierErr: false, }, { name: "missing envelope", @@ -182,7 +192,8 @@ func TestV001Entry_Unmarshal(t *testing.T) { Data: &models.CoseV001SchemaData{}, PublicKey: p([]byte("hello")), }, - wantErr: true, + wantErr: true, + wantVerifierErr: true, }, { name: "valid", @@ -191,7 +202,8 @@ func TestV001Entry_Unmarshal(t *testing.T) { PublicKey: p(pub), Message: msg, }, - wantErr: false, + wantErr: false, + wantVerifierErr: false, }, { name: "valid with aad", @@ -202,7 +214,8 @@ func TestV001Entry_Unmarshal(t *testing.T) { PublicKey: p(pub), Message: msgWithAAD, }, - wantErr: false, + wantErr: false, + wantVerifierErr: false, }, { name: "extra aad", @@ -213,7 +226,8 @@ func TestV001Entry_Unmarshal(t *testing.T) { PublicKey: p(pub), Message: msg, }, - wantErr: true, + wantErr: true, + wantVerifierErr: false, }, { name: "invalid envelope", @@ -222,7 +236,8 @@ func TestV001Entry_Unmarshal(t *testing.T) { PublicKey: p([]byte(pemBytes)), Message: []byte("hello"), }, - wantErr: true, + wantErr: true, + wantVerifierErr: false, }, { name: "cert", @@ -231,7 +246,8 @@ func TestV001Entry_Unmarshal(t *testing.T) { PublicKey: p([]byte(pemBytes)), Message: msg, }, - wantErr: false, + wantErr: false, + wantVerifierErr: false, }, { name: "invalid key", @@ -240,7 +256,8 @@ func TestV001Entry_Unmarshal(t *testing.T) { PublicKey: p([]byte("notavalidkey")), Message: []byte("hello"), }, - wantErr: true, + wantErr: true, + wantVerifierErr: true, }, } @@ -255,6 +272,48 @@ func TestV001Entry_Unmarshal(t *testing.T) { if err := v.Unmarshal(it); (err != nil) != tt.wantErr { t.Errorf("V001Entry.Unmarshal() error = %v, wantErr %v", err, tt.wantErr) } + + if !tt.wantErr { + if ok, err := v.Insertable(); !ok || err != nil { + t.Errorf("unexpected error calling Insertable on valid proposed entry: %v", err) + } + } + + verifiers, err := v.Verifiers() + if !tt.wantVerifierErr { + if err != nil { + s, _ := verifiers[0].CanonicalValue() + t.Errorf("%v: unexpected error for %v, got %v", tt.name, string(s), err) + } + + if !tt.wantErr { + b, err := v.Canonicalize(context.Background()) + if err != nil { + t.Errorf("unexpected error canonicalizing %v", tt.name) + } + if len(b) != 0 { + pe, err := models.UnmarshalProposedEntry(bytes.NewReader(b), runtime.JSONConsumer()) + if err != nil { + t.Errorf("unexpected err from Unmarshalling canonicalized entry for '%v': %v", tt.name, err) + } + ei, err := types.UnmarshalEntry(pe) + if err != nil { + t.Errorf("unexpected err from type-specific unmarshalling for '%v': %v", tt.name, err) + } + if ok, err := ei.Insertable(); ok || err == nil { + t.Errorf("entry created from canonicalized entry should not also be insertable") + } + } + } + + pubV, _ := verifiers[0].CanonicalValue() + if !reflect.DeepEqual(pubV, pub) && !reflect.DeepEqual(pubV, pemBytes) { + t.Errorf("verifier and public keys do not match: %v, %v", string(pubV), string(pub)) + } + } else if err == nil { + s, _ := verifiers[0].CanonicalValue() + t.Errorf("%v: expected error for %v, got %v", tt.name, string(s), err) + } }) } @@ -661,3 +720,202 @@ func mustContain(t *testing.T, want string, l []string) { } t.Fatalf("list %v does not contain %s", l, want) } + +func TestInsertable(t *testing.T) { + type TestCase struct { + caseDesc string + entry V001Entry + expectSuccess bool + } + + key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + t.Fatal(err) + } + der, err := x509.MarshalPKIXPublicKey(&key.PublicKey) + if err != nil { + t.Fatal(err) + } + pub := pem.EncodeToMemory(&pem.Block{ + Bytes: der, + Type: "PUBLIC KEY", + }) + keyObj, err := sigx509.NewPublicKey(bytes.NewReader(pub)) + if err != nil { + t.Fatal(err) + } + pubKey := strfmt.Base64(pub) + + testCases := []TestCase{ + { + caseDesc: "valid entry", + entry: V001Entry{ + CoseObj: models.CoseV001Schema{ + Data: &models.CoseV001SchemaData{ + Aad: strfmt.Base64([]byte("aad")), + }, + Message: strfmt.Base64([]byte("message")), + PublicKey: &pubKey, + }, + keyObj: keyObj, + sign1Msg: &gocose.Sign1Message{}, + envelopeHash: []byte("hash"), + }, + expectSuccess: true, + }, + { + caseDesc: "no aad", + entry: V001Entry{ + CoseObj: models.CoseV001Schema{ + Data: &models.CoseV001SchemaData{}, + Message: strfmt.Base64([]byte("message")), + PublicKey: &pubKey, + }, + keyObj: keyObj, + sign1Msg: &gocose.Sign1Message{}, + envelopeHash: []byte("hash"), + }, + expectSuccess: true, + }, + { + caseDesc: "missing hash", + entry: V001Entry{ + CoseObj: models.CoseV001Schema{ + Data: &models.CoseV001SchemaData{}, + Message: strfmt.Base64([]byte("message")), + PublicKey: &pubKey, + }, + keyObj: keyObj, + sign1Msg: &gocose.Sign1Message{}, + //envelopeHash: []byte("hash"), + }, + expectSuccess: false, + }, + { + caseDesc: "unparsed message", + entry: V001Entry{ + CoseObj: models.CoseV001Schema{ + Data: &models.CoseV001SchemaData{ + Aad: strfmt.Base64([]byte("aad")), + }, + Message: strfmt.Base64([]byte("message")), + PublicKey: &pubKey, + }, + keyObj: keyObj, + //sign1Msg: &gocose.Sign1Message{}, + envelopeHash: []byte("hash"), + }, + expectSuccess: false, + }, + { + caseDesc: "unparsed public key", + entry: V001Entry{ + CoseObj: models.CoseV001Schema{ + Data: &models.CoseV001SchemaData{ + Aad: strfmt.Base64([]byte("aad")), + }, + Message: strfmt.Base64([]byte("message")), + PublicKey: &pubKey, + }, + //keyObj: keyObj, + sign1Msg: &gocose.Sign1Message{}, + envelopeHash: []byte("hash"), + }, + expectSuccess: false, + }, + { + caseDesc: "missing public key", + entry: V001Entry{ + CoseObj: models.CoseV001Schema{ + Data: &models.CoseV001SchemaData{ + Aad: strfmt.Base64([]byte("aad")), + }, + Message: strfmt.Base64([]byte("message")), + //PublicKey: &pubKey, + }, + keyObj: keyObj, + sign1Msg: &gocose.Sign1Message{}, + envelopeHash: []byte("hash"), + }, + expectSuccess: false, + }, + { + caseDesc: "missing unparsed message", + entry: V001Entry{ + CoseObj: models.CoseV001Schema{ + Data: &models.CoseV001SchemaData{ + Aad: strfmt.Base64([]byte("aad")), + }, + //Message: strfmt.Base64([]byte("message")), + PublicKey: &pubKey, + }, + keyObj: keyObj, + sign1Msg: &gocose.Sign1Message{}, + envelopeHash: []byte("hash"), + }, + expectSuccess: false, + }, + { + caseDesc: "missing data", + entry: V001Entry{ + CoseObj: models.CoseV001Schema{ + /* + Data: &models.CoseV001SchemaData{ + Aad: strfmt.Base64([]byte("aad")), + }, + */ + Message: strfmt.Base64([]byte("message")), + PublicKey: &pubKey, + }, + keyObj: keyObj, + sign1Msg: &gocose.Sign1Message{}, + envelopeHash: []byte("hash"), + }, + expectSuccess: false, + }, + { + caseDesc: "missing cose obj", + entry: V001Entry{ + /* + CoseObj: models.CoseV001Schema{ + Data: &models.CoseV001SchemaData{ + Aad: strfmt.Base64([]byte("aad")), + }, + Message: strfmt.Base64([]byte("message")), + PublicKey: &pubKey, + }, + */ + keyObj: keyObj, + sign1Msg: &gocose.Sign1Message{}, + envelopeHash: []byte("hash"), + }, + expectSuccess: false, + }, + { + caseDesc: "empty obj", + entry: V001Entry{ + /* + CoseObj: models.CoseV001Schema{ + Data: &models.CoseV001SchemaData{ + Aad: strfmt.Base64([]byte("aad")), + }, + Message: strfmt.Base64([]byte("message")), + PublicKey: &pubKey, + }, + keyObj: keyObj, + sign1Msg: &gocose.Sign1Message{}, + envelopeHash: []byte("hash"), + */ + }, + expectSuccess: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.caseDesc, func(t *testing.T) { + if ok, err := tc.entry.Insertable(); ok != tc.expectSuccess { + t.Errorf("unexpected result calling Insertable: %v", err) + } + }) + } +} diff --git a/pkg/types/cose/v0.0.1/fuzz_test.go b/pkg/types/cose/v0.0.1/fuzz_test.go new file mode 100644 index 000000000..2e69e4cfa --- /dev/null +++ b/pkg/types/cose/v0.0.1/fuzz_test.go @@ -0,0 +1,101 @@ +// +// Copyright 2022 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 cose + +import ( + "context" + "sync" + "testing" + + fuzz "github.com/AdamKorcz/go-fuzz-headers-1" + "github.com/go-openapi/swag" + + fuzzUtils "github.com/sigstore/rekor/pkg/fuzz" + "github.com/sigstore/rekor/pkg/generated/models" + "github.com/sigstore/rekor/pkg/types" + "github.com/sigstore/rekor/pkg/types/cose" +) + +var initter sync.Once + +func FuzzCoseCreateProposedEntry(f *testing.F) { + f.Fuzz(func(t *testing.T, propsData []byte) { + initter.Do(fuzzUtils.SetFuzzLogger) + + version := "0.0.1" + + ff := fuzz.NewConsumer(propsData) + + props, cleanup, err := fuzzUtils.CreateProps(ff, "coseV001") + if err != nil { + t.Skip() + } + defer func() { + for _, c := range cleanup { + c() + } + }() + + it := cose.New() + entry, err := it.CreateProposedEntry(context.Background(), version, props) + if err != nil { + t.Skip() + } + + ei, err := types.CreateVersionedEntry(entry) + if err != nil { + t.Skip() + } + + if ok, err := ei.Insertable(); !ok || err != nil { + t.Errorf("entry created via CreateProposedEntry should be insertable: %v", err) + } + + if _, err := types.CanonicalizeEntry(context.Background(), ei); err != nil { + t.Errorf("valid insertable entry should be able to be canonicalized: %v", err) + } + + _, _ = ei.IndexKeys() + }) +} + +func FuzzCoseUnmarshalAndCanonicalize(f *testing.F) { + f.Fuzz(func(t *testing.T, entryData []byte) { + initter.Do(fuzzUtils.SetFuzzLogger) + + ff := fuzz.NewConsumer(entryData) + + targetV001 := &models.CoseV001Schema{} + + if err := ff.GenerateStruct(targetV001); err != nil { + t.Skip() + } + + targetEntry := &models.Cose{ + APIVersion: swag.String(APIVERSION), + Spec: targetV001, + } + + ei, err := types.UnmarshalEntry(targetEntry) + if err != nil { + t.Skip() + } + + if _, err := types.CanonicalizeEntry(context.Background(), ei); err != nil { + t.Errorf("error canonicalizing unmarshalled entry: %v", err) + } + }) +} diff --git a/pkg/types/dsse/README.md b/pkg/types/dsse/README.md new file mode 100644 index 000000000..3244c98ec --- /dev/null +++ b/pkg/types/dsse/README.md @@ -0,0 +1,25 @@ +**DSSE Type Data Documentation** + +This document provides a definition for each field that is not otherwise described in the [dsse +schema](https://github.com/sigstore/rekor/blob/main/pkg/types/dsse/v0.0.1/dsse_v0_0_1_schema.json). This +document also notes any additional information about the values +associated with each field such as the format in which the data is +stored and any necessary transformations. + +**How do you identify an object as an DSSE object?** + +The "Body" field will include an "dsseObj" field. + +**Recognized content types** + +- [in-toto + statements](https://github.com/in-toto/attestation/tree/main/spec#statement) + are recognized and parsed. The found subject hashes are indexed so + they can be searched for. + +**What data about the envelope is stored in Rekor** + +Only the hash of the payload (the content covered by the digital signature inside the envelope), the hash of the entire DSSE envelope (including signatures), +the signature(s) and their corresponding verifying materials (e.g. public key(s) or certificates) are stored. + +Even if Rekor is configured to use attestation storage, the entire DSSE envelope will not be stored. diff --git a/pkg/types/dsse/dsse.go b/pkg/types/dsse/dsse.go new file mode 100644 index 000000000..9036fe562 --- /dev/null +++ b/pkg/types/dsse/dsse.go @@ -0,0 +1,74 @@ +// +// 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. + +package dsse + +import ( + "context" + "errors" + "fmt" + + "github.com/sigstore/rekor/pkg/generated/models" + "github.com/sigstore/rekor/pkg/types" +) + +const ( + KIND = "dsse" +) + +type BaseDSSEType struct { + types.RekorType +} + +func init() { + types.TypeMap.Store(KIND, New) +} + +func New() types.TypeImpl { + bit := BaseDSSEType{} + bit.Kind = KIND + bit.VersionMap = VersionMap + return &bit +} + +var VersionMap = types.NewSemVerEntryFactoryMap() + +func (it BaseDSSEType) UnmarshalEntry(pe models.ProposedEntry) (types.EntryImpl, error) { + if pe == nil { + return nil, errors.New("proposed entry cannot be nil") + } + + in, ok := pe.(*models.DSSE) + if !ok { + return nil, errors.New("cannot unmarshal non-DSSE types") + } + + return it.VersionedUnmarshal(in, *in.APIVersion) +} + +func (it *BaseDSSEType) CreateProposedEntry(ctx context.Context, version string, props types.ArtifactProperties) (models.ProposedEntry, error) { + if version == "" { + version = it.DefaultVersion() + } + ei, err := it.VersionedUnmarshal(nil, version) + if err != nil { + return nil, fmt.Errorf("fetching DSSE version implementation: %w", err) + } + return ei.CreateFromArtifactProperties(ctx, props) +} + +func (it BaseDSSEType) DefaultVersion() string { + return "0.0.1" +} diff --git a/pkg/types/dsse/dsse_schema.json b/pkg/types/dsse/dsse_schema.json new file mode 100644 index 000000000..7dc710fe2 --- /dev/null +++ b/pkg/types/dsse/dsse_schema.json @@ -0,0 +1,12 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "http://rekor.sigstore.dev/types/dsse/dsse_schema.json", + "title": "DSSE Schema", + "description": "log entry schema for dsse envelopes", + "type": "object", + "oneOf": [ + { + "$ref": "v0.0.1/dsse_v0_0_1_schema.json" + } + ] +} diff --git a/pkg/types/dsse/dsse_test.go b/pkg/types/dsse/dsse_test.go new file mode 100644 index 000000000..d81aa164a --- /dev/null +++ b/pkg/types/dsse/dsse_test.go @@ -0,0 +1,173 @@ +// +// 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. + +package dsse + +import ( + "context" + "errors" + "testing" + + "github.com/go-openapi/swag" + + "github.com/sigstore/rekor/pkg/generated/models" + "github.com/sigstore/rekor/pkg/pki" + "github.com/sigstore/rekor/pkg/types" +) + +type UnmarshalTester struct { + models.DSSE + types.BaseUnmarshalTester +} + +type UnmarshalFailsTester struct { + types.BaseUnmarshalTester +} + +func (u UnmarshalFailsTester) NewEntry() types.EntryImpl { + return &UnmarshalFailsTester{} +} + +func (u UnmarshalFailsTester) Unmarshal(_ models.ProposedEntry) error { + return errors.New("error") +} + +func (u UnmarshalFailsTester) Verifiers() ([]pki.PublicKey, error) { + return nil, nil +} + +func TestDSSEType(t *testing.T) { + // empty to start + if VersionMap.Count() != 0 { + t.Error("semver range was not blank at start of test") + } + + u := UnmarshalTester{} + // ensure semver range parser is working + invalidSemVerRange := "not a valid semver range" + err := VersionMap.SetEntryFactory(invalidSemVerRange, u.NewEntry) + if err == nil || VersionMap.Count() > 0 { + t.Error("invalid semver range was incorrectly added to SemVerToFacFnMap") + } + + // valid semver range can be parsed + err = VersionMap.SetEntryFactory(">= 1.2.3", u.NewEntry) + if err != nil || VersionMap.Count() != 1 { + t.Error("valid semver range was not added to SemVerToFacFnMap") + } + + u.DSSE.APIVersion = swag.String("2.0.1") + brt := New() + + // version requested matches implementation in map + if _, err := brt.UnmarshalEntry(&u.DSSE); err != nil { + t.Errorf("unexpected error in Unmarshal: %v", err) + } + + // version requested fails to match implementation in map + u.DSSE.APIVersion = swag.String("1.2.2") + if _, err := brt.UnmarshalEntry(&u.DSSE); err == nil { + t.Error("unexpected success in Unmarshal for non-matching version") + } + + // error in Unmarshal call is raised appropriately + u.DSSE.APIVersion = swag.String("2.2.0") + u2 := UnmarshalFailsTester{} + _ = VersionMap.SetEntryFactory(">= 1.2.3", u2.NewEntry) + if _, err := brt.UnmarshalEntry(&u.DSSE); err == nil { + t.Error("unexpected success in Unmarshal when error is thrown") + } + + // version requested fails to match implementation in map + u.DSSE.APIVersion = swag.String("not_a_version") + if _, err := brt.UnmarshalEntry(&u.DSSE); err == nil { + t.Error("unexpected success in Unmarshal for invalid version") + } + + ti, err := brt.UnmarshalEntry(nil) + if ti != nil { + t.Error("unexpected success in unmarshal for nil") + } + if err == nil { + t.Error("expected error") + } + + ti, err = brt.UnmarshalEntry(types.BaseProposedEntryTester{}) + if ti != nil { + t.Error("unexpected success in unmarshal for nil") + } + if err == nil { + t.Error("expected error") + } + +} + +func TestDSSEDefaultVersion(t *testing.T) { + brt := New() + ver := brt.DefaultVersion() + if ver != "0.0.1" { + t.Errorf("unexpected default version %s", ver) + } +} + +func TestDSSECreateProposedEntry(t *testing.T) { + // Reset semver map + VersionMap = types.NewSemVerEntryFactoryMap() + u := UnmarshalTester{} + VersionMap.SetEntryFactory("0.0.1", u.NewEntry) + VersionMap.SetEntryFactory(New().DefaultVersion(), u.NewEntry) + + t.Run("unknown version", func(t *testing.T) { + ctx := context.Background() + brt := New() + props := types.ArtifactProperties{} + pe, err := brt.CreateProposedEntry(ctx, "1.2.3", props) + + if pe != nil { + t.Error("unexpected proposed entry") + } + if err == nil { + t.Error("expected error") + } + }) + t.Run("valid version", func(t *testing.T) { + ctx := context.Background() + brt := New() + props := types.ArtifactProperties{} + pe, err := brt.CreateProposedEntry(ctx, "0.0.1", props) + + // BaseUnmarshalTester returns nil for the proposed entry + if pe != nil { + t.Error("unexpected proposed entry") + } + if err != nil { + t.Error("unexpected error") + } + }) + t.Run("default version", func(t *testing.T) { + ctx := context.Background() + brt := New() + props := types.ArtifactProperties{} + pe, err := brt.CreateProposedEntry(ctx, "", props) + + // BaseUnmarshalTester returns nil for the proposed entry + if pe != nil { + t.Error("unexpected proposed entry") + } + if err != nil { + t.Error("unexpected error") + } + }) +} diff --git a/pkg/types/dsse/v0.0.1/dsse_v0_0_1_schema.json b/pkg/types/dsse/v0.0.1/dsse_v0_0_1_schema.json new file mode 100644 index 000000000..51ebe3990 --- /dev/null +++ b/pkg/types/dsse/v0.0.1/dsse_v0_0_1_schema.json @@ -0,0 +1,96 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "http://rekor.sigstore.dev/types/dsse/dsse_v0_0_1_schema.json", + "title": "DSSE v0.0.1 Schema", + "description": "Schema for DSSE envelopes", + "type": "object", + "properties": { + "proposedContent": { + "type": "object", + "properties": { + "envelope": { + "description": "DSSE envelope specified as a stringified JSON object", + "type": "string", + "writeOnly": true + }, + "verifiers": { + "description": "collection of all verification material (e.g. public keys or certificates) used to verify signatures over envelope's payload, specified as base64-encoded strings", + "type": "array", + "minItems": 1, + "items": { + "type": "string", + "format": "byte" + }, + "writeOnly": true + } + }, + "writeOnly": true, + "required": [ "envelope", "verifiers" ] + }, + "signatures": { + "description": "extracted collection of all signatures of the envelope's payload; elements will be sorted by lexicographical order of the base64 encoded signature strings", + "type": "array", + "minItems": 1, + "items": { + "description": "a signature of the envelope's payload along with the verification material for the signature", + "type": "object", + "properties": { + "signature": { + "description": "base64 encoded signature of the payload", + "type": "string", + "pattern": "^(?:[A-Za-z0-9+\\/]{4})*(?:[A-Za-z0-9+\\/]{2}==|[A-Za-z0-9+\\/]{3}=|[A-Za-z0-9+\\/]{4})$" + }, + "verifier": { + "description": "verification material that was used to verify the corresponding signature, specified as a base64 encoded string", + "type": "string", + "format": "byte" + } + }, + "required": [ "signature", "verifier" ] + }, + "readOnly": true + }, + "envelopeHash": { + "description": "Specifies the hash algorithm and value encompassing the entire envelope sent to Rekor", + "type": "object", + "properties": { + "algorithm": { + "description": "The hashing function used to compute the hash value", + "type": "string", + "enum": [ "sha256" ] + }, + "value": { + "description": "The value of the computed digest over the entire envelope", + "type": "string" + } + }, + "required": [ "algorithm", "value" ], + "readOnly": true + }, + "payloadHash": { + "description": "Specifies the hash algorithm and value covering the payload within the DSSE envelope", + "type": "object", + "properties": { + "algorithm": { + "description": "The hashing function used to compute the hash value", + "type": "string", + "enum": [ "sha256" ] + }, + "value": { + "description": "The value of the computed digest over the payload within the envelope", + "type": "string" + } + }, + "required": [ "algorithm", "value" ], + "readOnly": true + } + }, + "oneOf": [ + { + "required": [ "proposedContent" ] + }, + { + "required": [ "signatures", "envelopeHash", "payloadHash" ] + } + ] +} diff --git a/pkg/types/dsse/v0.0.1/e2e_test.go b/pkg/types/dsse/v0.0.1/e2e_test.go new file mode 100644 index 000000000..aa67775a9 --- /dev/null +++ b/pkg/types/dsse/v0.0.1/e2e_test.go @@ -0,0 +1,723 @@ +// +// 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. + +//go:build e2e + +package dsse + +import ( + "bytes" + "context" + "crypto" + "crypto/ecdsa" + "crypto/rsa" + "crypto/sha256" + "crypto/x509" + "encoding/base64" + "encoding/hex" + "encoding/json" + "encoding/pem" + "fmt" + "os" + "path/filepath" + "strings" + "testing" + "time" + + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/in-toto/in-toto-golang/in_toto" + "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/common" + slsa "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.2" + "github.com/secure-systems-lab/go-securesystemslib/dsse" + "github.com/sigstore/rekor/pkg/client" + "github.com/sigstore/rekor/pkg/generated/client/entries" + "github.com/sigstore/rekor/pkg/generated/models" + "github.com/sigstore/rekor/pkg/types" + "github.com/sigstore/sigstore/pkg/signature" + + sigx509 "github.com/sigstore/rekor/pkg/pki/x509" + "github.com/sigstore/rekor/pkg/util" +) + +func rekorServer() string { + if s := os.Getenv("REKOR_SERVER"); s != "" { + return s + } + return "http://localhost:3000" +} + +func GenerateSingleSignedDSSE(t *testing.T) ([]byte, []byte) { + t.Helper() + + // Get some random data so it's unique each run + d := util.RandomData(t, 10) + id := base64.StdEncoding.EncodeToString(d) + + it := in_toto.ProvenanceStatement{ + StatementHeader: in_toto.StatementHeader{ + Type: in_toto.StatementInTotoV01, + PredicateType: slsa.PredicateSLSAProvenance, + Subject: []in_toto.Subject{ + { + Name: "foobar", + Digest: common.DigestSet{ + "foo": "bar", + }, + }, + }, + }, + Predicate: slsa.ProvenancePredicate{ + Builder: common.ProvenanceBuilder{ + ID: "foo" + id, + }, + }, + } + + b, err := json.Marshal(it) + if err != nil { + t.Fatal(err) + } + + pb, _ := pem.Decode([]byte(sigx509.ECDSAPriv)) + priv, err := x509.ParsePKCS8PrivateKey(pb.Bytes) + if err != nil { + t.Fatal(err) + } + + s, err := signature.LoadECDSASigner(priv.(*ecdsa.PrivateKey), crypto.SHA256) + if err != nil { + t.Fatal(err) + } + + signer, err := dsse.NewEnvelopeSigner(&sigx509.Verifier{ + S: s, + }) + if err != nil { + t.Fatal(err) + } + + env, err := signer.SignPayload(context.Background(), in_toto.PayloadType, b) + if err != nil { + t.Fatal(err) + } + + eb, err := json.Marshal(env) + if err != nil { + t.Fatal(err) + } + + return b, eb +} + +func GenerateDoubleSignedDSSE(t *testing.T) ([]byte, []byte) { + t.Helper() + + // Get some random data so it's unique each run + d := util.RandomData(t, 10) + id := base64.StdEncoding.EncodeToString(d) + + it := in_toto.ProvenanceStatement{ + StatementHeader: in_toto.StatementHeader{ + Type: in_toto.StatementInTotoV01, + PredicateType: slsa.PredicateSLSAProvenance, + Subject: []in_toto.Subject{ + { + Name: "foobar", + Digest: common.DigestSet{ + "foo": "bar", + }, + }, + }, + }, + Predicate: slsa.ProvenancePredicate{ + Builder: common.ProvenanceBuilder{ + ID: "foo" + id, + }, + }, + } + + b, err := json.Marshal(it) + if err != nil { + t.Fatal(err) + } + + evps := []*sigx509.Verifier{} + + pb, _ := pem.Decode([]byte(sigx509.ECDSAPriv)) + priv, err := x509.ParsePKCS8PrivateKey(pb.Bytes) + if err != nil { + t.Fatal(err) + } + + signECDSA, err := signature.LoadECDSASigner(priv.(*ecdsa.PrivateKey), crypto.SHA256) + if err != nil { + t.Fatal(err) + } + + evps = append(evps, &sigx509.Verifier{ + S: signECDSA, + }) + + pbRSA, _ := pem.Decode([]byte(sigx509.RSAKey)) + rsaPriv, err := x509.ParsePKCS8PrivateKey(pbRSA.Bytes) + if err != nil { + t.Fatal(err) + } + + signRSA, err := signature.LoadRSAPKCS1v15Signer(rsaPriv.(*rsa.PrivateKey), crypto.SHA256) + if err != nil { + t.Fatal(err) + } + + evps = append(evps, &sigx509.Verifier{ + S: signRSA, + }) + + signer, err := dsse.NewMultiEnvelopeSigner(2, evps[0], evps[1]) + if err != nil { + t.Fatal(err) + } + + env, err := signer.SignPayload(context.Background(), in_toto.PayloadType, b) + if err != nil { + t.Fatal(err) + } + + eb, err := json.Marshal(env) + if err != nil { + t.Fatal(err) + } + + return b, eb +} + +func TestDsse(t *testing.T) { + td := t.TempDir() + attestationPath := filepath.Join(td, "attestation.json") + pubKeyPath := filepath.Join(td, "pub.pem") + + b, eb := GenerateSingleSignedDSSE(t) + + util.Write(t, string(eb), attestationPath) + util.Write(t, sigx509.ECDSAPub, pubKeyPath) + + out := util.RunCli(t, "upload", "--artifact", attestationPath, "--type", "dsse", "--public-key", pubKeyPath) + util.OutputContains(t, out, "Created entry at") + uuid := util.GetUUIDFromUploadOutput(t, out) + + out = util.RunCli(t, "get", "--uuid", uuid, "--format=json") + g := util.GetOut{} + if err := json.Unmarshal([]byte(out), &g); err != nil { + t.Fatal(err) + } + // The attestation should not be stored + + if len(g.Attestation) > 0 { + t.Fatal("unexpected attestation present in response") + } + + payloadHash := sha256.Sum256(b) + envelopeHash := sha256.Sum256(eb) + + dsseModel := &models.DSSEV001Schema{} + if err := types.DecodeEntry(g.Body.(map[string]interface{})["DSSEObj"], dsseModel); err != nil { + t.Errorf("could not convert body into dsse type: %v", err) + } + if dsseModel.PayloadHash == nil { + t.Errorf("could not find hash over payload %v", dsseModel) + } + recordedPayloadHash, err := hex.DecodeString(*dsseModel.PayloadHash.Value) + if err != nil { + t.Errorf("error converting payload hash to []byte: %v", err) + } + + if !bytes.Equal(payloadHash[:], recordedPayloadHash) { + t.Fatal(fmt.Errorf("payload hash %v doesnt match the payload we sent %v", hex.EncodeToString(payloadHash[:]), + *dsseModel.PayloadHash.Value)) + } + if dsseModel.EnvelopeHash == nil { + t.Errorf("could not find hash over entire envelope %v", dsseModel) + } + recordedEnvelopeHash, err := hex.DecodeString(*dsseModel.EnvelopeHash.Value) + if err != nil { + t.Errorf("error converting Envelope hash to []byte: %v", err) + } + + if !bytes.Equal(envelopeHash[:], recordedEnvelopeHash) { + t.Fatal(fmt.Errorf("envelope hash %v doesnt match the payload we sent %v", hex.EncodeToString(envelopeHash[:]), + *dsseModel.EnvelopeHash.Value)) + } + + if len(dsseModel.Signatures) != 1 { + t.Fatalf("expected one signatures but got %d instead", len(dsseModel.Signatures)) + } + + out = util.RunCli(t, "upload", "--artifact", attestationPath, "--type", "dsse", "--public-key", pubKeyPath) + util.OutputContains(t, out, "Entry already exists") +} +func TestDsseMultiSig(t *testing.T) { + td := t.TempDir() + attestationPath := filepath.Join(td, "attestation.json") + ecdsapubKeyPath := filepath.Join(td, "ecdsapub.pem") + rsapubKeyPath := filepath.Join(td, "rsapub.pem") + + b, eb := GenerateDoubleSignedDSSE(t) + + util.Write(t, string(eb), attestationPath) + util.Write(t, sigx509.ECDSAPub, ecdsapubKeyPath) + util.Write(t, sigx509.PubKey, rsapubKeyPath) + + out := util.RunCli(t, "upload", "--artifact", attestationPath, "--type", "dsse", "--public-key", ecdsapubKeyPath, "--public-key", rsapubKeyPath) + util.OutputContains(t, out, "Created entry at") + uuid := util.GetUUIDFromUploadOutput(t, out) + + out = util.RunCli(t, "get", "--uuid", uuid, "--format=json") + g := util.GetOut{} + if err := json.Unmarshal([]byte(out), &g); err != nil { + t.Fatal(err) + } + // The attestation should not be stored + + if len(g.Attestation) > 0 { + t.Fatal("unexpected attestation present in response") + } + + payloadHash := sha256.Sum256(b) + envelopeHash := sha256.Sum256(eb) + + dsseModel := &models.DSSEV001Schema{} + if err := types.DecodeEntry(g.Body.(map[string]interface{})["DSSEObj"], dsseModel); err != nil { + t.Errorf("could not convert body into dsse type: %v", err) + } + if dsseModel.PayloadHash == nil { + t.Errorf("could not find hash over payload %v", dsseModel) + } + recordedPayloadHash, err := hex.DecodeString(*dsseModel.PayloadHash.Value) + if err != nil { + t.Errorf("error converting payload hash to []byte: %v", err) + } + + if !bytes.Equal(payloadHash[:], recordedPayloadHash) { + t.Fatal(fmt.Errorf("payload hash %v doesnt match the payload we sent %v", hex.EncodeToString(payloadHash[:]), + *dsseModel.PayloadHash.Value)) + } + + if dsseModel.EnvelopeHash == nil { + t.Errorf("could not find hash over envelope %v", dsseModel) + } + recordedEnvelopeHash, err := hex.DecodeString(*dsseModel.EnvelopeHash.Value) + if err != nil { + t.Errorf("error converting envelope hash to []byte: %v", err) + } + + if !bytes.Equal(envelopeHash[:], recordedEnvelopeHash) { + t.Fatal(fmt.Errorf("envelope hash %v doesnt match the payload we sent %v", hex.EncodeToString(envelopeHash[:]), + *dsseModel.EnvelopeHash.Value)) + } + + if len(dsseModel.Signatures) != 2 { + t.Fatalf("expected two signatures but got %d instead", len(dsseModel.Signatures)) + } + + out = util.RunCli(t, "upload", "--artifact", attestationPath, "--type", "dsse", "--public-key", ecdsapubKeyPath, "--public-key", rsapubKeyPath) + util.OutputContains(t, out, "Entry already exists") +} + +func DecodeV001FromRekorResponse(t *testing.T, resp *entries.CreateLogEntryCreated) *V001Entry { + t.Helper() + + for _, e := range resp.Payload { + b, err := base64.StdEncoding.DecodeString(e.Body.(string)) + if err != nil { + t.Errorf("could not decode body into dsse type: %v", err) + } + + pe, err := models.UnmarshalProposedEntry(bytes.NewReader(b), runtime.JSONConsumer()) + if err != nil { + t.Errorf("could not unmarshal body into dsse type: %v", err) + } + eimpl, err := types.UnmarshalEntry(pe) + if err != nil { + t.Errorf("could not unmarshal body into dsse v0.0.1 type: %v", err) + } + return eimpl.(*V001Entry) + } + return nil +} + +// TestSendingCanonicalizedDSSE tests uploading a valid canonicalized entry. This should fail because the type requires +// the ProposedContent fields to be submitted on upload, and canonicalized entries will not have those fields persisted. +func TestSendingCanonicalizedDSSE(t *testing.T) { + b, eb := GenerateSingleSignedDSSE(t) + sha := sha256.New() + sha.Write(b) + payloadHashBytes := sha.Sum(nil) + payloadHashStr := hex.EncodeToString(payloadHashBytes) + sha.Reset() + sha.Write(eb) + envelopeHashBytes := sha.Sum(nil) + envelopeHashStr := hex.EncodeToString(envelopeHashBytes) + + ap := types.ArtifactProperties{ + ArtifactBytes: eb, + PublicKeyBytes: [][]byte{[]byte(sigx509.ECDSAPub)}, + } + + ei := NewEntry() + + entry, err := ei.CreateFromArtifactProperties(context.Background(), ap) + if err != nil { + t.Fatalf("error creating entry: %v", err) + } + + dsse_entry := entry.(*models.DSSE) + v001 := dsse_entry.Spec.(models.DSSEV001Schema) + v001.EnvelopeHash = &models.DSSEV001SchemaEnvelopeHash{ + Algorithm: swag.String("sha256"), + Value: swag.String(envelopeHashStr), + } + v001.PayloadHash = &models.DSSEV001SchemaPayloadHash{ + Algorithm: swag.String("sha256"), + Value: swag.String(payloadHashStr), + } + env := &dsse.Envelope{} + if err := json.Unmarshal([]byte(*v001.ProposedContent.Envelope), env); err != nil { + t.Fatalf("error extracting DSSE envelope") + } + pk := v001.ProposedContent.Verifiers[0] + v001.Signatures = []*models.DSSEV001SchemaSignaturesItems0{ + { + Signature: &env.Signatures[0].Sig, + Verifier: &pk, + }, + } + // erase proposed content and overwrite previous + v001.ProposedContent = nil + dsse_entry.Spec = v001 + + rc, err := client.GetRekorClient(rekorServer()) + if err != nil { + t.Errorf("error getting client: %v", err) + } + + params := &entries.CreateLogEntryParams{} + params.SetProposedEntry(dsse_entry) + params.SetContext(context.Background()) + params.SetTimeout(5 * time.Second) + + if _, err = rc.Entries.CreateLogEntry(params); err == nil { + t.Fatalf("expected error submitting canonicalized entry to rekor") + } + e, ok := err.(*entries.CreateLogEntryBadRequest) + if !ok { + t.Errorf("unexpected error returned from rekor: %v", err.Error()) + } + if !strings.Contains(e.Payload.Message, "missing proposed content") { + t.Errorf("expected error message to include 'missing proposed content': %v", e.Payload.Message) + } +} + +// TestSendingEntryWithClientComputedHashes tests uploading a valid entry with incorrect client-computed digests +// over the entire envelope and payload. The hashes should be computed server side, and the request should be rejected +func TestSendingEntryWithClientComputedHashes(t *testing.T) { + b, eb := GenerateSingleSignedDSSE(t) + sha := sha256.New() + sha.Write(b) + payloadHashBytes := sha.Sum(nil) + payloadHashStr := hex.EncodeToString(payloadHashBytes) + t.Logf(payloadHashStr) + sha.Reset() + sha.Write(eb) + envelopeHashBytes := sha.Sum(nil) + envelopeHashStr := hex.EncodeToString(envelopeHashBytes) + t.Logf(envelopeHashStr) + + ap := types.ArtifactProperties{ + ArtifactBytes: eb, + PublicKeyBytes: [][]byte{[]byte(sigx509.ECDSAPub)}, + } + + ei := NewEntry() + + entry, err := ei.CreateFromArtifactProperties(context.Background(), ap) + if err != nil { + t.Fatalf("error creating entry: %v", err) + } + + dsse_entry := entry.(*models.DSSE) + v001 := dsse_entry.Spec.(models.DSSEV001Schema) + v001.EnvelopeHash = &models.DSSEV001SchemaEnvelopeHash{ + Algorithm: swag.String("sha256"), + Value: swag.String("8810ad581e59f2bc3928b261707a71308f7e139eb04820366dc4d5c18d980225"), + } + v001.PayloadHash = &models.DSSEV001SchemaPayloadHash{ + Algorithm: swag.String("sha256"), + Value: swag.String("8810ad581e59f2bc3928b261707a71308f7e139eb04820366dc4d5c18d980225"), + } + dsse_entry.Spec = v001 + + rc, err := client.GetRekorClient(rekorServer()) + if err != nil { + t.Errorf("error getting client: %v", err) + } + + params := &entries.CreateLogEntryParams{} + params.SetProposedEntry(dsse_entry) + params.SetContext(context.Background()) + params.SetTimeout(5 * time.Second) + + _, err = rc.Entries.CreateLogEntry(params) + if err == nil { + t.Error("expected error uploading bad entry to Rekor") + } + + e, ok := err.(*entries.CreateLogEntryBadRequest) + if !ok { + t.Errorf("unexpected error returned from rekor: %v", err.Error()) + } + if !strings.Contains(e.Payload.Message, "either proposedContent or envelopeHash, payloadHash, and signatures must be present but not both") { + t.Errorf("unexpected error message returned: %v", e.Payload.Message) + } +} + +// TestMismatchedKeySingleSigner tests uploading a valid entry with the incorrect public key; this should be rejected by Rekor +func TestMismatchedKeySingleSigner(t *testing.T) { + _, eb := GenerateSingleSignedDSSE(t) + + ap := types.ArtifactProperties{ + ArtifactBytes: eb, + PublicKeyBytes: [][]byte{[]byte(sigx509.ECDSAPub)}, // this is the matching key, we will swap it out momentarily + } + + ei := NewEntry() + + entry, err := ei.CreateFromArtifactProperties(context.Background(), ap) + if err != nil { + t.Fatalf("error creating entry: %v", err) + } + + // swap out good public key for mismatched one + dsse_entry := entry.(*models.DSSE) + v001 := dsse_entry.Spec.(models.DSSEV001Schema) + v001.ProposedContent.Verifiers[0] = strfmt.Base64(sigx509.RSACert) + dsse_entry.Spec = v001 + + rc, err := client.GetRekorClient(rekorServer()) + if err != nil { + t.Errorf("error getting client: %v", err) + } + + params := &entries.CreateLogEntryParams{} + params.SetProposedEntry(dsse_entry) + params.SetContext(context.Background()) + params.SetTimeout(5 * time.Second) + + if _, err = rc.Entries.CreateLogEntry(params); err == nil { + t.Fatalf("expected error submitting canonicalized entry to rekor") + } + e, ok := err.(*entries.CreateLogEntryBadRequest) + if !ok { + t.Errorf("unexpected error returned from rekor: %v", err.Error()) + } + if !strings.Contains(e.Payload.Message, "could not verify envelope") { + t.Errorf("expected error message to include 'could not verify envelope': %v", e.Payload.Message) + } +} + +// TestNoSignature tests sending a valid JSON object as the DSSE envelope, but one that omits the +// signature. This should not be accepted by Rekor. +func TestNoSignature(t *testing.T) { + _, eb := GenerateSingleSignedDSSE(t) + + ap := types.ArtifactProperties{ + ArtifactBytes: eb, + PublicKeyBytes: [][]byte{[]byte(sigx509.ECDSAPub)}, //, []byte(sigx509.ECDSAPub)}, + } + + ei := NewEntry() + + entry, err := ei.CreateFromArtifactProperties(context.Background(), ap) + if err != nil { + t.Fatalf("error creating entry: %v", err) + } + + dsse_entry := entry.(*models.DSSE) + v001 := dsse_entry.Spec.(models.DSSEV001Schema) + + env := &dsse.Envelope{} + if err := json.Unmarshal([]byte(*v001.ProposedContent.Envelope), env); err != nil { + t.Fatalf("error extracting DSSE envelope") + } + + // remove signature + env.Signatures = []dsse.Signature{} + + noSigEnv, err := json.Marshal(env) + if err != nil { + t.Fatalf("error marshalling sorted DSSE envelope") + } + + v001.ProposedContent.Envelope = swag.String(string(noSigEnv)) + dsse_entry.Spec = v001 + + rc, err := client.GetRekorClient(rekorServer()) + if err != nil { + t.Errorf("error getting client: %v", err) + } + + params := &entries.CreateLogEntryParams{} + params.SetProposedEntry(dsse_entry) + params.SetContext(context.Background()) + params.SetTimeout(5 * time.Second) + + if _, err := rc.Entries.CreateLogEntry(params); err == nil { + t.Errorf("expected error to be returned from rekor given lack of signature in envelope") + } +} + +// TestTwoPublicKeysOneSignature tests uploading a valid entry with the both the correct and an incorrect public key; +// this should be accepted by Rekor, but with only the key that successfully verifies the signature. +func TestTwoPublicKeysOneSignature(t *testing.T) { + _, eb := GenerateSingleSignedDSSE(t) + + ap := types.ArtifactProperties{ + ArtifactBytes: eb, + PublicKeyBytes: [][]byte{[]byte(sigx509.ECDSAPub), []byte(sigx509.ECDSAPub)}, + } + + ei := NewEntry() + + entry, err := ei.CreateFromArtifactProperties(context.Background(), ap) + if err != nil { + t.Fatalf("error creating entry: %v", err) + } + + rc, err := client.GetRekorClient(rekorServer()) + if err != nil { + t.Errorf("error getting client: %v", err) + } + + params := &entries.CreateLogEntryParams{} + params.SetProposedEntry(entry) + params.SetContext(context.Background()) + params.SetTimeout(5 * time.Second) + + resp, err := rc.Entries.CreateLogEntry(params) + if err != nil { + t.Errorf("unexpected error returned from rekor: %v", err.Error()) + } + + v001 := DecodeV001FromRekorResponse(t, resp) + + if len(v001.DSSEObj.Signatures) != 1 { + t.Errorf("incorrect number of signatures returned in response: expected 1, got %d", len(v001.DSSEObj.Signatures)) + } +} + +// TestTwoPublicKeysTwoSignatures tests uploading a valid entry with the both the correct and an incorrect public key; +// this should be rejected by Rekor, as both signatures were not successfully verified +func TestTwoPublicKeysTwoSignatures(t *testing.T) { + _, eb := GenerateDoubleSignedDSSE(t) + + ap := types.ArtifactProperties{ + ArtifactBytes: eb, + PublicKeyBytes: [][]byte{[]byte(sigx509.ECDSAPub), []byte(sigx509.RSACert)}, // missing RSA pub key + } + + ei := NewEntry() + + entry, err := ei.CreateFromArtifactProperties(context.Background(), ap) + if err != nil { + t.Fatalf("error creating entry: %v", err) + } + + // swap out one of the good public keys for a mismatched one + dsse_entry := entry.(*models.DSSE) + v001 := dsse_entry.Spec.(models.DSSEV001Schema) + v001.ProposedContent.Verifiers[0] = strfmt.Base64(sigx509.RSACert) + v001.ProposedContent.Verifiers[1] = strfmt.Base64(sigx509.RSACert) + dsse_entry.Spec = v001 + + rc, err := client.GetRekorClient(rekorServer()) + if err != nil { + t.Errorf("error getting client: %v", err) + } + + params := &entries.CreateLogEntryParams{} + params.SetProposedEntry(dsse_entry) + params.SetContext(context.Background()) + params.SetTimeout(5 * time.Second) + + if _, err := rc.Entries.CreateLogEntry(params); err == nil { + t.Errorf("expected error to be returned from rekor given incorrect public keys provided") + } +} + +// TestThreePublicKeysTwoSignatures tests uploading a valid entry with the both the correct keys and an additional +// incorrect public key; this should be accepted by Rekor, but with only the two keys that successfully verified the signatures +func TestThreePublicKeysTwoSignatures(t *testing.T) { + _, eb := GenerateDoubleSignedDSSE(t) + + ap := types.ArtifactProperties{ + ArtifactBytes: eb, + PublicKeyBytes: [][]byte{[]byte(sigx509.ECDSAPub), []byte(sigx509.ECDSAPub), []byte(sigx509.RSACert)}, + } + + ei := NewEntry() + + entry, err := ei.CreateFromArtifactProperties(context.Background(), ap) + if err != nil { + t.Fatalf("error creating entry: %v", err) + } + + rc, err := client.GetRekorClient(rekorServer()) + if err != nil { + t.Errorf("error getting client: %v", err) + } + + params := &entries.CreateLogEntryParams{} + params.SetProposedEntry(entry) + params.SetContext(context.Background()) + params.SetTimeout(5 * time.Second) + + resp, err := rc.Entries.CreateLogEntry(params) + if err != nil { + t.Errorf("unexpected error returned from rekor: %v", err.Error()) + } + + for _, k := range resp.Payload { + b, err := base64.StdEncoding.DecodeString(k.Body.(string)) + if err != nil { + t.Errorf("unexpected error returned from rekor: %v", err.Error()) + } + + pe, err := models.UnmarshalProposedEntry(bytes.NewReader(b), runtime.JSONConsumer()) + if err != nil { + t.Errorf("unexpected error returned from rekor: %v", err.Error()) + } + eimpl, err := types.UnmarshalEntry(pe) + if err != nil { + t.Errorf("unexpected error returned from rekor: %v", err.Error()) + } + + dsse_eimpl := eimpl.(*V001Entry) + + if len(dsse_eimpl.DSSEObj.Signatures) != 2 { + t.Errorf("incorrect number of signatures returned in response: expected 2, got %d", len(dsse_eimpl.DSSEObj.Signatures)) + } + } +} diff --git a/pkg/types/dsse/v0.0.1/entry.go b/pkg/types/dsse/v0.0.1/entry.go new file mode 100644 index 000000000..ba41742b9 --- /dev/null +++ b/pkg/types/dsse/v0.0.1/entry.go @@ -0,0 +1,434 @@ +// +// 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. + +package dsse + +import ( + "bytes" + "context" + "crypto" + "crypto/sha256" + "encoding/hex" + "encoding/json" + "errors" + "fmt" + "os" + "path/filepath" + "sort" + "strings" + + "github.com/in-toto/in-toto-golang/in_toto" + "github.com/secure-systems-lab/go-securesystemslib/dsse" + + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + + "github.com/sigstore/rekor/pkg/generated/models" + "github.com/sigstore/rekor/pkg/log" + "github.com/sigstore/rekor/pkg/pki" + "github.com/sigstore/rekor/pkg/pki/x509" + "github.com/sigstore/rekor/pkg/types" + dsseType "github.com/sigstore/rekor/pkg/types/dsse" + "github.com/sigstore/sigstore/pkg/signature" + sigdsse "github.com/sigstore/sigstore/pkg/signature/dsse" +) + +const ( + APIVERSION = "0.0.1" +) + +func init() { + if err := dsseType.VersionMap.SetEntryFactory(APIVERSION, NewEntry); err != nil { + log.Logger.Panic(err) + } +} + +type V001Entry struct { + DSSEObj models.DSSEV001Schema + env *dsse.Envelope +} + +func (v V001Entry) APIVersion() string { + return APIVERSION +} + +func NewEntry() types.EntryImpl { + return &V001Entry{} +} + +// IndexKeys computes the list of keys that should map back to this entry. +// It should *never* reference v.DSSEObj.ProposedContent as those values would only +// be present at the time of insertion +func (v V001Entry) IndexKeys() ([]string, error) { + var result []string + + for _, sig := range v.DSSEObj.Signatures { + if sig == nil || sig.Verifier == nil { + return result, errors.New("missing or malformed public key") + } + keyObj, err := x509.NewPublicKey(bytes.NewReader(*sig.Verifier)) + if err != nil { + return result, err + } + + canonKey, err := keyObj.CanonicalValue() + if err != nil { + return result, fmt.Errorf("could not canonicalize key: %w", err) + } + + keyHash := sha256.Sum256(canonKey) + result = append(result, "sha256:"+hex.EncodeToString(keyHash[:])) + + result = append(result, keyObj.Subjects()...) + } + + if v.DSSEObj.PayloadHash != nil { + payloadHashKey := strings.ToLower(fmt.Sprintf("%s:%s", *v.DSSEObj.PayloadHash.Algorithm, *v.DSSEObj.PayloadHash.Value)) + result = append(result, payloadHashKey) + } + + if v.DSSEObj.EnvelopeHash != nil { + envelopeHashKey := strings.ToLower(fmt.Sprintf("%s:%s", *v.DSSEObj.EnvelopeHash.Algorithm, *v.DSSEObj.EnvelopeHash.Value)) + result = append(result, envelopeHashKey) + } + + if v.env == nil { + log.Logger.Info("DSSEObj content or DSSE envelope is nil, returning partial set of keys") + return result, nil + } + + switch v.env.PayloadType { + case in_toto.PayloadType: + + if v.env.Payload == "" { + log.Logger.Info("DSSEObj DSSE payload is empty") + return result, nil + } + decodedPayload, err := v.env.DecodeB64Payload() + if err != nil { + return result, fmt.Errorf("could not decode envelope payload: %w", err) + } + statement, err := parseStatement(decodedPayload) + if err != nil { + return result, err + } + for _, s := range statement.Subject { + for alg, ds := range s.Digest { + result = append(result, alg+":"+ds) + } + } + // Not all in-toto statements will contain a SLSA provenance predicate. + // See https://github.com/in-toto/attestation/blob/main/spec/README.md#predicate + // for other predicates. + if predicate, err := parseSlsaPredicate(decodedPayload); err == nil { + if predicate.Predicate.Materials != nil { + for _, s := range predicate.Predicate.Materials { + for alg, ds := range s.Digest { + result = append(result, alg+":"+ds) + } + } + } + } + default: + log.Logger.Infof("Unknown DSSE envelope payloadType: %s", v.env.PayloadType) + } + return result, nil +} + +func parseStatement(p []byte) (*in_toto.Statement, error) { + ps := in_toto.Statement{} + if err := json.Unmarshal(p, &ps); err != nil { + return nil, err + } + return &ps, nil +} + +func parseSlsaPredicate(p []byte) (*in_toto.ProvenanceStatement, error) { + predicate := in_toto.ProvenanceStatement{} + if err := json.Unmarshal(p, &predicate); err != nil { + return nil, err + } + return &predicate, nil +} + +func (v *V001Entry) Unmarshal(pe models.ProposedEntry) error { + it, ok := pe.(*models.DSSE) + if !ok { + return errors.New("cannot unmarshal non DSSE v0.0.1 type") + } + + dsseObj := &models.DSSEV001Schema{} + + if err := types.DecodeEntry(it.Spec, dsseObj); err != nil { + return err + } + + // field validation + if err := dsseObj.Validate(strfmt.Default); err != nil { + return err + } + + // either we have just proposed content or the canonicalized fields + if dsseObj.ProposedContent == nil { + // then we need canonicalized fields, and all must be present (if present, they would have been validated in the above call to Validate()) + if dsseObj.EnvelopeHash == nil || dsseObj.PayloadHash == nil || len(dsseObj.Signatures) == 0 { + return errors.New("either proposedContent or envelopeHash, payloadHash, and signatures must be present") + } + v.DSSEObj = *dsseObj + return nil + } + // if we're here, then we're trying to propose a new entry so we check to ensure client's aren't setting server-side computed fields + if dsseObj.EnvelopeHash != nil || dsseObj.PayloadHash != nil || len(dsseObj.Signatures) != 0 { + return errors.New("either proposedContent or envelopeHash, payloadHash, and signatures must be present but not both") + } + + env := &dsse.Envelope{} + if err := json.Unmarshal([]byte(*dsseObj.ProposedContent.Envelope), env); err != nil { + return err + } + + if len(env.Signatures) == 0 { + return errors.New("DSSE envelope must contain 1 or more signatures") + } + + allPubKeyBytes := make([][]byte, 0) + for _, publicKey := range dsseObj.ProposedContent.Verifiers { + if publicKey == nil { + return errors.New("an invalid null verifier was provided in ProposedContent") + } + + allPubKeyBytes = append(allPubKeyBytes, publicKey) + } + + sigToKeyMap, err := verifyEnvelope(allPubKeyBytes, env) + if err != nil { + return err + } + + // we need to ensure we canonicalize the ordering of signatures + sortedSigs := make([]string, 0, len(sigToKeyMap)) + for sig := range sigToKeyMap { + sortedSigs = append(sortedSigs, sig) + } + sort.Strings(sortedSigs) + + for i, sig := range sortedSigs { + key := sigToKeyMap[sig] + canonicalizedKey, err := key.CanonicalValue() + if err != nil { + return err + } + b64CanonicalizedKey := strfmt.Base64(canonicalizedKey) + + dsseObj.Signatures = append(dsseObj.Signatures, &models.DSSEV001SchemaSignaturesItems0{ + Signature: &sortedSigs[i], + Verifier: &b64CanonicalizedKey, + }) + } + + decodedPayload, err := env.DecodeB64Payload() + if err != nil { + // this shouldn't happen because failure would have occurred in verifyEnvelope call above + return err + } + + payloadHash := sha256.Sum256(decodedPayload) + dsseObj.PayloadHash = &models.DSSEV001SchemaPayloadHash{ + Algorithm: swag.String(models.DSSEV001SchemaPayloadHashAlgorithmSha256), + Value: swag.String(hex.EncodeToString(payloadHash[:])), + } + + envelopeHash := sha256.Sum256([]byte(*dsseObj.ProposedContent.Envelope)) + dsseObj.EnvelopeHash = &models.DSSEV001SchemaEnvelopeHash{ + Algorithm: swag.String(models.DSSEV001SchemaEnvelopeHashAlgorithmSha256), + Value: swag.String(hex.EncodeToString(envelopeHash[:])), + } + + // we've gotten through all processing without error, now update the object we're unmarshalling into + v.DSSEObj = *dsseObj + v.env = env + + return nil +} + +// Canonicalize returns a JSON representation of the entry to be persisted into the log. This +// will be further canonicalized by JSON Canonicalization Scheme (JCS) before being written. +// +// This function should not use v.DSSEObj.ProposedContent fields as they are client provided and +// should not be trusted; the other fields at the top level are only set server side. +func (v *V001Entry) Canonicalize(_ context.Context) ([]byte, error) { + canonicalEntry := models.DSSEV001Schema{ + Signatures: v.DSSEObj.Signatures, + EnvelopeHash: v.DSSEObj.EnvelopeHash, + PayloadHash: v.DSSEObj.PayloadHash, + ProposedContent: nil, // this is explicitly done as we don't want to canonicalize the envelope + } + + sort.Slice(canonicalEntry.Signatures, func(i, j int) bool { + return *canonicalEntry.Signatures[i].Signature < *canonicalEntry.Signatures[j].Signature + }) + + itObj := models.DSSE{} + itObj.APIVersion = swag.String(APIVERSION) + itObj.Spec = &canonicalEntry + + return json.Marshal(&itObj) +} + +// AttestationKey and AttestationKeyValue are not implemented so the envelopes will not be persisted in Rekor + +func (v V001Entry) CreateFromArtifactProperties(_ context.Context, props types.ArtifactProperties) (models.ProposedEntry, error) { + returnVal := models.DSSE{} + re := V001Entry{ + DSSEObj: models.DSSEV001Schema{ + ProposedContent: &models.DSSEV001SchemaProposedContent{}, + }, + } + var err error + artifactBytes := props.ArtifactBytes + if artifactBytes == nil { + if props.ArtifactPath == nil { + return nil, errors.New("path to artifact file must be specified") + } + if props.ArtifactPath.IsAbs() { + return nil, errors.New("dsse envelopes cannot be fetched over HTTP(S)") + } + artifactBytes, err = os.ReadFile(filepath.Clean(props.ArtifactPath.Path)) + if err != nil { + return nil, err + } + } + + env := &dsse.Envelope{} + if err := json.Unmarshal(artifactBytes, env); err != nil { + return nil, fmt.Errorf("payload must be a valid DSSE envelope: %w", err) + } + + allPubKeyBytes := make([][]byte, 0) + if len(props.PublicKeyBytes) > 0 { + allPubKeyBytes = append(allPubKeyBytes, props.PublicKeyBytes...) + } + + if len(props.PublicKeyPaths) > 0 { + for _, path := range props.PublicKeyPaths { + if path.IsAbs() { + return nil, errors.New("dsse public keys cannot be fetched over HTTP(S)") + } + + publicKeyBytes, err := os.ReadFile(filepath.Clean(path.Path)) + if err != nil { + return nil, fmt.Errorf("error reading public key file: %w", err) + } + + allPubKeyBytes = append(allPubKeyBytes, publicKeyBytes) + } + } + + keysBySig, err := verifyEnvelope(allPubKeyBytes, env) + if err != nil { + return nil, err + } + for _, key := range keysBySig { + canonicalKey, err := key.CanonicalValue() + if err != nil { + return nil, err + } + re.DSSEObj.ProposedContent.Verifiers = append(re.DSSEObj.ProposedContent.Verifiers, strfmt.Base64(canonicalKey)) + } + re.DSSEObj.ProposedContent.Envelope = swag.String(string(artifactBytes)) + + returnVal.Spec = re.DSSEObj + returnVal.APIVersion = swag.String(re.APIVersion()) + + return &returnVal, nil +} + +// verifyEnvelope takes in an array of possible key bytes and attempts to parse them as x509 public keys. +// it then uses these to verify the envelope and makes sure that every signature on the envelope is verified. +// it returns a map of verifiers indexed by the signature the verifier corresponds to. +func verifyEnvelope(allPubKeyBytes [][]byte, env *dsse.Envelope) (map[string]*x509.PublicKey, error) { + // generate a fake id for these keys so we can get back to the key bytes and match them to their corresponding signature + verifierBySig := make(map[string]*x509.PublicKey) + allSigs := make(map[string]struct{}) + for _, sig := range env.Signatures { + allSigs[sig.Sig] = struct{}{} + } + + for _, pubKeyBytes := range allPubKeyBytes { + if len(allSigs) == 0 { + break // if all signatures have been verified, do not attempt anymore + } + key, err := x509.NewPublicKey(bytes.NewReader(pubKeyBytes)) + if err != nil { + return nil, fmt.Errorf("could not parse public key as x509: %w", err) + } + + vfr, err := signature.LoadVerifier(key.CryptoPubKey(), crypto.SHA256) + if err != nil { + return nil, fmt.Errorf("could not load verifier: %w", err) + } + + dsseVfr, err := dsse.NewEnvelopeVerifier(&sigdsse.VerifierAdapter{SignatureVerifier: vfr}) + if err != nil { + return nil, fmt.Errorf("could not use public key as a dsse verifier: %w", err) + } + + accepted, err := dsseVfr.Verify(context.Background(), env) + if err != nil { + return nil, fmt.Errorf("could not verify envelope: %w", err) + } + + for _, accept := range accepted { + delete(allSigs, accept.Sig.Sig) + verifierBySig[accept.Sig.Sig] = key + } + } + + if len(allSigs) > 0 { + return nil, errors.New("all signatures must have a key that verifies it") + } + + return verifierBySig, nil +} + +func (v V001Entry) Verifiers() ([]pki.PublicKey, error) { + if len(v.DSSEObj.Signatures) == 0 { + return nil, errors.New("dsse v0.0.1 entry not initialized") + } + + var keys []pki.PublicKey + for _, s := range v.DSSEObj.Signatures { + key, err := x509.NewPublicKey(bytes.NewReader(*s.Verifier)) + if err != nil { + return nil, err + } + keys = append(keys, key) + } + return keys, nil +} + +func (v V001Entry) Insertable() (bool, error) { + if v.DSSEObj.ProposedContent == nil { + return false, errors.New("missing proposed content") + } + if v.DSSEObj.ProposedContent.Envelope == nil || len(*v.DSSEObj.ProposedContent.Envelope) == 0 { + return false, errors.New("missing proposed DSSE envelope") + } + if len(v.DSSEObj.ProposedContent.Verifiers) == 0 { + return false, errors.New("missing proposed verifiers") + } + + return true, nil +} diff --git a/pkg/types/dsse/v0.0.1/entry_test.go b/pkg/types/dsse/v0.0.1/entry_test.go new file mode 100644 index 000000000..e59e46fd5 --- /dev/null +++ b/pkg/types/dsse/v0.0.1/entry_test.go @@ -0,0 +1,523 @@ +// +// 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. + +package dsse + +import ( + "bytes" + "context" + "crypto" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/sha256" + "crypto/x509" + "encoding/base64" + "encoding/hex" + "encoding/json" + "encoding/pem" + "fmt" + "math/big" + "reflect" + "sort" + "strings" + "testing" + + "github.com/go-openapi/runtime" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + "github.com/in-toto/in-toto-golang/in_toto" + slsaCommon "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/common" + slsa "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.2" + "github.com/secure-systems-lab/go-securesystemslib/dsse" + "github.com/sigstore/rekor/pkg/generated/models" + "github.com/sigstore/rekor/pkg/types" + "github.com/sigstore/sigstore/pkg/signature" + sigdsse "github.com/sigstore/sigstore/pkg/signature/dsse" + "go.uber.org/goleak" +) + +func TestMain(m *testing.M) { + goleak.VerifyTestMain(m) +} + +func TestNewEntryReturnType(t *testing.T) { + entry := NewEntry() + if reflect.TypeOf(entry) != reflect.ValueOf(&V001Entry{}).Type() { + t.Errorf("invalid type returned from NewEntry: %T", entry) + } +} + +func envelope(t *testing.T, k *ecdsa.PrivateKey, payload []byte) *dsse.Envelope { + + s, err := signature.LoadECDSASigner(k, crypto.SHA256) + if err != nil { + t.Fatal(err) + } + signer, err := dsse.NewEnvelopeSigner(&sigdsse.SignerAdapter{ + SignatureSigner: s, + }) + if err != nil { + t.Fatal(err) + } + dsseEnv, err := signer.SignPayload(context.Background(), "application/vnd.in-toto+json", payload) + if err != nil { + t.Fatal(err) + } + + return dsseEnv +} + +func multiSignEnvelope(t *testing.T, k []*ecdsa.PrivateKey, payload []byte) *dsse.Envelope { + evps := []*sigdsse.SignerAdapter{} + for _, key := range k { + s, err := signature.LoadECDSASigner(key, crypto.SHA256) + if err != nil { + t.Fatal(err) + } + evps = append(evps, &sigdsse.SignerAdapter{ + SignatureSigner: s, + }) + } + + signer, err := dsse.NewMultiEnvelopeSigner(2, evps[0], evps[1]) + if err != nil { + t.Fatal(err) + } + dsseEnv, err := signer.SignPayload(context.Background(), in_toto.PayloadType, payload) + if err != nil { + t.Fatal(err) + } + + return dsseEnv +} + +func createRekorEnvelope(dsseEnv *dsse.Envelope, pub [][]byte) *models.DSSEV001SchemaProposedContent { + + envelopeBytes, _ := json.Marshal(dsseEnv) + proposedContent := &models.DSSEV001SchemaProposedContent{ + Envelope: swag.String(string(envelopeBytes)), + } + for _, key := range pub { + proposedContent.Verifiers = append(proposedContent.Verifiers, strfmt.Base64(key)) + } + return proposedContent +} + +func TestV001Entry_Unmarshal(t *testing.T) { + key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + t.Fatal(err) + } + der, err := x509.MarshalPKIXPublicKey(&key.PublicKey) + if err != nil { + t.Fatal(err) + } + pub := pem.EncodeToMemory(&pem.Block{ + Bytes: der, + Type: "PUBLIC KEY", + }) + + priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + t.Fatal(err) + } + + ca := &x509.Certificate{ + SerialNumber: big.NewInt(1), + } + caBytes, err := x509.CreateCertificate(rand.Reader, ca, ca, &priv.PublicKey, priv) + if err != nil { + t.Fatal(err) + } + pemBytes := pem.EncodeToMemory(&pem.Block{ + Type: "CERTIFICATE", + Bytes: caBytes, + }) + + invalid := dsse.Envelope{ + Payload: "hello", + Signatures: []dsse.Signature{ + { + Sig: string(strfmt.Base64("foobar")), + }, + }, + } + + validEnv := envelope(t, key, []byte("payload")) + validEnvBytes, _ := json.Marshal(validEnv) + + validPayload := "hellothispayloadisvalid" + + tests := []struct { + env *dsse.Envelope + name string + it *models.DSSEV001Schema + wantErr bool + }{ + { + name: "empty", + it: &models.DSSEV001Schema{}, + wantErr: true, + }, + { + name: "missing envelope", + it: &models.DSSEV001Schema{ + ProposedContent: &models.DSSEV001SchemaProposedContent{}, + }, + wantErr: true, + }, + { + env: envelope(t, key, []byte(validPayload)), + name: "valid", + it: &models.DSSEV001Schema{ + ProposedContent: createRekorEnvelope(envelope(t, key, []byte(validPayload)), [][]byte{pub}), + }, + wantErr: false, + }, + { + env: envelope(t, priv, []byte(validPayload)), + name: "cert", + it: &models.DSSEV001Schema{ + ProposedContent: createRekorEnvelope(envelope(t, priv, []byte(validPayload)), [][]byte{pemBytes}), + }, + wantErr: false, + }, + { + env: &invalid, + name: "invalid", + it: &models.DSSEV001Schema{ + ProposedContent: createRekorEnvelope(&invalid, [][]byte{pub}), + }, + wantErr: true, + }, + { + env: envelope(t, key, []byte(validPayload)), + name: "invalid key", + it: &models.DSSEV001Schema{ + ProposedContent: createRekorEnvelope(envelope(t, key, []byte(validPayload)), [][]byte{[]byte("notavalidkey")}), + }, + wantErr: true, + }, + { + env: multiSignEnvelope(t, []*ecdsa.PrivateKey{key, priv}, []byte(validPayload)), + name: "multi-key", + it: &models.DSSEV001Schema{ + ProposedContent: createRekorEnvelope(multiSignEnvelope(t, []*ecdsa.PrivateKey{key, priv}, []byte(validPayload)), [][]byte{pub, pemBytes}), + }, + wantErr: false, + }, + { + env: validEnv, + name: "null verifier in array", + it: &models.DSSEV001Schema{ + ProposedContent: &models.DSSEV001SchemaProposedContent{ + Envelope: swag.String(string(validEnvBytes)), + Verifiers: []strfmt.Base64{pub, nil}, + }, + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + v := &V001Entry{} + + it := &models.DSSE{ + Spec: tt.it, + } + + var uv = func() error { + if err := v.Unmarshal(it); err != nil { + return err + } + + if !tt.wantErr { + if ok, err := v.Insertable(); !ok || err != nil { + return fmt.Errorf("unexpected error calling Insertable: %w", err) + } + } + want := []string{} + for _, sig := range v.DSSEObj.Signatures { + keyHash := sha256.Sum256(*sig.Verifier) + want = append(want, "sha256:"+hex.EncodeToString(keyHash[:])) + } + decodedPayload, err := base64.StdEncoding.DecodeString(tt.env.Payload) + if err != nil { + return fmt.Errorf("could not decode envelope payload: %w", err) + } + h := sha256.Sum256(decodedPayload) + want = append(want, "sha256:"+hex.EncodeToString(h[:])) + + envHashBytes := sha256.Sum256([]byte(*tt.it.ProposedContent.Envelope)) + envHash := hex.EncodeToString(envHashBytes[:]) + + hashkey := strings.ToLower(fmt.Sprintf("sha256:%s", envHash)) + want = append(want, hashkey) + got, _ := v.IndexKeys() + sort.Strings(got) + sort.Strings(want) + if !reflect.DeepEqual(got, want) { + t.Errorf("V001Entry.IndexKeys() = %v, want %v", got, want) + } + payloadBytes, _ := v.env.DecodeB64Payload() + payloadSha := sha256.Sum256(payloadBytes) + payloadHash := hex.EncodeToString(payloadSha[:]) + + canonicalBytes, err := v.Canonicalize(context.Background()) + if err != nil { + t.Errorf("error canonicalizing entry: %v", err) + } + + pe, err := models.UnmarshalProposedEntry(bytes.NewReader(canonicalBytes), runtime.JSONConsumer()) + if err != nil { + t.Errorf("unexpected err from Unmarshalling canonicalized entry for '%v': %v", tt.name, err) + } + canonicalEntry, err := types.UnmarshalEntry(pe) + if err != nil { + t.Errorf("unexpected err from type-specific unmarshalling for '%v': %v", tt.name, err) + } + canonicalV001 := canonicalEntry.(*V001Entry) + if ok, err := canonicalV001.Insertable(); ok || err == nil { + t.Errorf("unexpected success testing Insertable against entry created from canonicalized content") + } + if *canonicalV001.DSSEObj.EnvelopeHash.Value != envHash { + t.Errorf("envelope hashes do not match post canonicalization: %v %v", *canonicalV001.DSSEObj.EnvelopeHash.Value, envHash) + } + if *canonicalV001.DSSEObj.PayloadHash.Value != payloadHash { + t.Errorf("payload hashes do not match post canonicalization: %v %v", canonicalV001.DSSEObj.PayloadHash.Value, payloadHash) + } + canonicalIndexKeys, _ := canonicalV001.IndexKeys() + if !cmp.Equal(got, canonicalIndexKeys, cmpopts.SortSlices(func(x, y string) bool { return x < y })) { + t.Errorf("index keys from hydrated object do not match those generated from canonicalized (and re-hydrated) object: %v %v", got, canonicalIndexKeys) + } + + return nil + } + if err := uv(); (err != nil) != tt.wantErr { + t.Errorf("V001Entry.Unmarshal() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} + +func TestV001Entry_IndexKeys(t *testing.T) { + key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + t.Fatal(err) + } + der, err := x509.MarshalPKIXPublicKey(&key.PublicKey) + if err != nil { + t.Fatal(err) + } + pub := pem.EncodeToMemory(&pem.Block{ + Bytes: der, + Type: "PUBLIC KEY", + }) + + tests := []struct { + name string + statement in_toto.Statement + want []string + }{ + { + name: "standard", + want: []string{}, + statement: in_toto.Statement{ + Predicate: "hello", + }, + }, + { + name: "subject", + want: []string{"sha256:foo"}, + statement: in_toto.Statement{ + StatementHeader: in_toto.StatementHeader{ + Subject: []in_toto.Subject{ + { + Name: "foo", + Digest: map[string]string{ + "sha256": "foo", + }, + }, + }, + }, + Predicate: "hello", + }, + }, + { + name: "slsa", + want: []string{"sha256:bar"}, + statement: in_toto.Statement{ + Predicate: slsa.ProvenancePredicate{ + Materials: []slsaCommon.ProvenanceMaterial{ + { + URI: "foo", + Digest: map[string]string{ + "sha256": "bar", + }}, + }, + }, + }, + }, + { + name: "slsa wit header", + want: []string{"sha256:foo", "sha256:bar"}, + statement: in_toto.Statement{ + StatementHeader: in_toto.StatementHeader{ + Subject: []in_toto.Subject{ + { + Name: "foo", + Digest: map[string]string{ + "sha256": "foo", + }, + }, + }, + }, + Predicate: slsa.ProvenancePredicate{ + Materials: []slsaCommon.ProvenanceMaterial{ + { + URI: "foo", + Digest: map[string]string{ + "sha256": "bar", + }}, + }, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + b, err := json.Marshal(tt.statement) + if err != nil { + t.Fatal(err) + } + pe := &models.DSSE{ + APIVersion: swag.String(APIVERSION), + Spec: &models.DSSEV001Schema{ + ProposedContent: createRekorEnvelope(envelope(t, key, b), [][]byte{pub}), + }, + } + v := V001Entry{} + if err := v.Unmarshal(pe); err != nil { + t.Error(err) + } + want := []string{} + for _, sig := range v.DSSEObj.Signatures { + keyHash := sha256.Sum256(*sig.Verifier) + want = append(want, "sha256:"+hex.EncodeToString(keyHash[:])) + } + decodedPayload, _ := base64.StdEncoding.DecodeString(v.env.Payload) + h := sha256.Sum256(decodedPayload) + want = append(want, "sha256:"+hex.EncodeToString(h[:])) + + envHashBytes := sha256.Sum256([]byte(*v.DSSEObj.ProposedContent.Envelope)) + envHash := hex.EncodeToString(envHashBytes[:]) + + hashkey := strings.ToLower(fmt.Sprintf("sha256:%s", envHash)) + want = append(want, hashkey) + want = append(want, tt.want...) + got, err := v.IndexKeys() + if err != nil { + t.Error(err) + } + sort.Strings(got) + sort.Strings(want) + if !cmp.Equal(got, want, cmpopts.EquateEmpty()) { + t.Errorf("V001Entry.IndexKeys() = %v, want %v", got, want) + } + }) + } +} + +func TestInsertable(t *testing.T) { + type TestCase struct { + caseDesc string + entry V001Entry + expectSuccess bool + } + + testCases := []TestCase{ + { + caseDesc: "valid entry", + entry: V001Entry{ + DSSEObj: models.DSSEV001Schema{ + ProposedContent: &models.DSSEV001SchemaProposedContent{ + Envelope: swag.String("envelope"), + Verifiers: []strfmt.Base64{ + []byte("keys"), + }, + }, + }, + }, + expectSuccess: true, + }, + { + caseDesc: "missing public keys", + entry: V001Entry{ + DSSEObj: models.DSSEV001Schema{ + ProposedContent: &models.DSSEV001SchemaProposedContent{ + Envelope: swag.String("envelope"), + /* + Verifiers: []strfmt.Base64{ + []byte("keys"), + }, + */ + }, + }, + }, + expectSuccess: false, + }, + { + caseDesc: "missing envelope", + entry: V001Entry{ + DSSEObj: models.DSSEV001Schema{ + ProposedContent: &models.DSSEV001SchemaProposedContent{ + //Envelope: swag.String("envelope"), + Verifiers: []strfmt.Base64{ + []byte("keys"), + }, + }, + }, + }, + expectSuccess: false, + }, + { + caseDesc: "missing proposed content obj", + entry: V001Entry{ + DSSEObj: models.DSSEV001Schema{ + /* + ProposedContent: &models.DSSEV001SchemaProposedContent{ + Envelope: swag.String("envelope"), + Verifiers: []strfmt.Base64{ + []byte("keys"), + }, + }, + */ + }, + }, + expectSuccess: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.caseDesc, func(t *testing.T) { + if ok, err := tc.entry.Insertable(); ok != tc.expectSuccess { + t.Errorf("unexpected result calling Insertable: %v", err) + } + }) + } +} diff --git a/pkg/types/dsse/v0.0.1/fuzz_test.go b/pkg/types/dsse/v0.0.1/fuzz_test.go new file mode 100644 index 000000000..8233cc85e --- /dev/null +++ b/pkg/types/dsse/v0.0.1/fuzz_test.go @@ -0,0 +1,99 @@ +// +// 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. + +package dsse + +import ( + "context" + "sync" + "testing" + + fuzz "github.com/AdamKorcz/go-fuzz-headers-1" + "github.com/go-openapi/swag" + + fuzzUtils "github.com/sigstore/rekor/pkg/fuzz" + "github.com/sigstore/rekor/pkg/generated/models" + "github.com/sigstore/rekor/pkg/types" + "github.com/sigstore/rekor/pkg/types/dsse" +) + +var initter sync.Once + +func FuzzDSSECreateProposedEntry(f *testing.F) { + f.Fuzz(func(t *testing.T, propsData []byte) { + initter.Do(fuzzUtils.SetFuzzLogger) + + ff := fuzz.NewConsumer(propsData) + + props, cleanup, err := fuzzUtils.CreateProps(ff, "dssev001") + if err != nil { + t.Skip() + } + defer func() { + for _, c := range cleanup { + c() + } + }() + + it := dsse.New() + entry, err := it.CreateProposedEntry(context.Background(), APIVERSION, props) + if err != nil { + t.Skip() + } + + ei, err := types.CreateVersionedEntry(entry) + if err != nil { + t.Skip() + } + + if ok, err := ei.Insertable(); !ok || err != nil { + t.Errorf("entry created via CreateProposedEntry should be insertable: %v", err) + } + + if _, err := types.CanonicalizeEntry(context.Background(), ei); err != nil { + t.Errorf("valid insertable entry should be able to be canonicalized: %v", err) + } + + _, _ = ei.IndexKeys() + }) +} + +func FuzzDSSEUnmarshalAndCanonicalize(f *testing.F) { + f.Fuzz(func(t *testing.T, entryData []byte) { + initter.Do(fuzzUtils.SetFuzzLogger) + + ff := fuzz.NewConsumer(entryData) + + targetV001 := &models.DSSEV001Schema{} + + if err := ff.GenerateStruct(targetV001); err != nil { + t.Skip() + } + + targetEntry := &models.DSSE{ + APIVersion: swag.String(APIVERSION), + Spec: targetV001, + } + + ei, err := types.UnmarshalEntry(targetEntry) + if err != nil { + t.Skip() + } + + if _, err := types.CanonicalizeEntry(context.Background(), ei); err != nil { + t.Errorf("error canonicalizing unmarshalled entry: %v", err) + } + }) +} diff --git a/pkg/types/entries.go b/pkg/types/entries.go index 4b0ee5b98..3bbf47e05 100644 --- a/pkg/types/entries.go +++ b/pkg/types/entries.go @@ -27,6 +27,7 @@ import ( "github.com/go-openapi/strfmt" "github.com/mitchellh/mapstructure" "github.com/sigstore/rekor/pkg/generated/models" + "github.com/sigstore/rekor/pkg/pki" ) // EntryImpl specifies the behavior of a versioned type @@ -36,6 +37,8 @@ type EntryImpl interface { Canonicalize(ctx context.Context) ([]byte, error) // marshal the canonical entry to be put into the tlog Unmarshal(e models.ProposedEntry) error // unmarshal the abstract entry into the specific struct for this versioned type CreateFromArtifactProperties(context.Context, ArtifactProperties) (models.ProposedEntry, error) + Verifiers() ([]pki.PublicKey, error) + Insertable() (bool, error) // denotes whether the entry that was unmarshalled has the writeOnly fields required to validate and insert into the log } // EntryWithAttestationImpl specifies the behavior of a versioned type that also stores attestations @@ -80,6 +83,12 @@ func CreateVersionedEntry(pe models.ProposedEntry) (EntryImpl, error) { if !tf.(func() TypeImpl)().IsSupportedVersion(ei.APIVersion()) { return nil, fmt.Errorf("entry kind '%v' does not support inserting entries of version '%v'", kind, ei.APIVersion()) } + } else { + return nil, fmt.Errorf("unknown kind '%v' specified", kind) + } + + if ok, err := ei.Insertable(); !ok { + return nil, fmt.Errorf("entry not insertable into log: %w", err) } return ei, nil diff --git a/pkg/types/hashedrekord/hashedrekord_test.go b/pkg/types/hashedrekord/hashedrekord_test.go index 5dda7f57c..aeb2975aa 100644 --- a/pkg/types/hashedrekord/hashedrekord_test.go +++ b/pkg/types/hashedrekord/hashedrekord_test.go @@ -22,6 +22,7 @@ import ( "github.com/go-openapi/swag" "github.com/sigstore/rekor/pkg/generated/models" + "github.com/sigstore/rekor/pkg/pki" "github.com/sigstore/rekor/pkg/types" ) @@ -38,10 +39,14 @@ func (u UnmarshalFailsTester) NewEntry() types.EntryImpl { return &UnmarshalFailsTester{} } -func (u UnmarshalFailsTester) Unmarshal(pe models.ProposedEntry) error { +func (u UnmarshalFailsTester) Unmarshal(_ models.ProposedEntry) error { return errors.New("error") } +func (u UnmarshalFailsTester) Verifiers() ([]pki.PublicKey, error) { + return nil, nil +} + func TestRekordType(t *testing.T) { // empty to start if VersionMap.Count() != 0 { diff --git a/pkg/types/hashedrekord/v0.0.1/entry.go b/pkg/types/hashedrekord/v0.0.1/entry.go index b5e7d7ee7..5fdef0286 100644 --- a/pkg/types/hashedrekord/v0.0.1/entry.go +++ b/pkg/types/hashedrekord/v0.0.1/entry.go @@ -104,7 +104,7 @@ func (v *V001Entry) Unmarshal(pe models.ProposedEntry) error { return err } -func (v *V001Entry) Canonicalize(ctx context.Context) ([]byte, error) { +func (v *V001Entry) Canonicalize(_ context.Context) ([]byte, error) { sigObj, keyObj, err := v.validate() if err != nil { return nil, types.ValidationError(err) @@ -189,7 +189,7 @@ func (v *V001Entry) validate() (pki.Signature, pki.PublicKey, error) { return sigObj, keyObj, nil } -func (v V001Entry) CreateFromArtifactProperties(ctx context.Context, props types.ArtifactProperties) (models.ProposedEntry, error) { +func (v V001Entry) CreateFromArtifactProperties(_ context.Context, props types.ArtifactProperties) (models.ProposedEntry, error) { returnVal := models.Hashedrekord{} re := V001Entry{} @@ -245,3 +245,42 @@ func (v V001Entry) CreateFromArtifactProperties(ctx context.Context, props types return &returnVal, nil } + +func (v V001Entry) Verifiers() ([]pki.PublicKey, error) { + if v.HashedRekordObj.Signature == nil || v.HashedRekordObj.Signature.PublicKey == nil || v.HashedRekordObj.Signature.PublicKey.Content == nil { + return nil, errors.New("hashedrekord v0.0.1 entry not initialized") + } + key, err := x509.NewPublicKey(bytes.NewReader(v.HashedRekordObj.Signature.PublicKey.Content)) + if err != nil { + return nil, err + } + return []pki.PublicKey{key}, nil +} + +func (v V001Entry) Insertable() (bool, error) { + if v.HashedRekordObj.Signature == nil { + return false, errors.New("missing signature property") + } + if len(v.HashedRekordObj.Signature.Content) == 0 { + return false, errors.New("missing signature content") + } + if v.HashedRekordObj.Signature.PublicKey == nil { + return false, errors.New("missing publicKey property") + } + if len(v.HashedRekordObj.Signature.PublicKey.Content) == 0 { + return false, errors.New("missing publicKey content") + } + if v.HashedRekordObj.Data == nil { + return false, errors.New("missing data property") + } + if v.HashedRekordObj.Data.Hash == nil { + return false, errors.New("missing hash property") + } + if v.HashedRekordObj.Data.Hash.Algorithm == nil { + return false, errors.New("missing hash algorithm") + } + if v.HashedRekordObj.Data.Hash.Value == nil { + return false, errors.New("missing hash value") + } + return true, nil +} diff --git a/pkg/types/hashedrekord/v0.0.1/entry_test.go b/pkg/types/hashedrekord/v0.0.1/entry_test.go index 72a55d61c..6c9fb2f31 100644 --- a/pkg/types/hashedrekord/v0.0.1/entry_test.go +++ b/pkg/types/hashedrekord/v0.0.1/entry_test.go @@ -59,6 +59,7 @@ func TestCrossFieldValidation(t *testing.T) { entry V001Entry expectUnmarshalSuccess bool expectCanonicalizeSuccess bool + expectedVerifierSuccess bool } key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) @@ -103,9 +104,10 @@ func TestCrossFieldValidation(t *testing.T) { testCases := []TestCase{ { - caseDesc: "empty obj", - entry: V001Entry{}, - expectUnmarshalSuccess: false, + caseDesc: "empty obj", + entry: V001Entry{}, + expectUnmarshalSuccess: false, + expectedVerifierSuccess: false, }, { caseDesc: "signature without url or content", @@ -114,7 +116,8 @@ func TestCrossFieldValidation(t *testing.T) { Signature: &models.HashedrekordV001SchemaSignature{}, }, }, - expectUnmarshalSuccess: false, + expectUnmarshalSuccess: false, + expectedVerifierSuccess: false, }, { caseDesc: "signature without public key", @@ -125,7 +128,8 @@ func TestCrossFieldValidation(t *testing.T) { }, }, }, - expectUnmarshalSuccess: false, + expectUnmarshalSuccess: false, + expectedVerifierSuccess: false, }, { caseDesc: "signature with empty public key", @@ -137,7 +141,8 @@ func TestCrossFieldValidation(t *testing.T) { }, }, }, - expectUnmarshalSuccess: false, + expectUnmarshalSuccess: false, + expectedVerifierSuccess: false, }, { caseDesc: "signature with ed25519 public key", @@ -152,6 +157,8 @@ func TestCrossFieldValidation(t *testing.T) { }, }, expectUnmarshalSuccess: false, + // successful even if unmarshalling fails, because the ed25519 key is valid + expectedVerifierSuccess: true, }, { caseDesc: "signature without data", @@ -165,7 +172,8 @@ func TestCrossFieldValidation(t *testing.T) { }, }, }, - expectUnmarshalSuccess: false, + expectUnmarshalSuccess: false, + expectedVerifierSuccess: true, }, { caseDesc: "signature with empty data", @@ -180,7 +188,8 @@ func TestCrossFieldValidation(t *testing.T) { Data: &models.HashedrekordV001SchemaData{}, }, }, - expectUnmarshalSuccess: false, + expectUnmarshalSuccess: false, + expectedVerifierSuccess: true, }, { caseDesc: "signature with hash", @@ -202,6 +211,7 @@ func TestCrossFieldValidation(t *testing.T) { }, expectUnmarshalSuccess: true, expectCanonicalizeSuccess: true, + expectedVerifierSuccess: true, }, { caseDesc: "signature with invalid sha length", @@ -223,6 +233,7 @@ func TestCrossFieldValidation(t *testing.T) { }, expectUnmarshalSuccess: false, expectCanonicalizeSuccess: false, + expectedVerifierSuccess: true, }, { caseDesc: "signature with hash & invalid signature", @@ -244,6 +255,7 @@ func TestCrossFieldValidation(t *testing.T) { }, expectUnmarshalSuccess: false, expectCanonicalizeSuccess: false, + expectedVerifierSuccess: true, }, } @@ -272,6 +284,13 @@ func TestCrossFieldValidation(t *testing.T) { t.Errorf("unexpected result in '%v': %v", tc.caseDesc, err) } + if tc.expectUnmarshalSuccess { + ok, err := v.Insertable() + if !ok || err != nil { + t.Errorf("unexpected failure in testing insertable on valid entry: %v", err) + } + } + b, err := v.Canonicalize(context.TODO()) if (err == nil) != tc.expectCanonicalizeSuccess { t.Errorf("unexpected result from Canonicalize for '%v': %v", tc.caseDesc, err) @@ -285,9 +304,33 @@ func TestCrossFieldValidation(t *testing.T) { if err != nil { t.Errorf("unexpected err from Unmarshalling canonicalized entry for '%v': %v", tc.caseDesc, err) } - if _, err := types.UnmarshalEntry(pe); err != nil { + ei, err := types.UnmarshalEntry(pe) + if err != nil { t.Errorf("unexpected err from type-specific unmarshalling for '%v': %v", tc.caseDesc, err) } + // hashedrekord is one of two types (rfc3161, hashedrekord) in that what is persisted is also insertable + ok, err := ei.Insertable() + if !ok || err != nil { + t.Errorf("unexpected failure in testing insertable on entry created from canonicalized content: %v", err) + } + } + + verifiers, err := v.Verifiers() + if tc.expectedVerifierSuccess { + if err != nil { + t.Errorf("%v: unexpected error, got %v", tc.caseDesc, err) + } else { + pub, _ := verifiers[0].CanonicalValue() + // invalidKeyBytes is a valid ed25519 key + if !reflect.DeepEqual(pub, keyBytes) && !reflect.DeepEqual(pub, invalidKeyBytes) { + t.Errorf("verifier and public keys do not match: %v, %v", string(pub), string(keyBytes)) + } + } + } else { + if err == nil { + s, _ := verifiers[0].CanonicalValue() + t.Errorf("%v: expected error for %v, got %v", tc.caseDesc, string(s), err) + } } } } @@ -413,3 +456,203 @@ func testKeyAndCert(t *testing.T) ([]byte, []byte, *ecdsa.PrivateKey) { return pub, certPem, priv } + +func TestInsertable(t *testing.T) { + type TestCase struct { + caseDesc string + entry V001Entry + expectSuccess bool + } + + testCases := []TestCase{ + { + caseDesc: "valid entry", + entry: V001Entry{ + HashedRekordObj: models.HashedrekordV001Schema{ + Data: &models.HashedrekordV001SchemaData{ + Hash: &models.HashedrekordV001SchemaDataHash{ + Algorithm: swag.String(models.HashedrekordV001SchemaDataHashAlgorithmSha256), + Value: swag.String("deadbeef"), + }, + }, + Signature: &models.HashedrekordV001SchemaSignature{ + Content: strfmt.Base64("sig"), + PublicKey: &models.HashedrekordV001SchemaSignaturePublicKey{ + Content: strfmt.Base64("key"), + }, + }, + }, + }, + expectSuccess: true, + }, + { + caseDesc: "missing key", + entry: V001Entry{ + HashedRekordObj: models.HashedrekordV001Schema{ + Data: &models.HashedrekordV001SchemaData{ + Hash: &models.HashedrekordV001SchemaDataHash{ + Algorithm: swag.String(models.HashedrekordV001SchemaDataHashAlgorithmSha256), + Value: swag.String("deadbeef"), + }, + }, + Signature: &models.HashedrekordV001SchemaSignature{ + Content: strfmt.Base64("sig"), + }, + }, + }, + expectSuccess: false, + }, + { + caseDesc: "missing key content", + entry: V001Entry{ + HashedRekordObj: models.HashedrekordV001Schema{ + Data: &models.HashedrekordV001SchemaData{ + Hash: &models.HashedrekordV001SchemaDataHash{ + Algorithm: swag.String(models.HashedrekordV001SchemaDataHashAlgorithmSha256), + Value: swag.String("deadbeef"), + }, + }, + Signature: &models.HashedrekordV001SchemaSignature{ + Content: strfmt.Base64("sig"), + PublicKey: &models.HashedrekordV001SchemaSignaturePublicKey{}, + }, + }, + }, + expectSuccess: false, + }, + { + caseDesc: "missing key content", + entry: V001Entry{ + HashedRekordObj: models.HashedrekordV001Schema{ + Data: &models.HashedrekordV001SchemaData{ + Hash: &models.HashedrekordV001SchemaDataHash{ + Algorithm: swag.String(models.HashedrekordV001SchemaDataHashAlgorithmSha256), + Value: swag.String("deadbeef"), + }, + }, + Signature: &models.HashedrekordV001SchemaSignature{ + Content: strfmt.Base64("sig"), + PublicKey: nil, + }, + }, + }, + expectSuccess: false, + }, + { + caseDesc: "missing sig content", + entry: V001Entry{ + HashedRekordObj: models.HashedrekordV001Schema{ + Data: &models.HashedrekordV001SchemaData{ + Hash: &models.HashedrekordV001SchemaDataHash{ + Algorithm: swag.String(models.HashedrekordV001SchemaDataHashAlgorithmSha256), + Value: swag.String("deadbeef"), + }, + }, + Signature: &models.HashedrekordV001SchemaSignature{ + Content: nil, + PublicKey: &models.HashedrekordV001SchemaSignaturePublicKey{ + Content: strfmt.Base64("key"), + }, + }, + }, + }, + expectSuccess: false, + }, + { + caseDesc: "missing hash value", + entry: V001Entry{ + HashedRekordObj: models.HashedrekordV001Schema{ + Data: &models.HashedrekordV001SchemaData{ + Hash: &models.HashedrekordV001SchemaDataHash{ + Algorithm: swag.String(models.HashedrekordV001SchemaDataHashAlgorithmSha256), + }, + }, + Signature: &models.HashedrekordV001SchemaSignature{ + Content: strfmt.Base64("sig"), + PublicKey: &models.HashedrekordV001SchemaSignaturePublicKey{ + Content: strfmt.Base64("key"), + }, + }, + }, + }, + expectSuccess: false, + }, + { + caseDesc: "missing hash algorithm", + entry: V001Entry{ + HashedRekordObj: models.HashedrekordV001Schema{ + Data: &models.HashedrekordV001SchemaData{ + Hash: &models.HashedrekordV001SchemaDataHash{ + Value: swag.String("deadbeef"), + }, + }, + Signature: &models.HashedrekordV001SchemaSignature{ + Content: strfmt.Base64("sig"), + PublicKey: &models.HashedrekordV001SchemaSignaturePublicKey{ + Content: strfmt.Base64("key"), + }, + }, + }, + }, + expectSuccess: false, + }, + { + caseDesc: "missing hash object", + entry: V001Entry{ + HashedRekordObj: models.HashedrekordV001Schema{ + Data: &models.HashedrekordV001SchemaData{}, + Signature: &models.HashedrekordV001SchemaSignature{ + Content: strfmt.Base64("sig"), + PublicKey: &models.HashedrekordV001SchemaSignaturePublicKey{ + Content: strfmt.Base64("key"), + }, + }, + }, + }, + expectSuccess: false, + }, + { + caseDesc: "missing data object", + entry: V001Entry{ + HashedRekordObj: models.HashedrekordV001Schema{ + Signature: &models.HashedrekordV001SchemaSignature{ + Content: strfmt.Base64("sig"), + PublicKey: &models.HashedrekordV001SchemaSignaturePublicKey{ + Content: strfmt.Base64("key"), + }, + }, + }, + }, + expectSuccess: false, + }, + { + caseDesc: "missing sig object", + entry: V001Entry{ + HashedRekordObj: models.HashedrekordV001Schema{ + Data: &models.HashedrekordV001SchemaData{ + Hash: &models.HashedrekordV001SchemaDataHash{ + Algorithm: swag.String(models.HashedrekordV001SchemaDataHashAlgorithmSha256), + Value: swag.String("deadbeef"), + }, + }, + }, + }, + expectSuccess: false, + }, + { + caseDesc: "empty object", + entry: V001Entry{ + HashedRekordObj: models.HashedrekordV001Schema{}, + }, + expectSuccess: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.caseDesc, func(t *testing.T) { + if ok, err := tc.entry.Insertable(); ok != tc.expectSuccess { + t.Errorf("unexpected result calling Insertable: %v", err) + } + }) + } +} diff --git a/pkg/types/hashedrekord/v0.0.1/fuzz_test.go b/pkg/types/hashedrekord/v0.0.1/fuzz_test.go new file mode 100644 index 000000000..c1878d7c4 --- /dev/null +++ b/pkg/types/hashedrekord/v0.0.1/fuzz_test.go @@ -0,0 +1,101 @@ +// +// 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. + +package hashedrekord + +import ( + "context" + "sync" + "testing" + + fuzz "github.com/AdamKorcz/go-fuzz-headers-1" + "github.com/go-openapi/swag" + + fuzzUtils "github.com/sigstore/rekor/pkg/fuzz" + "github.com/sigstore/rekor/pkg/generated/models" + "github.com/sigstore/rekor/pkg/types" + "github.com/sigstore/rekor/pkg/types/hashedrekord" +) + +var initter sync.Once + +func FuzzHashedRekordCreateProposedEntry(f *testing.F) { + f.Fuzz(func(t *testing.T, propsData []byte) { + initter.Do(fuzzUtils.SetFuzzLogger) + + version := "0.0.1" + + ff := fuzz.NewConsumer(propsData) + + props, cleanup, err := fuzzUtils.CreateProps(ff, "hashedrekordV001") + if err != nil { + t.Skip() + } + defer func() { + for _, c := range cleanup { + c() + } + }() + + it := hashedrekord.New() + entry, err := it.CreateProposedEntry(context.Background(), version, props) + if err != nil { + t.Skip() + } + + ei, err := types.CreateVersionedEntry(entry) + if err != nil { + t.Skip() + } + + if ok, err := ei.Insertable(); !ok || err != nil { + t.Errorf("entry created via CreateProposedEntry should be insertable: %v", err) + } + + if _, err := types.CanonicalizeEntry(context.Background(), ei); err != nil { + t.Errorf("valid insertable entry should be able to be canonicalized: %v", err) + } + + _, _ = ei.IndexKeys() + }) +} + +func FuzzHashedRekordUnmarshalAndCanonicalize(f *testing.F) { + f.Fuzz(func(t *testing.T, entryData []byte) { + initter.Do(fuzzUtils.SetFuzzLogger) + + ff := fuzz.NewConsumer(entryData) + + targetV001 := &models.HashedrekordV001Schema{} + + if err := ff.GenerateStruct(targetV001); err != nil { + t.Skip() + } + + targetEntry := &models.Hashedrekord{ + APIVersion: swag.String(APIVERSION), + Spec: targetV001, + } + + ei, err := types.UnmarshalEntry(targetEntry) + if err != nil { + t.Skip() + } + + if _, err := types.CanonicalizeEntry(context.Background(), ei); err != nil { + t.Errorf("error canonicalizing unmarshalled entry: %v", err) + } + }) +} diff --git a/pkg/types/helm/fuzz_test.go b/pkg/types/helm/fuzz_test.go deleted file mode 100644 index b97738c63..000000000 --- a/pkg/types/helm/fuzz_test.go +++ /dev/null @@ -1,42 +0,0 @@ -// -// Copyright 2022 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 helm - -import ( - "context" - "testing" - - fuzz "github.com/AdaLogics/go-fuzz-headers" - - "github.com/sigstore/rekor/pkg/types" -) - -func FuzzHelmCreateProposedEntry(f *testing.F) { - f.Fuzz(func(t *testing.T, version string, propsData []byte) { - ff := fuzz.NewConsumer(propsData) - props := types.ArtifactProperties{} - ff.GenerateStruct(&props) - it := New() - entry, err := it.CreateProposedEntry(context.Background(), version, props) - if err != nil { - t.Skip() - } - _, err = it.UnmarshalEntry(entry) - if err != nil { - t.Skip() - } - }) -} diff --git a/pkg/types/helm/helm_test.go b/pkg/types/helm/helm_test.go index 72cba153b..f3e17a6b7 100644 --- a/pkg/types/helm/helm_test.go +++ b/pkg/types/helm/helm_test.go @@ -22,6 +22,7 @@ import ( "github.com/go-openapi/swag" "github.com/sigstore/rekor/pkg/generated/models" + "github.com/sigstore/rekor/pkg/pki" "github.com/sigstore/rekor/pkg/types" ) @@ -38,10 +39,14 @@ func (u UnmarshalFailsTester) NewEntry() types.EntryImpl { return &UnmarshalFailsTester{} } -func (u UnmarshalFailsTester) Unmarshal(pe models.ProposedEntry) error { +func (u UnmarshalFailsTester) Unmarshal(_ models.ProposedEntry) error { return errors.New("error") } +func (u UnmarshalFailsTester) Verifiers() ([]pki.PublicKey, error) { + return nil, nil +} + func TestHelmType(t *testing.T) { // empty to start if VersionMap.Count() != 0 { diff --git a/pkg/types/helm/provenance.go b/pkg/types/helm/provenance.go index 74936042a..5c09eb44e 100644 --- a/pkg/types/helm/provenance.go +++ b/pkg/types/helm/provenance.go @@ -22,7 +22,7 @@ import ( "io" "strings" - "github.com/ghodss/yaml" + "sigs.k8s.io/yaml" //TODO: https://github.com/sigstore/rekor/issues/286 "golang.org/x/crypto/openpgp/clearsign" //nolint:staticcheck diff --git a/pkg/types/helm/v0.0.1/entry.go b/pkg/types/helm/v0.0.1/entry.go index dc538e527..9100a7d98 100644 --- a/pkg/types/helm/v0.0.1/entry.go +++ b/pkg/types/helm/v0.0.1/entry.go @@ -32,6 +32,7 @@ import ( "github.com/go-openapi/swag" "github.com/sigstore/rekor/pkg/generated/models" "github.com/sigstore/rekor/pkg/log" + "github.com/sigstore/rekor/pkg/pki" "github.com/sigstore/rekor/pkg/pki/pgp" "github.com/sigstore/rekor/pkg/types" "github.com/sigstore/rekor/pkg/types/helm" @@ -116,6 +117,10 @@ func (v *V001Entry) Unmarshal(pe models.ProposedEntry) error { } func (v *V001Entry) fetchExternalEntities(ctx context.Context) (*helm.Provenance, *pgp.PublicKey, *pgp.Signature, error) { + if err := v.validate(); err != nil { + return nil, nil, nil, types.ValidationError(err) + } + g, ctx := errgroup.WithContext(ctx) provenanceR, provenanceW := io.Pipe() @@ -343,3 +348,34 @@ func (v V001Entry) CreateFromArtifactProperties(ctx context.Context, props types return &returnVal, nil } + +func (v V001Entry) Verifiers() ([]pki.PublicKey, error) { + if v.HelmObj.PublicKey == nil || v.HelmObj.PublicKey.Content == nil { + return nil, errors.New("helm v0.0.1 entry not initialized") + } + key, err := pgp.NewPublicKey(bytes.NewReader(*v.HelmObj.PublicKey.Content)) + if err != nil { + return nil, err + } + return []pki.PublicKey{key}, nil +} + +func (v V001Entry) Insertable() (bool, error) { + if v.HelmObj.PublicKey == nil { + return false, errors.New("missing public key property") + } + if v.HelmObj.PublicKey.Content == nil || len(*v.HelmObj.PublicKey.Content) == 0 { + return false, errors.New("missing public key content") + } + + if v.HelmObj.Chart == nil { + return false, errors.New("missing chart property") + } + if v.HelmObj.Chart.Provenance == nil { + return false, errors.New("missing provenance property") + } + if len(v.HelmObj.Chart.Provenance.Content) == 0 { + return false, errors.New("missing provenance content") + } + return true, nil +} diff --git a/pkg/types/helm/v0.0.1/entry_test.go b/pkg/types/helm/v0.0.1/entry_test.go index 28e7417fa..d9f79eb98 100644 --- a/pkg/types/helm/v0.0.1/entry_test.go +++ b/pkg/types/helm/v0.0.1/entry_test.go @@ -48,6 +48,7 @@ func TestCrossFieldValidation(t *testing.T) { entry V001Entry expectUnmarshalSuccess bool expectCanonicalizeSuccess bool + expectedVerifierSuccess bool } keyBytes, _ := os.ReadFile("../tests/test_helm_armor.pub") @@ -55,9 +56,10 @@ func TestCrossFieldValidation(t *testing.T) { testCases := []TestCase{ { - caseDesc: "empty obj", - entry: V001Entry{}, - expectUnmarshalSuccess: false, + caseDesc: "empty obj", + entry: V001Entry{}, + expectUnmarshalSuccess: false, + expectedVerifierSuccess: false, }, { @@ -71,7 +73,8 @@ func TestCrossFieldValidation(t *testing.T) { }, }, }, - expectUnmarshalSuccess: false, + expectUnmarshalSuccess: false, + expectedVerifierSuccess: false, }, { caseDesc: "public key without provenance file", @@ -82,7 +85,8 @@ func TestCrossFieldValidation(t *testing.T) { }, }, }, - expectUnmarshalSuccess: false, + expectUnmarshalSuccess: false, + expectedVerifierSuccess: true, }, { caseDesc: "public key with empty provenance file", @@ -96,7 +100,8 @@ func TestCrossFieldValidation(t *testing.T) { }, }, }, - expectUnmarshalSuccess: false, + expectUnmarshalSuccess: false, + expectedVerifierSuccess: true, }, { caseDesc: "public key and invalid provenance content", @@ -114,6 +119,7 @@ func TestCrossFieldValidation(t *testing.T) { }, expectUnmarshalSuccess: true, expectCanonicalizeSuccess: false, + expectedVerifierSuccess: true, }, { caseDesc: "provenance content with invalid public key", @@ -131,6 +137,7 @@ func TestCrossFieldValidation(t *testing.T) { }, expectUnmarshalSuccess: true, expectCanonicalizeSuccess: false, + expectedVerifierSuccess: false, }, { caseDesc: "provenance content with valid public key", @@ -148,6 +155,7 @@ func TestCrossFieldValidation(t *testing.T) { }, expectUnmarshalSuccess: true, expectCanonicalizeSuccess: true, + expectedVerifierSuccess: true, }, } @@ -164,15 +172,21 @@ func TestCrossFieldValidation(t *testing.T) { Spec: tc.entry.HelmObj, } - if err := v.Unmarshal(&r); (err == nil) != tc.expectUnmarshalSuccess { + unmarshalAndValidate := func() error { + if err := v.Unmarshal(&r); err != nil { + return err + } + return v.validate() + } + if err := unmarshalAndValidate(); (err == nil) != tc.expectUnmarshalSuccess { t.Errorf("unexpected result in '%v': %v", tc.caseDesc, err) } - if !tc.expectUnmarshalSuccess { - return - } - if err := v.validate(); err != nil { - return + if tc.expectUnmarshalSuccess { + ok, err := v.Insertable() + if !ok || err != nil { + t.Errorf("unexpected error calling Insertable on valid proposed entry: %v", err) + } } b, err := v.Canonicalize(context.TODO()) @@ -188,9 +202,159 @@ func TestCrossFieldValidation(t *testing.T) { if err != nil { t.Errorf("unexpected err from Unmarshalling canonicalized entry for '%v': %v", tc.caseDesc, err) } - if _, err := types.UnmarshalEntry(pe); err != nil { + ei, err := types.UnmarshalEntry(pe) + if err != nil { t.Errorf("unexpected err from type-specific unmarshalling for '%v': %v", tc.caseDesc, err) } + if ok, err := ei.Insertable(); ok || err == nil { + t.Errorf("unexpected success calling Insertable on entry created from canonicalized content") + } + } + + verifiers, err := v.Verifiers() + if tc.expectedVerifierSuccess { + if err != nil { + t.Errorf("%v: unexpected error, got %v", tc.caseDesc, err) + } else { + // TODO: Improve this test once CanonicalValue returns same result as input for PGP keys + _, err := verifiers[0].CanonicalValue() + if err != nil { + t.Errorf("%v: unexpected error getting canonical value, got %v", tc.caseDesc, err) + } + } + } else { + if err == nil { + s, _ := verifiers[0].CanonicalValue() + t.Errorf("%v: expected error for %v, got %v", tc.caseDesc, string(s), err) + } + } + }) + } +} + +func TestInsertable(t *testing.T) { + type TestCase struct { + caseDesc string + entry V001Entry + expectSuccess bool + } + + pubKey := strfmt.Base64([]byte("pubKey")) + + testCases := []TestCase{ + { + caseDesc: "valid entry", + entry: V001Entry{ + HelmObj: models.HelmV001Schema{ + Chart: &models.HelmV001SchemaChart{ + Provenance: &models.HelmV001SchemaChartProvenance{ + Content: strfmt.Base64([]byte("content")), + }, + }, + PublicKey: &models.HelmV001SchemaPublicKey{ + Content: &pubKey, + }, + }, + }, + expectSuccess: true, + }, + { + caseDesc: "missing key content", + entry: V001Entry{ + HelmObj: models.HelmV001Schema{ + Chart: &models.HelmV001SchemaChart{ + Provenance: &models.HelmV001SchemaChartProvenance{ + Content: strfmt.Base64([]byte("content")), + }, + }, + PublicKey: &models.HelmV001SchemaPublicKey{ + //Content: &pubKey, + }, + }, + }, + expectSuccess: false, + }, + { + caseDesc: "missing key", + entry: V001Entry{ + HelmObj: models.HelmV001Schema{ + Chart: &models.HelmV001SchemaChart{ + Provenance: &models.HelmV001SchemaChartProvenance{ + Content: strfmt.Base64([]byte("content")), + }, + }, + /* + PublicKey: &models.HelmV001SchemaPublicKey{ + Content: &pubKey, + }, + */ + }, + }, + expectSuccess: false, + }, + { + caseDesc: "missing provenance content", + entry: V001Entry{ + HelmObj: models.HelmV001Schema{ + Chart: &models.HelmV001SchemaChart{ + Provenance: &models.HelmV001SchemaChartProvenance{ + //Content: strfmt.Base64([]byte("content")), + }, + }, + PublicKey: &models.HelmV001SchemaPublicKey{ + Content: &pubKey, + }, + }, + }, + expectSuccess: false, + }, + { + caseDesc: "missing provenance obj", + entry: V001Entry{ + HelmObj: models.HelmV001Schema{ + Chart: &models.HelmV001SchemaChart{ + /* + Provenance: &models.HelmV001SchemaChartProvenance{ + Content: strfmt.Base64([]byte("content")), + }, + */ + }, + PublicKey: &models.HelmV001SchemaPublicKey{ + Content: &pubKey, + }, + }, + }, + expectSuccess: false, + }, + { + caseDesc: "missing chart obj", + entry: V001Entry{ + HelmObj: models.HelmV001Schema{ + /* + Chart: &models.HelmV001SchemaChart{ + Provenance: &models.HelmV001SchemaChartProvenance{ + Content: strfmt.Base64([]byte("content")), + }, + }, + */ + PublicKey: &models.HelmV001SchemaPublicKey{ + Content: &pubKey, + }, + }, + }, + expectSuccess: false, + }, + { + caseDesc: "empty obj", + entry: V001Entry{}, + expectSuccess: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.caseDesc, func(t *testing.T) { + if ok, err := tc.entry.Insertable(); ok != tc.expectSuccess { + t.Errorf("unexpected result calling Insertable: %v", err) } }) } diff --git a/pkg/types/helm/v0.0.1/fuzz_test.go b/pkg/types/helm/v0.0.1/fuzz_test.go new file mode 100644 index 000000000..4c0695730 --- /dev/null +++ b/pkg/types/helm/v0.0.1/fuzz_test.go @@ -0,0 +1,109 @@ +// +// Copyright 2022 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 helm + +import ( + "bytes" + "context" + "sync" + "testing" + + fuzz "github.com/AdamKorcz/go-fuzz-headers-1" + "github.com/go-openapi/swag" + + fuzzUtils "github.com/sigstore/rekor/pkg/fuzz" + "github.com/sigstore/rekor/pkg/generated/models" + "github.com/sigstore/rekor/pkg/types" + "github.com/sigstore/rekor/pkg/types/helm" +) + +var initter sync.Once + +func FuzzHelmCreateProposedEntry(f *testing.F) { + f.Fuzz(func(t *testing.T, propsData []byte) { + initter.Do(fuzzUtils.SetFuzzLogger) + + version := "0.0.1" + + ff := fuzz.NewConsumer(propsData) + + props, cleanup, err := fuzzUtils.CreateProps(ff, "helmV001") + if err != nil { + t.Skip() + } + defer func() { + for _, c := range cleanup { + c() + } + }() + + it := helm.New() + entry, err := it.CreateProposedEntry(context.Background(), version, props) + if err != nil { + t.Skip() + } + ei, err := types.CreateVersionedEntry(entry) + if err != nil { + t.Skip() + } + + if ok, err := ei.Insertable(); !ok || err != nil { + t.Errorf("entry created via CreateProposedEntry should be insertable: %v", err) + } + + if _, err := types.CanonicalizeEntry(context.Background(), ei); err != nil { + t.Errorf("valid insertable entry should be able to be canonicalized: %v", err) + } + + _, _ = ei.IndexKeys() + }) +} + +func FuzzHelmUnmarshalAndCanonicalize(f *testing.F) { + f.Fuzz(func(t *testing.T, entryData []byte) { + initter.Do(fuzzUtils.SetFuzzLogger) + + ff := fuzz.NewConsumer(entryData) + + targetV001 := &models.HelmV001Schema{} + + if err := ff.GenerateStruct(targetV001); err != nil { + t.Skip() + } + + targetEntry := &models.Helm{ + APIVersion: swag.String(APIVERSION), + Spec: targetV001, + } + + ei, err := types.UnmarshalEntry(targetEntry) + if err != nil { + t.Skip() + } + + if _, err := types.CanonicalizeEntry(context.Background(), ei); err != nil { + t.Skip() + } + }) +} + +func FuzzHelmProvenanceUnmarshal(f *testing.F) { + f.Fuzz(func(t *testing.T, provenanceData []byte) { + p := &helm.Provenance{} + r := bytes.NewReader(provenanceData) + p.Unmarshal(r) + }) +} diff --git a/pkg/types/intoto/e2e_test.go b/pkg/types/intoto/e2e_test.go index 88b7bb10c..b0b3dd46d 100644 --- a/pkg/types/intoto/e2e_test.go +++ b/pkg/types/intoto/e2e_test.go @@ -19,6 +19,7 @@ package intoto import ( "bytes" + "context" "crypto" "crypto/ecdsa" "crypto/rsa" @@ -29,14 +30,19 @@ import ( "encoding/json" "encoding/pem" "fmt" + "io/ioutil" + "net/http" + "os" "path/filepath" "testing" "github.com/google/go-cmp/cmp" "github.com/in-toto/in-toto-golang/in_toto" + "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/common" slsa "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.2" "github.com/secure-systems-lab/go-securesystemslib/dsse" "github.com/sigstore/rekor/pkg/generated/models" + "github.com/sigstore/rekor/pkg/sharding" "github.com/sigstore/rekor/pkg/types" "github.com/sigstore/sigstore/pkg/signature" @@ -44,6 +50,13 @@ import ( "github.com/sigstore/rekor/pkg/util" ) +func rekorServer() string { + if s := os.Getenv("REKOR_SERVER"); s != "" { + return s + } + return "http://localhost:3000" +} + func TestIntoto(t *testing.T) { td := t.TempDir() attestationPath := filepath.Join(td, "attestation.json") @@ -60,14 +73,14 @@ func TestIntoto(t *testing.T) { Subject: []in_toto.Subject{ { Name: "foobar", - Digest: slsa.DigestSet{ + Digest: common.DigestSet{ "foo": "bar", }, }, }, }, Predicate: slsa.ProvenancePredicate{ - Builder: slsa.ProvenanceBuilder{ + Builder: common.ProvenanceBuilder{ ID: "foo" + id, }, }, @@ -96,7 +109,7 @@ func TestIntoto(t *testing.T) { t.Fatal(err) } - env, err := signer.SignPayload(in_toto.PayloadType, b) + env, err := signer.SignPayload(context.Background(), in_toto.PayloadType, b) if err != nil { t.Fatal(err) } @@ -149,7 +162,13 @@ func TestIntoto(t *testing.T) { out = util.RunCli(t, "upload", "--artifact", attestationPath, "--type", "intoto", "--public-key", pubKeyPath) util.OutputContains(t, out, "Entry already exists") + // issue1649 check for full UUID in printed Location value from 409 response header + if len(uuid) != sharding.EntryIDHexStringLen { + t.Fatal("UUID returned instead of entry ID (includes treeID)") + } + util.OutputContains(t, out, uuid) } + func TestIntotoMultiSig(t *testing.T) { td := t.TempDir() attestationPath := filepath.Join(td, "attestation.json") @@ -167,14 +186,14 @@ func TestIntotoMultiSig(t *testing.T) { Subject: []in_toto.Subject{ { Name: "foobar", - Digest: slsa.DigestSet{ + Digest: common.DigestSet{ "foo": "bar", }, }, }, }, Predicate: slsa.ProvenancePredicate{ - Builder: slsa.ProvenanceBuilder{ + Builder: common.ProvenanceBuilder{ ID: "foo" + id, }, }, @@ -222,7 +241,7 @@ func TestIntotoMultiSig(t *testing.T) { t.Fatal(err) } - env, err := signer.SignPayload(in_toto.PayloadType, b) + env, err := signer.SignPayload(context.Background(), in_toto.PayloadType, b) if err != nil { t.Fatal(err) } @@ -277,3 +296,140 @@ func TestIntotoMultiSig(t *testing.T) { out = util.RunCli(t, "upload", "--artifact", attestationPath, "--type", "intoto", "--public-key", ecdsapubKeyPath, "--public-key", rsapubKeyPath) util.OutputContains(t, out, "Entry already exists") } + +func TestValidationSearchIntotoV002MissingEnvelope(t *testing.T) { + body := `{ + "entries":[ + { + "kind":"intoto", + "apiVersion": "0.0.2", + "spec":{ + "content":{ + "hash":{ + "algorithm":"sha256", + "value":"782143e39f1e7a04e3f6da2d88b1c057e5657363c4f90679f3e8a071b7619e02" + }, + "payloadHash":{ + "algorithm":"sha256", + "value":"ebbfddda6277af199e93c5bb5cf5998a79311de238e49bcc8ac24102698761bb" + } + }, + "publicKey":"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNwRENDQWlxZ0F3SUJBZ0lVYWhsOEFRd1lZV05ZbnV6dlFvOEVrN1dMTURvd0NnWUlLb1pJemowRUF3TXcKTnpFVk1CTUdBMVVFQ2hNTWMybG5jM1J2Y21VdVpHVjJNUjR3SEFZRFZRUURFeFZ6YVdkemRHOXlaUzFwYm5SbApjbTFsWkdsaGRHVXdIaGNOTWpJd09ESTJNREV4TnpFM1doY05Nakl3T0RJMk1ERXlOekUzV2pBQU1Ga3dFd1lICktvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUVLWmZEQzlpalVyclpBWE9jWFYrQXFHRUlTSlEzVHRqSndJdEEKdTE3Rml2aWpnSk1hYUhGNDcrT3Z2OVR1ekFDQ3lpSUV5UDUyZXI2ZmF5bmZKYVVqOEtPQ0FVa3dnZ0ZGTUE0RwpBMVVkRHdFQi93UUVBd0lIZ0RBVEJnTlZIU1VFRERBS0JnZ3JCZ0VGQlFjREF6QWRCZ05WSFE0RUZnUVVHQldUCkMwdUU3dTRQcURVRjFYV0c0QlVWVUpBd0h3WURWUjBqQkJnd0ZvQVUzOVBwejFZa0VaYjVxTmpwS0ZXaXhpNFkKWkQ4d0pRWURWUjBSQVFIL0JCc3dHWUVYYzJGemIyRnJhWEpoTmpFeE5FQm5iV0ZwYkM1amIyMHdLUVlLS3dZQgpCQUdEdnpBQkFRUWJhSFIwY0hNNkx5OWhZMk52ZFc1MGN5NW5iMjluYkdVdVkyOXRNSUdMQmdvckJnRUVBZFo1CkFnUUNCSDBFZXdCNUFIY0FDR0NTOENoUy8yaEYwZEZySjRTY1JXY1lyQlk5d3pqU2JlYThJZ1kyYjNJQUFBR0MKMTdtSmhnQUFCQU1BU0RCR0FpRUFoS09BSkdWVlhCb1cxTDR4alk5eWJWOGZUUXN5TStvUEpIeDk5S29LYUpVQwpJUURCZDllc1Q0Mk1STng3Vm9BM1paKzV4akhNZWR6amVxQ2ZoZTcvd1pxYTlUQUtCZ2dxaGtqT1BRUURBd05vCkFEQmxBakVBcnBkeXlFRjc3b2JyTENMUXpzYmIxM2lsNjd3dzM4Y050amdNQml6Y2VUakRiY2VLeVFSN1RKNHMKZENsclkxY1BBakE4aXB6SUQ4VU1CaGxkSmUvZXJGcGdtN2swNWFic2lPN3V5dVZuS29VNk0rTXJ6VVUrZTlGdwpJRGhCanVRa1dRYz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=" + } + } + ] + } + ` + resp, err := http.Post(fmt.Sprintf("%s/api/v1/log/entries/retrieve", rekorServer()), + "application/json", + bytes.NewBuffer([]byte(body))) + if err != nil { + t.Fatal(err) + } + c, _ := ioutil.ReadAll(resp.Body) + if resp.StatusCode != 400 { + t.Fatalf("expected status 400, got %d instead: %v", resp.StatusCode, string(c)) + } +} + +func TestValidationSearchIntotoV002MissingEnvelopeHash(t *testing.T) { + body := `{ + "entries":[ + { + "kind":"intoto", + "apiVersion": "0.0.2", + "spec":{ + "content":{ + "envelope":{ + "payloadType":"asd", + "signatures":[ {} ] + }, + "payloadHash":{ + "algorithm":"sha256", + "value":"ebbfddda6277af199e93c5bb5cf5998a79311de238e49bcc8ac24102698761bb" + } + }, + "publicKey":"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNwRENDQWlxZ0F3SUJBZ0lVYWhsOEFRd1lZV05ZbnV6dlFvOEVrN1dMTURvd0NnWUlLb1pJemowRUF3TXcKTnpFVk1CTUdBMVVFQ2hNTWMybG5jM1J2Y21VdVpHVjJNUjR3SEFZRFZRUURFeFZ6YVdkemRHOXlaUzFwYm5SbApjbTFsWkdsaGRHVXdIaGNOTWpJd09ESTJNREV4TnpFM1doY05Nakl3T0RJMk1ERXlOekUzV2pBQU1Ga3dFd1lICktvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUVLWmZEQzlpalVyclpBWE9jWFYrQXFHRUlTSlEzVHRqSndJdEEKdTE3Rml2aWpnSk1hYUhGNDcrT3Z2OVR1ekFDQ3lpSUV5UDUyZXI2ZmF5bmZKYVVqOEtPQ0FVa3dnZ0ZGTUE0RwpBMVVkRHdFQi93UUVBd0lIZ0RBVEJnTlZIU1VFRERBS0JnZ3JCZ0VGQlFjREF6QWRCZ05WSFE0RUZnUVVHQldUCkMwdUU3dTRQcURVRjFYV0c0QlVWVUpBd0h3WURWUjBqQkJnd0ZvQVUzOVBwejFZa0VaYjVxTmpwS0ZXaXhpNFkKWkQ4d0pRWURWUjBSQVFIL0JCc3dHWUVYYzJGemIyRnJhWEpoTmpFeE5FQm5iV0ZwYkM1amIyMHdLUVlLS3dZQgpCQUdEdnpBQkFRUWJhSFIwY0hNNkx5OWhZMk52ZFc1MGN5NW5iMjluYkdVdVkyOXRNSUdMQmdvckJnRUVBZFo1CkFnUUNCSDBFZXdCNUFIY0FDR0NTOENoUy8yaEYwZEZySjRTY1JXY1lyQlk5d3pqU2JlYThJZ1kyYjNJQUFBR0MKMTdtSmhnQUFCQU1BU0RCR0FpRUFoS09BSkdWVlhCb1cxTDR4alk5eWJWOGZUUXN5TStvUEpIeDk5S29LYUpVQwpJUURCZDllc1Q0Mk1STng3Vm9BM1paKzV4akhNZWR6amVxQ2ZoZTcvd1pxYTlUQUtCZ2dxaGtqT1BRUURBd05vCkFEQmxBakVBcnBkeXlFRjc3b2JyTENMUXpzYmIxM2lsNjd3dzM4Y050amdNQml6Y2VUakRiY2VLeVFSN1RKNHMKZENsclkxY1BBakE4aXB6SUQ4VU1CaGxkSmUvZXJGcGdtN2swNWFic2lPN3V5dVZuS29VNk0rTXJ6VVUrZTlGdwpJRGhCanVRa1dRYz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=" + } + } + ] + } + ` + resp, err := http.Post(fmt.Sprintf("%s/api/v1/log/entries/retrieve", rekorServer()), + "application/json", + bytes.NewBuffer([]byte(body))) + if err != nil { + t.Fatal(err) + } + c, _ := ioutil.ReadAll(resp.Body) + if resp.StatusCode != 400 { + t.Fatalf("expected status 400, got %d instead: %v", resp.StatusCode, string(c)) + } +} + +func TestValidationSearchIntotoV002MissingPayloadHash(t *testing.T) { + body := `{ + "entries":[ + { + "kind":"intoto", + "apiVersion": "0.0.2", + "spec":{ + "content":{ + "envelope":{ + "payloadType":"asd", + "signatures":[ {} ] + }, + "hash":{ + "algorithm":"sha256", + "value":"782143e39f1e7a04e3f6da2d88b1c057e5657363c4f90679f3e8a071b7619e02" + }, + }, + "publicKey":"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNwRENDQWlxZ0F3SUJBZ0lVYWhsOEFRd1lZV05ZbnV6dlFvOEVrN1dMTURvd0NnWUlLb1pJemowRUF3TXcKTnpFVk1CTUdBMVVFQ2hNTWMybG5jM1J2Y21VdVpHVjJNUjR3SEFZRFZRUURFeFZ6YVdkemRHOXlaUzFwYm5SbApjbTFsWkdsaGRHVXdIaGNOTWpJd09ESTJNREV4TnpFM1doY05Nakl3T0RJMk1ERXlOekUzV2pBQU1Ga3dFd1lICktvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUVLWmZEQzlpalVyclpBWE9jWFYrQXFHRUlTSlEzVHRqSndJdEEKdTE3Rml2aWpnSk1hYUhGNDcrT3Z2OVR1ekFDQ3lpSUV5UDUyZXI2ZmF5bmZKYVVqOEtPQ0FVa3dnZ0ZGTUE0RwpBMVVkRHdFQi93UUVBd0lIZ0RBVEJnTlZIU1VFRERBS0JnZ3JCZ0VGQlFjREF6QWRCZ05WSFE0RUZnUVVHQldUCkMwdUU3dTRQcURVRjFYV0c0QlVWVUpBd0h3WURWUjBqQkJnd0ZvQVUzOVBwejFZa0VaYjVxTmpwS0ZXaXhpNFkKWkQ4d0pRWURWUjBSQVFIL0JCc3dHWUVYYzJGemIyRnJhWEpoTmpFeE5FQm5iV0ZwYkM1amIyMHdLUVlLS3dZQgpCQUdEdnpBQkFRUWJhSFIwY0hNNkx5OWhZMk52ZFc1MGN5NW5iMjluYkdVdVkyOXRNSUdMQmdvckJnRUVBZFo1CkFnUUNCSDBFZXdCNUFIY0FDR0NTOENoUy8yaEYwZEZySjRTY1JXY1lyQlk5d3pqU2JlYThJZ1kyYjNJQUFBR0MKMTdtSmhnQUFCQU1BU0RCR0FpRUFoS09BSkdWVlhCb1cxTDR4alk5eWJWOGZUUXN5TStvUEpIeDk5S29LYUpVQwpJUURCZDllc1Q0Mk1STng3Vm9BM1paKzV4akhNZWR6amVxQ2ZoZTcvd1pxYTlUQUtCZ2dxaGtqT1BRUURBd05vCkFEQmxBakVBcnBkeXlFRjc3b2JyTENMUXpzYmIxM2lsNjd3dzM4Y050amdNQml6Y2VUakRiY2VLeVFSN1RKNHMKZENsclkxY1BBakE4aXB6SUQ4VU1CaGxkSmUvZXJGcGdtN2swNWFic2lPN3V5dVZuS29VNk0rTXJ6VVUrZTlGdwpJRGhCanVRa1dRYz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=" + } + } + ] + } + ` + resp, err := http.Post(fmt.Sprintf("%s/api/v1/log/entries/retrieve", rekorServer()), + "application/json", + bytes.NewBuffer([]byte(body))) + if err != nil { + t.Fatal(err) + } + c, _ := ioutil.ReadAll(resp.Body) + if resp.StatusCode != 400 { + t.Fatalf("expected status 400, got %d instead: %v", resp.StatusCode, string(c)) + } +} + +func TestValidationSearchIntotoV001MissingPayloadHash(t *testing.T) { + body := `{ + "entries":[ + { + "kind":"intoto", + "apiVersion": "0.0.1", + "spec":{ + "content":{ + "hash":{ + "algorithm":"sha256", + "value":"ebbfddda6277af199e93c5bb5cf5998a79311de238e49bcc8ac24102698761bb" + } + }, + "publicKey":"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNwRENDQWlxZ0F3SUJBZ0lVYWhsOEFRd1lZV05ZbnV6dlFvOEVrN1dMTURvd0NnWUlLb1pJemowRUF3TXcKTnpFVk1CTUdBMVVFQ2hNTWMybG5jM1J2Y21VdVpHVjJNUjR3SEFZRFZRUURFeFZ6YVdkemRHOXlaUzFwYm5SbApjbTFsWkdsaGRHVXdIaGNOTWpJd09ESTJNREV4TnpFM1doY05Nakl3T0RJMk1ERXlOekUzV2pBQU1Ga3dFd1lICktvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUVLWmZEQzlpalVyclpBWE9jWFYrQXFHRUlTSlEzVHRqSndJdEEKdTE3Rml2aWpnSk1hYUhGNDcrT3Z2OVR1ekFDQ3lpSUV5UDUyZXI2ZmF5bmZKYVVqOEtPQ0FVa3dnZ0ZGTUE0RwpBMVVkRHdFQi93UUVBd0lIZ0RBVEJnTlZIU1VFRERBS0JnZ3JCZ0VGQlFjREF6QWRCZ05WSFE0RUZnUVVHQldUCkMwdUU3dTRQcURVRjFYV0c0QlVWVUpBd0h3WURWUjBqQkJnd0ZvQVUzOVBwejFZa0VaYjVxTmpwS0ZXaXhpNFkKWkQ4d0pRWURWUjBSQVFIL0JCc3dHWUVYYzJGemIyRnJhWEpoTmpFeE5FQm5iV0ZwYkM1amIyMHdLUVlLS3dZQgpCQUdEdnpBQkFRUWJhSFIwY0hNNkx5OWhZMk52ZFc1MGN5NW5iMjluYkdVdVkyOXRNSUdMQmdvckJnRUVBZFo1CkFnUUNCSDBFZXdCNUFIY0FDR0NTOENoUy8yaEYwZEZySjRTY1JXY1lyQlk5d3pqU2JlYThJZ1kyYjNJQUFBR0MKMTdtSmhnQUFCQU1BU0RCR0FpRUFoS09BSkdWVlhCb1cxTDR4alk5eWJWOGZUUXN5TStvUEpIeDk5S29LYUpVQwpJUURCZDllc1Q0Mk1STng3Vm9BM1paKzV4akhNZWR6amVxQ2ZoZTcvd1pxYTlUQUtCZ2dxaGtqT1BRUURBd05vCkFEQmxBakVBcnBkeXlFRjc3b2JyTENMUXpzYmIxM2lsNjd3dzM4Y050amdNQml6Y2VUakRiY2VLeVFSN1RKNHMKZENsclkxY1BBakE4aXB6SUQ4VU1CaGxkSmUvZXJGcGdtN2swNWFic2lPN3V5dVZuS29VNk0rTXJ6VVUrZTlGdwpJRGhCanVRa1dRYz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=" + } + } + ] + } + ` + resp, err := http.Post(fmt.Sprintf("%s/api/v1/log/entries/retrieve", rekorServer()), + "application/json", + bytes.NewBuffer([]byte(body))) + if err != nil { + t.Fatal(err) + } + c, _ := ioutil.ReadAll(resp.Body) + // No failure when payload hash is not present for canonicalization + if resp.StatusCode != 200 { + t.Fatalf("expected status 200, got %d instead: %v", resp.StatusCode, string(c)) + } +} diff --git a/pkg/types/intoto/fuzz_test.go b/pkg/types/intoto/fuzz_test.go deleted file mode 100644 index aa9cb0b2d..000000000 --- a/pkg/types/intoto/fuzz_test.go +++ /dev/null @@ -1,42 +0,0 @@ -// -// Copyright 2022 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 intoto - -import ( - "context" - "testing" - - fuzz "github.com/AdaLogics/go-fuzz-headers" - - "github.com/sigstore/rekor/pkg/types" -) - -func FuzzIntotoCreateProposedEntry(f *testing.F) { - f.Fuzz(func(t *testing.T, version string, propsData []byte) { - ff := fuzz.NewConsumer(propsData) - props := types.ArtifactProperties{} - ff.GenerateStruct(&props) - it := New() - entry, err := it.CreateProposedEntry(context.Background(), version, props) - if err != nil { - t.Skip() - } - _, err = it.UnmarshalEntry(entry) - if err != nil { - t.Skip() - } - }) -} diff --git a/pkg/types/intoto/intoto_test.go b/pkg/types/intoto/intoto_test.go index 69a9bbb85..782e50f9b 100644 --- a/pkg/types/intoto/intoto_test.go +++ b/pkg/types/intoto/intoto_test.go @@ -22,6 +22,7 @@ import ( "github.com/go-openapi/swag" "github.com/sigstore/rekor/pkg/generated/models" + "github.com/sigstore/rekor/pkg/pki" "github.com/sigstore/rekor/pkg/types" ) @@ -38,10 +39,14 @@ func (u UnmarshalFailsTester) NewEntry() types.EntryImpl { return &UnmarshalFailsTester{} } -func (u UnmarshalFailsTester) Unmarshal(pe models.ProposedEntry) error { +func (u UnmarshalFailsTester) Unmarshal(_ models.ProposedEntry) error { return errors.New("error") } +func (u UnmarshalFailsTester) Verifiers() ([]pki.PublicKey, error) { + return nil, nil +} + func TestIntotoType(t *testing.T) { // empty to start if VersionMap.Count() != 0 { diff --git a/pkg/types/intoto/v0.0.1/entry.go b/pkg/types/intoto/v0.0.1/entry.go index a07ded9af..ceb7371d5 100644 --- a/pkg/types/intoto/v0.0.1/entry.go +++ b/pkg/types/intoto/v0.0.1/entry.go @@ -183,10 +183,18 @@ func (v *V001Entry) Unmarshal(pe models.ProposedEntry) error { return v.validate() } -func (v *V001Entry) Canonicalize(ctx context.Context) ([]byte, error) { +func (v *V001Entry) Canonicalize(_ context.Context) ([]byte, error) { if v.keyObj == nil { - return nil, errors.New("cannot canonicalze empty key") + return nil, errors.New("cannot canonicalize empty key") } + if v.IntotoObj.Content == nil { + return nil, errors.New("missing content") + } + if v.IntotoObj.Content.Hash == nil { + return nil, errors.New("missing envelope hash") + } + // PayloadHash is not present for old entries + pk, err := v.keyObj.CanonicalValue() if err != nil { return nil, err @@ -200,12 +208,15 @@ func (v *V001Entry) Canonicalize(ctx context.Context) ([]byte, error) { Algorithm: v.IntotoObj.Content.Hash.Algorithm, Value: v.IntotoObj.Content.Hash.Value, }, - PayloadHash: &models.IntotoV001SchemaContentPayloadHash{ - Algorithm: v.IntotoObj.Content.PayloadHash.Algorithm, - Value: v.IntotoObj.Content.PayloadHash.Value, - }, }, } + // Set PayloadHash if present + if v.IntotoObj.Content.PayloadHash != nil { + canonicalEntry.Content.PayloadHash = &models.IntotoV001SchemaContentPayloadHash{ + Algorithm: v.IntotoObj.Content.PayloadHash.Algorithm, + Value: v.IntotoObj.Content.PayloadHash.Value, + } + } itObj := models.Intoto{} itObj.APIVersion = swag.String(APIVERSION) @@ -219,10 +230,25 @@ func (v *V001Entry) validate() error { // TODO handle multiple pk := v.keyObj.(*x509.PublicKey) - // This also gets called in the CLI, where we won't have this data + // one of two cases must be true: + // - ProposedEntry: client gives an envelope; (client provided hash/payloadhash are ignored as they are computed server-side) OR + // - CommittedEntry: NO envelope and hash/payloadHash must be present if v.IntotoObj.Content.Envelope == "" { + if v.IntotoObj.Content.Hash == nil { + return fmt.Errorf("missing hash value for envelope") + } else if err := v.IntotoObj.Content.Hash.Validate(strfmt.Default); err != nil { + return fmt.Errorf("validation error on envelope hash: %w", err) + } + // PayloadHash is not present for old entries + if v.IntotoObj.Content.PayloadHash != nil { + if err := v.IntotoObj.Content.PayloadHash.Validate(strfmt.Default); err != nil { + return fmt.Errorf("validation error on payload hash: %w", err) + } + } + // if there is no envelope, and hash/payloadHash are valid, then there's nothing else to do here return nil } + vfr, err := signature.LoadVerifier(pk.CryptoPubKey(), crypto.SHA256) if err != nil { return err @@ -326,3 +352,35 @@ func (v V001Entry) CreateFromArtifactProperties(_ context.Context, props types.A return &returnVal, nil } + +func (v V001Entry) Verifiers() ([]pki.PublicKey, error) { + if v.IntotoObj.PublicKey == nil { + return nil, errors.New("intoto v0.0.1 entry not initialized") + } + key, err := x509.NewPublicKey(bytes.NewReader(*v.IntotoObj.PublicKey)) + if err != nil { + return nil, err + } + return []pki.PublicKey{key}, nil +} + +func (v V001Entry) Insertable() (bool, error) { + if v.IntotoObj.Content == nil { + return false, errors.New("missing content property") + } + if len(v.IntotoObj.Content.Envelope) == 0 { + return false, errors.New("missing envelope content") + } + + if v.IntotoObj.PublicKey == nil || len(*v.IntotoObj.PublicKey) == 0 { + return false, errors.New("missing publicKey content") + } + + if v.keyObj == nil { + return false, errors.New("failed to parse public key") + } + if v.env.Payload == "" || v.env.PayloadType == "" || len(v.env.Signatures) == 0 { + return false, errors.New("invalid DSSE envelope") + } + return true, nil +} diff --git a/pkg/types/intoto/v0.0.1/entry_test.go b/pkg/types/intoto/v0.0.1/entry_test.go index f01b85450..23eb54939 100644 --- a/pkg/types/intoto/v0.0.1/entry_test.go +++ b/pkg/types/intoto/v0.0.1/entry_test.go @@ -42,9 +42,11 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/in-toto/in-toto-golang/in_toto" + "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/common" slsa "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.2" "github.com/secure-systems-lab/go-securesystemslib/dsse" "github.com/sigstore/rekor/pkg/generated/models" + pkix509 "github.com/sigstore/rekor/pkg/pki/x509" "github.com/sigstore/rekor/pkg/types" "github.com/sigstore/sigstore/pkg/signature" dsse_signer "github.com/sigstore/sigstore/pkg/signature/dsse" @@ -134,51 +136,100 @@ func TestV001Entry_Unmarshal(t *testing.T) { it *models.IntotoV001Schema wantErr bool additionalIndexKeys []string + wantVerifierErr bool }{ { - name: "empty", - it: &models.IntotoV001Schema{}, - wantErr: true, + name: "empty", + it: &models.IntotoV001Schema{}, + wantErr: true, + wantVerifierErr: true, }, { name: "missing envelope", it: &models.IntotoV001Schema{ PublicKey: p(pub), }, - wantErr: true, + wantErr: true, + wantVerifierErr: false, }, { - name: "missing envelope", + name: "invalid key", it: &models.IntotoV001Schema{ PublicKey: p([]byte("hello")), }, - wantErr: true, + wantErr: true, + wantVerifierErr: true, }, { name: "valid intoto", + it: &models.IntotoV001Schema{ + PublicKey: p(pub), + Content: &models.IntotoV001SchemaContent{ + Envelope: envelope(t, key, validPayload, "application/vnd.in-toto+json"), + }, + }, + wantErr: false, + wantVerifierErr: false, + }, + { + name: "valid intoto but hash specified by client (should be ignored)", it: &models.IntotoV001Schema{ PublicKey: p(pub), Content: &models.IntotoV001SchemaContent{ Envelope: envelope(t, key, validPayload, "application/vnd.in-toto+json"), Hash: &models.IntotoV001SchemaContentHash{ Algorithm: swag.String(models.IntotoV001SchemaContentHashAlgorithmSha256), + Value: swag.String("1a1707bb54e5fb4deddd19f07adcb4f1e022ca7879e3c8348da8d4fa496ae8e2"), }, }, }, - wantErr: false, + wantErr: false, + wantVerifierErr: false, }, { - name: "valid dsse but invalid intoto", + name: "valid intoto but payloadhash specified by client (should be ignored)", it: &models.IntotoV001Schema{ PublicKey: p(pub), Content: &models.IntotoV001SchemaContent{ - Envelope: envelope(t, key, validPayload, "text"), + Envelope: envelope(t, key, validPayload, "application/vnd.in-toto+json"), + PayloadHash: &models.IntotoV001SchemaContentPayloadHash{ + Algorithm: swag.String(models.IntotoV001SchemaContentPayloadHashAlgorithmSha256), + Value: swag.String("1a1707bb54e5fb4deddd19f07adcb4f1e022ca7879e3c8348da8d4fa496ae8e2"), + }, + }, + }, + wantErr: false, + wantVerifierErr: false, + }, + { + name: "valid intoto but envelope and payloadhash specified by client (hash values should be ignored)", + it: &models.IntotoV001Schema{ + PublicKey: p(pub), + Content: &models.IntotoV001SchemaContent{ + Envelope: envelope(t, key, validPayload, "application/vnd.in-toto+json"), Hash: &models.IntotoV001SchemaContentHash{ Algorithm: swag.String(models.IntotoV001SchemaContentHashAlgorithmSha256), + Value: swag.String("1a1707bb54e5fb4deddd19f07adcb4f1e022ca7879e3c8348da8d4fa496ae8e2"), }, + PayloadHash: &models.IntotoV001SchemaContentPayloadHash{ + Algorithm: swag.String(models.IntotoV001SchemaContentPayloadHashAlgorithmSha256), + Value: swag.String("1a1707bb54e5fb4deddd19f07adcb4f1e022ca7879e3c8348da8d4fa496ae8e2"), + }, + }, + }, + wantErr: false, + wantVerifierErr: false, + }, + { + name: "valid dsse but invalid intoto", + it: &models.IntotoV001Schema{ + PublicKey: p(pub), + Content: &models.IntotoV001SchemaContent{ + Envelope: envelope(t, key, validPayload, "text"), }, }, - wantErr: false, + wantErr: false, + wantVerifierErr: false, }, { name: "cert", @@ -186,13 +237,11 @@ func TestV001Entry_Unmarshal(t *testing.T) { PublicKey: p([]byte(pemBytes)), Content: &models.IntotoV001SchemaContent{ Envelope: envelope(t, priv, validPayload, "text"), - Hash: &models.IntotoV001SchemaContentHash{ - Algorithm: swag.String(models.IntotoV001SchemaContentHashAlgorithmSha256), - }, }, }, additionalIndexKeys: []string{"joe@schmoe.com"}, wantErr: false, + wantVerifierErr: false, }, { name: "invalid", @@ -200,12 +249,10 @@ func TestV001Entry_Unmarshal(t *testing.T) { PublicKey: p(pub), Content: &models.IntotoV001SchemaContent{ Envelope: string(invalid), - Hash: &models.IntotoV001SchemaContentHash{ - Algorithm: swag.String(models.IntotoV001SchemaContentHashAlgorithmSha256), - }, }, }, - wantErr: true, + wantErr: true, + wantVerifierErr: false, }, { name: "invalid key", @@ -213,22 +260,15 @@ func TestV001Entry_Unmarshal(t *testing.T) { PublicKey: p([]byte("notavalidkey")), Content: &models.IntotoV001SchemaContent{ Envelope: envelope(t, key, validPayload, "text"), - Hash: &models.IntotoV001SchemaContentHash{ - Algorithm: swag.String(models.IntotoV001SchemaContentHashAlgorithmSha256), - }, }, }, - wantErr: true, + wantErr: true, + wantVerifierErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { v := &V001Entry{} - if tt.it.Content != nil { - h := sha256.Sum256([]byte(tt.it.Content.Envelope)) - tt.it.Content.Hash.Algorithm = swag.String(models.IntotoV001SchemaContentHashAlgorithmSha256) - tt.it.Content.Hash.Value = swag.String(hex.EncodeToString(h[:])) - } it := &models.Intoto{ Spec: tt.it, @@ -238,9 +278,13 @@ func TestV001Entry_Unmarshal(t *testing.T) { if err := v.Unmarshal(it); err != nil { return err } - if err := v.validate(); err != nil { - return err + + if !tt.wantErr { + if ok, err := v.Insertable(); !ok || err != nil { + t.Errorf("unexpected error calling Insertable on valid proposed entry: %v", err) + } } + if v.IntotoObj.Content.Hash == nil || v.IntotoObj.Content.Hash.Algorithm != tt.it.Content.Hash.Algorithm || v.IntotoObj.Content.Hash.Value != tt.it.Content.Hash.Value { return errors.New("missing envelope hash in validated object") } @@ -274,6 +318,11 @@ func TestV001Entry_Unmarshal(t *testing.T) { if err != nil { t.Errorf("unexpected err from type-specific unmarshalling for '%v': %v", tt.name, err) } + + if ok, err := canonicalEntry.Insertable(); ok || err == nil { + t.Errorf("unexpected success calling Insertable on entry created from canonicalized content") + } + canonicalV001 := canonicalEntry.(*V001Entry) fmt.Printf("%v", canonicalV001.IntotoObj.Content) if *canonicalV001.IntotoObj.Content.Hash.Value != *tt.it.Content.Hash.Value { @@ -287,6 +336,23 @@ func TestV001Entry_Unmarshal(t *testing.T) { t.Errorf("index keys from hydrated object do not match those generated from canonicalized (and re-hydrated) object: %v %v", got, canonicalIndexKeys) } + verifiers, err := v.Verifiers() + if !tt.wantVerifierErr { + if err != nil { + t.Errorf("%v: unexpected error, got %v", tt.name, err) + } else { + pubV, _ := verifiers[0].CanonicalValue() + if !reflect.DeepEqual(pubV, pub) && !reflect.DeepEqual(pubV, pemBytes) { + t.Errorf("verifier and public keys do not match: %v, %v", string(pubV), string(pub)) + } + } + } else { + if err == nil { + s, _ := verifiers[0].CanonicalValue() + t.Errorf("%v: expected error for %v, got %v", tt.name, string(s), err) + } + } + return nil } if err := uv(); (err != nil) != tt.wantErr { @@ -296,6 +362,43 @@ func TestV001Entry_Unmarshal(t *testing.T) { } } +// Demonstrates that Unmarshal and Canonicalize will succeed with only a hash, +// since committed entries will have no envelope and may have no payload hash +func TestV001EntryWithoutEnvelopeOrPayloadHash(t *testing.T) { + key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + t.Fatal(err) + } + der, err := x509.MarshalPKIXPublicKey(&key.PublicKey) + if err != nil { + t.Fatal(err) + } + pub := pem.EncodeToMemory(&pem.Block{ + Bytes: der, + Type: "PUBLIC KEY", + }) + m := &models.IntotoV001Schema{ + PublicKey: p(pub), + Content: &models.IntotoV001SchemaContent{ + Hash: &models.IntotoV001SchemaContentHash{ + Algorithm: swag.String(models.IntotoV001SchemaContentHashAlgorithmSha256), + Value: swag.String("1a1707bb54e5fb4deddd19f07adcb4f1e022ca7879e3c8348da8d4fa496ae8e2"), + }, + }, + } + v := &V001Entry{} + it := &models.Intoto{ + Spec: m, + } + if err := v.Unmarshal(it); err != nil { + t.Fatalf("error umarshalling intoto without envelope: %v", err) + } + _, err = v.Canonicalize(context.TODO()) + if err != nil { + t.Fatalf("error canonicalizing intoto without envelope: %v", err) + } +} + func TestV001Entry_IndexKeys(t *testing.T) { h := sha256.Sum256([]byte("foo")) dataSHA := hex.EncodeToString(h[:]) @@ -335,7 +438,7 @@ func TestV001Entry_IndexKeys(t *testing.T) { want: []string{"sha256:bar", hashkey}, statement: in_toto.Statement{ Predicate: slsa.ProvenancePredicate{ - Materials: []slsa.ProvenanceMaterial{ + Materials: []common.ProvenanceMaterial{ { URI: "foo", Digest: map[string]string{ @@ -385,3 +488,136 @@ func TestV001Entry_IndexKeys(t *testing.T) { }) } } + +func TestInsertable(t *testing.T) { + type TestCase struct { + caseDesc string + entry V001Entry + expectSuccess bool + } + + key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + t.Fatal(err) + } + der, err := x509.MarshalPKIXPublicKey(&key.PublicKey) + if err != nil { + t.Fatal(err) + } + pub := pem.EncodeToMemory(&pem.Block{ + Bytes: der, + Type: "PUBLIC KEY", + }) + keyObj, err := pkix509.NewPublicKey(bytes.NewReader(pub)) + if err != nil { + t.Fatal(err) + } + + envStr := envelope(t, key, "payload", "payloadType") + env := dsse.Envelope{} + + if err := json.Unmarshal([]byte(envStr), &env); err != nil { + t.Fatal(err) + } + + testCases := []TestCase{ + { + caseDesc: "valid entry", + entry: V001Entry{ + IntotoObj: models.IntotoV001Schema{ + Content: &models.IntotoV001SchemaContent{ + Envelope: "envelope", + }, + PublicKey: p(pub), + }, + keyObj: keyObj, + env: env, + }, + expectSuccess: true, + }, + { + caseDesc: "missing parsed keyObj", + entry: V001Entry{ + IntotoObj: models.IntotoV001Schema{ + Content: &models.IntotoV001SchemaContent{ + Envelope: "envelope", + }, + PublicKey: p(pub), + }, + env: env, + }, + expectSuccess: false, + }, + { + caseDesc: "missing parsed DSSE envelope", + entry: V001Entry{ + IntotoObj: models.IntotoV001Schema{ + Content: &models.IntotoV001SchemaContent{ + Envelope: "envelope", + }, + PublicKey: p(pub), + }, + keyObj: keyObj, + }, + expectSuccess: false, + }, + { + caseDesc: "missing content", + entry: V001Entry{ + IntotoObj: models.IntotoV001Schema{ + PublicKey: p(pub), + }, + keyObj: keyObj, + env: env, + }, + expectSuccess: false, + }, + { + caseDesc: "missing envelope string", + entry: V001Entry{ + IntotoObj: models.IntotoV001Schema{ + Content: &models.IntotoV001SchemaContent{}, + PublicKey: p(pub), + }, + keyObj: keyObj, + env: env, + }, + expectSuccess: false, + }, + { + caseDesc: "missing unparsed public key", + entry: V001Entry{ + IntotoObj: models.IntotoV001Schema{ + Content: &models.IntotoV001SchemaContent{ + Envelope: "envelope", + }, + }, + keyObj: keyObj, + env: env, + }, + expectSuccess: false, + }, + { + caseDesc: "empty parsed DSSE envelope", + entry: V001Entry{ + IntotoObj: models.IntotoV001Schema{ + Content: &models.IntotoV001SchemaContent{ + Envelope: "envelope", + }, + PublicKey: p(pub), + }, + keyObj: keyObj, + env: dsse.Envelope{}, + }, + expectSuccess: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.caseDesc, func(t *testing.T) { + if ok, err := tc.entry.Insertable(); ok != tc.expectSuccess { + t.Errorf("unexpected result calling Insertable: %v", err) + } + }) + } +} diff --git a/pkg/types/intoto/v0.0.1/fuzz_test.go b/pkg/types/intoto/v0.0.1/fuzz_test.go new file mode 100644 index 000000000..feda07695 --- /dev/null +++ b/pkg/types/intoto/v0.0.1/fuzz_test.go @@ -0,0 +1,100 @@ +// +// Copyright 2022 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 intoto + +import ( + "context" + "sync" + "testing" + + fuzz "github.com/AdamKorcz/go-fuzz-headers-1" + "github.com/go-openapi/swag" + + fuzzUtils "github.com/sigstore/rekor/pkg/fuzz" + "github.com/sigstore/rekor/pkg/generated/models" + "github.com/sigstore/rekor/pkg/types" + "github.com/sigstore/rekor/pkg/types/intoto" +) + +var initter sync.Once + +func FuzzIntotoCreateProposedEntry(f *testing.F) { + f.Fuzz(func(t *testing.T, propsData []byte) { + initter.Do(fuzzUtils.SetFuzzLogger) + + version := "0.0.1" + + ff := fuzz.NewConsumer(propsData) + + props, cleanup, err := fuzzUtils.CreateProps(ff, "intotoV001") + if err != nil { + t.Skip() + } + defer func() { + for _, c := range cleanup { + c() + } + }() + + it := intoto.New() + entry, err := it.CreateProposedEntry(context.Background(), version, props) + if err != nil { + t.Skip() + } + ei, err := types.CreateVersionedEntry(entry) + if err != nil { + t.Skip() + } + + if ok, err := ei.Insertable(); !ok || err != nil { + t.Errorf("entry created via CreateProposedEntry should be insertable: %v", err) + } + + if _, err := types.CanonicalizeEntry(context.Background(), ei); err != nil { + t.Errorf("valid insertable entry should be able to be canonicalized: %v", err) + } + + _, _ = ei.IndexKeys() + }) +} + +func FuzzIntotoUnmarshalAndCanonicalize(f *testing.F) { + f.Fuzz(func(t *testing.T, entryData []byte) { + initter.Do(fuzzUtils.SetFuzzLogger) + + ff := fuzz.NewConsumer(entryData) + + targetV001 := &models.IntotoV001Schema{} + + if err := ff.GenerateStruct(targetV001); err != nil { + t.Skip() + } + + targetEntry := &models.Intoto{ + APIVersion: swag.String(APIVERSION), + Spec: targetV001, + } + + ei, err := types.UnmarshalEntry(targetEntry) + if err != nil { + t.Skip() + } + + if _, err := types.CanonicalizeEntry(context.Background(), ei); err != nil { + t.Errorf("error canonicalizing unmarshalled entry: %v", err) + } + }) +} diff --git a/pkg/types/intoto/v0.0.1/intoto_v0_0_1_schema.json b/pkg/types/intoto/v0.0.1/intoto_v0_0_1_schema.json index 39117a661..814f98e33 100644 --- a/pkg/types/intoto/v0.0.1/intoto_v0_0_1_schema.json +++ b/pkg/types/intoto/v0.0.1/intoto_v0_0_1_schema.json @@ -14,7 +14,7 @@ "writeOnly": true }, "hash": { - "description": "Specifies the hash algorithm and value encompassing the entire signed envelope", + "description": "Specifies the hash algorithm and value encompassing the entire signed envelope; this is computed by the rekor server, client-provided values are ignored", "type": "object", "properties": { "algorithm": { @@ -36,7 +36,7 @@ "readOnly": true }, "payloadHash": { - "description": "Specifies the hash algorithm and value covering the payload within the DSSE envelope", + "description": "Specifies the hash algorithm and value covering the payload within the DSSE envelope; this is computed by the rekor server, client-provided values are ignored", "type": "object", "properties": { "algorithm": { diff --git a/pkg/types/intoto/v0.0.2/entry.go b/pkg/types/intoto/v0.0.2/entry.go index ae8d278ac..69a9b4c14 100644 --- a/pkg/types/intoto/v0.0.2/entry.go +++ b/pkg/types/intoto/v0.0.2/entry.go @@ -32,12 +32,14 @@ import ( "github.com/in-toto/in-toto-golang/in_toto" "github.com/secure-systems-lab/go-securesystemslib/dsse" "github.com/spf13/viper" + "golang.org/x/exp/slices" "github.com/go-openapi/strfmt" "github.com/go-openapi/swag" "github.com/sigstore/rekor/pkg/generated/models" "github.com/sigstore/rekor/pkg/log" + "github.com/sigstore/rekor/pkg/pki" "github.com/sigstore/rekor/pkg/pki/x509" "github.com/sigstore/rekor/pkg/types" "github.com/sigstore/rekor/pkg/types/intoto" @@ -77,7 +79,10 @@ func (v V002Entry) IndexKeys() ([]string, error) { } for _, sig := range v.IntotoObj.Content.Envelope.Signatures { - keyObj, err := x509.NewPublicKey(bytes.NewReader(sig.PublicKey)) + if sig == nil || sig.PublicKey == nil { + return result, errors.New("malformed or missing signature") + } + keyObj, err := x509.NewPublicKey(bytes.NewReader(*sig.PublicKey)) if err != nil { return result, err } @@ -181,13 +186,17 @@ func (v *V002Entry) Unmarshal(pe models.ProposedEntry) error { } allPubKeyBytes := make([][]byte, 0) - for _, sig := range v.IntotoObj.Content.Envelope.Signatures { + for i, sig := range v.IntotoObj.Content.Envelope.Signatures { + if sig == nil { + v.IntotoObj.Content.Envelope.Signatures = slices.Delete(v.IntotoObj.Content.Envelope.Signatures, i, i) + continue + } env.Signatures = append(env.Signatures, dsse.Signature{ KeyID: sig.Keyid, - Sig: string(sig.Sig), + Sig: string(*sig.Sig), }) - allPubKeyBytes = append(allPubKeyBytes, sig.PublicKey) + allPubKeyBytes = append(allPubKeyBytes, *sig.PublicKey) } if _, err := verifyEnvelope(allPubKeyBytes, env); err != nil { @@ -210,7 +219,30 @@ func (v *V002Entry) Unmarshal(pe models.ProposedEntry) error { return nil } -func (v *V002Entry) Canonicalize(ctx context.Context) ([]byte, error) { +func (v *V002Entry) Canonicalize(_ context.Context) ([]byte, error) { + if err := v.IntotoObj.Validate(strfmt.Default); err != nil { + return nil, err + } + + if v.IntotoObj.Content.Hash == nil { + return nil, errors.New("missing envelope digest") + } + + if err := v.IntotoObj.Content.Hash.Validate(strfmt.Default); err != nil { + return nil, fmt.Errorf("error validating envelope digest: %w", err) + } + + if v.IntotoObj.Content.PayloadHash == nil { + return nil, errors.New("missing payload digest") + } + + if err := v.IntotoObj.Content.PayloadHash.Validate(strfmt.Default); err != nil { + return nil, fmt.Errorf("error validating payload digest: %w", err) + } + + if len(v.IntotoObj.Content.Envelope.Signatures) == 0 { + return nil, errors.New("missing signatures") + } canonicalEntry := models.IntotoV002Schema{ Content: &models.IntotoV002SchemaContent{ @@ -270,7 +302,7 @@ func (v *verifier) Public() crypto.PublicKey { return nil } -func (v *verifier) Sign(data []byte) (sig []byte, err error) { +func (v *verifier) Sign(_ context.Context, data []byte) (sig []byte, err error) { if v.s == nil { return nil, errors.New("nil signer") } @@ -281,7 +313,7 @@ func (v *verifier) Sign(data []byte) (sig []byte, err error) { return sig, nil } -func (v *verifier) Verify(data, sig []byte) error { +func (v *verifier) Verify(_ context.Context, data, sig []byte) error { if v.v == nil { return errors.New("nil verifier") } @@ -357,10 +389,11 @@ func (v V002Entry) CreateFromArtifactProperties(_ context.Context, props types.A } keyBytes := strfmt.Base64(canonKey) + sigBytes := strfmt.Base64([]byte(sig.Sig)) re.IntotoObj.Content.Envelope.Signatures = append(re.IntotoObj.Content.Envelope.Signatures, &models.IntotoV002SchemaContentEnvelopeSignaturesItems0{ Keyid: sig.KeyID, - Sig: strfmt.Base64([]byte(sig.Sig)), - PublicKey: keyBytes, + Sig: &sigBytes, + PublicKey: &keyBytes, }) } @@ -406,7 +439,7 @@ func verifyEnvelope(allPubKeyBytes [][]byte, env *dsse.Envelope) (map[string]*x5 return nil, fmt.Errorf("could not use public key as a dsse verifier: %w", err) } - accepted, err := dsseVfr.Verify(env) + accepted, err := dsseVfr.Verify(context.Background(), env) if err != nil { return nil, fmt.Errorf("could not verify envelope: %w", err) } @@ -423,3 +456,61 @@ func verifyEnvelope(allPubKeyBytes [][]byte, env *dsse.Envelope) (map[string]*x5 return verifierBySig, nil } + +func (v V002Entry) Verifiers() ([]pki.PublicKey, error) { + if v.IntotoObj.Content == nil || v.IntotoObj.Content.Envelope == nil { + return nil, errors.New("intoto v0.0.2 entry not initialized") + } + + sigs := v.IntotoObj.Content.Envelope.Signatures + if len(sigs) == 0 { + return nil, errors.New("no signatures found on intoto entry") + } + + var keys []pki.PublicKey + for _, s := range v.IntotoObj.Content.Envelope.Signatures { + key, err := x509.NewPublicKey(bytes.NewReader(*s.PublicKey)) + if err != nil { + return nil, err + } + keys = append(keys, key) + } + return keys, nil +} + +func (v V002Entry) Insertable() (bool, error) { + if v.IntotoObj.Content == nil { + return false, errors.New("missing content property") + } + if v.IntotoObj.Content.Envelope == nil { + return false, errors.New("missing envelope property") + } + if len(v.IntotoObj.Content.Envelope.Payload) == 0 { + return false, errors.New("missing envelope content") + } + + if v.IntotoObj.Content.Envelope.PayloadType == nil || len(*v.IntotoObj.Content.Envelope.PayloadType) == 0 { + return false, errors.New("missing payloadType content") + } + + if len(v.IntotoObj.Content.Envelope.Signatures) == 0 { + return false, errors.New("missing signatures content") + } + for _, sig := range v.IntotoObj.Content.Envelope.Signatures { + if sig == nil { + return false, errors.New("missing signature entry") + } + if sig.Sig == nil || len(*sig.Sig) == 0 { + return false, errors.New("missing signature content") + } + if sig.PublicKey == nil || len(*sig.PublicKey) == 0 { + return false, errors.New("missing publicKey content") + } + } + + if v.env.Payload == "" || v.env.PayloadType == "" || len(v.env.Signatures) == 0 { + return false, errors.New("invalid DSSE envelope") + } + + return true, nil +} diff --git a/pkg/types/intoto/v0.0.2/entry_test.go b/pkg/types/intoto/v0.0.2/entry_test.go index 8b432d71d..cde69708e 100644 --- a/pkg/types/intoto/v0.0.2/entry_test.go +++ b/pkg/types/intoto/v0.0.2/entry_test.go @@ -40,6 +40,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/in-toto/in-toto-golang/in_toto" + "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/common" slsa "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.2" "github.com/secure-systems-lab/go-securesystemslib/dsse" "github.com/sigstore/rekor/pkg/generated/models" @@ -60,19 +61,18 @@ func TestNewEntryReturnType(t *testing.T) { } func envelope(t *testing.T, k *ecdsa.PrivateKey, payload []byte) *dsse.Envelope { - s, err := signature.LoadECDSASigner(k, crypto.SHA256) if err != nil { t.Fatal(err) } - signer, err := in_toto.NewDSSESigner( + signer, err := dsse.NewEnvelopeSigner( &verifier{ s: s, }) if err != nil { t.Fatal(err) } - dsseEnv, err := signer.SignPayload(payload) + dsseEnv, err := signer.SignPayload(context.Background(), "application/vnd.in-toto+json", payload) if err != nil { t.Fatal(err) } @@ -96,7 +96,7 @@ func multiSignEnvelope(t *testing.T, k []*ecdsa.PrivateKey, payload []byte) *dss if err != nil { t.Fatal(err) } - dsseEnv, err := signer.SignPayload(in_toto.PayloadType, payload) + dsseEnv, err := signer.SignPayload(context.Background(), in_toto.PayloadType, payload) if err != nil { t.Fatal(err) } @@ -105,19 +105,21 @@ func multiSignEnvelope(t *testing.T, k []*ecdsa.PrivateKey, payload []byte) *dss } func createRekorEnvelope(dsseEnv *dsse.Envelope, pub [][]byte) *models.IntotoV002SchemaContentEnvelope { - env := &models.IntotoV002SchemaContentEnvelope{} b64 := strfmt.Base64([]byte(dsseEnv.Payload)) env.Payload = b64 env.PayloadType = &dsseEnv.PayloadType for i, sig := range dsseEnv.Signatures { + keyBytes := strfmt.Base64(pub[i]) + sigBytes := strfmt.Base64([]byte(sig.Sig)) env.Signatures = append(env.Signatures, &models.IntotoV002SchemaContentEnvelopeSignaturesItems0{ Keyid: sig.KeyID, - Sig: strfmt.Base64([]byte(sig.Sig)), - PublicKey: strfmt.Base64(pub[i]), + Sig: &sigBytes, + PublicKey: &keyBytes, }) } + return env } @@ -126,6 +128,7 @@ func envelopeHash(t *testing.T, dsseEnv *dsse.Envelope) string { if err != nil { t.Fatal(err) } + h := sha256.Sum256(val) return hex.EncodeToString(h[:]) } @@ -171,17 +174,21 @@ func TestV002Entry_Unmarshal(t *testing.T) { } validPayload := "hellothispayloadisvalid" + keyBytes := strfmt.Base64("key") + sigBytes := strfmt.Base64("sig") tests := []struct { - env *dsse.Envelope - name string - it *models.IntotoV002Schema - wantErr bool + env *dsse.Envelope + name string + it *models.IntotoV002Schema + wantErr bool + wantVerifierErr bool }{ { - name: "empty", - it: &models.IntotoV002Schema{}, - wantErr: true, + name: "empty", + it: &models.IntotoV002Schema{}, + wantErr: true, + wantVerifierErr: true, }, { name: "missing envelope", @@ -192,7 +199,8 @@ func TestV002Entry_Unmarshal(t *testing.T) { }, }, }, - wantErr: true, + wantErr: true, + wantVerifierErr: true, }, { env: envelope(t, key, []byte(validPayload)), @@ -206,7 +214,8 @@ func TestV002Entry_Unmarshal(t *testing.T) { }, }, }, - wantErr: false, + wantErr: false, + wantVerifierErr: false, }, { env: envelope(t, priv, []byte(validPayload)), @@ -220,7 +229,8 @@ func TestV002Entry_Unmarshal(t *testing.T) { }, }, }, - wantErr: false, + wantErr: false, + wantVerifierErr: false, }, { env: &invalid, @@ -234,7 +244,8 @@ func TestV002Entry_Unmarshal(t *testing.T) { }, }, }, - wantErr: true, + wantErr: true, + wantVerifierErr: false, }, { env: envelope(t, key, []byte(validPayload)), @@ -248,7 +259,8 @@ func TestV002Entry_Unmarshal(t *testing.T) { }, }, }, - wantErr: true, + wantErr: true, + wantVerifierErr: true, }, { env: multiSignEnvelope(t, []*ecdsa.PrivateKey{key, priv}, []byte(validPayload)), @@ -262,7 +274,33 @@ func TestV002Entry_Unmarshal(t *testing.T) { }, }, }, - wantErr: false, + wantErr: false, + wantVerifierErr: false, + }, + { + env: envelope(t, key, []byte(validPayload)), + name: "null array entry", + it: &models.IntotoV002Schema{ + Content: &models.IntotoV002SchemaContent{ + Envelope: &models.IntotoV002SchemaContentEnvelope{ + Payload: strfmt.Base64("cGF5bG9hZAo="), + PayloadType: swag.String("payloadType"), + Signatures: []*models.IntotoV002SchemaContentEnvelopeSignaturesItems0{ + { + PublicKey: &keyBytes, + Sig: &sigBytes, + }, + nil, + }, + }, + Hash: &models.IntotoV002SchemaContentHash{ + Algorithm: swag.String(models.IntotoV002SchemaContentHashAlgorithmSha256), + Value: swag.String(envelopeHash(t, envelope(t, key, []byte(validPayload)))), + }, + }, + }, + wantErr: true, + wantVerifierErr: true, }, } for _, tt := range tests { @@ -277,9 +315,16 @@ func TestV002Entry_Unmarshal(t *testing.T) { if err := v.Unmarshal(it); err != nil { return err } + + if !tt.wantErr { + if ok, err := v.Insertable(); !ok || err != nil { + t.Errorf("unexpected error calling insertable on valid proposed entry: %v", err) + } + } + want := []string{} for _, sig := range v.IntotoObj.Content.Envelope.Signatures { - keyHash := sha256.Sum256(sig.PublicKey) + keyHash := sha256.Sum256(*sig.PublicKey) want = append(want, "sha256:"+hex.EncodeToString(keyHash[:])) } decodedPayload, err := base64.StdEncoding.DecodeString(tt.env.Payload) @@ -316,6 +361,9 @@ func TestV002Entry_Unmarshal(t *testing.T) { if err != nil { t.Errorf("unexpected err from type-specific unmarshalling for '%v': %v", tt.name, err) } + if ok, err := canonicalEntry.Insertable(); ok || err == nil { + t.Errorf("unexpected success calling Insertable on entry created from canonicalized content") + } canonicalV002 := canonicalEntry.(*V002Entry) fmt.Printf("%v", canonicalV002.IntotoObj.Content) if *canonicalV002.IntotoObj.Content.Hash.Value != *tt.it.Content.Hash.Value { @@ -329,6 +377,23 @@ func TestV002Entry_Unmarshal(t *testing.T) { t.Errorf("index keys from hydrated object do not match those generated from canonicalized (and re-hydrated) object: %v %v", got, canonicalIndexKeys) } + verifiers, err := v.Verifiers() + if !tt.wantVerifierErr { + if err != nil { + t.Errorf("%v: unexpected error, got %v", tt.name, err) + } else { + pubV, _ := verifiers[0].CanonicalValue() + if !reflect.DeepEqual(pubV, pub) && !reflect.DeepEqual(pubV, pemBytes) { + t.Errorf("verifier and public keys do not match: %v, %v", string(pubV), string(pub)) + } + } + } else { + if err == nil { + s, _ := verifiers[0].CanonicalValue() + t.Errorf("%v: expected error for %v, got %v", tt.name, string(s), err) + } + } + return nil } if err := uv(); (err != nil) != tt.wantErr { @@ -386,7 +451,7 @@ func TestV002Entry_IndexKeys(t *testing.T) { want: []string{"sha256:bar"}, statement: in_toto.Statement{ Predicate: slsa.ProvenancePredicate{ - Materials: []slsa.ProvenanceMaterial{ + Materials: []common.ProvenanceMaterial{ { URI: "foo", Digest: map[string]string{ @@ -411,7 +476,7 @@ func TestV002Entry_IndexKeys(t *testing.T) { }, }, Predicate: slsa.ProvenancePredicate{ - Materials: []slsa.ProvenanceMaterial{ + Materials: []common.ProvenanceMaterial{ { URI: "foo", Digest: map[string]string{ @@ -447,7 +512,7 @@ func TestV002Entry_IndexKeys(t *testing.T) { } want := []string{} for _, sig := range v.IntotoObj.Content.Envelope.Signatures { - keyHash := sha256.Sum256(sig.PublicKey) + keyHash := sha256.Sum256(*sig.PublicKey) want = append(want, "sha256:"+hex.EncodeToString(keyHash[:])) } @@ -463,3 +528,227 @@ func TestV002Entry_IndexKeys(t *testing.T) { }) } } + +func TestInsertable(t *testing.T) { + type TestCase struct { + caseDesc string + entry V002Entry + expectSuccess bool + } + + key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + t.Fatal(err) + } + + env := envelope(t, key, []byte("payload")) + keyBytes := strfmt.Base64([]byte("key")) + sigBytes := strfmt.Base64([]byte("sig")) + + testCases := []TestCase{ + { + caseDesc: "valid entry", + entry: V002Entry{ + IntotoObj: models.IntotoV002Schema{ + Content: &models.IntotoV002SchemaContent{ + Envelope: &models.IntotoV002SchemaContentEnvelope{ + Payload: strfmt.Base64("payload"), + PayloadType: swag.String("payloadType"), + Signatures: []*models.IntotoV002SchemaContentEnvelopeSignaturesItems0{ + { + PublicKey: &keyBytes, + Sig: &sigBytes, + }, + }, + }, + }, + }, + env: *env, + }, + expectSuccess: true, + }, + { + caseDesc: "valid entry but hasn't been parsed", + entry: V002Entry{ + IntotoObj: models.IntotoV002Schema{ + Content: &models.IntotoV002SchemaContent{ + Envelope: &models.IntotoV002SchemaContentEnvelope{ + Payload: strfmt.Base64("payload"), + PayloadType: swag.String("payloadType"), + Signatures: []*models.IntotoV002SchemaContentEnvelopeSignaturesItems0{ + { + PublicKey: &keyBytes, + Sig: &sigBytes, + }, + }, + }, + }, + }, + env: dsse.Envelope{}, + }, + expectSuccess: false, + }, + { + caseDesc: "missing sig", + entry: V002Entry{ + IntotoObj: models.IntotoV002Schema{ + Content: &models.IntotoV002SchemaContent{ + Envelope: &models.IntotoV002SchemaContentEnvelope{ + Payload: strfmt.Base64("payload"), + PayloadType: swag.String("payloadType"), + Signatures: []*models.IntotoV002SchemaContentEnvelopeSignaturesItems0{ + { + PublicKey: &keyBytes, + //Sig: strfmt.Base64([]byte("sig")), + }, + }, + }, + }, + }, + env: *env, + }, + expectSuccess: false, + }, + { + caseDesc: "missing key", + entry: V002Entry{ + IntotoObj: models.IntotoV002Schema{ + Content: &models.IntotoV002SchemaContent{ + Envelope: &models.IntotoV002SchemaContentEnvelope{ + Payload: strfmt.Base64("payload"), + PayloadType: swag.String("payloadType"), + Signatures: []*models.IntotoV002SchemaContentEnvelopeSignaturesItems0{ + { + //PublicKey: strfmt.Base64([]byte("key")), + Sig: &sigBytes, + }, + }, + }, + }, + }, + env: *env, + }, + expectSuccess: false, + }, + { + caseDesc: "empty signatures", + entry: V002Entry{ + IntotoObj: models.IntotoV002Schema{ + Content: &models.IntotoV002SchemaContent{ + Envelope: &models.IntotoV002SchemaContentEnvelope{ + Payload: strfmt.Base64("payload"), + PayloadType: swag.String("payloadType"), + Signatures: []*models.IntotoV002SchemaContentEnvelopeSignaturesItems0{}, + /* + Signatures: []*models.IntotoV002SchemaContentEnvelopeSignaturesItems0{ + { + PublicKey: strfmt.Base64([]byte("key")), + Sig: strfmt.Base64([]byte("sig")), + }, + }, + */ + }, + }, + }, + env: *env, + }, + expectSuccess: false, + }, + { + caseDesc: "missing payloadType", + entry: V002Entry{ + IntotoObj: models.IntotoV002Schema{ + Content: &models.IntotoV002SchemaContent{ + Envelope: &models.IntotoV002SchemaContentEnvelope{ + Payload: strfmt.Base64("payload"), + //PayloadType: swag.String("payloadType"), + Signatures: []*models.IntotoV002SchemaContentEnvelopeSignaturesItems0{ + { + PublicKey: &keyBytes, + Sig: &sigBytes, + }, + }, + }, + }, + }, + env: *env, + }, + expectSuccess: false, + }, + { + caseDesc: "missing payload", + entry: V002Entry{ + IntotoObj: models.IntotoV002Schema{ + Content: &models.IntotoV002SchemaContent{ + Envelope: &models.IntotoV002SchemaContentEnvelope{ + //Payload: strfmt.Base64("payload"), + PayloadType: swag.String("payloadType"), + Signatures: []*models.IntotoV002SchemaContentEnvelopeSignaturesItems0{ + { + PublicKey: &keyBytes, + Sig: &sigBytes, + }, + }, + }, + }, + }, + env: *env, + }, + expectSuccess: false, + }, + { + caseDesc: "missing envelope", + entry: V002Entry{ + IntotoObj: models.IntotoV002Schema{ + Content: &models.IntotoV002SchemaContent{ + /* + Envelope: &models.IntotoV002SchemaContentEnvelope{ + Payload: strfmt.Base64("payload"), + PayloadType: swag.String("payloadType"), + Signatures: []*models.IntotoV002SchemaContentEnvelopeSignaturesItems0{ + { + PublicKey: strfmt.Base64([]byte("key")), + Sig: strfmt.Base64([]byte("sig")), + }, + }, + }, + */ + }, + }, + env: *env, + }, + expectSuccess: false, + }, + { + caseDesc: "missing content", + entry: V002Entry{ + IntotoObj: models.IntotoV002Schema{ + /* + Content: &models.IntotoV002SchemaContent{ + Envelope: &models.IntotoV002SchemaContentEnvelope{ + Payload: strfmt.Base64("payload"), + PayloadType: swag.String("payloadType"), + Signatures: []*models.IntotoV002SchemaContentEnvelopeSignaturesItems0{ + { + PublicKey: strfmt.Base64([]byte("key")), + Sig: strfmt.Base64([]byte("sig")), + }, + }, + }, + }, + */ + }, + env: *env, + }, + expectSuccess: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.caseDesc, func(t *testing.T) { + if ok, err := tc.entry.Insertable(); ok != tc.expectSuccess { + t.Errorf("unexpected result calling Insertable: %v", err) + } + }) + } +} diff --git a/pkg/types/intoto/v0.0.2/fuzz_test.go b/pkg/types/intoto/v0.0.2/fuzz_test.go new file mode 100644 index 000000000..67dccc72c --- /dev/null +++ b/pkg/types/intoto/v0.0.2/fuzz_test.go @@ -0,0 +1,100 @@ +// +// Copyright 2022 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 intoto + +import ( + "context" + "sync" + "testing" + + fuzz "github.com/AdamKorcz/go-fuzz-headers-1" + "github.com/go-openapi/swag" + + fuzzUtils "github.com/sigstore/rekor/pkg/fuzz" + "github.com/sigstore/rekor/pkg/generated/models" + "github.com/sigstore/rekor/pkg/types" + "github.com/sigstore/rekor/pkg/types/intoto" +) + +var initter sync.Once + +func FuzzIntotoCreateProposedEntry(f *testing.F) { + f.Fuzz(func(t *testing.T, propsData []byte) { + initter.Do(fuzzUtils.SetFuzzLogger) + + version := "0.0.2" + + ff := fuzz.NewConsumer(propsData) + + props, cleanup, err := fuzzUtils.CreateProps(ff, "intotoV002") + if err != nil { + t.Skip() + } + defer func() { + for _, c := range cleanup { + c() + } + }() + + it := intoto.New() + entry, err := it.CreateProposedEntry(context.Background(), version, props) + if err != nil { + t.Skip() + } + ei, err := types.CreateVersionedEntry(entry) + if err != nil { + t.Skip() + } + + if ok, err := ei.Insertable(); !ok || err != nil { + t.Errorf("entry created via CreateProposedEntry should be insertable: %v", err) + } + + if _, err := types.CanonicalizeEntry(context.Background(), ei); err != nil { + t.Errorf("valid insertable entry should be able to be canonicalized: %v", err) + } + + _, _ = ei.IndexKeys() + }) +} + +func FuzzIntotoUnmarshalAndCanonicalize(f *testing.F) { + f.Fuzz(func(t *testing.T, entryData []byte) { + initter.Do(fuzzUtils.SetFuzzLogger) + + ff := fuzz.NewConsumer(entryData) + + targetV002 := &models.IntotoV002Schema{} + + if err := ff.GenerateStruct(targetV002); err != nil { + t.Skip() + } + + targetEntry := &models.Intoto{ + APIVersion: swag.String(APIVERSION), + Spec: targetV002, + } + + ei, err := types.UnmarshalEntry(targetEntry) + if err != nil { + t.Skip() + } + + if _, err := types.CanonicalizeEntry(context.Background(), ei); err != nil { + t.Errorf("error canonicalizing unmarshalled entry: %v", err) + } + }) +} diff --git a/pkg/types/intoto/v0.0.2/intoto_v0_0_2_schema.json b/pkg/types/intoto/v0.0.2/intoto_v0_0_2_schema.json index 0008e46fb..3c404a30a 100644 --- a/pkg/types/intoto/v0.0.2/intoto_v0_0_2_schema.json +++ b/pkg/types/intoto/v0.0.2/intoto_v0_0_2_schema.json @@ -42,10 +42,10 @@ "publicKey": { "description": "public key that corresponds to this signature", "type": "string", - "format": "byte", - "readOnly": true + "format": "byte" } - } + }, + "required": ["sig", "publicKey"] } } }, @@ -93,7 +93,10 @@ ], "readOnly": true } - } + }, + "required": [ + "envelope" + ] } }, "required": [ diff --git a/pkg/types/jar/jar_test.go b/pkg/types/jar/jar_test.go index b60214186..afadab599 100644 --- a/pkg/types/jar/jar_test.go +++ b/pkg/types/jar/jar_test.go @@ -21,6 +21,7 @@ import ( "github.com/go-openapi/swag" "github.com/sigstore/rekor/pkg/generated/models" + "github.com/sigstore/rekor/pkg/pki" "github.com/sigstore/rekor/pkg/types" ) @@ -37,10 +38,14 @@ func (u UnmarshalFailsTester) NewEntry() types.EntryImpl { return &UnmarshalFailsTester{} } -func (u UnmarshalFailsTester) Unmarshal(pe models.ProposedEntry) error { +func (u UnmarshalFailsTester) Unmarshal(_ models.ProposedEntry) error { return errors.New("error") } +func (u UnmarshalFailsTester) Verifiers() ([]pki.PublicKey, error) { + return nil, nil +} + func TestJARType(t *testing.T) { // empty to start if VersionMap.Count() != 0 { diff --git a/pkg/types/jar/v0.0.1/entry.go b/pkg/types/jar/v0.0.1/entry.go index 28f600e02..01fc6aced 100644 --- a/pkg/types/jar/v0.0.1/entry.go +++ b/pkg/types/jar/v0.0.1/entry.go @@ -31,7 +31,9 @@ import ( "strings" "github.com/sigstore/rekor/pkg/log" + "github.com/sigstore/rekor/pkg/pki" "github.com/sigstore/rekor/pkg/pki/pkcs7" + "github.com/sigstore/rekor/pkg/pki/x509" "github.com/sigstore/rekor/pkg/types" "github.com/sigstore/rekor/pkg/types/jar" "github.com/sigstore/rekor/pkg/util" @@ -43,6 +45,7 @@ import ( "github.com/go-openapi/swag" jarutils "github.com/sassoftware/relic/lib/signjar" "github.com/sigstore/rekor/pkg/generated/models" + "github.com/spf13/viper" ) const ( @@ -107,7 +110,11 @@ func (v *V001Entry) Unmarshal(pe models.ProposedEntry) error { return v.validate() } -func (v *V001Entry) fetchExternalEntities(ctx context.Context) (*pkcs7.PublicKey, *pkcs7.Signature, error) { +func (v *V001Entry) fetchExternalEntities(_ context.Context) (*pkcs7.PublicKey, *pkcs7.Signature, error) { + if err := v.validate(); err != nil { + return nil, nil, types.ValidationError(err) + } + oldSHA := "" if v.JARModel.Archive.Hash != nil && v.JARModel.Archive.Hash.Value != nil { oldSHA = swag.StringValue(v.JARModel.Archive.Hash.Value) @@ -133,6 +140,20 @@ func (v *V001Entry) fetchExternalEntities(ctx context.Context) (*pkcs7.PublicKey return nil, nil, types.ValidationError(err) } + // Checking that uncompressed metadata files are within acceptable bounds before reading into memory. + // Checks match those performed by the relic library in the jarutils.Verify method below. For example, + // the META-INF/MANIFEST.MF is read into memory by the relic lib, but a META-INF/LICENSE file is not. + for _, f := range zipReader.File { + dir, name := path.Split(strings.ToUpper(f.Name)) + if dir != "META-INF/" || name == "" || strings.LastIndex(name, ".") < 0 { + continue + } + if f.UncompressedSize64 > viper.GetUint64("max_jar_metadata_size") && viper.GetUint64("max_jar_metadata_size") > 0 { + return nil, nil, types.ValidationError( + fmt.Errorf("uncompressed jar metadata of size %d exceeds max allowed size %d", f.UncompressedSize64, viper.GetUint64("max_jar_metadata_size"))) + } + } + // this ensures that the JAR is signed and the signature verifies, as // well as checks that the hashes in the signed manifest are all valid jarObjs, err := jarutils.Verify(zipReader, false) @@ -316,3 +337,25 @@ func (v *V001Entry) CreateFromArtifactProperties(ctx context.Context, props type return &returnVal, nil } + +func (v V001Entry) Verifiers() ([]pki.PublicKey, error) { + if v.JARModel.Signature == nil || v.JARModel.Signature.PublicKey == nil || v.JARModel.Signature.PublicKey.Content == nil { + return nil, errors.New("jar v0.0.1 entry not initialized") + } + key, err := x509.NewPublicKey(bytes.NewReader(*v.JARModel.Signature.PublicKey.Content)) + if err != nil { + return nil, err + } + return []pki.PublicKey{key}, nil +} + +func (v V001Entry) Insertable() (bool, error) { + if v.JARModel.Archive == nil { + return false, errors.New("missing archive property") + } + if len(v.JARModel.Archive.Content) == 0 { + return false, errors.New("missing archive content") + } + + return true, nil +} diff --git a/pkg/types/jar/v0.0.1/entry_test.go b/pkg/types/jar/v0.0.1/entry_test.go index b551c7a1d..9a096b3a2 100644 --- a/pkg/types/jar/v0.0.1/entry_test.go +++ b/pkg/types/jar/v0.0.1/entry_test.go @@ -20,6 +20,7 @@ import ( "context" "os" "reflect" + "strings" "testing" "github.com/go-openapi/runtime" @@ -27,6 +28,7 @@ import ( "github.com/go-openapi/swag" "github.com/sigstore/rekor/pkg/generated/models" "github.com/sigstore/rekor/pkg/types" + "github.com/spf13/viper" "go.uber.org/goleak" ) @@ -47,15 +49,32 @@ func TestCrossFieldValidation(t *testing.T) { entry V001Entry expectUnmarshalSuccess bool expectCanonicalizeSuccess bool + expectedVerifierSuccess bool } jarBytes, _ := os.ReadFile("tests/test.jar") + // extracted from jar + certificate := `-----BEGIN CERTIFICATE----- +MIIB+DCCAX6gAwIBAgITNVkDZoCiofPDsy7dfm6geLbuhzAKBggqhkjOPQQDAzAq +MRUwEwYDVQQKEwxzaWdzdG9yZS5kZXYxETAPBgNVBAMTCHNpZ3N0b3JlMB4XDTIx +MDMwNzAzMjAyOVoXDTMxMDIyMzAzMjAyOVowKjEVMBMGA1UEChMMc2lnc3RvcmUu +ZGV2MREwDwYDVQQDEwhzaWdzdG9yZTB2MBAGByqGSM49AgEGBSuBBAAiA2IABLSy +A7Ii5k+pNO8ZEWY0ylemWDowOkNa3kL+GZE5Z5GWehL9/A9bRNA3RbrsZ5i0Jcas +taRL7Sp5fp/jD5dxqc/UdTVnlvS16an+2Yfswe/QuLolRUCrcOE2+2iA5+tzd6Nm +MGQwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE +FMjFHQBBmiQpMlEk6w2uSu1KBtPsMB8GA1UdIwQYMBaAFMjFHQBBmiQpMlEk6w2u +Su1KBtPsMAoGCCqGSM49BAMDA2gAMGUCMH8liWJfMui6vXXBhjDgY4MwslmN/TJx +Ve/83WrFomwmNf056y1X48F9c4m3a3ozXAIxAKjRay5/aj/jsKKGIkmQatjI8uup +Hr/+CxFvaJWmpYqNkLDGRU+9orzh5hI2RrcuaQ== +-----END CERTIFICATE----- +` testCases := []TestCase{ { - caseDesc: "empty obj", - entry: V001Entry{}, - expectUnmarshalSuccess: false, + caseDesc: "empty obj", + entry: V001Entry{}, + expectUnmarshalSuccess: false, + expectedVerifierSuccess: false, }, { caseDesc: "empty archive", @@ -64,7 +83,8 @@ func TestCrossFieldValidation(t *testing.T) { Archive: &models.JarV001SchemaArchive{}, }, }, - expectUnmarshalSuccess: false, + expectUnmarshalSuccess: false, + expectedVerifierSuccess: false, }, { caseDesc: "archive with inline content", @@ -77,6 +97,7 @@ func TestCrossFieldValidation(t *testing.T) { }, expectUnmarshalSuccess: true, expectCanonicalizeSuccess: true, + expectedVerifierSuccess: true, }, } @@ -95,6 +116,10 @@ func TestCrossFieldValidation(t *testing.T) { continue } + if ok, err := v.Insertable(); !ok || err != nil { + t.Errorf("unexpected error calling Insertable on valid proposed entry: %v", err) + } + b, err := v.Canonicalize(context.TODO()) if (err == nil) != tc.expectCanonicalizeSuccess { t.Errorf("unexpected result from Canonicalize for '%v': %v", tc.caseDesc, err) @@ -108,9 +133,115 @@ func TestCrossFieldValidation(t *testing.T) { if err != nil { t.Errorf("unexpected err from Unmarshalling canonicalized entry for '%v': %v", tc.caseDesc, err) } - if _, err := types.UnmarshalEntry(pe); err != nil { + ei, err := types.UnmarshalEntry(pe) + if err != nil { t.Errorf("unexpected err from type-specific unmarshalling for '%v': %v", tc.caseDesc, err) } + if ok, err := ei.Insertable(); ok || err == nil { + t.Errorf("unexpected err from calling Insertable on entry created from canonicalized content") + } + } + + verifiers, err := v.Verifiers() + if tc.expectedVerifierSuccess { + if err != nil { + t.Errorf("%v: unexpected error, got %v", tc.caseDesc, err) + } else { + pub, _ := verifiers[0].CanonicalValue() + if !reflect.DeepEqual(pub, []byte(certificate)) { + t.Errorf("verifier and public keys do not match: %v, %v", string(pub), certificate) + } + } + } else { + if err == nil { + s, _ := verifiers[0].CanonicalValue() + t.Errorf("%v: expected error for %v, got %v", tc.caseDesc, string(s), err) + } } } } + +func TestJarMetadataSize(t *testing.T) { + jarBytes, _ := os.ReadFile("tests/test.jar") + + os.Setenv("MAX_JAR_METADATA_SIZE", "10") + viper.AutomaticEnv() + + v := V001Entry{ + JARModel: models.JarV001Schema{ + Archive: &models.JarV001SchemaArchive{ + Content: strfmt.Base64(jarBytes), + }, + }, + } + + r := models.Jar{ + APIVersion: swag.String(v.APIVersion()), + Spec: v.JARModel, + } + + if err := v.Unmarshal(&r); err != nil { + t.Errorf("unexpected unmarshal failure: %v", err) + } + + _, err := v.Canonicalize(context.TODO()) + if err == nil { + t.Fatal("expecting metadata too large err") + } + if !strings.Contains(err.Error(), "exceeds max allowed size 10") { + t.Fatalf("unexpected error %v", err) + } +} + +func TestInsertable(t *testing.T) { + type TestCase struct { + caseDesc string + entry V001Entry + expectSuccess bool + } + testCases := []TestCase{ + { + caseDesc: "valid entry", + entry: V001Entry{ + JARModel: models.JarV001Schema{ + Archive: &models.JarV001SchemaArchive{ + Content: strfmt.Base64([]byte("content")), + }, + }, + }, + expectSuccess: true, + }, + { + caseDesc: "missing archive content", + entry: V001Entry{ + JARModel: models.JarV001Schema{ + Archive: &models.JarV001SchemaArchive{ + //Content: strfmt.Base64([]byte("content")), + }, + }, + }, + expectSuccess: false, + }, + { + caseDesc: "missing archive obj", + entry: V001Entry{ + JARModel: models.JarV001Schema{ + /* + Archive: &models.JarV001SchemaArchive{ + Content: strfmt.Base64([]byte("content")), + }, + */ + }, + }, + expectSuccess: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.caseDesc, func(t *testing.T) { + if ok, err := tc.entry.Insertable(); ok != tc.expectSuccess { + t.Errorf("unexpected result calling Insertable: %v", err) + } + }) + } +} diff --git a/pkg/types/jar/v0.0.1/fuzz_test.go b/pkg/types/jar/v0.0.1/fuzz_test.go new file mode 100644 index 000000000..15c6148ea --- /dev/null +++ b/pkg/types/jar/v0.0.1/fuzz_test.go @@ -0,0 +1,162 @@ +// +// 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. + +package jar + +import ( + "archive/zip" + "bytes" + "context" + "sync" + "testing" + + fuzz "github.com/AdamKorcz/go-fuzz-headers-1" + "github.com/go-openapi/swag" + + jarutils "github.com/sassoftware/relic/lib/signjar" + + fuzzUtils "github.com/sigstore/rekor/pkg/fuzz" + "github.com/sigstore/rekor/pkg/generated/models" + "github.com/sigstore/rekor/pkg/types" + "github.com/sigstore/rekor/pkg/types/jar" +) + +var initter sync.Once + +func FuzzJarCreateProposedEntry(f *testing.F) { + f.Fuzz(func(t *testing.T, propsData []byte) { + initter.Do(fuzzUtils.SetFuzzLogger) + + version := "0.0.1" + + ff := fuzz.NewConsumer(propsData) + + props, cleanup, err := fuzzUtils.CreateProps(ff, "jarV001") + if err != nil { + t.Skip() + } + + defer func() { + for _, c := range cleanup { + c() + } + }() + + it := jar.New() + entry, err := it.CreateProposedEntry(context.Background(), version, props) + if err != nil { + t.Skip() + } + ei, err := types.CreateVersionedEntry(entry) + if err != nil { + t.Skip() + } + + if ok, err := ei.Insertable(); !ok || err != nil { + t.Errorf("entry created via CreateProposedEntry should be insertable: %v", err) + } + + if _, err := types.CanonicalizeEntry(context.Background(), ei); err != nil { + t.Errorf("valid insertable entry should be able to be canonicalized: %v", err) + } + + _, _ = ei.IndexKeys() + }) +} + +func FuzzJarUnmarshalAndCanonicalize(f *testing.F) { + f.Fuzz(func(t *testing.T, entryData []byte) { + initter.Do(fuzzUtils.SetFuzzLogger) + + ff := fuzz.NewConsumer(entryData) + + targetV001 := &models.JarV001Schema{} + + if err := ff.GenerateStruct(targetV001); err != nil { + t.Skip() + } + + targetEntry := &models.Jar{ + APIVersion: swag.String(APIVERSION), + Spec: targetV001, + } + + ei, err := types.UnmarshalEntry(targetEntry) + if err != nil { + t.Skip() + } + + if _, err := types.CanonicalizeEntry(context.Background(), ei); err != nil { + t.Skip() + } + }) +} + +type zipFile struct { + fileName string + fileBody []byte +} + +func FuzzJarutilsVerify(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + ff := fuzz.NewConsumer(data) + noOfFiles, err := ff.GetInt() + if err != nil { + return + } + zipFiles := make([]*zipFile, 0) + for i := 0; i < noOfFiles%20; i++ { + fileName, err := ff.GetString() + if err != nil { + return + } + fileBody, err := ff.GetBytes() + if err != nil { + return + } + zf := &zipFile{ + fileName: fileName, + fileBody: fileBody, + } + zipFiles = append(zipFiles, zf) + } + if len(zipFiles) == 0 { + return + } + + buf := new(bytes.Buffer) + w := zip.NewWriter(buf) + for _, file := range zipFiles { + f, err := w.Create(file.fileName) + if err != nil { + w.Close() + return + } + _, err = f.Write([]byte(file.fileBody)) + if err != nil { + w.Close() + return + } + } + + w.Close() + zipData := buf.Bytes() + zipReader, err := zip.NewReader(bytes.NewReader(zipData), int64(len(zipData))) + if err != nil { + return + } + _, _ = jarutils.Verify(zipReader, false) + }) +} diff --git a/pkg/types/rekord/fuzz_test.go b/pkg/types/rekord/fuzz_test.go deleted file mode 100644 index d5bd3f905..000000000 --- a/pkg/types/rekord/fuzz_test.go +++ /dev/null @@ -1,42 +0,0 @@ -// -// Copyright 2022 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 rekord - -import ( - "context" - "testing" - - fuzz "github.com/AdaLogics/go-fuzz-headers" - - "github.com/sigstore/rekor/pkg/types" -) - -func FuzzRekordCreateProposedEntry(f *testing.F) { - f.Fuzz(func(t *testing.T, version string, propsData []byte) { - ff := fuzz.NewConsumer(propsData) - props := types.ArtifactProperties{} - ff.GenerateStruct(&props) - it := New() - entry, err := it.CreateProposedEntry(context.Background(), version, props) - if err != nil { - t.Skip() - } - _, err = it.UnmarshalEntry(entry) - if err != nil { - t.Skip() - } - }) -} diff --git a/pkg/types/rekord/rekord_test.go b/pkg/types/rekord/rekord_test.go index 7b77db62b..c4cd059e1 100644 --- a/pkg/types/rekord/rekord_test.go +++ b/pkg/types/rekord/rekord_test.go @@ -22,6 +22,7 @@ import ( "github.com/go-openapi/swag" "github.com/sigstore/rekor/pkg/generated/models" + "github.com/sigstore/rekor/pkg/pki" "github.com/sigstore/rekor/pkg/types" ) @@ -38,10 +39,14 @@ func (u UnmarshalFailsTester) NewEntry() types.EntryImpl { return &UnmarshalFailsTester{} } -func (u UnmarshalFailsTester) Unmarshal(pe models.ProposedEntry) error { +func (u UnmarshalFailsTester) Unmarshal(_ models.ProposedEntry) error { return errors.New("error") } +func (u UnmarshalFailsTester) Verifiers() ([]pki.PublicKey, error) { + return nil, nil +} + func TestRekordType(t *testing.T) { // empty to start if VersionMap.Count() != 0 { diff --git a/pkg/types/rekord/v0.0.1/entry.go b/pkg/types/rekord/v0.0.1/entry.go index 0042521e5..da0af234e 100644 --- a/pkg/types/rekord/v0.0.1/entry.go +++ b/pkg/types/rekord/v0.0.1/entry.go @@ -36,6 +36,10 @@ import ( "github.com/sigstore/rekor/pkg/generated/models" "github.com/sigstore/rekor/pkg/log" "github.com/sigstore/rekor/pkg/pki" + "github.com/sigstore/rekor/pkg/pki/minisign" + "github.com/sigstore/rekor/pkg/pki/pgp" + "github.com/sigstore/rekor/pkg/pki/ssh" + "github.com/sigstore/rekor/pkg/pki/x509" "github.com/sigstore/rekor/pkg/types" "github.com/sigstore/rekor/pkg/types/rekord" "github.com/sigstore/rekor/pkg/util" @@ -340,7 +344,7 @@ func (v V001Entry) CreateFromArtifactProperties(ctx context.Context, props types var err error artifactBytes := props.ArtifactBytes - if artifactBytes == nil { + if len(artifactBytes) == 0 { var artifactReader io.ReadCloser if props.ArtifactPath == nil { return nil, errors.New("path to artifact file must be specified") @@ -373,9 +377,11 @@ func (v V001Entry) CreateFromArtifactProperties(ctx context.Context, props types re.RekordObj.Signature.Format = swag.String(models.RekordV001SchemaSignatureFormatX509) case "ssh": re.RekordObj.Signature.Format = swag.String(models.RekordV001SchemaSignatureFormatSSH) + default: + return nil, fmt.Errorf("unexpected format of public key: %s", props.PKIFormat) } sigBytes := props.SignatureBytes - if sigBytes == nil { + if len(sigBytes) == 0 { if props.SignaturePath == nil { return nil, errors.New("a detached signature must be provided") } @@ -418,3 +424,55 @@ func (v V001Entry) CreateFromArtifactProperties(ctx context.Context, props types return &returnVal, nil } + +func (v V001Entry) Verifiers() ([]pki.PublicKey, error) { + if v.RekordObj.Signature == nil || v.RekordObj.Signature.PublicKey == nil || v.RekordObj.Signature.PublicKey.Content == nil { + return nil, errors.New("rekord v0.0.1 entry not initialized") + } + + var key pki.PublicKey + var err error + switch f := *v.RekordObj.Signature.Format; f { + case "x509": + key, err = x509.NewPublicKey(bytes.NewReader(*v.RekordObj.Signature.PublicKey.Content)) + case "ssh": + key, err = ssh.NewPublicKey(bytes.NewReader(*v.RekordObj.Signature.PublicKey.Content)) + case "pgp": + key, err = pgp.NewPublicKey(bytes.NewReader(*v.RekordObj.Signature.PublicKey.Content)) + case "minisign": + key, err = minisign.NewPublicKey(bytes.NewReader(*v.RekordObj.Signature.PublicKey.Content)) + default: + return nil, fmt.Errorf("unexpected format of public key: %s", f) + } + if err != nil { + return nil, err + } + return []pki.PublicKey{key}, nil +} + +func (v V001Entry) Insertable() (bool, error) { + if v.RekordObj.Signature == nil { + return false, errors.New("missing signature property") + } + if v.RekordObj.Signature.Content == nil || len(*v.RekordObj.Signature.Content) == 0 { + return false, errors.New("missing signature content") + } + if v.RekordObj.Signature.PublicKey == nil { + return false, errors.New("missing publicKey property") + } + if v.RekordObj.Signature.PublicKey.Content == nil || len(*v.RekordObj.Signature.PublicKey.Content) == 0 { + return false, errors.New("missing publicKey content") + } + if v.RekordObj.Signature.Format == nil || len(*v.RekordObj.Signature.Format) == 0 { + return false, errors.New("missing signature format") + } + + if v.RekordObj.Data == nil { + return false, errors.New("missing data property") + } + if len(v.RekordObj.Data.Content) == 0 { + return false, errors.New("missing data content") + } + + return true, nil +} diff --git a/pkg/types/rekord/v0.0.1/entry_test.go b/pkg/types/rekord/v0.0.1/entry_test.go index 25b8ab202..e236a50f2 100644 --- a/pkg/types/rekord/v0.0.1/entry_test.go +++ b/pkg/types/rekord/v0.0.1/entry_test.go @@ -29,6 +29,7 @@ import ( "github.com/sigstore/rekor/pkg/generated/models" "github.com/sigstore/rekor/pkg/types" + "github.com/sigstore/rekor/pkg/types/rekord" ) func TestMain(m *testing.M) { @@ -48,6 +49,7 @@ func TestCrossFieldValidation(t *testing.T) { entry V001Entry expectUnmarshalSuccess bool expectCanonicalizeSuccess bool + expectedVerifierSuccess bool } sigBytes, _ := os.ReadFile("../tests/test_file.sig") @@ -56,9 +58,10 @@ func TestCrossFieldValidation(t *testing.T) { testCases := []TestCase{ { - caseDesc: "empty obj", - entry: V001Entry{}, - expectUnmarshalSuccess: false, + caseDesc: "empty obj", + entry: V001Entry{}, + expectUnmarshalSuccess: false, + expectedVerifierSuccess: false, }, { caseDesc: "signature without url or content", @@ -69,7 +72,8 @@ func TestCrossFieldValidation(t *testing.T) { }, }, }, - expectUnmarshalSuccess: false, + expectUnmarshalSuccess: false, + expectedVerifierSuccess: false, }, { caseDesc: "signature without public key", @@ -81,7 +85,8 @@ func TestCrossFieldValidation(t *testing.T) { }, }, }, - expectUnmarshalSuccess: false, + expectUnmarshalSuccess: false, + expectedVerifierSuccess: false, }, { caseDesc: "signature with empty public key", @@ -94,7 +99,8 @@ func TestCrossFieldValidation(t *testing.T) { }, }, }, - expectUnmarshalSuccess: false, + expectUnmarshalSuccess: false, + expectedVerifierSuccess: false, }, { caseDesc: "signature without data", @@ -109,7 +115,8 @@ func TestCrossFieldValidation(t *testing.T) { }, }, }, - expectUnmarshalSuccess: false, + expectUnmarshalSuccess: false, + expectedVerifierSuccess: true, }, { caseDesc: "signature with empty data", @@ -125,7 +132,8 @@ func TestCrossFieldValidation(t *testing.T) { Data: &models.RekordV001SchemaData{}, }, }, - expectUnmarshalSuccess: false, + expectUnmarshalSuccess: false, + expectedVerifierSuccess: true, }, { caseDesc: "signature with invalid sig content, key content & with data with content", @@ -145,6 +153,7 @@ func TestCrossFieldValidation(t *testing.T) { }, expectUnmarshalSuccess: true, expectCanonicalizeSuccess: false, + expectedVerifierSuccess: true, }, { caseDesc: "signature with sig content, invalid key content & with data with content", @@ -164,6 +173,7 @@ func TestCrossFieldValidation(t *testing.T) { }, expectUnmarshalSuccess: true, expectCanonicalizeSuccess: false, + expectedVerifierSuccess: false, }, { caseDesc: "signature with sig content, key content & with data with content", @@ -173,16 +183,17 @@ func TestCrossFieldValidation(t *testing.T) { Format: swag.String("pgp"), Content: (*strfmt.Base64)(&sigBytes), PublicKey: &models.RekordV001SchemaSignaturePublicKey{ - Content: (*strfmt.Base64)(&dataBytes), + Content: (*strfmt.Base64)(&keyBytes), }, }, Data: &models.RekordV001SchemaData{ - Content: strfmt.Base64(dataBytes), + Content: strfmt.Base64(keyBytes), }, }, }, expectUnmarshalSuccess: true, expectCanonicalizeSuccess: false, + expectedVerifierSuccess: true, }, { caseDesc: "signature with sig content, key content & with data with content", @@ -202,6 +213,7 @@ func TestCrossFieldValidation(t *testing.T) { }, expectUnmarshalSuccess: true, expectCanonicalizeSuccess: true, + expectedVerifierSuccess: true, }, } @@ -220,6 +232,10 @@ func TestCrossFieldValidation(t *testing.T) { continue } + if ok, err := v.Insertable(); !ok || err != nil { + t.Errorf("unexpected error calling Insertable on valid proposed entry: %v", err) + } + b, err := v.Canonicalize(context.TODO()) if (err == nil) != tc.expectCanonicalizeSuccess { t.Errorf("unexpected result from Canonicalize for '%v': %v", tc.caseDesc, err) @@ -233,9 +249,241 @@ func TestCrossFieldValidation(t *testing.T) { if err != nil { t.Errorf("unexpected err from Unmarshalling canonicalized entry for '%v': %v", tc.caseDesc, err) } - if _, err := types.UnmarshalEntry(pe); err != nil { + ei, err := types.UnmarshalEntry(pe) + if err != nil { t.Errorf("unexpected err from type-specific unmarshalling for '%v': %v", tc.caseDesc, err) } + if ok, err := ei.Insertable(); ok || err == nil { + t.Errorf("unexpected success calling Insertable on entry created from canonicalized content") + } + } + + verifiers, err := v.Verifiers() + if tc.expectedVerifierSuccess { + if err != nil { + t.Errorf("%v: unexpected error, got %v", tc.caseDesc, err) + } else { + // TODO: Improve this test once CanonicalValue returns same result as input for PGP keys + _, err := verifiers[0].CanonicalValue() + if err != nil { + t.Errorf("%v: unexpected error getting canonical value, got %v", tc.caseDesc, err) + } + } + + } else { + if err == nil { + s, _ := verifiers[0].CanonicalValue() + t.Errorf("%v: expected error for %v, got %v", tc.caseDesc, string(s), err) + } } } } + +func TestUnspecifiedPKIFormat(t *testing.T) { + props := types.ArtifactProperties{ + ArtifactBytes: []byte("something"), + SignatureBytes: []byte("signature"), + PublicKeyBytes: [][]byte{[]byte("public_key")}, + // PKIFormat is deliberately unspecified + } + rek := rekord.New() + if _, err := rek.CreateProposedEntry(context.Background(), APIVERSION, props); err == nil { + t.Errorf("no signature, public key or format should not create a valid entry") + } + + props.PKIFormat = "invalid_format" + if _, err := rek.CreateProposedEntry(context.Background(), APIVERSION, props); err == nil { + t.Errorf("invalid pki format should not create a valid entry") + } +} + +func TestInsertable(t *testing.T) { + type TestCase struct { + caseDesc string + entry V001Entry + expectSuccess bool + } + + sig := strfmt.Base64([]byte("sig")) + pub := strfmt.Base64([]byte("pub")) + testCases := []TestCase{ + { + caseDesc: "valid entry", + entry: V001Entry{ + RekordObj: models.RekordV001Schema{ + Data: &models.RekordV001SchemaData{ + Content: strfmt.Base64([]byte("content")), + }, + Signature: &models.RekordV001SchemaSignature{ + Content: &sig, + Format: swag.String("format"), + PublicKey: &models.RekordV001SchemaSignaturePublicKey{ + Content: &pub, + }, + }, + }, + }, + expectSuccess: true, + }, + { + caseDesc: "missing public key content", + entry: V001Entry{ + RekordObj: models.RekordV001Schema{ + Data: &models.RekordV001SchemaData{ + Content: strfmt.Base64([]byte("content")), + }, + Signature: &models.RekordV001SchemaSignature{ + Content: &sig, + Format: swag.String("format"), + PublicKey: &models.RekordV001SchemaSignaturePublicKey{ + //Content: &pub, + }, + }, + }, + }, + expectSuccess: false, + }, + { + caseDesc: "missing public key obj", + entry: V001Entry{ + RekordObj: models.RekordV001Schema{ + Data: &models.RekordV001SchemaData{ + Content: strfmt.Base64([]byte("content")), + }, + Signature: &models.RekordV001SchemaSignature{ + Content: &sig, + Format: swag.String("format"), + /* + PublicKey: &models.RekordV001SchemaSignaturePublicKey{ + Content: &pub, + }, + */ + }, + }, + }, + expectSuccess: false, + }, + { + caseDesc: "missing format string", + entry: V001Entry{ + RekordObj: models.RekordV001Schema{ + Data: &models.RekordV001SchemaData{ + Content: strfmt.Base64([]byte("content")), + }, + Signature: &models.RekordV001SchemaSignature{ + Content: &sig, + //Format: swag.String("format"), + PublicKey: &models.RekordV001SchemaSignaturePublicKey{ + Content: &pub, + }, + }, + }, + }, + expectSuccess: false, + }, + { + caseDesc: "missing signature content", + entry: V001Entry{ + RekordObj: models.RekordV001Schema{ + Data: &models.RekordV001SchemaData{ + Content: strfmt.Base64([]byte("content")), + }, + Signature: &models.RekordV001SchemaSignature{ + //Content: &sig, + Format: swag.String("format"), + PublicKey: &models.RekordV001SchemaSignaturePublicKey{ + Content: &pub, + }, + }, + }, + }, + expectSuccess: false, + }, + { + caseDesc: "missing signature obj", + entry: V001Entry{ + RekordObj: models.RekordV001Schema{ + Data: &models.RekordV001SchemaData{ + Content: strfmt.Base64([]byte("content")), + }, + /* + Signature: &models.RekordV001SchemaSignature{ + Content: &sig, + Format: swag.String("format"), + PublicKey: &models.RekordV001SchemaSignaturePublicKey{ + Content: &pub, + }, + }, + */ + }, + }, + expectSuccess: false, + }, + { + caseDesc: "missing data content", + entry: V001Entry{ + RekordObj: models.RekordV001Schema{ + Data: &models.RekordV001SchemaData{ + //Content: strfmt.Base64([]byte("content")), + }, + Signature: &models.RekordV001SchemaSignature{ + Content: &sig, + Format: swag.String("format"), + PublicKey: &models.RekordV001SchemaSignaturePublicKey{ + Content: &pub, + }, + }, + }, + }, + expectSuccess: false, + }, + { + caseDesc: "missing data obj", + entry: V001Entry{ + RekordObj: models.RekordV001Schema{ + /* + Data: &models.RekordV001SchemaData{ + Content: strfmt.Base64([]byte("content")), + }, + */ + Signature: &models.RekordV001SchemaSignature{ + Content: &sig, + Format: swag.String("format"), + PublicKey: &models.RekordV001SchemaSignaturePublicKey{ + Content: &pub, + }, + }, + }, + }, + expectSuccess: false, + }, + { + caseDesc: "empty obj", + entry: V001Entry{ + RekordObj: models.RekordV001Schema{ + /* + Data: &models.RekordV001SchemaData{ + Content: strfmt.Base64([]byte("content")), + }, + Signature: &models.RekordV001SchemaSignature{ + Content: &sig, + Format: swag.String("format"), + PublicKey: &models.RekordV001SchemaSignaturePublicKey{ + Content: &pub, + }, + }, + */ + }, + }, + expectSuccess: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.caseDesc, func(t *testing.T) { + if ok, err := tc.entry.Insertable(); ok != tc.expectSuccess { + t.Errorf("unexpected result calling Insertable: %v", err) + } + }) + } +} diff --git a/pkg/types/rekord/v0.0.1/fuzz_test.go b/pkg/types/rekord/v0.0.1/fuzz_test.go new file mode 100644 index 000000000..a4343a0d1 --- /dev/null +++ b/pkg/types/rekord/v0.0.1/fuzz_test.go @@ -0,0 +1,100 @@ +// +// Copyright 2022 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 rekord + +import ( + "context" + "sync" + "testing" + + fuzz "github.com/AdamKorcz/go-fuzz-headers-1" + "github.com/go-openapi/swag" + + fuzzUtils "github.com/sigstore/rekor/pkg/fuzz" + "github.com/sigstore/rekor/pkg/generated/models" + "github.com/sigstore/rekor/pkg/types" + "github.com/sigstore/rekor/pkg/types/rekord" +) + +var initter sync.Once + +func FuzzRekordCreateProposedEntry(f *testing.F) { + f.Fuzz(func(t *testing.T, propsData []byte) { + initter.Do(fuzzUtils.SetFuzzLogger) + + version := "0.0.1" + + ff := fuzz.NewConsumer(propsData) + + props, cleanup, err := fuzzUtils.CreateProps(ff, "rekordV001") + if err != nil { + t.Skip() + } + defer func() { + for _, c := range cleanup { + c() + } + }() + + it := rekord.New() + entry, err := it.CreateProposedEntry(context.Background(), version, props) + if err != nil { + t.Skip() + } + ei, err := types.CreateVersionedEntry(entry) + if err != nil { + t.Skip() + } + + if ok, err := ei.Insertable(); !ok || err != nil { + t.Errorf("entry created via CreateProposedEntry should be insertable: %v", err) + } + + if _, err := types.CanonicalizeEntry(context.Background(), ei); err != nil { + t.Errorf("valid insertable entry should be able to be canonicalized: %v", err) + } + + _, _ = ei.IndexKeys() + }) +} + +func FuzzRekordUnmarshalAndCanonicalize(f *testing.F) { + f.Fuzz(func(t *testing.T, entryData []byte) { + initter.Do(fuzzUtils.SetFuzzLogger) + + ff := fuzz.NewConsumer(entryData) + + targetV001 := &models.RekordV001Schema{} + + if err := ff.GenerateStruct(targetV001); err != nil { + t.Skip() + } + + targetEntry := &models.Rekord{ + APIVersion: swag.String(APIVERSION), + Spec: targetV001, + } + + ei, err := types.UnmarshalEntry(targetEntry) + if err != nil { + t.Skip() + } + + if _, err := types.CanonicalizeEntry(context.Background(), ei); err != nil { + t.Skip() + } + }) +} diff --git a/pkg/types/rfc3161/fuzz_test.go b/pkg/types/rfc3161/fuzz_test.go deleted file mode 100644 index 583b69485..000000000 --- a/pkg/types/rfc3161/fuzz_test.go +++ /dev/null @@ -1,42 +0,0 @@ -// -// Copyright 2022 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 rfc3161 - -import ( - "context" - "testing" - - fuzz "github.com/AdaLogics/go-fuzz-headers" - - "github.com/sigstore/rekor/pkg/types" -) - -func FuzzRfc3161CreateProposedEntry(f *testing.F) { - f.Fuzz(func(t *testing.T, version string, propsData []byte) { - ff := fuzz.NewConsumer(propsData) - props := types.ArtifactProperties{} - ff.GenerateStruct(&props) - it := New() - entry, err := it.CreateProposedEntry(context.Background(), version, props) - if err != nil { - t.Skip() - } - _, err = it.UnmarshalEntry(entry) - if err != nil { - t.Skip() - } - }) -} diff --git a/pkg/types/rfc3161/rfc3161_test.go b/pkg/types/rfc3161/rfc3161_test.go index fda59023e..556267eac 100644 --- a/pkg/types/rfc3161/rfc3161_test.go +++ b/pkg/types/rfc3161/rfc3161_test.go @@ -22,6 +22,7 @@ import ( "github.com/go-openapi/swag" "github.com/sigstore/rekor/pkg/generated/models" + "github.com/sigstore/rekor/pkg/pki" "github.com/sigstore/rekor/pkg/types" ) @@ -38,10 +39,14 @@ func (u UnmarshalFailsTester) NewEntry() types.EntryImpl { return &UnmarshalFailsTester{} } -func (u UnmarshalFailsTester) Unmarshal(pe models.ProposedEntry) error { +func (u UnmarshalFailsTester) Unmarshal(_ models.ProposedEntry) error { return errors.New("error") } +func (u UnmarshalFailsTester) Verifiers() ([]pki.PublicKey, error) { + return nil, nil +} + func TestRfc3161Type(t *testing.T) { // empty to start if VersionMap.Count() != 0 { diff --git a/pkg/types/rfc3161/v0.0.1/entry.go b/pkg/types/rfc3161/v0.0.1/entry.go index 9ebfd8065..9a6c04949 100644 --- a/pkg/types/rfc3161/v0.0.1/entry.go +++ b/pkg/types/rfc3161/v0.0.1/entry.go @@ -27,6 +27,7 @@ import ( "os" "path/filepath" + "github.com/sigstore/rekor/pkg/pki" "github.com/sigstore/rekor/pkg/types/rfc3161" "github.com/go-openapi/strfmt" @@ -117,7 +118,7 @@ func (v *V001Entry) Unmarshal(pe models.ProposedEntry) error { return nil } -func (v *V001Entry) Canonicalize(ctx context.Context) ([]byte, error) { +func (v *V001Entry) Canonicalize(_ context.Context) ([]byte, error) { if v.tsrContent == nil { return nil, errors.New("tsr content must be set before canonicalizing") } @@ -205,3 +206,23 @@ func (v V001Entry) CreateFromArtifactProperties(_ context.Context, props types.A return &returnVal, nil } + +func (v V001Entry) Verifiers() ([]pki.PublicKey, error) { + return nil, errors.New("Verifiers() does not support rfc3161 entry type") +} + +func (v V001Entry) Insertable() (bool, error) { + if v.Rfc3161Obj.Tsr == nil { + return false, errors.New("missing tsr property") + } + + if v.Rfc3161Obj.Tsr.Content == nil || len(*v.Rfc3161Obj.Tsr.Content) == 0 { + return false, errors.New("missing tsr content") + } + + if v.tsrContent == nil || len(*v.tsrContent) == 0 { + return false, errors.New("timestamp response has not been parsed") + } + + return true, nil +} diff --git a/pkg/types/rfc3161/v0.0.1/entry_test.go b/pkg/types/rfc3161/v0.0.1/entry_test.go index b3e4dac5c..6c5457455 100644 --- a/pkg/types/rfc3161/v0.0.1/entry_test.go +++ b/pkg/types/rfc3161/v0.0.1/entry_test.go @@ -27,6 +27,7 @@ import ( "strings" "testing" + "github.com/sassoftware/relic/lib/pkcs7" "github.com/sassoftware/relic/lib/pkcs9" "github.com/go-openapi/runtime" @@ -169,6 +170,12 @@ func TestCrossFieldValidation(t *testing.T) { } } + if tc.expectUnmarshalSuccess { + if ok, err := v.Insertable(); !ok || err != nil { + t.Errorf("unexpected error calling Insertable on valid proposed entry: %v", err) + } + } + b, err := v.Canonicalize(context.TODO()) if (err == nil) != tc.expectCanonicalizeSuccess { t.Errorf("unexpected result from Canonicalize for '%v': %v", tc.caseDesc, err) @@ -182,9 +189,14 @@ func TestCrossFieldValidation(t *testing.T) { if err != nil { t.Errorf("unexpected err from Unmarshalling canonicalized entry for '%v': %v", tc.caseDesc, err) } - if _, err := types.UnmarshalEntry(pe); err != nil { + ei, err := types.UnmarshalEntry(pe) + if err != nil { t.Errorf("unexpected err from type-specific unmarshalling for '%v': %v", tc.caseDesc, err) } + // rfc3161 is one of two types that Insertable() should return true from canonicalized entries + if ok, err := ei.Insertable(); !ok || err != nil { + t.Errorf("unexpected error calling insertable on entry created from canonicalized content") + } } } } @@ -230,7 +242,7 @@ func tBadContent(t *testing.T, bytes []byte) []byte { if _, err := asn1.Unmarshal(bytes, &tsr); err != nil { t.Fatal(err) } - tsr.TimeStampToken.Content.Certificates = []asn1.RawValue{} + tsr.TimeStampToken.Content.Certificates = pkcs7.RawCertificates{} if b, err := asn1.Marshal(tsr); err != nil { t.Fatal(err) } else { @@ -243,3 +255,93 @@ func p(b []byte) *strfmt.Base64 { b64 := strfmt.Base64(b) return &b64 } + +func TestInsertable(t *testing.T) { + type TestCase struct { + caseDesc string + entry V001Entry + expectSuccess bool + } + + tsr := strfmt.Base64([]byte("tsr")) + + testCases := []TestCase{ + { + caseDesc: "valid entry", + entry: V001Entry{ + Rfc3161Obj: models.Rfc3161V001Schema{ + Tsr: &models.Rfc3161V001SchemaTsr{ + Content: &tsr, + }, + }, + tsrContent: &tsr, + }, + expectSuccess: true, + }, + { + caseDesc: "unparsed tsr", + entry: V001Entry{ + Rfc3161Obj: models.Rfc3161V001Schema{ + Tsr: &models.Rfc3161V001SchemaTsr{ + Content: &tsr, + }, + }, + //tsrContent: &tsr, + }, + expectSuccess: false, + }, + { + caseDesc: "missing tsr content", + entry: V001Entry{ + Rfc3161Obj: models.Rfc3161V001Schema{ + Tsr: &models.Rfc3161V001SchemaTsr{ + //Content: &tsr, + }, + }, + tsrContent: &tsr, + }, + expectSuccess: false, + }, + { + caseDesc: "missing tsr obj", + entry: V001Entry{ + Rfc3161Obj: models.Rfc3161V001Schema{ + /* + Tsr: &models.Rfc3161V001SchemaTsr{ + Content: &tsr, + }, + */ + }, + tsrContent: &tsr, + }, + expectSuccess: false, + }, + { + caseDesc: "missing Rfc3161 obj", + entry: V001Entry{ + /* + Rfc3161Obj: models.Rfc3161V001Schema{ + Tsr: &models.Rfc3161V001SchemaTsr{ + Content: &tsr, + }, + }, + */ + tsrContent: &tsr, + }, + expectSuccess: false, + }, + { + caseDesc: "empty obj", + entry: V001Entry{}, + expectSuccess: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.caseDesc, func(t *testing.T) { + if ok, err := tc.entry.Insertable(); ok != tc.expectSuccess { + t.Errorf("unexpected result calling Insertable: %v", err) + } + }) + } +} diff --git a/pkg/types/rfc3161/v0.0.1/fuzz_test.go b/pkg/types/rfc3161/v0.0.1/fuzz_test.go new file mode 100644 index 000000000..c5f3bbe8c --- /dev/null +++ b/pkg/types/rfc3161/v0.0.1/fuzz_test.go @@ -0,0 +1,100 @@ +// +// Copyright 2022 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 rfc3161 + +import ( + "context" + "sync" + "testing" + + fuzz "github.com/AdamKorcz/go-fuzz-headers-1" + "github.com/go-openapi/swag" + + fuzzUtils "github.com/sigstore/rekor/pkg/fuzz" + "github.com/sigstore/rekor/pkg/generated/models" + "github.com/sigstore/rekor/pkg/types" + "github.com/sigstore/rekor/pkg/types/rfc3161" +) + +var initter sync.Once + +func FuzzRfc3161CreateProposedEntry(f *testing.F) { + f.Fuzz(func(t *testing.T, propsData []byte) { + initter.Do(fuzzUtils.SetFuzzLogger) + + version := "0.0.1" + + ff := fuzz.NewConsumer(propsData) + + props, cleanup, err := fuzzUtils.CreateProps(ff, "rfc3161V001") + if err != nil { + t.Skip() + } + defer func() { + for _, c := range cleanup { + c() + } + }() + + it := rfc3161.New() + entry, err := it.CreateProposedEntry(context.Background(), version, props) + if err != nil { + t.Skip() + } + ei, err := types.CreateVersionedEntry(entry) + if err != nil { + t.Skip() + } + + if ok, err := ei.Insertable(); !ok || err != nil { + t.Errorf("entry created via CreateProposedEntry should be insertable: %v", err) + } + + if _, err := types.CanonicalizeEntry(context.Background(), ei); err != nil { + t.Errorf("valid insertable entry should be able to be canonicalized: %v", err) + } + + _, _ = ei.IndexKeys() + }) +} + +func FuzzRfc3161UnmarshalAndCanonicalize(f *testing.F) { + f.Fuzz(func(t *testing.T, entryData []byte) { + initter.Do(fuzzUtils.SetFuzzLogger) + + ff := fuzz.NewConsumer(entryData) + + targetV001 := &models.Rfc3161V001Schema{} + + if err := ff.GenerateStruct(targetV001); err != nil { + t.Skip() + } + + targetEntry := &models.Rfc3161{ + APIVersion: swag.String(APIVERSION), + Spec: targetV001, + } + + ei, err := types.UnmarshalEntry(targetEntry) + if err != nil { + t.Skip() + } + + if _, err := types.CanonicalizeEntry(context.Background(), ei); err != nil { + t.Errorf("error canonicalizing unmarshalled entry: %v", err) + } + }) +} diff --git a/pkg/types/rpm/rpm_test.go b/pkg/types/rpm/rpm_test.go index 9fa25edcc..390cf21b0 100644 --- a/pkg/types/rpm/rpm_test.go +++ b/pkg/types/rpm/rpm_test.go @@ -22,6 +22,7 @@ import ( "github.com/go-openapi/swag" "github.com/sigstore/rekor/pkg/generated/models" + "github.com/sigstore/rekor/pkg/pki" "github.com/sigstore/rekor/pkg/types" ) @@ -38,10 +39,14 @@ func (u UnmarshalFailsTester) NewEntry() types.EntryImpl { return &UnmarshalFailsTester{} } -func (u UnmarshalFailsTester) Unmarshal(pe models.ProposedEntry) error { +func (u UnmarshalFailsTester) Unmarshal(_ models.ProposedEntry) error { return errors.New("error") } +func (u UnmarshalFailsTester) Verifiers() ([]pki.PublicKey, error) { + return nil, nil +} + func TestRPMType(t *testing.T) { // empty to start if VersionMap.Count() != 0 { diff --git a/pkg/types/rpm/v0.0.1/entry.go b/pkg/types/rpm/v0.0.1/entry.go index 971fcbfe0..fd3b91ce7 100644 --- a/pkg/types/rpm/v0.0.1/entry.go +++ b/pkg/types/rpm/v0.0.1/entry.go @@ -37,6 +37,7 @@ import ( "github.com/sigstore/rekor/pkg/generated/models" "github.com/sigstore/rekor/pkg/log" + "github.com/sigstore/rekor/pkg/pki" "github.com/sigstore/rekor/pkg/pki/pgp" "github.com/sigstore/rekor/pkg/types" "github.com/sigstore/rekor/pkg/types/rpm" @@ -369,3 +370,31 @@ func (v V001Entry) CreateFromArtifactProperties(ctx context.Context, props types return &returnVal, nil } + +func (v V001Entry) Verifiers() ([]pki.PublicKey, error) { + if v.RPMModel.PublicKey == nil || v.RPMModel.PublicKey.Content == nil { + return nil, errors.New("rpm v0.0.1 entry not initialized") + } + key, err := pgp.NewPublicKey(bytes.NewReader(*v.RPMModel.PublicKey.Content)) + if err != nil { + return nil, err + } + return []pki.PublicKey{key}, nil +} + +func (v V001Entry) Insertable() (bool, error) { + if v.RPMModel.PublicKey == nil { + return false, errors.New("missing publicKey property") + } + if v.RPMModel.PublicKey.Content == nil || len(*v.RPMModel.PublicKey.Content) == 0 { + return false, errors.New("missing publicKey content") + } + + if v.RPMModel.Package == nil { + return false, errors.New("missing package property") + } + if len(v.RPMModel.Package.Content) == 0 { + return false, errors.New("missing package content") + } + return true, nil +} diff --git a/pkg/types/rpm/v0.0.1/entry_test.go b/pkg/types/rpm/v0.0.1/entry_test.go index 3add385f1..9b1ec7bd0 100644 --- a/pkg/types/rpm/v0.0.1/entry_test.go +++ b/pkg/types/rpm/v0.0.1/entry_test.go @@ -48,6 +48,7 @@ func TestCrossFieldValidation(t *testing.T) { entry V001Entry expectUnmarshalSuccess bool expectCanonicalizeSuccess bool + expectVerifierSuccess bool } keyBytes, _ := os.ReadFile("../tests/test_rpm_public_key.key") @@ -58,6 +59,7 @@ func TestCrossFieldValidation(t *testing.T) { caseDesc: "empty obj", entry: V001Entry{}, expectUnmarshalSuccess: false, + expectVerifierSuccess: false, }, { caseDesc: "public key without content", @@ -67,6 +69,7 @@ func TestCrossFieldValidation(t *testing.T) { }, }, expectUnmarshalSuccess: false, + expectVerifierSuccess: false, }, { caseDesc: "public key without package", @@ -78,6 +81,7 @@ func TestCrossFieldValidation(t *testing.T) { }, }, expectUnmarshalSuccess: false, + expectVerifierSuccess: true, }, { caseDesc: "public key with empty package", @@ -90,6 +94,7 @@ func TestCrossFieldValidation(t *testing.T) { }, }, expectUnmarshalSuccess: false, + expectVerifierSuccess: true, }, { caseDesc: "public key with invalid key content & with data with content", @@ -105,6 +110,7 @@ func TestCrossFieldValidation(t *testing.T) { }, expectUnmarshalSuccess: true, expectCanonicalizeSuccess: false, + expectVerifierSuccess: false, }, { caseDesc: "public key with key content & with data with content", @@ -120,6 +126,7 @@ func TestCrossFieldValidation(t *testing.T) { }, expectUnmarshalSuccess: true, expectCanonicalizeSuccess: true, + expectVerifierSuccess: true, }, { caseDesc: "public key with key content & with invalid data with content", @@ -135,6 +142,7 @@ func TestCrossFieldValidation(t *testing.T) { }, expectUnmarshalSuccess: true, expectCanonicalizeSuccess: false, + expectVerifierSuccess: true, }, } @@ -159,6 +167,12 @@ func TestCrossFieldValidation(t *testing.T) { t.Errorf("unexpected result in '%v': %v", tc.caseDesc, err) } + if tc.expectUnmarshalSuccess { + if ok, err := v.Insertable(); !ok || err != nil { + t.Errorf("unexpected error calling Insertable on valid proposed entry: %v", err) + } + } + b, err := v.Canonicalize(context.TODO()) if (err == nil) != tc.expectCanonicalizeSuccess { t.Errorf("unexpected result from Canonicalize for '%v': %v", tc.caseDesc, err) @@ -173,9 +187,131 @@ func TestCrossFieldValidation(t *testing.T) { if err != nil { t.Errorf("unexpected err from Unmarshalling canonicalized entry for '%v': %v", tc.caseDesc, err) } - if _, err := types.UnmarshalEntry(pe); err != nil { + ei, err := types.UnmarshalEntry(pe) + if err != nil { t.Errorf("unexpected err from type-specific unmarshalling for '%v': %v", tc.caseDesc, err) } + if ok, err := ei.Insertable(); ok || err == nil { + t.Errorf("unexpected success calling Insertable on entry created from canonicalized content") + } + } + + verifiers, err := v.Verifiers() + if tc.expectVerifierSuccess { + if err != nil { + t.Errorf("%v: unexpected error, got %v", tc.caseDesc, err) + } else { + // TODO: Improve this test once CanonicalValue returns same result as input for PGP keys + _, err := verifiers[0].CanonicalValue() + if err != nil { + t.Errorf("%v: unexpected error getting canonical value, got %v", tc.caseDesc, err) + } + } + } else { + if err == nil { + s, _ := verifiers[0].CanonicalValue() + t.Errorf("%v: expected error for %v, got %v", tc.caseDesc, string(s), err) + } } } } + +func TestInsertable(t *testing.T) { + type TestCase struct { + caseDesc string + entry V001Entry + expectSuccess bool + } + + pub := strfmt.Base64([]byte("pub")) + + testCases := []TestCase{ + { + caseDesc: "valid entry", + entry: V001Entry{ + RPMModel: models.RpmV001Schema{ + Package: &models.RpmV001SchemaPackage{ + Content: strfmt.Base64([]byte("content")), + }, + PublicKey: &models.RpmV001SchemaPublicKey{ + Content: &pub, + }, + }, + }, + expectSuccess: true, + }, + { + caseDesc: "missing public key content", + entry: V001Entry{ + RPMModel: models.RpmV001Schema{ + Package: &models.RpmV001SchemaPackage{ + Content: strfmt.Base64([]byte("content")), + }, + PublicKey: &models.RpmV001SchemaPublicKey{ + //Content: &pub, + }, + }, + }, + expectSuccess: false, + }, + { + caseDesc: "missing public key obj", + entry: V001Entry{ + RPMModel: models.RpmV001Schema{ + Package: &models.RpmV001SchemaPackage{ + Content: strfmt.Base64([]byte("content")), + }, + /* + PublicKey: &models.RpmV001SchemaPublicKey{ + Content: &pub, + }, + */ + }, + }, + expectSuccess: false, + }, + { + caseDesc: "missing package content", + entry: V001Entry{ + RPMModel: models.RpmV001Schema{ + Package: &models.RpmV001SchemaPackage{ + //Content: strfmt.Base64([]byte("content")), + }, + PublicKey: &models.RpmV001SchemaPublicKey{ + Content: &pub, + }, + }, + }, + expectSuccess: false, + }, + { + caseDesc: "missing package obj", + entry: V001Entry{ + RPMModel: models.RpmV001Schema{ + /* + Package: &models.RpmV001SchemaPackage{ + Content: strfmt.Base64([]byte("content")), + }, + */ + PublicKey: &models.RpmV001SchemaPublicKey{ + Content: &pub, + }, + }, + }, + expectSuccess: false, + }, + { + caseDesc: "empty obj", + entry: V001Entry{}, + expectSuccess: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.caseDesc, func(t *testing.T) { + if ok, err := tc.entry.Insertable(); ok != tc.expectSuccess { + t.Errorf("unexpected result calling Insertable: %v", err) + } + }) + } +} diff --git a/pkg/types/rpm/v0.0.1/fuzz_test.go b/pkg/types/rpm/v0.0.1/fuzz_test.go new file mode 100644 index 000000000..7c3e0d0f7 --- /dev/null +++ b/pkg/types/rpm/v0.0.1/fuzz_test.go @@ -0,0 +1,100 @@ +// +// Copyright 2022 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 rpm + +import ( + "context" + "sync" + "testing" + + fuzz "github.com/AdamKorcz/go-fuzz-headers-1" + "github.com/go-openapi/swag" + + fuzzUtils "github.com/sigstore/rekor/pkg/fuzz" + "github.com/sigstore/rekor/pkg/generated/models" + "github.com/sigstore/rekor/pkg/types" + "github.com/sigstore/rekor/pkg/types/rpm" +) + +var initter sync.Once + +func FuzzRpmCreateProposedEntry(f *testing.F) { + f.Fuzz(func(t *testing.T, propsData []byte) { + initter.Do(fuzzUtils.SetFuzzLogger) + + version := "0.0.1" + + ff := fuzz.NewConsumer(propsData) + + props, cleanup, err := fuzzUtils.CreateProps(ff, "rpmV001") + if err != nil { + t.Skip() + } + defer func() { + for _, c := range cleanup { + c() + } + }() + + it := rpm.New() + entry, err := it.CreateProposedEntry(context.Background(), version, props) + if err != nil { + t.Skip() + } + ei, err := types.CreateVersionedEntry(entry) + if err != nil { + t.Skip() + } + + if ok, err := ei.Insertable(); !ok || err != nil { + t.Errorf("entry created via CreateProposedEntry should be insertable: %v", err) + } + + if _, err := types.CanonicalizeEntry(context.Background(), ei); err != nil { + t.Errorf("valid insertable entry should be able to be canonicalized: %v", err) + } + + _, _ = ei.IndexKeys() + }) +} + +func FuzzRpmUnmarshalAndCanonicalize(f *testing.F) { + f.Fuzz(func(t *testing.T, entryData []byte) { + initter.Do(fuzzUtils.SetFuzzLogger) + + ff := fuzz.NewConsumer(entryData) + + targetV001 := &models.RpmV001Schema{} + + if err := ff.GenerateStruct(targetV001); err != nil { + t.Skip() + } + + targetEntry := &models.Rpm{ + APIVersion: swag.String(APIVERSION), + Spec: targetV001, + } + + ei, err := types.UnmarshalEntry(targetEntry) + if err != nil { + t.Skip() + } + + if _, err := types.CanonicalizeEntry(context.Background(), ei); err != nil { + t.Skip() + } + }) +} diff --git a/pkg/types/test_util.go b/pkg/types/test_util.go index 423c3a230..529d71b79 100644 --- a/pkg/types/test_util.go +++ b/pkg/types/test_util.go @@ -22,6 +22,7 @@ import ( "github.com/go-openapi/strfmt" "github.com/sigstore/rekor/pkg/generated/models" + "github.com/sigstore/rekor/pkg/pki" ) type BaseUnmarshalTester struct{} @@ -30,6 +31,10 @@ func (u BaseUnmarshalTester) NewEntry() EntryImpl { return &BaseUnmarshalTester{} } +func (u BaseUnmarshalTester) Verifiers() ([]pki.PublicKey, error) { + return nil, nil +} + func (u BaseUnmarshalTester) APIVersion() string { return "2.0.1" } @@ -38,11 +43,11 @@ func (u BaseUnmarshalTester) IndexKeys() ([]string, error) { return []string{}, nil } -func (u BaseUnmarshalTester) Canonicalize(ctx context.Context) ([]byte, error) { +func (u BaseUnmarshalTester) Canonicalize(_ context.Context) ([]byte, error) { return nil, nil } -func (u BaseUnmarshalTester) Unmarshal(pe models.ProposedEntry) error { +func (u BaseUnmarshalTester) Unmarshal(_ models.ProposedEntry) error { return nil } @@ -62,20 +67,24 @@ func (u BaseUnmarshalTester) CreateFromArtifactProperties(_ context.Context, _ A return nil, nil } +func (u BaseUnmarshalTester) Insertable() (bool, error) { + return false, nil +} + type BaseProposedEntryTester struct{} func (b BaseProposedEntryTester) Kind() string { return "nil" } -func (b BaseProposedEntryTester) SetKind(v string) { +func (b BaseProposedEntryTester) SetKind(_ string) { } -func (b BaseProposedEntryTester) Validate(r strfmt.Registry) error { +func (b BaseProposedEntryTester) Validate(_ strfmt.Registry) error { return nil } -func (b BaseProposedEntryTester) ContextValidate(ctx context.Context, r strfmt.Registry) error { +func (b BaseProposedEntryTester) ContextValidate(_ context.Context, _ strfmt.Registry) error { return nil } diff --git a/pkg/types/tuf/fuzz_test.go b/pkg/types/tuf/fuzz_test.go deleted file mode 100644 index 477dd0a01..000000000 --- a/pkg/types/tuf/fuzz_test.go +++ /dev/null @@ -1,42 +0,0 @@ -// -// Copyright 2022 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 tuf - -import ( - "context" - "testing" - - fuzz "github.com/AdaLogics/go-fuzz-headers" - - "github.com/sigstore/rekor/pkg/types" -) - -func FuzzTufCreateProposedEntry(f *testing.F) { - f.Fuzz(func(t *testing.T, version string, propsData []byte) { - ff := fuzz.NewConsumer(propsData) - props := types.ArtifactProperties{} - ff.GenerateStruct(&props) - it := New() - entry, err := it.CreateProposedEntry(context.Background(), version, props) - if err != nil { - t.Skip() - } - _, err = it.UnmarshalEntry(entry) - if err != nil { - t.Skip() - } - }) -} diff --git a/pkg/types/tuf/tuf_test.go b/pkg/types/tuf/tuf_test.go index 572947fb2..282881955 100644 --- a/pkg/types/tuf/tuf_test.go +++ b/pkg/types/tuf/tuf_test.go @@ -22,6 +22,7 @@ import ( "github.com/go-openapi/swag" "github.com/sigstore/rekor/pkg/generated/models" + "github.com/sigstore/rekor/pkg/pki" "github.com/sigstore/rekor/pkg/types" ) @@ -38,7 +39,11 @@ func (u UnmarshalFailsTester) NewEntry() types.EntryImpl { return &UnmarshalFailsTester{} } -func (u UnmarshalFailsTester) Unmarshal(pe models.ProposedEntry) error { +func (u UnmarshalFailsTester) Verifiers() ([]pki.PublicKey, error) { + return nil, nil +} + +func (u UnmarshalFailsTester) Unmarshal(_ models.ProposedEntry) error { return errors.New("error") } diff --git a/pkg/types/tuf/v0.0.1/entry.go b/pkg/types/tuf/v0.0.1/entry.go index 684070626..be24fd6ed 100644 --- a/pkg/types/tuf/v0.0.1/entry.go +++ b/pkg/types/tuf/v0.0.1/entry.go @@ -19,6 +19,7 @@ import ( "bytes" "context" "crypto/sha256" + "encoding/base64" "encoding/hex" "encoding/json" "errors" @@ -81,11 +82,11 @@ func NewEntry() types.EntryImpl { func (v V001Entry) IndexKeys() ([]string, error) { var result []string - keyBytes, err := json.Marshal(v.TufObj.Root.Content) + keyBytes, err := v.parseRootContent() if err != nil { return nil, err } - sigBytes, err := json.Marshal(v.TufObj.Metadata.Content) + sigBytes, err := v.parseMetadataContent() if err != nil { return nil, err } @@ -160,7 +161,7 @@ func (v *V001Entry) fetchExternalEntities(ctx context.Context) (pki.PublicKey, p var contentBytes []byte if v.TufObj.Metadata.Content != nil { var err error - contentBytes, err = json.Marshal(v.TufObj.Metadata.Content) + contentBytes, err = v.parseMetadataContent() if err != nil { return closePipesOnError(err) } @@ -189,7 +190,7 @@ func (v *V001Entry) fetchExternalEntities(ctx context.Context) (pki.PublicKey, p var contentBytes []byte if v.TufObj.Root.Content != nil { var err error - contentBytes, err = json.Marshal(v.TufObj.Root.Content) + contentBytes, err = v.parseRootContent() if err != nil { return closePipesOnError(err) } @@ -368,3 +369,75 @@ func (v V001Entry) CreateFromArtifactProperties(ctx context.Context, props types return &returnVal, nil } + +func (v V001Entry) Verifiers() ([]pki.PublicKey, error) { + if v.TufObj.Root == nil { + return nil, errors.New("tuf v0.0.1 entry not initialized") + } + keyBytes, err := v.parseRootContent() + if err != nil { + return nil, err + } + key, err := ptuf.NewPublicKey(bytes.NewReader(keyBytes)) + if err != nil { + return nil, err + } + return []pki.PublicKey{key}, nil +} + +func (v V001Entry) Insertable() (bool, error) { + if v.TufObj.Metadata == nil { + return false, errors.New("missing metadata property") + } + if v.TufObj.Metadata.Content == nil { + return false, errors.New("missing metadata content") + } + + if v.TufObj.Root == nil { + return false, errors.New("missing root property") + } + if v.TufObj.Root.Content == nil { + return false, errors.New("missing root content") + } + return true, nil +} + +func (v V001Entry) parseRootContent() ([]byte, error) { + var keyBytes []byte + // Root.Content can either be a base64-encoded string or object + switch v := v.TufObj.Root.Content.(type) { + case string: + b, err := base64.StdEncoding.DecodeString(v) + if err != nil { + return nil, fmt.Errorf("base64 decoding TUF root content: %w", err) + } + keyBytes = b + default: + var err error + keyBytes, err = json.Marshal(v) + if err != nil { + return nil, err + } + } + return keyBytes, nil +} + +func (v V001Entry) parseMetadataContent() ([]byte, error) { + var sigBytes []byte + // Metadata.Content can either be a base64-encoded string or object + switch v := v.TufObj.Metadata.Content.(type) { + case string: + b, err := base64.StdEncoding.DecodeString(v) + if err != nil { + return nil, fmt.Errorf("base64 decoding TUF metadata content: %w", err) + } + sigBytes = b + default: + var err error + sigBytes, err = json.Marshal(v) + if err != nil { + return nil, err + } + } + return sigBytes, nil +} diff --git a/pkg/types/tuf/v0.0.1/entry_test.go b/pkg/types/tuf/v0.0.1/entry_test.go index 7a42c6411..174bb8c69 100644 --- a/pkg/types/tuf/v0.0.1/entry_test.go +++ b/pkg/types/tuf/v0.0.1/entry_test.go @@ -19,6 +19,7 @@ package tuf import ( "bytes" "context" + "encoding/base64" "encoding/json" "os" "reflect" @@ -65,6 +66,7 @@ func TestCrossFieldValidation(t *testing.T) { entry V001Entry expectUnmarshalSuccess bool expectCanonicalizeSuccess bool + expectVerifierSuccess bool } keyBytes, _ := os.ReadFile("tests/test_root.json") @@ -94,6 +96,7 @@ func TestCrossFieldValidation(t *testing.T) { }, }, expectUnmarshalSuccess: false, + expectVerifierSuccess: false, }, { caseDesc: "root without manifest", @@ -106,6 +109,7 @@ func TestCrossFieldValidation(t *testing.T) { }, }, expectUnmarshalSuccess: false, + expectVerifierSuccess: true, }, { caseDesc: "root with invalid manifest & valid metadata", @@ -121,6 +125,7 @@ func TestCrossFieldValidation(t *testing.T) { }, expectUnmarshalSuccess: true, expectCanonicalizeSuccess: false, + expectVerifierSuccess: false, }, { caseDesc: "root with manifest & content", @@ -136,6 +141,23 @@ func TestCrossFieldValidation(t *testing.T) { }, expectUnmarshalSuccess: true, expectCanonicalizeSuccess: true, + expectVerifierSuccess: true, + }, + { + caseDesc: "root with manifest & content base64-encoded", + entry: V001Entry{ + TufObj: models.TUFV001Schema{ + Root: &models.TUFV001SchemaRoot{ + Content: base64.StdEncoding.EncodeToString(keyBytes), + }, + Metadata: &models.TUFV001SchemaMetadata{ + Content: base64.StdEncoding.EncodeToString(dataBytes), + }, + }, + }, + expectUnmarshalSuccess: true, + expectCanonicalizeSuccess: true, + expectVerifierSuccess: true, }, { caseDesc: "root with invalid key content & with manifest with content", @@ -151,6 +173,7 @@ func TestCrossFieldValidation(t *testing.T) { }, expectUnmarshalSuccess: true, expectCanonicalizeSuccess: false, + expectVerifierSuccess: false, }, { caseDesc: "public key with key content & with invalid data with content", @@ -166,51 +189,180 @@ func TestCrossFieldValidation(t *testing.T) { }, expectUnmarshalSuccess: true, expectCanonicalizeSuccess: false, + expectVerifierSuccess: true, }, } for _, tc := range testCases { - if err := tc.entry.Validate(); (err == nil) != tc.expectUnmarshalSuccess { - t.Errorf("unexpected result in '%v': %v", tc.caseDesc, err) - } - // No need to continue here if we failed at unmarshal - if !tc.expectUnmarshalSuccess { - continue - } - - v := &V001Entry{} - r := models.TUF{ - APIVersion: swag.String(tc.entry.APIVersion()), - Spec: tc.entry.TufObj, - } - - unmarshalAndValidate := func() error { - if err := v.Unmarshal(&r); err != nil { - return err + t.Run(tc.caseDesc, func(t *testing.T) { + if err := tc.entry.Validate(); (err == nil) != tc.expectUnmarshalSuccess { + t.Errorf("unexpected result in '%v': %v", tc.caseDesc, err) + } + // No need to continue here if we failed at unmarshal + if !tc.expectUnmarshalSuccess { + return + } + + v := &V001Entry{} + r := models.TUF{ + APIVersion: swag.String(tc.entry.APIVersion()), + Spec: tc.entry.TufObj, + } + + unmarshalAndValidate := func() error { + if err := v.Unmarshal(&r); err != nil { + return err + } + return v.Validate() + } + if err := unmarshalAndValidate(); (err == nil) != tc.expectUnmarshalSuccess { + t.Errorf("unexpected result in '%v': %v", tc.caseDesc, err) } - return v.Validate() - } - if err := unmarshalAndValidate(); (err == nil) != tc.expectUnmarshalSuccess { - t.Errorf("unexpected result in '%v': %v", tc.caseDesc, err) - } - - b, err := v.Canonicalize(context.TODO()) - if (err == nil) != tc.expectCanonicalizeSuccess { - t.Errorf("unexpected result from Canonicalize for '%v': %v", tc.caseDesc, err) - } else if err != nil { - if _, ok := err.(types.ValidationError); !ok { - t.Errorf("canonicalize returned an unexpected error that isn't of type types.ValidationError: %v", err) + + if tc.expectUnmarshalSuccess { + if ok, err := v.Insertable(); !ok || err != nil { + t.Errorf("unexpected error calling Insertable on valid proposed entry: %v", err) + } + } + + b, err := v.Canonicalize(context.TODO()) + if (err == nil) != tc.expectCanonicalizeSuccess { + t.Errorf("unexpected result from Canonicalize for '%v': %v", tc.caseDesc, err) + } else if err != nil { + if _, ok := err.(types.ValidationError); !ok { + t.Errorf("canonicalize returned an unexpected error that isn't of type types.ValidationError: %v", err) + } } - } - if b != nil { - pe, err := models.UnmarshalProposedEntry(bytes.NewReader(b), runtime.JSONConsumer()) - if err != nil { - t.Errorf("unexpected err from Unmarshalling canonicalized entry for '%v': %v", tc.caseDesc, err) + if b != nil { + pe, err := models.UnmarshalProposedEntry(bytes.NewReader(b), runtime.JSONConsumer()) + if err != nil { + t.Errorf("unexpected err from Unmarshalling canonicalized entry for '%v': %v", tc.caseDesc, err) + } + if _, err := types.UnmarshalEntry(pe); err != nil { + t.Errorf("unexpected err from type-specific unmarshalling for '%v': %v", tc.caseDesc, err) + } + // Insertable on canonicalized content is variable so we skip testing it here } - if _, err := types.UnmarshalEntry(pe); err != nil { - t.Errorf("unexpected err from type-specific unmarshalling for '%v': %v", tc.caseDesc, err) + + verifiers, err := v.Verifiers() + if tc.expectVerifierSuccess { + if err != nil { + t.Errorf("%v: unexpected error, got %v", tc.caseDesc, err) + } else { + pub, _ := verifiers[0].CanonicalValue() + rootBytes := new(bytes.Buffer) + if err := json.Compact(rootBytes, keyBytes); err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(pub, rootBytes.Bytes()) { + t.Errorf("%v: verifier and public keys do not match: %v, %v", tc.caseDesc, string(pub), rootBytes) + } + } + } else { + if err == nil { + s, _ := verifiers[0].CanonicalValue() + t.Errorf("%v: expected error for %v, got %v", tc.caseDesc, string(s), err) + } + } + }) + } +} + +func TestInsertable(t *testing.T) { + type TestCase struct { + caseDesc string + entry V001Entry + expectSuccess bool + } + + testCases := []TestCase{ + { + caseDesc: "valid entry", + entry: V001Entry{ + TufObj: models.TUFV001Schema{ + Metadata: &models.TUFV001SchemaMetadata{ + Content: struct{}{}, + }, + Root: &models.TUFV001SchemaRoot{ + Content: struct{}{}, + }, + }, + }, + expectSuccess: true, + }, + { + caseDesc: "missing root content", + entry: V001Entry{ + TufObj: models.TUFV001Schema{ + Metadata: &models.TUFV001SchemaMetadata{ + Content: struct{}{}, + }, + Root: &models.TUFV001SchemaRoot{ + //Content: struct{}{}, + }, + }, + }, + expectSuccess: false, + }, + { + caseDesc: "missing root obj", + entry: V001Entry{ + TufObj: models.TUFV001Schema{ + Metadata: &models.TUFV001SchemaMetadata{ + Content: struct{}{}, + }, + /* + Root: &models.TUFV001SchemaRoot{ + Content: struct{}{}, + }, + */ + }, + }, + expectSuccess: false, + }, + { + caseDesc: "missing metadata content", + entry: V001Entry{ + TufObj: models.TUFV001Schema{ + Metadata: &models.TUFV001SchemaMetadata{ + //Content: struct{}{}, + }, + Root: &models.TUFV001SchemaRoot{ + Content: struct{}{}, + }, + }, + }, + expectSuccess: false, + }, + { + caseDesc: "missing metadata content", + entry: V001Entry{ + TufObj: models.TUFV001Schema{ + /* + Metadata: &models.TUFV001SchemaMetadata{ + Content: struct{}{}, + }, + */ + Root: &models.TUFV001SchemaRoot{ + Content: struct{}{}, + }, + }, + }, + expectSuccess: false, + }, + { + caseDesc: "empty obj", + entry: V001Entry{}, + expectSuccess: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.caseDesc, func(t *testing.T) { + if ok, err := tc.entry.Insertable(); ok != tc.expectSuccess { + t.Errorf("unexpected result calling Insertable: %v", err) } - } + }) } } diff --git a/pkg/types/tuf/v0.0.1/fuzz_test.go b/pkg/types/tuf/v0.0.1/fuzz_test.go new file mode 100644 index 000000000..3b4dec6a8 --- /dev/null +++ b/pkg/types/tuf/v0.0.1/fuzz_test.go @@ -0,0 +1,100 @@ +// +// Copyright 2022 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 tuf + +import ( + "context" + "sync" + "testing" + + fuzz "github.com/AdamKorcz/go-fuzz-headers-1" + "github.com/go-openapi/swag" + + fuzzUtils "github.com/sigstore/rekor/pkg/fuzz" + "github.com/sigstore/rekor/pkg/generated/models" + "github.com/sigstore/rekor/pkg/types" + "github.com/sigstore/rekor/pkg/types/tuf" +) + +var initter sync.Once + +func FuzzTufCreateProposedEntry(f *testing.F) { + f.Fuzz(func(t *testing.T, propsData []byte) { + initter.Do(fuzzUtils.SetFuzzLogger) + + version := "0.0.1" + + ff := fuzz.NewConsumer(propsData) + + props, cleanup, err := fuzzUtils.CreateProps(ff, "tufV001") + if err != nil { + t.Skip() + } + defer func() { + for _, c := range cleanup { + c() + } + }() + + it := tuf.New() + entry, err := it.CreateProposedEntry(context.Background(), version, props) + if err != nil { + t.Skip() + } + ei, err := types.CreateVersionedEntry(entry) + if err != nil { + t.Skip() + } + + if ok, err := ei.Insertable(); !ok || err != nil { + t.Errorf("entry created via CreateProposedEntry should be insertable: %v", err) + } + + if _, err := types.CanonicalizeEntry(context.Background(), ei); err != nil { + t.Errorf("valid insertable entry should be able to be canonicalized: %v", err) + } + + _, _ = ei.IndexKeys() + }) +} + +func FuzzTufUnmarshalAndCanonicalize(f *testing.F) { + f.Fuzz(func(t *testing.T, entryData []byte) { + initter.Do(fuzzUtils.SetFuzzLogger) + + ff := fuzz.NewConsumer(entryData) + + targetV001 := &models.TUFV001Schema{} + + if err := ff.GenerateStruct(targetV001); err != nil { + t.Skip() + } + + targetEntry := &models.TUF{ + APIVersion: swag.String(APIVERSION), + Spec: targetV001, + } + + ei, err := types.UnmarshalEntry(targetEntry) + if err != nil { + t.Skip() + } + + if _, err := types.CanonicalizeEntry(context.Background(), ei); err != nil { + t.Skip() + } + }) +} diff --git a/pkg/types/tuf/v0.0.1/tuf_v0_0_1_schema.json b/pkg/types/tuf/v0.0.1/tuf_v0_0_1_schema.json index f1a6cd3aa..5d2dc210d 100644 --- a/pkg/types/tuf/v0.0.1/tuf_v0_0_1_schema.json +++ b/pkg/types/tuf/v0.0.1/tuf_v0_0_1_schema.json @@ -20,7 +20,7 @@ "additionalProperties": true } }, - "required": [ "metadata" ] + "required": [ "content" ] }, "root" : { "description": "root metadata containing about the public keys used to sign the manifest", diff --git a/pkg/types/types_test.go b/pkg/types/types_test.go index ea7c5302e..7d9ca6647 100644 --- a/pkg/types/types_test.go +++ b/pkg/types/types_test.go @@ -38,11 +38,11 @@ func (e InvalidEntry) Kind() string { func (e InvalidEntry) SetKind(string) {} -func (e InvalidEntry) Validate(formats strfmt.Registry) error { +func (e InvalidEntry) Validate(_ strfmt.Registry) error { return nil } -func (e InvalidEntry) ContextValidate(context context.Context, formats strfmt.Registry) error { +func (e InvalidEntry) ContextValidate(_ context.Context, _ strfmt.Registry) error { return nil } @@ -57,11 +57,11 @@ func (e UnmarshalErrorValidEntry) Kind() string { func (e UnmarshalErrorValidEntry) SetKind(string) {} -func (e UnmarshalErrorValidEntry) Validate(formats strfmt.Registry) error { +func (e UnmarshalErrorValidEntry) Validate(_ strfmt.Registry) error { return errors.New("invalid content") } -func (e UnmarshalErrorValidEntry) ContextValidate(context context.Context, formats strfmt.Registry) error { +func (e UnmarshalErrorValidEntry) ContextValidate(_ context.Context, _ strfmt.Registry) error { return nil } diff --git a/pkg/util/checkpoint.go b/pkg/util/checkpoint.go index ee6059e2b..3d3534aec 100644 --- a/pkg/util/checkpoint.go +++ b/pkg/util/checkpoint.go @@ -25,12 +25,11 @@ import ( "strings" "time" - "github.com/google/trillian/types" "github.com/sigstore/sigstore/pkg/signature" "github.com/sigstore/sigstore/pkg/signature/options" ) -// heavily borrowed from https://github.com/google/trillian-examples/blob/master/formats/log/checkpoint.go +// heavily borrowed from https://github.com/transparency-dev/formats/blob/main/log/checkpoint.go type Checkpoint struct { // Origin is the unique identifier/version string @@ -168,11 +167,11 @@ func (r *SignedCheckpoint) GetTimestamp() uint64 { } // CreateAndSignCheckpoint creates a signed checkpoint as a commitment to the current root hash -func CreateAndSignCheckpoint(ctx context.Context, hostname string, treeID int64, root *types.LogRootV1, signer signature.Signer) ([]byte, error) { +func CreateAndSignCheckpoint(ctx context.Context, hostname string, treeID int64, treeSize uint64, rootHash []byte, signer signature.Signer) ([]byte, error) { sth, err := CreateSignedCheckpoint(Checkpoint{ Origin: fmt.Sprintf("%s - %d", hostname, treeID), - Size: root.TreeSize, - Hash: root.RootHash, + Size: treeSize, + Hash: rootHash, }) if err != nil { return nil, fmt.Errorf("error creating checkpoint: %v", err) diff --git a/pkg/util/checkpoint_test.go b/pkg/util/checkpoint_test.go index d78d6d5ff..cfc54ffe7 100644 --- a/pkg/util/checkpoint_test.go +++ b/pkg/util/checkpoint_test.go @@ -30,7 +30,6 @@ import ( "time" "github.com/google/go-cmp/cmp" - "github.com/google/trillian/types" "github.com/sigstore/sigstore/pkg/signature" "github.com/sigstore/sigstore/pkg/signature/options" "golang.org/x/mod/sumdb/note" @@ -458,7 +457,7 @@ func TestSignCheckpoint(t *testing.T) { t.Fatalf("error generating signer: %v", err) } ctx := context.Background() - scBytes, err := CreateAndSignCheckpoint(ctx, hostname, treeID, &types.LogRootV1{TreeSize: treeSize, RootHash: rootHash[:]}, signer) + scBytes, err := CreateAndSignCheckpoint(ctx, hostname, treeID, treeSize, rootHash[:], signer) if err != nil { t.Fatalf("error creating signed checkpoint: %v", err) } diff --git a/pkg/util/pubkey.go b/pkg/util/pubkey.go deleted file mode 100644 index 06c49ca23..000000000 --- a/pkg/util/pubkey.go +++ /dev/null @@ -1,44 +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 util - -import ( - "context" - "crypto/ecdsa" - "errors" - - "github.com/sigstore/rekor/pkg/generated/client" - "github.com/sigstore/rekor/pkg/generated/client/pubkey" - "github.com/sigstore/sigstore/pkg/cryptoutils" -) - -func PublicKey(ctx context.Context, c *client.Rekor) (*ecdsa.PublicKey, error) { - resp, err := c.Pubkey.GetPublicKey(&pubkey.GetPublicKeyParams{Context: ctx}) - if err != nil { - return nil, err - } - - // marshal the pubkey - pubKey, err := cryptoutils.UnmarshalPEMToPublicKey([]byte(resp.GetPayload())) - if err != nil { - return nil, err - } - ed, ok := pubKey.(*ecdsa.PublicKey) - if !ok { - return nil, errors.New("public key retrieved from Rekor is not an ECDSA key") - } - return ed, nil -} diff --git a/pkg/util/timestamp_note.go b/pkg/util/timestamp_note.go deleted file mode 100644 index d2f44c288..000000000 --- a/pkg/util/timestamp_note.go +++ /dev/null @@ -1,171 +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 util - -import ( - "bytes" - "encoding/base64" - "errors" - "fmt" - "net/url" - "strconv" - "strings" - "time" -) - -// Signed note based timestamp responses - -type TimestampNote struct { - // Origin is the unique identifier/version string - Origin string - // MessageImprint is the hash of the message to timestamp, of the form sha256: - MessageImprint string - // Nonce is a short random bytes to prove response freshness - Nonce []byte - // Time is the timestamp to imprint on the message - Time time.Time - // Radius is the time in microseconds used to indicate certainty - Radius int64 - // CertChainRef is a reference URL to the valid timestamping cert chain used to sign the response - CertChainRef *url.URL - // OtherContent is any additional data to be included in the signed payload; each element is assumed to be one line - OtherContent []string -} - -// String returns the String representation of the TimestampNote -func (t TimestampNote) String() string { - var b strings.Builder - time, _ := t.Time.MarshalText() - fmt.Fprintf(&b, "%s\n%s\n%s\n%s\n%d\n%s\n", t.Origin, t.MessageImprint, base64.StdEncoding.EncodeToString(t.Nonce), - time, t.Radius, t.CertChainRef) - for _, line := range t.OtherContent { - fmt.Fprintf(&b, "%s\n", line) - } - return b.String() -} - -// MarshalText returns the common format representation of this TimestampNote. -func (t TimestampNote) MarshalText() ([]byte, error) { - return []byte(t.String()), nil -} - -// UnmarshalText parses the common formatted timestamp note data and stores the result -// in the TimestampNote. -// -// The supplied data is expected to begin with the following 6 lines of text, -// each followed by a newline: -// -// -// -// -// -// -// ... -// ... -// -// This will discard any content found after the checkpoint (including signatures) -func (t *TimestampNote) UnmarshalText(data []byte) error { - l := bytes.Split(data, []byte("\n")) - if len(l) < 7 { - return errors.New("invalid timestamp note - too few newlines") - } - origin := string(l[0]) - if len(origin) == 0 { - return errors.New("invalid timestamp note - empty ecosystem") - } - h := string(l[1]) - if err := ValidateSHA256Value(h); err != nil { - return fmt.Errorf("invalid timestamp note - invalid message hash: %w", err) - } - - nonce, err := base64.StdEncoding.DecodeString(string(l[2])) - if err != nil { - return fmt.Errorf("invalid timestamp note - invalid nonce: %w", err) - } - var timestamp time.Time - if err := timestamp.UnmarshalText(l[3]); err != nil { - return fmt.Errorf("invalid timestamp note - invalid time: %w", err) - } - r, err := strconv.ParseInt(string(l[4]), 10, 64) - if err != nil { - return fmt.Errorf("invalid timestamp note - invalid radius: %w", err) - } - u, err := url.Parse(string(l[5])) - if err != nil { - return fmt.Errorf("invalid timestamp note - invalid URI: %w", err) - - } - *t = TimestampNote{ - Origin: origin, - MessageImprint: h, - Nonce: nonce, - Time: timestamp, - Radius: r, - CertChainRef: u, - } - if len(l) >= 8 { - for _, line := range l[6:] { - if len(line) == 0 { - break - } - t.OtherContent = append(t.OtherContent, string(line)) - } - } - return nil -} - -type SignedTimestampNote struct { - TimestampNote - SignedNote -} - -func CreateSignedTimestampNote(t TimestampNote) (*SignedTimestampNote, error) { - text, err := t.MarshalText() - if err != nil { - return nil, err - } - return &SignedTimestampNote{ - TimestampNote: t, - SignedNote: SignedNote{Note: string(text)}, - }, nil -} - -func SignedTimestampNoteValidator(strToValidate string) bool { - s := SignedNote{} - if err := s.UnmarshalText([]byte(strToValidate)); err != nil { - return false - } - c := &TimestampNote{} - return c.UnmarshalText([]byte(s.Note)) == nil -} - -func TimestampNoteValidator(strToValidate string) bool { - c := &TimestampNote{} - return c.UnmarshalText([]byte(strToValidate)) == nil -} - -func (r *SignedTimestampNote) UnmarshalText(data []byte) error { - s := SignedNote{} - if err := s.UnmarshalText([]byte(data)); err != nil { - return fmt.Errorf("unmarshalling signed note: %w", err) - } - t := TimestampNote{} - if err := t.UnmarshalText([]byte(s.Note)); err != nil { - return fmt.Errorf("unmarshalling timestamp note: %w", err) - } - *r = SignedTimestampNote{TimestampNote: t, SignedNote: s} - return nil -} diff --git a/pkg/util/timestamp_note_test.go b/pkg/util/timestamp_note_test.go deleted file mode 100644 index f263e1d85..000000000 --- a/pkg/util/timestamp_note_test.go +++ /dev/null @@ -1,537 +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 util - -import ( - "crypto" - "crypto/ecdsa" - "crypto/ed25519" - "crypto/elliptic" - "crypto/rand" - "crypto/rsa" - "crypto/sha256" - "encoding/hex" - "math/big" - "net/url" - "testing" - "time" - - "github.com/google/go-cmp/cmp" - "github.com/sigstore/sigstore/pkg/signature" - "github.com/sigstore/sigstore/pkg/signature/options" - "golang.org/x/mod/sumdb/note" -) - -// heavily borrowed from https://github.com/google/trillian-examples/blob/master/formats/log/checkpoint_test.go - -func TestMarshalTimestampNote(t *testing.T) { - certChainURL, err := url.Parse("http://localhost:3000/api/v1/timestamp/certchain") - if err != nil { - t.Fatal("error parsing URL") - } - location, err := time.LoadLocation("UTC") - if err != nil { - t.Fatal("error loading location") - } - someTime := time.Date(2021, 07, 26, 0, 0, 0, 0, location) - for _, test := range []struct { - msg []byte - t TimestampNote - want string - }{ - { - msg: []byte("bananas"), - t: TimestampNote{ - Origin: "Timestamp Note v0", - Nonce: big.NewInt(123).Bytes(), - Time: someTime, - Radius: 123, - CertChainRef: certChainURL, - }, - want: "Timestamp Note v0\nsha256:e4ba5cbd251c98e6cd1c23f126a3b81d8d8328abc95387229850952b3ef9f904\new==\n2021-07-26T00:00:00Z\n123\nhttp://localhost:3000/api/v1/timestamp/certchain\n", - }, - { - msg: []byte("the view from the tree tops is great!"), - t: TimestampNote{ - Origin: "Timestamp Note v1", - Nonce: big.NewInt(12345678).Bytes(), - Time: someTime, - Radius: 1, - CertChainRef: certChainURL, - }, - want: "Timestamp Note v1\nsha256:17fb2e8cbf5f60f881c075b1fd0cad32913f2f08b35053fed1c5a785dff90e8e\nvGFO\n2021-07-26T00:00:00Z\n1\nhttp://localhost:3000/api/v1/timestamp/certchain\n", - }, { - msg: []byte("bananas"), - t: TimestampNote{ - Origin: "Timestamp Note v7", - Nonce: big.NewInt(123).Bytes(), - Time: someTime, - Radius: 123, - CertChainRef: certChainURL, - OtherContent: []string{"foo", "bar"}, - }, - want: "Timestamp Note v7\nsha256:e4ba5cbd251c98e6cd1c23f126a3b81d8d8328abc95387229850952b3ef9f904\new==\n2021-07-26T00:00:00Z\n123\nhttp://localhost:3000/api/v1/timestamp/certchain\nfoo\nbar\n", - }, - } { - t.Run(string(test.t.Origin), func(t *testing.T) { - h := sha256.Sum256([]byte(test.msg)) - test.t.MessageImprint = "sha256:" + hex.EncodeToString(h[:]) - got, err := test.t.MarshalText() - if err != nil { - t.Fatalf("unexpected error marshalling: %v", err) - } - if string(got) != test.want { - t.Fatalf("Marshal = %q, want %q", got, test.want) - } - }) - } -} - -func TestUnmarshalTimestampNote(t *testing.T) { - certChainURL, err := url.Parse("http://localhost:3000/api/v1/timestamp/certchain") - if err != nil { - t.Fatal("error parsing URL") - } - location, err := time.LoadLocation("UTC") - if err != nil { - t.Fatal("error loading location") - } - someTime := time.Date(2021, 07, 26, 0, 0, 0, 0, location) - for _, test := range []struct { - desc string - m string - want TimestampNote - wantErr bool - }{ - { - desc: "valid one", - m: "Timestamp Note v0\nsha256:e4ba5cbd251c98e6cd1c23f126a3b81d8d8328abc95387229850952b3ef9f904\new==\n2021-07-26T00:00:00Z\n123\nhttp://localhost:3000/api/v1/timestamp/certchain\n", - want: TimestampNote{ - Origin: "Timestamp Note v0", - MessageImprint: "sha256:e4ba5cbd251c98e6cd1c23f126a3b81d8d8328abc95387229850952b3ef9f904", - Nonce: big.NewInt(123).Bytes(), - Time: someTime, - Radius: 123, - CertChainRef: certChainURL, - }, - wantErr: false, - }, { - desc: "valid with different ecosystem", - m: "Timestamp Note v1\nsha256:17fb2e8cbf5f60f881c075b1fd0cad32913f2f08b35053fed1c5a785dff90e8e\nvGFO\n2021-07-26T00:00:00Z\n1\nhttp://localhost:3000/api/v1/timestamp/certchain\n", - want: TimestampNote{ - Origin: "Timestamp Note v1", - MessageImprint: "sha256:17fb2e8cbf5f60f881c075b1fd0cad32913f2f08b35053fed1c5a785dff90e8e", - Nonce: big.NewInt(12345678).Bytes(), - Time: someTime, - Radius: 1, - CertChainRef: certChainURL, - }, - }, { - desc: "valid with trailing data", - m: "Timestamp Note v7\nsha256:e4ba5cbd251c98e6cd1c23f126a3b81d8d8328abc95387229850952b3ef9f904\new==\n2021-07-26T00:00:00Z\n123\nhttp://localhost:3000/api/v1/timestamp/certchain\nfoo\nbar\n", - want: TimestampNote{ - Origin: "Timestamp Note v7", - MessageImprint: "sha256:e4ba5cbd251c98e6cd1c23f126a3b81d8d8328abc95387229850952b3ef9f904", - Nonce: big.NewInt(123).Bytes(), - Time: someTime, - Radius: 123, - CertChainRef: certChainURL, - OtherContent: []string{"foo", "bar"}, - }, - }, { - desc: "valid with trailing newlines", - m: "Timestamp Note v1\nsha256:17fb2e8cbf5f60f881c075b1fd0cad32913f2f08b35053fed1c5a785dff90e8e\nvGFO\n2021-07-26T00:00:00Z\n1\nhttp://localhost:3000/api/v1/timestamp/certchain\n\n\n\n", - want: TimestampNote{ - Origin: "Timestamp Note v1", - MessageImprint: "sha256:17fb2e8cbf5f60f881c075b1fd0cad32913f2f08b35053fed1c5a785dff90e8e", - Nonce: big.NewInt(12345678).Bytes(), - Time: someTime, - Radius: 1, - CertChainRef: certChainURL, - }, - }, { - desc: "invalid - insufficient lines", - m: "Timestamp Note v1\nsha256:17fb2e8cbf5f60f881c075b1fd0cad32913f2f08b35053fed1c5a785dff90e8e\n", - wantErr: true, - }, { - desc: "invalid - empty header", - m: "\nsha256:17fb2e8cbf5f60f881c075b1fd0cad32913f2f08b35053fed1c5a785dff90e8e\nvGFO\n2021-07-26T00:00:00Z\n1\nhttp://localhost:3000/api/v1/timestamp/certchain\n", - wantErr: true, - }, { - desc: "invalid - missing newline", - m: "Timestamp Note v1\nsha256:17fb2e8cbf5f60f881c075b1fd0cad32913f2f08b35053fed1c5a785dff90e8e\nvGFO\n2021-07-26T00:00:00Z\n1\nhttp://localhost:3000/api/v1/timestamp/certchain", - wantErr: true, - }, { - desc: "invalid sha - not a valid sha", - m: "Timestamp Note v1\nsha256:17fb2e8cbf60f881c075b1fd0cad32913f2f08b35053fed1c5a785dff90e8e\nvGFO\n2021-07-26T00:00:00Z\n1\nhttp://localhost:3000/api/v1/timestamp/certchain\n", - wantErr: true, - }, { - desc: "invalid base64 - nonce", - m: "Timestamp Note v1\nsha256:17fb2e8cbf5f60f881c075b1fd0cad32913f2f08b35053fed1c5a785dff90e8e\n@\n2021-07-26T00:00:00Z\n1\nhttp://localhost:3000/api/v1/timestamp/certchain\n", - wantErr: true, - }, { - desc: "invalid time", - m: "Timestamp Note v1\nsha256:17fb2e8cbf5f60f881c075b1fd0cad32913f2f08b35053fed1c5a785dff90e8e\nvGFO\nabc\n1\nhttp://localhost:3000/api/v1/timestamp/certchain\n", - wantErr: true, - }, { - desc: "invalid radius - not an int", - m: "Timestamp Note v1\nsha256:17fb2e8cbf5f60f881c075b1fd0cad32913f2f08b35053fed1c5a785dff90e8e\nvGFO\n2021-07-26T00:00:00Z\na\nhttp://localhost:3000/api/v1/timestamp/certchain\n", - wantErr: true, - }, - { - desc: "invalid cert chain - not a url", - m: "Timestamp Note v1\nsha256:17fb2e8cbf5f60f881c075b1fd0cad32913f2f08b35053fed1c5a785dff90e8e\nvGFO\n2021-07-26T00:00:00Z\n1\n%gh&%ij\n", - wantErr: true, - }, - } { - t.Run(string(test.desc), func(t *testing.T) { - var got TimestampNote - var gotErr error - if gotErr = got.UnmarshalText([]byte(test.m)); (gotErr != nil) != test.wantErr { - t.Fatalf("Unmarshal = %q, wantErr: %T", gotErr, test.wantErr) - } - if diff := cmp.Diff(test.want, got); len(diff) != 0 { - t.Fatalf("Unmarshalled TimestampNote with diff %s", diff) - } - if !test.wantErr != TimestampNoteValidator(test.m) { - t.Fatalf("Validator failed for %s", test.desc) - } - }) - } -} - -func TestSigningRoundtripTimestampNote(t *testing.T) { - certChainURL, err := url.Parse("http://localhost:3000/api/v1/timestamp/certchain") - if err != nil { - t.Fatal("error parsing URL") - } - location, err := time.LoadLocation("UTC") - if err != nil { - t.Fatal("error loading location") - } - someTime := time.Date(2021, 07, 26, 0, 0, 0, 0, location) - rsaKey, _ := rsa.GenerateKey(rand.Reader, 2048) - ecdsaKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) - edPubKey, edPrivKey, _ := ed25519.GenerateKey(rand.Reader) - for _, test := range []struct { - t TimestampNote - identity string - signer crypto.Signer - pubKey crypto.PublicKey - opts crypto.SignerOpts - wantSignErr bool - wantVerifyErr bool - }{ - { - t: TimestampNote{ - Origin: "Timestamp Note RSA v0", - MessageImprint: "sha256:e4ba5cbd251c98e6cd1c23f126a3b81d8d8328abc95387229850952b3ef9f904", - Nonce: big.NewInt(123).Bytes(), - Time: someTime, - Radius: 123, - CertChainRef: certChainURL, - }, - identity: "someone", - signer: rsaKey, - pubKey: rsaKey.Public(), - opts: &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthAuto, Hash: crypto.SHA256}, - wantSignErr: false, - wantVerifyErr: false, - }, - { - t: TimestampNote{ - Origin: "Timestamp Note ECDSA v0", - MessageImprint: "sha256:e4ba5cbd251c98e6cd1c23f126a3b81d8d8328abc95387229850952b3ef9f904", - Nonce: big.NewInt(123).Bytes(), - Time: someTime, - Radius: 123, - CertChainRef: certChainURL, - }, - identity: "someone", - signer: ecdsaKey, - pubKey: ecdsaKey.Public(), - opts: nil, - wantSignErr: false, - wantVerifyErr: false, - }, - { - t: TimestampNote{ - Origin: "Timestamp Note ED25519 v0", - MessageImprint: "sha256:e4ba5cbd251c98e6cd1c23f126a3b81d8d8328abc95387229850952b3ef9f904", - Nonce: big.NewInt(123).Bytes(), - Time: someTime, - Radius: 123, - CertChainRef: certChainURL, - }, - identity: "someone", - signer: edPrivKey, - pubKey: edPubKey, - opts: crypto.Hash(0), - wantSignErr: false, - wantVerifyErr: false, - }, - { - t: TimestampNote{ - Origin: "Timestamp Note Mismatch v0", - MessageImprint: "sha256:e4ba5cbd251c98e6cd1c23f126a3b81d8d8328abc95387229850952b3ef9f904", - Nonce: big.NewInt(123).Bytes(), - Time: someTime, - Radius: 123, - CertChainRef: certChainURL, - }, - identity: "someone", - signer: edPrivKey, - pubKey: ecdsaKey.Public(), - opts: crypto.Hash(0), - wantSignErr: false, - wantVerifyErr: true, - }, - { - t: TimestampNote{ - Origin: "Timestamp Note Mismatch v1", - MessageImprint: "sha256:e4ba5cbd251c98e6cd1c23f126a3b81d8d8328abc95387229850952b3ef9f904", - Nonce: big.NewInt(123).Bytes(), - Time: someTime, - Radius: 123, - CertChainRef: certChainURL, - }, - identity: "someone", - signer: ecdsaKey, - pubKey: rsaKey.Public(), - opts: &rsa.PSSOptions{Hash: crypto.SHA256}, - wantSignErr: false, - wantVerifyErr: true, - }, - { - t: TimestampNote{ - Origin: "Timestamp Note Mismatch v2", - MessageImprint: "sha256:e4ba5cbd251c98e6cd1c23f126a3b81d8d8328abc95387229850952b3ef9f904", - Nonce: big.NewInt(123).Bytes(), - Time: someTime, - Radius: 123, - CertChainRef: certChainURL, - }, - identity: "someone", - signer: edPrivKey, - pubKey: rsaKey.Public(), - opts: &rsa.PSSOptions{Hash: crypto.SHA256}, - wantSignErr: false, - wantVerifyErr: true, - }, - { - t: TimestampNote{ - Origin: "Timestamp Note Mismatch v3", - MessageImprint: "sha256:e4ba5cbd251c98e6cd1c23f126a3b81d8d8328abc95387229850952b3ef9f904", - Nonce: big.NewInt(123).Bytes(), - Time: someTime, - Radius: 123, - CertChainRef: certChainURL, - }, - identity: "someone", - signer: ecdsaKey, - pubKey: edPubKey, - opts: nil, - wantSignErr: false, - wantVerifyErr: true, - }, - } { - t.Run(string(test.t.Origin), func(t *testing.T) { - text, _ := test.t.MarshalText() - sc := &SignedNote{ - Note: string(text), - } - signer, _ := signature.LoadSigner(test.signer, crypto.SHA256) - if _, ok := test.signer.(*rsa.PrivateKey); ok { - signer, _ = signature.LoadRSAPSSSigner(test.signer.(*rsa.PrivateKey), crypto.SHA256, test.opts.(*rsa.PSSOptions)) - } - - _, err := sc.Sign(test.identity, signer, options.WithCryptoSignerOpts(test.opts)) - if (err != nil) != test.wantSignErr { - t.Fatalf("signing test failed: wantSignErr %v, err %v", test.wantSignErr, err) - } - if !test.wantSignErr { - verifier, _ := signature.LoadVerifier(test.pubKey, crypto.SHA256) - if _, ok := test.pubKey.(*rsa.PublicKey); ok { - verifier, _ = signature.LoadRSAPSSVerifier(test.pubKey.(*rsa.PublicKey), crypto.SHA256, test.opts.(*rsa.PSSOptions)) - } - - if !sc.Verify(verifier) != test.wantVerifyErr { - t.Fatalf("verification test failed %v", sc.Verify(verifier)) - } - if _, err := sc.Sign("second", signer, options.WithCryptoSignerOpts(test.opts)); err != nil { - t.Fatalf("adding second signature failed: %v", err) - } - if len(sc.Signatures) != 2 { - t.Fatalf("expected two signatures on checkpoint, only found %v", len(sc.Signatures)) - } - // finally, test marshalling object and unmarshalling - marshalledSc, err := sc.MarshalText() - if err != nil { - t.Fatalf("error during marshalling: %v", err) - } - text, _ = test.t.MarshalText() - sc2 := &SignedNote{ - Note: string(text), - } - if err := sc2.UnmarshalText(marshalledSc); err != nil { - t.Fatalf("error unmarshalling just marshalled object %v\n%v", err, string(marshalledSc)) - } - if diff := cmp.Diff(sc, sc2); len(diff) != 0 { - t.Fatalf("UnmarshalText = diff %s", diff) - } - } - }) - } -} - -func TestInvalidSigVerificationTimestampNote(t *testing.T) { - certChainURL, err := url.Parse("http://localhost:3000/api/v1/timestamp/certchain") - if err != nil { - t.Fatal("error parsing URL") - } - location, err := time.LoadLocation("UTC") - if err != nil { - t.Fatal("error loading location") - } - someTime := time.Date(2021, 07, 26, 0, 0, 0, 0, location) - ecdsaKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) - for _, test := range []struct { - t TimestampNote - s []note.Signature - pubKey crypto.PublicKey - expectedResult bool - }{ - { - t: TimestampNote{ - Origin: "Timestamp Note v0", - MessageImprint: "sha256:e4ba5cbd251c98e6cd1c23f126a3b81d8d8328abc95387229850952b3ef9f904", - Nonce: big.NewInt(123).Bytes(), - Time: someTime, - Radius: 123, - CertChainRef: certChainURL, - }, - s: []note.Signature{}, - pubKey: ecdsaKey.Public(), - expectedResult: false, - }, - { - t: TimestampNote{ - Origin: "Timestamp Note v0 - not base 64", - MessageImprint: "sha256:e4ba5cbd251c98e6cd1c23f126a3b81d8d8328abc95387229850952b3ef9f904", - Nonce: big.NewInt(123).Bytes(), - Time: someTime, - Radius: 123, - CertChainRef: certChainURL, - }, - pubKey: ecdsaKey.Public(), - s: []note.Signature{ - { - Name: "something", - Hash: 1234, - Base64: "not_base 64 string", - }, - }, - expectedResult: false, - }, - { - t: TimestampNote{ - Origin: "Timestamp Note v0 invalid signature", - MessageImprint: "sha256:e4ba5cbd251c98e6cd1c23f126a3b81d8d8328abc95387229850952b3ef9f904", - Nonce: big.NewInt(123).Bytes(), - Time: someTime, - Radius: 123, - CertChainRef: certChainURL, - }, - pubKey: ecdsaKey.Public(), - s: []note.Signature{ - { - Name: "someone", - Hash: 142, - Base64: "bm90IGEgc2ln", // valid base64, not a valid signature - }, - }, - expectedResult: false, - }, - } { - t.Run(string(test.t.Origin), func(t *testing.T) { - text, _ := test.t.MarshalText() - sc := SignedNote{ - Note: string(text), - Signatures: test.s, - } - verifier, _ := signature.LoadVerifier(test.pubKey, crypto.SHA256) - result := sc.Verify(verifier) - if result != test.expectedResult { - t.Fatal("verification test generated unexpected result") - } - }) - } -} - -// does not test validity of signatures but merely parsing logic -func TestUnmarshalSignedTimestampNote(t *testing.T) { - for _, test := range []struct { - desc string - m string - wantErr bool - }{ - { - desc: "invalid timestamp note, no signatures", - m: "Timestamp Note v0\n\new==\n2021-07-26T00:00:00Z\n123\nhttp://localhost:3000/api/v1/timestamp/certchain\n\n", - wantErr: true, - }, { - desc: "valid timestamp note, no signatures", - m: "Timestamp Note v0\nsha256:e4ba5cbd251c98e6cd1c23f126a3b81d8d8328abc95387229850952b3ef9f904\new==\n2021-07-26T00:00:00Z\n123\nhttp://localhost:3000/api/v1/timestamp/certchain\n\n", - wantErr: true, - }, { - desc: "incorrect signature line format", - m: "Timestamp Note v0\nsha256:e4ba5cbd251c98e6cd1c23f126a3b81d8d8328abc95387229850952b3ef9f904\new==\n2021-07-26T00:00:00Z\n123\nhttp://localhost:3000/api/v1/timestamp/certchain\n\n* name not-a-sig\n", - wantErr: true, - }, { - desc: "signature not base64 encoded", - - m: "Timestamp Note v0\nsha256:e4ba5cbd251c98e6cd1c23f126a3b81d8d8328abc95387229850952b3ef9f904\new==\n2021-07-26T00:00:00Z\n123\nhttp://localhost:3000/api/v1/timestamp/certchain\n\n\u2014 name not-b64\n", - wantErr: true, - }, { - desc: "missing identity", - m: "Timestamp Note v0\nsha256:e4ba5cbd251c98e6cd1c23f126a3b81d8d8328abc95387229850952b3ef9f904\new==\n2021-07-26T00:00:00Z\n123\nhttp://localhost:3000/api/v1/timestamp/certchain\n\n\u2014 YQ==\n", - wantErr: true, - }, { - desc: "signature base64 encoded but too short", - m: "Timestamp Note v0\nsha256:e4ba5cbd251c98e6cd1c23f126a3b81d8d8328abc95387229850952b3ef9f904\new==\n2021-07-26T00:00:00Z\n123\nhttp://localhost:3000/api/v1/timestamp/certchain\n\n\u2014 name YQ==\n", - wantErr: true, - }, { - desc: "valid signed timestamp note - single signature", - m: "Timestamp Note v0\nsha256:e4ba5cbd251c98e6cd1c23f126a3b81d8d8328abc95387229850952b3ef9f904\new==\n2021-07-26T00:00:00Z\n123\nhttp://localhost:3000/api/v1/timestamp/certchain\n\n\u2014 name pOhM+S/mYjEYtQsOF4lL8o/dR+nbjoz5Cvg/n486KIismpVq0s4wxBaakmryI7zThjWAqRUyECPL3WSEcVDEBQ==\n", - wantErr: false, - }, { - desc: "valid signed timestamp note - two signatures", - m: "Timestamp Note v0\nsha256:e4ba5cbd251c98e6cd1c23f126a3b81d8d8328abc95387229850952b3ef9f904\new==\n2021-07-26T00:00:00Z\n123\nhttp://localhost:3000/api/v1/timestamp/certchain\n\n\u2014 name pOhM+S/mYjEYtQsOF4lL8o/dR+nbjoz5Cvg/n486KIismpVq0s4wxBaakmryI7zThjWAqRUyECPL3WSEcVDEBQ==\n\u2014 another_name pOhM+S/mYjEYtQsOF4lL8o/dR+nbjoz5Cvg/n486KIismpVq0s4wxBaakmryI7zThjWAqRUyECPL3WSEcVDEBQ==\n", - wantErr: false, - }, - } { - t.Run(string(test.desc), func(t *testing.T) { - var got SignedNote - var gotErr error - if gotErr = got.UnmarshalText([]byte(test.m)); (gotErr != nil) != test.wantErr { - t.Fatalf("UnmarshalText(%s) = %q, wantErr: %v", test.desc, gotErr, test.wantErr) - } - if !test.wantErr != SignedTimestampNoteValidator(test.m) { - t.Fatalf("Validator failed for %s", test.desc) - } - }) - } -} diff --git a/pkg/util/util.go b/pkg/util/util.go index b800738aa..3075cc2e6 100644 --- a/pkg/util/util.go +++ b/pkg/util/util.go @@ -35,8 +35,6 @@ import ( "time" "golang.org/x/crypto/openpgp" - - "github.com/sigstore/rekor/pkg/generated/models" ) var ( @@ -384,19 +382,6 @@ func CreateArtifact(t *testing.T, artifactPath string) string { return artifact } -func extractLogEntry(t *testing.T, le models.LogEntry) models.LogEntryAnon { - t.Helper() - - if len(le) != 1 { - t.Fatal("expected length to be 1, is actually", len(le)) - } - for _, v := range le { - return v - } - // this should never happen - return models.LogEntryAnon{} -} - func write(t *testing.T, data string, path string) { t.Helper() if err := ioutil.WriteFile(path, []byte(data), 0644); err != nil { diff --git a/pkg/verify/verify.go b/pkg/verify/verify.go index 94908c00d..0bb7f1704 100644 --- a/pkg/verify/verify.go +++ b/pkg/verify/verify.go @@ -41,6 +41,8 @@ func ProveConsistency(ctx context.Context, rClient *client.Rekor, oldSTH *util.SignedCheckpoint, newSTH *util.SignedCheckpoint, treeID string) error { oldTreeSize := int64(oldSTH.Size) switch { + case oldTreeSize == 0: + return errors.New("consistency proofs can not be computed starting from an empty log") case oldTreeSize == int64(newSTH.Size): if !bytes.Equal(oldSTH.Hash, newSTH.Hash) { return errors.New("old root hash does not match STH hash") diff --git a/pkg/verify/verify_test.go b/pkg/verify/verify_test.go index dd7b1ac61..eae1c6775 100644 --- a/pkg/verify/verify_test.go +++ b/pkg/verify/verify_test.go @@ -24,7 +24,6 @@ import ( "github.com/go-openapi/runtime" "github.com/go-openapi/strfmt" "github.com/go-openapi/swag" - "github.com/google/trillian/types" "github.com/sigstore/rekor/pkg/generated/client" "github.com/sigstore/rekor/pkg/generated/client/tlog" "github.com/sigstore/rekor/pkg/generated/models" @@ -38,7 +37,7 @@ type TlogClient struct { LogInfo models.LogInfo } -func (m *TlogClient) GetLogProof(params *tlog.GetLogProofParams, opts ...tlog.ClientOption) (*tlog.GetLogProofOK, error) { +func (m *TlogClient) GetLogProof(_ *tlog.GetLogProofParams, _ ...tlog.ClientOption) (*tlog.GetLogProofOK, error) { return &tlog.GetLogProofOK{ Payload: &models.ConsistencyProof{ Hashes: m.Proof, @@ -46,20 +45,21 @@ func (m *TlogClient) GetLogProof(params *tlog.GetLogProofParams, opts ...tlog.Cl }}, nil } -func (m *TlogClient) GetLogInfo(params *tlog.GetLogInfoParams, opts ...tlog.ClientOption) (*tlog.GetLogInfoOK, error) { +func (m *TlogClient) GetLogInfo(_ *tlog.GetLogInfoParams, _ ...tlog.ClientOption) (*tlog.GetLogInfoOK, error) { return &tlog.GetLogInfoOK{ Payload: &m.LogInfo, }, nil } // TODO: Implement mock -func (m *TlogClient) SetTransport(transport runtime.ClientTransport) { +func (m *TlogClient) SetTransport(_ runtime.ClientTransport) { } func TestConsistency(t *testing.T) { root2String := "5be1758dd2228acfaf2546b4b6ce8aa40c82a3748f3dcb550e0d67ba34f02a45" root2, _ := hex.DecodeString(root2String) root1, _ := hex.DecodeString("59a575f157274702c38de3ab1e1784226f391fb79500ebf9f02b4439fb77574c") + root0, _ := hex.DecodeString("1a341bc342ff4e567387de9789ab14000b147124317841489172419874198147") hashes := []string{"d3be742c8d73e2dd3c5635843e987ad3dfb3837616f412a07bf730c3ad73f5cb"} for _, test := range []struct { name string @@ -138,6 +138,20 @@ func TestConsistency(t *testing.T) { }, wantErr: true, }, + { + name: "invalid consistency - empty log", + oldC: util.Checkpoint{ + Origin: "test", + Size: uint64(0), + Hash: root0, + }, + newC: util.Checkpoint{ + Origin: "test", + Size: uint64(2), + Hash: root2, + }, + wantErr: true, + }, } { var mClient client.Rekor mClient.Tlog = &TlogClient{Proof: hashes, Root: root2String} @@ -238,7 +252,7 @@ func TestCheckpoint(t *testing.T) { t.Fatalf("error generating signer: %v", err) } ctx := context.Background() - scBytes, err := util.CreateAndSignCheckpoint(ctx, hostname, treeID, &types.LogRootV1{TreeSize: treeSize, RootHash: rootHash[:]}, signer) + scBytes, err := util.CreateAndSignCheckpoint(ctx, hostname, treeID, treeSize, rootHash[:], signer) if err != nil { t.Fatalf("error creating signed checkpoint: %v", err) } diff --git a/pkg/witness/mockclient/generate.go b/pkg/witness/mockclient/generate.go new file mode 100644 index 000000000..a3be36d65 --- /dev/null +++ b/pkg/witness/mockclient/generate.go @@ -0,0 +1,18 @@ +// 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. + +// Package mockclient provides a mockable version of the Trillian log client API. +package mockclient + +//go:generate mockgen -package mockclient -destination mock_log_client.go github.com/google/trillian TrillianLogClient diff --git a/pkg/witness/mockclient/mock_log_client.go b/pkg/witness/mockclient/mock_log_client.go new file mode 100644 index 000000000..33859f9f7 --- /dev/null +++ b/pkg/witness/mockclient/mock_log_client.go @@ -0,0 +1,217 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/google/trillian (interfaces: TrillianLogClient) + +// Package mockclient is a generated GoMock package. +package mockclient + +import ( + context "context" + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + trillian "github.com/google/trillian" + grpc "google.golang.org/grpc" +) + +// MockTrillianLogClient is a mock of TrillianLogClient interface. +type MockTrillianLogClient struct { + ctrl *gomock.Controller + recorder *MockTrillianLogClientMockRecorder +} + +// MockTrillianLogClientMockRecorder is the mock recorder for MockTrillianLogClient. +type MockTrillianLogClientMockRecorder struct { + mock *MockTrillianLogClient +} + +// NewMockTrillianLogClient creates a new mock instance. +func NewMockTrillianLogClient(ctrl *gomock.Controller) *MockTrillianLogClient { + mock := &MockTrillianLogClient{ctrl: ctrl} + mock.recorder = &MockTrillianLogClientMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockTrillianLogClient) EXPECT() *MockTrillianLogClientMockRecorder { + return m.recorder +} + +// AddSequencedLeaves mocks base method. +func (m *MockTrillianLogClient) AddSequencedLeaves(arg0 context.Context, arg1 *trillian.AddSequencedLeavesRequest, arg2 ...grpc.CallOption) (*trillian.AddSequencedLeavesResponse, error) { + m.ctrl.T.Helper() + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "AddSequencedLeaves", varargs...) + ret0, _ := ret[0].(*trillian.AddSequencedLeavesResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// AddSequencedLeaves indicates an expected call of AddSequencedLeaves. +func (mr *MockTrillianLogClientMockRecorder) AddSequencedLeaves(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddSequencedLeaves", reflect.TypeOf((*MockTrillianLogClient)(nil).AddSequencedLeaves), varargs...) +} + +// GetConsistencyProof mocks base method. +func (m *MockTrillianLogClient) GetConsistencyProof(arg0 context.Context, arg1 *trillian.GetConsistencyProofRequest, arg2 ...grpc.CallOption) (*trillian.GetConsistencyProofResponse, error) { + m.ctrl.T.Helper() + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "GetConsistencyProof", varargs...) + ret0, _ := ret[0].(*trillian.GetConsistencyProofResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetConsistencyProof indicates an expected call of GetConsistencyProof. +func (mr *MockTrillianLogClientMockRecorder) GetConsistencyProof(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetConsistencyProof", reflect.TypeOf((*MockTrillianLogClient)(nil).GetConsistencyProof), varargs...) +} + +// GetEntryAndProof mocks base method. +func (m *MockTrillianLogClient) GetEntryAndProof(arg0 context.Context, arg1 *trillian.GetEntryAndProofRequest, arg2 ...grpc.CallOption) (*trillian.GetEntryAndProofResponse, error) { + m.ctrl.T.Helper() + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "GetEntryAndProof", varargs...) + ret0, _ := ret[0].(*trillian.GetEntryAndProofResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetEntryAndProof indicates an expected call of GetEntryAndProof. +func (mr *MockTrillianLogClientMockRecorder) GetEntryAndProof(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetEntryAndProof", reflect.TypeOf((*MockTrillianLogClient)(nil).GetEntryAndProof), varargs...) +} + +// GetInclusionProof mocks base method. +func (m *MockTrillianLogClient) GetInclusionProof(arg0 context.Context, arg1 *trillian.GetInclusionProofRequest, arg2 ...grpc.CallOption) (*trillian.GetInclusionProofResponse, error) { + m.ctrl.T.Helper() + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "GetInclusionProof", varargs...) + ret0, _ := ret[0].(*trillian.GetInclusionProofResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetInclusionProof indicates an expected call of GetInclusionProof. +func (mr *MockTrillianLogClientMockRecorder) GetInclusionProof(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetInclusionProof", reflect.TypeOf((*MockTrillianLogClient)(nil).GetInclusionProof), varargs...) +} + +// GetInclusionProofByHash mocks base method. +func (m *MockTrillianLogClient) GetInclusionProofByHash(arg0 context.Context, arg1 *trillian.GetInclusionProofByHashRequest, arg2 ...grpc.CallOption) (*trillian.GetInclusionProofByHashResponse, error) { + m.ctrl.T.Helper() + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "GetInclusionProofByHash", varargs...) + ret0, _ := ret[0].(*trillian.GetInclusionProofByHashResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetInclusionProofByHash indicates an expected call of GetInclusionProofByHash. +func (mr *MockTrillianLogClientMockRecorder) GetInclusionProofByHash(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetInclusionProofByHash", reflect.TypeOf((*MockTrillianLogClient)(nil).GetInclusionProofByHash), varargs...) +} + +// GetLatestSignedLogRoot mocks base method. +func (m *MockTrillianLogClient) GetLatestSignedLogRoot(arg0 context.Context, arg1 *trillian.GetLatestSignedLogRootRequest, arg2 ...grpc.CallOption) (*trillian.GetLatestSignedLogRootResponse, error) { + m.ctrl.T.Helper() + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "GetLatestSignedLogRoot", varargs...) + ret0, _ := ret[0].(*trillian.GetLatestSignedLogRootResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetLatestSignedLogRoot indicates an expected call of GetLatestSignedLogRoot. +func (mr *MockTrillianLogClientMockRecorder) GetLatestSignedLogRoot(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLatestSignedLogRoot", reflect.TypeOf((*MockTrillianLogClient)(nil).GetLatestSignedLogRoot), varargs...) +} + +// GetLeavesByRange mocks base method. +func (m *MockTrillianLogClient) GetLeavesByRange(arg0 context.Context, arg1 *trillian.GetLeavesByRangeRequest, arg2 ...grpc.CallOption) (*trillian.GetLeavesByRangeResponse, error) { + m.ctrl.T.Helper() + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "GetLeavesByRange", varargs...) + ret0, _ := ret[0].(*trillian.GetLeavesByRangeResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetLeavesByRange indicates an expected call of GetLeavesByRange. +func (mr *MockTrillianLogClientMockRecorder) GetLeavesByRange(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLeavesByRange", reflect.TypeOf((*MockTrillianLogClient)(nil).GetLeavesByRange), varargs...) +} + +// InitLog mocks base method. +func (m *MockTrillianLogClient) InitLog(arg0 context.Context, arg1 *trillian.InitLogRequest, arg2 ...grpc.CallOption) (*trillian.InitLogResponse, error) { + m.ctrl.T.Helper() + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "InitLog", varargs...) + ret0, _ := ret[0].(*trillian.InitLogResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// InitLog indicates an expected call of InitLog. +func (mr *MockTrillianLogClientMockRecorder) InitLog(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InitLog", reflect.TypeOf((*MockTrillianLogClient)(nil).InitLog), varargs...) +} + +// QueueLeaf mocks base method. +func (m *MockTrillianLogClient) QueueLeaf(arg0 context.Context, arg1 *trillian.QueueLeafRequest, arg2 ...grpc.CallOption) (*trillian.QueueLeafResponse, error) { + m.ctrl.T.Helper() + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "QueueLeaf", varargs...) + ret0, _ := ret[0].(*trillian.QueueLeafResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueueLeaf indicates an expected call of QueueLeaf. +func (mr *MockTrillianLogClientMockRecorder) QueueLeaf(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueueLeaf", reflect.TypeOf((*MockTrillianLogClient)(nil).QueueLeaf), varargs...) +} diff --git a/pkg/witness/publish_checkpoint.go b/pkg/witness/publish_checkpoint.go new file mode 100644 index 000000000..b812e3687 --- /dev/null +++ b/pkg/witness/publish_checkpoint.go @@ -0,0 +1,199 @@ +// 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. + +package witness + +import ( + "context" + "encoding/hex" + "fmt" + "strconv" + "time" + + "github.com/google/trillian" + "github.com/google/trillian/types" + "github.com/prometheus/client_golang/prometheus" + "github.com/redis/go-redis/v9" + "github.com/sigstore/rekor/pkg/log" + "github.com/sigstore/rekor/pkg/trillianclient" + "github.com/sigstore/rekor/pkg/util" + "github.com/sigstore/sigstore/pkg/signature" + "google.golang.org/grpc/codes" +) + +// CheckpointPublisher is a long-running job to periodically publish signed checkpoints to etc.d +type CheckpointPublisher struct { + ctx context.Context + // logClient is the client for Trillian + logClient trillian.TrillianLogClient + // treeID is used to construct the origin and configure the Trillian client + treeID int64 + // hostname is used to construct the origin ("hostname - treeID") + hostname string + // signer signs the checkpoint + signer signature.Signer + // publishFreq is how often a new checkpoint is published to Rekor, in minutes + checkpointFreq uint + // redisClient to upload signed checkpoints + redisClient *redis.Client + // reqCounter tracks successes and failures for publishing + reqCounter *prometheus.CounterVec +} + +// Constant values used with metrics +const ( + Success = iota + SuccessObtainLock + GetCheckpoint + UnmarshalCheckpoint + SignCheckpoint + RedisFailure + RedisLatestFailure +) + +// NewCheckpointPublisher creates a CheckpointPublisher to write stable checkpoints to Redis +func NewCheckpointPublisher(ctx context.Context, + logClient trillian.TrillianLogClient, + treeID int64, + hostname string, + signer signature.Signer, + redisClient *redis.Client, + checkpointFreq uint, + reqCounter *prometheus.CounterVec) CheckpointPublisher { + return CheckpointPublisher{ctx: ctx, logClient: logClient, treeID: treeID, hostname: hostname, + signer: signer, checkpointFreq: checkpointFreq, redisClient: redisClient, reqCounter: reqCounter} +} + +// StartPublisher creates a long-running task that publishes the latest checkpoint every X minutes +// Writing to Redis is best effort. Failure will be detected either through metrics or by witnesses +// or Verifiers monitoring for fresh checkpoints. Failure can occur after a lock is obtained but +// before publishing the latest checkpoint. If this occurs due to a sporadic failure, this simply +// means that a witness will not see a fresh checkpoint for an additional period. +func (c *CheckpointPublisher) StartPublisher(ctx context.Context) { + tc := trillianclient.NewTrillianClient(context.Background(), c.logClient, c.treeID) + sTreeID := strconv.FormatInt(c.treeID, 10) + + // publish on startup to ensure a checkpoint is available the first time Rekor starts up + c.publish(&tc, sTreeID) + + ticker := time.NewTicker(time.Duration(c.checkpointFreq) * time.Minute) + go func() { + for { + select { + case <-ctx.Done(): + return + case <-ticker.C: + c.publish(&tc, sTreeID) + } + } + }() +} + +// publish publishes the latest checkpoint to Redis once +func (c *CheckpointPublisher) publish(tc *trillianclient.TrillianClient, sTreeID string) { + // get latest checkpoint + resp := tc.GetLatest(0) + if resp.Status != codes.OK { + c.reqCounter.With( + map[string]string{ + "shard": sTreeID, + "code": strconv.Itoa(GetCheckpoint), + }).Inc() + log.Logger.Errorf("error getting latest checkpoint to publish: %v", resp.Status) + return + } + + // unmarshal checkpoint + root := &types.LogRootV1{} + if err := root.UnmarshalBinary(resp.GetLatestResult.SignedLogRoot.LogRoot); err != nil { + c.reqCounter.With( + map[string]string{ + "shard": sTreeID, + "code": strconv.Itoa(UnmarshalCheckpoint), + }).Inc() + log.Logger.Errorf("error unmarshalling latest checkpoint to publish: %v", err) + return + } + + // sign checkpoint with Rekor private key + checkpoint, err := util.CreateAndSignCheckpoint(context.Background(), c.hostname, c.treeID, root.TreeSize, root.RootHash, c.signer) + if err != nil { + c.reqCounter.With( + map[string]string{ + "shard": sTreeID, + "code": strconv.Itoa(SignCheckpoint), + }).Inc() + log.Logger.Errorf("error signing checkpoint to publish: %v", err) + return + } + + // encode checkpoint as hex to write to redis + hexCP := hex.EncodeToString(checkpoint) + + // write checkpoint to Redis if key does not yet exist + // this prevents multiple instances of Rekor from writing different checkpoints in the same time window + ts := time.Now().Truncate(time.Duration(c.checkpointFreq) * time.Minute).UnixNano() + // key is treeID/timestamp, where timestamp is rounded down to the nearest X minutes + key := fmt.Sprintf("%d/%d", c.treeID, ts) + ctx, cancel := context.WithTimeout(c.ctx, 10*time.Second) + defer cancel() + + // return value ignored, which is whether or not the entry was set + // no error is thrown if the key already exists + successNX, err := c.redisClient.SetNX(ctx, key, hexCP, 0).Result() + if err != nil { + c.reqCounter.With( + map[string]string{ + "shard": sTreeID, + "code": strconv.Itoa(RedisFailure), + }).Inc() + log.Logger.Errorf("error with client publishing checkpoint: %v", err) + return + } + // if the key was not set, then the key already exists for this time period + if !successNX { + return + } + + // successful obtaining of lock for time period + c.reqCounter.With( + map[string]string{ + "shard": sTreeID, + "code": strconv.Itoa(SuccessObtainLock), + }).Inc() + + // on successfully obtaining the "lock" for the time window, update latest checkpoint + latestKey := fmt.Sprintf("%d/latest", c.treeID) + latestCtx, latestCancel := context.WithTimeout(c.ctx, 10*time.Second) + defer latestCancel() + + // return value ignored, which is whether or not the entry was set + // no error is thrown if the key already exists + if _, err = c.redisClient.Set(latestCtx, latestKey, hexCP, 0).Result(); err != nil { + c.reqCounter.With( + map[string]string{ + "shard": sTreeID, + "code": strconv.Itoa(RedisLatestFailure), + }).Inc() + log.Logger.Errorf("error with client publishing latest checkpoint: %v", err) + return + } + + // successful publish + c.reqCounter.With( + map[string]string{ + "shard": sTreeID, + "code": strconv.Itoa(Success), + }).Inc() +} diff --git a/pkg/witness/publish_checkpoint_test.go b/pkg/witness/publish_checkpoint_test.go new file mode 100644 index 000000000..c6453f35e --- /dev/null +++ b/pkg/witness/publish_checkpoint_test.go @@ -0,0 +1,324 @@ +// 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. + +package witness + +import ( + "context" + "crypto" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "errors" + "fmt" + "testing" + "time" + + "github.com/go-redis/redismock/v9" + "github.com/golang/mock/gomock" + "github.com/google/trillian" + "github.com/google/trillian/types" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/testutil" + "github.com/sigstore/rekor/pkg/witness/mockclient" + "github.com/sigstore/sigstore/pkg/signature" + "go.uber.org/goleak" +) + +func TestPublishCheckpoint(t *testing.T) { + treeID := 1234 + hostname := "rekor-test" + freq := 1 + counter := prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "rekor_checkpoint_publish", + Help: "Checkpoint publishing by shard and code", + }, []string{"shard", "code"}) + priv, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + signer, _ := signature.LoadSigner(priv, crypto.SHA256) + + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + root := &types.LogRootV1{TreeSize: 10, RootHash: []byte{1}, TimestampNanos: 123, Revision: 0} + mRoot, err := root.MarshalBinary() + if err != nil { + t.Fatalf("error marshalling log root: %v", err) + } + + mockTrillianLogClient := mockclient.NewMockTrillianLogClient(ctrl) + mockTrillianLogClient.EXPECT().GetLatestSignedLogRoot(gomock.Any(), &trillian.GetLatestSignedLogRootRequest{ + LogId: int64(treeID), + FirstTreeSize: 0, + }).Return(&trillian.GetLatestSignedLogRootResponse{SignedLogRoot: &trillian.SignedLogRoot{LogRoot: mRoot}}, nil) + + redisClient, mock := redismock.NewClientMock() + ts := time.Now().Truncate(time.Duration(freq) * time.Minute).UnixNano() + mock.Regexp().ExpectSetNX(fmt.Sprintf("%d/%d", treeID, ts), "[0-9a-fA-F]+", 0).SetVal(true) + mock.Regexp().ExpectSet(fmt.Sprintf("%d/latest", treeID), "[0-9a-fA-F]+", 0).SetVal("OK") + + publisher := NewCheckpointPublisher(context.Background(), mockTrillianLogClient, int64(treeID), hostname, signer, redisClient, uint(freq), counter) + + ctx, cancel := context.WithCancel(context.Background()) + publisher.StartPublisher(ctx) + defer cancel() + + // wait for initial publish + time.Sleep(1 * time.Second) + + if err := mock.ExpectationsWereMet(); err != nil { + t.Error(err) + } + + if res := testutil.CollectAndCount(counter); res != 2 { + t.Fatalf("unexpected number of metrics: %d", res) + } + if res := testutil.ToFloat64(counter.WithLabelValues(fmt.Sprint(treeID), fmt.Sprint(Success))); res != 1.0 { + t.Fatalf("unexpected number of metrics: %2f", res) + } + if res := testutil.ToFloat64(counter.WithLabelValues(fmt.Sprint(treeID), fmt.Sprint(SuccessObtainLock))); res != 1.0 { + t.Fatalf("unexpected number of metrics: %2f", res) + } +} + +func TestPublishCheckpointMultiple(t *testing.T) { + treeID := 1234 + hostname := "rekor-test" + freq := 1 + counter := prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "rekor_checkpoint_publish", + Help: "Checkpoint publishing by shard and code", + }, []string{"shard", "code"}) + priv, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + signer, _ := signature.LoadSigner(priv, crypto.SHA256) + + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + root := &types.LogRootV1{TreeSize: 10, RootHash: []byte{1}, TimestampNanos: 123, Revision: 0} + mRoot, err := root.MarshalBinary() + if err != nil { + t.Fatalf("error marshalling log root: %v", err) + } + + mockTrillianLogClient := mockclient.NewMockTrillianLogClient(ctrl) + mockTrillianLogClient.EXPECT().GetLatestSignedLogRoot(gomock.Any(), &trillian.GetLatestSignedLogRootRequest{ + LogId: int64(treeID), + FirstTreeSize: 0, + }).Return(&trillian.GetLatestSignedLogRootResponse{SignedLogRoot: &trillian.SignedLogRoot{LogRoot: mRoot}}, nil).MaxTimes(2) + + redisClient, mock := redismock.NewClientMock() + ts := time.Now().Truncate(time.Duration(freq) * time.Minute).UnixNano() + mock.Regexp().ExpectSetNX(fmt.Sprintf("%d/%d", treeID, ts), "[0-9a-fA-F]+", 0).SetVal(true) + mock.Regexp().ExpectSet(fmt.Sprintf("%d/latest", treeID), "[0-9a-fA-F]+", 0).SetVal("OK") + + publisher := NewCheckpointPublisher(context.Background(), mockTrillianLogClient, int64(treeID), hostname, signer, redisClient, uint(freq), counter) + ctx, cancel := context.WithCancel(context.Background()) + publisher.StartPublisher(ctx) + defer cancel() + + redisClientEx, mockEx := redismock.NewClientMock() + mockEx.Regexp().ExpectSetNX(fmt.Sprintf("%d/%d", treeID, ts), "[0-9a-fA-F]+", 0).SetVal(false) + publisherEx := NewCheckpointPublisher(context.Background(), mockTrillianLogClient, int64(treeID), hostname, signer, redisClientEx, uint(freq), counter) + ctxEx, cancelEx := context.WithCancel(context.Background()) + publisherEx.StartPublisher(ctxEx) + defer cancelEx() + + // wait for initial publish + time.Sleep(1 * time.Second) + + if err := mock.ExpectationsWereMet(); err != nil { + t.Error(err) + } + if err := mockEx.ExpectationsWereMet(); err != nil { + t.Error(err) + } + + // only publishes once + if res := testutil.CollectAndCount(counter); res != 2 { + t.Fatalf("unexpected number of metrics: %d", res) + } + if res := testutil.ToFloat64(counter.WithLabelValues(fmt.Sprint(treeID), fmt.Sprint(Success))); res != 1.0 { + t.Fatalf("unexpected number of metrics: %2f", res) + } + if res := testutil.ToFloat64(counter.WithLabelValues(fmt.Sprint(treeID), fmt.Sprint(SuccessObtainLock))); res != 1.0 { + t.Fatalf("unexpected number of metrics: %2f", res) + } +} + +func TestPublishCheckpointTrillianError(t *testing.T) { + treeID := 1234 + hostname := "rekor-test" + freq := 1 + counter := prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "rekor_checkpoint_publish", + Help: "Checkpoint publishing by shard and code", + }, []string{"shard", "code"}) + priv, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + signer, _ := signature.LoadSigner(priv, crypto.SHA256) + + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + // return error + mockTrillianLogClient := mockclient.NewMockTrillianLogClient(ctrl) + mockTrillianLogClient.EXPECT().GetLatestSignedLogRoot(gomock.Any(), gomock.Any()).Return(nil, errors.New("error: LatestSLR")) + + redisClient, _ := redismock.NewClientMock() + + publisher := NewCheckpointPublisher(context.Background(), mockTrillianLogClient, int64(treeID), hostname, signer, redisClient, uint(freq), counter) + ctx, cancel := context.WithCancel(context.Background()) + publisher.StartPublisher(ctx) + defer cancel() + + // wait for initial publish + time.Sleep(1 * time.Second) + + if res := testutil.CollectAndCount(counter); res != 1 { + t.Fatalf("unexpected number of metrics: %d", res) + } + if res := testutil.ToFloat64(counter.WithLabelValues(fmt.Sprint(treeID), fmt.Sprint(GetCheckpoint))); res != 1.0 { + t.Fatalf("unexpected number of metrics: %2f", res) + } +} + +func TestPublishCheckpointInvalidTrillianResponse(t *testing.T) { + treeID := 1234 + hostname := "rekor-test" + freq := 1 + counter := prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "rekor_checkpoint_publish", + Help: "Checkpoint publishing by shard and code", + }, []string{"shard", "code"}) + priv, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + signer, _ := signature.LoadSigner(priv, crypto.SHA256) + + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + // set no log root in response + mockTrillianLogClient := mockclient.NewMockTrillianLogClient(ctrl) + mockTrillianLogClient.EXPECT().GetLatestSignedLogRoot(gomock.Any(), gomock.Any()). + Return(&trillian.GetLatestSignedLogRootResponse{SignedLogRoot: &trillian.SignedLogRoot{LogRoot: []byte{}}}, nil) + + redisClient, _ := redismock.NewClientMock() + + publisher := NewCheckpointPublisher(context.Background(), mockTrillianLogClient, int64(treeID), hostname, signer, redisClient, uint(freq), counter) + ctx, cancel := context.WithCancel(context.Background()) + publisher.StartPublisher(ctx) + defer cancel() + + // wait for initial publish + time.Sleep(1 * time.Second) + + if res := testutil.CollectAndCount(counter); res != 1 { + t.Fatalf("unexpected number of metrics: %d", res) + } + if res := testutil.ToFloat64(counter.WithLabelValues(fmt.Sprint(treeID), fmt.Sprint(UnmarshalCheckpoint))); res != 1.0 { + t.Fatalf("unexpected number of metrics: %2f", res) + } +} + +func TestPublishCheckpointRedisFailure(t *testing.T) { + treeID := 1234 + hostname := "rekor-test" + freq := 1 + counter := prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "rekor_checkpoint_publish", + Help: "Checkpoint publishing by shard and code", + }, []string{"shard", "code"}) + priv, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + signer, _ := signature.LoadSigner(priv, crypto.SHA256) + + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + root := &types.LogRootV1{TreeSize: 10, RootHash: []byte{1}, TimestampNanos: 123, Revision: 0} + mRoot, err := root.MarshalBinary() + if err != nil { + t.Fatalf("error marshalling log root: %v", err) + } + + mockTrillianLogClient := mockclient.NewMockTrillianLogClient(ctrl) + mockTrillianLogClient.EXPECT().GetLatestSignedLogRoot(gomock.Any(), gomock.Any()). + Return(&trillian.GetLatestSignedLogRootResponse{SignedLogRoot: &trillian.SignedLogRoot{LogRoot: mRoot}}, nil) + + redisClient, mock := redismock.NewClientMock() + // error on first redis call + mock.Regexp().ExpectSetNX(".+", "[0-9a-fA-F]+", 0).SetErr(errors.New("redis error")) + + publisher := NewCheckpointPublisher(context.Background(), mockTrillianLogClient, int64(treeID), hostname, signer, redisClient, uint(freq), counter) + ctx, cancel := context.WithCancel(context.Background()) + publisher.StartPublisher(ctx) + defer cancel() + + // wait for initial publish + time.Sleep(1 * time.Second) + + if res := testutil.CollectAndCount(counter); res != 1 { + t.Fatalf("unexpected number of metrics: %d", res) + } + if res := testutil.ToFloat64(counter.WithLabelValues(fmt.Sprint(treeID), fmt.Sprint(RedisFailure))); res != 1.0 { + t.Fatalf("unexpected number of metrics: %2f", res) + } +} + +func TestPublishCheckpointRedisLatestFailure(t *testing.T) { + treeID := 1234 + hostname := "rekor-test" + freq := 1 + counter := prometheus.NewCounterVec(prometheus.CounterOpts{ + Name: "rekor_checkpoint_publish", + Help: "Checkpoint publishing by shard and code", + }, []string{"shard", "code"}) + priv, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + signer, _ := signature.LoadSigner(priv, crypto.SHA256) + + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + root := &types.LogRootV1{TreeSize: 10, RootHash: []byte{1}, TimestampNanos: 123, Revision: 0} + mRoot, err := root.MarshalBinary() + if err != nil { + t.Fatalf("error marshalling log root: %v", err) + } + + mockTrillianLogClient := mockclient.NewMockTrillianLogClient(ctrl) + mockTrillianLogClient.EXPECT().GetLatestSignedLogRoot(gomock.Any(), gomock.Any()). + Return(&trillian.GetLatestSignedLogRootResponse{SignedLogRoot: &trillian.SignedLogRoot{LogRoot: mRoot}}, nil) + + redisClient, mock := redismock.NewClientMock() + mock.Regexp().ExpectSetNX(".+", "[0-9a-fA-F]+", 0).SetVal(true) + // error on second redis call + mock.Regexp().ExpectSet(".*", "[0-9a-fA-F]+", 0).SetErr(errors.New("error")) + + publisher := NewCheckpointPublisher(context.Background(), mockTrillianLogClient, int64(treeID), hostname, signer, redisClient, uint(freq), counter) + ctx, cancel := context.WithCancel(context.Background()) + publisher.StartPublisher(ctx) + defer cancel() + + // wait for initial publish + time.Sleep(1 * time.Second) + + // two metrics, one success for initial redis and one failure for latest + if res := testutil.CollectAndCount(counter); res != 2 { + t.Fatalf("unexpected number of metrics: %d", res) + } + if res := testutil.ToFloat64(counter.WithLabelValues(fmt.Sprint(treeID), fmt.Sprint(RedisLatestFailure))); res != 1.0 { + t.Fatalf("unexpected number of metrics: %2f", res) + } +} + +func TestMain(m *testing.M) { + goleak.VerifyTestMain(m) +} diff --git a/release/README.md b/release/README.md index 76ff1fc57..bfd4ae6c6 100644 --- a/release/README.md +++ b/release/README.md @@ -1,11 +1,12 @@ # Release -This directory contain the files and scripts to run a cosign release. +This directory contain the files and scripts to run a Rekor release. # Cutting a Rekor Release 1. Release notes: Create a PR to update and review release notes in CHANGELOG.md. - - Check merged pull requests since the last release and make sure enhancements, bug fixes, and authors are reflected in the notes. + +Check merged pull requests since the last release and make sure enhancements, bug fixes, and authors are reflected in the notes. You can get a list of pull requests since the last release by substituting in the date of the last release and running: @@ -19,46 +20,41 @@ and a list of authors by running: git log --pretty="* %an" --after="YYYY-MM-DD" | sort -u ``` -2. Tag the repository +2. Open a Pull Request to update CHANGELOG.md + +3. Tag the repository + +**WARNING**: Tags should not be updated to a new ref or deleted/recreated after creation. Go provides a [checksum database](https://sum.golang.org/) +that persists an immutable mapping between version and ref, and updating the tag will break clients that have already downloaded the release. ```shell -$ export RELEASE_TAG= +$ export RELEASE_TAG= $ git tag -s ${RELEASE_TAG} -m "${RELEASE_TAG}" -$ git push origin ${RELEASE_TAG} +$ git push upstream ${RELEASE_TAG} ``` -3. Submit the cloudbuild Job using the following command: +Note that `upstream` should be the upstream `sigstore/rekor` repository. You may have to change this if you've configured remotes. -```shell -$ gcloud builds submit --config \ - --substitutions _GIT_TAG=<_GIT_TAG>,_TOOL_ORG=sigstore,_TOOL_REPO=rekor,_STORAGE_LOCATION=rekor-releases,_KEY_RING=,_KEY_NAME=,_GITHUB_USER= \ - --project -``` +4. Then go to the `Actions` tab and click on the [Cut Release workflow](https://github.com/sigstore/rekor/actions/workflows/cut-release.yml). Note you need +to be in [this list](https://github.com/sigstore/sigstore/blob/main/.github/workflows/reusable-release.yml#L45) to trigger this workflow. + +Click to run a workflow and insert the following parameters ("Cosign" is correct, this refers to the artifact signing key): -Where: + - `Release tag`: the tag that use pushed for the release + - `Key ring for cosign key`: the value is `release-cosign` + - `Key name for cosign key`: the value is `cosign` -- `PATH_TO_CLOUDBUILD` is the path where the cloudbuild.yaml can be found. -- `GCP_PROJECT` is the GCP project where we will run the job. -- `_GIT_TAG` is the release version we are publishing, this will also create the GitHub Tag. -- `_TOOL_ORG` is the GitHub Org we will use. Default `sigstore`. -- `_TOOL_REPO` is the repository we will use to clone. Default `cosign`. -- `_STORAGE_LOCATION` where to push the built artifacts. Default `cosign-releases`. -- `_KEY_RING` key ring name of your cosign key. -- `_KEY_NAME` key name of your cosign key. -- `_KEY_VERSION` version of the key storaged in KMS. Default `1`. -- `_KEY_LOCATION` location in GCP where the key is storaged. Default `global`. -- `_GITHUB_USER` GitHub user to authenticate for pushing to GHCR. +That will trigger a CloudBuild job and will run the release using `goreleaser`, which will publish images to +`gcr.io` and `ghcr.io`, and the binaries will be available in the GitHub release. -4. When the job finish, whithout issues, you should be able to see in GitHub a draft release. -You now can review the release, make any changes if needed and then publish to make it an official release. +If you have permissions to access the project, you can follow the CloudBuild job in the `projectsigstore`(https://console.cloud.google.com/cloud-build/builds?project=projectsigstore) GCP Project. -5. Send an annoucement email to `sigstore-dev@googlegroups.com` mailling list +As the last step of the CloudBuild job, `goreleaser` will create a `draft release` in GitHub. -6. Tweet about the new release with a fun new trigonometry pun! +5. Navigate to the `Draft Release` in the Github repository. Click the `Publish Release` button to make the Release available. -7. Honk! +You might want/need to add any extra notes/breaking changes notices, upgrade paths. -#### After the release: +6. Post on the `#general` and `#rekor` Slack channels. -* Add a pending new section in CHANGELOG.md to set up for the next release -* Create a new GitHub Milestone +7. If it's a significant release, send an announcement email to sigstore-dev@googlegroups.com mailing list. diff --git a/release/cloudbuild.yaml b/release/cloudbuild.yaml index 89821e215..20b54b28a 100644 --- a/release/cloudbuild.yaml +++ b/release/cloudbuild.yaml @@ -32,16 +32,19 @@ steps: echo "Checking out ${_GIT_TAG}" git checkout ${_GIT_TAG} -- name: 'gcr.io/projectsigstore/cosign:v1.13.1@sha256:fd5b09be23ef1027e1bdd490ce78dcc65d2b15902e1f4ba8e04f3b4019cc1057' +- name: 'gcr.io/projectsigstore/cosign:v2.2.0@sha256:280b47054876d415f66a279e666e35157cae6881f3538599710290c70bb75369' dir: "go/src/sigstore/rekor" env: - - COSIGN_EXPERIMENTAL=true - TUF_ROOT=/tmp args: - 'verify' - - 'ghcr.io/gythialy/golang-cross:v1.19.4-0@sha256:53ee894818ac14377996a6fe7c8fe6156d018a20f82aaf69f2519fc45d897bec' + - 'ghcr.io/gythialy/golang-cross:v1.21.1-0@sha256:7864d898e45db9d749f14180051edb46ff61bf42914e3b8ecddec5a36813aa6c' + - '--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.1-0" -- name: ghcr.io/gythialy/golang-cross:v1.19.4-0@sha256:53ee894818ac14377996a6fe7c8fe6156d018a20f82aaf69f2519fc45d897bec +- name: ghcr.io/gythialy/golang-cross:v1.21.1-0@sha256:7864d898e45db9d749f14180051edb46ff61bf42914e3b8ecddec5a36813aa6c entrypoint: /bin/sh dir: "go/src/sigstore/rekor" env: @@ -54,7 +57,7 @@ steps: - KEY_VERSION=${_KEY_VERSION} - GIT_TAG=${_GIT_TAG} - GOOGLE_SERVICE_ACCOUNT_NAME=keyless@${PROJECT_ID}.iam.gserviceaccount.com - - COSIGN_EXPERIMENTAL=true + - COSIGN_YES=true - KO_PREFIX=gcr.io/${PROJECT_ID} secretEnv: - GITHUB_TOKEN @@ -64,7 +67,7 @@ steps: gcloud auth configure-docker \ && make release -- name: ghcr.io/gythialy/golang-cross:v1.19.4-0@sha256:53ee894818ac14377996a6fe7c8fe6156d018a20f82aaf69f2519fc45d897bec +- name: ghcr.io/gythialy/golang-cross:v1.21.1-0@sha256:7864d898e45db9d749f14180051edb46ff61bf42914e3b8ecddec5a36813aa6c entrypoint: 'bash' dir: "go/src/sigstore/rekor" env: diff --git a/release/ko-sign-release-images.sh b/release/ko-sign-release-images.sh index 1688d0e77..8716a31d4 100755 --- a/release/ko-sign-release-images.sh +++ b/release/ko-sign-release-images.sh @@ -52,15 +52,15 @@ if [[ ! -f trillianSignerImagerefs ]]; then fi echo "Signing images with GCP KMS Key..." -cosign sign --force --key "gcpkms://projects/$PROJECT_ID/locations/$KEY_LOCATION/keyRings/$KEY_RING/cryptoKeys/$KEY_NAME/versions/$KEY_VERSION" -a GIT_HASH="$GIT_HASH" -a GIT_VERSION="$GIT_VERSION" $(cat rekorServerImagerefs) -cosign sign --force --key "gcpkms://projects/$PROJECT_ID/locations/$KEY_LOCATION/keyRings/$KEY_RING/cryptoKeys/$KEY_NAME/versions/$KEY_VERSION" -a GIT_HASH="$GIT_HASH" -a GIT_VERSION="$GIT_VERSION" $(cat rekorCliImagerefs) -cosign sign --force --key "gcpkms://projects/$PROJECT_ID/locations/$KEY_LOCATION/keyRings/$KEY_RING/cryptoKeys/$KEY_NAME/versions/$KEY_VERSION" -a GIT_HASH="$GIT_HASH" -a GIT_VERSION="$GIT_VERSION" $(cat bRedisImagerefs) -cosign sign --force --key "gcpkms://projects/$PROJECT_ID/locations/$KEY_LOCATION/keyRings/$KEY_RING/cryptoKeys/$KEY_NAME/versions/$KEY_VERSION" -a GIT_HASH="$GIT_HASH" -a GIT_VERSION="$GIT_VERSION" $(cat trillianServerImagerefs) -cosign sign --force --key "gcpkms://projects/$PROJECT_ID/locations/$KEY_LOCATION/keyRings/$KEY_RING/cryptoKeys/$KEY_NAME/versions/$KEY_VERSION" -a GIT_HASH="$GIT_HASH" -a GIT_VERSION="$GIT_VERSION" $(cat trillianSignerImagerefs) +cosign sign --yes --key "gcpkms://projects/$PROJECT_ID/locations/$KEY_LOCATION/keyRings/$KEY_RING/cryptoKeys/$KEY_NAME/versions/$KEY_VERSION" -a GIT_HASH="$GIT_HASH" -a GIT_VERSION="$GIT_VERSION" $(cat rekorServerImagerefs) +cosign sign --yes --key "gcpkms://projects/$PROJECT_ID/locations/$KEY_LOCATION/keyRings/$KEY_RING/cryptoKeys/$KEY_NAME/versions/$KEY_VERSION" -a GIT_HASH="$GIT_HASH" -a GIT_VERSION="$GIT_VERSION" $(cat rekorCliImagerefs) +cosign sign --yes --key "gcpkms://projects/$PROJECT_ID/locations/$KEY_LOCATION/keyRings/$KEY_RING/cryptoKeys/$KEY_NAME/versions/$KEY_VERSION" -a GIT_HASH="$GIT_HASH" -a GIT_VERSION="$GIT_VERSION" $(cat bRedisImagerefs) +cosign sign --yes --key "gcpkms://projects/$PROJECT_ID/locations/$KEY_LOCATION/keyRings/$KEY_RING/cryptoKeys/$KEY_NAME/versions/$KEY_VERSION" -a GIT_HASH="$GIT_HASH" -a GIT_VERSION="$GIT_VERSION" $(cat trillianServerImagerefs) +cosign sign --yes --key "gcpkms://projects/$PROJECT_ID/locations/$KEY_LOCATION/keyRings/$KEY_RING/cryptoKeys/$KEY_NAME/versions/$KEY_VERSION" -a GIT_HASH="$GIT_HASH" -a GIT_VERSION="$GIT_VERSION" $(cat trillianSignerImagerefs) echo "Signing images with Keyless..." -cosign sign --force -a GIT_HASH="$GIT_HASH" -a GIT_VERSION="$GIT_VERSION" $(cat rekorServerImagerefs) -cosign sign --force -a GIT_HASH="$GIT_HASH" -a GIT_VERSION="$GIT_VERSION" $(cat rekorCliImagerefs) -cosign sign --force -a GIT_HASH="$GIT_HASH" -a GIT_VERSION="$GIT_VERSION" $(cat bRedisImagerefs) -cosign sign --force -a GIT_HASH="$GIT_HASH" -a GIT_VERSION="$GIT_VERSION" $(cat trillianServerImagerefs) -cosign sign --force -a GIT_HASH="$GIT_HASH" -a GIT_VERSION="$GIT_VERSION" $(cat trillianSignerImagerefs) +cosign sign --yes -a GIT_HASH="$GIT_HASH" -a GIT_VERSION="$GIT_VERSION" $(cat rekorServerImagerefs) +cosign sign --yes -a GIT_HASH="$GIT_HASH" -a GIT_VERSION="$GIT_VERSION" $(cat rekorCliImagerefs) +cosign sign --yes -a GIT_HASH="$GIT_HASH" -a GIT_VERSION="$GIT_VERSION" $(cat bRedisImagerefs) +cosign sign --yes -a GIT_HASH="$GIT_HASH" -a GIT_VERSION="$GIT_VERSION" $(cat trillianServerImagerefs) +cosign sign --yes -a GIT_HASH="$GIT_HASH" -a GIT_VERSION="$GIT_VERSION" $(cat trillianSignerImagerefs) diff --git a/release/release.mk b/release/release.mk index 19a1c6d63..575a7432e 100644 --- a/release/release.mk +++ b/release/release.mk @@ -5,12 +5,12 @@ # used when releasing together with GCP CloudBuild .PHONY: release release: - CLI_LDFLAGS="$(CLI_LDFLAGS)" SERVER_LDFLAGS="$(SERVER_LDFLAGS)" goreleaser release --rm-dist --timeout 120m + CLI_LDFLAGS="$(CLI_LDFLAGS)" SERVER_LDFLAGS="$(SERVER_LDFLAGS)" goreleaser release --clean --timeout 120m # used when need to validate the goreleaser .PHONY: snapshot snapshot: - CLI_LDFLAGS="$(CLI_LDFLAGS)" SERVER_LDFLAGS="$(SERVER_LDFLAGS)" goreleaser release --skip-sign --skip-publish --snapshot --rm-dist --timeout 120m + CLI_LDFLAGS="$(CLI_LDFLAGS)" SERVER_LDFLAGS="$(SERVER_LDFLAGS)" goreleaser release --skip-sign --skip-publish --snapshot --clean --timeout 120m ########################### # sign section diff --git a/scripts/storage.sql b/scripts/storage.sql index 1e691a8b8..939ed1272 100644 --- a/scripts/storage.sql +++ b/scripts/storage.sql @@ -129,7 +129,7 @@ CREATE TABLE IF NOT EXISTS SequencedLeafData( ); -CREATE INDEX SequencedLeafMerkleIdx +CREATE INDEX IF NOT EXISTS SequencedLeafMerkleIdx ON SequencedLeafData(TreeId, MerkleLeafHash); CREATE TABLE IF NOT EXISTS Unsequenced( diff --git a/tests/e2e-test.sh b/tests/e2e-test.sh index a9167909f..f57550621 100755 --- a/tests/e2e-test.sh +++ b/tests/e2e-test.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # # Copyright 2021 The Sigstore Authors. # @@ -22,8 +22,11 @@ rm -f /tmp/rekor-*.cov echo "installing gocovmerge" make gocovmerge +echo "building test-only containers" +docker build -t gcp-pubsub-emulator -f Dockerfile.pubsub-emulator . + echo "starting services" -docker-compose -f docker-compose.yml -f docker-compose.test.yml up -d --build +docker compose -f docker-compose.yml -f docker-compose.test.yml up -d --build echo "building CLI and server" go test -c ./cmd/rekor-cli -o rekor-cli -cover -covermode=count -coverpkg=./... @@ -31,15 +34,17 @@ go test -c ./cmd/rekor-server -o rekor-server -covermode=count -coverpkg=./... count=0 -echo -n "waiting up to 60 sec for system to start" -until [ $(docker-compose ps | grep -c "(healthy)") == 3 ]; +echo "waiting up to 2 min for system to start" +until [ $(docker compose ps | \ + grep -E "(rekor-mysql|rekor-redis|rekor-server|gcp-pubsub-emulator)" | \ + grep -c "(healthy)" ) == 4 ]; do - if [ $count -eq 6 ]; then + if [ $count -eq 24 ]; then echo "! timeout reached" exit 1 else echo -n "." - sleep 10 + sleep 5 let 'count+=1' fi done @@ -49,25 +54,34 @@ echo "running tests" REKORTMPDIR="$(mktemp -d -t rekor_test.XXXXXX)" touch $REKORTMPDIR.rekor.yaml trap "rm -rf $REKORTMPDIR" EXIT -if ! REKORTMPDIR=$REKORTMPDIR go test -tags=e2e ./tests/; then - docker-compose logs --no-color > /tmp/docker-compose.log +if ! REKORTMPDIR=$REKORTMPDIR go test -tags=e2e ./tests/ -run TestIssue1308; then + docker compose logs --no-color > /tmp/docker compose.log + exit 1 +fi +if ! REKORTMPDIR=$REKORTMPDIR PUBSUB_EMULATOR_HOST=localhost:8085 go test -tags=e2e ./tests/; then + docker compose logs --no-color > /tmp/docker compose.log exit 1 fi -if docker-compose logs --no-color | grep -q "panic: runtime error:" ; then +if docker compose logs --no-color | grep -q "panic: runtime error:" ; then # if we're here, we found a panic echo "Failing due to panics detected in logs" - docker-compose logs --no-color > /tmp/docker-compose.log + docker compose logs --no-color > /tmp/docker compose.log exit 1 fi echo "generating code coverage" -curl -X GET 0.0.0.0:2345/kill -sleep 5 +docker compose restart rekor-server + +# docker compose appears to name the containers slightly differently in GHA CI vs locally on macOS +container_name="rekor_rekor-server" +if [[ "$(uname -s)" -eq "Darwin" ]]; then + container_name="rekor-rekor-server" +fi -if ! docker cp $(docker ps -aqf "name=rekor_rekor-server"):go/rekor-server.cov /tmp/rekor-server.cov ; then +if ! docker cp $(docker ps -aqf "name=${container_name}"):/go/rekor-server.cov /tmp/rekor-server.cov ; then # failed to copy code coverage report from server echo "Failed to retrieve server code coverage report" - docker-compose logs --no-color > /tmp/docker-compose.log + docker compose logs --no-color > /tmp/docker compose.log exit 1 fi diff --git a/tests/e2e_test.go b/tests/e2e_test.go index 6ec8f7868..425c1b329 100644 --- a/tests/e2e_test.go +++ b/tests/e2e_test.go @@ -21,14 +21,15 @@ import ( "bytes" "context" "crypto" + "crypto/ecdsa" "crypto/sha256" "encoding/hex" "encoding/json" + "errors" "fmt" "io/ioutil" "net/http" "os" - "os/exec" "path/filepath" "strconv" "strings" @@ -37,20 +38,22 @@ import ( "golang.org/x/sync/errgroup" + "cloud.google.com/go/pubsub" "github.com/cyberphone/json-canonicalization/go/src/webpki.org/jsoncanonicalizer" "github.com/go-openapi/strfmt" "github.com/go-openapi/swag" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/sigstore/rekor/pkg/client" + generatedClient "github.com/sigstore/rekor/pkg/generated/client" "github.com/sigstore/rekor/pkg/generated/client/entries" + "github.com/sigstore/rekor/pkg/generated/client/pubkey" "github.com/sigstore/rekor/pkg/generated/models" sigx509 "github.com/sigstore/rekor/pkg/pki/x509" "github.com/sigstore/rekor/pkg/sharding" "github.com/sigstore/rekor/pkg/signer" _ "github.com/sigstore/rekor/pkg/types/intoto/v0.0.1" rekord "github.com/sigstore/rekor/pkg/types/rekord/v0.0.1" - "github.com/sigstore/rekor/pkg/util" "github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/sigstore/sigstore/pkg/signature" "github.com/sigstore/sigstore/pkg/signature/options" @@ -181,30 +184,22 @@ func TestGetCLI(t *testing.T) { runCli(t, "get", "--format=json", "--uuid", entryID.ReturnEntryIDString()) } -func TestWatch(t *testing.T) { - td := t.TempDir() - cmd := exec.Command(server, "watch", "--interval=1s") - cmd.Env = append(os.Environ(), "REKOR_STH_BUCKET=file://"+td) - go func() { - b, err := cmd.CombinedOutput() - t.Log(string(b)) - if cmd.ProcessState.Exited() && cmd.ProcessState.ExitCode() != 0 { - if err != nil { - t.Fatal(err) - } - } - }() - - // Wait 3 intervals - time.Sleep(3 * time.Second) - cmd.Process.Kill() +func publicKeyFromRekorClient(ctx context.Context, c *generatedClient.Rekor) (*ecdsa.PublicKey, error) { + resp, err := c.Pubkey.GetPublicKey(&pubkey.GetPublicKeyParams{Context: ctx}) + if err != nil { + return nil, err + } - // Check for files - fi, err := ioutil.ReadDir(td) - if err != nil || len(fi) == 0 { - t.Error("expected files") + // marshal the pubkey + pubKey, err := cryptoutils.UnmarshalPEMToPublicKey([]byte(resp.GetPayload())) + if err != nil { + return nil, err + } + ed, ok := pubKey.(*ecdsa.PublicKey) + if !ok { + return nil, errors.New("public key retrieved from Rekor is not an ECDSA key") } - fmt.Println(fi[0].Name()) + return ed, nil } func TestSignedEntryTimestamp(t *testing.T) { @@ -273,7 +268,7 @@ func TestSignedEntryTimestamp(t *testing.T) { t.Fatal(err) } // get rekor's public key - rekorPubKey, err := util.PublicKey(ctx, rekorClient) + rekorPubKey, err := publicKeyFromRekorClient(ctx, rekorClient) if err != nil { t.Fatal(err) } @@ -291,13 +286,18 @@ func TestEntryUpload(t *testing.T) { artifactPath := filepath.Join(t.TempDir(), "artifact") sigPath := filepath.Join(t.TempDir(), "signature.asc") + // Create the entry file createdPGPSignedArtifact(t, artifactPath, sigPath) - payload, _ := ioutil.ReadFile(artifactPath) - sig, _ := ioutil.ReadFile(sigPath) + payload, err := ioutil.ReadFile(artifactPath) + if err != nil { + t.Fatal(err) + } + sig, err := ioutil.ReadFile(sigPath) + if err != nil { + t.Fatal(err) + } - // Create the entry file entryPath := filepath.Join(t.TempDir(), "entry.json") - pubKeyBytes := []byte(publicKey) re := rekord.V001Entry{ @@ -321,16 +321,66 @@ func TestEntryUpload(t *testing.T) { } entryBytes, err := json.Marshal(returnVal) if err != nil { - t.Error(err) + t.Fatal(err) } - if err := ioutil.WriteFile(entryPath, entryBytes, 0644); err != nil { - t.Error(err) + t.Fatal(err) + } + + // Start pubsub client to capture notifications. Values match those in + // docker-compose.test.yml. + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + psc, err := pubsub.NewClient(ctx, "test-project") + if err != nil { + t.Fatalf("Create pubsub client: %v", err) + } + topic, err := psc.CreateTopic(ctx, "new-entry") + if err != nil { + // Assume error is AlreadyExists if one occurrs unless it is context timeout. + // If the error was not AlreadyExists, it will be caught in later error + // checks in this test. + if errors.Is(err, os.ErrDeadlineExceeded) { + t.Fatalf("Create pubsub topic: %v", err) + } + topic = psc.Topic("new-entry") + } + filters := []string{ + `attributes:rekor_entry_kind`, // Ignore any messages that do not have this attribute + `attributes.rekor_signing_subjects = "test@rekor.dev"`, // This is the email in the hard-coded PGP test key + `attributes.datacontenttype = "application/json"`, // Only fetch the JSON formatted events + } + cfg := pubsub.SubscriptionConfig{ + Topic: topic, + Filter: strings.Join(filters, " AND "), } + sub, err := psc.CreateSubscription(ctx, "new-entry-sub", cfg) + if err != nil { + if errors.Is(err, os.ErrDeadlineExceeded) { + t.Fatalf("Create pubsub subscription: %v", err) + } + sub = psc.Subscription("new-entry-sub") + } + ch := make(chan []byte, 1) + go func() { + if err := sub.Receive(ctx, func(_ context.Context, m *pubsub.Message) { + ch <- m.Data + }); err != nil { + t.Errorf("Receive pubusub msg: %v", err) + } + }() // Now upload to rekor! out := runCli(t, "upload", "--entry", entryPath) outputContains(t, out, "Created entry at") + + // Await pubsub + select { + case msg := <-ch: + t.Logf("Got pubsub message!\n%s", string(msg)) + case <-ctx.Done(): + t.Errorf("Did not receive pubsub message: %v", ctx.Err()) + } } // Regression test for https://github.com/sigstore/rekor/pull/956 @@ -396,8 +446,18 @@ func TestInclusionProofRace(t *testing.T) { } } +// TestIssue1308 should be run once before any other tests (against an empty log) +func TestIssue1308(t *testing.T) { + // we run this to validate issue 1308 which needs to be tested against an empty log + if getTotalTreeSize(t) == 0 { + TestSearchQueryNonExistentEntry(t) + } else { + t.Skip("skipping because log is not empty") + } +} + func TestSearchQueryNonExistentEntry(t *testing.T) { - // Nonexistent but well-formed entry results in 404 not found. + // Nonexistent but well-formed entry results in 200 with empty array as body wd, err := os.Getwd() if err != nil { t.Fatal(err) @@ -407,7 +467,6 @@ func TestSearchQueryNonExistentEntry(t *testing.T) { t.Fatal(err) } body := fmt.Sprintf("{\"entries\":[%s]}", b) - t.Log(string(body)) resp, err := http.Post(fmt.Sprintf("%s/api/v1/log/entries/retrieve", rekorServer()), "application/json", bytes.NewBuffer([]byte(body))) @@ -416,7 +475,7 @@ func TestSearchQueryNonExistentEntry(t *testing.T) { } c, _ := ioutil.ReadAll(resp.Body) if resp.StatusCode != 200 { - t.Fatalf("expected status 200, got %d instead", resp.StatusCode) + t.Fatalf("expected status 200, got %d instead: %v", resp.StatusCode, string(c)) } if strings.TrimSpace(string(c)) != "[]" { t.Fatalf("expected empty JSON array as response, got %s instead", string(c)) @@ -434,6 +493,17 @@ func getTreeID(t *testing.T) int64 { return tid } +func getTotalTreeSize(t *testing.T) int64 { + out := runCli(t, "loginfo") + sizeStr := strings.Fields(strings.Split(out, "Total Tree Size: ")[1])[0] + size, err := strconv.ParseInt(sizeStr, 10, 64) + if err != nil { + t.Errorf(err.Error()) + } + t.Log("Total Tree Size:", size) + return size +} + // This test confirms that we validate tree ID when using the /api/v1/log/entries/retrieve endpoint // https://github.com/sigstore/rekor/issues/1014 func TestSearchValidateTreeID(t *testing.T) { diff --git a/tests/fuzz-testdata/FuzzHelmProvenanceUnmarshal.options b/tests/fuzz-testdata/FuzzHelmProvenanceUnmarshal.options new file mode 100644 index 000000000..6ccf0d403 --- /dev/null +++ b/tests/fuzz-testdata/FuzzHelmProvenanceUnmarshal.options @@ -0,0 +1,3 @@ +[libfuzzer] +max_len = 1500000 +len_control = 0 diff --git a/tests/fuzz-testdata/FuzzPackageUnmarshal.options b/tests/fuzz-testdata/FuzzPackageUnmarshal.options new file mode 100644 index 000000000..c7fb5a73c --- /dev/null +++ b/tests/fuzz-testdata/FuzzPackageUnmarshal.options @@ -0,0 +1,3 @@ +[libfuzzer] +max_len = 300000 +len_control = 0 diff --git a/tests/fuzz-testdata/seeds/alpine/FuzzPackageUnmarshal/FuzzPackageUnmarshal_seed1 b/tests/fuzz-testdata/seeds/alpine/FuzzPackageUnmarshal/FuzzPackageUnmarshal_seed1 new file mode 100644 index 000000000..d4111d43e Binary files /dev/null and b/tests/fuzz-testdata/seeds/alpine/FuzzPackageUnmarshal/FuzzPackageUnmarshal_seed1 differ diff --git a/tests/oss_fuzz.sh b/tests/oss_fuzz.sh old mode 100644 new mode 100755 index 0a6a7a56d..2ffae34e4 --- a/tests/oss_fuzz.sh +++ b/tests/oss_fuzz.sh @@ -14,15 +14,17 @@ # See the License for the specific language governing permissions and # limitations under the License. -cd $SRC -git clone --depth=1 https://github.com/AdamKorcz/instrumentation -cd instrumentation -go run main.go $SRC/rekor +# remove e2e build comments. +# This is a temporary fix. +# TODO AdamKorcz: Get rid of these sed commands +sed -i '16,17d' $SRC/rekor/pkg/pki/x509/e2e.go +sed -i '16d' $SRC/rekor/pkg/util/util.go cd $SRC/rekor go mod tidy go get github.com/AdamKorcz/go-118-fuzz-build/testing +compile_native_go_fuzzer github.com/sigstore/rekor/pkg/pki FuzzKeys FuzzKeys compile_native_go_fuzzer github.com/sigstore/rekor/pkg/sharding FuzzCreateEntryIDFromParts FuzzCreateEntryIDFromParts compile_native_go_fuzzer github.com/sigstore/rekor/pkg/sharding FuzzGetUUIDFromIDString FuzzGetUUIDFromIDString compile_native_go_fuzzer github.com/sigstore/rekor/pkg/sharding FuzzGetTreeIDFromIDString FuzzGetTreeIDFromIDString @@ -33,13 +35,41 @@ compile_native_go_fuzzer github.com/sigstore/rekor/pkg/sharding FuzzValidateUUID compile_native_go_fuzzer github.com/sigstore/rekor/pkg/sharding FuzzValidateTreeID FuzzValidateTreeID compile_native_go_fuzzer github.com/sigstore/rekor/pkg/sharding FuzzValidateEntryID FuzzValidateEntryID compile_native_go_fuzzer github.com/sigstore/rekor/pkg/signer FuzzNewFile FuzzNewFile -compile_native_go_fuzzer github.com/sigstore/rekor/pkg/types/cose FuzzCreateProposedEntry FuzzCreateProposedEntry +compile_native_go_fuzzer github.com/sigstore/rekor/pkg/types/cose/v0.0.1 FuzzCoseCreateProposedEntry FuzzCoseCreateProposedEntry +compile_native_go_fuzzer github.com/sigstore/rekor/pkg/types/cose/v0.0.1 FuzzCoseUnmarshalAndCanonicalize FuzzCoseUnmarshalAndCanonicalize +compile_native_go_fuzzer github.com/sigstore/rekor/pkg/types/hashedrekord FuzzHashedRekord FuzzHashedRekord +compile_native_go_fuzzer github.com/sigstore/rekor/pkg/types/hashedrekord/v0.0.1 FuzzHashedRekordCreateProposedEntry FuzzHashedRekordCreateProposedEntry +compile_native_go_fuzzer github.com/sigstore/rekor/pkg/types/hashedrekord/v0.0.1 FuzzHashedRekordUnmarshalAndCanonicalize FuzzHashedRekordUnmarshalAndCanonicalize compile_native_go_fuzzer github.com/sigstore/rekor/pkg/types/alpine FuzzPackageUnmarshal FuzzPackageUnmarshal +compile_native_go_fuzzer github.com/sigstore/rekor/pkg/types/alpine/v0.0.1 FuzzAlpineCreateProposedEntry FuzzAlpineCreateProposedEntry +compile_native_go_fuzzer github.com/sigstore/rekor/pkg/types/alpine/v0.0.1 FuzzAlpineUnmarshalAndCanonicalize FuzzAlpineUnmarshalAndCanonicalize compile_native_go_fuzzer github.com/sigstore/rekor/pkg/types/jar FuzzJarUnmarshal FuzzJarUnmarshal -compile_native_go_fuzzer github.com/sigstore/rekor/pkg/types/hashedrekord FuzzHashedRekord FuzzHashedRekord -compile_native_go_fuzzer github.com/sigstore/rekor/pkg/types/intoto FuzzIntotoCreateProposedEntry FuzzIntotoCreateProposedEntry -compile_native_go_fuzzer github.com/sigstore/rekor/pkg/types/tuf FuzzTufCreateProposedEntry FuzzTufCreateProposedEntry -compile_native_go_fuzzer github.com/sigstore/rekor/pkg/types/rfc3161 FuzzRfc3161CreateProposedEntry FuzzRfc3161CreateProposedEntry -compile_native_go_fuzzer github.com/sigstore/rekor/pkg/types/rpm FuzzRpmCreateProposedEntry FuzzRpmCreateProposedEntry -compile_native_go_fuzzer github.com/sigstore/rekor/pkg/types/helm FuzzHelmCreateProposedEntry FuzzHelmCreateProposedEntry -compile_native_go_fuzzer github.com/sigstore/rekor/pkg/types/rekord FuzzRekordCreateProposedEntry FuzzRekordCreateProposedEntry +compile_native_go_fuzzer github.com/sigstore/rekor/pkg/types/jar/v0.0.1 FuzzJarCreateProposedEntry FuzzJarCreateProposedEntry +compile_native_go_fuzzer github.com/sigstore/rekor/pkg/types/jar/v0.0.1 FuzzJarUnmarshalAndCanonicalize FuzzJarUnmarshalAndCanonicalize +compile_native_go_fuzzer github.com/sigstore/rekor/pkg/types/intoto/v0.0.1 FuzzIntotoCreateProposedEntry FuzzIntotoCreateProposedEntry_v001 +compile_native_go_fuzzer github.com/sigstore/rekor/pkg/types/intoto/v0.0.1 FuzzIntotoUnmarshalAndCanonicalize FuzzIntotoUnmarshalAndCanonicalize_v001 +compile_native_go_fuzzer github.com/sigstore/rekor/pkg/types/intoto/v0.0.2 FuzzIntotoCreateProposedEntry FuzzIntotoCreateProposedEntry_v002 +compile_native_go_fuzzer github.com/sigstore/rekor/pkg/types/intoto/v0.0.2 FuzzIntotoUnmarshalAndCanonicalize FuzzIntotoUnmarshalAndCanonicalize_v002 +compile_native_go_fuzzer github.com/sigstore/rekor/pkg/types/tuf/v0.0.1 FuzzTufCreateProposedEntry FuzzTufCreateProposedEntry +compile_native_go_fuzzer github.com/sigstore/rekor/pkg/types/tuf/v0.0.1 FuzzTufUnmarshalAndCanonicalize FuzzTufUnmarshalAndCanonicalize +compile_native_go_fuzzer github.com/sigstore/rekor/pkg/types/rfc3161/v0.0.1 FuzzRfc3161CreateProposedEntry FuzzRfc3161CreateProposedEntry +compile_native_go_fuzzer github.com/sigstore/rekor/pkg/types/rfc3161/v0.0.1 FuzzRfc3161UnmarshalAndCanonicalize FuzzRfc3161UnmarshalAndCanonicalize +compile_native_go_fuzzer github.com/sigstore/rekor/pkg/types/rpm/v0.0.1 FuzzRpmCreateProposedEntry FuzzRpmCreateProposedEntry +compile_native_go_fuzzer github.com/sigstore/rekor/pkg/types/rpm/v0.0.1 FuzzRpmUnmarshalAndCanonicalize FuzzRpmUnmarshalAndCanonicalize +compile_native_go_fuzzer github.com/sigstore/rekor/pkg/types/helm/v0.0.1 FuzzHelmCreateProposedEntry FuzzHelmCreateProposedEntry +compile_native_go_fuzzer github.com/sigstore/rekor/pkg/types/helm/v0.0.1 FuzzHelmUnmarshalAndCanonicalize FuzzHelmUnmarshalAndCanonicalize +compile_native_go_fuzzer github.com/sigstore/rekor/pkg/types/helm/v0.0.1 FuzzHelmProvenanceUnmarshal FuzzHelmProvenanceUnmarshal +compile_native_go_fuzzer github.com/sigstore/rekor/pkg/types/rekord/v0.0.1 FuzzRekordCreateProposedEntry FuzzRekordCreateProposedEntry +compile_native_go_fuzzer github.com/sigstore/rekor/pkg/types/rekord/v0.0.1 FuzzRekordUnmarshalAndCanonicalize FuzzRekordUnmarshalAndCanonicalize +compile_native_go_fuzzer github.com/sigstore/rekor/pkg/types/dsse/v0.0.1 FuzzDSSECreateProposedEntry FuzzDSSECreateProposedEntry +compile_native_go_fuzzer github.com/sigstore/rekor/pkg/types/dsse/v0.0.1 FuzzDSSEUnmarshalAndCanonicalize FuzzDSSEUnmarshalAndCanonicalize + +# Test 3rd party API that rekor/pkg/types/jar/v0.0.1 uses +go mod edit -replace github.com/sassoftware/relic=$SRC/relic +go mod tidy +go get github.com/AdamKorcz/go-118-fuzz-build/testing +compile_native_go_fuzzer github.com/sigstore/rekor/pkg/types/jar/v0.0.1 FuzzJarutilsVerify FuzzJarutilsVerify + + +cp $SRC/rekor/tests/fuzz-testdata/*.options $OUT/ +zip $OUT/FuzzPackageUnmarshal_seed_corpus.zip $SRC/rekor/tests/fuzz-testdata/seeds/alpine/FuzzPackageUnmarshal/FuzzPackageUnmarshal_seed1 diff --git a/tests/rekor-harness.sh b/tests/rekor-harness.sh index acdcdd645..87815b63d 100755 --- a/tests/rekor-harness.sh +++ b/tests/rekor-harness.sh @@ -30,7 +30,7 @@ function start_server () { else echo "turning down rekor and restarting at version $server_version" docker stop $(docker ps --filter name=rekor-server --format {{.ID}}) - + # Replace log in docker-compose.yml with the Tree ID we want search="# Uncomment this for production logging" replace="\"--trillian_log_server.tlog_id=$TREE_ID\"," @@ -75,7 +75,7 @@ function run_tests () { trap "rm -rf $REKORTMPDIR" EXIT go clean -testcache - if ! REKORTMPDIR=$REKORTMPDIR SERVER_VERSION=$1 CLI_VERSION=$2 go test -run TestHarness -v -tags=e2e ./tests/ ; then + if ! REKORTMPDIR=$REKORTMPDIR SERVER_VERSION=$1 CLI_VERSION=$2 go test -run TestHarness -v -tags=e2e ./cmd/rekor-server/ ; then docker-compose logs --no-color > /tmp/docker-compose.log exit 1 fi @@ -104,10 +104,10 @@ echo $VERSIONS export REKOR_HARNESS_TMPDIR="$(mktemp -d -t rekor_test_harness.XXXXXX)" docker-compose down -for server_version in $VERSIONS +for server_version in $VERSIONS do start_server $server_version - for cli_version in $VERSIONS + for cli_version in $VERSIONS do echo "=======================================================" echo "Running tests with server version $server_version and CLI version $cli_version"