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"