58 Commits

Author SHA1 Message Date
dependabot[bot]
bd2c4d7d8a feat(deps): bump github.com/sigstore/cosign/v2 from 2.2.4 to 2.3.0 (#98)
* feat(deps): bump github.com/sigstore/cosign/v2 from 2.2.4 to 2.3.0

Bumps [github.com/sigstore/cosign/v2](https://github.com/sigstore/cosign) from 2.2.4 to 2.3.0.
- [Release notes](https://github.com/sigstore/cosign/releases)
- [Changelog](https://github.com/sigstore/cosign/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sigstore/cosign/compare/v2.2.4...v2.3.0)

---
updated-dependencies:
- dependency-name: github.com/sigstore/cosign/v2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* update to go 1.22.5

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: mrjoelkamp <joel.kamp@docker.com>
2024-07-24 13:30:56 +01:00
dependabot[bot]
03ba59c6b9 feat(deps): bump google.golang.org/api from 0.188.0 to 0.189.0 (#97) 2024-07-23 19:08:01 +00:00
dependabot[bot]
ac82c65d7c feat(deps): bump github.com/aws/aws-sdk-go-v2/config (#93) 2024-07-23 19:03:53 +00:00
Joel Kamp
24a81bbfe1 Merge pull request #96 from docker/chore-update-dev-root
chore: update dev root
2024-07-23 08:03:03 -05:00
mrjoelkamp
1e3c120272 fix: test targets file no ext 2024-07-22 16:03:23 -05:00
mrjoelkamp
d252a7f4d7 chore: update oci test data 2024-07-22 15:57:35 -05:00
mrjoelkamp
02421f8cf5 chore: update http test data 2024-07-22 15:52:14 -05:00
mrjoelkamp
a6cd978bc0 chore: update dev root 2024-07-22 15:23:28 -05:00
James Carnegie
efb73f4cae Use DSSE artifactType in referrers (#95)
* bug: Use DSSE media types for artifactType

* Don't serialize DSSE extension if not present

* Update pkg/attestation/types.go

Co-authored-by: Joel Kamp <joel.kamp@docker.com>

* Don't error on no referrers

---------

Co-authored-by: Joel Kamp <joel.kamp@docker.com>
2024-07-22 18:17:12 +01:00
James Carnegie
5e68d94ad4 set artifactType correctly for referrers fallback (#94)
* set artifactType correctly for referrers fallback
2024-07-19 16:39:35 +01:00
dependabot[bot]
10d4f129b5 feat(deps): bump github.com/theupdateframework/go-tuf/v2 from 2.0.0-20240504210453-5a634eb214ae to 2.0.0 (#92)
* feat(deps): bump github.com/theupdateframework/go-tuf/v2

Bumps [github.com/theupdateframework/go-tuf/v2](https://github.com/theupdateframework/go-tuf) from 2.0.0-20240504210453-5a634eb214ae to 2.0.0.
- [Release notes](https://github.com/theupdateframework/go-tuf/releases)
- [Changelog](https://github.com/theupdateframework/go-tuf/blob/master/.goreleaser.yaml)
- [Commits](https://github.com/theupdateframework/go-tuf/commits/v2.0.0)

---
updated-dependencies:
- dependency-name: github.com/theupdateframework/go-tuf/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* Tidy go.mod

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jonny Stoten <jonny.stoten@docker.com>
2024-07-17 17:01:09 +01:00
James Carnegie
de5668aca2 chore: fix linting errors (#91) 2024-07-16 12:52:33 +01:00
dependabot[bot]
79566ff70a feat(deps): bump github.com/sigstore/sigstore/pkg/signature/kms/aws (#88)
Bumps [github.com/sigstore/sigstore/pkg/signature/kms/aws](https://github.com/sigstore/sigstore) from 1.8.6 to 1.8.7.
- [Release notes](https://github.com/sigstore/sigstore/releases)
- [Commits](https://github.com/sigstore/sigstore/compare/v1.8.6...v1.8.7)

---
updated-dependencies:
- dependency-name: github.com/sigstore/sigstore/pkg/signature/kms/aws
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-16 11:46:03 +01:00
dependabot[bot]
d01395144b feat(deps): bump github.com/sigstore/sigstore/pkg/signature/kms/gcp (#89)
Bumps [github.com/sigstore/sigstore/pkg/signature/kms/gcp](https://github.com/sigstore/sigstore) from 1.8.6 to 1.8.7.
- [Release notes](https://github.com/sigstore/sigstore/releases)
- [Commits](https://github.com/sigstore/sigstore/compare/v1.8.6...v1.8.7)

---
updated-dependencies:
- dependency-name: github.com/sigstore/sigstore/pkg/signature/kms/gcp
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-16 11:32:17 +01:00
James Carnegie
065b354d3c Make referrers attestations OCI compliant (#80)
* Single attestation when creating VSA

* Create single layer images for referrers attestations

* Move mock to test package. Add artifacts test

* Add test for envelope detection

* Add tests for image/index saving

* Add mirror tests

* Remove AttestationImage field from AttestationManifest

* Update naming. strictReferers != laxReferrers

* Add specific test for SaveReferrers
2024-07-16 10:05:17 +01:00
Jonny Stoten
a4c3bd07fe Add proper mirror support (#74)
* Add rewrite support and fix existing tests

* Add unit tests for policy matching

* Compile regexes up front and store policies in map

* Add test for verify flow with mirror

* Rename ImageName -> ResolvedName

And only set it when necessary

* Rename Rewrite -> Replacement

but keep it as rewrite in the yaml
2024-07-12 17:09:41 +01:00
dependabot[bot]
247448a765 feat(deps): bump github.com/aws/aws-sdk-go-v2/config (#86)
Bumps [github.com/aws/aws-sdk-go-v2/config](https://github.com/aws/aws-sdk-go-v2) from 1.27.24 to 1.27.26.
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/config/v1.27.24...config/v1.27.26)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go-v2/config
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-12 10:38:33 +01:00
dependabot[bot]
64e7f1ccab feat(deps): bump github.com/testcontainers/testcontainers-go/modules/registry (#79)
Bumps [github.com/testcontainers/testcontainers-go/modules/registry](https://github.com/testcontainers/testcontainers-go) from 0.31.0 to 0.32.0.
- [Release notes](https://github.com/testcontainers/testcontainers-go/releases)
- [Commits](https://github.com/testcontainers/testcontainers-go/compare/v0.31.0...v0.32.0)

---
updated-dependencies:
- dependency-name: github.com/testcontainers/testcontainers-go/modules/registry
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-12 10:35:30 +01:00
dependabot[bot]
f3354d1251 feat(deps): bump github.com/google/go-containerregistry (#81)
Bumps [github.com/google/go-containerregistry](https://github.com/google/go-containerregistry) from 0.19.2 to 0.20.0.
- [Release notes](https://github.com/google/go-containerregistry/releases)
- [Changelog](https://github.com/google/go-containerregistry/blob/main/.goreleaser.yml)
- [Commits](https://github.com/google/go-containerregistry/compare/v0.19.2...v0.20.0)

---
updated-dependencies:
- dependency-name: github.com/google/go-containerregistry
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-12 10:27:37 +01:00
dependabot[bot]
a36c43a173 feat(deps): bump google.golang.org/api from 0.187.0 to 0.188.0 (#83)
Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.187.0 to 0.188.0.
- [Release notes](https://github.com/googleapis/google-api-go-client/releases)
- [Changelog](https://github.com/googleapis/google-api-go-client/blob/main/CHANGES.md)
- [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.187.0...v0.188.0)

---
updated-dependencies:
- dependency-name: google.golang.org/api
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-12 10:27:14 +01:00
Joel Kamp
7e9b48baf9 Merge pull request #87 from docker/chore-update-defaults-export-roots
chore: update default urls and export roots
2024-07-11 13:22:36 -05:00
mrjoelkamp
da310234a4 feat: export embedded root names 2024-07-11 09:55:00 -05:00
mrjoelkamp
d65be7be7c fix: use prod as default for mirroring 2024-07-11 09:41:04 -05:00
Joel Kamp
2e2bc49387 Merge pull request #85 from docker/refactor--use-embedded-root-types
feat: add EmbeddedRoot type
2024-07-11 03:36:06 -05:00
mrjoelkamp
0330ea4755 feat: add EmbeddedRoot type 2024-07-10 17:30:35 -05:00
Joel Kamp
0336a21a7d Merge pull request #84 from docker/feat-add-prod-tuf-root
feat: add production TUF root
2024-07-10 16:39:44 -05:00
mrjoelkamp
1754a98e4e fix: dont use keyword var 2024-07-10 16:35:48 -05:00
Joel Kamp
a05fc10d53 Update pkg/tuf/tuf_test.go
Co-authored-by: David Dooling <141646279+whalelines@users.noreply.github.com>
2024-07-10 16:19:58 -05:00
mrjoelkamp
e830271d01 feat: add test 2024-07-10 14:39:52 -05:00
mrjoelkamp
1cb3e4a281 feat: add production tuf root 2024-07-10 14:29:59 -05:00
James Carnegie
6b199f027a Enable GCP integration test (#82) 2024-07-09 15:02:49 +01:00
dependabot[bot]
aaf043e9cd feat(deps): bump google.golang.org/api from 0.185.0 to 0.187.0 (#76)
Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.185.0 to 0.187.0.
- [Release notes](https://github.com/googleapis/google-api-go-client/releases)
- [Changelog](https://github.com/googleapis/google-api-go-client/blob/main/CHANGES.md)
- [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.185.0...v0.187.0)

---
updated-dependencies:
- dependency-name: google.golang.org/api
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-05 12:36:47 +01:00
Jonny Stoten
ac693a45c7 Don't upload coverage results if we don't run e2e (#77)
this way the coverage doesn't fluctuate between e2e and non-e2e test
runs
2024-07-05 12:28:47 +01:00
James Carnegie
0038e3d23d Unify functions for use in sign & verify --vsa (#71)
* Use receivers for manifest functions
* Move SaveImage/SaveIndex from image-signing-verifier
* Ignore test fixtures in coverage
* Add AddImagesToIndex function
2024-07-05 09:29:14 +01:00
James Carnegie
0dd63bf5a3 Add GCP KMS support (#73)
* Add GCP KMS support
2024-07-04 15:32:10 +01:00
dependabot[bot]
5d56efa2df feat(deps): bump github.com/aws/aws-sdk-go-v2/config (#75)
Bumps [github.com/aws/aws-sdk-go-v2/config](https://github.com/aws/aws-sdk-go-v2) from 1.27.23 to 1.27.24.
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/config/v1.27.23...config/v1.27.24)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go-v2/config
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-04 09:41:32 +01:00
dependabot[bot]
3ffef89dda feat(deps): bump github.com/sigstore/sigstore/pkg/signature/kms/aws from 1.8.5 to 1.8.6 (#67) 2024-07-03 19:56:29 +00:00
dependabot[bot]
3c26a89496 feat(deps): bump github.com/open-policy-agent/opa from 0.65.0 to 0.66.0 (#69) 2024-07-03 19:45:50 +00:00
dependabot[bot]
6ee1d32ddc feat(deps): bump github.com/aws/aws-sdk-go-v2/config (#70) 2024-07-03 19:33:53 +00:00
Joel Kamp
3140e2d903 Merge pull request #72 from docker/dependabot/go_modules/github.com/containerd/containerd-1.7.19
feat(deps): bump github.com/containerd/containerd from 1.7.18 to 1.7.19
2024-07-03 14:28:01 -05:00
dependabot[bot]
dd1141c231 feat(deps): bump github.com/containerd/containerd from 1.7.18 to 1.7.19
Bumps [github.com/containerd/containerd](https://github.com/containerd/containerd) from 1.7.18 to 1.7.19.
- [Release notes](https://github.com/containerd/containerd/releases)
- [Changelog](https://github.com/containerd/containerd/blob/main/RELEASES.md)
- [Commits](https://github.com/containerd/containerd/compare/v1.7.18...v1.7.19)

---
updated-dependencies:
- dependency-name: github.com/containerd/containerd
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-03 08:39:19 +00:00
James Carnegie
bda1910107 Add e2e auth test (#68)
* Add e2e auth test
2024-07-01 14:14:23 +01:00
dependabot[bot]
80658a4b5f feat(deps): bump github.com/sigstore/sigstore/pkg/signature/kms/aws (#65) 2024-06-26 16:43:41 +00:00
Joel Kamp
46db2b9fd5 Merge pull request #59 from docker/feat-cloud-provider-authn
feat: cloud provider authn
2024-06-26 09:28:03 -05:00
mrjoelkamp
e37f788865 refactor: drop ACR support for now 2024-06-25 13:44:29 -05:00
Joel Kamp
13172cb502 Merge branch 'main' into feat-cloud-provider-authn 2024-06-25 12:06:46 -05:00
mrjoelkamp
abb3163628 fix: update aws-sdk-go-v2 2024-06-25 11:49:58 -05:00
James Carnegie
742f98fbeb Generate coverage when tests are run (#64)
* Generate coverage when tests are run
* Use docker's codecov account
2024-06-24 14:26:07 +01:00
Joel Kamp
8cae188735 Merge branch 'main' into feat-cloud-provider-authn 2024-06-21 16:39:45 -05:00
Joel Kamp
7586f4dfc4 Merge pull request #61 from docker/dependabot/go_modules/github.com/aws/aws-sdk-go-v2/config-1.27.21
feat(deps): bump github.com/aws/aws-sdk-go-v2/config from 1.27.19 to 1.27.21
2024-06-21 16:35:01 -05:00
Joel Kamp
acb862ea42 Merge branch 'main' into dependabot/go_modules/github.com/aws/aws-sdk-go-v2/config-1.27.21 2024-06-21 16:32:11 -05:00
dependabot[bot]
92985e9a12 feat(deps): bump github.com/aws/aws-sdk-go-v2/config
Bumps [github.com/aws/aws-sdk-go-v2/config](https://github.com/aws/aws-sdk-go-v2) from 1.27.19 to 1.27.21.
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/config/v1.27.19...config/v1.27.21)

---
updated-dependencies:
- dependency-name: github.com/aws/aws-sdk-go-v2/config
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-20 08:23:40 +00:00
mrjoelkamp
08e823e05b refactor: make common authn function 2024-06-18 12:00:47 -05:00
Joel Kamp
ff38975c76 Merge branch 'main' into feat-cloud-provider-authn 2024-06-18 10:09:04 -05:00
mrjoelkamp
f95760d8b2 chore: fmt go.mod 2024-06-18 10:04:38 -05:00
mrjoelkamp
f611f81fff feat: add support for ecr, gcp, acr authn 2024-06-18 09:59:04 -05:00
mrjoelkamp
8e3c6a2ec5 feat: use os.ModePerm 2024-06-18 09:39:12 -05:00
mrjoelkamp
a3921c206a fix: ineffectual assign 2024-06-18 09:38:50 -05:00
134 changed files with 3154 additions and 1361 deletions

View File

@@ -7,6 +7,9 @@ on:
workflow_dispatch:
jobs:
golang:
permissions:
contents: read
id-token: write
strategy:
matrix:
go-version: [1.21.x]
@@ -21,9 +24,42 @@ jobs:
- uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go-version }}
- name: Login to Docker Hub
if: matrix.os == 'ubuntu-latest' && github.actor != 'dependabot[bot]'
uses: docker/login-action@v3
with:
username: dockerpublicbot
password: ${{ secrets.DOCKERPUBLICBOT_WRITE_PAT }}
- name: Authenticate to AWS
if: matrix.os == 'ubuntu-latest' && github.actor != 'dependabot[bot]'
uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 #v4.0.2
with:
aws-region: "us-east-1"
role-to-assume: arn:aws:iam::175142243308:role/doi-github-actions-signing
- name: auth-with-gcp
if: matrix.os == 'ubuntu-latest' && github.actor != 'dependabot[bot]'
uses: google-github-actions/auth@v2
with:
project_id: 'attest-kms-test'
export_environment_variables: true
workload_identity_provider: 'projects/385966116051/locations/global/workloadIdentityPools/attest-kms-test/providers/attest-kms-test'
service_account: 'attest-kms-test@attest-kms-test.iam.gserviceaccount.com'
- name: Setup Testcontainers Cloud Client
uses: atomicjar/testcontainers-cloud-setup-action@v1
with:
token: ${{ secrets.TC_CLOUD_TOKEN }}
- name: go test
run: go test ./...
- name: go test including e2e
if: matrix.os == 'ubuntu-latest' && github.actor != 'dependabot[bot]'
run: go test -tags=e2e -v ./... -coverprofile=coverage.out -covermode=atomic
- name: go test excluding e2e
if: matrix.os == 'macos-latest' || github.actor == 'dependabot[bot]'
run: go test -v ./...
- name: Upload coverage to Codecov
if: matrix.os == 'ubuntu-latest' && github.actor != 'dependabot[bot]'
uses: codecov/codecov-action@v4
with:
file: ./coverage.out
flags: unittests
name: codecov-umbrella
fail_ci_if_error: true
token: ${{ secrets.CODECOV_TOKEN }}

View File

@@ -1,6 +1,8 @@
# attest
library to create, verify, and evaluate policy for attestations on container images
[![codecov](https://codecov.io/gh/docker/attest/graph/badge.svg?token=cGT0f1ACKg)](https://codecov.io/gh/docker/attest)
# usage
## signing and verifying attestations
See [example_sign_test.go](./pkg/attest/example_sign_test.go)

2
codecov.yml Normal file
View File

@@ -0,0 +1,2 @@
ignore:
- "internal/test"

119
go.mod
View File

@@ -1,34 +1,46 @@
module github.com/docker/attest
go 1.22.1
go 1.22.5
require (
github.com/Masterminds/semver/v3 v3.2.1
github.com/aws/aws-sdk-go-v2/config v1.27.19
github.com/containerd/containerd v1.7.18
github.com/aws/aws-sdk-go-v2/config v1.27.27
github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20231024185945-8841054dbdb8
github.com/containerd/platforms v0.2.1
github.com/distribution/reference v0.6.0
github.com/go-openapi/runtime v0.28.0
github.com/go-openapi/strfmt v0.23.0
github.com/google/go-containerregistry v0.19.2
github.com/google/go-containerregistry v0.20.1
github.com/hashicorp/go-cleanhttp v0.5.2
github.com/in-toto/in-toto-golang v0.9.0
github.com/open-policy-agent/opa v0.65.0
github.com/open-policy-agent/opa v0.66.0
github.com/opencontainers/image-spec v1.1.0
github.com/package-url/packageurl-go v0.1.3
github.com/pkg/errors v0.9.1
github.com/secure-systems-lab/go-securesystemslib v0.8.0
github.com/sigstore/cosign/v2 v2.2.4
github.com/sigstore/cosign/v2 v2.3.0
github.com/sigstore/rekor v1.3.6
github.com/sigstore/sigstore/pkg/signature/kms/aws v1.8.4
github.com/sigstore/sigstore/pkg/signature/kms/aws v1.8.7
github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.8.7
github.com/stretchr/testify v1.9.0
github.com/testcontainers/testcontainers-go v0.31.0
github.com/testcontainers/testcontainers-go/modules/registry v0.31.0
github.com/theupdateframework/go-tuf/v2 v2.0.0-20240504210453-5a634eb214ae // for https://github.com/theupdateframework/go-tuf/pull/632
github.com/testcontainers/testcontainers-go/modules/registry v0.32.0
github.com/theupdateframework/go-tuf/v2 v2.0.0
google.golang.org/api v0.189.0
gopkg.in/yaml.v3 v3.0.1
sigs.k8s.io/yaml v1.4.0
)
// fork of a fork (in case it goes away) with changes to support ArtifactType (https://github.com/google/go-containerregistry/pull/1931)
replace github.com/google/go-containerregistry v0.20.1 => github.com/kipz/go-containerregistry v0.0.0-20240722163910-ebe90246535d
require (
cloud.google.com/go v0.115.0 // indirect
cloud.google.com/go/auth v0.7.2 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.3 // indirect
cloud.google.com/go/compute/metadata v0.5.0 // indirect
cloud.google.com/go/iam v1.1.10 // indirect
cloud.google.com/go/kms v1.18.2 // indirect
cloud.google.com/go/longrunning v0.5.9 // indirect
dario.cat/mergo v1.0.0 // indirect
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
@@ -37,25 +49,27 @@ require (
github.com/ProtonMail/go-crypto v1.0.0 // indirect
github.com/agnivade/levenshtein v1.1.1 // indirect
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
github.com/aws/aws-sdk-go-v2 v1.28.0 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.17.19 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.6 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.10 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.10 // indirect
github.com/aws/aws-sdk-go-v2 v1.30.3 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.17.27 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.12 // indirect
github.com/aws/aws-sdk-go-v2/service/kms v1.32.1 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.20.12 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.24.6 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.28.13 // indirect
github.com/aws/smithy-go v1.20.2 // indirect
github.com/aws/aws-sdk-go-v2/service/ecr v1.29.1 // indirect
github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.24.1 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17 // indirect
github.com/aws/aws-sdk-go-v2/service/kms v1.35.1 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.22.4 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.30.3 // indirect
github.com/aws/smithy-go v1.20.3 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/blang/semver v3.5.1+incompatible // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/cloudflare/circl v1.3.8 // indirect
github.com/containerd/errdefs v0.1.0 // indirect
github.com/containerd/containerd v1.7.19 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/containerd/stargz-snapshotter/estargz v0.15.1 // indirect
github.com/cpuguy83/dockercfg v0.3.1 // indirect
@@ -65,7 +79,7 @@ require (
github.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7 // indirect
github.com/docker/cli v26.1.3+incompatible // indirect
github.com/docker/distribution v2.8.3+incompatible // indirect
github.com/docker/docker v26.1.3+incompatible // indirect
github.com/docker/docker v27.0.3+incompatible // indirect
github.com/docker/docker-credential-helpers v0.8.1 // indirect
github.com/docker/go-connections v0.5.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
@@ -74,7 +88,7 @@ require (
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/go-chi/chi v4.1.2+incompatible // indirect
github.com/go-ini/ini v1.67.0 // indirect
github.com/go-jose/go-jose/v4 v4.0.1 // indirect
github.com/go-jose/go-jose/v4 v4.0.2 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect
@@ -88,18 +102,24 @@ require (
github.com/go-openapi/validate v0.24.0 // indirect
github.com/gobwas/glob v0.2.3 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/certificate-transparency-go v1.1.8 // indirect
github.com/google/certificate-transparency-go v1.2.1 // indirect
github.com/google/s2a-go v0.1.7 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
github.com/googleapis/gax-go/v2 v2.12.5 // indirect
github.com/gorilla/mux v1.8.1 // indirect
github.com/hashicorp/go-retryablehttp v0.7.6 // indirect
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
github.com/hashicorp/hcl v1.0.1-vault-5 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267 // indirect
github.com/jellydator/ttlcache/v3 v3.2.0 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/klauspost/compress v1.17.8 // indirect
github.com/letsencrypt/boulder v0.0.0-20240515153123-6ae6aa8e9055 // indirect
github.com/letsencrypt/boulder v0.0.0-20240620165639-de9c06129bec // indirect
github.com/lufia/plan9stats v0.0.0-20240513124658-fba389f38bae // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
@@ -111,6 +131,7 @@ require (
github.com/moby/sys/user v0.1.0 // indirect
github.com/moby/term v0.5.0 // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481 // indirect
github.com/oklog/ulid v1.3.1 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
@@ -120,8 +141,8 @@ require (
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
github.com/prometheus/client_golang v1.19.1 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.53.0 // indirect
github.com/prometheus/procfs v0.15.0 // indirect
github.com/prometheus/common v0.55.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
@@ -129,18 +150,19 @@ require (
github.com/shibumi/go-pathspec v1.3.0 // indirect
github.com/shirou/gopsutil/v3 v3.24.4 // indirect
github.com/shoenig/go-m1cpu v0.1.6 // indirect
github.com/sigstore/sigstore v1.8.3 // indirect
github.com/sigstore/sigstore v1.8.7 // indirect
github.com/sigstore/timestamp-authority v1.2.2 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.6.0 // indirect
github.com/spf13/cobra v1.8.0 // indirect
github.com/spf13/cobra v1.8.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.18.2 // indirect
github.com/spf13/viper v1.19.0 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect
github.com/tchap/go-patricia/v2 v2.3.1 // indirect
github.com/testcontainers/testcontainers-go v0.32.0 // indirect
github.com/theupdateframework/go-tuf v0.7.0 // indirect
github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect
github.com/tklauser/go-sysconf v0.3.14 // indirect
@@ -152,23 +174,30 @@ require (
github.com/yashtewari/glob-intersection v0.2.0 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
go.mongodb.org/mongo-driver v1.15.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.51.0 // indirect
go.opentelemetry.io/otel v1.26.0 // indirect
go.opentelemetry.io/otel/metric v1.26.0 // indirect
go.opentelemetry.io/otel/sdk v1.26.0 // indirect
go.opentelemetry.io/otel/trace v1.26.0 // indirect
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.52.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.52.0 // indirect
go.opentelemetry.io/otel v1.28.0 // indirect
go.opentelemetry.io/otel/metric v1.28.0 // indirect
go.opentelemetry.io/otel/sdk v1.28.0 // indirect
go.opentelemetry.io/otel/trace v1.28.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/crypto v0.23.0 // indirect
golang.org/x/crypto v0.25.0 // indirect
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect
golang.org/x/mod v0.17.0 // indirect
golang.org/x/net v0.27.0 // indirect
golang.org/x/oauth2 v0.21.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/term v0.20.0 // indirect
golang.org/x/text v0.15.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240515191416-fc5f0ca64291 // indirect
google.golang.org/grpc v1.64.0 // indirect
google.golang.org/protobuf v1.34.1 // indirect
golang.org/x/sys v0.22.0 // indirect
golang.org/x/term v0.22.0 // indirect
golang.org/x/text v0.16.0 // indirect
golang.org/x/time v0.5.0 // indirect
google.golang.org/genproto v0.0.0-20240722135656-d784300faade // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240722135656-d784300faade // indirect
google.golang.org/grpc v1.65.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
k8s.io/klog/v2 v2.120.1 // indirect

406
go.sum
View File

@@ -1,16 +1,22 @@
cloud.google.com/go v0.112.1 h1:uJSeirPke5UNZHIb4SxfZklVSiWWVqW4oXlETwZziwM=
cloud.google.com/go/compute v1.25.1 h1:ZRpHJedLtTpKgr3RV1Fx23NuaAEN1Zfx9hw1u4aJdjU=
cloud.google.com/go/compute v1.25.1/go.mod h1:oopOIR53ly6viBYxaDhBfJwzUAxf1zE//uf3IB011ls=
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/iam v1.1.6 h1:bEa06k05IO4f4uJonbB5iAgKTPpABy1ayxaIZV/GHVc=
cloud.google.com/go/iam v1.1.6/go.mod h1:O0zxdPeGBoFdWW3HWmBxJsk0pfvNM/p/qa82rWOGTwI=
cloud.google.com/go/kms v1.15.8 h1:szIeDCowID8th2i8XE4uRev5PMxQFqW+JjwYxL9h6xs=
cloud.google.com/go/kms v1.15.8/go.mod h1:WoUHcDjD9pluCg7pNds131awnH429QGvRM3N/4MyoVs=
cuelabs.dev/go/oci/ociregistry v0.0.0-20240314152124-224736b49f2e h1:GwCVItFUPxwdsEYnlUcJ6PJxOjTeFFCKOh6QWg4oAzQ=
cuelabs.dev/go/oci/ociregistry v0.0.0-20240314152124-224736b49f2e/go.mod h1:ApHceQLLwcOkCEXM1+DyCXTHEJhNGDpJ2kmV6axsx24=
cuelang.org/go v0.8.1 h1:VFYsxIFSPY5KgSaH1jQ2GxHOrbu6Ga3kEI70yCZwnOg=
cuelang.org/go v0.8.1/go.mod h1:CoDbYolfMms4BhWUlhD+t5ORnihR7wvjcfgyO9lL5FI=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.115.0 h1:CnFSK6Xo3lDYRoBKEcAtia6VSC837/ZkJuRduSFnr14=
cloud.google.com/go v0.115.0/go.mod h1:8jIM5vVgoAEoiVxQ/O4BFTfHqulPZgs/ufEzMcFMdWU=
cloud.google.com/go/auth v0.7.2 h1:uiha352VrCDMXg+yoBtaD0tUF4Kv9vrtrWPYXwutnDE=
cloud.google.com/go/auth v0.7.2/go.mod h1:VEc4p5NNxycWQTMQEDQF0bd6aTMb6VgYDXEwiJJQAbs=
cloud.google.com/go/auth/oauth2adapt v0.2.3 h1:MlxF+Pd3OmSudg/b1yZ5lJwoXCEaeedAguodky1PcKI=
cloud.google.com/go/auth/oauth2adapt v0.2.3/go.mod h1:tMQXOfZzFuNuUxOypHlQEXgdfX5cuhwU+ffUuXRJE8I=
cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY=
cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY=
cloud.google.com/go/iam v1.1.10 h1:ZSAr64oEhQSClwBL670MsJAW5/RLiC6kfw3Bqmd5ZDI=
cloud.google.com/go/iam v1.1.10/go.mod h1:iEgMq62sg8zx446GCaijmA2Miwg5o3UbO+nI47WHJps=
cloud.google.com/go/kms v1.18.2 h1:EGgD0B9k9tOOkbPhYW1PHo2W0teamAUYMOUIcDRMfPk=
cloud.google.com/go/kms v1.18.2/go.mod h1:YFz1LYrnGsXARuRePL729oINmN5J/5e7nYijgvfiIeY=
cloud.google.com/go/longrunning v0.5.9 h1:haH9pAuXdPAMqHvzX0zlWQigXT7B0+CL4/2nXXdBo5k=
cloud.google.com/go/longrunning v0.5.9/go.mod h1:HD+0l9/OOW0za6UWdKJtXoFAX/BGg/3Wj8p10NeWF7c=
cuelabs.dev/go/oci/ociregistry v0.0.0-20240404174027-a39bec0462d2 h1:BnG6pr9TTr6CYlrJznYUDj6V7xldD1W+1iXPum0wT/w=
cuelabs.dev/go/oci/ociregistry v0.0.0-20240404174027-a39bec0462d2/go.mod h1:pK23AUVXuNzzTpfMCA06sxZGeVQ/75FdVtW249de9Uo=
cuelang.org/go v0.9.2 h1:pfNiry2PdRBr02G/aKm5k2vhzmqbAOoaB4WurmEbWvs=
cuelang.org/go v0.9.2/go.mod h1:qpAYsLOf7gTM1YdEg6cxh553uZ4q9ZDWlPbtZr9q1Wk=
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
@@ -23,12 +29,12 @@ github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/alibabacloudsdkgo
github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/alibabacloudsdkgo/helper v0.2.0/go.mod h1:GgeIE+1be8Ivm7Sh4RgwI42aTtC9qrcj+Y9Y6CjJhJs=
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU=
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.10.0 h1:n1DH8TPV4qqPTje2RcUBYwtrTWlabVp4n46+74X2pn4=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.10.0/go.mod h1:HDcZnuGbiyppErN6lB+idp4CKhjbc8gwjto6OPpyggM=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 h1:sO0/P7g68FrryJzljemN+6GTssUXdANk6aJ7T1ZxnsQ=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1/go.mod h1:h8hyGFDsU5HMivxiS2iYFZsgDbU9OnnJ163x5UGVKYo=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 h1:LqbJ/WzJUwBf8UiaSzgX7aMclParm9/5Vgp+TY51uBQ=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2/go.mod h1:yInRyqWXAuaPrgI7p70+lDDgh3mlBohis29jGMISnmc=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.12.0 h1:1nGuui+4POelzDwI7RG56yfQJHCnKvwfMoU7VsEp+Zg=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.12.0/go.mod h1:99EvauvlcJ1U06amZiksfYz/3aFGyIhWGHVyiZXtBAI=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 h1:tfLQ34V6F7tVSwoTf/4lH5sE0o6eCJuNDTmH09nDpbc=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0/go.mod h1:9kIvujWAA58nmPmWB1m23fyWic1kYZMxD9CxaWn4Qpg=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.9.0 h1:H+U3Gk9zY56G3u872L82bk4thcsy2Gghb9ExT4Zvm1o=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.9.0/go.mod h1:mgrmMSgaLp9hmax62XQTd0N4aAqSE5E0DulSpVYK7vc=
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.1.0 h1:DRiANoJTiW6obBQe3SqZizkuV1PEgfiiGivmVocDy64=
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.1.0/go.mod h1:qLIye2hwb/ZouqhpSD9Zn3SJipvpEnz1Ywl3VUk9Y0s=
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0 h1:D3occbWoio4EBLkbkevetNMAVX197GkzbUMtqjGWn80=
@@ -53,6 +59,7 @@ github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUM
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU=
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0=
github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
@@ -95,52 +102,54 @@ github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
github.com/aws/aws-sdk-go v1.53.10 h1:3enP5l5WtezT9Ql+XZqs56JBf5YUd/FEzTCg///OIGY=
github.com/aws/aws-sdk-go v1.53.10/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
github.com/aws/aws-sdk-go-v2 v1.28.0 h1:ne6ftNhY0lUvlazMUQF15FF6NH80wKmPRFG7g2q6TCw=
github.com/aws/aws-sdk-go-v2 v1.28.0/go.mod h1:ffIFB97e2yNsv4aTSGkqtHnppsIJzw7G7BReUZ3jCXM=
github.com/aws/aws-sdk-go-v2/config v1.27.19 h1:+DBS8gJP6VsxYkZ6UEV0/VsRM2rYpbQCYsosW9RRmeQ=
github.com/aws/aws-sdk-go-v2/config v1.27.19/go.mod h1:KzZcioJWzy9oV+oS5CobYXlDtU9+eW7bPG1g7gizTW4=
github.com/aws/aws-sdk-go-v2/credentials v1.17.19 h1:R18G7nBBGLby51CFEqUBFF2IVl7LUdCtYj6iosUwh/0=
github.com/aws/aws-sdk-go-v2/credentials v1.17.19/go.mod h1:xr9kUMnaLTB866HItT6pg58JgiBP77fSQLBwIa//zk8=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.6 h1:vVOuhRyslJ6T/HteG71ZWCTas1q2w6f0NKsNbkXHs/A=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.6/go.mod h1:jimWaqLiT0sJGLh51dKCLLtExRYPtMU7MpxuCgtbkxg=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.10 h1:LZIUb8sQG2cb89QaVFtMSnER10gyKkqU1k3hP3g9das=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.10/go.mod h1:BRIqay//vnIOCZjoXWSLffL2uzbtxEmnSlfbvVh7Z/4=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.10 h1:HY7CXLA0GiQUo3WYxOP7WYkLcwvRX4cLPf5joUcrQGk=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.10/go.mod h1:kfRBSxRa+I+VyON7el3wLZdrO91oxUxEwdAaWgFqN90=
github.com/aws/aws-sdk-go v1.54.19 h1:tyWV+07jagrNiCcGRzRhdtVjQs7Vy41NwsuOcl0IbVI=
github.com/aws/aws-sdk-go v1.54.19/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU=
github.com/aws/aws-sdk-go-v2 v1.30.3 h1:jUeBtG0Ih+ZIFH0F4UkmL9w3cSpaMv9tYYDbzILP8dY=
github.com/aws/aws-sdk-go-v2 v1.30.3/go.mod h1:nIQjQVp5sfpQcTc9mPSr1B0PaWK5ByX9MOoDadSN4lc=
github.com/aws/aws-sdk-go-v2/config v1.27.27 h1:HdqgGt1OAP0HkEDDShEl0oSYa9ZZBSOmKpdpsDMdO90=
github.com/aws/aws-sdk-go-v2/config v1.27.27/go.mod h1:MVYamCg76dFNINkZFu4n4RjDixhVr51HLj4ErWzrVwg=
github.com/aws/aws-sdk-go-v2/credentials v1.17.27 h1:2raNba6gr2IfA0eqqiP2XiQ0UVOpGPgDSi0I9iAP+UI=
github.com/aws/aws-sdk-go-v2/credentials v1.17.27/go.mod h1:gniiwbGahQByxan6YjQUMcW4Aov6bLC3m+evgcoN4r4=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11 h1:KreluoV8FZDEtI6Co2xuNk/UqI9iwMrOx/87PBNIKqw=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11/go.mod h1:SeSUYBLsMYFoRvHE0Tjvn7kbxaUhl75CJi1sbfhMxkU=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15 h1:SoNJ4RlFEQEbtDcCEt+QG56MY4fm4W8rYirAmq+/DdU=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15/go.mod h1:U9ke74k1n2bf+RIgoX1SXFed1HLs51OgUSs+Ph0KJP8=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15 h1:C6WHdGnTDIYETAm5iErQUiVNsclNx9qbJVPIt03B6bI=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15/go.mod h1:ZQLZqhcu+JhSrA9/NXRm8SkDvsycE+JkV3WGY41e+IM=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY=
github.com/aws/aws-sdk-go-v2/service/ecr v1.20.2 h1:y6LX9GUoEA3mO0qpFl1ZQHj1rFyPWVphlzebiSt2tKE=
github.com/aws/aws-sdk-go-v2/service/ecr v1.20.2/go.mod h1:Q0LcmaN/Qr8+4aSBrdrXXePqoX0eOuYpJLbYpilmWnA=
github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.18.2 h1:PpbXaecV3sLAS6rjQiaKw4/jyq3Z8gNzmoJupHAoBp0=
github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.18.2/go.mod h1:fUHpGXr4DrXkEDpGAjClPsviWf+Bszeb0daKE0blxv8=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 h1:Ji0DY1xUsUr3I8cHps0G+XM3WWU16lP6yG8qu1GAZAs=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2/go.mod h1:5CsjAbs3NlGQyZNFACh+zztPDI7fU6eW9QsxjfnuBKg=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.12 h1:kO2J7WMroF/OTHN9WTcUtMjPhJ7ZoNxx0dwv6UCXQgY=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.12/go.mod h1:mrNxrjYvXaSjZe5fkKaWgDnOQ6BExLn/7Ru9OpRsMPY=
github.com/aws/aws-sdk-go-v2/service/kms v1.32.1 h1:FARrQLRQXpCFYylIUVF1dRij6YbPCmtwudq9NBk4kFc=
github.com/aws/aws-sdk-go-v2/service/kms v1.32.1/go.mod h1:8lETO9lelSG2B6KMXFh2OwPPqGV6WQM3RqLAEjP1xaU=
github.com/aws/aws-sdk-go-v2/service/sso v1.20.12 h1:FsYii6U+2k8ynYBo+pywlCBY9HNAFRh+iICRHbn+Qyw=
github.com/aws/aws-sdk-go-v2/service/sso v1.20.12/go.mod h1:j9Rps+Lcs2A0tYypWsNBeJOjgsIYUf1Styppo9Es0Wo=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.24.6 h1:lEE+xEcq3lh9bk362tgErP1+n689q5ERdmTwmF1XT3M=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.24.6/go.mod h1:2tR0x1DCL5IgnVZ1NQNFDNg5/XL/kiQgWI5l7I/N5Js=
github.com/aws/aws-sdk-go-v2/service/sts v1.28.13 h1:TSzmuUeruVJ4XWYp3bYzKCXue70ECpJWmbP3UfEvhYY=
github.com/aws/aws-sdk-go-v2/service/sts v1.28.13/go.mod h1:FppRtFjBA9mSWTj2cIAWCP66+bbBPMuPpBfWRXC5Yi0=
github.com/aws/smithy-go v1.20.2 h1:tbp628ireGtzcHDDmLT/6ADHidqnwgF57XOXZe6tp4Q=
github.com/aws/smithy-go v1.20.2/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E=
github.com/aws/aws-sdk-go-v2/service/ecr v1.29.1 h1:ywNLJrn/Qn4enDsz/XnKlvpnLqvJxFGQV2BltWltbis=
github.com/aws/aws-sdk-go-v2/service/ecr v1.29.1/go.mod h1:WadVIk+UrTvWuAsCp6BKGX4i2snurpz8mPWhJQnS7Dg=
github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.24.1 h1:Eq9i/mvOlGghiKe9NtsmeD9Wlwg8p4fbsqrMb3nWirM=
github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.24.1/go.mod h1:VtOgEoLEPV1YADuq+Z2XOK6/wKkGW2YK6DjChZ/GvDs=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3 h1:dT3MqvGhSoaIhRseqw2I0yH81l7wiR2vjs57O51EAm8=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3/go.mod h1:GlAeCkHwugxdHaueRr4nhPuY+WW+gR8UjlcqzPr1SPI=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17 h1:HGErhhrxZlQ044RiM+WdoZxp0p+EGM62y3L6pwA4olE=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17/go.mod h1:RkZEx4l0EHYDJpWppMJ3nD9wZJAa8/0lq9aVC+r2UII=
github.com/aws/aws-sdk-go-v2/service/kms v1.35.1 h1:0gP2OJJT6HM2BYltZ9x+A87OE8LJL96DXeAAdLv3t1M=
github.com/aws/aws-sdk-go-v2/service/kms v1.35.1/go.mod h1:hGONorZkQCfR5DW6l2xdy7zC8vfO0r9pJlwyg6gmGeo=
github.com/aws/aws-sdk-go-v2/service/sso v1.22.4 h1:BXx0ZIxvrJdSgSvKTZ+yRBeSqqgPM89VPlulEcl37tM=
github.com/aws/aws-sdk-go-v2/service/sso v1.22.4/go.mod h1:ooyCOXjvJEsUw7x+ZDHeISPMhtwI3ZCB7ggFMcFfWLU=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4 h1:yiwVzJW2ZxZTurVbYWA7QOrAaCYQR72t0wrSBfoesUE=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4/go.mod h1:0oxfLkpz3rQ/CHlx5hB7H69YUpFiI1tql6Q6Ne+1bCw=
github.com/aws/aws-sdk-go-v2/service/sts v1.30.3 h1:ZsDKRLXGWHk8WdtyYMoGNO7bTudrvuKpDKgMVRlepGE=
github.com/aws/aws-sdk-go-v2/service/sts v1.30.3/go.mod h1:zwySh8fpFyXp9yOr/KVzxOl8SRqgf/IDw5aUt9UKFcQ=
github.com/aws/smithy-go v1.20.3 h1:ryHwveWzPV5BIof6fyDvor6V3iUL7nTfiTKXHiW05nE=
github.com/aws/smithy-go v1.20.3/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E=
github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20231024185945-8841054dbdb8 h1:SoFYaT9UyGkR0+nogNyD/Lj+bsixB+SNuAS4ABlEs6M=
github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20231024185945-8841054dbdb8/go.mod h1:2JF49jcDOrLStIXN/j/K1EKRq8a8R2qRnlZA6/o/c7c=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/buildkite/agent/v3 v3.62.0 h1:yvzSjI8Lgifw883I8m9u8/L/Thxt4cLFd5aWPn3gg70=
github.com/buildkite/agent/v3 v3.62.0/go.mod h1:jN6SokGXrVNNIpI0BGQ+j5aWeI3gin8F+3zwA5Q6gqM=
github.com/buildkite/go-pipeline v0.3.2 h1:SW4EaXNwfjow7xDRPGgX0Rcx+dPj5C1kV9LKCLjWGtM=
github.com/buildkite/go-pipeline v0.3.2/go.mod h1:iY5jzs3Afc8yHg6KDUcu3EJVkfaUkd9x/v/OH98qyUA=
github.com/buildkite/interpolate v0.0.0-20200526001904-07f35b4ae251 h1:k6UDF1uPYOs0iy1HPeotNa155qXRWrzKnqAaGXHLZCE=
github.com/buildkite/interpolate v0.0.0-20200526001904-07f35b4ae251/go.mod h1:gbPR1gPu9dB96mucYIR7T3B7p/78hRVSOuzIWLHK2Y4=
github.com/buildkite/agent/v3 v3.75.1 h1:FJg1gss9nUESExTsfx6yWqs/g20Vyd4pHSEB9iuT4pI=
github.com/buildkite/agent/v3 v3.75.1/go.mod h1:UXCAEaqJnw5UsoZjJ9NxMvdSGc4oMHBnQFQqzGPDM0Y=
github.com/buildkite/go-pipeline v0.10.0 h1:EDffu+LfMY2k5u+iEdo6Jn3obGKsrL5wicc1O/yFeRs=
github.com/buildkite/go-pipeline v0.10.0/go.mod h1:eMH1kiav5VeiTiu0Mk2/M7nZhKyFeL4iGj7Y7rj4f3w=
github.com/buildkite/interpolate v0.1.3 h1:OFEhqji1rNTRg0u9DsSodg63sjJQEb1uWbENq9fUOBM=
github.com/buildkite/interpolate v0.1.3/go.mod h1:UNVe6A+UfiBNKbhAySrBbZFZFxQ+DXr9nWen6WVt/A8=
github.com/buildkite/roko v1.2.0 h1:hbNURz//dQqNl6Eo9awjQOVOZwSDJ8VEbBDxSfT9rGQ=
github.com/buildkite/roko v1.2.0/go.mod h1:23R9e6nHxgedznkwwfmqZ6+0VJZJZ2Sg/uVcp2cP46I=
github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
github.com/bytecodealliance/wasmtime-go/v3 v3.0.2 h1:3uZCA/BLTIu+DqCfguByNMJa2HVHpXvjfy0Dy7g6fuA=
github.com/bytecodealliance/wasmtime-go/v3 v3.0.2/go.mod h1:RnUjnIXxEJcL6BgCvNyzCCRzZcxCgsZCi+RNlvYor5Q=
@@ -148,6 +157,7 @@ github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTx
github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs=
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
@@ -159,28 +169,30 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=
github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
github.com/cloudflare/circl v1.3.8 h1:j+V8jJt09PoeMFIu2uh5JUyEaIHTXVOHslFoLNAKqwI=
github.com/cloudflare/circl v1.3.8/go.mod h1:PDRU+oXvdD7KCtgKxW95M5Z8BpSCJXQORiZFnBQS5QU=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cockroachdb/apd/v3 v3.2.1 h1:U+8j7t0axsIgvQUqthuNm82HIrYXodOV2iWLWtEaIwg=
github.com/cockroachdb/apd/v3 v3.2.1/go.mod h1:klXJcjp+FffLTHlhIG69tezTDvdP065naDsHzKhYSqc=
github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb h1:EDmT6Q9Zs+SbUoc7Ik9EfrFqcylYqgPZ9ANSbTAntnE=
github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb/go.mod h1:ZjrT6AXHbDs86ZSdt/osfBi5qfexBrKUdONk989Wnk4=
github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be h1:J5BL2kskAlV9ckgEsNQXscjIaLiOYiZ75d4e94E6dcQ=
github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be/go.mod h1:mk5IQ+Y0ZeO87b858TlA645sVcEcbiX6YqP98kt+7+w=
github.com/containerd/containerd v1.7.18 h1:jqjZTQNfXGoEaZdW1WwPU0RqSn1Bm2Ay/KJPUuO8nao=
github.com/containerd/containerd v1.7.18/go.mod h1:IYEk9/IO6wAPUz2bCMVUbsfXjzw5UNP5fLz4PsUygQ4=
github.com/containerd/errdefs v0.1.0 h1:m0wCRBiu1WJT/Fr+iOoQHMQS/eP5myQ8lCv4Dz5ZURM=
github.com/containerd/errdefs v0.1.0/go.mod h1:YgWiiHtLmSeBrvpw+UfPijzbLaB77mEG1WwJTDETIV0=
github.com/containerd/containerd v1.7.19 h1:/xQ4XRJ0tamDkdzrrBAUy/LE5nCcxFKdBm4EcPrSMEE=
github.com/containerd/containerd v1.7.19/go.mod h1:h4FtNYUUMB4Phr6v+xG89RYKj9XccvbNSCKjdufCrkc=
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A=
github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw=
github.com/containerd/stargz-snapshotter/estargz v0.15.1 h1:eXJjw9RbkLFgioVaTG+G/ZW/0kEe2oEKCdS/ZxIyoCU=
github.com/containerd/stargz-snapshotter/estargz v0.15.1/go.mod h1:gr2RNwukQ/S9Nv33Lt6UC7xEx58C+LHRdoqbEKjz1Kk=
github.com/coreos/go-oidc/v3 v3.10.0 h1:tDnXHnLyiTVyT/2zLDGj09pFPkhND8Gl8lnTRhoEaJU=
github.com/coreos/go-oidc/v3 v3.10.0/go.mod h1:5j11xcw0D3+SGxn6Z/WFADsgcWVMyNAlSQupk0KK3ac=
github.com/coreos/go-oidc/v3 v3.11.0 h1:Ia3MxdwpSw702YW0xgfmP1GVCMA9aEFWu12XUZ3/OtI=
github.com/coreos/go-oidc/v3 v3.11.0/go.mod h1:gE3LgjOgFoHi9a4ce4/tJczr0Ai2/BoDhf0r5lltWI0=
github.com/cpuguy83/dockercfg v0.3.1 h1:/FpZ+JaygUR/lZP2NlFI2DVfrOEMAIKP5wWEJdoYe9E=
github.com/cpuguy83/dockercfg v0.3.1/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc=
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/cyberphone/json-canonicalization v0.0.0-20231217050601-ba74d44ecf5f h1:eHnXnuK47UlSTOQexbzxAZfekVz6i+LKRdj1CU5DPaM=
@@ -210,8 +222,8 @@ github.com/docker/cli v26.1.3+incompatible h1:bUpXT/N0kDE3VUHI2r5VMsYQgi38kYuoC0
github.com/docker/cli v26.1.3+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v26.1.3+incompatible h1:lLCzRbrVZrljpVNobJu1J2FHk8V0s4BawoZippkc+xo=
github.com/docker/docker v26.1.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v27.0.3+incompatible h1:aBGI9TeQ4MPlhquTQKq9XbK79rKFVwXNUAYz9aXyEBE=
github.com/docker/docker v27.0.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker-credential-helpers v0.8.1 h1:j/eKUktUltBtMzKqmfLB0PAgqYyMHOp5vfsD1807oKo=
github.com/docker/docker-credential-helpers v0.8.1/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M=
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
@@ -224,6 +236,10 @@ github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxER
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/emicklei/proto v1.12.1 h1:6n/Z2pZAnBwuhU66Gs8160B8rrrYKo7h2F2sCOnNceE=
github.com/emicklei/proto v1.12.1/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
@@ -245,8 +261,8 @@ github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A=
github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k=
github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ=
github.com/go-jose/go-jose/v4 v4.0.1 h1:QVEPDE3OluqXBQZDcnNvQrInro2h0e4eqNbnZSWqS6U=
github.com/go-jose/go-jose/v4 v4.0.1/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY=
github.com/go-jose/go-jose/v4 v4.0.2 h1:R3l3kkBds16bO7ZFAEEcofK0MkrAJt3jlJznWZG0nvk=
github.com/go-jose/go-jose/v4 v4.0.2/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
@@ -278,8 +294,8 @@ github.com/go-openapi/validate v0.24.0/go.mod h1:iyeX1sEufmv3nPbBdX3ieNviWnOZaJ1
github.com/go-piv/piv-go v1.11.0 h1:5vAaCdRTFSIW4PeqMbnsDlUZ7odMYWnHBDGdmtU/Zhg=
github.com/go-piv/piv-go v1.11.0/go.mod h1:NZ2zmjVkfFaL/CF8cVQ/pXdXtuj110zEKGdJM6fJZZM=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg=
github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U=
github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
@@ -290,39 +306,46 @@ github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOW
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang/glog v1.2.0 h1:uCdmnmatrKCgMBlM4rMuJZWOkPDqdbZPnrMXDY4gI68=
github.com/golang/glog v1.2.0/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/glog v1.2.1 h1:OptwRhECazUx5ix5TTWC3EZhsZEHWcYWY4FQHTIubm4=
github.com/golang/glog v1.2.1/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/certificate-transparency-go v1.1.8 h1:LGYKkgZF7satzgTak9R4yzfJXEeYVAjV6/EAEJOf1to=
github.com/google/certificate-transparency-go v1.1.8/go.mod h1:bV/o8r0TBKRf1X//iiiSgWrvII4d7/8OiA+3vG26gI8=
github.com/google/certificate-transparency-go v1.2.1 h1:4iW/NwzqOqYEEoCBEFP+jPbBXbLqMpq3CifMyOnDUME=
github.com/google/certificate-transparency-go v1.2.1/go.mod h1:bvn/ytAccv+I6+DGkqpvSsEdiVGramgaSC6RD3tEmeE=
github.com/google/flatbuffers v2.0.8+incompatible h1:ivUb1cGomAB101ZM1T0nOiWz9pSrTMoa9+EiY7igmkM=
github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49 h1:0VpGH+cDhbDtdcweoyCVsF3fhN8kejK6rFe/2FFX2nU=
github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49/go.mod h1:BkkQ4L1KS1xMt2aWSPStnn55ChGC0DPOn2FQYj+f25M=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.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.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-containerregistry v0.19.2 h1:TannFKE1QSajsP6hPWb5oJNgKe1IKjHukIKDUmvsV6w=
github.com/google/go-containerregistry v0.19.2/go.mod h1:YCMFNQeeXeLF+dnhhWkqDItx/JSkH01j1Kis4PsjzFI=
github.com/google/go-github/v55 v55.0.0 h1:4pp/1tNMB9X/LuAhs5i0KQAE40NmiR/y6prLNb9x9cg=
github.com/google/go-github/v55 v55.0.0/go.mod h1:JLahOTA1DnXzhxEymmFF5PP2tSS9JVNj68mSZNDwskA=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
@@ -336,17 +359,18 @@ github.com/google/tink/go v1.7.0 h1:6Eox8zONGebBFcCBqkVmt60LaWZa6xg1cl/DwAh/J1w=
github.com/google/tink/go v1.7.0/go.mod h1:GAUOd+QE3pgj9q8VKIGTCP33c/B7eb4NhxLcgTJZStM=
github.com/google/trillian v1.6.0 h1:jMBeDBIkINFvS2n6oV5maDqfRlxREAc6CW9QYWQ0qT4=
github.com/google/trillian v1.6.0/go.mod h1:Yu3nIMITzNhhMJEHjAtp6xKiu+H/iHu2Oq5FjV2mCWI=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs=
github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0=
github.com/googleapis/gax-go/v2 v2.12.3 h1:5/zPPDvw8Q1SuXjrqrZslrqT7dL/uJT2CQii/cLCKqA=
github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBHwWRvkNFJUQcS4=
github.com/googleapis/gax-go/v2 v2.12.5 h1:8gw9KZK8TiVKB6q3zHY3SBzLnrGp6HQjyfYBYGmXdxA=
github.com/googleapis/gax-go/v2 v2.12.5/go.mod h1:BUDKcWo+RaKq5SC9vVYL0wLADa3VcfswbOMMRmB9H3E=
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0 h1:RtRsiaGvWxcwd8y3BiRZxsylPT8hLWZ5SPcfI+3IDNk=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0/go.mod h1:TzP6duP4Py2pHLVPPQp42aoYI92+PCrVotyR5e8Vqlk=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
@@ -355,8 +379,8 @@ github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB1
github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/hashicorp/go-retryablehttp v0.7.6 h1:TwRYfx2z2C4cLbXmT8I5PgP/xmuqASDyiVuGYfs9GZM=
github.com/hashicorp/go-retryablehttp v0.7.6/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk=
github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU=
github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk=
github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc=
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=
@@ -367,8 +391,8 @@ github.com/hashicorp/go-sockaddr v1.0.5 h1:dvk7TIXCZpmfOlM+9mlcrWmWjw/wlKT+VDq2w
github.com/hashicorp/go-sockaddr v1.0.5/go.mod h1:uoUUmtwU7n9Dv3O4SNLeFvg0SxQ3lyjsj6+CCykpaxI=
github.com/hashicorp/hcl v1.0.1-vault-5 h1:kI3hhbbyzr4dldA8UdTb7ZlVVlI2DACdCfz31RPDgJM=
github.com/hashicorp/hcl v1.0.1-vault-5/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM=
github.com/hashicorp/vault/api v1.12.2 h1:7YkCTE5Ni90TcmYHDBExdt4WGJxhpzaHqR6uGbQb/rE=
github.com/hashicorp/vault/api v1.12.2/go.mod h1:LSGf1NGT1BnvFFnKVtnvcaLBM2Lz+gJdpL6HUYed8KE=
github.com/hashicorp/vault/api v1.14.0 h1:Ah3CFLixD5jmjusOgm8grfN9M0d+Y8fVR2SW0K6pJLU=
github.com/hashicorp/vault/api v1.14.0/go.mod h1:pV9YLxBGSz+cItFDd8Ii4G17waWOQ32zVjMWHe/cOqk=
github.com/howeyc/gopass v0.0.0-20210920133722-c8aef6fb66ef h1:A9HsByNhogrvm9cWb28sjiS3i7tcKCkflWFEkHfuAgM=
github.com/howeyc/gopass v0.0.0-20210920133722-c8aef6fb66ef/go.mod h1:lADxMC39cJJqL93Duh1xhAs4I2Zs8mKS89XWXFGp9cs=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
@@ -385,12 +409,16 @@ github.com/jellydator/ttlcache/v3 v3.2.0 h1:6lqVJ8X3ZaUwvzENqPAobDsXNExfUJd61u++
github.com/jellydator/ttlcache/v3 v3.2.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 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/jmhodges/clock v1.2.0 h1:eq4kys+NI0PLngzaHEe7AmPT90XMGIEySD1JfV1PDIs=
github.com/jmhodges/clock v1.2.0/go.mod h1:qKjhA7x7u/lQpPB1XAqX1b1lCI/w3/fNuYpI/ZjLynI=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/kipz/go-containerregistry v0.0.0-20240722163910-ebe90246535d h1:5QaWAwKhslfqxEyMZY0ofvsbMJkMLcx5E30JFufMVj8=
github.com/kipz/go-containerregistry v0.0.0-20240722163910-ebe90246535d/go.mod h1:YCMFNQeeXeLF+dnhhWkqDItx/JSkH01j1Kis4PsjzFI=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
@@ -401,8 +429,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/letsencrypt/boulder v0.0.0-20240515153123-6ae6aa8e9055 h1:sl8s8GXv/oHUSid9gd4B+Rovu9DOW4PxnKT2rNRfmzM=
github.com/letsencrypt/boulder v0.0.0-20240515153123-6ae6aa8e9055/go.mod h1:wGJPvcZTEexA3UpMx+4cZ19nk6gRrzrdW4jFEPsEqf0=
github.com/letsencrypt/boulder v0.0.0-20240620165639-de9c06129bec h1:2tTW6cDth2TSgRbAhD7yjZzTQmcN25sDRPEeinR51yQ=
github.com/letsencrypt/boulder v0.0.0-20240620165639-de9c06129bec/go.mod h1:TmwEoGCwIti7BCeJ9hescZgRtatxRE+A72pCoPfmcfk=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/lufia/plan9stats v0.0.0-20240513124658-fba389f38bae h1:dIZY4ULFcto4tAFlj1FYZl8ztUZ13bdq+PLY+NOfbyI=
github.com/lufia/plan9stats v0.0.0-20240513124658-fba389f38bae/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k=
@@ -465,8 +493,8 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw=
github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
github.com/open-policy-agent/opa v0.65.0 h1:wnEU0pEk80YjFi3yoDbFTMluyNssgPI4VJNJetD9a4U=
github.com/open-policy-agent/opa v0.65.0/go.mod h1:CNoLL44LuCH1Yot/zoeZXRKFylQtCJV+oGFiP2TeeEc=
github.com/open-policy-agent/opa v0.66.0 h1:DbrvfJQja0FBRcPOB3Z/BOckocN+M4ApNWyNhSRJt0w=
github.com/open-policy-agent/opa v0.66.0/go.mod h1:EIgNnJcol7AvQR/IcWLwL13k64gHVbNAVG46b2G+/EY=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
@@ -491,12 +519,13 @@ github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
github.com/prometheus/common v0.53.0 h1:U2pL9w9nmJwJDa4qqLQ3ZaePJ6ZTwt7cMD3AG3+aLCE=
github.com/prometheus/common v0.53.0/go.mod h1:BrxBKv3FWBIGXw89Mg1AeBq7FSyRzXWI3l3e7W3RN5U=
github.com/prometheus/procfs v0.15.0 h1:A82kmvXJq2jTu5YUhSGNlYoxh85zLnKgPz4bMZgI5Ek=
github.com/prometheus/procfs v0.15.0/go.mod h1:Y0RJ/Y5g5wJpkTisOtqwDSo4HwhGmLB4VQSw2sQJLHk=
github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/protocolbuffers/txtpbfmt v0.0.0-20231025115547-084445ff1adf h1:014O62zIzQwvoD7Ekj3ePDF5bv9Xxy0w6AZk0qYbjUk=
github.com/protocolbuffers/txtpbfmt v0.0.0-20231025115547-084445ff1adf/go.mod h1:jgxiZysxFPM+iWKwQwPR+y+Jvo54ARd4EisXxKYpB5c=
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM=
@@ -526,22 +555,22 @@ github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFt
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k=
github.com/sigstore/cosign/v2 v2.2.4 h1:iY4vtEacmu2hkNj1Fh+8EBqBwKs2DHM27/lbNWDFJro=
github.com/sigstore/cosign/v2 v2.2.4/go.mod h1:JZlRD2uaEjVAvZ1XJ3QkkZJhTqSDVtLaet+C/TMR81Y=
github.com/sigstore/fulcio v1.4.5 h1:WWNnrOknD0DbruuZWCbN+86WRROpEl3Xts+WT2Ek1yc=
github.com/sigstore/fulcio v1.4.5/go.mod h1:oz3Qwlma8dWcSS/IENR/6SjbW4ipN0cxpRVfgdsjMU8=
github.com/sigstore/cosign/v2 v2.3.0 h1:rBLVdKMYuER0blmaKMfMNkvawBdK1lTMz2L5PtTPrI8=
github.com/sigstore/cosign/v2 v2.3.0/go.mod h1:tjACBZS6LoH3bap5hU8MxyGC4DIJiatqhZxuJWFcIJ0=
github.com/sigstore/fulcio v1.5.1 h1:Iasy1zfNjaq8BV4S8o6pXspLDU28PQC2z07GmOu9zpM=
github.com/sigstore/fulcio v1.5.1/go.mod h1:W1A/UHrTopy1IBZPMtHmxg7GPYAu+vt5dRXM3W6yjPo=
github.com/sigstore/rekor v1.3.6 h1:QvpMMJVWAp69a3CHzdrLelqEqpTM3ByQRt5B5Kspbi8=
github.com/sigstore/rekor v1.3.6/go.mod h1:JDTSNNMdQ/PxdsS49DJkJ+pRJCO/83nbR5p3aZQteXc=
github.com/sigstore/sigstore v1.8.3 h1:G7LVXqL+ekgYtYdksBks9B38dPoIsbscjQJX/MGWkA4=
github.com/sigstore/sigstore v1.8.3/go.mod h1:mqbTEariiGA94cn6G3xnDiV6BD8eSLdL/eA7bvJ0fVs=
github.com/sigstore/sigstore/pkg/signature/kms/aws v1.8.4 h1:okxaVlaTrQowE1FA4UQ3rw54f7BUjdnzERIxbZTBZuc=
github.com/sigstore/sigstore/pkg/signature/kms/aws v1.8.4/go.mod h1:jkcPErmnCECuSJajUaUq5pwCMOeBF19VzQo6bv4l1D0=
github.com/sigstore/sigstore/pkg/signature/kms/azure v1.8.3 h1:xgbPRCr2npmmsuVVteJqi/ERw9+I13Wou7kq0Yk4D8g=
github.com/sigstore/sigstore/pkg/signature/kms/azure v1.8.3/go.mod h1:G4+I83FILPX6MtnoaUdmv/bRGEVtR3JdLeJa/kXdk/0=
github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.8.3 h1:vDl2fqPT0h3D/k6NZPlqnKFd1tz3335wm39qjvpZNJc=
github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.8.3/go.mod h1:9uOJXbXEXj+M6QjMKH5PaL5WDMu43rHfbIMgXzA8eKI=
github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.8.3 h1:h9G8j+Ds21zqqulDbA/R/ft64oQQIyp8S7wJYABYSlg=
github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.8.3/go.mod h1:zgCeHOuqF6k7A7TTEvftcA9V3FRzB7mrPtHOhXAQBnc=
github.com/sigstore/sigstore v1.8.7 h1:L7/zKauHTg0d0Hukx7qlR4nifh6T6O6UIt9JBwAmTIg=
github.com/sigstore/sigstore v1.8.7/go.mod h1:MPiQ/NIV034Fc3Kk2IX9/XmBQdK60wfmpvgK9Z1UjRA=
github.com/sigstore/sigstore/pkg/signature/kms/aws v1.8.7 h1:SoahswHQm2JhO8h3KTAeX8IZeE7mSR2Lc53ay5choes=
github.com/sigstore/sigstore/pkg/signature/kms/aws v1.8.7/go.mod h1:TOVOPOqldrrz4dP7x4/0DFQTs9QSXZUoHu21+JHmixA=
github.com/sigstore/sigstore/pkg/signature/kms/azure v1.8.7 h1:jcdKxc5bvwfL7+ZbeCszaN/qsBd6180fGAHxeX5Ckm0=
github.com/sigstore/sigstore/pkg/signature/kms/azure v1.8.7/go.mod h1:gakVcpRiN+aFdLhPXXP8ubOCWiedM1YJ/gR74ez/tT0=
github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.8.7 h1:zYg1XlbKpQkmE7FpWTkLuUn7RttLAq4FcZ1G9JcqhoY=
github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.8.7/go.mod h1:VmUsO1R4OHuyHBEgI4bbSUn0z2nojszrDMvlDxyX/dE=
github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.8.7 h1:dbcB9VEddYrvK+y4rHeES5OZ/pMQuucfJ0qCNWQmnp0=
github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.8.7/go.mod h1:96MrPJBkHiAvqFyqviuYbwPAdbPCj8CR3V0RJ9bKjrE=
github.com/sigstore/timestamp-authority v1.2.2 h1:X4qyutnCQqJ0apMewFyx+3t7Tws00JQ/JonBiu3QvLE=
github.com/sigstore/timestamp-authority v1.2.2/go.mod h1:nEah4Eq4wpliDjlY342rXclGSO7Kb9hoRrl9tqLW13A=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
@@ -554,14 +583,14 @@ github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
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.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ=
github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk=
github.com/spiffe/go-spiffe/v2 v2.2.0 h1:9Vf06UsvsDbLYK/zJ4sYsIsHmMFknUD+feA7IYoWMQY=
github.com/spiffe/go-spiffe/v2 v2.2.0/go.mod h1:Urzb779b3+IwDJD2ZbN8fVl3Aa8G4N/PiUe6iXC0XxU=
github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
github.com/spiffe/go-spiffe/v2 v2.3.0 h1:g2jYNb/PDMB8I7mBGL2Zuq/Ur6hUhoroxGQFyD6tTj8=
github.com/spiffe/go-spiffe/v2 v2.3.0/go.mod h1:Oxsaio7DBgSNqhAO9i/9tLClaVlfRok7zvJnTV8ZyIY=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
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=
@@ -572,6 +601,7 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
@@ -581,16 +611,16 @@ github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDd
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48=
github.com/tchap/go-patricia/v2 v2.3.1 h1:6rQp39lgIYZ+MHmdEq4xzuk1t7OdC35z/xm0BGhTkes=
github.com/tchap/go-patricia/v2 v2.3.1/go.mod h1:VZRHKAb53DLaG+nA9EaYYiaEx6YztwDlLElMsnSHD4k=
github.com/testcontainers/testcontainers-go v0.31.0 h1:W0VwIhcEVhRflwL9as3dhY6jXjVCA27AkmbnZ+UTh3U=
github.com/testcontainers/testcontainers-go v0.31.0/go.mod h1:D2lAoA0zUFiSY+eAflqK5mcUx/A5hrrORaEQrd0SefI=
github.com/testcontainers/testcontainers-go/modules/registry v0.31.0 h1:QiQb8omImfD5ZWSh0YR0WNrFeRU+j2Cqfd8+dYdLgaE=
github.com/testcontainers/testcontainers-go/modules/registry v0.31.0/go.mod h1:rrkCrh2acVVbQw9JfN4DOBm/ODVCIHbveEq+k+HSyfU=
github.com/testcontainers/testcontainers-go v0.32.0 h1:ug1aK08L3gCHdhknlTTwWjPHPS+/alvLJU/DRxTD/ME=
github.com/testcontainers/testcontainers-go v0.32.0/go.mod h1:CRHrzHLQhlXUsa5gXjTOfqIEJcrK5+xMDmBr/WMI88E=
github.com/testcontainers/testcontainers-go/modules/registry v0.32.0 h1:b4JSSEhbGXGtQA1WXJ3BlbkVjjdXoFTtBPvLRe+9Y9Y=
github.com/testcontainers/testcontainers-go/modules/registry v0.32.0/go.mod h1:bX3JF8vQkv3D2frmrDyQd0GCQIQGl5nPG91xUvl7UhA=
github.com/thales-e-security/pool v0.0.2 h1:RAPs4q2EbWsTit6tpzuvTFlgFRJ3S8Evf5gtvVDbmPg=
github.com/thales-e-security/pool v0.0.2/go.mod h1:qtpMm2+thHtqhLzTwgDBj/OuNnMpupY8mv0Phz0gjhU=
github.com/theupdateframework/go-tuf v0.7.0 h1:CqbQFrWo1ae3/I0UCblSbczevCCbS31Qvs5LdxRWqRI=
github.com/theupdateframework/go-tuf v0.7.0/go.mod h1:uEB7WSY+7ZIugK6R1hiBMBjQftaFzn7ZCDJcp1tCUug=
github.com/theupdateframework/go-tuf/v2 v2.0.0-20240504210453-5a634eb214ae h1:Cb5/8rY0k9oB+SigleRtEP5BeQ3PZQGX051cFIyBNaM=
github.com/theupdateframework/go-tuf/v2 v2.0.0-20240504210453-5a634eb214ae/go.mod h1:LJo5jrV0LYV0jVSbCjPem6+0zrkPz8FnimzIECzsFDY=
github.com/theupdateframework/go-tuf/v2 v2.0.0 h1:rD8d9RotYBprZVgC+9oyTZ5MmawepnTSTqoDuxjWgbs=
github.com/theupdateframework/go-tuf/v2 v2.0.0/go.mod h1:baB22nBHeHBCeuGZcIlctNq4P61PcOdyARlplg5xmLA=
github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 h1:e/5i7d4oYZ+C1wj2THlRK+oAhjeS/TRQwMfkIuet3w0=
github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399/go.mod h1:LdwHTNJT99C5fTAzDz0ud328OgXz+gierycbcIx2fRs=
github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=
@@ -605,8 +635,8 @@ github.com/transparency-dev/merkle v0.0.2 h1:Q9nBoQcZcgPamMkGn7ghV8XiTZ/kRxn1yCG
github.com/transparency-dev/merkle v0.0.2/go.mod h1:pqSy+OXefQ1EDUVmAJ8MUhHB9TXGuzVAT58PqBoHz1A=
github.com/vbatts/tar-split v0.11.5 h1:3bHCTIheBm1qFTcgh9oPu+nNBtX+XJIupG/vacinCts=
github.com/vbatts/tar-split v0.11.5/go.mod h1:yZbwRsSeGjusneWgA781EKej9HF8vme8okylkAeNKLk=
github.com/xanzy/go-gitlab v0.102.0 h1:ExHuJ1OTQ2yt25zBMMj0G96ChBirGYv8U7HyUiYkZ+4=
github.com/xanzy/go-gitlab v0.102.0/go.mod h1:ETg8tcj4OhrB84UEgeE8dSuV/0h4BBL1uOV/qK0vlyI=
github.com/xanzy/go-gitlab v0.107.0 h1:P2CT9Uy9yN9lJo3FLxpMZ4xj6uWcpnigXsjvqJ6nd2Y=
github.com/xanzy/go-gitlab v0.107.0/go.mod h1:wKNKh3GkYDMOsGmnfuX+ITCmDuSDWFO0G+C4AygL9RY=
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
@@ -626,28 +656,28 @@ go.mongodb.org/mongo-driver v1.15.0 h1:rJCKC8eEliewXjZGf0ddURtl7tTVy1TK3bfl0gkUS
go.mongodb.org/mongo-driver v1.15.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c=
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.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.51.0 h1:Xs2Ncz0gNihqu9iosIZ5SkBbWo5T8JhhLJFMQL1qmLI=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.51.0/go.mod h1:vy+2G/6NvVMpwGX/NyLqcC41fxepnuKHk16E6IZUcJc=
go.opentelemetry.io/otel v1.26.0 h1:LQwgL5s/1W7YiiRwxf03QGnWLb2HW4pLiAhaA5cZXBs=
go.opentelemetry.io/otel v1.26.0/go.mod h1:UmLkJHUAidDval2EICqBMbnAd0/m2vmpf/dAM+fvFs4=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0/go.mod h1:zgBdWWAu7oEEMC06MMKc5NLbA/1YDXV1sMpSqEeLQLg=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 h1:tIqheXEFWAZ7O8A7m+J0aPTmpJN3YQ7qetUAdkkkKpk=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0/go.mod h1:nUeKExfxAQVbiVFn32YXpXZZHZ61Cc3s3Rn1pDBGAb0=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.52.0 h1:vS1Ao/R55RNV4O7TA2Qopok8yN+X0LIP6RVWLFkprck=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.52.0/go.mod h1:BMsdeOxN04K0L5FNUBfjFdvwWGNe/rkmSwH4Aelu/X0=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.52.0 h1:9l89oX4ba9kHbBol3Xin3leYJ+252h0zszDtBwyKe2A=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.52.0/go.mod h1:XLZfZboOJWHNKUv7eH0inh0E9VV6eWDFB/9yJyTLPp0=
go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo=
go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.27.0 h1:R9DE4kQ4k+YtfLI2ULwX82VtNQ2J8yZmA7ZIF/D+7Mc=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.27.0/go.mod h1:OQFyQVrDlbe+R7xrEyDr/2Wr67Ol0hRUgsfA+V5A95s=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 h1:qFffATk0X+HD+f1Z8lswGiOQYKHRlzfmdJm0wEaVrFA=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0/go.mod h1:MOiCmryaYtc+V0Ei+Tx9o5S1ZjA7kzLucuVuyzBZloQ=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 h1:IeMeyr1aBvBiPVYihXIaeIZba6b8E1bYp7lbdxK8CQg=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0/go.mod h1:oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU=
go.opentelemetry.io/otel/metric v1.26.0 h1:7S39CLuY5Jgg9CrnA9HHiEjGMF/X2VHvoXGgSllRz30=
go.opentelemetry.io/otel/metric v1.26.0/go.mod h1:SY+rHOI4cEawI9a7N1A4nIg/nTQXe1ccCNWYOJUrpX4=
go.opentelemetry.io/otel/sdk v1.26.0 h1:Y7bumHf5tAiDlRYFmGqetNcLaVUZmh4iYfmGxtmz7F8=
go.opentelemetry.io/otel/sdk v1.26.0/go.mod h1:0p8MXpqLeJ0pzcszQQN4F0S5FVjBLgypeGSngLsmirs=
go.opentelemetry.io/otel/trace v1.26.0 h1:1ieeAUb4y0TE26jUFrCIXKpTuVK7uJGN9/Z/2LP5sQA=
go.opentelemetry.io/otel/trace v1.26.0/go.mod h1:4iDxvGDQuUkHve82hJJ8UqrwswHYsZuWCBllGV2U2y0=
go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I=
go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM=
go.step.sm/crypto v0.44.2 h1:t3p3uQ7raP2jp2ha9P6xkQF85TJZh+87xmjSLaib+jk=
go.step.sm/crypto v0.44.2/go.mod h1:x1439EnFhadzhkuaGX7sz03LEMQ+jV4gRamf5LCZJQQ=
go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q=
go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s=
go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE=
go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg=
go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g=
go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI=
go.opentelemetry.io/proto/otlp v1.2.0 h1:pVeZGk7nXDC9O2hncA6nHldxEjm6LByfA2aN8IOkz94=
go.opentelemetry.io/proto/otlp v1.2.0/go.mod h1:gGpR8txAl5M03pDhMC79G6SdqNV26naRm/KDsgaHD8A=
go.step.sm/crypto v0.50.0 h1:BqI9sEgocoHDLLHiZnFqdqXl5FjdMvOWKMm/fKL/lrw=
go.step.sm/crypto v0.50.0/go.mod h1:NCFMhLS6FJXQ9sD9PP282oHtsBWLrI6wXZY0eOkq7t8=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
@@ -660,22 +690,31 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM=
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
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-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-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/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-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
@@ -684,11 +723,13 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/oauth2 v0.19.0 h1:9+E/EZBCbTLNrbN35fHv/a/d/mOBatymz1zbtQrXpIg=
golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8=
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs=
golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -696,6 +737,7 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -725,15 +767,15 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk=
golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@@ -741,44 +783,61 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/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=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw=
golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
google.golang.org/api v0.172.0 h1:/1OcMZGPmW1rX2LCu2CmGUD1KXK1+pfzxotxyRUCCdk=
google.golang.org/api v0.172.0/go.mod h1:+fJZq6QXWfa9pXhnIzsjx4yI22d4aI9ZpLb58gvXjis=
google.golang.org/genproto v0.0.0-20240311173647-c811ad7063a7 h1:ImUcDPHjTrAqNhlOkSocDLfG9rrNHH7w7uoKWPaWZ8s=
google.golang.org/genproto v0.0.0-20240311173647-c811ad7063a7/go.mod h1:/3XmxOjePkvmKrHuBy4zNFw7IzxJXtAgdpXi8Ll990U=
google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 h1:RFiFrvy37/mpSpdySBDrUdipW/dHwsRwh3J3+A9VgT4=
google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237/go.mod h1:Z5Iiy3jtmioajWHDGFk7CeugTyHtPvMHA4UTmUkyalE=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240515191416-fc5f0ca64291 h1:AgADTJarZTBqgjiUzRgfaBchgYB3/WFTC80GPwsMcRI=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240515191416-fc5f0ca64291/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0=
google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY=
google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg=
google.golang.org/api v0.189.0 h1:equMo30LypAkdkLMBqfeIqtyAnlyig1JSZArl4XPwdI=
google.golang.org/api v0.189.0/go.mod h1:FLWGJKb0hb+pU2j+rJqwbnsF+ym+fQs73rbJ+KAUgy8=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20240722135656-d784300faade h1:lKFsS7wpngDgSCeFn7MoLy+wBDQZ1UQIJD4UNM1Qvkg=
google.golang.org/genproto v0.0.0-20240722135656-d784300faade/go.mod h1:FfBgJBJg9GcpPvKIuHSZ/aE1g2ecGL74upMzGZjiGEY=
google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 h1:0+ozOGcrp+Y8Aq8TLNN2Aliibms5LEzsq99ZZmAGYm0=
google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094/go.mod h1:fJ/e3If/Q67Mj99hin0hMhiNyCRmt6BQ2aWIJshUSJw=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240722135656-d784300faade h1:oCRSWfwGXQsqlVdErcyTt4A93Y8fo0/9D4b1gnI++qo=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240722135656-d784300faade/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.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.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
@@ -791,14 +850,17 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkep
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.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
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=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools/v3 v3.5.0 h1:Ljk6PdHdOhAb5aDMWXjDLMMhph+BpztA4v1QdqEW2eY=
gotest.tools/v3 v3.5.0/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
k8s.io/api v0.28.3 h1:Gj1HtbSdB4P08C8rs9AR94MfSGpRhJgsS+GF9V26xMM=
k8s.io/api v0.28.3/go.mod h1:MRCV/jr1dW87/qJnZ57U5Pak65LGmQVkKTzf3AtKFHc=
k8s.io/apimachinery v0.28.3 h1:B1wYx8txOaCQG0HmYF6nbpU8dg6HvA06x5tEffvOe7A=
@@ -809,12 +871,12 @@ k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw=
k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780=
k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA=
k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI=
k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0 h1:jgGTlFYnhF1PM1Ax/lAlxUPE+KfCIXHaathvJg1C3ak=
k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
sigs.k8s.io/release-utils v0.7.7 h1:JKDOvhCk6zW8ipEOkpTGDH/mW3TI+XqtPp16aaQ79FU=
sigs.k8s.io/release-utils v0.7.7/go.mod h1:iU7DGVNi3umZJ8q6aHyUFzsDUIaYwNnNKGHo3YE5E3s=
sigs.k8s.io/release-utils v0.8.3 h1:KtOtA4qDmzJyeQ2zkDsFVI25+NViwms/o5eL2NftFdA=
sigs.k8s.io/release-utils v0.8.3/go.mod h1:fp82Fma06OXBhEJ+GUJKqvcplDBomruK1R/1fWJnsrQ=
sigs.k8s.io/structured-merge-diff/v4 v4.3.0 h1:UZbZAZfX0wV2zr7YZorDz6GXROfDFj6LvqCRm4VUVKk=
sigs.k8s.io/structured-merge-diff/v4 v4.3.0/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08=
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=

View File

@@ -1,42 +1,42 @@
{
"signatures": [
{
"keyid": "b7474a42f2588fa92ed4a2ebea6047a7b1b2f7351f1cfe0912732c0d0fb0fc09",
"sig": "3064023037bbb03c3472b140572a7d5a2895bd80e74435bbcb7053949731f81b104c6d05a0876590cd6a2e94d7ed619426a2f6fa02303adc8c9006fa5506fdd7ea87d2960074a537ad8bf2459f2863e806b47682cbb2f9b01b7502eaf5437a1a68fdaaeac114"
"keyid": "76d0a7e1ff8617ce99627d0fa5c9809f2c0f0d52e0bf65c7b84c031608d25221",
"sig": "3065023000f7d0a866576e94eaabc173b9233d4c8fcfa495527088f9022dff5a553f7a457da1015a6d0fc714f84848ec627387360231009fa70b2eebbe15241a2ec9b96a094ebd28661e30b8c3d1eab8d694df2b340bda511c489393630c9a9dacde42c99e9fa1"
}
],
"signed": {
"_type": "root",
"consistent_snapshot": true,
"expires": "2034-04-02T17:00:22Z",
"expires": "2034-05-29T20:14:11Z",
"keys": {
"198f00ff96ea7cbfa7eac480cc9bfc43ce13bb434b901011ab777856533997d3": {
"keytype": "ecdsa",
"keyval": {
"public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEgDpP6O0sEt2R+l84WlfmqPBsFSby\nxJsJ6YmeUVgDk/wk9++8IAR6YBYewaKye56gMnIYjTFbyOI8WomA2NQFBw==\n-----END PUBLIC KEY-----\n"
},
"scheme": "ecdsa-sha2-nistp256",
"x-tuf-on-ci-online-uri": "awskms:arn:aws:kms:us-east-1:175142243308:key/fbd8dab6-5677-4b57-87e6-8369c45b3b61"
},
"b7474a42f2588fa92ed4a2ebea6047a7b1b2f7351f1cfe0912732c0d0fb0fc09": {
"76d0a7e1ff8617ce99627d0fa5c9809f2c0f0d52e0bf65c7b84c031608d25221": {
"keytype": "ecdsa",
"keyval": {
"public": "-----BEGIN PUBLIC KEY-----\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE3+asmp2GD6UijwWvMezwVG/BwFLuQa3o\nT6eRxFvkILGpVDbZ92ZYWidHl9LZ/eJUjhIjuVEkNVKoenw5KjKl8veP3MthZrQA\nSkYytOIwkidZo9Rk2dczbDcFSJvLGsmd\n-----END PUBLIC KEY-----\n"
},
"scheme": "ecdsa-sha2-nistp384",
"x-tuf-on-ci-keyowner": "@mrjoelkamp"
},
"bdd1703ecbde8812614b112a6551d58de3ad681048fd90fca2a3e491edd8afe5": {
"keytype": "ecdsa",
"keyval": {
"public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEgDpP6O0sEt2R+l84WlfmqPBsFSby\nxJsJ6YmeUVgDk/wk9++8IAR6YBYewaKye56gMnIYjTFbyOI8WomA2NQFBw==\n-----END PUBLIC KEY-----\n"
},
"scheme": "ecdsa-sha2-nistp256",
"x-tuf-on-ci-online-uri": "awskms:arn:aws:kms:us-east-1:175142243308:key/fbd8dab6-5677-4b57-87e6-8369c45b3b61"
}
},
"roles": {
"root": {
"keyids": [
"b7474a42f2588fa92ed4a2ebea6047a7b1b2f7351f1cfe0912732c0d0fb0fc09"
"76d0a7e1ff8617ce99627d0fa5c9809f2c0f0d52e0bf65c7b84c031608d25221"
],
"threshold": 1
},
"snapshot": {
"keyids": [
"198f00ff96ea7cbfa7eac480cc9bfc43ce13bb434b901011ab777856533997d3"
"bdd1703ecbde8812614b112a6551d58de3ad681048fd90fca2a3e491edd8afe5"
],
"threshold": 1,
"x-tuf-on-ci-expiry-period": 3650,
@@ -44,13 +44,13 @@
},
"targets": {
"keyids": [
"b7474a42f2588fa92ed4a2ebea6047a7b1b2f7351f1cfe0912732c0d0fb0fc09"
"76d0a7e1ff8617ce99627d0fa5c9809f2c0f0d52e0bf65c7b84c031608d25221"
],
"threshold": 1
},
"timestamp": {
"keyids": [
"198f00ff96ea7cbfa7eac480cc9bfc43ce13bb434b901011ab777856533997d3"
"bdd1703ecbde8812614b112a6551d58de3ad681048fd90fca2a3e491edd8afe5"
],
"threshold": 1,
"x-tuf-on-ci-expiry-period": 3650,

View File

@@ -0,0 +1,152 @@
{
"signatures": [
{
"keyid": "08d6f4ca1d0be93a6ceddca15051c0aeec6b98c73e29f3a714de301042d6eeee",
"sig": "306502307ddba543fbd1b9e2ccbee604349024e62bbb1a37906bbd5605a7403fbdb51b701b52f5fcd1b0a0ebfaeef97fa9c344f8023100c37ab675fe96b3976469a5e0cc8a5ffb5d8d6de15020f493d7cf28b0c7e60f450b65c02bfbac0e40642863a1ae3bfa4a"
},
{
"keyid": "3ebd40525193d7628d0b9eccd4771df7297bc87519ec6f312863bb4470966bea",
"sig": "3065023100bc963925fb139dd65653b5e9640572876c5bcd0a3f8bb81e4b0cbd397c10ec4fa0aed7942d77ec78b865e14c72e20e76023043ce7ff39067f054d6d2eaca5dd5176b2c25e27bd763b4ef873aaf4c75762bfb085bb766613692b68206ea0df2863426"
},
{
"keyid": "9c8e1be7d8d0e30656adc81ac201e05cb47a5a097d4d301fd121b77c320231c4",
"sig": "306502307e82d7bc0c66074b06cfc13bac3761c8f677eef252c08448eb33c0249569500e8be2a1ae78c87b5888ed80d088f97fbb023100c358c6ebe18d237bae9a9daeaf2db82297cda8eca635fc22719142740fb23b32eac0341754dd2a85b684c46e3a087ada"
},
{
"keyid": "373d0a38247919a78cf400cf9a90abb9aa23a3c3dce1deee995fdd6a81507117",
"sig": "306402305d9b5fdf3b24240b266a7ae7e02bbcadce8e06f8c111dcef03282faa0baaffb8114653cecda3da115d7859f657508d4f02304b5939fc4404f9e1e8b9d3eb49e195a779b501bd4000cef6cff7a8e657020176dae99cce2a7300b88e549d427278309c"
},
{
"keyid": "48a873aa6c4189804228590af4d48ee5ad3b76417592efdbcef2532401925669",
"sig": "306402306bc5f44621c0d6e18ce16155ebc7890def8fb283859175f7a8425190f0f233e4270b2688df05b017cfc852dee30f9f5b023016572d059d6f27968976df2aaff8238ee0970cea229e5ef30350f2c91347b04e794683da69cf6afe6cf9206dcebc81f4"
}
],
"signed": {
"_type": "root",
"consistent_snapshot": true,
"expires": "2025-06-04T15:05:22Z",
"keys": {
"08d6f4ca1d0be93a6ceddca15051c0aeec6b98c73e29f3a714de301042d6eeee": {
"keytype": "ecdsa",
"keyval": {
"public": "-----BEGIN PUBLIC KEY-----\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEC4ggHc/D9koyS1/AMNsMGiydM2jDzdsI\nrkC/nyZf8d4UtYJJRxuFRfmyKw9Mh0Ulw/IIyf8ZW2NsnkHgJwGre9/Ici6uomOX\n8yAOlX0Du/oAa7v4igCG7tsW0Z1ljAID\n-----END PUBLIC KEY-----\n"
},
"scheme": "ecdsa-sha2-nistp384",
"x-tuf-on-ci-keyowner": "@jeanlaurent"
},
"2ff207ae7d7b595ef69589622067ef5b6668e1a43081377d942ed8749fa919b4": {
"keytype": "ecdsa",
"keyval": {
"public": "-----BEGIN PUBLIC KEY-----\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE5pyJ/RXlRO/a2WBSAprikm+VVPqZGC1M\nqgVXE3avwqb9d9lPc9Cphfd4CIAzPCKgeUkGMzQWcC1OwVjOwiB+GRq2Owf7T8pa\nKUe/zRoLjAlUnzUITHP226L1DmQ6Swos\n-----END PUBLIC KEY-----\n"
},
"scheme": "ecdsa-sha2-nistp384",
"x-tuf-on-ci-keyowner": "@kipz"
},
"373d0a38247919a78cf400cf9a90abb9aa23a3c3dce1deee995fdd6a81507117": {
"keytype": "ecdsa",
"keyval": {
"public": "-----BEGIN PUBLIC KEY-----\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER2zST05lNvybLsSe4UA/hiUrJbA6aFyz\nDimwewwbHvw+gt29EHYtHPqTlO/hSZD5vqZ94Cga9rDsOm3eI5bPkPHApUjw4W7u\n5lDnxuuFKluQ7EiUbswUN0ONTPnmY7Wo\n-----END PUBLIC KEY-----\n"
},
"scheme": "ecdsa-sha2-nistp384",
"x-tuf-on-ci-keyowner": "@binman-docker"
},
"3ebd40525193d7628d0b9eccd4771df7297bc87519ec6f312863bb4470966bea": {
"keytype": "ecdsa",
"keyval": {
"public": "-----BEGIN PUBLIC KEY-----\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE9C53JKQtD1RYLiSwmR4XRhI7jf28W9TK\nhV3aXW0Z87JyJ4wGNOFnGRE6PuEh7Bbu4ecH0PpsEoirWzzRIgBMR3yHVCSkFBDu\nqfycsInCTAS1jvzLiDHciKXENxAWARHj\n-----END PUBLIC KEY-----\n"
},
"scheme": "ecdsa-sha2-nistp384",
"x-tuf-on-ci-keyowner": "@ingshtrom"
},
"48a873aa6c4189804228590af4d48ee5ad3b76417592efdbcef2532401925669": {
"keytype": "ecdsa",
"keyval": {
"public": "-----BEGIN PUBLIC KEY-----\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEpQrE8o+fz6kBrs3TD6zqcDPwRZf3FxOX\n+SiT0k3SL1JHsMbxwFAKq+wJzqpqbhzFySuO1VVT93xNDd/rmjEU6HSY7wvT0m/l\nZ0S7yIwl3UnlplzKUYg/8wWJM0C2Qdpj\n-----END PUBLIC KEY-----\n"
},
"scheme": "ecdsa-sha2-nistp384",
"x-tuf-on-ci-keyowner": "@cdupuis"
},
"6132f1f2dd14bf3e9ba1a8df4c8435a77d2fd57f4a99bbb699ae61f85907818e": {
"keytype": "ecdsa",
"keyval": {
"public": "-----BEGIN PUBLIC KEY-----\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEkFPn3WTH/xVIEFhdP/TCqtnuiOqdgb/v\nEIBjng1TBCVmr7NnW4y4bdZG4Tf9OVTSqlJzuUFThJT/JQR3M7xEzW9WJqUfBTS1\nUuF980elHtMpRkS3NtRp/T0IrkH7+COa\n-----END PUBLIC KEY-----\n"
},
"scheme": "ecdsa-sha2-nistp384",
"x-tuf-on-ci-keyowner": "@jonnystoten"
},
"9c8e1be7d8d0e30656adc81ac201e05cb47a5a097d4d301fd121b77c320231c4": {
"keytype": "ecdsa",
"keyval": {
"public": "-----BEGIN PUBLIC KEY-----\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEWDreR+iXRtTStv5zmCLGoSmvvfV9/agY\nkx4O1XpRinBwAAA/IO4MI+YCoY0EQpKlSxl0DoVe6hmiXq2ezjTbebGDO66+fTZH\nkrr4KiCsZ8QcdPAR2cUvXkgyBp0WtYYS\n-----END PUBLIC KEY-----\n"
},
"scheme": "ecdsa-sha2-nistp384",
"x-tuf-on-ci-keyowner": "@rachel-taylor-docker"
},
"aef160e03958d5346c903dda755c07e952127ef523df5ec33bd9b24d41fe1cf4": {
"keytype": "ecdsa",
"keyval": {
"public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE5gH1kg/MZeiF/GO222hxMerv7MBC\nn91IJG8BbYWKmqZm2za+/QDyrMZExTguYlutu77jZqbkRZEFb/LbL4Ntuw==\n-----END PUBLIC KEY-----\n"
},
"scheme": "ecdsa-sha2-nistp256",
"x-tuf-on-ci-online-uri": "awskms:arn:aws:kms:us-east-1:654654578585:key/751429f1-0aea-4bd8-b450-bb1bce6b058f"
},
"cda750ab29ce33e19ad2fdee4204ad0190b0a33f79e1c5c18a38992d576143d7": {
"keytype": "ecdsa",
"keyval": {
"public": "-----BEGIN PUBLIC KEY-----\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEYTPARe9DPvvVVf7ch5fTVWXtS9FS97lh\nyZr3Pk33qRprnVB9u7BaEzvQtTYycPO7cmYW5yTOC5ZZa9p2B/v15bOK4NTU0WTT\nXTwSgKmJDh8CD/PBp386S8cwyyIp7NiR\n-----END PUBLIC KEY-----\n"
},
"scheme": "ecdsa-sha2-nistp384",
"x-tuf-on-ci-keyowner": "@whalelines"
},
"f2149d8b7c1ece56d87d81f27fa68b745efc841892b3acfa382ad7f611e612ec": {
"keytype": "ecdsa",
"keyval": {
"public": "-----BEGIN PUBLIC KEY-----\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEtWRLfl1pLhd5pn4gOmiCQwxE68U0+mIl\n1sU9ugeUz2aCZ9GcTjDNFE/7ZOat74ajeaFi9zmdeCi3UTYioLXNOXfbN6mxM9iQ\nGG3Z5OWYsZpeAv+5jhly2JeWUhFTuJpd\n-----END PUBLIC KEY-----\n"
},
"scheme": "ecdsa-sha2-nistp384",
"x-tuf-on-ci-keyowner": "@mrjoelkamp"
}
},
"roles": {
"root": {
"keyids": [
"08d6f4ca1d0be93a6ceddca15051c0aeec6b98c73e29f3a714de301042d6eeee",
"3ebd40525193d7628d0b9eccd4771df7297bc87519ec6f312863bb4470966bea",
"9c8e1be7d8d0e30656adc81ac201e05cb47a5a097d4d301fd121b77c320231c4",
"373d0a38247919a78cf400cf9a90abb9aa23a3c3dce1deee995fdd6a81507117",
"48a873aa6c4189804228590af4d48ee5ad3b76417592efdbcef2532401925669"
],
"threshold": 3
},
"snapshot": {
"keyids": [
"aef160e03958d5346c903dda755c07e952127ef523df5ec33bd9b24d41fe1cf4"
],
"threshold": 1,
"x-tuf-on-ci-expiry-period": 365,
"x-tuf-on-ci-signing-period": 60
},
"targets": {
"keyids": [
"f2149d8b7c1ece56d87d81f27fa68b745efc841892b3acfa382ad7f611e612ec",
"2ff207ae7d7b595ef69589622067ef5b6668e1a43081377d942ed8749fa919b4",
"6132f1f2dd14bf3e9ba1a8df4c8435a77d2fd57f4a99bbb699ae61f85907818e",
"cda750ab29ce33e19ad2fdee4204ad0190b0a33f79e1c5c18a38992d576143d7"
],
"threshold": 2
},
"timestamp": {
"keyids": [
"aef160e03958d5346c903dda755c07e952127ef523df5ec33bd9b24d41fe1cf4"
],
"threshold": 1,
"x-tuf-on-ci-expiry-period": 2,
"x-tuf-on-ci-signing-period": 1
}
},
"spec_version": "1.0.31",
"version": 1,
"x-tuf-on-ci-expiry-period": 365,
"x-tuf-on-ci-signing-period": 60
}
}

View File

@@ -2,12 +2,44 @@ package embed
import (
_ "embed"
"fmt"
)
//go:embed embedded-roots/1.root-dev.json
var DevRoot []byte
var devRoot []byte
//go:embed embedded-roots/1.root-staging.json
var StagingRoot []byte
var stagingRoot []byte
var DefaultRoot = StagingRoot
//go:embed embedded-roots/1.root.json
var prodRoot []byte
var defaultRoot = prodRoot
type RootName string
type EmbeddedRoot struct {
Data []byte
Name RootName
}
var (
RootDev = EmbeddedRoot{Data: devRoot, Name: "dev"}
RootStaging = EmbeddedRoot{Data: stagingRoot, Name: "staging"}
RootProd = EmbeddedRoot{Data: prodRoot, Name: "prod"}
RootDefault = EmbeddedRoot{Data: defaultRoot, Name: ""}
)
func GetRootFromName(root string) (*EmbeddedRoot, error) {
switch root {
case string(RootDev.Name):
return &RootDev, nil
case string(RootStaging.Name):
return &RootStaging, nil
case string(RootProd.Name):
return &RootProd, nil
case string(RootDefault.Name):
return &RootDefault, nil
default:
return nil, fmt.Errorf("invalid tuf root: %s", root)
}
}

64
internal/test/mocks.go Normal file
View File

@@ -0,0 +1,64 @@
package test
import (
"context"
"os"
"path/filepath"
"github.com/docker/attest/pkg/attestation"
"github.com/docker/attest/pkg/oci"
"github.com/docker/attest/pkg/signerverifier"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/secure-systems-lab/go-securesystemslib/dsse"
)
type MockResolver struct {
Envs []*attestation.Envelope
}
func (r MockResolver) Attestations(ctx context.Context, mediaType string) ([]*attestation.Envelope, error) {
return r.Envs, nil
}
func (r MockResolver) ImageName(ctx context.Context) (string, error) {
return "library/alpine:latest", nil
}
func (r MockResolver) ImageDescriptor(ctx context.Context) (*v1.Descriptor, error) {
digest, err := v1.NewHash("sha256:da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620")
if err != nil {
return nil, err
}
return &v1.Descriptor{
Digest: digest,
Size: 1234,
MediaType: "application/vnd.oci.image.manifest.v1+json",
}, nil
}
func (r MockResolver) ImagePlatform(ctx context.Context) (*v1.Platform, error) {
return oci.ParsePlatform("linux/amd64")
}
type MockRegistryResolver struct {
Subject *v1.Descriptor
ImageNameStr string
*MockResolver
}
func (r *MockRegistryResolver) ImageDescriptor(ctx context.Context) (*v1.Descriptor, error) {
return r.Subject, nil
}
func (r *MockRegistryResolver) ImageName(ctx context.Context) (string, error) {
return r.ImageNameStr, nil
}
func GetMockSigner(ctx context.Context) (dsse.SignerVerifier, error) {
priv, err := os.ReadFile(filepath.Join("..", "..", "test", "testdata", "test-signing-key.pem"))
if err != nil {
return nil, err
}
return signerverifier.LoadKeyPair(priv)
}

View File

@@ -6,7 +6,6 @@ import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"strings"
"testing"
@@ -82,14 +81,6 @@ func Setup(t *testing.T) (context.Context, dsse.SignerVerifier) {
return ctx, signer
}
func GetMockSigner(ctx context.Context) (dsse.SignerVerifier, error) {
priv, err := os.ReadFile(filepath.Join("..", "..", "test", "testdata", "test-signing-key.pem"))
if err != nil {
return nil, err
}
return signerverifier.LoadKeyPair(priv)
}
type AnnotatedStatement struct {
OCIDescriptor *v1.Descriptor
InTotoStatement *intoto.Statement

View File

@@ -13,7 +13,7 @@ import (
"github.com/google/go-containerregistry/pkg/v1/mutate"
)
func ExampleSign_remote() {
func ExampleSignStatements_remote() {
// configure signerverifier
// local signer (unsafe for production)
signer, err := signerverifier.GenKeyPair()
@@ -27,27 +27,35 @@ func ExampleSign_remote() {
// configure signing options
opts := &attestation.SigningOptions{
Replace: true, // replace unsigned intoto statements with signed intoto attestations, otherwise leave in place
SkipTL: true, // skip trust logging to a transparency log
}
// load image index with unsigned attestation-manifests
ref := "docker/image-signer-verifier:latest"
att, err := oci.SubjectIndexFromRemote(ref)
attIdx, err := oci.IndexFromRemote(ref)
if err != nil {
panic(err)
}
// example for local image index
// path := "/myimage"
// att, err := oci.AttestationIndexFromLocal(path)
// attIdx, err = oci.IndexFromPath(path)
// if err != nil {
// panic(err)
// }
// sign attestations
signedImageIndex, err := attest.Sign(context.Background(), att.Index, signer, opts)
// sign all attestations in an image index
signedManifests, err := attest.SignStatements(context.Background(), attIdx.Index, signer, opts)
if err != nil {
panic(err)
}
signedIndex := attIdx.Index
signedIndex, err = attestation.UpdateIndexImages(signedIndex, signedManifests)
if err != nil {
panic(err)
}
// push image index with signed attestation-manifests
err = mirror.PushIndexToRegistry(signedImageIndex, ref)
err = mirror.PushIndexToRegistry(signedIndex, ref)
if err != nil {
panic(err)
}
@@ -55,10 +63,10 @@ func ExampleSign_remote() {
path := "/myimage"
idx := v1.ImageIndex(empty.Index)
idx = mutate.AppendManifests(idx, mutate.IndexAddendum{
Add: signedImageIndex,
Add: signedIndex,
Descriptor: v1.Descriptor{
Annotations: map[string]string{
oci.OciReferenceTarget: att.Name,
oci.OciReferenceTarget: attIdx.Name,
},
},
})

View File

@@ -21,7 +21,7 @@ func createTufClient(outputPath string) (*tuf.TufClient, error) {
// metadataURI := "https://docker.github.io/tuf-staging/metadata"
// targetsURI := "https://docker.github.io/tuf-staging/targets"
return tuf.NewTufClient(embed.StagingRoot, outputPath, metadataURI, targetsURI, tuf.NewMockVersionChecker())
return tuf.NewTufClient(embed.RootStaging.Data, outputPath, metadataURI, targetsURI, tuf.NewMockVersionChecker())
}
func ExampleVerify_remote() {

View File

@@ -2,246 +2,28 @@ package attest
import (
"context"
"encoding/json"
"fmt"
"github.com/docker/attest/pkg/attestation"
"github.com/docker/attest/pkg/oci"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/empty"
"github.com/google/go-containerregistry/pkg/v1/match"
"github.com/google/go-containerregistry/pkg/v1/mutate"
"github.com/google/go-containerregistry/pkg/v1/partial"
"github.com/google/go-containerregistry/pkg/v1/static"
"github.com/google/go-containerregistry/pkg/v1/types"
intoto "github.com/in-toto/in-toto-golang/in_toto"
"github.com/secure-systems-lab/go-securesystemslib/dsse"
)
func Sign(ctx context.Context, idx v1.ImageIndex, signer dsse.SignerVerifier, opts *attestation.SigningOptions) (v1.ImageIndex, error) {
images, err := SignedAttestationImages(ctx, idx, signer, opts)
if err != nil {
return nil, fmt.Errorf("failed to sign attestation images: %w", err)
}
for _, image := range images {
idx, err = addImageToIndex(idx, image.Image, image.Descriptor, image.AttestationManifest)
if err != nil {
return nil, fmt.Errorf("failed to add signed layers to index: %w", err)
}
}
return idx, nil
}
func SignedAttestationImages(ctx context.Context, idx v1.ImageIndex, signer dsse.SignerVerifier, opts *attestation.SigningOptions) ([]*attestation.SignedAttestationImage, error) {
// this is only relevant if there are (unsigned) in-toto statements
func SignStatements(ctx context.Context, idx v1.ImageIndex, signer dsse.SignerVerifier, opts *attestation.SigningOptions) ([]*attestation.AttestationManifest, error) {
// extract attestation manifests from index
attestationManifests, err := attestation.GetAttestationManifestsFromIndex(idx)
if err != nil {
return nil, fmt.Errorf("failed to get attestation manifests: %w", err)
return nil, fmt.Errorf("failed to load attestation manifests from index: %w", err)
}
if len(attestationManifests) == 0 {
return nil, fmt.Errorf("no attestation manifests found")
}
images := []*attestation.SignedAttestationImage{}
// sign every attestation layer in each manifest
for _, manifest := range attestationManifests {
newImg, newDescriptor, err := SignLayersAndAddToImage(ctx, manifest.Attestation.Layers, manifest, signer, opts)
if err != nil {
return nil, fmt.Errorf("failed to add signed layers to image: %w", err)
}
images = append(images, &attestation.SignedAttestationImage{
Image: newImg,
Descriptor: newDescriptor,
AttestationManifest: manifest,
})
}
return images, nil
}
func AddAttestation(ctx context.Context, idx v1.ImageIndex, statement *intoto.Statement, signer dsse.SignerVerifier) (v1.ImageIndex, error) {
if len(statement.Subject) == 0 {
return nil, fmt.Errorf("statement has no subjects")
}
subjectDigests := make(map[string]bool)
for _, subject := range statement.Subject {
subjectDigest := fmt.Sprintf("sha256:%s", subject.Digest["sha256"])
subjectDigests[subjectDigest] = true
}
attestationManifests, err := attestation.GetAttestationManifestsFromIndex(idx)
if err != nil {
return nil, fmt.Errorf("failed to get attestation manifests: %w", err)
}
updatedIndex := false
for _, manifest := range attestationManifests {
if subjectDigests[manifest.Annotations[attestation.DockerReferenceDigest]] {
attestationLayers := []attestation.AttestationLayer{
{
Statement: statement,
MediaType: types.MediaType(intoto.PayloadType),
Annotations: map[string]string{
oci.InTotoPredicateType: statement.PredicateType,
},
},
}
// hard-coding replace to false here, because if it's true we will remove any unsigned statements, even unrelated ones
newImg, newDec, err := SignLayersAndAddToImage(ctx, attestationLayers, manifest, signer, &attestation.SigningOptions{Replace: false})
for _, layer := range manifest.OriginalLayers {
err = manifest.AddAttestation(ctx, signer, layer.Statement, opts)
if err != nil {
return nil, fmt.Errorf("failed to add signed layers to image: %w", err)
}
idx, err = addImageToIndex(idx, newImg, newDec, manifest)
if err != nil {
return nil, fmt.Errorf("failed to add attestation image to index: %w", err)
}
updatedIndex = true
}
}
if !updatedIndex {
return nil, fmt.Errorf("no attestation manifest found for statement")
}
return idx, nil
}
func SignLayersAndAddToImage(
ctx context.Context,
attestationLayers []attestation.AttestationLayer,
manifest attestation.AttestationManifest,
signer dsse.SignerVerifier,
opts *attestation.SigningOptions) (v1.Image, *v1.Descriptor, error) {
signedLayers, err := signLayers(ctx, attestationLayers, signer, opts)
if err != nil {
return nil, nil, fmt.Errorf("failed to sign attestations: %w", err)
}
newImg, err := addSignedLayers(signedLayers, manifest, opts)
if err != nil {
return nil, nil, fmt.Errorf("failed to add signed layers: %w", err)
}
if !opts.SkipSubject {
newImg = mutate.Subject(newImg, *manifest.SubjectDescriptor).(v1.Image)
}
newDesc, err := partial.Descriptor(newImg)
if err != nil {
return nil, nil, fmt.Errorf("failed to get descriptor: %w", err)
}
cf, err := manifest.Attestation.Image.ConfigFile()
if err != nil {
return nil, nil, fmt.Errorf("failed to get config file: %w", err)
}
newDesc.Platform = cf.Platform()
if newDesc.Platform == nil {
newDesc.Platform = &v1.Platform{
Architecture: "unknown",
OS: "unknown",
}
}
newDesc.MediaType = manifest.MediaType
newDesc.Annotations = manifest.Annotations
return newImg, newDesc, nil
}
func addImageToIndex(
idx v1.ImageIndex,
img v1.Image,
desc *v1.Descriptor,
manifest attestation.AttestationManifest,
) (v1.ImageIndex, error) {
idx = mutate.RemoveManifests(idx, match.Digests(manifest.Digest))
idx = mutate.AppendManifests(idx, mutate.IndexAddendum{
Add: img,
Descriptor: *desc,
})
return idx, nil
}
// signLayers signs each intoto attestation layer with the given signer
func signLayers(ctx context.Context, layers []attestation.AttestationLayer, signer dsse.SignerVerifier, opts *attestation.SigningOptions) ([]mutate.Addendum, error) {
var signedLayers []mutate.Addendum
for _, layer := range layers {
// only sign intoto layers
if layer.MediaType != types.MediaType(intoto.PayloadType) {
continue
}
// mark attestation as experimental
layer.Annotations[InTotoReferenceLifecycleStage] = LifecycleStageExperimental
// sign the statement
env, err := signInTotoStatement(ctx, layer.Statement, signer, opts)
if err != nil {
return nil, fmt.Errorf("failed to sign statement: %w", err)
}
mediaType, err := attestation.DSSEMediaType(layer.Statement.PredicateType)
if err != nil {
return nil, fmt.Errorf("failed to get DSSE media type: %w", err)
}
data, err := json.Marshal(env)
if err != nil {
return nil, fmt.Errorf("failed to marshal envelope: %w", err)
}
newLayer := static.NewLayer(data, types.MediaType(mediaType))
withAnnotations := mutate.Addendum{
Layer: newLayer,
Annotations: layer.Annotations,
}
signedLayers = append(signedLayers, withAnnotations)
}
return signedLayers, nil
}
func signInTotoStatement(ctx context.Context, statement *intoto.Statement, signer dsse.SignerVerifier, opts *attestation.SigningOptions) (*attestation.Envelope, error) {
payload, err := json.Marshal(statement)
if err != nil {
return nil, fmt.Errorf("failed to marshal statement: %w", err)
}
env, err := attestation.SignDSSE(ctx, payload, signer, opts)
if err != nil {
return nil, fmt.Errorf("failed to sign statement: %w", err)
}
return env, nil
}
// addSignedLayers adds signed layers to a new or existing attestation image
func addSignedLayers(signedLayers []mutate.Addendum, manifest attestation.AttestationManifest, opts *attestation.SigningOptions) (v1.Image, error) {
withAnnotations := func(img v1.Image) v1.Image {
// this is handy when dealing with referrers
return mutate.Annotations(img, map[string]string{
attestation.DockerReferenceType: attestation.AttestationManifestType,
attestation.DockerReferenceDigest: manifest.SubjectDescriptor.Digest.String(),
}).(v1.Image)
}
var err error
if opts.Replace {
// create a new attestation image with only signed layers
newImg := empty.Image
newImg = mutate.MediaType(newImg, manifest.MediaType)
newImg = mutate.ConfigMediaType(newImg, "application/vnd.oci.image.config.v1+json")
for _, layer := range signedLayers {
newImg, err = mutate.Append(newImg, layer)
if err != nil {
return nil, fmt.Errorf("failed to append signed layer: %w", err)
return nil, fmt.Errorf("failed to sign attestation layer %w", err)
}
}
// add any existing unsigned (non-intoto) layers to the new image
for _, layer := range manifest.Attestation.Layers {
if layer.MediaType != types.MediaType(intoto.PayloadType) {
newImg, err = mutate.AppendLayers(newImg, layer.Layer)
if err != nil {
return nil, fmt.Errorf("failed to append unsigned layer: %w", err)
}
}
}
return withAnnotations(newImg), nil
}
// Add signed layers to the existing image
for _, layer := range signedLayers {
manifest.Attestation.Image, err = mutate.Append(manifest.Attestation.Image, layer)
if err != nil {
return nil, fmt.Errorf("failed to append layer: %w", err)
}
}
return withAnnotations(manifest.Attestation.Image), nil
return attestationManifests, nil
}

View File

@@ -3,13 +3,17 @@ package attest
import (
"encoding/json"
"fmt"
"net/http/httptest"
"net/url"
"path/filepath"
"testing"
"github.com/docker/attest/internal/test"
"github.com/docker/attest/pkg/attestation"
"github.com/docker/attest/pkg/mirror"
"github.com/docker/attest/pkg/oci"
"github.com/docker/attest/pkg/policy"
"github.com/google/go-containerregistry/pkg/registry"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/empty"
"github.com/google/go-containerregistry/pkg/v1/layout"
@@ -23,12 +27,13 @@ import (
)
var (
UnsignedTestImage = filepath.Join("..", "..", "test", "testdata", "unsigned-test-image")
NoProvenanceImage = filepath.Join("..", "..", "test", "testdata", "no-provenance-image")
PassPolicyDir = filepath.Join("..", "..", "test", "testdata", "local-policy-pass")
PassNoTLPolicyDir = filepath.Join("..", "..", "test", "testdata", "local-policy-no-tl")
FailPolicyDir = filepath.Join("..", "..", "test", "testdata", "local-policy-fail")
TestTempDir = "attest-sign-test"
UnsignedTestImage = filepath.Join("..", "..", "test", "testdata", "unsigned-test-image")
NoProvenanceImage = filepath.Join("..", "..", "test", "testdata", "no-provenance-image")
PassPolicyDir = filepath.Join("..", "..", "test", "testdata", "local-policy-pass")
PassMirrorPolicyDir = filepath.Join("..", "..", "test", "testdata", "local-policy-mirror")
PassNoTLPolicyDir = filepath.Join("..", "..", "test", "testdata", "local-policy-no-tl")
FailPolicyDir = filepath.Join("..", "..", "test", "testdata", "local-policy-fail")
TestTempDir = "attest-sign-test"
)
func TestSignVerifyOCILayout(t *testing.T) {
@@ -41,7 +46,6 @@ func TestSignVerifyOCILayout(t *testing.T) {
expectedAttestations int
replace bool
}{
{"signed replaced", UnsignedTestImage, 0, 4, true},
{"without replace", UnsignedTestImage, 4, 4, false},
// image without provenance doesn't fail
@@ -54,14 +58,14 @@ func TestSignVerifyOCILayout(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
outputLayout := test.CreateTempDir(t, "", TestTempDir)
opts := &attestation.SigningOptions{
Replace: tc.replace,
}
attIdx, err := oci.SubjectIndexFromPath(tc.TestImage)
opts := &attestation.SigningOptions{}
attIdx, err := oci.IndexFromPath(tc.TestImage)
require.NoError(t, err)
signedIndex, err := Sign(ctx, attIdx.Index, signer, opts)
signedManifests, err := SignStatements(ctx, attIdx.Index, signer, opts)
require.NoError(t, err)
signedIndex := attIdx.Index
signedIndex, err = attestation.UpdateIndexImages(signedIndex, signedManifests, attestation.WithReplacedLayers(tc.replace))
require.NoError(t, err)
// output signed attestations
idx := v1.ImageIndex(empty.Index)
idx = mutate.AppendManifests(idx, mutate.IndexAddendum{
@@ -88,8 +92,8 @@ func TestSignVerifyOCILayout(t *testing.T) {
allEnvelopes = append(allEnvelopes, statements...)
for _, stmt := range statements {
assert.Equalf(t, predicate, stmt.Annotations[oci.InTotoPredicateType], "expected predicate-type annotation to be set to %s, got %s", predicate, stmt.Annotations[oci.InTotoPredicateType])
assert.Equalf(t, LifecycleStageExperimental, stmt.Annotations[InTotoReferenceLifecycleStage], "expected reference lifecycle stage annotation to be set to %s, got %s", LifecycleStageExperimental, stmt.Annotations[InTotoReferenceLifecycleStage])
assert.Equalf(t, predicate, stmt.Annotations[attestation.InTotoPredicateType], "expected predicate-type annotation to be set to %s, got %s", predicate, stmt.Annotations[attestation.InTotoPredicateType])
assert.Equalf(t, attestation.LifecycleStageExperimental, stmt.Annotations[attestation.InTotoReferenceLifecycleStage], "expected reference lifecycle stage annotation to be set to %s, got %s", attestation.LifecycleStageExperimental, stmt.Annotations[attestation.InTotoReferenceLifecycleStage])
}
}
assert.Equalf(t, tc.expectedAttestations, len(allEnvelopes), "expected %d attestations, got %d", tc.expectedAttestations, len(allEnvelopes))
@@ -100,71 +104,8 @@ func TestSignVerifyOCILayout(t *testing.T) {
}
}
func TestAddAttestation(t *testing.T) {
ctx, signer := test.Setup(t)
expectedAttestations := 2
expectedStatements := 4
outputLayout := test.CreateTempDir(t, "", TestTempDir)
attIdx, err := oci.SubjectIndexFromPath(UnsignedTestImage)
require.NoError(t, err)
statementToAdd := &intoto.Statement{
StatementHeader: intoto.StatementHeader{
PredicateType: attestation.VSAPredicateType,
Type: intoto.StatementInTotoV01,
Subject: []intoto.Subject{
{
Name: attIdx.Name,
Digest: map[string]string{
"sha256": "da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620",
},
},
{
Name: attIdx.Name,
Digest: map[string]string{
"sha256": "7a76cec943853f9f7105b1976afa1bf7cd5bb6afc4e9d5852dd8da7cf81ae86e",
},
},
},
},
}
signedIndex, err := AddAttestation(ctx, attIdx.Index, statementToAdd, signer)
require.NoError(t, err)
// output signed attestations
idx := v1.ImageIndex(empty.Index)
idx = mutate.AppendManifests(idx, mutate.IndexAddendum{
Add: signedIndex,
Descriptor: v1.Descriptor{
Annotations: map[string]string{
oci.OciReferenceTarget: attIdx.Name,
},
},
})
_, err = layout.Write(outputLayout, idx)
require.NoError(t, err)
var allEnvelopes []*test.AnnotatedStatement
mt, _ := attestation.DSSEMediaType(attestation.VSAPredicateType)
statements, err := test.ExtractAnnotatedStatements(outputLayout, mt)
require.NoError(t, err)
allEnvelopes = append(allEnvelopes, statements...)
for _, stmt := range statements {
assert.Equalf(t, attestation.VSAPredicateType, stmt.Annotations[oci.InTotoPredicateType], "expected predicate-type annotation to be set to %s, got %s", attestation.VSAPredicateType, stmt.Annotations[oci.InTotoPredicateType])
assert.Equalf(t, LifecycleStageExperimental, stmt.Annotations[InTotoReferenceLifecycleStage], "expected reference lifecycle stage annotation to be set to %s, got %s", LifecycleStageExperimental, stmt.Annotations[InTotoReferenceLifecycleStage])
}
assert.Equalf(t, expectedAttestations, len(allEnvelopes), "expected %d attestations, got %d", expectedAttestations, len(allEnvelopes))
statements, err = test.ExtractAnnotatedStatements(outputLayout, intoto.PayloadType)
fmt.Printf("statements: %+v\n", statements)
require.NoError(t, err)
assert.Equalf(t, expectedStatements, len(statements), "expected %d statement, got %d", expectedStatements, len(statements))
}
func TestAddSignedLayerAnnotations(t *testing.T) {
ctx, signer := test.Setup(t)
testCases := []struct {
name string
replace bool
@@ -176,33 +117,32 @@ func TestAddSignedLayerAnnotations(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
data := []byte("signed")
signedLayer := static.NewLayer(data, types.MediaType(intoto.PayloadType))
signedLayers := []mutate.Addendum{
{
Layer: signedLayer,
Annotations: map[string]string{"test": "test"},
},
}
data = []byte("test")
testLayer := static.NewLayer(data, types.MediaType(intoto.PayloadType))
mediaType := types.OCIManifestSchema1
opts := &attestation.SigningOptions{
Replace: tc.replace,
}
manifest := attestation.AttestationManifest{
MediaType: mediaType,
Attestation: attestation.AttestationImage{
Image: empty.Image,
Layers: []attestation.AttestationLayer{
{
Layer: testLayer,
Statement: &intoto.Statement{},
},
opts := &attestation.SigningOptions{}
originalLayer := &attestation.AttestationLayer{
Layer: testLayer,
Statement: &intoto.Statement{
StatementHeader: intoto.StatementHeader{
PredicateType: attestation.VSAPredicateType,
},
},
Annotations: map[string]string{"test": "test"},
}
manifest := &attestation.AttestationManifest{
OriginalDescriptor: &v1.Descriptor{
MediaType: mediaType,
},
OriginalLayers: []*attestation.AttestationLayer{
originalLayer,
},
SubjectDescriptor: &v1.Descriptor{},
}
newImg, err := addSignedLayers(signedLayers, manifest, opts)
err := manifest.AddAttestation(ctx, signer, originalLayer.Statement, opts)
require.NoError(t, err)
newImg, err := manifest.BuildAttestationImage(attestation.WithReplacedLayers(tc.replace))
require.NoError(t, err)
mf, _ := newImg.RawManifest()
type Annotations struct {
@@ -219,3 +159,88 @@ func TestAddSignedLayerAnnotations(t *testing.T) {
})
}
}
func TestSimpleStatementSigning(t *testing.T) {
ctx, signer := test.Setup(t)
empty := types.MediaType("application/vnd.oci.empty.v1+json")
testCases := []struct {
name string
replace bool
}{
{"replaced", true},
{"not replaced", false},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
opts := &attestation.SigningOptions{}
statement := &intoto.Statement{
StatementHeader: intoto.StatementHeader{
PredicateType: attestation.VSAPredicateType,
},
}
statement2 := &intoto.Statement{
StatementHeader: intoto.StatementHeader{
PredicateType: attestation.VSAPredicateType,
},
}
digest, err := v1.NewHash("sha256:da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620")
require.NoError(t, err)
subject := &v1.Descriptor{
MediaType: "application/vnd.oci.image.manifest.v1+json",
Digest: digest,
}
manifest, err := NewAttestationManifest(subject)
require.NoError(t, err)
err = manifest.AddAttestation(ctx, signer, statement, opts)
require.NoError(t, err)
err = manifest.AddAttestation(ctx, signer, statement2, opts)
require.NoError(t, err)
// fake that the manfifest was loaded from a real image
manifest.OriginalLayers = manifest.SignedLayers
envelopes, err := oci.ExtractEnvelopes(manifest, attestation.VSAPredicateType)
require.NoError(t, err)
assert.Len(t, envelopes, 2)
newImg, err := manifest.BuildAttestationImage(attestation.WithReplacedLayers(tc.replace))
require.NoError(t, err)
layers, err := newImg.Layers()
require.NoError(t, err)
if tc.replace {
assert.Len(t, layers, 2)
} else {
assert.Len(t, layers, 4)
}
newImgs, err := manifest.BuildReferringArtifacts()
require.NoError(t, err)
assert.Len(t, newImgs, 2)
for _, img := range newImgs {
mf, err := img.Manifest()
require.NoError(t, err)
assert.Contains(t, mf.ArtifactType, "application/vnd.in-toto")
assert.Contains(t, mf.ArtifactType, "+dsse")
assert.Equal(t, subject.MediaType, mf.MediaType)
assert.Equal(t, empty, mf.Config.MediaType)
assert.Equal(t, int64(2), mf.Config.Size)
assert.Equal(t, "{}", string(mf.Config.Data))
layers, err := img.Layers()
require.NoError(t, err)
assert.Len(t, layers, 1)
}
server := httptest.NewServer(registry.New(registry.WithReferrersSupport(true)))
defer server.Close()
u, err := url.Parse(server.URL)
require.NoError(t, err)
indexName := fmt.Sprintf("%s/repo:root", u.Host)
output, err := oci.ParseImageSpecs(indexName)
require.NoError(t, err)
err = mirror.SaveReferrers(manifest, output)
require.NoError(t, err)
})
}
}

View File

@@ -4,14 +4,10 @@ import (
"fmt"
"github.com/docker/attest/pkg/policy"
v1 "github.com/google/go-containerregistry/pkg/v1"
intoto "github.com/in-toto/in-toto-golang/in_toto"
)
const (
InTotoReferenceLifecycleStage = "vnd.docker.lifecycle-stage"
LifecycleStageExperimental = "experimental"
)
type Outcome string
const (
@@ -32,9 +28,10 @@ func (o Outcome) StringForVSA() (string, error) {
}
type VerificationResult struct {
Outcome Outcome
Policy *policy.Policy
Input *policy.PolicyInput
VSA *intoto.Statement
Violations []policy.Violation
Outcome Outcome
Policy *policy.Policy
Input *policy.PolicyInput
VSA *intoto.Statement
Violations []policy.Violation
SubjectDescriptor *v1.Descriptor
}

View File

@@ -3,12 +3,15 @@ package attest
import (
"context"
"fmt"
"strings"
"time"
"github.com/distribution/reference"
"github.com/docker/attest/pkg/attestation"
"github.com/docker/attest/pkg/config"
"github.com/docker/attest/pkg/oci"
"github.com/docker/attest/pkg/policy"
v1 "github.com/google/go-containerregistry/pkg/v1"
intoto "github.com/in-toto/in-toto-golang/in_toto"
)
@@ -36,12 +39,12 @@ func Verify(ctx context.Context, src *oci.ImageSpec, opts *policy.PolicyOptions)
}
// this is overriding the mapping with a referrers config. Useful for testing if nothing else
if opts.ReferrersRepo != "" {
pctx.Mapping.Attestations = &config.ReferrersConfig{
pctx.Mapping.Attestations = &config.AttestationConfig{
Repo: opts.ReferrersRepo,
Style: config.AttestationStyleReferrers,
}
} else if opts.AttestationStyle == config.AttestationStyleAttached {
pctx.Mapping.Attestations = &config.ReferrersConfig{
pctx.Mapping.Attestations = &config.AttestationConfig{
Repo: opts.ReferrersRepo,
Style: config.AttestationStyleAttached,
}
@@ -58,7 +61,7 @@ func Verify(ctx context.Context, src *oci.ImageSpec, opts *policy.PolicyOptions)
return result, nil
}
func ToPolicyResult(p *policy.Policy, input *policy.PolicyInput, result *policy.Result) (*VerificationResult, error) {
func toVerificationResult(p *policy.Policy, input *policy.PolicyInput, result *policy.Result) (*VerificationResult, error) {
dgst, err := oci.SplitDigest(input.Digest)
if err != nil {
return nil, fmt.Errorf("failed to split digest: %w", err)
@@ -110,10 +113,11 @@ func ToPolicyResult(p *policy.Policy, input *policy.PolicyInput, result *policy.
}
func VerifyAttestations(ctx context.Context, resolver oci.AttestationResolver, pctx *policy.Policy) (*VerificationResult, error) {
digest, err := resolver.ImageDigest(ctx)
desc, err := resolver.ImageDescriptor(ctx)
if err != nil {
return nil, fmt.Errorf("failed to get image digest: %w", err)
return nil, fmt.Errorf("failed to get image descriptor: %w", err)
}
digest := desc.Digest.String()
name, err := resolver.ImageName(ctx)
if err != nil {
return nil, fmt.Errorf("failed to get image name: %w", err)
@@ -122,6 +126,19 @@ func VerifyAttestations(ctx context.Context, resolver oci.AttestationResolver, p
if err != nil {
return nil, err
}
if pctx.ResolvedName != "" {
// this means the name we have is not the one we want to use for policy evaluation
// so we need to replace it with the one we resolved during policy resolution.
// this can happen if the name is an alias for another image, e.g. if it is a mirror
ref, err := reference.ParseNormalizedNamed(name)
if err != nil {
return nil, fmt.Errorf("failed to parse image name: %w", err)
}
oldName := ref.Name()
name = strings.Replace(name, oldName, pctx.ResolvedName, 1)
}
purl, canonical, err := oci.RefToPURL(name, platform)
if err != nil {
return nil, fmt.Errorf("failed to convert ref to purl: %w", err)
@@ -140,5 +157,20 @@ func VerifyAttestations(ctx context.Context, resolver oci.AttestationResolver, p
if err != nil {
return nil, fmt.Errorf("policy evaluation failed: %w", err)
}
return ToPolicyResult(pctx, input, result)
verificationResult, err := toVerificationResult(pctx, input, result)
if err != nil {
return nil, fmt.Errorf("failed to convert to policy result: %w", err)
}
verificationResult.SubjectDescriptor = desc
return verificationResult, nil
}
func NewAttestationManifest(subject *v1.Descriptor) (*attestation.AttestationManifest, error) {
return &attestation.AttestationManifest{
OriginalDescriptor: &v1.Descriptor{
MediaType: "application/vnd.oci.image.manifest.v1+json",
},
OriginalLayers: []*attestation.AttestationLayer{},
SubjectDescriptor: subject,
}, nil
}

View File

@@ -36,7 +36,7 @@ func TestVerifyAttestations(t *testing.T) {
var env = new(attestation.Envelope)
err = json.Unmarshal(ex, env)
assert.NoError(t, err)
resolver := &oci.MockResolver{
resolver := &test.MockResolver{
Envs: []*attestation.Envelope{env},
}
@@ -59,7 +59,7 @@ func TestVerifyAttestations(t *testing.T) {
}
ctx := policy.WithPolicyEvaluator(context.Background(), &mockPE)
_, err := VerifyAttestations(ctx, resolver, nil)
_, err := VerifyAttestations(ctx, resolver, &policy.Policy{ResolvedName: ""})
if tc.expectedError != nil {
if assert.Error(t, err) {
assert.Equal(t, tc.expectedError.Error(), err.Error())
@@ -77,13 +77,14 @@ func TestVSA(t *testing.T) {
// setup an image with signed attestations
outputLayout := test.CreateTempDir(t, "", TestTempDir)
opts := &attestation.SigningOptions{
Replace: true,
}
attIdx, err := oci.SubjectIndexFromPath(UnsignedTestImage)
assert.NoError(t, err)
signedIndex, err := Sign(ctx, attIdx.Index, signer, opts)
opts := &attestation.SigningOptions{}
attIdx, err := oci.IndexFromPath(UnsignedTestImage)
assert.NoError(t, err)
signedManifests, err := SignStatements(ctx, attIdx.Index, signer, opts)
require.NoError(t, err)
signedIndex := attIdx.Index
signedIndex, err = attestation.UpdateIndexImages(signedIndex, signedManifests)
require.NoError(t, err)
// output signed attestations
idx := v1.ImageIndex(empty.Index)
@@ -133,13 +134,14 @@ func TestVerificationFailure(t *testing.T) {
// setup an image with signed attestations
outputLayout := test.CreateTempDir(t, "", TestTempDir)
opts := &attestation.SigningOptions{
Replace: true,
}
attIdx, err := oci.SubjectIndexFromPath(UnsignedTestImage)
assert.NoError(t, err)
signedIndex, err := Sign(ctx, attIdx.Index, signer, opts)
opts := &attestation.SigningOptions{}
attIdx, err := oci.IndexFromPath(UnsignedTestImage)
assert.NoError(t, err)
signedManifests, err := SignStatements(ctx, attIdx.Index, signer, opts)
require.NoError(t, err)
signedIndex := attIdx.Index
signedIndex, err = attestation.UpdateIndexImages(signedIndex, signedManifests, attestation.WithReplacedLayers(true))
require.NoError(t, err)
// output signed attestations
idx := v1.ImageIndex(empty.Index)
@@ -183,44 +185,52 @@ func TestVerificationFailure(t *testing.T) {
assert.Equal(t, "https://docker.com/official/policy/v0.1", attestationPredicate.Policy.URI)
}
// test signing without a TL entry
func TestSignVerifyNoTL(t *testing.T) {
func TestSignVerify(t *testing.T) {
ctx, signer := test.Setup(t)
ctx = policy.WithPolicyEvaluator(ctx, policy.NewRegoEvaluator(true))
// setup an image with signed attestations
outputLayout := test.CreateTempDir(t, "", TestTempDir)
testCases := []struct {
name string
signTL bool
policyDir string
success bool
name string
signTL bool
policyDir string
imageName string
expectError bool
}{
{name: "happy path", signTL: true, policyDir: PassNoTLPolicyDir, success: true},
{name: "sign tl, verify no tl", signTL: true, policyDir: PassPolicyDir, success: false},
{name: "no tl", signTL: false, policyDir: PassPolicyDir, success: false},
{name: "happy path", signTL: true, policyDir: PassNoTLPolicyDir},
{name: "sign tl, verify no tl", signTL: true, policyDir: PassPolicyDir},
{name: "no tl", signTL: false, policyDir: PassPolicyDir},
{name: "mirror", signTL: true, policyDir: PassMirrorPolicyDir, imageName: "mirror.org/library/test-image:test"},
{name: "mirror no match", signTL: true, policyDir: PassMirrorPolicyDir, imageName: "incorrect.org/library/test-image:test", expectError: true},
}
attIdx, err := oci.SubjectIndexFromPath(UnsignedTestImage)
attIdx, err := oci.IndexFromPath(UnsignedTestImage)
assert.NoError(t, err)
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
opts := &attestation.SigningOptions{
Replace: true,
SkipTL: tc.signTL,
SkipTL: tc.signTL,
}
signedIndex, err := Sign(ctx, attIdx.Index, signer, opts)
assert.NoError(t, err)
signedManifests, err := SignStatements(ctx, attIdx.Index, signer, opts)
require.NoError(t, err)
signedIndex := attIdx.Index
signedIndex, err = attestation.UpdateIndexImages(signedIndex, signedManifests, attestation.WithReplacedLayers(true))
require.NoError(t, err)
imageName := tc.imageName
if imageName == "" {
imageName = attIdx.Name
}
// output signed attestations
idx := v1.ImageIndex(empty.Index)
idx = mutate.AppendManifests(idx, mutate.IndexAddendum{
Add: signedIndex,
Descriptor: v1.Descriptor{
Annotations: map[string]string{
oci.OciReferenceTarget: attIdx.Name,
oci.OciReferenceTarget: imageName,
},
},
})
@@ -233,8 +243,17 @@ func TestSignVerifyNoTL(t *testing.T) {
src, err := oci.ParseImageSpec("oci://"+outputLayout, oci.WithPlatform(LinuxAMD64))
require.NoError(t, err)
results, err := Verify(ctx, src, policyOpts)
if tc.expectError {
require.Error(t, err)
return
}
require.NoError(t, err)
assert.Equal(t, OutcomeSuccess, results.Outcome)
platform, err := oci.ParsePlatform(LinuxAMD64)
require.NoError(t, err)
expectedPURL, _, err := oci.RefToPURL(attIdx.Name, platform)
require.NoError(t, err)
assert.Equal(t, expectedPURL, results.Input.Purl)
})
}
}

View File

@@ -1,18 +1,24 @@
package attestation
import (
"context"
"encoding/json"
"fmt"
"maps"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/empty"
"github.com/google/go-containerregistry/pkg/v1/match"
"github.com/google/go-containerregistry/pkg/v1/mutate"
"github.com/google/go-containerregistry/pkg/v1/partial"
"github.com/google/go-containerregistry/pkg/v1/static"
"github.com/google/go-containerregistry/pkg/v1/types"
intoto "github.com/in-toto/in-toto-golang/in_toto"
"github.com/secure-systems-lab/go-securesystemslib/dsse"
)
// GetAttestationManifestsFromIndex extracts all attestation manifests from an index
func GetAttestationManifestsFromIndex(index v1.ImageIndex) ([]AttestationManifest, error) {
func GetAttestationManifestsFromIndex(index v1.ImageIndex) ([]*AttestationManifest, error) {
idx, err := index.IndexManifest()
if err != nil {
return nil, fmt.Errorf("failed to extract IndexManifest from ImageIndex: %w", err)
@@ -22,44 +28,38 @@ func GetAttestationManifestsFromIndex(index v1.ImageIndex) ([]AttestationManifes
subjects[subject.Digest.String()] = &subject
}
var attestationManifests []AttestationManifest
for _, manifest := range idx.Manifests {
if manifest.Annotations[DockerReferenceType] == AttestationManifestType {
subject := subjects[manifest.Annotations[DockerReferenceDigest]]
var attestationManifests []*AttestationManifest
for _, desc := range idx.Manifests {
if desc.Annotations[DockerReferenceType] == AttestationManifestType {
subject := subjects[desc.Annotations[DockerReferenceDigest]]
if subject == nil {
return nil, fmt.Errorf("failed to find subject for attestation manifest: %w", err)
}
attestationImage, err := index.Image(manifest.Digest)
attestationImage, err := index.Image(desc.Digest)
if err != nil {
return nil, fmt.Errorf("failed to extract attestation image with digest %s: %w", manifest.Digest.String(), err)
return nil, fmt.Errorf("failed to extract attestation image with digest %s: %w", desc.Digest.String(), err)
}
attestationLayers, err := GetAttestationsFromImage(attestationImage)
if err != nil {
return nil, fmt.Errorf("failed to get attestations from image: %w", err)
}
attestationManifests = append(attestationManifests,
AttestationManifest{
Descriptor: manifest,
SubjectDescriptor: subject,
Attestation: AttestationImage{
Layers: attestationLayers,
Image: attestationImage},
MediaType: manifest.MediaType,
Annotations: manifest.Annotations,
Digest: manifest.Digest})
&AttestationManifest{
OriginalDescriptor: &desc,
SubjectDescriptor: subject,
OriginalLayers: attestationLayers})
}
}
return attestationManifests, nil
}
// GetAttestationsFromImage extracts all attestation layers from an image
func GetAttestationsFromImage(image v1.Image) ([]AttestationLayer, error) {
func GetAttestationsFromImage(image v1.Image) ([]*AttestationLayer, error) {
layers, err := image.Layers()
if err != nil {
return nil, fmt.Errorf("failed to extract layers from image: %w", err)
}
var attestationLayers []AttestationLayer
var attestationLayers []*AttestationLayer
for _, layer := range layers {
// parse layer blob as json
r, err := layer.Uncompressed()
@@ -85,7 +85,240 @@ func GetAttestationsFromImage(image v1.Image) ([]AttestationLayer, error) {
return nil, fmt.Errorf("failed to decode statement layer contents: %w", err)
}
}
attestationLayers = append(attestationLayers, AttestationLayer{Layer: layer, MediaType: mt, Statement: stmt, Annotations: ann})
attestationLayers = append(attestationLayers, &AttestationLayer{Layer: layer, Statement: stmt, Annotations: ann})
}
return attestationLayers, nil
}
func (manifest *AttestationManifest) AddAttestation(ctx context.Context, signer dsse.SignerVerifier, statement *intoto.Statement, opts *SigningOptions) error {
layer, err := createSignedImageLayer(ctx, statement, signer, opts)
if err != nil {
return fmt.Errorf("failed to create signed layer: %w", err)
}
manifest.SignedLayers = append(manifest.SignedLayers, layer)
return nil
}
func createSignedImageLayer(ctx context.Context, statement *intoto.Statement, signer dsse.SignerVerifier, opts *SigningOptions) (*AttestationLayer, error) {
// sign the statement
env, err := SignInTotoStatement(ctx, statement, signer, opts)
if err != nil {
return nil, fmt.Errorf("failed to sign statement: %w", err)
}
mediaType, err := DSSEMediaType(statement.PredicateType)
if err != nil {
return nil, fmt.Errorf("failed to get DSSE media type: %w", err)
}
data, err := json.Marshal(env)
if err != nil {
return nil, fmt.Errorf("failed to marshal envelope: %w", err)
}
return &AttestationLayer{
Statement: statement,
Annotations: map[string]string{
InTotoPredicateType: statement.PredicateType,
InTotoReferenceLifecycleStage: LifecycleStageExperimental,
},
Layer: static.NewLayer(data, types.MediaType(mediaType)),
}, nil
}
func SignInTotoStatement(ctx context.Context, statement *intoto.Statement, signer dsse.SignerVerifier, opts *SigningOptions) (*Envelope, error) {
payload, err := json.Marshal(statement)
if err != nil {
return nil, fmt.Errorf("failed to marshal statement: %w", err)
}
env, err := SignDSSE(ctx, payload, signer, opts)
if err != nil {
return nil, fmt.Errorf("failed to sign statement: %w", err)
}
return env, nil
}
func UpdateIndexImage(
idx v1.ImageIndex,
manifest *AttestationManifest,
options ...func(*AttestationManifestImageOptions) error) (v1.ImageIndex, error) {
image, err := manifest.BuildAttestationImage(options...)
if err != nil {
return nil, fmt.Errorf("failed to build image: %w", err)
}
newDesc, err := partial.Descriptor(image)
if err != nil {
return nil, fmt.Errorf("failed to get descriptor: %w", err)
}
newDesc.Platform = &v1.Platform{
Architecture: "unknown",
OS: "unknown",
}
newDesc.MediaType = manifest.OriginalDescriptor.MediaType
newDesc.Annotations = manifest.OriginalDescriptor.Annotations
idx = mutate.RemoveManifests(idx, match.Digests(manifest.OriginalDescriptor.Digest))
idx = mutate.AppendManifests(idx, mutate.IndexAddendum{
Add: image,
Descriptor: *newDesc,
})
return idx, nil
}
func UpdateIndexImages(idx v1.ImageIndex, manifest []*AttestationManifest, options ...func(*AttestationManifestImageOptions) error) (v1.ImageIndex, error) {
var err error
for _, m := range manifest {
idx, err = UpdateIndexImage(idx, m, options...)
if err != nil {
return nil, fmt.Errorf("failed to add image to index: %w", err)
}
}
return idx, nil
}
func newOptions(options ...func(*AttestationManifestImageOptions) error) (*AttestationManifestImageOptions, error) {
opts := &AttestationManifestImageOptions{}
for _, opt := range options {
err := opt(opts)
if err != nil {
return nil, err
}
}
return opts, nil
}
func WithoutSubject(skipSubject bool) func(*AttestationManifestImageOptions) error {
return func(r *AttestationManifestImageOptions) error {
r.skipSubject = skipSubject
return nil
}
}
func WithReplacedLayers(replaceLayers bool) func(*AttestationManifestImageOptions) error {
return func(r *AttestationManifestImageOptions) error {
r.replaceLayers = replaceLayers
return nil
}
}
// build an image with signed attestations, optionally replacing existing layers with signed layers
func (manifest *AttestationManifest) BuildAttestationImage(options ...func(*AttestationManifestImageOptions) error) (v1.Image, error) {
opts, err := newOptions(options...)
if err != nil {
return nil, fmt.Errorf("failed to create options: %w", err)
}
resultLayers := manifest.SignedLayers
for _, existingLayer := range manifest.OriginalLayers {
var found bool
for _, signedLayer := range manifest.SignedLayers {
if existingLayer.Statement == signedLayer.Statement {
found = true
// copy over original annotations
for k, v := range existingLayer.Annotations {
signedLayer.Annotations[k] = v
}
break
}
}
//add existing layers if they've not been signed or we're not replacing them
if !found || !opts.replaceLayers {
resultLayers = append(resultLayers, existingLayer)
}
}
// so taht we attach all attestations to a single attestations image - as per current buildkit
opts.laxReferrers = true
newImg, err := buildImage(resultLayers, manifest.OriginalDescriptor, manifest.SubjectDescriptor, opts)
if err != nil {
return nil, fmt.Errorf("failed to build image: %w", err)
}
return newImg, nil
}
// build an image per attestation (layer) suitable for use as Referrers
func (manifest *AttestationManifest) BuildReferringArtifacts() ([]v1.Image, error) {
var images []v1.Image
for _, layer := range manifest.SignedLayers {
opts := &AttestationManifestImageOptions{}
newImg, err := buildImage([]*AttestationLayer{layer}, manifest.OriginalDescriptor, manifest.SubjectDescriptor, opts)
if err != nil {
return nil, fmt.Errorf("failed to build image: %w", err)
}
images = append(images, newImg)
}
return images, nil
}
// build and image containing only layers
func buildImage(layers []*AttestationLayer, manifest *v1.Descriptor, subject *v1.Descriptor, opts *AttestationManifestImageOptions) (v1.Image, error) {
newImg := empty.Image
var err error
if len(layers) == 0 {
return nil, fmt.Errorf("no layers supplied to build image")
}
// NB: if we add the subject before the layers, it does not end up being computed/serialised in the output for some reason
//TODO - recreate this bug and push upstream
for _, layer := range layers {
add := mutate.Addendum{
Layer: layer.Layer,
Annotations: layer.Annotations,
}
newImg, err = mutate.Append(newImg, add)
if err != nil {
return nil, fmt.Errorf("failed to add layer to image: %w", err)
}
}
// this is for attaching attestations to an attestation image in the index
if opts.laxReferrers {
newImg = mutate.ConfigMediaType(newImg, "application/vnd.oci.image.config.v1+json")
} else {
dsseMediatType, err := DSSEMediaType(layers[0].Statement.PredicateType)
if err != nil {
return nil, fmt.Errorf("failed to get DSSE media type: %w", err)
}
newImg = mutate.ArtifactType(newImg, dsseMediatType)
newImg = mutate.ConfigMediaType(newImg, "application/vnd.oci.empty.v1+json")
}
// we need to set this even when we set the artifact type otherwise things break (even the go-container-registry client)
// even though it's allowed to be empty by spec when setting artifact type
newImg = mutate.MediaType(newImg, manifest.MediaType)
// see note above - must be added after the layers!
if !opts.skipSubject {
subject.Platform = nil
newImg = mutate.Subject(newImg, *subject).(v1.Image)
}
if !opts.laxReferrers {
// as per https://github.com/opencontainers/image-spec/blob/main/manifest.md#guidance-for-an-empty-descriptor
newImg = &EmptyConfigImage{newImg}
}
return newImg, nil
}
type EmptyConfigImage struct {
v1.Image
}
func (i *EmptyConfigImage) RawConfigFile() ([]byte, error) {
return []byte("{}"), nil
}
func (i *EmptyConfigImage) Manifest() (*v1.Manifest, error) {
mf, err := i.Image.Manifest()
if err != nil {
return nil, fmt.Errorf("failed to get manifest: %w", err)
}
mf.Config = v1.Descriptor{
MediaType: "application/vnd.oci.empty.v1+json",
Size: 2,
Digest: v1.Hash{Algorithm: "sha256", Hex: "44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a"},
Data: []byte("{}"),
}
return mf, nil
}
func (i *EmptyConfigImage) RawManifest() ([]byte, error) {
mf, err := i.Manifest()
if err != nil {
return nil, fmt.Errorf("failed to get manifest: %w", err)
}
return json.Marshal(mf)
}

View File

@@ -37,53 +37,50 @@ func TestAttestationReferenceTypes(t *testing.T) {
ctx = policy.WithPolicyEvaluator(ctx, policy.NewRegoEvaluator(true))
platforms := []string{"linux/amd64", "linux/arm64"}
for _, tc := range []struct {
name string
server *httptest.Server
referrersServer *httptest.Server
skipSubject bool
useDigest bool
referrersRepo string
attestationSource config.AttestationStyle
expectFailure bool
policyDir string
}{
{
name: "referrers support, defaults",
server: httptest.NewServer(registry.New(registry.WithReferrersSupport(true))),
},
{
server: httptest.NewServer(registry.New()),
},
{
server: httptest.NewServer(registry.New(registry.WithReferrersSupport(true))),
skipSubject: true,
attestationSource: config.AttestationStyleAttached,
},
{
name: "use digest",
server: httptest.NewServer(registry.New(registry.WithReferrersSupport(true))),
useDigest: true,
},
{
name: "attached attestations, referrers repo (mismatched args)",
server: httptest.NewServer(registry.New(registry.WithReferrersSupport(true))),
expectFailure: true, //mismatched args
attestationSource: config.AttestationStyleAttached,
referrersRepo: "referrers",
},
{
name: "referrers attestations, referrers repo (no policy)",
server: httptest.NewServer(registry.New(registry.WithReferrersSupport(true))),
expectFailure: true, // no policy
attestationSource: config.AttestationStyleReferrers,
referrersRepo: "referrers",
},
{
name: "referrers attestations",
server: httptest.NewServer(registry.New(registry.WithReferrersSupport(true))),
attestationSource: config.AttestationStyleReferrers,
},
{
name: "referrers attestations, no referrers support on server",
server: httptest.NewServer(registry.New(registry.WithReferrersSupport(false))),
attestationSource: config.AttestationStyleReferrers,
referrersServer: httptest.NewServer(registry.New(registry.WithReferrersSupport(true))),
},
} {
t.Run(fmt.Sprint(tc), func(t *testing.T) {
t.Run(tc.name, func(t *testing.T) {
s := tc.server
defer s.Close()
@@ -94,31 +91,35 @@ func TestAttestationReferenceTypes(t *testing.T) {
require.NoError(t, err)
opts := &attestation.SigningOptions{
Replace: true,
SkipSubject: tc.skipSubject,
SkipTL: true,
}
attIdx, err := oci.SubjectIndexFromPath(UnsignedTestImage)
attIdx, err := oci.IndexFromPath(UnsignedTestImage)
require.NoError(t, err)
indexName := fmt.Sprintf("%s/repo:root", u.Host)
require.NoError(t, err)
outputRepo := indexName
if tc.referrersServer != nil {
ru, err := url.Parse(s.URL)
require.NoError(t, err)
repo := fmt.Sprintf("%s/referrers", ru.Host)
tc.referrersRepo = repo
images, err := attest.SignedAttestationImages(ctx, attIdx.Index, signer, opts)
require.NoError(t, err)
err = mirror.PushIndexToRegistry(attIdx.Index, indexName)
for _, img := range images {
err = mirror.PushImageToRegistry(img.Image, fmt.Sprintf("%s:tag-does-not-matter", repo))
require.NoError(t, err)
}
} else {
signedIndex, err := attest.Sign(ctx, attIdx.Index, signer, opts)
require.NoError(t, err)
err = mirror.PushIndexToRegistry(signedIndex, indexName)
tc.referrersRepo = fmt.Sprintf("%s/referrers", ru.Host)
outputRepo = tc.referrersRepo
}
// sign all the statements in the index
signedManifests, err := attest.SignStatements(ctx, attIdx.Index, signer, opts)
require.NoError(t, err)
// push subject image so that it can be resolved
require.NoError(t, err)
err = mirror.PushIndexToRegistry(attIdx.Index, indexName)
require.NoError(t, err)
// upload referrers
output, err := oci.ParseImageSpec(outputRepo)
require.NoError(t, err)
for _, attIdx := range signedManifests {
err = mirror.SaveReferrers(attIdx, []*oci.ImageSpec{output})
require.NoError(t, err)
}
@@ -139,9 +140,6 @@ func TestAttestationReferenceTypes(t *testing.T) {
policyOpts := &policy.PolicyOptions{
LocalPolicyDir: LocalPolicy,
}
if tc.policyDir != "" {
policyOpts.LocalPolicyDir = tc.policyDir
}
if tc.referrersRepo != "" {
policyOpts.ReferrersRepo = tc.referrersRepo
@@ -160,26 +158,23 @@ func TestAttestationReferenceTypes(t *testing.T) {
require.NoError(t, err)
assert.Equal(t, attest.OutcomeSuccess, results.Outcome)
if !tc.skipSubject {
// can evaluate policy using referrers
if tc.useDigest {
p, err := oci.ParsePlatform(platform)
require.NoError(t, err)
options := oci.WithOptions(ctx, p)
subjectRef, err := name.ParseReference(indexName)
require.NoError(t, err)
desc, err := remote.Image(subjectRef, options...)
require.NoError(t, err)
subjectDigest, err := desc.Digest()
require.NoError(t, err)
ref = fmt.Sprintf("%s/repo@%s", u.Host, subjectDigest.String())
}
src, err := oci.ParseImageSpec(ref, oci.WithPlatform(platform))
if tc.useDigest {
p, err := oci.ParsePlatform(platform)
require.NoError(t, err)
results, err = attest.Verify(ctx, src, policyOpts)
options := oci.WithOptions(ctx, p)
subjectRef, err := name.ParseReference(indexName)
require.NoError(t, err)
assert.Equal(t, attest.OutcomeSuccess, results.Outcome)
desc, err := remote.Image(subjectRef, options...)
require.NoError(t, err)
subjectDigest, err := desc.Digest()
require.NoError(t, err)
ref = fmt.Sprintf("%s/repo@%s", u.Host, subjectDigest.String())
}
src, err = oci.ParseImageSpec(ref, oci.WithPlatform(platform))
require.NoError(t, err)
results, err = attest.Verify(ctx, src, policyOpts)
require.NoError(t, err)
assert.Equal(t, attest.OutcomeSuccess, results.Outcome)
}
})
}
@@ -189,14 +184,17 @@ func TestReferencesInDifferentRepo(t *testing.T) {
ctx, signer := test.Setup(t)
repoName := "repo"
for _, tc := range []struct {
name string
server *httptest.Server
refServer *httptest.Server
}{
{
name: "referrers support",
server: httptest.NewServer(registry.New(registry.WithReferrersSupport(true))),
refServer: httptest.NewServer(registry.New(registry.WithReferrersSupport(true))),
},
{
name: "no referrers support",
server: httptest.NewServer(registry.New()),
refServer: httptest.NewServer(registry.New(registry.WithReferrersSupport(true))),
},
@@ -212,42 +210,119 @@ func TestReferencesInDifferentRepo(t *testing.T) {
require.NoError(t, err)
opts := &attestation.SigningOptions{
Replace: true,
SkipTL: true,
SkipTL: true,
}
attIdx, err := oci.SubjectIndexFromPath(UnsignedTestImage)
attIdx, err := oci.IndexFromPath(UnsignedTestImage)
require.NoError(t, err)
indexName := fmt.Sprintf("%s/%s:latest", serverUrl.Host, repoName)
err = mirror.PushIndexToRegistry(attIdx.Index, indexName)
require.NoError(t, err)
signedImages, err := attest.SignedAttestationImages(ctx, attIdx.Index, signer, opts)
signedManifests, err := attest.SignStatements(ctx, attIdx.Index, signer, opts)
require.NoError(t, err)
// push signed attestation image to the ref server
for _, img := range signedImages {
for _, signedManifest := range signedManifests {
// push references using subject-digest.att convention
err = mirror.PushImageToRegistry(img.Image, fmt.Sprintf("%s/%s:tag-does-not-matter", refServerUrl.Host, repoName))
image, err := signedManifest.BuildAttestationImage()
require.NoError(t, err)
}
mfs2, err := attIdx.Index.IndexManifest()
require.NoError(t, err)
for _, mf := range mfs2.Manifests {
//skip signed/unsigned attestations
if mf.Annotations[attestation.DockerReferenceType] == attestation.AttestationManifestType {
continue
err = mirror.PushImageToRegistry(image, fmt.Sprintf("%s/%s:tag-does-not-matter", refServerUrl.Host, repoName))
require.NoError(t, err)
refServer := tc.refServer
defer refServer.Close()
refServerUrl, err := url.Parse(refServer.URL)
require.NoError(t, err)
opts := &attestation.SigningOptions{
SkipTL: true,
}
// can evaluate policy using referrers in a different repo
referencedImage := fmt.Sprintf("%s@%s", indexName, mf.Digest.String())
policyOpts := &policy.PolicyOptions{
LocalPolicyDir: PassPolicyDir,
attIdx, err := oci.IndexFromPath(UnsignedTestImage)
require.NoError(t, err)
indexName := fmt.Sprintf("%s/%s:latest", serverUrl.Host, repoName)
err = mirror.PushIndexToRegistry(attIdx.Index, indexName)
require.NoError(t, err)
signedManifests, err := attest.SignStatements(ctx, attIdx.Index, signer, opts)
require.NoError(t, err)
// push signed attestation image to the ref server
for _, mf := range signedManifests {
// push references using subject-digest.att convention
imgs, err := mf.BuildReferringArtifacts()
require.NoError(t, err)
for _, img := range imgs {
err = mirror.PushImageToRegistry(img, fmt.Sprintf("%s/%s:tag-does-not-matter", refServerUrl.Host, repoName))
require.NoError(t, err)
}
}
src, err := oci.ParseImageSpec(referencedImage)
mfs2, err := attIdx.Index.IndexManifest()
require.NoError(t, err)
results, err := attest.Verify(ctx, src, policyOpts)
require.NoError(t, err)
assert.Equal(t, attest.OutcomeSuccess, results.Outcome)
for _, mf := range mfs2.Manifests {
//skip signed/unsigned attestations
if mf.Annotations[attestation.DockerReferenceType] == attestation.AttestationManifestType {
continue
}
// can evaluate policy using referrers in a different repo
referencedImage := fmt.Sprintf("%s@%s", indexName, mf.Digest.String())
policyOpts := &policy.PolicyOptions{
LocalPolicyDir: PassPolicyDir,
}
src, err := oci.ParseImageSpec(referencedImage)
require.NoError(t, err)
results, err := attest.Verify(ctx, src, policyOpts)
require.NoError(t, err)
assert.Equal(t, attest.OutcomeSuccess, results.Outcome)
}
}
}
}
func TestCorrectArtifactTypeInTagFallback(t *testing.T) {
ctx, signer := test.Setup(t)
server := httptest.NewServer(registry.New())
defer server.Close()
serverUrl, err := url.Parse(server.URL)
require.NoError(t, err)
repoName := "repo"
opts := &attestation.SigningOptions{
SkipTL: true,
}
attIdx, err := oci.IndexFromPath(UnsignedTestImage)
require.NoError(t, err)
indexName := fmt.Sprintf("%s/%s:latest", serverUrl.Host, repoName)
err = mirror.PushIndexToRegistry(attIdx.Index, indexName)
require.NoError(t, err)
signedManifests, err := attest.SignStatements(ctx, attIdx.Index, signer, opts)
require.NoError(t, err)
// this should create and maintain an index of referrers
for _, mf := range signedManifests {
imgs, err := mf.BuildReferringArtifacts()
require.NoError(t, err)
for _, img := range imgs {
err = mirror.PushImageToRegistry(img, fmt.Sprintf("%s/%s:tag-does-not-matter", serverUrl.Host, repoName))
require.NoError(t, err)
mf, err := img.Manifest()
require.NoError(t, err)
subject := mf.Subject
subjectRef, err := name.ParseReference(fmt.Sprintf("%s/%s:sha256-%s", serverUrl.Host, repoName, subject.Digest.Hex))
require.NoError(t, err)
idx, err := remote.Index(subjectRef)
require.NoError(t, err)
imf, err := idx.IndexManifest()
require.NoError(t, err)
for _, m := range imf.Manifests {
assert.Contains(t, m.ArtifactType, "application/vnd.in-toto")
assert.Contains(t, m.ArtifactType, "+dsse")
}
}
}
}

View File

@@ -5,19 +5,21 @@ import (
"fmt"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/types"
intoto "github.com/in-toto/in-toto-golang/in_toto"
v02 "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.2"
ociv1 "github.com/opencontainers/image-spec/specs-go/v1"
)
const (
DockerReferenceType = "vnd.docker.reference.type"
AttestationManifestType = "attestation-manifest"
DockerReferenceDigest = "vnd.docker.reference.digest"
DockerDsseExtKind = "application/vnd.docker.attestation-verification.v1+json"
RekorTlExtKind = "Rekor"
OCIDescriptorDSSEMediaType = ociv1.MediaTypeDescriptor + "+dsse"
DockerReferenceType = "vnd.docker.reference.type"
AttestationManifestType = "attestation-manifest"
InTotoPredicateType = "in-toto.io/predicate-type"
DockerReferenceDigest = "vnd.docker.reference.digest"
DockerDsseExtKind = "application/vnd.docker.attestation-verification.v1+json"
RekorTlExtKind = "Rekor"
OCIDescriptorDSSEMediaType = ociv1.MediaTypeDescriptor + "+dsse"
InTotoReferenceLifecycleStage = "vnd.docker.lifecycle-stage"
LifecycleStageExperimental = "experimental"
)
var base64Encoding = base64.StdEncoding.Strict()
@@ -25,30 +27,27 @@ var base64Encoding = base64.StdEncoding.Strict()
type AttestationLayer struct {
Statement *intoto.Statement
Layer v1.Layer
MediaType types.MediaType
Annotations map[string]string
}
type AttestationImage struct {
Layers []AttestationLayer
Image v1.Image
}
type SignedAttestationImage struct {
Image v1.Image
Descriptor *v1.Descriptor
AttestationManifest AttestationManifest
}
type AttestationManifest struct {
Descriptor v1.Descriptor
Attestation AttestationImage
MediaType types.MediaType
Annotations map[string]string
Digest v1.Hash
OriginalDescriptor *v1.Descriptor
OriginalLayers []*AttestationLayer
// accumulated during signing
SignedLayers []*AttestationLayer
// details of subect image
SubjectName string
SubjectDescriptor *v1.Descriptor
}
type AttestationManifestImageOptions struct {
// how to output the image
skipSubject bool
replaceLayers bool
laxReferrers bool
}
// the following types are needed until https://github.com/secure-systems-lab/dsse/pull/61 is merged
type Envelope struct {
PayloadType string `json:"payloadType"`
@@ -58,7 +57,7 @@ type Envelope struct {
type Signature struct {
KeyID string `json:"keyid"`
Sig string `json:"sig"`
Extension Extension `json:"extension"`
Extension Extension `json:"extension,omitempty"`
}
type Extension struct {
Kind string `json:"kind"`
@@ -80,12 +79,8 @@ type VerifyOptions struct {
}
type SigningOptions struct {
// replace unsigned statements with signed attestations
Replace bool
// don't log to the configured transparency log
SkipTL bool
// don't add OCI subject field to attestation image
SkipSubject bool
}
func DSSEMediaType(predicateType string) (string, error) {

View File

@@ -4,6 +4,7 @@ import (
"fmt"
"os"
"path/filepath"
"regexp"
"github.com/docker/attest/pkg/tuf"
goyaml "gopkg.in/yaml.v3"
@@ -17,7 +18,7 @@ func LoadLocalMappings(configDir string) (*PolicyMappings, error) {
if configDir == "" {
return nil, nil
}
mappings := &PolicyMappings{}
mappings := &policyMappingsFile{}
path := filepath.Join(configDir, MappingFilename)
mappingFile, err := os.ReadFile(path)
if err != nil {
@@ -27,7 +28,7 @@ func LoadLocalMappings(configDir string) (*PolicyMappings, error) {
if err != nil {
return nil, fmt.Errorf("failed to unmarshal policy mapping file %s: %w", path, err)
}
return mappings, nil
return expandMappingFile(mappings)
}
func LoadTufMappings(tufClient tuf.TUFClient, localTargetsDir string) (*PolicyMappings, error) {
@@ -39,11 +40,38 @@ func LoadTufMappings(tufClient tuf.TUFClient, localTargetsDir string) (*PolicyMa
if err != nil {
return nil, fmt.Errorf("failed to download policy mapping file %s: %w", filename, err)
}
mappings := &PolicyMappings{}
mappings := &policyMappingsFile{}
err = goyaml.Unmarshal(fileContents, mappings)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal policy mapping file %s: %w", filename, err)
}
return mappings, nil
return expandMappingFile(mappings)
}
func expandMappingFile(mappingFile *policyMappingsFile) (*PolicyMappings, error) {
policies := make(map[string]*PolicyMapping)
for _, policy := range mappingFile.Policies {
policies[policy.Id] = policy
}
var rules []*PolicyRule
for _, rule := range mappingFile.Rules {
r, err := regexp.Compile(rule.Pattern)
if err != nil {
return nil, err
}
rules = append(rules, &PolicyRule{
Pattern: r,
PolicyId: rule.PolicyId,
Replacement: rule.Replacement,
})
}
return &PolicyMappings{
Version: mappingFile.Version,
Kind: mappingFile.Kind,
Policies: policies,
Rules: rules,
}, nil
}

View File

@@ -1,10 +1,25 @@
package config
import "regexp"
type policyMappingsFile struct {
Version string `yaml:"version"`
Kind string `yaml:"kind"`
Policies []*PolicyMapping `yaml:"policies"`
Rules []*policyRuleFile `yaml:"rules"`
}
type policyRuleFile struct {
Pattern string `yaml:"pattern"`
PolicyId string `yaml:"policy-id"`
Replacement string `yaml:"rewrite"`
}
type PolicyMappings struct {
Version string `json:"version"`
Kind string `json:"kind"`
Policies []*PolicyMapping `json:"policies"`
Mirrors []*PolicyMirror `json:"mirrors"`
Version string
Kind string
Policies map[string]*PolicyMapping
Rules []*PolicyRule
}
type AttestationStyle string
@@ -15,34 +30,23 @@ const (
)
type PolicyMapping struct {
Id string `json:"id"`
Description string `json:"description"`
Origin *PolicyOrigin `json:"origin"`
Files []PolicyMappingFile `json:"files"`
Attestations *ReferrersConfig `json:"attestations"`
Id string `yaml:"id"`
Description string `yaml:"description"`
Files []PolicyMappingFile `yaml:"files"`
Attestations *AttestationConfig `yaml:"attestations"`
}
type ReferrersConfig struct {
Style AttestationStyle `json:"style"`
Repo string `json:"repo"`
type AttestationConfig struct {
Style AttestationStyle `yaml:"style"`
Repo string `yaml:"repo"`
}
type PolicyMappingFile struct {
Path string `json:"path"`
Path string `yaml:"path"`
}
type PolicyMirror struct {
PolicyId string `yaml:"policy-id"`
Mirror MirrorSpec `json:"mirror"`
}
type MirrorSpec struct {
Domains []string `json:"domains"`
Prefix string `json:"prefix"`
}
type PolicyOrigin struct {
Name string `json:"name"`
Prefix string `json:"prefix"`
Domain string `json:"domain"`
type PolicyRule struct {
Pattern *regexp.Regexp
PolicyId string
Replacement string
}

34
pkg/mirror/authn_test.go Normal file
View File

@@ -0,0 +1,34 @@
//go:build e2e
package mirror_test
import (
"path/filepath"
"testing"
"github.com/docker/attest/pkg/mirror"
"github.com/docker/attest/pkg/oci"
"github.com/stretchr/testify/require"
)
func TestRegistryAuth(t *testing.T) {
UnsignedTestImage := filepath.Join("..", "..", "test", "testdata", "unsigned-test-image")
attIdx, err := oci.IndexFromPath(UnsignedTestImage)
require.NoError(t, err)
// test cases for ecr, gcr and dockerhub
testCases := []struct {
Image string
}{
{Image: "175142243308.dkr.ecr.us-east-1.amazonaws.com/e2e-test-image:latest"},
{Image: "docker/image-signer-verifier-test:latest"},
}
for _, tc := range testCases {
t.Run(tc.Image, func(t *testing.T) {
err := mirror.PushIndexToRegistry(attIdx.Index, tc.Image)
require.NoError(t, err)
_, err = oci.IndexFromRemote(tc.Image)
require.NoError(t, err)
})
}
}

View File

@@ -29,7 +29,7 @@ func ExampleNewTufMirror() {
// configure TUF mirror
metadataURI := "https://docker.github.io/tuf-staging/metadata"
targetsURI := "https://docker.github.io/tuf-staging/targets"
m, err := mirror.NewTufMirror(embed.StagingRoot, tufOutputPath, metadataURI, targetsURI, tuf.NewMockVersionChecker())
m, err := mirror.NewTufMirror(embed.RootStaging.Data, tufOutputPath, metadataURI, targetsURI, tuf.NewMockVersionChecker())
if err != nil {
panic(err)
}

View File

@@ -21,7 +21,7 @@ func TestGetTufMetadataMirror(t *testing.T) {
defer server.Close()
path := test.CreateTempDir(t, "", "tuf_temp")
m, err := NewTufMirror(embed.DevRoot, path, server.URL+"/metadata", server.URL+"/targets", tuf.NewMockVersionChecker())
m, err := NewTufMirror(embed.RootDev.Data, path, server.URL+"/metadata", server.URL+"/targets", tuf.NewMockVersionChecker())
assert.NoError(t, err)
tufMetadata, err := m.getTufMetadataMirror(server.URL + "/metadata")
@@ -39,7 +39,7 @@ func TestGetMetadataManifest(t *testing.T) {
defer server.Close()
path := test.CreateTempDir(t, "", "tuf_temp")
m, err := NewTufMirror(embed.DevRoot, path, server.URL+"/metadata", server.URL+"/targets", tuf.NewMockVersionChecker())
m, err := NewTufMirror(embed.RootDev.Data, path, server.URL+"/metadata", server.URL+"/targets", tuf.NewMockVersionChecker())
assert.NoError(t, err)
img, err := m.GetMetadataManifest(server.URL + "/metadata")
@@ -78,7 +78,7 @@ func TestGetDelegatedMetadataMirrors(t *testing.T) {
defer server.Close()
path := test.CreateTempDir(t, "", "tuf_temp")
m, err := NewTufMirror(embed.DevRoot, path, server.URL+"/metadata", server.URL+"/targets", tuf.NewMockVersionChecker())
m, err := NewTufMirror(embed.RootDev.Data, path, server.URL+"/metadata", server.URL+"/targets", tuf.NewMockVersionChecker())
assert.NoError(t, err)
delegations, err := m.GetDelegatedMetadataMirrors()

View File

@@ -5,18 +5,20 @@ import (
"os"
"github.com/docker/attest/internal/embed"
"github.com/docker/attest/pkg/attestation"
"github.com/docker/attest/pkg/oci"
"github.com/docker/attest/pkg/tuf"
"github.com/google/go-containerregistry/pkg/authn"
"github.com/google/go-containerregistry/pkg/name"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/empty"
"github.com/google/go-containerregistry/pkg/v1/layout"
"github.com/google/go-containerregistry/pkg/v1/mutate"
"github.com/google/go-containerregistry/pkg/v1/remote"
)
func NewTufMirror(root []byte, tufPath, metadataURL, targetsURL string, versionChecker tuf.VersionChecker) (*TufMirror, error) {
if root == nil {
root = embed.DefaultRoot
root = embed.RootDefault.Data
}
tufClient, err := tuf.NewTufClient(root, tufPath, metadataURL, targetsURL, versionChecker)
if err != nil {
@@ -26,38 +28,29 @@ func NewTufMirror(root []byte, tufPath, metadataURL, targetsURL string, versionC
}
func PushImageToRegistry(image v1.Image, imageName string) error {
// Parse the image name
ref, err := name.ParseReference(imageName)
if err != nil {
return fmt.Errorf("Failed to parse image name '%s': %w", imageName, err)
}
// Get the authenticator from the default Docker keychain
auth, err := authn.DefaultKeychain.Resolve(ref.Context())
if err != nil {
return fmt.Errorf("Failed to get authenticator: %w", err)
}
// Push the image to the registry
return remote.Write(ref, image, remote.WithAuth(auth))
return remote.Write(ref, image, oci.MultiKeychainOption())
}
func PushIndexToRegistry(image v1.ImageIndex, imageName string) error {
func PushIndexToRegistry(index v1.ImageIndex, imageName string) error {
// Parse the index name
ref, err := name.ParseReference(imageName)
if err != nil {
return fmt.Errorf("Failed to parse image name: %w", err)
}
// Get the authenticator from the default Docker keychain
auth, err := authn.DefaultKeychain.Resolve(ref.Context())
if err != nil {
return fmt.Errorf("Failed to get authenticator: %w", err)
}
// Push the index to the registry
return remote.WriteIndex(ref, image, remote.WithAuth(auth))
return remote.WriteIndex(ref, index, oci.MultiKeychainOption())
}
func SaveImageAsOCILayout(image v1.Image, path string) error {
// Save the image to the local filesystem
err := os.MkdirAll(path, os.FileMode(0777))
err := os.MkdirAll(path, os.ModePerm)
if err != nil {
return fmt.Errorf("failed to create directory: %w", err)
}
@@ -71,7 +64,7 @@ func SaveImageAsOCILayout(image v1.Image, path string) error {
func SaveIndexAsOCILayout(image v1.ImageIndex, path string) error {
// Save the index to the local filesystem
err := os.MkdirAll(path, os.FileMode(0777))
err := os.MkdirAll(path, os.ModePerm)
if err != nil {
return fmt.Errorf("failed to create directory: %w", err)
}
@@ -82,3 +75,83 @@ func SaveIndexAsOCILayout(image v1.ImageIndex, path string) error {
}
return nil
}
func SaveIndex(outputs []*oci.ImageSpec, index v1.ImageIndex, indexName string) error {
// split output by comma and write or push each one
for _, output := range outputs {
if output.Type == oci.OCI {
idx := v1.ImageIndex(empty.Index)
idx = mutate.AppendManifests(idx, mutate.IndexAddendum{
Add: index,
Descriptor: v1.Descriptor{
Annotations: map[string]string{
oci.OciReferenceTarget: indexName,
},
},
})
err := SaveIndexAsOCILayout(idx, output.Identifier)
if err != nil {
return fmt.Errorf("failed to write signed image: %w", err)
}
} else {
err := PushIndexToRegistry(index, output.Identifier)
if err != nil {
return fmt.Errorf("failed to push signed image: %w", err)
}
}
}
return nil
}
func SaveImage(output *oci.ImageSpec, image v1.Image, imageName string) error {
if output.Type == oci.OCI {
idx := v1.ImageIndex(empty.Index)
idx = mutate.AppendManifests(idx, mutate.IndexAddendum{
Add: image,
Descriptor: v1.Descriptor{
Annotations: map[string]string{
oci.OciReferenceTarget: imageName,
},
},
})
err := SaveIndexAsOCILayout(idx, output.Identifier)
if err != nil {
return fmt.Errorf("failed to write signed image: %w", err)
}
} else {
err := PushImageToRegistry(image, output.Identifier)
if err != nil {
return fmt.Errorf("failed to push signed image: %w", err)
}
}
return nil
}
func SaveReferrers(manifest *attestation.AttestationManifest, outputs []*oci.ImageSpec) error {
for _, output := range outputs {
if output.Type == oci.OCI {
continue
}
// so that we use the same tag each time to reduce number of tags (tags aren't needed for referrers but we must push one)
attOut, err := oci.ReplaceTagInSpec(output, manifest.SubjectDescriptor.Digest)
if err != nil {
return err
}
//otherwise we end up with the detected platform, though I'm not sure it matters
attOut.Platform = &v1.Platform{
OS: "unknown",
Architecture: "unknown",
}
images, err := manifest.BuildReferringArtifacts()
if err != nil {
return fmt.Errorf("failed to build image: %w", err)
}
for _, image := range images {
err = SaveImage(attOut, image, "")
}
if err != nil {
return fmt.Errorf("failed to push image: %w", err)
}
}
return nil
}

111
pkg/mirror/mirror_test.go Normal file
View File

@@ -0,0 +1,111 @@
package mirror
import (
"fmt"
"net/http/httptest"
"net/url"
"path/filepath"
"testing"
"github.com/docker/attest/internal/test"
"github.com/docker/attest/pkg/attest"
"github.com/docker/attest/pkg/attestation"
"github.com/docker/attest/pkg/oci"
"github.com/google/go-containerregistry/pkg/registry"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/empty"
intoto "github.com/in-toto/in-toto-golang/in_toto"
"github.com/stretchr/testify/require"
)
func TestSavingIndex(t *testing.T) {
UnsignedTestImage := filepath.Join("..", "..", "test", "testdata", "unsigned-test-image")
outputLayout := test.CreateTempDir(t, "", "mirror-test")
attIdx, err := oci.IndexFromPath(UnsignedTestImage)
require.NoError(t, err)
server := httptest.NewServer(registry.New())
defer server.Close()
u, err := url.Parse(server.URL)
require.NoError(t, err)
indexName := fmt.Sprintf("%s/repo:root", u.Host)
output, err := oci.ParseImageSpecs(indexName)
require.NoError(t, err)
err = SaveIndex(output, attIdx.Index, indexName)
require.NoError(t, err)
ociOutput, err := oci.ParseImageSpecs("oci://" + outputLayout)
require.NoError(t, err)
err = SaveIndex(ociOutput, attIdx.Index, indexName)
require.NoError(t, err)
}
func TestSavingImage(t *testing.T) {
outputLayout := test.CreateTempDir(t, "", "mirror-test")
img := empty.Image
server := httptest.NewServer(registry.New())
defer server.Close()
u, err := url.Parse(server.URL)
require.NoError(t, err)
indexName := fmt.Sprintf("%s/repo:root", u.Host)
output, err := oci.ParseImageSpec(indexName)
require.NoError(t, err)
err = SaveImage(output, img, indexName)
require.NoError(t, err)
ociOutput, err := oci.ParseImageSpec("oci://" + outputLayout)
require.NoError(t, err)
err = SaveImage(ociOutput, img, indexName)
require.NoError(t, err)
}
func TestSavingReferrers(t *testing.T) {
ctx, signer := test.Setup(t)
opts := &attestation.SigningOptions{}
statement := &intoto.Statement{
StatementHeader: intoto.StatementHeader{
PredicateType: attestation.VSAPredicateType,
},
}
digest, err := v1.NewHash("sha256:da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620")
require.NoError(t, err)
subject := &v1.Descriptor{
MediaType: "application/vnd.oci.image.manifest.v1+json",
Digest: digest,
}
manifest, err := attest.NewAttestationManifest(subject)
require.NoError(t, err)
err = manifest.AddAttestation(ctx, signer, statement, opts)
require.NoError(t, err)
server := httptest.NewServer(registry.New(registry.WithReferrersSupport(true)))
defer server.Close()
u, err := url.Parse(server.URL)
require.NoError(t, err)
indexName := fmt.Sprintf("%s/repo:root", u.Host)
output, err := oci.ParseImageSpecs(indexName)
require.NoError(t, err)
err = SaveReferrers(manifest, output)
require.NoError(t, err)
reg := &test.MockRegistryResolver{
Subject: subject,
MockResolver: &test.MockResolver{},
ImageNameStr: indexName,
}
require.NoError(t, err)
refResolver, err := oci.NewReferrersAttestationResolver(reg)
require.NoError(t, err)
attestations, err := refResolver.Attestations(ctx, attestation.VSAPredicateType)
require.NoError(t, err)
require.Len(t, attestations, 1)
}

View File

@@ -27,7 +27,7 @@ func TestGetTufTargetsMirror(t *testing.T) {
defer server.Close()
path := test.CreateTempDir(t, "", "tuf_temp")
m, err := NewTufMirror(embed.DevRoot, path, server.URL+"/metadata", server.URL+"/targets", tuf.NewMockVersionChecker())
m, err := NewTufMirror(embed.RootDev.Data, path, server.URL+"/metadata", server.URL+"/targets", tuf.NewMockVersionChecker())
assert.NoError(t, err)
targets, err := m.GetTufTargetMirrors()
@@ -50,8 +50,8 @@ func TestGetTufTargetsMirror(t *testing.T) {
ann, ok := layer.Annotations[tufFileAnnotation]
assert.True(t, ok)
parts := strings.Split(ann, ".")
// <digest>.filename.json
assert.Equal(t, len(parts), 3)
// <digest>.filename.<ext|optional>
assert.GreaterOrEqual(t, len(parts), 2)
}
}
}
@@ -61,7 +61,7 @@ func TestTargetDelegationMetadata(t *testing.T) {
defer server.Close()
path := test.CreateTempDir(t, "", "tuf_temp")
tm, err := NewTufMirror(embed.DevRoot, path, server.URL+"/metadata", server.URL+"/targets", tuf.NewMockVersionChecker())
tm, err := NewTufMirror(embed.RootDev.Data, path, server.URL+"/metadata", server.URL+"/targets", tuf.NewMockVersionChecker())
assert.NoError(t, err)
targets, err := tm.TufClient.LoadDelegatedTargets("test-role", "targets")
@@ -74,7 +74,7 @@ func TestGetDelegatedTargetMirrors(t *testing.T) {
defer server.Close()
path := test.CreateTempDir(t, "", "tuf_temp")
m, err := NewTufMirror(embed.DevRoot, path, server.URL+"/metadata", server.URL+"/targets", tuf.NewMockVersionChecker())
m, err := NewTufMirror(embed.RootDev.Data, path, server.URL+"/metadata", server.URL+"/targets", tuf.NewMockVersionChecker())
assert.NoError(t, err)
mirrors, err := m.GetDelegatedTargetMirrors()
@@ -97,8 +97,8 @@ func TestGetDelegatedTargetMirrors(t *testing.T) {
ann, ok := layer.Annotations[tufFileAnnotation]
assert.True(t, ok)
parts := strings.Split(ann, ".")
// <subdir>/<digest>.filename.json
assert.Equal(t, len(parts), 3)
// <subdir>/<digest>.filename.<ext|optional>
assert.GreaterOrEqual(t, len(parts), 2)
}
}
}

View File

@@ -7,8 +7,8 @@ import (
)
const (
DefaultMetadataURL = "https://docker.github.io/tuf-staging/metadata"
DefaultTargetsURL = "https://docker.github.io/tuf-staging/targets"
DefaultMetadataURL = "https://docker.github.io/tuf/metadata"
DefaultTargetsURL = "https://docker.github.io/tuf/targets"
tufMetadataMediaType = "application/vnd.tuf.metadata+json"
tufTargetMediaType = "application/vnd.tuf.target"
tufFileAnnotation = "tuf.io/filename"

21
pkg/oci/authn.go Normal file
View File

@@ -0,0 +1,21 @@
package oci
import (
ecr "github.com/awslabs/amazon-ecr-credential-helper/ecr-login"
"github.com/google/go-containerregistry/pkg/authn"
"github.com/google/go-containerregistry/pkg/v1/google"
"github.com/google/go-containerregistry/pkg/v1/remote"
)
func MultiKeychainOption() remote.Option {
return remote.WithAuthFromKeychain(MultiKeychainAll())
}
func MultiKeychainAll() authn.Keychain {
// Create a multi-keychain that will use the default Docker, Google, or ECR keychain
return authn.NewMultiKeychain(
authn.DefaultKeychain,
google.Keychain,
authn.NewKeychainFromHelper(ecr.NewECRHelper()),
)
}

View File

@@ -4,8 +4,8 @@ import (
"context"
"encoding/json"
"fmt"
"strings"
"github.com/docker/attest/pkg/attestation"
att "github.com/docker/attest/pkg/attestation"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/layout"
@@ -14,7 +14,7 @@ import (
// implementation of AttestationResolver that closes over attestations from an oci layout
type OCILayoutResolver struct {
*AttestationManifest
*attestation.AttestationManifest
*ImageSpec
}
@@ -29,7 +29,7 @@ func NewOCILayoutAttestationResolver(src *ImageSpec) (*OCILayoutResolver, error)
return r, nil
}
func (r *OCILayoutResolver) fetchAttestationManifest() (*AttestationManifest, error) {
func (r *OCILayoutResolver) fetchAttestationManifest() (*attestation.AttestationManifest, error) {
if r.AttestationManifest == nil {
m, err := attestationManifestFromOCILayout(r.Identifier, r.ImageSpec.Platform)
if err != nil {
@@ -42,29 +42,23 @@ func (r *OCILayoutResolver) fetchAttestationManifest() (*AttestationManifest, er
}
func (r *OCILayoutResolver) Attestations(ctx context.Context, predicateType string) ([]*att.Envelope, error) {
attestationImage := r.AttestationManifest.Image
layers, err := attestationImage.Layers()
if err != nil {
return nil, fmt.Errorf("failed to extract layers from attestation image: %w", err)
}
var envs []*att.Envelope
manifest := r.AttestationManifest.Manifest
for i, l := range manifest.Layers {
if l.Annotations[InTotoPredicateType] != predicateType {
continue
}
layer := layers[i]
mt, err := layer.MediaType()
dsseMediaType, err := attestation.DSSEMediaType(predicateType)
if err != nil {
return nil, fmt.Errorf("failed to get DSSE media type for predicate '%s': %w", predicateType, err)
}
for _, attestationLayer := range r.AttestationManifest.OriginalLayers {
mt, err := attestationLayer.Layer.MediaType()
if err != nil {
return nil, fmt.Errorf("failed to get layer media type: %w", err)
}
mts := string(mt)
if !strings.HasSuffix(mts, "+dsse") {
if mts != dsseMediaType {
continue
}
var env = new(att.Envelope)
// parse layer blob as json
r, err := layer.Uncompressed()
r, err := attestationLayer.Layer.Uncompressed()
if err != nil {
return nil, fmt.Errorf("failed to get layer contents: %w", err)
@@ -80,18 +74,18 @@ func (r *OCILayoutResolver) Attestations(ctx context.Context, predicateType stri
}
func (r *OCILayoutResolver) ImageName(ctx context.Context) (string, error) {
return r.Name, nil
return r.SubjectName, nil
}
func (r *OCILayoutResolver) ImageDigest(ctx context.Context) (string, error) {
return r.Digest, nil
func (r *OCILayoutResolver) ImageDescriptor(ctx context.Context) (*v1.Descriptor, error) {
return r.SubjectDescriptor, nil
}
func (r *OCILayoutResolver) ImagePlatform(ctx context.Context) (*v1.Platform, error) {
return r.ImageSpec.Platform, nil
}
func attestationManifestFromOCILayout(path string, platform *v1.Platform) (*AttestationManifest, error) {
func attestationManifestFromOCILayout(path string, platform *v1.Platform) (*attestation.AttestationManifest, error) {
idx, err := layout.ImageIndexFromPath(path)
if err != nil {
return nil, err
@@ -114,18 +108,19 @@ func attestationManifestFromOCILayout(path string, platform *v1.Platform) (*Atte
if err != nil {
return nil, fmt.Errorf("failed to extract IndexManifest from ImageIndex: %w", err)
}
var imageDigest string
var subjectDescriptor *v1.Descriptor
for _, mf := range mfs2.Manifests {
if mf.Platform.Equals(*platform) {
imageDigest = mf.Digest.String()
subjectDescriptor = &mf
break
}
}
for _, mf := range mfs2.Manifests {
if mf.Annotations[att.DockerReferenceType] != AttestationManifestType {
if mf.Annotations[att.DockerReferenceType] != attestation.AttestationManifestType {
continue
}
if mf.Annotations[att.DockerReferenceDigest] != imageDigest {
if mf.Annotations[att.DockerReferenceDigest] != subjectDescriptor.Digest.String() {
continue
}
@@ -133,17 +128,15 @@ func attestationManifestFromOCILayout(path string, platform *v1.Platform) (*Atte
if err != nil {
return nil, fmt.Errorf("failed to extract attestation image with digest %s: %w", mf.Digest.String(), err)
}
manifest, err := attestationImage.Manifest()
layers, err := attestation.GetAttestationsFromImage(attestationImage)
if err != nil {
return nil, fmt.Errorf("failed to get manifest: %w", err)
return nil, fmt.Errorf("failed to get attestations from image: %w", err)
}
attest := &AttestationManifest{
Name: name,
Image: attestationImage,
Manifest: manifest,
Descriptor: &mf,
Digest: imageDigest,
Platform: platform,
attest := &attestation.AttestationManifest{
OriginalLayers: layers,
OriginalDescriptor: &mf,
SubjectName: name,
SubjectDescriptor: subjectDescriptor,
}
return attest, nil
}

View File

@@ -6,10 +6,10 @@ import (
"fmt"
"strings"
"github.com/containerd/containerd/platforms"
"github.com/containerd/platforms"
"github.com/distribution/reference"
"github.com/docker/attest/pkg/attestation"
att "github.com/docker/attest/pkg/attestation"
"github.com/google/go-containerregistry/pkg/authn"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/remote"
"github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/common"
@@ -38,7 +38,7 @@ func ParsePlatform(platformStr string) (*v1.Platform, error) {
func WithOptions(ctx context.Context, platform *v1.Platform) []remote.Option {
// prepare options
options := []remote.Option{remote.WithAuthFromKeychain(authn.DefaultKeychain), remote.WithTransport(HttpTransport()), remote.WithContext(ctx)}
options := []remote.Option{MultiKeychainOption(), remote.WithTransport(HttpTransport()), remote.WithContext(ctx)}
// add in platform into remote Get operation; this might conflict with an explicit digest, but we are trying anyway
if platform != nil {
@@ -47,19 +47,19 @@ func WithOptions(ctx context.Context, platform *v1.Platform) []remote.Option {
return options
}
func ExtractEnvelopes(ia *AttestationManifest, predicateType string) ([]*att.Envelope, error) {
manifest := ia.Manifest
image := ia.Image
func ExtractEnvelopes(manifest *attestation.AttestationManifest, predicateType string) ([]*att.Envelope, error) {
var envs []*att.Envelope
layers, err := image.Layers()
dsseMediaType, err := attestation.DSSEMediaType(predicateType)
if err != nil {
return nil, fmt.Errorf("failed to get layers: %w", err)
return nil, fmt.Errorf("failed to get DSSE media type for predicate '%s': %w", predicateType, err)
}
for i, l := range manifest.Layers {
if (strings.HasPrefix(string(l.MediaType), "application/vnd.in-toto.")) &&
strings.HasSuffix(string(l.MediaType), "+dsse") &&
l.Annotations[InTotoPredicateType] == predicateType {
reader, err := layers[i].Uncompressed()
for _, attestationLayer := range manifest.OriginalLayers {
mt, err := attestationLayer.Layer.MediaType()
if err != nil {
return nil, fmt.Errorf("failed to get layer media type: %w", err)
}
if string(mt) == dsseMediaType {
reader, err := attestationLayer.Layer.Uncompressed()
if err != nil {
return nil, fmt.Errorf("failed to get layer contents: %w", err)
}
@@ -76,13 +76,13 @@ func ExtractEnvelopes(ia *AttestationManifest, predicateType string) ([]*att.Env
return envs, nil
}
func imageDigestForPlatform(ix *v1.IndexManifest, platform *v1.Platform) (string, error) {
func imageDescriptor(ix *v1.IndexManifest, platform *v1.Platform) (*v1.Descriptor, error) {
for _, m := range ix.Manifests {
if (m.MediaType == ocispec.MediaTypeImageManifest || m.MediaType == "application/vnd.docker.distribution.manifest.v2+json") && m.Platform.Equals(*platform) {
return m.Digest.String(), nil
return &m, nil
}
}
return "", errors.New(fmt.Sprintf("no image found for platform %v", platform))
return nil, errors.New(fmt.Sprintf("no image found for platform %v", platform))
}
func attestationDigestForDigest(ix *v1.IndexManifest, imageDigest string, attestType string) (string, error) {
@@ -148,3 +148,27 @@ func SplitDigest(digest string) (common.DigestSet, error) {
parts[0]: parts[1],
}, nil
}
func ReplaceTagInSpec(src *ImageSpec, digest v1.Hash) (*ImageSpec, error) {
newName, err := replaceTag(src.Identifier, digest)
if err != nil {
return nil, fmt.Errorf("failed to parse repo name: %w", err)
}
return &ImageSpec{
Identifier: newName,
Type: src.Type,
Platform: src.Platform,
}, nil
}
// so that the index tag is replaced with a tag unique to the image digest and doesn't overwrite it
func replaceTag(image string, digest v1.Hash) (string, error) {
if strings.HasPrefix(image, LocalPrefix) {
return image, nil
}
notag, err := WithoutTag(image)
if err != nil {
return "", nil
}
return fmt.Sprintf("%s:%s-%s.att", notag, digest.Algorithm, digest.Hex), nil
}

View File

@@ -4,6 +4,7 @@ import (
"path/filepath"
"testing"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/layout"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -75,14 +76,16 @@ func TestImageDigestForPlatform(t *testing.T) {
p, err := ParsePlatform("linux/amd64")
assert.NoError(t, err)
digest, err := imageDigestForPlatform(mfs2, p)
desc, err := imageDescriptor(mfs2, p)
assert.NoError(t, err)
digest := desc.Digest.String()
assert.Equal(t, "sha256:da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620", digest)
p, err = ParsePlatform("linux/arm64")
assert.NoError(t, err)
digest, err = imageDigestForPlatform(mfs2, p)
desc, err = imageDescriptor(mfs2, p)
assert.NoError(t, err)
digest = desc.Digest.String()
assert.Equal(t, "sha256:7a76cec943853f9f7105b1976afa1bf7cd5bb6afc4e9d5852dd8da7cf81ae86e", digest)
}
@@ -106,3 +109,31 @@ func TestWithoutTag(t *testing.T) {
})
}
}
func TestReplaceTag(t *testing.T) {
tc := []struct {
name string
expected string
}{
{name: "image:tag", expected: "index.docker.io/library/image:sha256-digest.att"},
{name: "image", expected: "index.docker.io/library/image:sha256-digest.att"},
{name: "image:sha256-digest.att", expected: "index.docker.io/library/image:sha256-digest.att"},
{name: "docker://image:tag", expected: "docker://index.docker.io/library/image:sha256-digest.att"},
{name: "image@sha256:166710df254975d4a6c4c407c315951c22753dcaa829e020a3fd5d18fff70dd2", expected: "index.docker.io/library/image:sha256-digest.att"},
{name: "oci://foobar", expected: "oci://foobar"},
{name: "docker://image@sha256:166710df254975d4a6c4c407c315951c22753dcaa829e020a3fd5d18fff70dd2", expected: "docker://index.docker.io/library/image:sha256-digest.att"},
{name: "docker://127.0.0.1:36555/repo:latest", expected: "docker://127.0.0.1:36555/repo:sha256-digest.att"},
}
digest := v1.Hash{
Algorithm: "sha256",
Hex: "digest",
}
for _, c := range tc {
t.Run(c.name, func(t *testing.T) {
replaced, err := replaceTag(c.name, digest)
require.NoError(t, err)
assert.Equal(t, c.expected, replaced)
})
}
}

View File

@@ -4,22 +4,20 @@ import (
"context"
"fmt"
"github.com/docker/attest/pkg/attestation"
att "github.com/docker/attest/pkg/attestation"
"github.com/google/go-containerregistry/pkg/name"
"github.com/google/go-containerregistry/pkg/v1/remote"
"github.com/pkg/errors"
)
type ReferrersResolver struct {
digest string
referrersRepo string
manifests []*AttestationManifest
*RegistryImageDetailsResolver
ImageDetailsResolver
}
func NewReferrersAttestationResolver(src *RegistryImageDetailsResolver, options ...func(*ReferrersResolver) error) (*ReferrersResolver, error) {
func NewReferrersAttestationResolver(src ImageDetailsResolver, options ...func(*ReferrersResolver) error) (*ReferrersResolver, error) {
res := &ReferrersResolver{
RegistryImageDetailsResolver: src,
ImageDetailsResolver: src,
}
for _, opt := range options {
err := opt(res)
@@ -37,80 +35,86 @@ func WithReferrersRepo(repo string) func(*ReferrersResolver) error {
}
}
func (r *ReferrersResolver) resolveAttestations(ctx context.Context) error {
if r.manifests == nil {
subjectRef, err := name.ParseReference(r.Identifier)
if err != nil {
return fmt.Errorf("failed to parse reference: %w", err)
}
subjectDigest, err := r.ImageDigest(ctx)
if err != nil {
return fmt.Errorf("failed to get digest: %w", err)
}
var referrersSubjectRef name.Digest
if r.referrersRepo != "" {
referrersSubjectRef, err = name.NewDigest(fmt.Sprintf("%s@%s", r.referrersRepo, subjectDigest))
if err != nil {
return fmt.Errorf("failed to create referrers reference: %w", err)
}
} else {
referrersSubjectRef = subjectRef.Context().Digest(subjectDigest)
}
referrersIndex, err := remote.Referrers(referrersSubjectRef)
if err != nil {
return fmt.Errorf("failed to get referrers: %w", err)
}
referrersIndexManifest, err := referrersIndex.IndexManifest()
if err != nil {
return fmt.Errorf("failed to get index manifest: %w", err)
}
if len(referrersIndexManifest.Manifests) == 0 {
return errors.New("no referrers found")
}
aManifests := make([]*AttestationManifest, 0)
for _, m := range referrersIndexManifest.Manifests {
remoteRef := referrersSubjectRef.Context().Digest(m.Digest.String())
attestationImage, err := remote.Image(remoteRef)
if err != nil {
return fmt.Errorf("failed to get referred image: %w", err)
}
manifest, err := attestationImage.Manifest()
if err != nil {
return fmt.Errorf("failed to get manifest: %w", err)
}
if manifest.Annotations[att.DockerReferenceType] != AttestationManifestType {
continue
}
if manifest.Annotations[att.DockerReferenceDigest] != subjectDigest {
continue
}
attest := &AttestationManifest{
Name: r.Identifier,
Image: attestationImage,
Manifest: manifest,
Descriptor: &m,
Digest: subjectDigest,
Platform: r.Platform,
}
aManifests = append(aManifests, attest)
}
if len(aManifests) == 0 {
return errors.New("no attestation manifests found")
}
r.manifests = aManifests
func (r *ReferrersResolver) resolveAttestations(ctx context.Context, predicateType string) ([]*attestation.AttestationManifest,
error) {
dsseMediaType, err := attestation.DSSEMediaType(predicateType)
if err != nil {
return nil, fmt.Errorf("failed to get DSSE media type for predicate '%s': %w", predicateType, err)
}
return nil
imageName, err := r.ImageName(ctx)
if err != nil {
return nil, fmt.Errorf("failed to get image name: %w", err)
}
subjectRef, err := name.ParseReference(imageName)
if err != nil {
return nil, fmt.Errorf("failed to parse reference: %w", err)
}
desc, err := r.ImageDescriptor(ctx)
if err != nil {
return nil, fmt.Errorf("failed to get descriptor: %w", err)
}
subjectDigest := desc.Digest.String()
if err != nil {
return nil, fmt.Errorf("failed to get digest: %w", err)
}
var referrersSubjectRef name.Digest
if r.referrersRepo != "" {
referrersSubjectRef, err = name.NewDigest(fmt.Sprintf("%s@%s", r.referrersRepo, subjectDigest))
if err != nil {
return nil, fmt.Errorf("failed to create referrers reference: %w", err)
}
} else {
referrersSubjectRef = subjectRef.Context().Digest(subjectDigest)
}
options := WithOptions(ctx, nil)
options = append(options, remote.WithFilter("artifactType", dsseMediaType))
referrersIndex, err := remote.Referrers(referrersSubjectRef, options...)
if err != nil {
return nil, fmt.Errorf("failed to get referrers: %w", err)
}
referrersIndexManifest, err := referrersIndex.IndexManifest()
if err != nil {
return nil, fmt.Errorf("failed to get index manifest: %w", err)
}
aManifests := make([]*attestation.AttestationManifest, 0)
for _, m := range referrersIndexManifest.Manifests {
remoteRef := referrersSubjectRef.Context().Digest(m.Digest.String())
attestationImage, err := remote.Image(remoteRef)
if err != nil {
return nil, fmt.Errorf("failed to get referred image: %w", err)
}
layers, err := attestation.GetAttestationsFromImage(attestationImage)
if err != nil {
return nil, fmt.Errorf("failed to get attestations from image: %w", err)
}
if len(layers) != 1 {
return nil, fmt.Errorf("expected exactly one layer, got %d", len(layers))
}
mt, err := layers[0].Layer.MediaType()
if err != nil {
return nil, fmt.Errorf("failed to get layer media type: %w", err)
}
if string(mt) != dsseMediaType {
return nil, fmt.Errorf("expected layer media type %s, got %s", dsseMediaType, mt)
}
attest := &attestation.AttestationManifest{
SubjectName: imageName,
OriginalLayers: layers,
OriginalDescriptor: &m,
SubjectDescriptor: desc,
}
aManifests = append(aManifests, attest)
}
return aManifests, nil
}
func (r *ReferrersResolver) Attestations(ctx context.Context, predicateType string) ([]*att.Envelope, error) {
err := r.resolveAttestations(ctx)
manifests, err := r.resolveAttestations(ctx, predicateType)
if err != nil {
return nil, fmt.Errorf("failed to resolve attestations: %w", err)
}
var envs []*att.Envelope
for _, attest := range r.manifests {
for _, attest := range manifests {
es, err := ExtractEnvelopes(attest, predicateType)
if err != nil {
return nil, fmt.Errorf("failed to extract envelopes: %w", err)

View File

@@ -2,9 +2,9 @@ package oci
import (
"context"
"encoding/json"
"fmt"
"github.com/docker/attest/pkg/attestation"
att "github.com/docker/attest/pkg/attestation"
"github.com/google/go-containerregistry/pkg/name"
v1 "github.com/google/go-containerregistry/pkg/v1"
@@ -13,12 +13,12 @@ import (
type RegistryResolver struct {
*RegistryImageDetailsResolver
*AttestationManifest
*attestation.AttestationManifest
}
type RegistryImageDetailsResolver struct {
*ImageSpec
digest string
descriptor *v1.Descriptor
}
func NewRegistryImageDetailsResolver(src *ImageSpec) (*RegistryImageDetailsResolver, error) {
@@ -41,24 +41,36 @@ func (r *RegistryImageDetailsResolver) ImagePlatform(ctx context.Context) (*v1.P
return r.Platform, nil
}
func (r *RegistryImageDetailsResolver) ImageDigest(ctx context.Context) (string, error) {
if r.digest == "" {
func (r *RegistryImageDetailsResolver) ImageDescriptor(ctx context.Context) (*v1.Descriptor, error) {
if r.descriptor == nil {
subjectRef, err := name.ParseReference(r.Identifier)
if err != nil {
return "", fmt.Errorf("failed to parse reference: %w", err)
return nil, fmt.Errorf("failed to parse reference: %w", err)
}
options := WithOptions(ctx, r.Platform)
desc, err := remote.Image(subjectRef, options...)
image, err := remote.Image(subjectRef, options...)
if err != nil {
return "", fmt.Errorf("failed to get image manifest: %w", err)
return nil, fmt.Errorf("failed to get image manifest: %w", err)
}
subjectDigest, err := desc.Digest()
digest, err := image.Digest()
if err != nil {
return "", fmt.Errorf("failed to get image digest: %w", err)
return nil, fmt.Errorf("failed to get image digest: %w", err)
}
size, err := image.Size()
if err != nil {
return nil, fmt.Errorf("failed to get image size: %w", err)
}
mediaType, err := image.MediaType()
if err != nil {
return nil, fmt.Errorf("failed to get image media type: %w", err)
}
r.descriptor = &v1.Descriptor{
Digest: digest,
Size: size,
MediaType: mediaType,
}
r.digest = subjectDigest.String()
}
return r.digest, nil
return r.descriptor, nil
}
func (r *RegistryResolver) Attestations(ctx context.Context, predicateType string) ([]*att.Envelope, error) {
@@ -72,7 +84,7 @@ func (r *RegistryResolver) Attestations(ctx context.Context, predicateType strin
return ExtractEnvelopes(r.AttestationManifest, predicateType)
}
func FetchAttestationManifest(ctx context.Context, image string, platform *v1.Platform) (*AttestationManifest, error) {
func FetchAttestationManifest(ctx context.Context, image string, platform *v1.Platform) (*attestation.AttestationManifest, error) {
// we want to get to the image index, so ignoring platform for now
options := WithOptions(ctx, nil)
ref, err := name.ParseReference(image)
@@ -87,10 +99,12 @@ func FetchAttestationManifest(ctx context.Context, image string, platform *v1.Pl
if err != nil {
return nil, fmt.Errorf("failed to get index manifest: %w", err)
}
digest, err := imageDigestForPlatform(indexManifest, platform)
subjectDescriptor, err := imageDescriptor(indexManifest, platform)
if err != nil {
return nil, fmt.Errorf("failed to obtain image for platform: %w", err)
}
digest := subjectDescriptor.Digest.String()
ref, err = name.ParseReference(fmt.Sprintf("%s@%s", ref.Context().Name(), digest))
if err != nil {
return nil, fmt.Errorf("failed to parse attestation reference: %w", err)
@@ -108,22 +122,20 @@ func FetchAttestationManifest(ctx context.Context, image string, platform *v1.Pl
if err != nil {
return nil, fmt.Errorf("failed to get attestation: %w", err)
}
manifest := new(v1.Manifest)
err = json.Unmarshal(remoteDescriptor.Manifest, manifest)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal attestation: %w", err)
}
attestationImage, err := remoteDescriptor.Image()
if err != nil {
return nil, fmt.Errorf("failed to get attestation image: %w", err)
}
attest := &AttestationManifest{
Name: image,
Image: attestationImage,
Manifest: manifest,
Descriptor: &remoteDescriptor.Descriptor,
Digest: digest,
Platform: platform,
layers, err := attestation.GetAttestationsFromImage(attestationImage)
if err != nil {
return nil, fmt.Errorf("failed to get attestations from image: %w", err)
}
attest := &attestation.AttestationManifest{
OriginalLayers: layers,
OriginalDescriptor: &remoteDescriptor.Descriptor,
SubjectName: image,
SubjectDescriptor: subjectDescriptor,
}
return attest, nil
}

View File

@@ -25,13 +25,13 @@ func TestRegistry(t *testing.T) {
u, err := url.Parse(server.URL)
require.NoError(t, err)
opts := &attestation.SigningOptions{
Replace: true,
SkipSubject: true,
}
attIdx, err := oci.SubjectIndexFromPath(oci.UnsignedTestImage)
opts := &attestation.SigningOptions{}
attIdx, err := oci.IndexFromPath(oci.UnsignedTestImage)
require.NoError(t, err)
signedIndex, err := attest.Sign(ctx, attIdx.Index, signer, opts)
signedManifests, err := attest.SignStatements(ctx, attIdx.Index, signer, opts)
require.NoError(t, err)
signedIndex := attIdx.Index
signedIndex, err = attestation.UpdateIndexImages(signedIndex, signedManifests)
require.NoError(t, err)
indexName := fmt.Sprintf("%s/repo:root", u.Host)
@@ -44,7 +44,8 @@ func TestRegistry(t *testing.T) {
resolver, err := policy.CreateImageDetailsResolver(spec)
require.NoError(t, err)
digest, err := resolver.ImageDigest(ctx)
desc, err := resolver.ImageDescriptor(ctx)
require.NoError(t, err)
digest := desc.Digest.String()
assert.True(t, strings.Contains(digest, "sha256:"))
}

View File

@@ -7,21 +7,6 @@ import (
v1 "github.com/google/go-containerregistry/pkg/v1"
)
type AttestationManifests struct {
Manifests []*AttestationManifest
}
type AttestationManifest struct {
// attestation image details
Image v1.Image
Manifest *v1.Manifest
Descriptor *v1.Descriptor
// details of subect image
Name string
Digest string
Platform *v1.Platform
}
type AttestationResolver interface {
ImageDetailsResolver
Attestations(ctx context.Context, mediaType string) ([]*att.Envelope, error)
@@ -30,25 +15,5 @@ type AttestationResolver interface {
type ImageDetailsResolver interface {
ImageName(ctx context.Context) (string, error)
ImagePlatform(ctx context.Context) (*v1.Platform, error)
ImageDigest(ctx context.Context) (string, error)
}
type MockResolver struct {
Envs []*att.Envelope
}
func (r MockResolver) Attestations(ctx context.Context, mediaType string) ([]*att.Envelope, error) {
return r.Envs, nil
}
func (r MockResolver) ImageName(ctx context.Context) (string, error) {
return "library/alpine:latest", nil
}
func (r MockResolver) ImageDigest(ctx context.Context) (string, error) {
return "sha256:test-digest", nil
}
func (r MockResolver) ImagePlatform(ctx context.Context) (*v1.Platform, error) {
return ParsePlatform("linux/amd64")
ImageDescriptor(ctx context.Context) (*v1.Descriptor, error)
}

View File

@@ -4,7 +4,6 @@ import (
"fmt"
"strings"
"github.com/google/go-containerregistry/pkg/authn"
"github.com/google/go-containerregistry/pkg/name"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/layout"
@@ -12,17 +11,15 @@ import (
)
const (
AttestationManifestType = "attestation-manifest"
InTotoPredicateType = "in-toto.io/predicate-type"
OciReferenceTarget = "org.opencontainers.image.ref.name"
LocalPrefix = "oci://"
RegistryPrefix = "docker://"
OCI SourceType = "OCI"
Docker SourceType = "Docker"
OciReferenceTarget = "org.opencontainers.image.ref.name"
LocalPrefix = "oci://"
RegistryPrefix = "docker://"
OCI SourceType = "OCI"
Docker SourceType = "Docker"
)
type SourceType string
type SubjectIndex struct {
type NamedIndex struct {
Index v1.ImageIndex
Name string
}
@@ -43,7 +40,7 @@ type ImageSpec struct {
Platform *v1.Platform
}
func SubjectIndexFromPath(path string) (*SubjectIndex, error) {
func IndexFromPath(path string) (*NamedIndex, error) {
wrapperIdx, err := layout.ImageIndexFromPath(path)
if err != nil {
return nil, fmt.Errorf("failed to load image index: %w", err)
@@ -60,38 +57,34 @@ func SubjectIndexFromPath(path string) (*SubjectIndex, error) {
if err != nil {
return nil, fmt.Errorf("failed to extract ImageIndex for digest %s: %w", idxDigest.String(), err)
}
return &SubjectIndex{
return &NamedIndex{
Index: idx,
Name: imageName,
}, nil
}
func SubjectIndexFromRemote(image string) (*SubjectIndex, error) {
func IndexFromRemote(image string) (*NamedIndex, error) {
ref, err := name.ParseReference(image)
if err != nil {
return nil, fmt.Errorf("failed to parse image reference %s: %w", image, err)
}
// Get the authenticator from the default Docker keychain
auth, err := authn.DefaultKeychain.Resolve(ref.Context())
if err != nil {
return nil, fmt.Errorf("failed to resolve auth for image %s: %w", image, err)
}
// Pull the image from the registry
idx, err := remote.Index(ref, remote.WithAuth(auth))
idx, err := remote.Index(ref, MultiKeychainOption())
if err != nil {
return nil, fmt.Errorf("failed to pull image %s: %w", image, err)
}
return &SubjectIndex{
return &NamedIndex{
Index: idx,
Name: image,
}, nil
}
func LoadSubjectIndex(input *ImageSpec) (*SubjectIndex, error) {
func LoadIndex(input *ImageSpec) (*NamedIndex, error) {
if input.Type == OCI {
return SubjectIndexFromPath(input.Identifier)
return IndexFromPath(input.Identifier)
} else {
return SubjectIndexFromRemote(input.Identifier)
return IndexFromRemote(input.Identifier)
}
}

View File

@@ -6,15 +6,13 @@ import (
"os"
"path"
"path/filepath"
"slices"
"strings"
"github.com/distribution/reference"
"github.com/docker/attest/pkg/config"
"github.com/docker/attest/pkg/oci"
)
func resolveLocalPolicy(opts *PolicyOptions, mapping *config.PolicyMapping) (*Policy, error) {
func resolveLocalPolicy(opts *PolicyOptions, mapping *config.PolicyMapping, imageName string, matchedName string) (*Policy, error) {
if opts.LocalPolicyDir == "" {
return nil, fmt.Errorf("local policy dir not set")
}
@@ -35,10 +33,13 @@ func resolveLocalPolicy(opts *PolicyOptions, mapping *config.PolicyMapping) (*Po
InputFiles: files,
Mapping: mapping,
}
if imageName != matchedName {
policy.ResolvedName = matchedName
}
return policy, nil
}
func resolveTufPolicy(opts *PolicyOptions, mapping *config.PolicyMapping) (*Policy, error) {
func resolveTufPolicy(opts *PolicyOptions, mapping *config.PolicyMapping, imageName string, matchedName string) (*Policy, error) {
files := make([]*PolicyFile, 0, len(mapping.Files))
for _, f := range mapping.Files {
filename := f.Path
@@ -55,32 +56,68 @@ func resolveTufPolicy(opts *PolicyOptions, mapping *config.PolicyMapping) (*Poli
InputFiles: files,
Mapping: mapping,
}
if imageName != matchedName {
policy.ResolvedName = matchedName
}
return policy, nil
}
func findPolicyMatch(named reference.Named, mappings *config.PolicyMappings) (*config.PolicyMapping, *config.PolicyMirror) {
if mappings != nil {
for _, mapping := range mappings.Policies {
if mapping.Origin.Domain == reference.Domain(named) &&
strings.HasPrefix(reference.Path(named), mapping.Origin.Prefix) {
return mapping, nil
}
}
// now search mirrors
for _, mirror := range mappings.Mirrors {
if (slices.Contains(mirror.Mirror.Domains, reference.Domain(named)) ||
slices.Contains(mirror.Mirror.Domains, "*")) &&
strings.HasPrefix(reference.Path(named), mirror.Mirror.Prefix) {
for _, mapping := range mappings.Policies {
if mapping.Id == mirror.PolicyId {
return mapping, nil
}
type matchType string
const (
matchTypePolicy matchType = "policy"
matchTypeMatchNoPolicy matchType = "match_no_policy"
matchTypeNoMatch matchType = "no_match"
)
type policyMatch struct {
matchType matchType
policy *config.PolicyMapping
rule *config.PolicyRule
matchedName string
}
func findPolicyMatch(imageName string, mappings *config.PolicyMappings) (*policyMatch, error) {
if mappings == nil {
return &policyMatch{matchType: matchTypeNoMatch, matchedName: imageName}, nil
}
return findPolicyMatchImpl(imageName, mappings, make(map[*config.PolicyRule]bool))
}
func findPolicyMatchImpl(imageName string, mappings *config.PolicyMappings, matched map[*config.PolicyRule]bool) (*policyMatch, error) {
for _, rule := range mappings.Rules {
if rule.Pattern.MatchString(imageName) {
switch {
case rule.PolicyId == "" && rule.Replacement == "":
return nil, fmt.Errorf("rule %s has neither policy-id nor rewrite", rule.Pattern)
case rule.PolicyId != "" && rule.Replacement != "":
return nil, fmt.Errorf("rule %s has both policy-id and rewrite", rule.Pattern)
case rule.PolicyId != "":
policy := mappings.Policies[rule.PolicyId]
if policy != nil {
return &policyMatch{
matchType: matchTypePolicy,
policy: policy,
rule: rule,
matchedName: imageName,
}, nil
}
return nil, mirror
return &policyMatch{
matchType: matchTypeMatchNoPolicy,
rule: rule,
matchedName: imageName,
}, nil
case rule.Replacement != "":
if matched[rule] {
return nil, fmt.Errorf("rewrite loop detected")
}
matched[rule] = true
imageName = rule.Pattern.ReplaceAllString(imageName, rule.Replacement)
return findPolicyMatchImpl(imageName, mappings, matched)
}
}
}
return nil, nil
return &policyMatch{matchType: matchTypeNoMatch, matchedName: imageName}, nil
}
func resolvePolicyById(opts *PolicyOptions) (*Policy, error) {
@@ -90,10 +127,9 @@ func resolvePolicyById(opts *PolicyOptions) (*Policy, error) {
return nil, fmt.Errorf("failed to load local policy mappings: %w", err)
}
if localMappings != nil {
for _, mapping := range localMappings.Policies {
if mapping.Id == opts.PolicyId {
return resolveLocalPolicy(opts, mapping)
}
policy := localMappings.Policies[opts.PolicyId]
if policy != nil {
return resolveLocalPolicy(opts, policy, "", "")
}
}
@@ -102,10 +138,9 @@ func resolvePolicyById(opts *PolicyOptions) (*Policy, error) {
if err != nil {
return nil, fmt.Errorf("failed to load tuf policy mappings by id: %w", err)
}
for _, mapping := range tufMappings.Policies {
if mapping.Id == opts.PolicyId {
return resolveTufPolicy(opts, mapping)
}
policy := tufMappings.Policies[opts.PolicyId]
if policy != nil {
return resolveTufPolicy(opts, policy, "", "")
}
return nil, fmt.Errorf("policy with id %s not found", opts.PolicyId)
}
@@ -124,7 +159,7 @@ func ResolvePolicy(ctx context.Context, detailsResolver oci.ImageDetailsResolver
if err != nil {
return nil, fmt.Errorf("failed to get image name: %w", err)
}
named, err := reference.ParseNormalizedNamed(imageName)
imageName, err = normalizeImageName(imageName)
if err != nil {
return nil, fmt.Errorf("failed to parse image name: %w", err)
}
@@ -132,9 +167,12 @@ func ResolvePolicy(ctx context.Context, detailsResolver oci.ImageDetailsResolver
if err != nil {
return nil, fmt.Errorf("failed to load local policy mappings: %w", err)
}
mapping, mirror := findPolicyMatch(named, localMappings)
if mapping != nil {
return resolveLocalPolicy(opts, mapping)
match, err := findPolicyMatch(imageName, localMappings)
if err != nil {
return nil, err
}
if match.matchType == matchTypePolicy {
return resolveLocalPolicy(opts, match.policy, imageName, match.matchedName)
}
// must check tuf
tufMappings, err := config.LoadTufMappings(opts.TufClient, opts.LocalTargetsDir)
@@ -143,20 +181,31 @@ func ResolvePolicy(ctx context.Context, detailsResolver oci.ImageDetailsResolver
}
// it's a mirror of a tuf policy
if mirror != nil {
if match.matchType == matchTypeMatchNoPolicy {
for _, mapping := range tufMappings.Policies {
if mapping.Id == mirror.PolicyId {
return resolveTufPolicy(opts, mapping)
if mapping.Id == match.rule.PolicyId {
return resolveTufPolicy(opts, mapping, imageName, match.matchedName)
}
}
}
// try to resolve a tuf policy directly
mapping, _ = findPolicyMatch(named, tufMappings)
if mapping == nil {
return nil, nil
match, err = findPolicyMatch(imageName, tufMappings)
if err != nil {
return nil, err
}
return resolveTufPolicy(opts, mapping)
if match.matchType == matchTypePolicy {
return resolveTufPolicy(opts, match.policy, imageName, match.matchedName)
}
return nil, nil
}
func normalizeImageName(imageName string) (string, error) {
named, err := reference.ParseNormalizedNamed(imageName)
if err != nil {
return "", fmt.Errorf("failed to parse image name: %w", err)
}
return named.Name(), nil
}
func CreateImageDetailsResolver(imageSource *oci.ImageSpec) (oci.ImageDetailsResolver, error) {

View File

@@ -0,0 +1,121 @@
package policy
import (
"path/filepath"
"testing"
"github.com/docker/attest/pkg/config"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestFindPolicyMatch(t *testing.T) {
testCases := []struct {
name string
imageName string
mappingDir string
expectError bool
expectedMatchType matchType
expectedPolicyID string
expectedImageName string
}{
{
name: "alpine",
mappingDir: "doi",
imageName: "docker.io/library/alpine",
expectedMatchType: matchTypePolicy,
expectedPolicyID: "docker-official-images",
expectedImageName: "docker.io/library/alpine",
},
{
name: "no match",
mappingDir: "doi",
imageName: "docker.io/something/else",
expectedMatchType: matchTypeNoMatch,
expectedImageName: "docker.io/something/else",
},
{
name: "match, no policy",
mappingDir: "local",
imageName: "docker.io/library/alpine",
expectedMatchType: matchTypeMatchNoPolicy,
expectedImageName: "docker.io/library/alpine",
},
{
name: "simple rewrite",
mappingDir: "simple-rewrite",
imageName: "mycoolmirror.org/library/alpine",
expectedMatchType: matchTypePolicy,
expectedPolicyID: "docker-official-images",
expectedImageName: "docker.io/library/alpine",
},
{
name: "rewrite no match",
mappingDir: "rewrite-to-no-match",
imageName: "mycoolmirror.org/library/alpine",
expectedMatchType: matchTypeNoMatch,
expectedImageName: "badredirect.org/alpine",
},
{
name: "rewrite to match, no policy",
mappingDir: "rewrite-to-local",
imageName: "mycoolmirror.org/library/alpine",
expectedMatchType: matchTypeMatchNoPolicy,
expectedImageName: "docker.io/library/alpine",
},
{
name: "multiple rewrites",
mappingDir: "rewrite-multiple",
imageName: "myevencoolermirror.org/library/alpine",
expectedMatchType: matchTypePolicy,
expectedPolicyID: "docker-official-images",
expectedImageName: "docker.io/library/alpine",
},
{
name: "invalid rewrites",
mappingDir: "rewrite-invalid",
imageName: "mycoolmirror.org/library/alpine",
expectError: true,
expectedMatchType: matchTypePolicy,
expectedPolicyID: "docker-official-images",
expectedImageName: "docker.io/library/alpine",
},
{
name: "rewrite loop",
mappingDir: "rewrite-loop",
imageName: "yin/alpine",
expectError: true,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
mappings, err := config.LoadLocalMappings(filepath.Join("testdata", "mappings", tc.mappingDir))
require.NoError(t, err)
match, err := findPolicyMatch(tc.imageName, mappings)
if tc.expectError {
require.Error(t, err)
// TODO: check error matches expected error message
return
}
require.NoError(t, err)
assert.Equal(t, tc.expectedMatchType, match.matchType)
if match.matchType == matchTypePolicy {
if assert.NotNil(t, match.policy) {
assert.Equal(t, tc.expectedPolicyID, match.policy.Id)
}
}
assert.Equal(t, tc.expectedImageName, match.matchedName)
})
}
}

View File

@@ -38,7 +38,7 @@ func TestRegoEvaluator_Evaluate(t *testing.T) {
re := policy.NewRegoEvaluator(true)
defaultResolver := oci.MockResolver{
defaultResolver := test.MockResolver{
Envs: []*attestation.Envelope{loadAttestation(t, ExampleAttestation)},
}
@@ -84,6 +84,7 @@ func TestRegoEvaluator_Evaluate(t *testing.T) {
src, err := oci.ParseImageSpec(imageName, oci.WithPlatform(platform.String()))
require.NoError(t, err)
resolver, err := policy.CreateImageDetailsResolver(src)
require.NoError(t, err)
policy, err := policy.ResolvePolicy(ctx, resolver, tc.policy)
if tc.errorStr != "" {
require.Error(t, err)
@@ -91,6 +92,7 @@ func TestRegoEvaluator_Evaluate(t *testing.T) {
return
}
require.NoErrorf(t, err, "failed to resolve policy")
require.NotNil(t, policy, "policy should not be nil")
result, err := re.Evaluate(ctx, tc.resolver, policy, input)
require.NoErrorf(t, err, "Evaluate failed")
@@ -107,8 +109,10 @@ func TestRegoEvaluator_Evaluate(t *testing.T) {
func TestLoadingMappings(t *testing.T) {
policyMappings, err := config.LoadLocalMappings(filepath.Join("testdata", "mock-tuf-allow"))
require.NoError(t, err)
assert.Equal(t, len(policyMappings.Mirrors), 1)
for _, mirror := range policyMappings.Mirrors {
assert.Equal(t, "docker-official-images", mirror.PolicyId)
assert.Equal(t, len(policyMappings.Rules), 3)
for _, mirror := range policyMappings.Rules {
if mirror.PolicyId != "" {
assert.Equal(t, "docker-official-images", mirror.PolicyId)
}
}
}

View File

@@ -0,0 +1,10 @@
version: v1
kind: policy-mapping
policies:
- id: docker-official-images
description: Docker Official Images
files:
- path: doi/policy.rego
rules:
- pattern: "^docker[.]io/library/(.*)$"
policy-id: docker-official-images

View File

@@ -0,0 +1,10 @@
version: v1
kind: policy-mapping
policies:
- id: local-policy
description: Local Policy
files:
- path: local-policy.rego
rules:
- pattern: "^docker[.]io/library/(.*)$"
policy-id: docker-official-images # note this policy does not exist in this file

View File

@@ -0,0 +1,13 @@
version: v1
kind: policy-mapping
policies:
- id: docker-official-images
description: Docker Official Images
files:
- path: doi/policy.rego
rules:
- pattern: "^docker[.]io/library/(.*)$"
policy-id: docker-official-images
- pattern: "^mycoolmirror[.]org/library/(.*)$"
rewrite: "docker.io/library/$1"
policy-id: docker-official-images # invalid to specify both rewrite and policy-id

View File

@@ -0,0 +1,14 @@
version: v1
kind: policy-mapping
policies:
- id: docker-official-images
description: Docker Official Images
files:
- path: doi/policy.rego
rules:
- pattern: "^docker[.]io/library/(.*)$"
policy-id: docker-official-images
- pattern: "^yin/(.*)$"
rewrite: "yang/$1"
- pattern: "^yang/(.*)$"
rewrite: "yin/$1"

View File

@@ -0,0 +1,14 @@
version: v1
kind: policy-mapping
policies:
- id: docker-official-images
description: Docker Official Images
files:
- path: doi/policy.rego
rules:
- pattern: "^docker[.]io/library/(.*)$"
policy-id: docker-official-images
- pattern: "^mycoolmirror[.]org/library/(.*)$"
rewrite: "docker.io/library/$1"
- pattern: "^myevencoolermirror[.]org/library/(.*)$"
rewrite: "mycoolmirror.org/library/$1"

View File

@@ -0,0 +1,12 @@
version: v1
kind: policy-mapping
policies:
- id: local-policy
description: Local Policy
files:
- path: local-policy.rego
rules:
- pattern: "^docker[.]io/library/(.*)$"
policy-id: docker-official-images # note this policy does not exist in this file
- pattern: "^mycoolmirror[.]org/library/(.*)$"
rewrite: "docker.io/library/$1"

View File

@@ -0,0 +1,12 @@
version: v1
kind: policy-mapping
policies:
- id: docker-official-images
description: Docker Official Images
files:
- path: doi/policy.rego
rules:
- pattern: "^docker[.]io/library/(.*)$"
policy-id: docker-official-images
- pattern: "^mycoolmirror[.]org/library/(.*)$"
rewrite: "badredirect.org/$1" # no matching rule for this rewrite

View File

@@ -0,0 +1,12 @@
version: v1
kind: policy-mapping
policies:
- id: docker-official-images
description: Docker Official Images
files:
- path: doi/policy.rego
rules:
- pattern: "^docker[.]io/library/(.*)$"
policy-id: docker-official-images
- pattern: "^mycoolmirror[.]org/library/(.*)$"
rewrite: "docker.io/library/$1"

View File

@@ -2,15 +2,16 @@
version: v1
kind: policy-mapping
policies:
- origin:
domain: docker.io
prefix: library/
id: docker-official-images
- id: docker-official-images
description: Docker Official Images
attestations:
repo: "localhost:5001/library-refs"
files:
- path: doi/policy.rego
mirrors:
- policy-id: docker-official-images
mirror:
domains: [localhost:5001, registry.local:5000]
prefix: ""
rules:
- pattern: "^docker[.]io/library/(.*)$"
policy-id: docker-official-images
- pattern: ^localhost:5001/(.*)$
rewrite: docker.io/library/$1
- pattern: ^registry[.]local:5000/(.*)$
rewrite: docker.io/library/$1

View File

@@ -2,17 +2,16 @@
version: v1
kind: policy-mapping
policies:
- origin:
domain: docker.io
prefix: library/
id: docker-official-images
- id: docker-official-images
description: Docker Official Images
attestations:
repo: "localhost:5001/library-refs"
files:
- path: doi/policy.rego
mirrors:
- policy-id: docker-official-images
mirror:
domains: [localhost:5001, registry.local:5000]
prefix: ""
rules:
- pattern: "^docker[.]io/library/(.*)$"
policy-id: docker-official-images
- pattern: ^localhost:5001/(.*)$
rewrite: docker.io/library/$1
- pattern: ^registry[.]local:5000/(.*)$
rewrite: docker.io/library/$1

View File

@@ -2,10 +2,10 @@
version: v1
kind: policy-mapping
policies:
- origin:
domain: docker.io
prefix: library/
id: docker-official-images
- id: docker-official-images
description: Docker Official Images
files:
- path: doi/policy.rego
rules:
- pattern: "^docker[.]io/library/(.*)$"
policy-id: docker-official-images

View File

@@ -2,10 +2,10 @@
version: v1
kind: policy-mapping
policies:
- origin:
domain: docker.io
prefix: library/
id: docker-official-images
- id: docker-official-images
description: Docker Official Images
files:
- path: doi/policy.rego
rules:
- pattern: "^docker[.]io/library/(.*)$"
policy-id: docker-official-images

View File

@@ -2,10 +2,10 @@
version: v1
kind: policy-mapping
policies:
- origin:
domain: docker.io
prefix: library/
id: docker-official-images
- id: docker-official-images
description: Docker Official Images
files:
- path: doi/policy.rego
rules:
- pattern: "^docker[.]io/library/(.*)$"
policy-id: docker-official-images

View File

@@ -36,9 +36,10 @@ type PolicyOptions struct {
}
type Policy struct {
InputFiles []*PolicyFile
Query string
Mapping *config.PolicyMapping
InputFiles []*PolicyFile
Query string
Mapping *config.PolicyMapping
ResolvedName string
}
type PolicyInput struct {

28
pkg/signerverifier/gcp.go Normal file
View File

@@ -0,0 +1,28 @@
package signerverifier
import (
"context"
"fmt"
"github.com/secure-systems-lab/go-securesystemslib/dsse"
gcpsigner "github.com/sigstore/sigstore/pkg/signature/kms/gcp"
"google.golang.org/api/option"
)
// using GCP KMS
// reference should be in the format projects/[PROJECT_ID]/locations/[LOCATION]/keyRings/[KEY_RING]/cryptoKeys/[KEY]/cryptoKeyVersions/[VERSION]
func GetGCPSigner(ctx context.Context, reference string, opts ...option.ClientOption) (dsse.SignerVerifier, error) {
reference = fmt.Sprintf("gcpkms://%s", reference)
sv, err := gcpsigner.LoadSignerVerifier(ctx, reference, opts...)
if err != nil {
return nil, fmt.Errorf("error loading gcp signer verifier: %w", err)
}
cs, _, err := sv.CryptoSigner(ctx, func(err error) {})
if err != nil {
return nil, fmt.Errorf("error getting gcp crypto signer: %w", err)
}
signer := &ECDSA256_SignerVerifier{
Signer: cs,
}
return signer, nil
}

View File

@@ -0,0 +1,45 @@
//go:build e2e
package signerverifier
import (
"context"
"crypto/ecdsa"
"testing"
"github.com/docker/attest/internal/util"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
const publicKeyPEM = `-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMswW3iu7PR/rWTQjlhVmUsPK7rF
k2s4SO3XbQ2GG2alm289SUUpmBAuVxvT8muYQ8HC/QzixzyTACTXsBDjQg==
-----END PUBLIC KEY-----`
// to run locally, we need to impersonate the GCP service account
// gcloud auth application-default login --impersonate-service-account attest-kms-test@attest-kms-test.iam.gserviceaccount.com
func TestGCPKMS_Signer(t *testing.T) {
// create a new signer
ctx := context.TODO()
ref := "projects/attest-kms-test/locations/us-west1/keyRings/attest-kms-test/cryptoKeys/test-signing-key/cryptoKeyVersions/1"
signer, err := GetGCPSigner(ctx, ref)
require.NoError(t, err)
msg := []byte("hello world")
hash := util.SHA256(msg)
// sign message digest
sig, err := signer.Sign(ctx, hash)
require.NoError(t, err)
assert.NotEmpty(t, sig)
// get Key ID from signer
keyId, err := signer.KeyID()
require.NoError(t, err)
assert.NotEmpty(t, keyId)
publicKey, err := Parse([]byte(publicKeyPEM))
require.NoError(t, err)
// verify payload ecdsa signature
ok := ecdsa.VerifyASN1(publicKey, hash, sig)
assert.True(t, ok)
}

View File

@@ -21,7 +21,7 @@ func ExampleNewTufClient_registry() {
metadataURI := "registry-1.docker.io/docker/tuf-metadata:latest"
targetsURI := "registry-1.docker.io/docker/tuf-targets"
registryClient, err := tuf.NewTufClient(embed.StagingRoot, tufOutputPath, metadataURI, targetsURI, tuf.NewMockVersionChecker())
registryClient, err := tuf.NewTufClient(embed.RootStaging.Data, tufOutputPath, metadataURI, targetsURI, tuf.NewMockVersionChecker())
if err != nil {
panic(err)
}

View File

@@ -10,6 +10,7 @@ import (
"strings"
"time"
"github.com/docker/attest/pkg/oci"
"github.com/google/go-containerregistry/pkg/authn"
"github.com/google/go-containerregistry/pkg/crane"
v1 "github.com/google/go-containerregistry/pkg/v1"
@@ -124,7 +125,7 @@ func (d *RegistryFetcher) getManifest(ref string) ([]byte, error) {
crane.WithUserAgent(d.httpUserAgent),
crane.WithTransport(transportWithTimeout(d.timeout)),
crane.WithAuth(authn.Anonymous),
crane.WithAuthFromKeychain(authn.DefaultKeychain))
crane.WithAuthFromKeychain(oci.MultiKeychainAll()))
if err != nil {
return nil, err
}
@@ -144,7 +145,7 @@ func (d *RegistryFetcher) pullFileLayer(ref string, maxLength int64) ([]byte, er
crane.WithUserAgent(d.httpUserAgent),
crane.WithTransport(transportWithTimeout(d.timeout)),
crane.WithAuth(authn.Anonymous),
crane.WithAuthFromKeychain(authn.DefaultKeychain))
crane.WithAuthFromKeychain(oci.MultiKeychainAll()))
if err != nil {
return nil, err
}

View File

@@ -11,7 +11,7 @@ import (
"github.com/docker/attest/internal/embed"
"github.com/docker/attest/internal/util"
"github.com/google/go-containerregistry/pkg/authn"
"github.com/docker/attest/pkg/oci"
"github.com/google/go-containerregistry/pkg/crane"
"github.com/google/go-containerregistry/pkg/name"
v1 "github.com/google/go-containerregistry/pkg/v1"
@@ -22,7 +22,6 @@ import (
"github.com/google/go-containerregistry/pkg/v1/static"
"github.com/google/go-containerregistry/pkg/v1/types"
"github.com/stretchr/testify/assert"
"github.com/testcontainers/testcontainers-go"
"github.com/testcontainers/testcontainers-go/modules/registry"
"github.com/theupdateframework/go-tuf/v2/metadata"
"github.com/theupdateframework/go-tuf/v2/metadata/config"
@@ -52,7 +51,7 @@ func TestRegistryFetcher(t *testing.T) {
delegatedDir := CreateTempDir(t, dir, delegatedRole)
delegatedTargetFile := fmt.Sprintf("%s/%s", delegatedRole, targetFile)
cfg, err := config.New(metadataRepo, embed.DevRoot)
cfg, err := config.New(metadataRepo, embed.RootDev.Data)
assert.NoError(t, err)
cfg.Fetcher = NewRegistryFetcher(metadataRepo, metadataImgTag, targetsRepo)
@@ -342,7 +341,7 @@ func TestGetManifest(t *testing.T) {
// RunTestRegistry starts a registry testcontainer for TUF on OCI testdata
func RunTestRegistry(t *testing.T) (*registry.RegistryContainer, *url.URL) {
registryContainer, err := registry.RunContainer(context.Background(), testcontainers.WithImage("registry:2.8.3"))
registryContainer, err := registry.Run(context.Background(), "registry:2.8.3")
if err != nil {
t.Fatalf("failed to start container: %s", err)
}
@@ -407,13 +406,13 @@ func LoadRegistryTestData(t *testing.T, registry *url.URL, path string) {
if err != nil {
t.Fatal(err)
}
err = remote.Write(ref, img, remote.WithAuthFromKeychain(authn.DefaultKeychain))
err = remote.Write(ref, img, oci.MultiKeychainOption())
if err != nil {
t.Fatal(err)
}
} else if len(mf.Manifests) > 1 {
// delegated target
err = remote.WriteIndex(ref, tIdx, remote.WithAuthFromKeychain(authn.DefaultKeychain))
err = remote.WriteIndex(ref, tIdx, oci.MultiKeychainOption())
if err != nil {
t.Fatal(err)
}
@@ -441,5 +440,5 @@ func LoadMetadata(path, host, repo, tag string) error {
if err != nil {
return err
}
return remote.Write(ref, img, remote.WithAuthFromKeychain(authn.DefaultKeychain))
return remote.Write(ref, img, oci.MultiKeychainOption())
}

View File

@@ -11,6 +11,7 @@ import (
"strings"
"time"
"github.com/docker/attest/internal/embed"
"github.com/docker/attest/internal/util"
"github.com/theupdateframework/go-tuf/v2/metadata"
"github.com/theupdateframework/go-tuf/v2/metadata/config"
@@ -26,6 +27,13 @@ const (
OciSource TufSource = "oci"
)
var (
DockerTufRootProd = embed.RootProd
DockerTufRootStaging = embed.RootStaging
DockerTufRootDev = embed.RootDev
DockerTufRootDefault = embed.RootDefault
)
type TUFClient interface {
DownloadTarget(target, filePath string) (actualFilePath string, data []byte, err error)
}
@@ -227,3 +235,8 @@ func ensureTrailingSlash(url string) string {
}
return url + "/"
}
// GetEmbeddedTufRoot returns the embedded TUF root based on the given root name
func GetEmbeddedTufRoot(root string) (*embed.EmbeddedRoot, error) {
return embed.GetRootFromName(root)
}

View File

@@ -65,17 +65,17 @@ func TestRootInit(t *testing.T) {
}
for _, tc := range testCases {
_, err := NewTufClient(embed.DevRoot, tufPath, tc.metadataSource, tc.targetsSource, alwaysGoodVersionChecker)
_, err := NewTufClient(embed.RootDev.Data, tufPath, tc.metadataSource, tc.targetsSource, alwaysGoodVersionChecker)
assert.NoErrorf(t, err, "Failed to create TUF client: %v", err)
// recreation should work with same root
_, err = NewTufClient(embed.DevRoot, tufPath, tc.metadataSource, tc.targetsSource, alwaysGoodVersionChecker)
_, err = NewTufClient(embed.RootDev.Data, tufPath, tc.metadataSource, tc.targetsSource, alwaysGoodVersionChecker)
assert.NoErrorf(t, err, "Failed to recreate TUF client: %v", err)
_, err = NewTufClient([]byte("broken"), tufPath, tc.metadataSource, tc.targetsSource, alwaysGoodVersionChecker)
assert.Errorf(t, err, "Expected error recreating TUF client with broken root: %v", err)
_, err = NewTufClient(embed.DevRoot, tufPath, tc.metadataSource, tc.targetsSource, alwaysBadVersionChecker)
_, err = NewTufClient(embed.RootDev.Data, tufPath, tc.metadataSource, tc.targetsSource, alwaysBadVersionChecker)
assert.Errorf(t, err, "Expected error creating TUF client with bad attest version: %v", err)
}
}
@@ -111,7 +111,7 @@ func TestDownloadTarget(t *testing.T) {
}
for _, tc := range testCases {
tufClient, err := NewTufClient(embed.DevRoot, tufPath, tc.metadataSource, tc.targetsSource, alwaysGoodVersionChecker)
tufClient, err := NewTufClient(embed.RootDev.Data, tufPath, tc.metadataSource, tc.targetsSource, alwaysGoodVersionChecker)
assert.NoErrorf(t, err, "Failed to create TUF client: %v", err)
// get trusted tuf metadata
@@ -133,3 +133,24 @@ func TestDownloadTarget(t *testing.T) {
assert.NoError(t, err)
}
}
func TestGetEmbeddedTufRootBytes(t *testing.T) {
dev, err := GetEmbeddedTufRoot("dev")
assert.NoError(t, err)
staging, err := GetEmbeddedTufRoot("staging")
assert.NoError(t, err)
assert.NotEqual(t, dev.Data, staging.Data)
prod, err := GetEmbeddedTufRoot("prod")
assert.NoError(t, err)
assert.NotEqual(t, dev.Data, prod.Data)
assert.NotEqual(t, staging.Data, prod.Data)
def, err := GetEmbeddedTufRoot("")
assert.NoError(t, err)
assert.Equal(t, def.Data, prod.Data)
_, err = GetEmbeddedTufRoot("invalid")
assert.Error(t, err)
}

View File

@@ -1,11 +1,10 @@
# map repos to policies
version: v1
kind: policy-mapping
policies:
- origin:
domain: docker.io
prefix: library/
id: test-images
- id: test-images
description: Local test images
files:
- path: doi/policy.rego
- path: policy.rego
rules:
- pattern: ".*"
policy-id: test-images

View File

@@ -0,0 +1,12 @@
version: v1
kind: policy-mapping
policies:
- id: test-images
description: Local test images
files:
- path: policy.rego
rules:
- pattern: "^docker[.]io/library/test-image$"
policy-id: test-images
- pattern: "^mirror[.]org/library/(.*)$"
rewrite: docker.io/library/$1

View File

@@ -0,0 +1,54 @@
package attest
import rego.v1
keys := [{
"id": "6b241993defaba26558c64f94a94303ce860e7ad9163d801495c91cf57197c75",
"key": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEZmicqYSY38DprGr42jU0V3ND0ROj\nzSRH1+yjsxhh0bi52Hh/DuOhrSq2KJ5a09lW3ybnDjljowbkof0Y1i9Oow==\n-----END PUBLIC KEY-----",
"from": "2023-12-15T14:00:00Z",
"to": null,
# this key is still active
"status": "active",
"signing-format": "dssev1",
}]
provs(pred) := p if {
res := attest.fetch(pred)
not res.error
p := res.value
}
atts := union({
provs("https://slsa.dev/provenance/v0.2"),
provs("https://spdx.dev/Document"),
})
opts := {"keys": keys}
statements contains s if {
some att in atts
res := attest.verify(att, opts)
not res.error
s := res.value
}
subjects contains subject if {
some statement in statements
some subject in statement.subject
}
success if {
print("input:",input)
true
}
result := {
"success": success,
"violations": set(),
"summary": {
"subjects": subjects,
"slsa_levels": ["SLSA_BUILD_LEVEL_3"],
"verifier": "docker-official-images",
"policy_uri": "https://docker.com/official/policy/v0.1",
},
}

View File

@@ -1,11 +1,10 @@
# map repos to policies
version: v1
kind: policy-mapping
policies:
- origin:
domain: docker.io
prefix: library/
id: test-images
- id: test-images
description: Local test images
files:
- path: doi/policy.rego
- path: policy.rego
rules:
- pattern: ".*"
policy-id: test-images

View File

@@ -1,16 +1,10 @@
# map repos to policies
version: v1
kind: policy-mapping
policies:
- origin:
domain: docker.io
prefix: library/
id: test-images
- id: test-images
description: Local test images
files:
- path: doi/policy.rego
mirrors:
- policy-id: test-images
mirror:
domains: ["*"]
prefix: ""
- path: policy.rego
rules:
- pattern: ".*"
policy-id: test-images

View File

@@ -1,29 +1,18 @@
# map repos to policies
version: v1
kind: policy-mapping
policies:
- origin:
domain: docker.io
prefix: library/
id: test-images
description: Local test images
- id: docker-official-images
description: Docker Official Images
files:
- path: "doi/policy.rego"
mirrors:
- policy-id: test-images
mirror:
domains: ["*"]
prefix: "repo"
- policy-id: test-images
mirror:
domains: ["*"]
prefix: "library/"
- policy-id: test-images
mirror:
domains: ["*"]
prefix: "test-image"
- policy-id: test-images
mirror:
domains: ["*"]
prefix: "image-signer-verifier-test"
- path: doi/policy.rego
rules:
- pattern: "^docker[.]io/library/(.*)$"
policy-id: docker-official-images
- pattern: "repo$"
policy-id: docker-official-images
- pattern: "test-image$"
policy-id: docker-official-images
- pattern: "image-signer-verifier-test$"
policy-id: docker-official-images
- pattern: "library/(.*)$"
rewrite: docker.io/library/$1

View File

@@ -0,0 +1 @@
{"signatures":[{"keyid":"76d0a7e1ff8617ce99627d0fa5c9809f2c0f0d52e0bf65c7b84c031608d25221","sig":"3065023079fce0ddea385d0e5b6eed0da688946f417d1c1bf6397edaa44279bf948d6de41daf5e0852069900f363175abd95959b023100d2b950cb3f39cc4df8140d2ec3c60d81d2811827fbc61034786cd877586f6ab5f9ba03ad95d7de58e9241917d79687a9"},{"keyid":"beac53949c4cf075824edede7d41715941f524db247d1b455a2389d7490ecd72","sig":""}],"signed":{"_type":"root","consistent_snapshot":true,"expires":"2034-06-12T17:21:13Z","keys":{"76d0a7e1ff8617ce99627d0fa5c9809f2c0f0d52e0bf65c7b84c031608d25221":{"keytype":"ecdsa","keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE3+asmp2GD6UijwWvMezwVG/BwFLuQa3o\nT6eRxFvkILGpVDbZ92ZYWidHl9LZ/eJUjhIjuVEkNVKoenw5KjKl8veP3MthZrQA\nSkYytOIwkidZo9Rk2dczbDcFSJvLGsmd\n-----END PUBLIC KEY-----\n"},"scheme":"ecdsa-sha2-nistp384","x-tuf-on-ci-keyowner":"@mrjoelkamp"},"bdd1703ecbde8812614b112a6551d58de3ad681048fd90fca2a3e491edd8afe5":{"keytype":"ecdsa","keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEgDpP6O0sEt2R+l84WlfmqPBsFSby\nxJsJ6YmeUVgDk/wk9++8IAR6YBYewaKye56gMnIYjTFbyOI8WomA2NQFBw==\n-----END PUBLIC KEY-----\n"},"scheme":"ecdsa-sha2-nistp256","x-tuf-on-ci-online-uri":"awskms:arn:aws:kms:us-east-1:175142243308:key/fbd8dab6-5677-4b57-87e6-8369c45b3b61"},"beac53949c4cf075824edede7d41715941f524db247d1b455a2389d7490ecd72":{"keytype":"ecdsa","keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEERet/8hs3WHIXyOXNzhLpTOz6DBx\n7zzHnenJgV/TB0dRMAx6j9UVRvlEkh5OcYuktNeqnLpHce1rLjLjpiRPVg==\n-----END PUBLIC KEY-----\n"},"scheme":"ecdsa-sha2-nistp256","x-tuf-on-ci-keyowner":"@jonnystoten"}},"roles":{"root":{"keyids":["76d0a7e1ff8617ce99627d0fa5c9809f2c0f0d52e0bf65c7b84c031608d25221","beac53949c4cf075824edede7d41715941f524db247d1b455a2389d7490ecd72"],"threshold":1},"snapshot":{"keyids":["bdd1703ecbde8812614b112a6551d58de3ad681048fd90fca2a3e491edd8afe5"],"threshold":1,"x-tuf-on-ci-expiry-period":3650,"x-tuf-on-ci-signing-period":60},"targets":{"keyids":["76d0a7e1ff8617ce99627d0fa5c9809f2c0f0d52e0bf65c7b84c031608d25221","beac53949c4cf075824edede7d41715941f524db247d1b455a2389d7490ecd72"],"threshold":1},"timestamp":{"keyids":["bdd1703ecbde8812614b112a6551d58de3ad681048fd90fca2a3e491edd8afe5"],"threshold":1,"x-tuf-on-ci-expiry-period":3650,"x-tuf-on-ci-signing-period":60}},"spec_version":"1.0.31","version":2,"x-tuf-on-ci-expiry-period":3650,"x-tuf-on-ci-signing-period":60}}

View File

@@ -0,0 +1 @@
{"signatures":[{"keyid":"bdd1703ecbde8812614b112a6551d58de3ad681048fd90fca2a3e491edd8afe5","sig":"304502204019c08b30b7525b95c4010e5c1420c5618c18d5b0719fb1d9392ef93322ca4e022100924ec18242ba21edcc2c7ad92ee13a38a6f4a8e1315c588eb9eb2d0bce0a1a80"}],"signed":{"_type":"timestamp","expires":"2034-06-23T12:47:16Z","meta":{"snapshot.json":{"version":7}},"spec_version":"1.0.31","version":7}}

View File

@@ -1 +0,0 @@
{"signatures":[{"keyid":"198f00ff96ea7cbfa7eac480cc9bfc43ce13bb434b901011ab777856533997d3","sig":"3044022039b56cd2e3597df74e57d200a652ba020cdc9a8cd050bd65b5f8e2640d50691d02205e073e4b6fc260acc64327a331e4440601af5b1cbff594ea91cf7b70d5828fb1"}],"signed":{"_type":"snapshot","expires":"2034-04-03T15:59:47Z","meta":{"targets.json":{"version":5},"test-role.json":{"version":3}},"spec_version":"1.0.31","version":6}}

View File

@@ -1 +0,0 @@
{"signatures":[{"keyid":"198f00ff96ea7cbfa7eac480cc9bfc43ce13bb434b901011ab777856533997d3","sig":"3045022011f2afa9b448fcbbac983c11fc3e264e95d5d7a9c9527b09d83a316ee762635f022100d05197a78ccc7a713ebdb0bccb44844f67a7c5208af8d346e201064b7ce11055"}],"signed":{"_type":"timestamp","expires":"2034-04-03T15:59:47Z","meta":{"snapshot.json":{"version":6}},"spec_version":"1.0.31","version":6}}

View File

@@ -1,42 +1,42 @@
{
"signatures": [
{
"keyid": "b7474a42f2588fa92ed4a2ebea6047a7b1b2f7351f1cfe0912732c0d0fb0fc09",
"sig": "3064023037bbb03c3472b140572a7d5a2895bd80e74435bbcb7053949731f81b104c6d05a0876590cd6a2e94d7ed619426a2f6fa02303adc8c9006fa5506fdd7ea87d2960074a537ad8bf2459f2863e806b47682cbb2f9b01b7502eaf5437a1a68fdaaeac114"
"keyid": "76d0a7e1ff8617ce99627d0fa5c9809f2c0f0d52e0bf65c7b84c031608d25221",
"sig": "3065023000f7d0a866576e94eaabc173b9233d4c8fcfa495527088f9022dff5a553f7a457da1015a6d0fc714f84848ec627387360231009fa70b2eebbe15241a2ec9b96a094ebd28661e30b8c3d1eab8d694df2b340bda511c489393630c9a9dacde42c99e9fa1"
}
],
"signed": {
"_type": "root",
"consistent_snapshot": true,
"expires": "2034-04-02T17:00:22Z",
"expires": "2034-05-29T20:14:11Z",
"keys": {
"198f00ff96ea7cbfa7eac480cc9bfc43ce13bb434b901011ab777856533997d3": {
"keytype": "ecdsa",
"keyval": {
"public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEgDpP6O0sEt2R+l84WlfmqPBsFSby\nxJsJ6YmeUVgDk/wk9++8IAR6YBYewaKye56gMnIYjTFbyOI8WomA2NQFBw==\n-----END PUBLIC KEY-----\n"
},
"scheme": "ecdsa-sha2-nistp256",
"x-tuf-on-ci-online-uri": "awskms:arn:aws:kms:us-east-1:175142243308:key/fbd8dab6-5677-4b57-87e6-8369c45b3b61"
},
"b7474a42f2588fa92ed4a2ebea6047a7b1b2f7351f1cfe0912732c0d0fb0fc09": {
"76d0a7e1ff8617ce99627d0fa5c9809f2c0f0d52e0bf65c7b84c031608d25221": {
"keytype": "ecdsa",
"keyval": {
"public": "-----BEGIN PUBLIC KEY-----\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE3+asmp2GD6UijwWvMezwVG/BwFLuQa3o\nT6eRxFvkILGpVDbZ92ZYWidHl9LZ/eJUjhIjuVEkNVKoenw5KjKl8veP3MthZrQA\nSkYytOIwkidZo9Rk2dczbDcFSJvLGsmd\n-----END PUBLIC KEY-----\n"
},
"scheme": "ecdsa-sha2-nistp384",
"x-tuf-on-ci-keyowner": "@mrjoelkamp"
},
"bdd1703ecbde8812614b112a6551d58de3ad681048fd90fca2a3e491edd8afe5": {
"keytype": "ecdsa",
"keyval": {
"public": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEgDpP6O0sEt2R+l84WlfmqPBsFSby\nxJsJ6YmeUVgDk/wk9++8IAR6YBYewaKye56gMnIYjTFbyOI8WomA2NQFBw==\n-----END PUBLIC KEY-----\n"
},
"scheme": "ecdsa-sha2-nistp256",
"x-tuf-on-ci-online-uri": "awskms:arn:aws:kms:us-east-1:175142243308:key/fbd8dab6-5677-4b57-87e6-8369c45b3b61"
}
},
"roles": {
"root": {
"keyids": [
"b7474a42f2588fa92ed4a2ebea6047a7b1b2f7351f1cfe0912732c0d0fb0fc09"
"76d0a7e1ff8617ce99627d0fa5c9809f2c0f0d52e0bf65c7b84c031608d25221"
],
"threshold": 1
},
"snapshot": {
"keyids": [
"198f00ff96ea7cbfa7eac480cc9bfc43ce13bb434b901011ab777856533997d3"
"bdd1703ecbde8812614b112a6551d58de3ad681048fd90fca2a3e491edd8afe5"
],
"threshold": 1,
"x-tuf-on-ci-expiry-period": 3650,
@@ -44,13 +44,13 @@
},
"targets": {
"keyids": [
"b7474a42f2588fa92ed4a2ebea6047a7b1b2f7351f1cfe0912732c0d0fb0fc09"
"76d0a7e1ff8617ce99627d0fa5c9809f2c0f0d52e0bf65c7b84c031608d25221"
],
"threshold": 1
},
"timestamp": {
"keyids": [
"198f00ff96ea7cbfa7eac480cc9bfc43ce13bb434b901011ab777856533997d3"
"bdd1703ecbde8812614b112a6551d58de3ad681048fd90fca2a3e491edd8afe5"
],
"threshold": 1,
"x-tuf-on-ci-expiry-period": 3650,

View File

@@ -0,0 +1 @@
{"signatures":[{"keyid":"bdd1703ecbde8812614b112a6551d58de3ad681048fd90fca2a3e491edd8afe5","sig":"3045022018e31a2e743b21054939262706520be10375829fb93dec7f3042e48ed8eb9cec0221008c2765ee9e49d49c12a6b9a5124c984d414b8d86452cdbcc2fc2f2ca10a11e67"}],"signed":{"_type":"snapshot","expires":"2034-06-23T12:47:16Z","meta":{"targets.json":{"version":8},"test-role.json":{"version":2}},"spec_version":"1.0.31","version":7}}

View File

@@ -0,0 +1 @@
{"architecture":"","created":"0001-01-01T00:00:00Z","history":[{"created":"0001-01-01T00:00:00Z"},{"created":"0001-01-01T00:00:00Z"},{"created":"0001-01-01T00:00:00Z"},{"created":"0001-01-01T00:00:00Z"},{"created":"0001-01-01T00:00:00Z"}],"os":"","rootfs":{"type":"layers","diff_ids":["sha256:5a9f60b64b708d05e4e4da0354529fc7fe5015807b79f0bf7b136207bf952bd7","sha256:1e6d780fc1967ff3d2d65c01b3614536a1562de0f0e5981718df82f61dc0c670","sha256:5caaed86d85583b60586eff2da6ecff41a35d0ec5b8a603330db791249f7d497","sha256:ddc840cc61ca4a5cf9b79d683fc81144977f2d95f1734ebf247b3f9da4d644fb","sha256:1f83502e00bf791ad0b4308fed7ba4a2cb099665069585f21f819fb35be140d8"]},"config":{}}

View File

@@ -1 +0,0 @@
{"schemaVersion":2,"mediaType":"application/vnd.oci.image.manifest.v1+json","config":{"mediaType":"application/vnd.oci.image.config.v1+json","size":669,"digest":"sha256:ad4cacc170229608305ffccd8d09eeb59578fcb72ae394763cf7ef492175b1ee"},"layers":[{"mediaType":"application/vnd.tuf.metadata+json","size":2607,"digest":"sha256:a2e026ce65c198ee68a7ed2df6978ed0287bb38342f6ddb7bf934a456f1d6f87","annotations":{"tuf.io/filename":"2.root.json"}},{"mediaType":"application/vnd.tuf.metadata+json","size":2200,"digest":"sha256:61a98e1e86ae279e59415d927e38beae430d7e6d2bd6207054179429ea9b6763","annotations":{"tuf.io/filename":"1.root.json"}},{"mediaType":"application/vnd.tuf.metadata+json","size":410,"digest":"sha256:1fd0d9781f02486718fcbd7724db0e4c4ba47b649930cec22a3e7e6b6077ba38","annotations":{"tuf.io/filename":"6.snapshot.json"}},{"mediaType":"application/vnd.tuf.metadata+json","size":1683,"digest":"sha256:ea7713eb649ca1a33d79ebdccda9f7f066595b1b2c6e37e52dbfd250f5287260","annotations":{"tuf.io/filename":"5.targets.json"}},{"mediaType":"application/vnd.tuf.metadata+json","size":383,"digest":"sha256:4c1054844dba3241525cbd71ff9e58becca652fb1ce4a0e6ea55a01c4ec41950","annotations":{"tuf.io/filename":"timestamp.json"}}]}

View File

@@ -1 +0,0 @@
{"signatures":[{"keyid":"b7474a42f2588fa92ed4a2ebea6047a7b1b2f7351f1cfe0912732c0d0fb0fc09","sig":"3066023100e99acc5f74777ebf40376b60f0216e8fe1829c1a49a5f6a6899126c15de1df7a56533baf493b2b53159c50843a289102023100b6a006b24da62ea0b743fbe38e1497ff485bf3a0833894985fc27a0305ad0693eeb968a7b52723ed3c49af8bef2027b6"},{"keyid":"81cf5a78d6ea2cd904256b9d814b340289b765e6f75ec4397e4ebb7586cab664","sig":"30440220136debcc2f60dd1d63c9c2704f9b13c2cb2f5d2df58ea93f07f7c10f54f36742022059d7f8c6620e33506c6f1766394a32f86c9b008328f6398831ba7ebcf4ce0838"}],"signed":{"_type":"root","consistent_snapshot":true,"expires":"2034-04-03T08:45:50Z","keys":{"198f00ff96ea7cbfa7eac480cc9bfc43ce13bb434b901011ab777856533997d3":{"keytype":"ecdsa","keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEgDpP6O0sEt2R+l84WlfmqPBsFSby\nxJsJ6YmeUVgDk/wk9++8IAR6YBYewaKye56gMnIYjTFbyOI8WomA2NQFBw==\n-----END PUBLIC KEY-----\n"},"scheme":"ecdsa-sha2-nistp256","x-tuf-on-ci-online-uri":"awskms:arn:aws:kms:us-east-1:175142243308:key/fbd8dab6-5677-4b57-87e6-8369c45b3b61"},"81cf5a78d6ea2cd904256b9d814b340289b765e6f75ec4397e4ebb7586cab664":{"keytype":"ecdsa","keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEWmhpAfB7Q53UNluMhpkDxXXup4E0\n2Hh4PSgHC1Yh6brGl6Akq9a4io55LtZTk5mnCTqxuB+rc5cI/yaNUeWEqQ==\n-----END PUBLIC KEY-----\n"},"scheme":"ecdsa-sha2-nistp256","x-tuf-on-ci-keyowner":"@kipz"},"b7474a42f2588fa92ed4a2ebea6047a7b1b2f7351f1cfe0912732c0d0fb0fc09":{"keytype":"ecdsa","keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE3+asmp2GD6UijwWvMezwVG/BwFLuQa3o\nT6eRxFvkILGpVDbZ92ZYWidHl9LZ/eJUjhIjuVEkNVKoenw5KjKl8veP3MthZrQA\nSkYytOIwkidZo9Rk2dczbDcFSJvLGsmd\n-----END PUBLIC KEY-----\n"},"scheme":"ecdsa-sha2-nistp384","x-tuf-on-ci-keyowner":"@mrjoelkamp"}},"roles":{"root":{"keyids":["b7474a42f2588fa92ed4a2ebea6047a7b1b2f7351f1cfe0912732c0d0fb0fc09","81cf5a78d6ea2cd904256b9d814b340289b765e6f75ec4397e4ebb7586cab664"],"threshold":1},"snapshot":{"keyids":["198f00ff96ea7cbfa7eac480cc9bfc43ce13bb434b901011ab777856533997d3"],"threshold":1,"x-tuf-on-ci-expiry-period":3650,"x-tuf-on-ci-signing-period":60},"targets":{"keyids":["b7474a42f2588fa92ed4a2ebea6047a7b1b2f7351f1cfe0912732c0d0fb0fc09","81cf5a78d6ea2cd904256b9d814b340289b765e6f75ec4397e4ebb7586cab664"],"threshold":1},"timestamp":{"keyids":["198f00ff96ea7cbfa7eac480cc9bfc43ce13bb434b901011ab777856533997d3"],"threshold":1,"x-tuf-on-ci-expiry-period":3650,"x-tuf-on-ci-signing-period":60}},"spec_version":"1.0.31","version":2,"x-tuf-on-ci-expiry-period":3650,"x-tuf-on-ci-signing-period":60}}

View File

@@ -1 +0,0 @@
{"schemaVersion":2,"mediaType":"application/vnd.oci.image.manifest.v1+json","config":{"mediaType":"application/vnd.oci.image.config.v1+json","size":669,"digest":"sha256:c927b30f17fa8c64e3c20b8f92b7e348733f9c1281b5b7e6b6d669a8a74230a7"},"layers":[{"mediaType":"application/vnd.tuf.metadata+json","size":2200,"digest":"sha256:61a98e1e86ae279e59415d927e38beae430d7e6d2bd6207054179429ea9b6763","annotations":{"tuf.io/filename":"1.root.json"}},{"mediaType":"application/vnd.tuf.metadata+json","size":2607,"digest":"sha256:a2e026ce65c198ee68a7ed2df6978ed0287bb38342f6ddb7bf934a456f1d6f87","annotations":{"tuf.io/filename":"2.root.json"}},{"mediaType":"application/vnd.tuf.metadata+json","size":410,"digest":"sha256:1fd0d9781f02486718fcbd7724db0e4c4ba47b649930cec22a3e7e6b6077ba38","annotations":{"tuf.io/filename":"6.snapshot.json"}},{"mediaType":"application/vnd.tuf.metadata+json","size":1683,"digest":"sha256:ea7713eb649ca1a33d79ebdccda9f7f066595b1b2c6e37e52dbfd250f5287260","annotations":{"tuf.io/filename":"5.targets.json"}},{"mediaType":"application/vnd.tuf.metadata+json","size":383,"digest":"sha256:4c1054844dba3241525cbd71ff9e58becca652fb1ce4a0e6ea55a01c4ec41950","annotations":{"tuf.io/filename":"timestamp.json"}}]}

View File

@@ -1 +0,0 @@
{"architecture":"","created":"0001-01-01T00:00:00Z","history":[{"created":"0001-01-01T00:00:00Z"},{"created":"0001-01-01T00:00:00Z"},{"created":"0001-01-01T00:00:00Z"},{"created":"0001-01-01T00:00:00Z"},{"created":"0001-01-01T00:00:00Z"}],"os":"","rootfs":{"type":"layers","diff_ids":["sha256:a2e026ce65c198ee68a7ed2df6978ed0287bb38342f6ddb7bf934a456f1d6f87","sha256:61a98e1e86ae279e59415d927e38beae430d7e6d2bd6207054179429ea9b6763","sha256:1fd0d9781f02486718fcbd7724db0e4c4ba47b649930cec22a3e7e6b6077ba38","sha256:ea7713eb649ca1a33d79ebdccda9f7f066595b1b2c6e37e52dbfd250f5287260","sha256:4c1054844dba3241525cbd71ff9e58becca652fb1ce4a0e6ea55a01c4ec41950"]},"config":{}}

View File

@@ -1 +0,0 @@
{"architecture":"","created":"0001-01-01T00:00:00Z","history":[{"created":"0001-01-01T00:00:00Z"},{"created":"0001-01-01T00:00:00Z"},{"created":"0001-01-01T00:00:00Z"},{"created":"0001-01-01T00:00:00Z"},{"created":"0001-01-01T00:00:00Z"}],"os":"","rootfs":{"type":"layers","diff_ids":["sha256:61a98e1e86ae279e59415d927e38beae430d7e6d2bd6207054179429ea9b6763","sha256:a2e026ce65c198ee68a7ed2df6978ed0287bb38342f6ddb7bf934a456f1d6f87","sha256:1fd0d9781f02486718fcbd7724db0e4c4ba47b649930cec22a3e7e6b6077ba38","sha256:ea7713eb649ca1a33d79ebdccda9f7f066595b1b2c6e37e52dbfd250f5287260","sha256:4c1054844dba3241525cbd71ff9e58becca652fb1ce4a0e6ea55a01c4ec41950"]},"config":{}}

View File

@@ -0,0 +1 @@
{"signatures":[{"keyid":"76d0a7e1ff8617ce99627d0fa5c9809f2c0f0d52e0bf65c7b84c031608d25221","sig":""},{"keyid":"beac53949c4cf075824edede7d41715941f524db247d1b455a2389d7490ecd72","sig":"304602210086552ad4ffddd7e60f2b80d095b4dfad9d2836cfce5d6b12dfb2aec0786240df02210097807190a1f64c615798b74068e8c9f19a29f495566bc1f16d296c7edd9343b3"}],"signed":{"_type":"targets","delegations":{"keys":{"76d0a7e1ff8617ce99627d0fa5c9809f2c0f0d52e0bf65c7b84c031608d25221":{"keytype":"ecdsa","keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE3+asmp2GD6UijwWvMezwVG/BwFLuQa3o\nT6eRxFvkILGpVDbZ92ZYWidHl9LZ/eJUjhIjuVEkNVKoenw5KjKl8veP3MthZrQA\nSkYytOIwkidZo9Rk2dczbDcFSJvLGsmd\n-----END PUBLIC KEY-----\n"},"scheme":"ecdsa-sha2-nistp384","x-tuf-on-ci-keyowner":"@mrjoelkamp"}},"roles":[{"keyids":["76d0a7e1ff8617ce99627d0fa5c9809f2c0f0d52e0bf65c7b84c031608d25221"],"name":"test-role","paths":["test-role/*","test-role/*/*","test-role/*/*/*","test-role/*/*/*/*"],"terminating":true,"threshold":1}]},"expires":"2034-06-23T12:42:15Z","spec_version":"1.0.31","targets":{"always-fail.rego":{"hashes":{"sha256":"e8a5b75ac27a28056d2155ff63acc1ffd76c30ed8558011c54708f4832f073ac"},"length":364},"jonnystoten2.rego":{"hashes":{"sha256":"bc46e8c31646f166a9efbd14fef154dd84cf07efc95c96be3a201c84470dcbc1"},"length":5857},"mapping.yaml":{"hashes":{"sha256":"baad1a9d61afa5d6f8717f576b57b9749e5549da4b826746fd73a5a914ac5be1"},"length":272},"test.txt":{"hashes":{"sha256":"02119a076ec3878c736c3a95e20794f5a8d5bce3d7ecc264681bb7334ca2e24b"},"length":31},"version-constraints":{"hashes":{"sha256":"bd6394a08afc1edfe5512fc14e63025a337e25ca0013c1068ec879742fc3a3c3"},"length":12}},"version":8,"x-tuf-on-ci-expiry-period":3650,"x-tuf-on-ci-signing-period":60}}

View File

@@ -0,0 +1 @@
{"schemaVersion":2,"mediaType":"application/vnd.oci.image.manifest.v1+json","config":{"mediaType":"application/vnd.oci.image.config.v1+json","size":669,"digest":"sha256:742736cf58eef752676e9254241b3143779ad66e10707f980b6a477cdc23ad59"},"layers":[{"mediaType":"application/vnd.tuf.metadata+json","size":2202,"digest":"sha256:5a9f60b64b708d05e4e4da0354529fc7fe5015807b79f0bf7b136207bf952bd7","annotations":{"tuf.io/filename":"1.root.json"}},{"mediaType":"application/vnd.tuf.metadata+json","size":2472,"digest":"sha256:1e6d780fc1967ff3d2d65c01b3614536a1562de0f0e5981718df82f61dc0c670","annotations":{"tuf.io/filename":"2.root.json"}},{"mediaType":"application/vnd.tuf.metadata+json","size":412,"digest":"sha256:5caaed86d85583b60586eff2da6ecff41a35d0ec5b8a603330db791249f7d497","annotations":{"tuf.io/filename":"7.snapshot.json"}},{"mediaType":"application/vnd.tuf.metadata+json","size":1746,"digest":"sha256:ddc840cc61ca4a5cf9b79d683fc81144977f2d95f1734ebf247b3f9da4d644fb","annotations":{"tuf.io/filename":"8.targets.json"}},{"mediaType":"application/vnd.tuf.metadata+json","size":383,"digest":"sha256:1f83502e00bf791ad0b4308fed7ba4a2cb099665069585f21f819fb35be140d8","annotations":{"tuf.io/filename":"timestamp.json"}}]}

View File

@@ -1 +0,0 @@
{"signatures":[{"keyid":"b7474a42f2588fa92ed4a2ebea6047a7b1b2f7351f1cfe0912732c0d0fb0fc09","sig":""},{"keyid":"81cf5a78d6ea2cd904256b9d814b340289b765e6f75ec4397e4ebb7586cab664","sig":"3046022100f892a496c9bd96082e3b06d5eae85429355876b8eb455aa04b53ab9051911d90022100a3e89c29b15bccfc2877278c0fb2d3b34500da6351e245ad0b3f8c0ae6b67eff"}],"signed":{"_type":"targets","delegations":{"keys":{"81cf5a78d6ea2cd904256b9d814b340289b765e6f75ec4397e4ebb7586cab664":{"keytype":"ecdsa","keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEWmhpAfB7Q53UNluMhpkDxXXup4E0\n2Hh4PSgHC1Yh6brGl6Akq9a4io55LtZTk5mnCTqxuB+rc5cI/yaNUeWEqQ==\n-----END PUBLIC KEY-----\n"},"scheme":"ecdsa-sha2-nistp256","x-tuf-on-ci-keyowner":"@kipz"},"b7474a42f2588fa92ed4a2ebea6047a7b1b2f7351f1cfe0912732c0d0fb0fc09":{"keytype":"ecdsa","keyval":{"public":"-----BEGIN PUBLIC KEY-----\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE3+asmp2GD6UijwWvMezwVG/BwFLuQa3o\nT6eRxFvkILGpVDbZ92ZYWidHl9LZ/eJUjhIjuVEkNVKoenw5KjKl8veP3MthZrQA\nSkYytOIwkidZo9Rk2dczbDcFSJvLGsmd\n-----END PUBLIC KEY-----\n"},"scheme":"ecdsa-sha2-nistp384","x-tuf-on-ci-keyowner":"@mrjoelkamp"}},"roles":[{"keyids":["b7474a42f2588fa92ed4a2ebea6047a7b1b2f7351f1cfe0912732c0d0fb0fc09","81cf5a78d6ea2cd904256b9d814b340289b765e6f75ec4397e4ebb7586cab664"],"name":"test-role","paths":["test-role/*","test-role/*/*","test-role/*/*/*","test-role/*/*/*/*"],"terminating":true,"threshold":1}]},"expires":"2034-04-03T15:28:29Z","spec_version":"1.0.31","targets":{"test.txt":{"hashes":{"sha256":"02119a076ec3878c736c3a95e20794f5a8d5bce3d7ecc264681bb7334ca2e24b"},"length":31}},"version":5,"x-tuf-on-ci-expiry-period":3650,"x-tuf-on-ci-signing-period":60}}

View File

@@ -5,7 +5,7 @@
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"size": 1220,
"digest": "sha256:a744a2f1e62ae4ce410822b5e3f5508dbaf6a76768a9d23741828172bab1dc97"
"digest": "sha256:e744131b8e5deec56c893bb4de662fdefa3b82fb8c66a9fa4a039ea543afa5e1"
}
]
}

View File

@@ -1 +0,0 @@
{"signatures":[{"keyid":"b7474a42f2588fa92ed4a2ebea6047a7b1b2f7351f1cfe0912732c0d0fb0fc09","sig":""},{"keyid":"81cf5a78d6ea2cd904256b9d814b340289b765e6f75ec4397e4ebb7586cab664","sig":"3044022015b6ebe9d30895e3be20e707a6738e38460197d90cae3dc37527ddb7c437868602207f85f3d4e068bef4c51a749f5d166cc7fe2cb9483999ea197e72395081c3aa61"}],"signed":{"_type":"targets","expires":"2034-04-03T15:39:02Z","spec_version":"1.0.31","targets":{"test-role/dir1/dir2/dir3/myfile.txt":{"hashes":{"sha256":"ea230621c53e0bb858ea5526125414f8957fb29c08350528d50a162c620f36b1"},"length":10},"test-role/test.txt":{"hashes":{"sha256":"d1bb6181284970ae43fbbc88b5e72f9a5942ebac20588aa0c4bf78ba621e1ee2"},"length":32}},"version":3,"x-tuf-on-ci-expiry-period":3650,"x-tuf-on-ci-signing-period":60}}

View File

@@ -0,0 +1 @@
{"schemaVersion":2,"mediaType":"application/vnd.oci.image.manifest.v1+json","config":{"mediaType":"application/vnd.oci.image.config.v1+json","size":233,"digest":"sha256:84fd82cab3086626411db7936836bca343f3f2cb7a9b41846cbc42d6ff64da98"},"layers":[{"mediaType":"application/vnd.tuf.metadata+json","size":742,"digest":"sha256:ad7b6cdc3c7c0af0f8f05459471074adb6353ff72e65e2ec2629fafcce1603b1","annotations":{"tuf.io/filename":"2.test-role.json"}}]}

View File

@@ -1 +0,0 @@
{"schemaVersion":2,"mediaType":"application/vnd.oci.image.manifest.v1+json","config":{"mediaType":"application/vnd.oci.image.config.v1+json","size":233,"digest":"sha256:9edf24c022c2cd6796e87f49ec6a6ea2fad3e7c939c32a8219aaa4726792457c"},"layers":[{"mediaType":"application/vnd.tuf.metadata+json","size":764,"digest":"sha256:2b2d4fba192ec164e05e6d90399c5cf4a45e4fe2ddebb9066c55aa2bcf0a73d3","annotations":{"tuf.io/filename":"3.test-role.json"}}]}

View File

@@ -1 +1 @@
{"architecture":"","created":"0001-01-01T00:00:00Z","history":[{"created":"0001-01-01T00:00:00Z"}],"os":"","rootfs":{"type":"layers","diff_ids":["sha256:2b2d4fba192ec164e05e6d90399c5cf4a45e4fe2ddebb9066c55aa2bcf0a73d3"]},"config":{}}
{"architecture":"","created":"0001-01-01T00:00:00Z","history":[{"created":"0001-01-01T00:00:00Z"}],"os":"","rootfs":{"type":"layers","diff_ids":["sha256:ad7b6cdc3c7c0af0f8f05459471074adb6353ff72e65e2ec2629fafcce1603b1"]},"config":{}}

View File

@@ -0,0 +1 @@
{"signatures":[{"keyid":"76d0a7e1ff8617ce99627d0fa5c9809f2c0f0d52e0bf65c7b84c031608d25221","sig":"3065023100c37572d6e0608e0501026d99238ee37d26856d93074227410b0748e56775f8369cf7c44553b73d8a30aa94a388148ca602305b46acbb0e8818657725024a39d02589538845ad9fa0c2b6eb18f431f560096045fd825586dce81688c9574b11b975da"}],"signed":{"_type":"targets","expires":"2034-05-29T20:25:01Z","spec_version":"1.0.31","targets":{"test-role/dir1/dir2/dir3/test.txt":{"hashes":{"sha256":"bb8fcf06f6c067dcbcb394d7d9ced788316fc02b715fe679097281108a4bd465"},"length":46},"test-role/test.txt":{"hashes":{"sha256":"d1bb6181284970ae43fbbc88b5e72f9a5942ebac20588aa0c4bf78ba621e1ee2"},"length":32}},"version":2,"x-tuf-on-ci-expiry-period":3650,"x-tuf-on-ci-signing-period":60}}

View File

@@ -5,7 +5,7 @@
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"size": 444,
"digest": "sha256:7c8d8f5dfca62068e3a4b18bb41cf85dad23ec9cdc7d7d2e10bc37b86ebffff5"
"digest": "sha256:6536fc6f6e006b674a97c23b28c01e97153533777a48c3de9ff06a20a200dcbc"
}
]
}

View File

@@ -0,0 +1 @@
{"schemaVersion":2,"mediaType":"application/vnd.oci.image.manifest.v1+json","config":{"mediaType":"application/vnd.oci.image.config.v1+json","size":233,"digest":"sha256:518931eb24f93aa58c711c77e59d63171462133141ba9c6f8b6bc99a8daaab4d"},"layers":[{"mediaType":"application/vnd.tuf.target","size":272,"digest":"sha256:baad1a9d61afa5d6f8717f576b57b9749e5549da4b826746fd73a5a914ac5be1","annotations":{"tuf.io/filename":"baad1a9d61afa5d6f8717f576b57b9749e5549da4b826746fd73a5a914ac5be1.mapping.yaml"}}]}

View File

@@ -1 +1 @@
{"architecture":"","created":"0001-01-01T00:00:00Z","history":[{"created":"0001-01-01T00:00:00Z"}],"os":"","rootfs":{"type":"layers","diff_ids":["sha256:ea230621c53e0bb858ea5526125414f8957fb29c08350528d50a162c620f36b1"]},"config":{}}
{"architecture":"","created":"0001-01-01T00:00:00Z","history":[{"created":"0001-01-01T00:00:00Z"}],"os":"","rootfs":{"type":"layers","diff_ids":["sha256:baad1a9d61afa5d6f8717f576b57b9749e5549da4b826746fd73a5a914ac5be1"]},"config":{}}

View File

@@ -0,0 +1,12 @@
version: v1
kind: policy-mapping
policies:
- origin:
domain: docker.io
prefix: jonnystoten2/
id: jonnystoten2
description: jonnystoten2 personal images for testing
attestations:
style: "referrers"
files:
- path: jonnystoten2.rego

View File

@@ -0,0 +1,11 @@
{
"schemaVersion": 2,
"mediaType": "application/vnd.oci.image.index.v1+json",
"manifests": [
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"size": 498,
"digest": "sha256:08fcd920e5ff68ff16601b7952c58b05a947e007ebf4cc8898c43b71a375604f"
}
]
}

View File

@@ -0,0 +1,3 @@
{
"imageLayoutVersion": "1.0.0"
}

View File

@@ -0,0 +1 @@
{"schemaVersion":2,"mediaType":"application/vnd.oci.image.manifest.v1+json","config":{"mediaType":"application/vnd.oci.image.config.v1+json","size":233,"digest":"sha256:b3ed84cbb194e472b365c914d6551e2420167022e156409e10701c0ec9418b10"},"layers":[{"mediaType":"application/vnd.tuf.target","size":5857,"digest":"sha256:bc46e8c31646f166a9efbd14fef154dd84cf07efc95c96be3a201c84470dcbc1","annotations":{"tuf.io/filename":"bc46e8c31646f166a9efbd14fef154dd84cf07efc95c96be3a201c84470dcbc1.jonnystoten2.rego"}}]}

View File

@@ -0,0 +1 @@
{"architecture":"","created":"0001-01-01T00:00:00Z","history":[{"created":"0001-01-01T00:00:00Z"}],"os":"","rootfs":{"type":"layers","diff_ids":["sha256:bc46e8c31646f166a9efbd14fef154dd84cf07efc95c96be3a201c84470dcbc1"]},"config":{}}

Some files were not shown because too many files have changed in this diff Show More