33 Commits

Author SHA1 Message Date
Jonny Stoten
7fffbf9d3f Suppress logs from ecr credential helper (#163)
This gets rid of those annoying logs like:

```
time="2024-09-11T15:22:04Z" level=error msg="Error parsing the serverURL" error="docker-credential-ecr-login can only be used with Amazon Elastic Container Registry." serverURL="localhost:5000"
time="2024-09-11T15:22:04Z" level=error msg="Error parsing the serverURL" error="docker-credential-ecr-login can only be used with Amazon Elastic Container Registry." serverURL="localhost:5000"
time="2024-09-11T15:22:04Z" level=error msg="Error parsing the serverURL" error="docker-credential-ecr-login can only be used with Amazon Elastic Container Registry." serverURL="localhost:5000"
time="2024-09-11T15:22:04Z" level=error msg="Error parsing the serverURL" error="docker-credential-ecr-login can only be used with Amazon Elastic Container Registry." serverURL="localhost:5000"
```
2024-09-11 16:36:28 +01:00
dependabot[bot]
070fa33d0d feat(deps): bump google.golang.org/api from 0.196.0 to 0.197.0 (#162)
Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.196.0 to 0.197.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.196.0...v0.197.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-09-11 12:27:09 +01:00
Jonny Stoten
602295492f fix: regexes for autolabeler (#160)
* Fix regexes for autolabeler

* Remove branch autolabeler rules
2024-09-10 21:02:05 +01:00
Jonny Stoten
6edcc3d5d7 Test on Go 1.23 as well (#161) 2024-09-10 17:40:43 +01:00
Jonny Stoten
c029bcfbaa feat: add a prefix path to TUF client (#159)
This is to allow us to store new policy files in the production TUF repository
under a testing delegation, and for clients to opt-in to using this testing
delegation when retrieving policy from TUF.

If the prefix path is set, it is prepended to every target path on download
with path.Join. For example, if the prefix path is testing and we download
the target a/b, the TUF client with actually download testing/a/b.

Also get the latest testdata from tuf-dev.
2024-09-10 17:40:20 +01:00
James Carnegie
206b33c5d9 fix: expose version and user agent to consumers (#158) 2024-09-09 12:08:01 -05:00
James Carnegie
b4e6767cc6 feature!: support for setting HTTP User-Agent header (#157)
* feature!: support for setting HTTP User-Agent header

* fix lint

* fix e2e

* refactor: move http.go to internal/util/useragent package and rename functions to Get and Set

* Move packages and use attest version
2024-09-09 14:22:17 +01:00
James Carnegie
ed0ae8ecf6 fix: verify mapped image name against subjects (#156)
* fix: verify mapped image name against subjects
2024-09-05 08:08:55 -05:00
Joel Kamp
a363be7f3a Merge pull request #150 from docker/dependabot/go_modules/google.golang.org/api-0.196.0
feat(deps): bump google.golang.org/api from 0.195.0 to 0.196.0
2024-09-04 16:47:27 -05:00
dependabot[bot]
99846a3483 feat(deps): bump google.golang.org/api from 0.195.0 to 0.196.0
Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.195.0 to 0.196.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.195.0...v0.196.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>
2024-09-04 21:43:32 +00:00
Joel Kamp
f760b12bb2 Merge pull request #151 from docker/dependabot/go_modules/github.com/sigstore/sigstore/pkg/signature/kms/gcp-1.8.9
feat(deps): bump github.com/sigstore/sigstore/pkg/signature/kms/gcp from 1.8.8 to 1.8.9
2024-09-04 16:41:22 -05:00
Joel Kamp
bab474669f Merge pull request #155 from docker/dependabot/go_modules/github.com/aws/aws-sdk-go-v2/config-1.27.33
feat(deps): bump github.com/aws/aws-sdk-go-v2/config from 1.27.31 to 1.27.33
2024-09-04 16:40:18 -05:00
dependabot[bot]
0705a71115 feat(deps): bump github.com/sigstore/sigstore/pkg/signature/kms/gcp
Bumps [github.com/sigstore/sigstore/pkg/signature/kms/gcp](https://github.com/sigstore/sigstore) from 1.8.8 to 1.8.9.
- [Release notes](https://github.com/sigstore/sigstore/releases)
- [Commits](https://github.com/sigstore/sigstore/compare/v1.8.8...v1.8.9)

---
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>
2024-09-04 21:37:46 +00:00
dependabot[bot]
b00e02af01 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.31 to 1.27.33.
- [Release notes](https://github.com/aws/aws-sdk-go-v2/releases)
- [Commits](https://github.com/aws/aws-sdk-go-v2/compare/config/v1.27.31...config/v1.27.33)

---
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-09-04 21:36:36 +00:00
Joel Kamp
ff53657cc9 Merge pull request #153 from docker/dependabot/github_actions/actions/create-github-app-token-1.10.4
chore(deps): bump actions/create-github-app-token from 1.10.3 to 1.10.4
2024-09-04 16:34:38 -05:00
Joel Kamp
c8383f3f5a Merge pull request #149 from docker/dependabot/go_modules/github.com/sigstore/sigstore/pkg/signature/kms/aws-1.8.9
feat(deps): bump github.com/sigstore/sigstore/pkg/signature/kms/aws from 1.8.8 to 1.8.9
2024-09-04 16:33:50 -05:00
Joel Kamp
dc247bd348 Merge pull request #143 from docker/dependabot/go_modules/github.com/open-policy-agent/opa-0.68.0
feat(deps): bump github.com/open-policy-agent/opa from 0.67.1 to 0.68.0
2024-09-04 16:33:28 -05:00
Joel Kamp
ce7d173150 Merge pull request #154 from docker/feat--add-slsa-v1-predicate-type
feat: add slsa v1 predicate type
2024-09-04 16:32:21 -05:00
mrjoelkamp
fb69d9a09b feat: add slsa v1 predicate type 2024-09-04 16:15:56 -05:00
James Carnegie
48e58a9115 Verify input image/platform against attestation subjects before passing to rego (#148)
* feat: verify subjects before passing to rego
2024-09-04 10:20:00 +01:00
dependabot[bot]
bfacaf1de0 chore(deps): bump actions/create-github-app-token from 1.10.3 to 1.10.4
Bumps [actions/create-github-app-token](https://github.com/actions/create-github-app-token) from 1.10.3 to 1.10.4.
- [Release notes](https://github.com/actions/create-github-app-token/releases)
- [Commits](31c86eb3b3...3378cda945)

---
updated-dependencies:
- dependency-name: actions/create-github-app-token
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-04 08:46:09 +00:00
dependabot[bot]
67ad27ac22 feat(deps): bump github.com/sigstore/sigstore/pkg/signature/kms/aws
Bumps [github.com/sigstore/sigstore/pkg/signature/kms/aws](https://github.com/sigstore/sigstore) from 1.8.8 to 1.8.9.
- [Release notes](https://github.com/sigstore/sigstore/releases)
- [Commits](https://github.com/sigstore/sigstore/compare/v1.8.8...v1.8.9)

---
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>
2024-09-04 08:41:30 +00:00
James Carnegie
41847ef238 fix: escape ! remove .* (global match) (#146) 2024-09-03 12:24:26 +01:00
James Carnegie
1f806f33a8 feat: validate mapping files on load (#147) 2024-09-03 12:21:24 +01:00
James Carnegie
8982778507 refactor! remove pkg directory (#145)
* refactor!: remove pkg directory

* chore: include breaking changes in draft
2024-09-02 16:17:50 +01:00
James Carnegie
23849c1c2e fix: use canonical names inside TUF fetcher (#144)
* fix: use canonical names inside TUF fetcher
* keep hold of reference to Config
2024-08-30 17:03:29 +01:00
dependabot[bot]
16834292de feat(deps): bump github.com/open-policy-agent/opa from 0.67.1 to 0.68.0
Bumps [github.com/open-policy-agent/opa](https://github.com/open-policy-agent/opa) from 0.67.1 to 0.68.0.
- [Release notes](https://github.com/open-policy-agent/opa/releases)
- [Changelog](https://github.com/open-policy-agent/opa/blob/main/CHANGELOG.md)
- [Commits](https://github.com/open-policy-agent/opa/compare/v0.67.1...v0.68.0)

---
updated-dependencies:
- dependency-name: github.com/open-policy-agent/opa
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-30 08:37:19 +00:00
dependabot[bot]
bada1df262 feat(deps): bump google.golang.org/api from 0.194.0 to 0.195.0 (#139)
Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.194.0 to 0.195.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.194.0...v0.195.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>
Co-authored-by: James Carnegie <kipz@users.noreply.github.com>
2024-08-30 09:29:19 +01:00
James Carnegie
4778d3de6a fix: tuf oci image parsing (#142)
* fix: tuf oci image parsing
2024-08-29 12:27:13 -05:00
James Carnegie
a4ac09e7da refactor! don't use ctx for policy evaluator (#140)
* refactor! don't use ctx for policy evaluator
2024-08-29 17:43:45 +01:00
Joel Kamp
9250552c5b Merge pull request #138 from docker/feat-add-tuf-resolver-tests
feat: add policy resolver tests
2024-08-29 10:28:34 -05:00
mrjoelkamp
2acc30693f fix: remove mock tuf client output 2024-08-29 10:03:07 -05:00
mrjoelkamp
5db1b5c4c1 feat: add tuf resolver test 2024-08-28 17:08:46 -05:00
207 changed files with 3058 additions and 1296 deletions

View File

@@ -14,6 +14,9 @@ categories:
- title: "🧰 Maintenance"
labels:
- "chore"
- title: "💥 Breaking Changes"
labels:
- "breaking"
change-template: "- $TITLE @$AUTHOR (#$NUMBER)"
change-title-escapes: '\<*_&' # You can add # and @ to disable mentions, and add ` to disable code blocks.
@@ -21,6 +24,7 @@ version-resolver:
major:
labels:
- "major"
- "breaking"
minor:
labels:
- "minor"
@@ -37,26 +41,19 @@ autolabeler:
- label: "chore"
files:
- "*.md"
branch:
- '/docs{0,1}\/.+/'
- '/tests{0,1}\/.+/'
- '/chore{0,1}\/.+/'
title:
- "/docs/i"
- "/test/i"
- "/chore/i"
- "/^docs!?:/i"
- "/^test!?:/i"
- "/^chore!?:/i"
- "/^refactor!?:/i"
- label: "bug"
branch:
- '/fix\/.+/'
- '/revert\/.+/'
title:
- "/fix/i"
- "/revert/i"
- "/^fix!?:/i"
- "/^revert!?:/i"
- label: "feature"
branch:
- '/feature\/.+/'
- '/feat\/.+/'
- '/add\/.+/'
title:
- "/feat/i"
- "/add/i"
- "/^feat!?:/i"
- "/^add!?:/i"
- label: "breaking"
title:
- "/^[a-zA-Z]+!:/i"

View File

@@ -10,7 +10,7 @@ jobs:
steps:
- name: Generate GitHub App Token
id: app-token
uses: actions/create-github-app-token@31c86eb3b33c9b601a1f60f98dcbfd1d70f379b4 # v1.10.3
uses: actions/create-github-app-token@3378cda945da322a8db4b193e19d46352ebe2de5 # v1.10.4
with:
app-id: ${{ vars.ATTEST_RELEASE_APP_ID }}
private-key: ${{ secrets.ATTEST_RELEASE_APP_PRIVATE_KEY }}

View File

@@ -12,7 +12,7 @@ jobs:
id-token: write
strategy:
matrix:
go-version: [1.22.x]
go-version: [1.22.x, 1.23.x]
# temp disable windows tests see https://github.com/docker/image-signer-verifier/pull/154
# os: [ubuntu-latest, macos-latest, windows-latest]
os: [ubuntu-latest, macos-latest]

1
.gitignore vendored
View File

@@ -19,3 +19,4 @@
# Go workspace file
go.work
.aider*

View File

@@ -66,7 +66,7 @@ See [Policy Mapping](#policy-mapping) for more details.
The `attest.Verify` function returns a `VerificationSummary` object, which contains the results of the policy evaluation.
See [example_verify_test.go](./pkg/attest/example_verify_test.go) for an example of how to verify an image against a policy.
See [example_verify_test.go](./example_verify_test.go) for an example of how to verify an image against a policy.
## Signing Attestations
@@ -76,7 +76,7 @@ This function takes a statement and DSSE signer, and returns a signed DSSE envel
For the common use case of signing a statement and adding it to a manifest, e.g. for pushing to a registry as a referrer to the image being attested, the `attestation.AttestationManifest` type can be used.
See [example_attestation_manifest_test.go](./pkg/attestation/example_attestation_manifest_test.go)
See also [example_sign_test.go](./pkg/attest/example_sign_test.go) for an example of how to sign all attached in-toto statements on an image, e.g. those produced by buildkit.
See also [example_sign_test.go](./example_sign_test.go) for an example of how to sign all attached in-toto statements on an image, e.g. those produced by buildkit.
# Rego Policy

View File

@@ -8,7 +8,7 @@ import (
"maps"
"strings"
"github.com/docker/attest/pkg/oci"
"github.com/docker/attest/oci"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/empty"
"github.com/google/go-containerregistry/pkg/v1/layout"

View File

@@ -3,8 +3,8 @@ package attestation_test
import (
"testing"
"github.com/docker/attest/attestation"
"github.com/docker/attest/internal/test"
"github.com/docker/attest/pkg/attestation"
intoto "github.com/in-toto/in-toto-golang/in_toto"
"github.com/stretchr/testify/assert"
)
@@ -12,7 +12,7 @@ import (
const ExpectedStatements = 4
func TestExtractAnnotatedStatements(t *testing.T) {
statements, err := attestation.ExtractAnnotatedStatements(test.UnsignedTestImage, intoto.PayloadType)
statements, err := attestation.ExtractAnnotatedStatements(test.UnsignedTestImage(".."), intoto.PayloadType)
assert.NoError(t, err)
assert.Equalf(t, len(statements), ExpectedStatements, "expected %d statement, got %d", ExpectedStatements, len(statements))
}

View File

@@ -4,9 +4,9 @@ import (
"context"
"time"
"github.com/docker/attest/pkg/attestation"
"github.com/docker/attest/pkg/oci"
"github.com/docker/attest/pkg/signerverifier"
"github.com/docker/attest/attestation"
"github.com/docker/attest/oci"
"github.com/docker/attest/signerverifier"
v1 "github.com/google/go-containerregistry/pkg/v1"
intoto "github.com/in-toto/in-toto-golang/in_toto"
"github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/common"
@@ -82,7 +82,8 @@ func ExampleManifest() {
if err != nil {
panic(err)
}
err = oci.SaveImagesNoTag(artifacts, output)
ctx := context.Background()
err = oci.SaveImagesNoTag(ctx, artifacts, output)
if err != nil {
panic(err)
}

View File

@@ -5,7 +5,7 @@ import (
"encoding/json"
"fmt"
"github.com/docker/attest/pkg/oci"
"github.com/docker/attest/oci"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/layout"
)

View File

@@ -4,11 +4,11 @@ import (
"strings"
"testing"
"github.com/docker/attest"
"github.com/docker/attest/attestation"
"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/docker/attest/pkg/policy"
"github.com/docker/attest/oci"
"github.com/docker/attest/policy"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -24,7 +24,7 @@ func TestAttestationFromOCILayout(t *testing.T) {
}
opts := &attestation.SigningOptions{}
attIdx, err := oci.IndexFromPath(test.UnsignedTestImage)
attIdx, err := oci.IndexFromPath(test.UnsignedTestImage(".."))
require.NoError(t, err)
signedManifests, err := attest.SignStatements(ctx, attIdx.Index, signer, opts)
require.NoError(t, err)
@@ -33,7 +33,7 @@ func TestAttestationFromOCILayout(t *testing.T) {
require.NoError(t, err)
spec, err := oci.ParseImageSpec(oci.LocalPrefix + outputLayout)
require.NoError(t, err)
err = oci.SaveIndex([]*oci.ImageSpec{spec}, signedIndex, outputLayout)
err = oci.SaveIndex(ctx, []*oci.ImageSpec{spec}, signedIndex, outputLayout)
require.NoError(t, err)
testCases := []struct {

View File

@@ -3,12 +3,19 @@ package attestation
import (
"context"
"github.com/docker/attest/pkg/oci"
"github.com/docker/attest/oci"
v1 "github.com/google/go-containerregistry/pkg/v1"
)
// ensure MockResolver implements Resolver.
var _ oci.ImageDetailsResolver = MockResolver{}
type MockResolver struct {
Envs []*Envelope
Envs []*Envelope
Image string
PlatformFn func() (*v1.Platform, error)
DescriptorFn func() (*v1.Descriptor, error)
ImangeNameFn func() (string, error)
}
func (r MockResolver) Attestations(_ context.Context, _ string) ([]*Envelope, error) {
@@ -16,10 +23,19 @@ func (r MockResolver) Attestations(_ context.Context, _ string) ([]*Envelope, er
}
func (r MockResolver) ImageName(_ context.Context) (string, error) {
if r.Image != "" {
return r.Image, nil
}
if r.ImangeNameFn != nil {
return r.ImangeNameFn()
}
return "library/alpine:latest", nil
}
func (r MockResolver) ImageDescriptor(_ context.Context) (*v1.Descriptor, error) {
if r.DescriptorFn != nil {
return r.DescriptorFn()
}
digest, err := v1.NewHash("sha256:da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620")
if err != nil {
return nil, err
@@ -32,6 +48,9 @@ func (r MockResolver) ImageDescriptor(_ context.Context) (*v1.Descriptor, error)
}
func (r MockResolver) ImagePlatform(_ context.Context) (*v1.Platform, error) {
if r.PlatformFn != nil {
return r.PlatformFn()
}
return oci.ParsePlatform("linux/amd64")
}

View File

@@ -5,11 +5,14 @@ import (
"fmt"
"strings"
"github.com/docker/attest/pkg/oci"
"github.com/docker/attest/oci"
"github.com/google/go-containerregistry/pkg/name"
"github.com/google/go-containerregistry/pkg/v1/remote"
)
// ensure ReferrersResolver implements Resolver.
var _ Resolver = &ReferrersResolver{}
type ReferrersResolver struct {
referrersRepo string
oci.ImageDetailsResolver

View File

@@ -7,12 +7,12 @@ import (
"path/filepath"
"testing"
"github.com/docker/attest"
"github.com/docker/attest/attestation"
"github.com/docker/attest/config"
"github.com/docker/attest/internal/test"
"github.com/docker/attest/pkg/attest"
"github.com/docker/attest/pkg/attestation"
"github.com/docker/attest/pkg/config"
"github.com/docker/attest/pkg/oci"
"github.com/docker/attest/pkg/policy"
"github.com/docker/attest/oci"
"github.com/docker/attest/policy"
"github.com/google/go-containerregistry/pkg/name"
"github.com/google/go-containerregistry/pkg/registry"
"github.com/google/go-containerregistry/pkg/v1/remote"
@@ -21,18 +21,17 @@ import (
)
var (
NoProvenanceImage = filepath.Join("..", "..", "test", "testdata", "no-provenance-image")
PassPolicyDir = filepath.Join("..", "..", "test", "testdata", "local-policy-pass")
LocalPolicy = filepath.Join("..", "..", "test", "testdata", "local-policy")
LocalPolicyAttached = filepath.Join("..", "..", "test", "testdata", "local-policy-attached")
PassNoTLPolicyDir = filepath.Join("..", "..", "test", "testdata", "local-policy-no-tl")
FailPolicyDir = filepath.Join("..", "..", "test", "testdata", "local-policy-fail")
NoProvenanceImage = filepath.Join("..", "test", "testdata", "no-provenance-image")
PassPolicyDir = filepath.Join("..", "test", "testdata", "local-policy-pass")
LocalPolicy = filepath.Join("..", "test", "testdata", "local-policy")
LocalPolicyAttached = filepath.Join("..", "test", "testdata", "local-policy-attached")
PassNoTLPolicyDir = filepath.Join("..", "test", "testdata", "local-policy-no-tl")
FailPolicyDir = filepath.Join("..", "test", "testdata", "local-policy-fail")
TestTempDir = "attest-sign-test"
)
func TestAttestationReferenceTypes(t *testing.T) {
ctx, signer := test.Setup(t)
ctx = policy.WithPolicyEvaluator(ctx, policy.NewRegoEvaluator(true))
platforms := []string{"linux/amd64", "linux/arm64"}
for _, tc := range []struct {
name string
@@ -45,37 +44,38 @@ func TestAttestationReferenceTypes(t *testing.T) {
}{
{
name: "referrers support, defaults",
server: httptest.NewServer(registry.New(registry.WithReferrersSupport(true))),
server: test.NewLocalRegistry(ctx, registry.WithReferrersSupport(true)),
},
{
name: "use digest",
server: httptest.NewServer(registry.New(registry.WithReferrersSupport(true))),
server: test.NewLocalRegistry(ctx, registry.WithReferrersSupport(true)),
useDigest: true,
},
{
name: "attached attestations, referrers repo (mismatched args)",
server: httptest.NewServer(registry.New(registry.WithReferrersSupport(true))),
server: test.NewLocalRegistry(ctx, 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))),
server: test.NewLocalRegistry(ctx, registry.WithReferrersSupport(true)),
expectFailure: true, // no policy
attestationSource: config.AttestationStyleReferrers,
referrersRepo: "referrers",
},
{
name: "referrers attestations",
server: httptest.NewServer(registry.New(registry.WithReferrersSupport(true))),
server: test.NewLocalRegistry(ctx, registry.WithReferrersSupport(true)),
attestationSource: config.AttestationStyleReferrers,
},
{
name: "referrers attestations, no referrers support on server",
server: httptest.NewServer(registry.New(registry.WithReferrersSupport(false))),
name: "referrers attestations, no referrers support on server",
server: test.NewLocalRegistry(ctx, registry.WithReferrersSupport(false)),
attestationSource: config.AttestationStyleReferrers,
referrersServer: httptest.NewServer(registry.New(registry.WithReferrersSupport(true))),
referrersServer: test.NewLocalRegistry(ctx, registry.WithReferrersSupport(true)),
},
} {
t.Run(tc.name, func(t *testing.T) {
@@ -91,7 +91,7 @@ func TestAttestationReferenceTypes(t *testing.T) {
opts := &attestation.SigningOptions{
SkipTL: true,
}
attIdx, err := oci.IndexFromPath(test.UnsignedTestImage)
attIdx, err := oci.IndexFromPath(test.UnsignedTestImage(".."))
require.NoError(t, err)
indexName := fmt.Sprintf("%s/repo:root", u.Host)
@@ -110,7 +110,7 @@ func TestAttestationReferenceTypes(t *testing.T) {
// push subject image so that it can be resolved
require.NoError(t, err)
err = oci.PushIndexToRegistry(attIdx.Index, indexName)
err = oci.PushIndexToRegistry(ctx, attIdx.Index, indexName)
require.NoError(t, err)
// upload referrers
@@ -119,7 +119,7 @@ func TestAttestationReferenceTypes(t *testing.T) {
for _, attIdx := range signedManifests {
images, err := attIdx.BuildReferringArtifacts()
require.NoError(t, err)
err = oci.SaveImagesNoTag(images, []*oci.ImageSpec{output})
err = oci.SaveImagesNoTag(ctx, images, []*oci.ImageSpec{output})
require.NoError(t, err)
}
@@ -191,13 +191,13 @@ func TestReferencesInDifferentRepo(t *testing.T) {
}{
{
name: "referrers support",
server: httptest.NewServer(registry.New(registry.WithReferrersSupport(true))),
refServer: httptest.NewServer(registry.New(registry.WithReferrersSupport(true))),
server: test.NewLocalRegistry(ctx, registry.WithReferrersSupport(true)),
refServer: test.NewLocalRegistry(ctx, registry.WithReferrersSupport(true)),
},
{
name: "no referrers support",
server: httptest.NewServer(registry.New()),
refServer: httptest.NewServer(registry.New(registry.WithReferrersSupport(true))),
server: test.NewLocalRegistry(ctx, registry.WithReferrersSupport(false)),
refServer: test.NewLocalRegistry(ctx, registry.WithReferrersSupport(true)),
},
} {
server := tc.server
@@ -213,11 +213,11 @@ func TestReferencesInDifferentRepo(t *testing.T) {
opts := &attestation.SigningOptions{
SkipTL: true,
}
attIdx, err := oci.IndexFromPath(test.UnsignedTestImage)
attIdx, err := oci.IndexFromPath(test.UnsignedTestImage(".."))
require.NoError(t, err)
indexName := fmt.Sprintf("%s/%s:latest", serverURL.Host, repoName)
err = oci.PushIndexToRegistry(attIdx.Index, indexName)
err = oci.PushIndexToRegistry(ctx, attIdx.Index, indexName)
require.NoError(t, err)
signedManifests, err := attest.SignStatements(ctx, attIdx.Index, signer, opts)
@@ -228,7 +228,7 @@ func TestReferencesInDifferentRepo(t *testing.T) {
// push references using subject-digest.att convention
image, err := signedManifest.BuildImage()
require.NoError(t, err)
err = oci.PushImageToRegistry(image, fmt.Sprintf("%s/%s:tag-does-not-matter", refServerURL.Host, repoName))
err = oci.PushImageToRegistry(ctx, image, fmt.Sprintf("%s/%s:tag-does-not-matter", refServerURL.Host, repoName))
require.NoError(t, err)
refServer := tc.refServer
@@ -239,11 +239,11 @@ func TestReferencesInDifferentRepo(t *testing.T) {
opts := &attestation.SigningOptions{
SkipTL: true,
}
attIdx, err := oci.IndexFromPath(test.UnsignedTestImage)
attIdx, err := oci.IndexFromPath(test.UnsignedTestImage(".."))
require.NoError(t, err)
indexName := fmt.Sprintf("%s/%s:latest", serverURL.Host, repoName)
err = oci.PushIndexToRegistry(attIdx.Index, indexName)
err = oci.PushIndexToRegistry(ctx, attIdx.Index, indexName)
require.NoError(t, err)
signedManifests, err := attest.SignStatements(ctx, attIdx.Index, signer, opts)
@@ -255,7 +255,7 @@ func TestReferencesInDifferentRepo(t *testing.T) {
imgs, err := mf.BuildReferringArtifacts()
require.NoError(t, err)
for _, img := range imgs {
err = oci.PushImageToRegistry(img, fmt.Sprintf("%s/%s:tag-does-not-matter", refServerURL.Host, repoName))
err = oci.PushImageToRegistry(ctx, img, fmt.Sprintf("%s/%s:tag-does-not-matter", refServerURL.Host, repoName))
require.NoError(t, err)
}
}
@@ -284,10 +284,9 @@ func TestReferencesInDifferentRepo(t *testing.T) {
func TestCorrectArtifactTypeInTagFallback(t *testing.T) {
ctx, signer := test.Setup(t)
server := httptest.NewServer(registry.New())
defer server.Close()
serverURL, err := url.Parse(server.URL)
regServer := test.NewLocalRegistry(ctx, registry.WithReferrersSupport(false))
defer regServer.Close()
serverURL, err := url.Parse(regServer.URL)
require.NoError(t, err)
repoName := "repo"
@@ -295,11 +294,11 @@ func TestCorrectArtifactTypeInTagFallback(t *testing.T) {
opts := &attestation.SigningOptions{
SkipTL: true,
}
attIdx, err := oci.IndexFromPath(test.UnsignedTestImage)
attIdx, err := oci.IndexFromPath(test.UnsignedTestImage(".."))
require.NoError(t, err)
indexName := fmt.Sprintf("%s/%s:latest", serverURL.Host, repoName)
err = oci.PushIndexToRegistry(attIdx.Index, indexName)
err = oci.PushIndexToRegistry(ctx, attIdx.Index, indexName)
require.NoError(t, err)
signedManifests, err := attest.SignStatements(ctx, attIdx.Index, signer, opts)
@@ -310,14 +309,14 @@ func TestCorrectArtifactTypeInTagFallback(t *testing.T) {
imgs, err := mf.BuildReferringArtifacts()
require.NoError(t, err)
for _, img := range imgs {
err = oci.PushImageToRegistry(img, fmt.Sprintf("%s/%s:tag-does-not-matter", serverURL.Host, repoName))
err = oci.PushImageToRegistry(ctx, 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)
idx, err := remote.Index(subjectRef, oci.WithOptions(ctx, nil)...)
require.NoError(t, err)
imf, err := idx.IndexManifest()
require.NoError(t, err)

View File

@@ -4,12 +4,15 @@ import (
"context"
"fmt"
"github.com/docker/attest/pkg/oci"
"github.com/docker/attest/oci"
"github.com/google/go-containerregistry/pkg/name"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/remote"
)
// ensure RegistryResolver implements Resolver.
var _ Resolver = &RegistryResolver{}
type RegistryResolver struct {
*oci.RegistryImageDetailsResolver
*Manifest

View File

@@ -2,16 +2,15 @@ package attestation_test
import (
"fmt"
"net/http/httptest"
"net/url"
"strings"
"testing"
"github.com/docker/attest"
"github.com/docker/attest/attestation"
"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/docker/attest/pkg/policy"
"github.com/docker/attest/oci"
"github.com/docker/attest/policy"
"github.com/google/go-containerregistry/pkg/registry"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -19,13 +18,13 @@ import (
func TestRegistry(t *testing.T) {
ctx, signer := test.Setup(t)
server := httptest.NewServer(registry.New(registry.WithReferrersSupport(false)))
defer server.Close()
u, err := url.Parse(server.URL)
regServer := test.NewLocalRegistry(ctx, registry.WithReferrersSupport(false))
defer regServer.Close()
u, err := url.Parse(regServer.URL)
require.NoError(t, err)
opts := &attestation.SigningOptions{}
attIdx, err := oci.IndexFromPath(test.UnsignedTestImage)
attIdx, err := oci.IndexFromPath(test.UnsignedTestImage(".."))
require.NoError(t, err)
signedManifests, err := attest.SignStatements(ctx, attIdx.Index, signer, opts)
require.NoError(t, err)
@@ -35,7 +34,7 @@ func TestRegistry(t *testing.T) {
indexName := fmt.Sprintf("%s/repo:root", u.Host)
require.NoError(t, err)
err = oci.PushIndexToRegistry(signedIndex, indexName)
err = oci.PushIndexToRegistry(ctx, signedIndex, indexName)
require.NoError(t, err)
spec, err := oci.ParseImageSpec(indexName)

View File

@@ -3,7 +3,7 @@ package attestation
import (
"context"
"github.com/docker/attest/pkg/oci"
"github.com/docker/attest/oci"
)
type Resolver interface {

View File

@@ -5,7 +5,7 @@ import (
"fmt"
"github.com/docker/attest/internal/util"
"github.com/docker/attest/pkg/tlog"
"github.com/docker/attest/tlog"
intoto "github.com/in-toto/in-toto-golang/in_toto"
"github.com/secure-systems-lab/go-securesystemslib/dsse"
)

View File

@@ -6,15 +6,14 @@ import (
"crypto/rand"
"encoding/json"
"fmt"
"net/http/httptest"
"net/url"
"testing"
"time"
"github.com/docker/attest/attestation"
"github.com/docker/attest/internal/test"
"github.com/docker/attest/pkg/attestation"
"github.com/docker/attest/pkg/oci"
"github.com/docker/attest/pkg/signerverifier"
"github.com/docker/attest/oci"
"github.com/docker/attest/signerverifier"
"github.com/google/go-containerregistry/pkg/registry"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/static"
@@ -283,10 +282,10 @@ func TestSimpleStatementSigning(t *testing.T) {
require.NoError(t, err)
assert.Len(t, layers, 1)
}
server := httptest.NewServer(registry.New(registry.WithReferrersSupport(true)))
defer server.Close()
regServer := test.NewLocalRegistry(ctx, registry.WithReferrersSupport(true))
defer regServer.Close()
u, err := url.Parse(server.URL)
u, err := url.Parse(regServer.URL)
require.NoError(t, err)
indexName := fmt.Sprintf("%s/repo:root", u.Host)
@@ -294,7 +293,7 @@ func TestSimpleStatementSigning(t *testing.T) {
require.NoError(t, err)
artifacts, err := manifest.BuildReferringArtifacts()
require.NoError(t, err)
err = oci.SaveImagesNoTag(artifacts, output)
err = oci.SaveImagesNoTag(ctx, artifacts, output)
require.NoError(t, err)
})
}

View File

@@ -7,6 +7,7 @@ import (
v1 "github.com/google/go-containerregistry/pkg/v1"
intoto "github.com/in-toto/in-toto-golang/in_toto"
v02 "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.2"
slsav1 "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v1"
ociv1 "github.com/opencontainers/image-spec/specs-go/v1"
)
@@ -98,6 +99,8 @@ type Options struct {
func DSSEMediaType(predicateType string) (string, error) {
var predicateName string
switch predicateType {
case slsav1.PredicateSLSAProvenance:
predicateName = "provenance"
case v02.PredicateSLSAProvenance:
predicateName = "provenance"
case intoto.PredicateSPDX:

44
attestation/types_test.go Normal file
View File

@@ -0,0 +1,44 @@
package attestation
import (
"fmt"
"testing"
intoto "github.com/in-toto/in-toto-golang/in_toto"
v02 "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.2"
slsav1 "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v1"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestDSSEMediaType(t *testing.T) {
testcases := []struct {
name string
expected string
}{
{
name: slsav1.PredicateSLSAProvenance,
expected: "provenance",
},
{
name: v02.PredicateSLSAProvenance,
expected: "provenance",
},
{
name: intoto.PredicateSPDX,
expected: "spdx",
},
{
name: VSAPredicateType,
expected: "verification_summary",
},
}
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
mt, err := DSSEMediaType(tc.name)
require.NoError(t, err)
assert.Equal(t, fmt.Sprintf("application/vnd.in-toto.%s+dsse", tc.expected), mt)
})
}
}

View File

@@ -10,8 +10,8 @@ import (
"time"
"github.com/docker/attest/internal/util"
"github.com/docker/attest/pkg/signerverifier"
"github.com/docker/attest/pkg/tlog"
"github.com/docker/attest/signerverifier"
"github.com/docker/attest/tlog"
intoto "github.com/in-toto/in-toto-golang/in_toto"
ociv1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/secure-systems-lab/go-securesystemslib/dsse"

View File

@@ -4,8 +4,8 @@ import (
"encoding/base64"
"testing"
"github.com/docker/attest/attestation"
"github.com/docker/attest/internal/test"
"github.com/docker/attest/pkg/attestation"
intoto "github.com/in-toto/in-toto-golang/in_toto"
ociv1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/stretchr/testify/assert"

120
config/config.go Normal file
View File

@@ -0,0 +1,120 @@
package config
import (
"errors"
"fmt"
"os"
"path/filepath"
"regexp"
"github.com/docker/attest/tuf"
"sigs.k8s.io/yaml"
)
const (
MappingFilename = "mapping.yaml"
)
func validateMappingsFile(mappings *policyMappingsFile) error {
var validationErrors []error
if mappings.Kind != "policy-mapping" {
validationErrors = append(validationErrors, fmt.Errorf("file is not of kind policy-mapping: %s", mappings.Kind))
}
if mappings.Version != "v1" {
validationErrors = append(validationErrors, fmt.Errorf("unsupported policy mapping file version: %s", mappings.Version))
}
for _, rule := range mappings.Rules {
if rule.Pattern == "" {
validationErrors = append(validationErrors, fmt.Errorf("rule missing pattern: %s", rule))
}
if rule.PolicyID == "" && rule.Replacement == "" {
validationErrors = append(validationErrors, fmt.Errorf("rule must have policy-id or replacement: %s", rule))
}
if rule.PolicyID != "" && rule.Replacement != "" {
validationErrors = append(validationErrors, fmt.Errorf("rule cannot have both policy-id and replacement: %s", rule))
}
}
for _, policy := range mappings.Policies {
if policy.ID == "" {
validationErrors = append(validationErrors, fmt.Errorf("policy missing id: %s", policy.ID))
}
if len(policy.Files) == 0 {
validationErrors = append(validationErrors, fmt.Errorf("policy missing files: %v", policy))
}
for _, file := range policy.Files {
if file.Path == "" {
validationErrors = append(validationErrors, fmt.Errorf("file missing path: %s", file))
}
}
}
if len(validationErrors) > 0 {
return errors.Join(validationErrors...)
}
return nil
}
func parsePolicyMappingsFile(data []byte) (*PolicyMappings, error) {
mappings := &policyMappingsFile{}
err := yaml.Unmarshal(data, mappings)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal policy mapping file: %w", err)
}
err = validateMappingsFile(mappings)
if err != nil {
return nil, fmt.Errorf("invalid policy mapping file: %w", err)
}
return expandMappingFile(mappings)
}
func LoadLocalMappings(configDir string) (*PolicyMappings, error) {
if configDir == "" {
return nil, nil
}
path := filepath.Join(configDir, MappingFilename)
mappingFile, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("failed to read local policy mapping file %s: %w", path, err)
}
return parsePolicyMappingsFile(mappingFile)
}
func LoadTUFMappings(tufClient tuf.Downloader, localTargetsDir string) (*PolicyMappings, error) {
if tufClient == nil {
return nil, fmt.Errorf("tuf client not set")
}
filename := MappingFilename
file, err := tufClient.DownloadTarget(filename, filepath.Join(localTargetsDir, filename))
if err != nil {
return nil, fmt.Errorf("failed to download policy mapping file %s: %w", filename, err)
}
return parsePolicyMappingsFile(file.Data)
}
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
}

82
config/config_test.go Normal file
View File

@@ -0,0 +1,82 @@
package config
import (
"testing"
"github.com/stretchr/testify/require"
)
func newMapping() *policyMappingsFile {
return &policyMappingsFile{
Version: "v1",
Kind: "policy-mapping",
Policies: []*PolicyMapping{
{
ID: "docker-official-images",
Files: []PolicyMappingFile{
{
Path: "docker.io/library/alpine",
},
},
},
},
Rules: []*policyRuleFile{
{
Pattern: "docker.io/library/alpine",
PolicyID: "docker-official-images",
},
},
}
}
func TestMappingsFileValidation(t *testing.T) {
mappings := newMapping()
err := validateMappingsFile(mappings)
require.NoError(t, err)
mappings = newMapping()
mappings.Kind = "not-policy-mapping"
err = validateMappingsFile(mappings)
require.ErrorContains(t, err, "file is not of kind policy-mapping: not-policy-mapping")
mappings = newMapping()
mappings.Version = "v2"
err = validateMappingsFile(mappings)
require.ErrorContains(t, err, "unsupported policy mapping file version: v2")
mappings = newMapping()
mappings.Rules[0].Pattern = ""
err = validateMappingsFile(mappings)
require.ErrorContains(t, err, "rule missing pattern")
mappings = newMapping()
mappings.Rules[0].PolicyID = ""
err = validateMappingsFile(mappings)
require.ErrorContains(t, err, "rule must have policy-id or replacement")
mappings = newMapping()
mappings.Rules[0].PolicyID = "docker-official-images"
mappings.Rules[0].Replacement = "docker.io/library/alpine"
err = validateMappingsFile(mappings)
require.ErrorContains(t, err, "rule cannot have both policy-id and replacement")
mappings = newMapping()
mappings.Policies[0].ID = ""
err = validateMappingsFile(mappings)
require.ErrorContains(t, err, "policy missing id")
mappings = newMapping()
mappings.Policies[0].Files = nil
err = validateMappingsFile(mappings)
require.ErrorContains(t, err, "policy missing files")
mappings = newMapping()
mappings.Policies[0].Files[0].Path = ""
err = validateMappingsFile(mappings)
require.ErrorContains(t, err, "file missing path")
// multiple errors
mappings.Policies[0].ID = ""
err = validateMappingsFile(mappings)
require.ErrorContains(t, err, "policy missing id: \nfile missing path: {}")
}

View File

@@ -3,10 +3,10 @@ package attest_test
import (
"context"
"github.com/docker/attest/pkg/attest"
"github.com/docker/attest/pkg/attestation"
"github.com/docker/attest/pkg/oci"
"github.com/docker/attest/pkg/signerverifier"
"github.com/docker/attest"
"github.com/docker/attest/attestation"
"github.com/docker/attest/oci"
"github.com/docker/attest/signerverifier"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/empty"
"github.com/google/go-containerregistry/pkg/v1/mutate"
@@ -31,7 +31,7 @@ func ExampleSignStatements_remote() {
// load image index with unsigned attestation-manifests
ref := "docker/image-signer-verifier:latest"
attIdx, err := oci.IndexFromRemote(ref)
attIdx, err := oci.IndexFromRemote(context.Background(), ref)
if err != nil {
panic(err)
}
@@ -54,7 +54,7 @@ func ExampleSignStatements_remote() {
}
// push image index with signed attestation-manifests
err = oci.PushIndexToRegistry(signedIndex, ref)
err = oci.PushIndexToRegistry(context.Background(), signedIndex, ref)
if err != nil {
panic(err)
}

View File

@@ -6,10 +6,10 @@ import (
"os"
"path/filepath"
"github.com/docker/attest/pkg/attest"
"github.com/docker/attest/pkg/oci"
"github.com/docker/attest/pkg/policy"
"github.com/docker/attest/pkg/tuf"
"github.com/docker/attest"
"github.com/docker/attest/oci"
"github.com/docker/attest/policy"
"github.com/docker/attest/tuf"
)
func ExampleVerify_remote() {

107
go.mod
View File

@@ -4,27 +4,25 @@ go 1.22.5
require (
github.com/Masterminds/semver/v3 v3.3.0
github.com/aws/aws-sdk-go-v2/config v1.27.31
github.com/aws/aws-sdk-go-v2/config v1.27.33
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.20.1
github.com/hashicorp/go-cleanhttp v0.5.2
github.com/google/go-containerregistry v0.20.2
github.com/in-toto/in-toto-golang v0.9.0
github.com/open-policy-agent/opa v0.67.1
github.com/open-policy-agent/opa v0.68.0
github.com/opencontainers/image-spec v1.1.0
github.com/package-url/packageurl-go v0.1.3
github.com/secure-systems-lab/go-securesystemslib v0.8.0
github.com/sigstore/cosign/v2 v2.4.0
github.com/sigstore/rekor v1.3.6
github.com/sigstore/sigstore/pkg/signature/kms/aws v1.8.8
github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.8.8
github.com/sigstore/sigstore/pkg/signature/kms/aws v1.8.9
github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.8.9
github.com/stretchr/testify v1.9.0
github.com/testcontainers/testcontainers-go/modules/registry v0.33.0
github.com/theupdateframework/go-tuf/v2 v2.0.0
google.golang.org/api v0.194.0
google.golang.org/api v0.197.0
sigs.k8s.io/yaml v1.4.0
)
@@ -33,53 +31,44 @@ replace github.com/google/go-containerregistry => github.com/docker/go-container
require (
cloud.google.com/go v0.115.1 // indirect
cloud.google.com/go/auth v0.9.1 // indirect
cloud.google.com/go/auth v0.9.3 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.4 // indirect
cloud.google.com/go/compute/metadata v0.5.0 // indirect
cloud.google.com/go/iam v1.1.12 // indirect
cloud.google.com/go/kms v1.18.4 // indirect
cloud.google.com/go/longrunning v0.5.11 // indirect
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
cloud.google.com/go/iam v1.2.0 // indirect
cloud.google.com/go/kms v1.19.0 // indirect
cloud.google.com/go/longrunning v0.6.0 // indirect
github.com/OneOfOne/xxhash v1.2.8 // indirect
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.30.4 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.17.30 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.12 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.16 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.16 // indirect
github.com/aws/aws-sdk-go-v2 v1.30.5 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.17.32 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.13 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.17 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.17 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // 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.4 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.18 // indirect
github.com/aws/aws-sdk-go-v2/service/kms v1.35.3 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.22.5 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.5 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.30.5 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.19 // indirect
github.com/aws/aws-sdk-go-v2/service/kms v1.35.5 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.22.7 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.7 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.30.7 // indirect
github.com/aws/smithy-go v1.20.4 // 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/containerd v1.7.20 // 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
github.com/cyberphone/json-canonicalization v0.0.0-20231217050601-ba74d44ecf5f // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/digitorus/pkcs7 v0.0.0-20230818184609-3a137a874352 // indirect
github.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7 // indirect
github.com/docker/cli v27.1.1+incompatible // indirect
github.com/docker/distribution v2.8.3+incompatible // indirect
github.com/docker/docker v27.1.1+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
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
@@ -88,7 +77,6 @@ require (
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
github.com/go-openapi/analysis v0.23.0 // indirect
github.com/go-openapi/errors v0.22.0 // indirect
github.com/go-openapi/jsonpointer v0.21.0 // indirect
@@ -98,35 +86,28 @@ require (
github.com/go-openapi/swag v0.23.0 // indirect
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/snappy v0.0.4 // indirect
github.com/google/certificate-transparency-go v1.2.1 // indirect
github.com/google/s2a-go v0.1.8 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect
github.com/googleapis/gax-go/v2 v2.13.0 // indirect
github.com/gorilla/mux v1.8.1 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // 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/jellydator/ttlcache/v3 v3.3.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/klauspost/compress v1.17.9 // 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
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect
github.com/moby/patternmatcher v0.6.0 // indirect
github.com/moby/sys/sequential v0.5.0 // indirect
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
@@ -135,8 +116,7 @@ require (
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
github.com/prometheus/client_golang v1.19.1 // indirect
github.com/prometheus/client_golang v1.20.2 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.55.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
@@ -145,8 +125,6 @@ require (
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/sassoftware/relic v7.2.1+incompatible // indirect
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/protobuf-specs v0.3.2 // indirect
github.com/sigstore/sigstore v1.8.8 // indirect
github.com/sigstore/timestamp-authority v1.2.2 // indirect
@@ -160,44 +138,41 @@ require (
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.33.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
github.com/tklauser/numcpus v0.8.0 // indirect
github.com/transparency-dev/merkle v0.0.2 // indirect
github.com/vbatts/tar-split v0.11.5 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/yashtewari/glob-intersection v0.2.0 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
go.mongodb.org/mongo-driver v1.15.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.53.0 // indirect
go.opentelemetry.io/otel v1.28.0 // indirect
go.opentelemetry.io/otel/metric v1.28.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect
go.opentelemetry.io/otel v1.29.0 // indirect
go.opentelemetry.io/otel/metric v1.29.0 // indirect
go.opentelemetry.io/otel/sdk v1.28.0 // indirect
go.opentelemetry.io/otel/trace v1.28.0 // indirect
go.opentelemetry.io/otel/trace v1.29.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/crypto v0.26.0 // indirect
golang.org/x/crypto v0.27.0 // indirect
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect
golang.org/x/mod v0.19.0 // indirect
golang.org/x/net v0.28.0 // indirect
golang.org/x/oauth2 v0.22.0 // indirect
golang.org/x/net v0.29.0 // indirect
golang.org/x/oauth2 v0.23.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.24.0 // indirect
golang.org/x/term v0.23.0 // indirect
golang.org/x/text v0.17.0 // indirect
golang.org/x/sys v0.25.0 // indirect
golang.org/x/term v0.24.0 // indirect
golang.org/x/text v0.18.0 // indirect
golang.org/x/time v0.6.0 // indirect
google.golang.org/genproto v0.0.0-20240814211410-ddb44dafa142 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240730163845-b1a4ccb954bf // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect
google.golang.org/grpc v1.65.0 // indirect
google.golang.org/genproto v0.0.0-20240903143218-8af14fe29dc1 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect
google.golang.org/grpc v1.66.1 // 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
gopkg.in/yaml.v3 v3.0.1 // indirect
gotest.tools/v3 v3.5.1 // indirect
k8s.io/klog/v2 v2.120.1 // indirect
)

227
go.sum
View File

@@ -1,28 +1,24 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.115.1 h1:Jo0SM9cQnSkYfp44+v+NQXHpcHqlnRJk2qxh6yvxxxQ=
cloud.google.com/go v0.115.1/go.mod h1:DuujITeaufu3gL68/lOFIirVNJwQeyf5UXyi+Wbgknc=
cloud.google.com/go/auth v0.9.1 h1:+pMtLEV2k0AXKvs/tGZojuj6QaioxfUjOpMsG5Gtx+w=
cloud.google.com/go/auth v0.9.1/go.mod h1:Sw8ocT5mhhXxFklyhT12Eiy0ed6tTrPMCJjSI8KhYLk=
cloud.google.com/go/auth v0.9.3 h1:VOEUIAADkkLtyfr3BLa3R8Ed/j6w1jTBmARx+wb5w5U=
cloud.google.com/go/auth v0.9.3/go.mod h1:7z6VY+7h3KUdRov5F1i8NDP5ZzWKYmEPO842BgCsmTk=
cloud.google.com/go/auth/oauth2adapt v0.2.4 h1:0GWE/FUsXhf6C+jAkWgYm7X9tK8cuEIfy19DBn6B6bY=
cloud.google.com/go/auth/oauth2adapt v0.2.4/go.mod h1:jC/jOpwFP6JBxhB3P5Rr0a9HLMC/Pe3eaL4NmdvqPtc=
cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY=
cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY=
cloud.google.com/go/iam v1.1.12 h1:JixGLimRrNGcxvJEQ8+clfLxPlbeZA6MuRJ+qJNQ5Xw=
cloud.google.com/go/iam v1.1.12/go.mod h1:9LDX8J7dN5YRyzVHxwQzrQs9opFFqn0Mxs9nAeB+Hhg=
cloud.google.com/go/kms v1.18.4 h1:dYN3OCsQ6wJLLtOnI8DGUwQ5shMusXsWCCC+s09ATsk=
cloud.google.com/go/kms v1.18.4/go.mod h1:SG1bgQ3UWW6/KdPo9uuJnzELXY5YTTMJtDYvajiQ22g=
cloud.google.com/go/longrunning v0.5.11 h1:Havn1kGjz3whCfoD8dxMLP73Ph5w+ODyZB9RUsDxtGk=
cloud.google.com/go/longrunning v0.5.11/go.mod h1:rDn7//lmlfWV1Dx6IB4RatCPenTwwmqXuiP0/RgoEO4=
cloud.google.com/go/iam v1.2.0 h1:kZKMKVNk/IsSSc/udOb83K0hL/Yh/Gcqpz+oAkoIFN8=
cloud.google.com/go/iam v1.2.0/go.mod h1:zITGuWgsLZxd8OwAlX+eMFgZDXzBm7icj1PVTYG766Q=
cloud.google.com/go/kms v1.19.0 h1:x0OVJDl6UH1BSX4THKlMfdcFWoE4ruh90ZHuilZekrU=
cloud.google.com/go/kms v1.19.0/go.mod h1:e4imokuPJUc17Trz2s6lEXFDt8bgDmvpVynH39bdrHM=
cloud.google.com/go/longrunning v0.6.0 h1:mM1ZmaNsQsnb+5n1DNPeL0KwQd9jQRqSqSDEkBZr+aI=
cloud.google.com/go/longrunning v0.6.0/go.mod h1:uHzSZqW89h7/pasCWNYdUpwGz3PcVWhrWupreVPYLts=
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=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU=
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
github.com/AdamKorcz/go-fuzz-headers-1 v0.0.0-20230919221257-8b5d3ce2d11d h1:zjqpY4C7H15HjRPEenkS4SAn3Jy2eRRjkjZbGR30TOg=
github.com/AdamKorcz/go-fuzz-headers-1 v0.0.0-20230919221257-8b5d3ce2d11d/go.mod h1:XNqJ7hv2kY++g8XEHREpi+JqZo3+0l+CH2egBVN4yqM=
github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/alibabacloudsdkgo/helper v0.2.0 h1:8+4G8JaejP8Xa6W46PzJEwisNgBXMvFcz78N6zG/ARw=
@@ -39,8 +35,6 @@ github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.1.0 h1:DRiANoJ
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=
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0/go.mod h1:bTSOgj05NGRuHHhQwAdPnYr9TOdNmKlZTgGLL6nyAdI=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs=
github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
github.com/Azure/go-autorest/autorest v0.11.29 h1:I4+HL/JDvErx2LjyzaVxllw2lRDB5/BT2Bm4g20iqYw=
@@ -102,18 +96,18 @@ github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3d
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
github.com/aws/aws-sdk-go v1.55.5 h1:KKUZBfBoyqy5d3swXyiC7Q76ic40rYcbqH7qjh59kzU=
github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU=
github.com/aws/aws-sdk-go-v2 v1.30.4 h1:frhcagrVNrzmT95RJImMHgabt99vkXGslubDaDagTk8=
github.com/aws/aws-sdk-go-v2 v1.30.4/go.mod h1:CT+ZPWXbYrci8chcARI3OmI/qgd+f6WtuLOoaIA8PR0=
github.com/aws/aws-sdk-go-v2/config v1.27.31 h1:kxBoRsjhT3pq0cKthgj6RU6bXTm/2SgdoUMyrVw0rAI=
github.com/aws/aws-sdk-go-v2/config v1.27.31/go.mod h1:z04nZdSWFPaDwK3DdJOG2r+scLQzMYuJeW0CujEm9FM=
github.com/aws/aws-sdk-go-v2/credentials v1.17.30 h1:aau/oYFtibVovr2rDt8FHlU17BTicFEMAi29V1U+L5Q=
github.com/aws/aws-sdk-go-v2/credentials v1.17.30/go.mod h1:BPJ/yXV92ZVq6G8uYvbU0gSl8q94UB63nMT5ctNO38g=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.12 h1:yjwoSyDZF8Jth+mUk5lSPJCkMC0lMy6FaCD51jm6ayE=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.12/go.mod h1:fuR57fAgMk7ot3WcNQfb6rSEn+SUffl7ri+aa8uKysI=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.16 h1:TNyt/+X43KJ9IJJMjKfa3bNTiZbUP7DeCxfbTROESwY=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.16/go.mod h1:2DwJF39FlNAUiX5pAc0UNeiz16lK2t7IaFcm0LFHEgc=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.16 h1:jYfy8UPmd+6kJW5YhY0L1/KftReOGxI/4NtVSTh9O/I=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.16/go.mod h1:7ZfEPZxkW42Afq4uQB8H2E2e6ebh6mXTueEpYzjCzcs=
github.com/aws/aws-sdk-go-v2 v1.30.5 h1:mWSRTwQAb0aLE17dSzztCVJWI9+cRMgqebndjwDyK0g=
github.com/aws/aws-sdk-go-v2 v1.30.5/go.mod h1:CT+ZPWXbYrci8chcARI3OmI/qgd+f6WtuLOoaIA8PR0=
github.com/aws/aws-sdk-go-v2/config v1.27.33 h1:Nof9o/MsmH4oa0s2q9a0k7tMz5x/Yj5k06lDODWz3BU=
github.com/aws/aws-sdk-go-v2/config v1.27.33/go.mod h1:kEqdYzRb8dd8Sy2pOdEbExTTF5v7ozEXX0McgPE7xks=
github.com/aws/aws-sdk-go-v2/credentials v1.17.32 h1:7Cxhp/BnT2RcGy4VisJ9miUPecY+lyE9I8JvcZofn9I=
github.com/aws/aws-sdk-go-v2/credentials v1.17.32/go.mod h1:P5/QMF3/DCHbXGEGkdbilXHsyTBX5D3HSwcrSc9p20I=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.13 h1:pfQ2sqNpMVK6xz2RbqLEL0GH87JOwSxPV2rzm8Zsb74=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.13/go.mod h1:NG7RXPUlqfsCLLFfi0+IpKN4sCB9D9fw/qTaSB+xRoU=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.17 h1:pI7Bzt0BJtYA0N/JEC6B8fJ4RBrEMi1LBrkMdFYNSnQ=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.17/go.mod h1:Dh5zzJYMtxfIjYW+/evjQ8uj2OyR/ve2KROHGHlSFqE=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.17 h1:Mqr/V5gvrhA2gvgnF42Zh5iMiQNcOYthFYwCyrnuWlc=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.17/go.mod h1:aLJpZlCmjE+V+KtN1q1uyZkfnUWpQGpbsn89XPKyzfU=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc=
github.com/aws/aws-sdk-go-v2/service/ecr v1.29.1 h1:ywNLJrn/Qn4enDsz/XnKlvpnLqvJxFGQV2BltWltbis=
@@ -122,16 +116,16 @@ github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.24.1 h1:Eq9i/mvOlGghiKe9NtsmeD
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.4 h1:KypMCbLPPHEmf9DgMGw51jMj77VfGPAN2Kv4cfhlfgI=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.4/go.mod h1:Vz1JQXliGcQktFTN/LN6uGppAIRoLBR2bMvIMP0gOjc=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.18 h1:tJ5RnkHCiSH0jyd6gROjlJtNwov0eGYNz8s8nFcR0jQ=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.18/go.mod h1:++NHzT+nAF7ZPrHPsA+ENvsXkOO8wEu+C6RXltAG4/c=
github.com/aws/aws-sdk-go-v2/service/kms v1.35.3 h1:UPTdlTOwWUX49fVi7cymEN6hDqCwe3LNv1vi7TXUutk=
github.com/aws/aws-sdk-go-v2/service/kms v1.35.3/go.mod h1:gjDP16zn+WWalyaUqwCCioQ8gU8lzttCCc9jYsiQI/8=
github.com/aws/aws-sdk-go-v2/service/sso v1.22.5 h1:zCsFCKvbj25i7p1u94imVoO447I/sFv8qq+lGJhRN0c=
github.com/aws/aws-sdk-go-v2/service/sso v1.22.5/go.mod h1:ZeDX1SnKsVlejeuz41GiajjZpRSWR7/42q/EyA/QEiM=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.5 h1:SKvPgvdvmiTWoi0GAJ7AsJfOz3ngVkD/ERbs5pUnHNI=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.5/go.mod h1:20sz31hv/WsPa3HhU3hfrIet2kxM4Pe0r20eBZ20Tac=
github.com/aws/aws-sdk-go-v2/service/sts v1.30.5 h1:OMsEmCyz2i89XwRwPouAJvhj81wINh+4UK+k/0Yo/q8=
github.com/aws/aws-sdk-go-v2/service/sts v1.30.5/go.mod h1:vmSqFK+BVIwVpDAGZB3CoCXHzurt4qBE8lf+I/kRTh0=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.19 h1:rfprUlsdzgl7ZL2KlXiUAoJnI/VxfHCvDFr2QDFj6u4=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.19/go.mod h1:SCWkEdRq8/7EK60NcvvQ6NXKuTcchAD4ROAsC37VEZE=
github.com/aws/aws-sdk-go-v2/service/kms v1.35.5 h1:XUomV7SiclZl1QuXORdGcfFqHxEHET7rmNGtxTfNB+M=
github.com/aws/aws-sdk-go-v2/service/kms v1.35.5/go.mod h1:A5CS0VRmxxj2YKYLCY08l/Zzbd01m6JZn0WzxgT1OCA=
github.com/aws/aws-sdk-go-v2/service/sso v1.22.7 h1:pIaGg+08llrP7Q5aiz9ICWbY8cqhTkyy+0SHvfzQpTc=
github.com/aws/aws-sdk-go-v2/service/sso v1.22.7/go.mod h1:eEygMHnTKH/3kNp9Jr1n3PdejuSNcgwLe1dWgQtO0VQ=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.7 h1:/Cfdu0XV3mONYKaOt1Gr0k1KvQzkzPyiKUdlWJqy+J4=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.7/go.mod h1:bCbAxKDqNvkHxRaIMnyVPXPo+OaPRwvmgzMxbz1VKSA=
github.com/aws/aws-sdk-go-v2/service/sts v1.30.7 h1:NKTa1eqZYw8tiHSRGpP0VtTdub/8KNk8sDkNPFaOKDE=
github.com/aws/aws-sdk-go-v2/service/sts v1.30.7/go.mod h1:NXi1dIAGteSaRLqYgarlhP/Ij0cFT+qmCwiJqWh/U5o=
github.com/aws/smithy-go v1.20.4 h1:2HK1zBdPgRbjFOHlfeQZfpC4r72MOb9bZkiFwggKO+4=
github.com/aws/smithy-go v1.20.4/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg=
github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20231024185945-8841054dbdb8 h1:SoFYaT9UyGkR0+nogNyD/Lj+bsixB+SNuAS4ABlEs6M=
@@ -178,8 +172,6 @@ github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb h1:EDmT6Q9Zs+SbUo
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.20 h1:Sl6jQYk3TRavaU83h66QMbI2Nqg9Jm6qzwX57Vsn1SQ=
github.com/containerd/containerd v1.7.20/go.mod h1:52GsS5CwquuqPuLncsXwG0t2CiUce+KsNHJZQJvAgR0=
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=
@@ -188,11 +180,7 @@ github.com/containerd/stargz-snapshotter/estargz v0.15.1 h1:eXJjw9RbkLFgioVaTG+G
github.com/containerd/stargz-snapshotter/estargz v0.15.1/go.mod h1:gr2RNwukQ/S9Nv33Lt6UC7xEx58C+LHRdoqbEKjz1Kk=
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.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=
github.com/cyberphone/json-canonicalization v0.0.0-20231217050601-ba74d44ecf5f/go.mod h1:uzvlm1mxhHkdfqitSA92i7Se+S9ksOn3a3qmv/kyOCw=
github.com/danieljoos/wincred v1.2.1 h1:dl9cBrupW8+r5250DYkYxocLeZ1Y4vB1kxgtjxw8GQs=
@@ -220,16 +208,10 @@ github.com/docker/cli v27.1.1+incompatible h1:goaZxOqs4QKxznZjjBWKONQci/MywhtRv2
github.com/docker/cli v27.1.1+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 v27.1.1+incompatible h1:hO/M4MtV36kzKldqnA37IWhebRA+LnqqcqDja6kVaKY=
github.com/docker/docker v27.1.1+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=
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
github.com/docker/go-containerregistry v0.0.0-20240808132857-c8bfc44af7c8 h1:T/wutVfQ1Oj4H5tbP5IZL5l6PZqzvapVJ5cB4Wy4Ucc=
github.com/docker/go-containerregistry v0.0.0-20240808132857-c8bfc44af7c8/go.mod h1:z38EKdKh4h7IP2gSfUUqEvalZBqs6AoLeWfUy34nQC8=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
@@ -268,9 +250,6 @@ github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
github.com/go-openapi/analysis v0.23.0 h1:aGday7OWupfMs+LbmLZG4k0MYXIANxcuBTYUC03zFCU=
github.com/go-openapi/analysis v0.23.0/go.mod h1:9mz9ZWaSlV8TvjQHLl2mUW2PbZtemkE8yA5v22ohupo=
github.com/go-openapi/errors v0.22.0 h1:c4xY/OLxUBSTiepAg3j/MHuAv5mJhnf53LLMWFB+u/w=
@@ -342,7 +321,6 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
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=
@@ -362,8 +340,8 @@ github.com/google/trillian v1.6.0/go.mod h1:Yu3nIMITzNhhMJEHjAtp6xKiu+H/iHu2Oq5F
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/enterprise-certificate-proxy v0.3.4 h1:XYIDZApgAnrN1c855gTgghdIA6Stxb52D5RnLI1SLyw=
github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA=
github.com/googleapis/gax-go/v2 v2.13.0 h1:yitjD5f7jQHhyDsnhKEBU52NdvvdSeGzlAnDPT0hH1s=
github.com/googleapis/gax-go/v2 v2.13.0/go.mod h1:Z/fvTZXF8/uw7Xu5GuslPw+bplx6SS338j1Is2S+B7A=
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
@@ -405,8 +383,8 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267 h1:TMtDYDHKYY15rFihtRfck/bfFqNfvcabqvXAFQfAUpY=
github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267/go.mod h1:h1nSAbGFqGVzn6Jyl1R/iCcBUHN4g+gW1u9CoBTrb9E=
github.com/jellydator/ttlcache/v3 v3.2.0 h1:6lqVJ8X3ZaUwvzENqPAobDsXNExfUJd61u++uW8a3LE=
github.com/jellydator/ttlcache/v3 v3.2.0/go.mod h1:hi7MGFdMAwZna5n2tuvh63DvFLzVKySzCVW6+0gA2n4=
github.com/jellydator/ttlcache/v3 v3.3.0 h1:BdoC9cE81qXfrxeb9eoJi9dWrdhSuwXMAnHTbnBm4Wc=
github.com/jellydator/ttlcache/v3 v3.3.0/go.mod h1:bj2/e0l4jRnQdrnSTaGTsh4GSXvMjQcy41i7th0GVGw=
github.com/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=
@@ -417,10 +395,8 @@ github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8Hm
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/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=
github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
@@ -429,9 +405,6 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
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=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
@@ -450,22 +423,10 @@ github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQ
github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc=
github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo=
github.com/moby/sys/user v0.1.0 h1:WmZ93f5Ux6het5iituh9x2zAG7NFY9Aqi49jjE1PaQg=
github.com/moby/sys/user v0.1.0/go.mod h1:fKJhFOnsCN6xZ5gSfbM6zaHGgDJMrqt9/reuj4T7MmU=
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/mozillazg/docker-credential-acr-helper v0.3.0 h1:DVWFZ3/O8BP6Ue3iS/Olw+G07u1hCq1EOVCDZZjCIBI=
github.com/mozillazg/docker-credential-acr-helper v0.3.0/go.mod h1:cZlu3tof523ujmLuiNUb6JsjtHcNA70u1jitrrdnuyA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
@@ -491,8 +452,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.67.1 h1:rzy26J6g1X+CKknAcx0Vfbt41KqjuSzx4E0A8DAZf3E=
github.com/open-policy-agent/opa v0.67.1/go.mod h1:aqKlHc8E2VAAylYE9x09zJYr/fYzGX+JKne89UGqFzk=
github.com/open-policy-agent/opa v0.68.0 h1:Jl3U2vXRjwk7JrHmS19U3HZO5qxQRinQbJ2eCJYSqJQ=
github.com/open-policy-agent/opa v0.68.0/go.mod h1:5E5SvaPwTpwt2WM177I9Z3eT7qUpmOGjk1ZdHs+TZ4w=
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=
@@ -512,11 +473,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
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_golang v1.20.2 h1:5ctymQzZlyOON1666svgwn3s6IKWgfbjsejTMiXIyjg=
github.com/prometheus/client_golang v1.20.2/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_model v0.0.0-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=
@@ -547,12 +505,6 @@ github.com/segmentio/ksuid v1.0.4 h1:sBo2BdShXjmcugAMwjugoGUdUV0pcxY5mW4xKRn3v4c
github.com/segmentio/ksuid v1.0.4/go.mod h1:/XUiZBD3kVx5SmUOl55voK5yeAbBNNIed+2O73XgrPE=
github.com/shibumi/go-pathspec v1.3.0 h1:QUyMZhFo0Md5B8zV8x2tesohbb5kfbpTi9rBnKh5dkI=
github.com/shibumi/go-pathspec v1.3.0/go.mod h1:Xutfslp817l2I1cZvgcfeMQJG5QnU2lh5tVaaMCl3jE=
github.com/shirou/gopsutil/v3 v3.24.4 h1:dEHgzZXt4LMNm+oYELpzl9YCqV65Yr/6SfrvgRBtXeU=
github.com/shirou/gopsutil/v3 v3.24.4/go.mod h1:lTd2mdiOspcqLgAnr9/nGi71NkeMpWKdmhuxm9GusH8=
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
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.4.0 h1:2NdidNgClg+oXr/fDIr37E/BE6j00gqgUhSiBK2kjSQ=
github.com/sigstore/cosign/v2 v2.4.0/go.mod h1:j+fH1DCUkcn92qp6ezDj4JbGMri6eG1nLJC+hs64rvc=
github.com/sigstore/fulcio v1.5.1 h1:Iasy1zfNjaq8BV4S8o6pXspLDU28PQC2z07GmOu9zpM=
@@ -565,12 +517,12 @@ github.com/sigstore/sigstore v1.8.8 h1:B6ZQPBKK7Z7tO3bjLNnlCMG+H66tO4E/+qAphX8T/
github.com/sigstore/sigstore v1.8.8/go.mod h1:GW0GgJSCTBJY3fUOuGDHeFWcD++c4G8Y9K015pwcpDI=
github.com/sigstore/sigstore-go v0.5.1 h1:5IhKvtjlQBeLnjKkzMELNG4tIBf+xXQkDzhLV77+/8Y=
github.com/sigstore/sigstore-go v0.5.1/go.mod h1:TuOfV7THHqiDaUHuJ5+QN23RP/YoKmsbwJpY+aaYPN0=
github.com/sigstore/sigstore/pkg/signature/kms/aws v1.8.8 h1:2zHmUvaYCwV6LVeTo+OAkTm8ykOGzA9uFlAjwDPAUWM=
github.com/sigstore/sigstore/pkg/signature/kms/aws v1.8.8/go.mod h1:OEhheBplZinUsm7W9BupafztVZV3ldkAxEHbpAeC0Pk=
github.com/sigstore/sigstore/pkg/signature/kms/aws v1.8.9 h1:tgpdvjyoEgYFeTBFe4MHvBKsG+J4E7NVtstChIExVT8=
github.com/sigstore/sigstore/pkg/signature/kms/aws v1.8.9/go.mod h1:wCz6cAZKL/wFumDHX9l8VkVITS2GntrOfs2j/kwH4wo=
github.com/sigstore/sigstore/pkg/signature/kms/azure v1.8.8 h1:RKk4Z+qMaLORUdT7zntwMqKiYAej1VQlCswg0S7xNSY=
github.com/sigstore/sigstore/pkg/signature/kms/azure v1.8.8/go.mod h1:dMJdlBWKHMu2xf0wIKpbo7+QfG+RzVkBB3nHP8EMM5o=
github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.8.8 h1:89Xtxj8oqZt3UlSpCP4wApFvnQ2Z/dgowW5QOVhQigI=
github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.8.8/go.mod h1:Wa4xn/H3pU/yW/6tHiMXTpObBtBSGC5q29KYFEPKN6o=
github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.8.9 h1:liWcl12dfFeQXU0JemQVgdVQx02Fls9UPdrFzVrCWhs=
github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.8.9/go.mod h1:Ckx62auqPQvNJWRBAboY+/kHs77gy6L33b6UtB/FB5U=
github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.8.8 h1:Zte3Oogkd8m+nu2oK3yHtGmN++TZWh2Lm6q2iSprT1M=
github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.8.8/go.mod h1:j00crVw6ki4/WViXflw0zWgNALrAzZT+GbIK8v7Xlz4=
github.com/sigstore/timestamp-authority v1.2.2 h1:X4qyutnCQqJ0apMewFyx+3t7Tws00JQ/JonBiu3QvLE=
@@ -613,10 +565,6 @@ 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.33.0 h1:zJS9PfXYT5O0ZFXM2xxXfk4J5UMw/kRiISng037Gxdw=
github.com/testcontainers/testcontainers-go v0.33.0/go.mod h1:W80YpTa8D5C3Yy16icheD01UTDu+LmXIA2Keo+jWtT8=
github.com/testcontainers/testcontainers-go/modules/registry v0.33.0 h1:rpQS5KcFpyRPM3xVKERuXDqUcE5xjwE8MQUgmKVkL0o=
github.com/testcontainers/testcontainers-go/modules/registry v0.33.0/go.mod h1:qr3nJgBZ2ovQva6vadXchwi786/mBBDzhBPbrmWkYIE=
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=
@@ -627,12 +575,6 @@ github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 h1:e/5i7d4oYZ+C
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=
github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU=
github.com/tklauser/go-sysconf v0.3.14/go.mod h1:1ym4lWMLUOhuBOPGtRcJm7tEGX4SCYNEEEtghGG/8uY=
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
github.com/tklauser/numcpus v0.8.0 h1:Mx4Wwe/FjZLeQsK/6kt2EOepwwSl7SmJrK5bV/dXYgY=
github.com/tklauser/numcpus v0.8.0/go.mod h1:ZJZlAY+dmR4eut8epnzf0u/VwodKmryxR8txiloSqBE=
github.com/transparency-dev/merkle v0.0.2 h1:Q9nBoQcZcgPamMkGn7ghV8XiTZ/kRxn1yCG81+twTK4=
github.com/transparency-dev/merkle v0.0.2/go.mod h1:pqSy+OXefQ1EDUVmAJ8MUhHB9TXGuzVAT58PqBoHz1A=
github.com/vbatts/tar-split v0.11.5 h1:3bHCTIheBm1qFTcgh9oPu+nNBtX+XJIupG/vacinCts=
@@ -645,11 +587,8 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHo
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/yashtewari/glob-intersection v0.2.0 h1:8iuHdN88yYuCzCdjt0gDe+6bAhUwBeEWqThExu54RFg=
github.com/yashtewari/glob-intersection v0.2.0/go.mod h1:LK7pIC3piUjovexikBbJ26Yml7g8xa5bsjfx2v1fwok=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
github.com/zalando/go-keyring v0.2.3 h1:v9CUu9phlABObO4LPWycf+zwMG7nlbb3t/B5wa97yms=
github.com/zalando/go-keyring v0.2.3/go.mod h1:HL4k+OXQfJUWaMnqyuSOc0drfGPX2b51Du6K+MRgZMk=
github.com/zeebo/errs v1.3.0 h1:hmiaKqgYZzcVgRL1Vkc1Mn2914BbzB0IBxs+ebeutGs=
@@ -658,24 +597,22 @@ 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.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.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg=
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/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 h1:r6I7RJCN86bpD/FQwedZ0vSixDpwuWREjW9oRMsmqDc=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0/go.mod h1:B9yO6b04uB80CzjedvewuqDhxJxi11s7/GtiGa8bAjI=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8=
go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw=
go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 h1:R3X6ZXmNPRR8ul6i3WgFURCHzaXjHdm0karRG/+dj3s=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0/go.mod h1:QWFXnDavXWwMx2EEcZsf3yxgEKAqsxQ+Syjp+seyInw=
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.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q=
go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s=
go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc=
go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8=
go.opentelemetry.io/otel/sdk v1.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/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4=
go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ=
go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0=
go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8=
go.step.sm/crypto v0.51.1 h1:ktUg/2hetEMiBAqgz502ktZDGoDoGrcHFg3XpkmkvvA=
@@ -692,15 +629,14 @@ 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.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
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=
@@ -713,7 +649,6 @@ golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73r
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=
@@ -725,15 +660,14 @@ 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.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA=
golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs=
golang.org/x/oauth2 v0.23.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=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -744,40 +678,33 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h
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=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
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.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
golang.org/x/sys v0.25.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.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU=
golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk=
golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM=
golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8=
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=
@@ -785,8 +712,8 @@ 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.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -795,9 +722,7 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3
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.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg=
@@ -807,26 +732,26 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T
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.194.0 h1:dztZKG9HgtIpbI35FhfuSNR/zmaMVdxNlntHj1sIS4s=
google.golang.org/api v0.194.0/go.mod h1:AgvUFdojGANh3vI+P7EVnxj3AISHllxGCJSFmggmnd0=
google.golang.org/api v0.197.0 h1:x6CwqQLsFiA5JKAiGyGBjc2bNtHtLddhJCE2IKuhhcQ=
google.golang.org/api v0.197.0/go.mod h1:AuOuo20GoQ331nq7DquGHlU6d+2wN2fZ8O0ta60nRNw=
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-20240814211410-ddb44dafa142 h1:oLiyxGgE+rt22duwci1+TG7bg2/L1LQsXwfjPlmuJA0=
google.golang.org/genproto v0.0.0-20240814211410-ddb44dafa142/go.mod h1:G11eXq53iI5Q+kyNOmCvnzBaxEA2Q/Ik5Tj7nqBE8j4=
google.golang.org/genproto/googleapis/api v0.0.0-20240730163845-b1a4ccb954bf h1:GillM0Ef0pkZPIB+5iO6SDK+4T9pf6TpaYR6ICD5rVE=
google.golang.org/genproto/googleapis/api v0.0.0-20240730163845-b1a4ccb954bf/go.mod h1:OFMYQFHJ4TM3JRlWDZhJbZfra2uqc3WLBZiaaqP4DtU=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 h1:e7S5W7MGGLaSu8j3YjdezkZ+m1/Nm0uRVRMEMGk26Xs=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
google.golang.org/genproto v0.0.0-20240903143218-8af14fe29dc1 h1:BulPr26Jqjnd4eYDVe+YvyR7Yc2vJGkO5/0UxD0/jZU=
google.golang.org/genproto v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:hL97c3SYopEHblzpxRL4lSs523++l8DYxGM1FQiYmb4=
google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed h1:3RgNmBoI9MZhsj3QxC+AP/qQhNwpCLOvYDYYsFrhFt0=
google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed/go.mod h1:OCdP9MfskevB/rbYvHTsXTtKC+3bHWajPdoKgjcYkfo=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
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/grpc v1.66.1 h1:hO5qAXR19+/Z44hmvIM4dQFMSYX9XcWsByfoxutBpAM=
google.golang.org/grpc v1.66.1/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=

View File

@@ -2,26 +2,39 @@ package test
import (
"context"
"crypto"
"crypto/x509"
_ "embed"
"encoding/pem"
"fmt"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"strings"
"testing"
"time"
"github.com/docker/attest/pkg/policy"
"github.com/docker/attest/pkg/signerverifier"
"github.com/docker/attest/pkg/tlog"
"github.com/docker/attest/attestation"
"github.com/docker/attest/signerverifier"
"github.com/docker/attest/tlog"
"github.com/docker/attest/useragent"
"github.com/google/go-containerregistry/pkg/registry"
"github.com/secure-systems-lab/go-securesystemslib/dsse"
)
const (
UseMockTL = true
UseMockKMS = true
UseMockPolicy = true
UseMockTL = true
UseMockKMS = true
AWSRegion = "us-east-1"
AWSKMSKeyARN = "arn:aws:kms:us-east-1:175142243308:alias/doi-signing" // sandbox
)
var UnsignedTestImage = filepath.Join("..", "..", "test", "testdata", "unsigned-test-image")
func UnsignedTestImage(rel ...string) string {
rel = append(rel, "test", "testdata", "unsigned-test-image")
return filepath.Join(rel...)
}
func CreateTempDir(t *testing.T, dir, pattern string) string {
// Create a temporary directory for output oci layout
@@ -39,12 +52,11 @@ func CreateTempDir(t *testing.T, dir, pattern string) string {
return tempDir
}
//go:embed test-signing-key.pem
var signingKey []byte
func GetMockSigner(_ 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)
return signerverifier.LoadKeyPair(signingKey)
}
func Setup(t *testing.T) (context.Context, dsse.SignerVerifier) {
@@ -57,15 +69,6 @@ func Setup(t *testing.T) (context.Context, dsse.SignerVerifier) {
ctx := tlog.WithTL(context.Background(), tl)
var policyEvaluator policy.Evaluator
if UseMockPolicy {
policyEvaluator = policy.GetMockPolicy()
} else {
policyEvaluator = policy.NewRegoEvaluator(true)
}
ctx = policy.WithPolicyEvaluator(ctx, policyEvaluator)
var signer dsse.SignerVerifier
var err error
if UseMockKMS {
@@ -82,3 +85,51 @@ func Setup(t *testing.T) (context.Context, dsse.SignerVerifier) {
return ctx, signer
}
func NewLocalRegistry(ctx context.Context, options ...registry.Option) *httptest.Server {
regHandler := registry.New(options...)
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Check the user agent
ua := r.Header.Get("User-Agent")
userAgent := useragent.Get(ctx)
if !strings.HasPrefix(ua, userAgent) {
http.Error(w, fmt.Sprintf("expected user agent to contain %q, got %q", userAgent, ua), http.StatusForbidden)
}
regHandler.ServeHTTP(w, r)
}))
}
func publicKeyToPEM(pubKey crypto.PublicKey) (string, error) {
derBytes, err := x509.MarshalPKIXPublicKey(pubKey)
if err != nil {
return "", err
}
pemBlock := &pem.Block{
Type: "PUBLIC KEY",
Bytes: derBytes,
}
return string(pem.EncodeToMemory(pemBlock)), nil
}
// LoadKeyMetadata loads the key metadata for the given signer verifier.
func GenKeyMetadata(sv dsse.SignerVerifier) (*attestation.KeyMetadata, error) {
pub := sv.Public()
pem, err := publicKeyToPEM(pub)
if err != nil {
return nil, fmt.Errorf("failed to convert public key to PEM: %w", err)
}
id, err := sv.KeyID()
if err != nil {
return nil, err
}
return &attestation.KeyMetadata{
ID: id,
Status: "active",
SigningFormat: "dssev1",
From: time.Now(),
PEM: pem,
}, nil
}

View File

@@ -1,14 +1,15 @@
package mirror_test
import (
"context"
"fmt"
"os"
"path/filepath"
"strings"
"github.com/docker/attest/pkg/mirror"
"github.com/docker/attest/pkg/oci"
"github.com/docker/attest/pkg/tuf"
"github.com/docker/attest/mirror"
"github.com/docker/attest/oci"
"github.com/docker/attest/tuf"
v1 "github.com/google/go-containerregistry/pkg/v1"
)
@@ -29,7 +30,8 @@ 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(tuf.DockerTUFRootStaging.Data, tufOutputPath, metadataURI, targetsURI, tuf.NewMockVersionChecker())
ctx := context.Background()
m, err := mirror.NewTUFMirror(ctx, tuf.DockerTUFRootStaging.Data, tufOutputPath, metadataURI, targetsURI, tuf.NewMockVersionChecker())
if err != nil {
panic(err)
}
@@ -64,7 +66,7 @@ func ExampleNewTUFMirror() {
}
// push metadata and targets to registry (optional)
err = mirrorToRegistry(mirrorOutput)
err = mirrorToRegistry(ctx, mirrorOutput)
if err != nil {
panic(err)
}
@@ -77,10 +79,10 @@ func ExampleNewTUFMirror() {
}
}
func mirrorToRegistry(o *TufMirrorOutput) error {
func mirrorToRegistry(ctx context.Context, o *TufMirrorOutput) error {
// push metadata to registry
metadataRepo := "registry-1.docker.io/docker/tuf-metadata:latest"
err := oci.PushImageToRegistry(o.metadata, metadataRepo)
err := oci.PushImageToRegistry(ctx, o.metadata, metadataRepo)
if err != nil {
return err
}
@@ -91,7 +93,7 @@ func mirrorToRegistry(o *TufMirrorOutput) error {
return fmt.Errorf("failed to get repo without tag: %s", metadataRepo)
}
imageName := fmt.Sprintf("%s:%s", repo, metadata.Tag)
err = oci.PushImageToRegistry(metadata.Image, imageName)
err = oci.PushImageToRegistry(ctx, metadata.Image, imageName)
if err != nil {
return err
}
@@ -101,7 +103,7 @@ func mirrorToRegistry(o *TufMirrorOutput) error {
targetsRepo := "registry-1.docker.io/docker/tuf-targets"
for _, target := range o.targets {
imageName := fmt.Sprintf("%s:%s", targetsRepo, target.Tag)
err = oci.PushImageToRegistry(target.Image, imageName)
err = oci.PushImageToRegistry(ctx, target.Image, imageName)
if err != nil {
return err
}
@@ -109,7 +111,7 @@ func mirrorToRegistry(o *TufMirrorOutput) error {
// push delegated targets to registry
for _, target := range o.delegatedTargets {
imageName := fmt.Sprintf("%s:%s", targetsRepo, target.Tag)
err = oci.PushIndexToRegistry(target.Index, imageName)
err = oci.PushIndexToRegistry(ctx, target.Index, imageName)
if err != nil {
return err
}

View File

@@ -4,7 +4,7 @@ import (
"fmt"
"strconv"
"github.com/docker/attest/pkg/oci"
"github.com/docker/attest/oci"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/empty"
"github.com/google/go-containerregistry/pkg/v1/mutate"

View File

@@ -1,6 +1,7 @@
package mirror
import (
"context"
"encoding/json"
"net/http"
"net/http/httptest"
@@ -10,7 +11,7 @@ import (
"testing"
"github.com/docker/attest/internal/test"
"github.com/docker/attest/pkg/tuf"
"github.com/docker/attest/tuf"
"github.com/stretchr/testify/assert"
"github.com/theupdateframework/go-tuf/v2/metadata"
)
@@ -21,11 +22,11 @@ const (
)
func TestGetTufMetadataMirror(t *testing.T) {
server := httptest.NewServer(http.FileServer(http.Dir(filepath.Join("..", "..", "test", "testdata", "tuf", "test-repo"))))
server := httptest.NewServer(http.FileServer(http.Dir(filepath.Join("..", "test", "testdata", "tuf", "test-repo"))))
defer server.Close()
path := test.CreateTempDir(t, "", "tuf_temp")
m, err := NewTUFMirror(tuf.DockerTUFRootDev.Data, path, server.URL+metadataPath, server.URL+targetsPath, tuf.NewMockVersionChecker())
m, err := NewTUFMirror(context.Background(), tuf.DockerTUFRootDev.Data, path, server.URL+metadataPath, server.URL+targetsPath, tuf.NewMockVersionChecker())
assert.NoError(t, err)
tufMetadata, err := m.getMetadataMirror(server.URL + metadataPath)
@@ -39,11 +40,11 @@ func TestGetTufMetadataMirror(t *testing.T) {
}
func TestGetMetadataManifest(t *testing.T) {
server := httptest.NewServer(http.FileServer(http.Dir(filepath.Join("..", "..", "test", "testdata", "tuf", "test-repo"))))
server := httptest.NewServer(http.FileServer(http.Dir(filepath.Join("..", "test", "testdata", "tuf", "test-repo"))))
defer server.Close()
path := test.CreateTempDir(t, "", "tuf_temp")
m, err := NewTUFMirror(tuf.DockerTUFRootDev.Data, path, server.URL+metadataPath, server.URL+targetsPath, tuf.NewMockVersionChecker())
m, err := NewTUFMirror(context.Background(), tuf.DockerTUFRootDev.Data, path, server.URL+metadataPath, server.URL+targetsPath, tuf.NewMockVersionChecker())
assert.NoError(t, err)
img, err := m.GetMetadataManifest(server.URL + metadataPath)
@@ -78,11 +79,11 @@ func TestGetMetadataManifest(t *testing.T) {
}
func TestGetDelegatedMetadataMirrors(t *testing.T) {
server := httptest.NewServer(http.FileServer(http.Dir(filepath.Join("..", "..", "test", "testdata", "tuf", "test-repo"))))
server := httptest.NewServer(http.FileServer(http.Dir(filepath.Join("..", "test", "testdata", "tuf", "test-repo"))))
defer server.Close()
path := test.CreateTempDir(t, "", "tuf_temp")
m, err := NewTUFMirror(tuf.DockerTUFRootDev.Data, path, server.URL+metadataPath, server.URL+targetsPath, tuf.NewMockVersionChecker())
m, err := NewTUFMirror(context.Background(), tuf.DockerTUFRootDev.Data, path, server.URL+metadataPath, server.URL+targetsPath, tuf.NewMockVersionChecker())
assert.NoError(t, err)
delegations, err := m.GetDelegatedMetadataMirrors()

19
mirror/mirror.go Normal file
View File

@@ -0,0 +1,19 @@
package mirror
import (
"context"
"fmt"
"github.com/docker/attest/tuf"
)
func NewTUFMirror(ctx context.Context, root []byte, tufPath, metadataURL, targetsURL string, versionChecker tuf.VersionChecker) (*TUFMirror, error) {
if root == nil {
root = tuf.DockerTUFRootDefault.Data
}
tufClient, err := tuf.NewClient(ctx, &tuf.ClientOptions{InitialRoot: root, LocalStorageDir: tufPath, MetadataSource: metadataURL, TargetsSource: targetsURL, VersionChecker: versionChecker})
if err != nil {
return nil, fmt.Errorf("failed to create TUF client: %w", err)
}
return &TUFMirror{TUFClient: tufClient, tufPath: tufPath, metadataURL: metadataURL, targetsURL: targetsURL}, nil
}

View File

@@ -5,7 +5,7 @@ import (
"path/filepath"
"strings"
"github.com/docker/attest/pkg/oci"
"github.com/docker/attest/oci"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/empty"
"github.com/google/go-containerregistry/pkg/v1/mutate"

View File

@@ -1,6 +1,7 @@
package mirror
import (
"context"
"encoding/json"
"net/http"
"net/http/httptest"
@@ -9,7 +10,7 @@ import (
"testing"
"github.com/docker/attest/internal/test"
"github.com/docker/attest/pkg/tuf"
"github.com/docker/attest/tuf"
"github.com/stretchr/testify/assert"
)
@@ -22,11 +23,11 @@ type Layers struct {
}
func TestGetTufTargetsMirror(t *testing.T) {
server := httptest.NewServer(http.FileServer(http.Dir(filepath.Join("..", "..", "test", "testdata", "tuf", "test-repo"))))
server := httptest.NewServer(http.FileServer(http.Dir(filepath.Join("..", "test", "testdata", "tuf", "test-repo"))))
defer server.Close()
path := test.CreateTempDir(t, "", "tuf_temp")
m, err := NewTUFMirror(tuf.DockerTUFRootDev.Data, path, server.URL+metadataPath, server.URL+targetsPath, tuf.NewMockVersionChecker())
m, err := NewTUFMirror(context.Background(), tuf.DockerTUFRootDev.Data, path, server.URL+metadataPath, server.URL+targetsPath, tuf.NewMockVersionChecker())
assert.NoError(t, err)
targets, err := m.GetTUFTargetMirrors()
@@ -56,11 +57,11 @@ func TestGetTufTargetsMirror(t *testing.T) {
}
func TestTargetDelegationMetadata(t *testing.T) {
server := httptest.NewServer(http.FileServer(http.Dir(filepath.Join("..", "..", "test", "testdata", "tuf", "test-repo"))))
server := httptest.NewServer(http.FileServer(http.Dir(filepath.Join("..", "test", "testdata", "tuf", "test-repo"))))
defer server.Close()
path := test.CreateTempDir(t, "", "tuf_temp")
tm, err := NewTUFMirror(tuf.DockerTUFRootDev.Data, path, server.URL+metadataPath, server.URL+targetsPath, tuf.NewMockVersionChecker())
tm, err := NewTUFMirror(context.Background(), tuf.DockerTUFRootDev.Data, path, server.URL+metadataPath, server.URL+targetsPath, tuf.NewMockVersionChecker())
assert.NoError(t, err)
targets, err := tm.TUFClient.LoadDelegatedTargets("test-role", "targets")
@@ -69,11 +70,11 @@ func TestTargetDelegationMetadata(t *testing.T) {
}
func TestGetDelegatedTargetMirrors(t *testing.T) {
server := httptest.NewServer(http.FileServer(http.Dir(filepath.Join("..", "..", "test", "testdata", "tuf", "test-repo"))))
server := httptest.NewServer(http.FileServer(http.Dir(filepath.Join("..", "test", "testdata", "tuf", "test-repo"))))
defer server.Close()
path := test.CreateTempDir(t, "", "tuf_temp")
m, err := NewTUFMirror(tuf.DockerTUFRootDev.Data, path, server.URL+metadataPath, server.URL+targetsPath, tuf.NewMockVersionChecker())
m, err := NewTUFMirror(context.Background(), tuf.DockerTUFRootDev.Data, path, server.URL+metadataPath, server.URL+targetsPath, tuf.NewMockVersionChecker())
assert.NoError(t, err)
mirrors, err := m.GetDelegatedTargetMirrors()

View File

@@ -1,8 +1,8 @@
package mirror
import (
"github.com/docker/attest/pkg/oci"
"github.com/docker/attest/pkg/tuf"
"github.com/docker/attest/oci"
"github.com/docker/attest/tuf"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/theupdateframework/go-tuf/v2/metadata"
)

View File

@@ -1,6 +1,8 @@
package oci
import (
"io"
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"
@@ -16,6 +18,6 @@ func MultiKeychainAll() authn.Keychain {
return authn.NewMultiKeychain(
authn.DefaultKeychain,
google.Keychain,
authn.NewKeychainFromHelper(ecr.NewECRHelper()),
authn.NewKeychainFromHelper(ecr.NewECRHelper(ecr.WithLogger(io.Discard))),
)
}

View File

@@ -3,15 +3,16 @@
package oci_test
import (
"context"
"testing"
"github.com/docker/attest/internal/test"
"github.com/docker/attest/pkg/oci"
"github.com/docker/attest/oci"
"github.com/stretchr/testify/require"
)
func TestRegistryAuth(t *testing.T) {
attIdx, err := oci.IndexFromPath(test.UnsignedTestImage)
attIdx, err := oci.IndexFromPath(test.UnsignedTestImage(".."))
require.NoError(t, err)
// test cases for ecr, gcr and dockerhub
testCases := []struct {
@@ -20,11 +21,12 @@ func TestRegistryAuth(t *testing.T) {
{Image: "175142243308.dkr.ecr.us-east-1.amazonaws.com/e2e-test-image:latest"},
{Image: "docker/image-signer-verifier-test:latest"},
}
ctx := context.Background()
for _, tc := range testCases {
t.Run(tc.Image, func(t *testing.T) {
err := oci.PushIndexToRegistry(attIdx.Index, tc.Image)
err := oci.PushIndexToRegistry(ctx, attIdx.Index, tc.Image)
require.NoError(t, err)
_, err = oci.IndexFromRemote(tc.Image)
_, err = oci.IndexFromRemote(ctx, tc.Image)
require.NoError(t, err)
})
}

View File

@@ -7,6 +7,7 @@ import (
"github.com/containerd/platforms"
"github.com/distribution/reference"
"github.com/docker/attest/useragent"
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"
@@ -33,7 +34,11 @@ func ParsePlatform(platformStr string) (*v1.Platform, error) {
func WithOptions(ctx context.Context, platform *v1.Platform) []remote.Option {
// prepare options
options := []remote.Option{MultiKeychainOption(), remote.WithTransport(HTTPTransport()), remote.WithContext(ctx)}
options := []remote.Option{
MultiKeychainOption(),
remote.WithContext(ctx),
remote.WithUserAgent(useragent.Get(ctx)),
}
// add in platform into remote Get operation; this might conflict with an explicit digest, but we are trying anyway
if platform != nil {
@@ -87,7 +92,7 @@ func RefToPURL(named reference.Named, platform *v1.Platform) (string, bool, erro
})
}
p := packageurl.NewPackageURL("docker", ns, name, version, qualifiers, "")
p := packageurl.NewPackageURL(packageurl.TypeDocker, ns, name, version, qualifiers, "")
return p.ToString(), isCanonical, nil
}

View File

@@ -5,7 +5,7 @@ import (
"github.com/distribution/reference"
"github.com/docker/attest/internal/test"
"github.com/docker/attest/pkg/oci"
"github.com/docker/attest/oci"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/layout"
"github.com/stretchr/testify/assert"
@@ -67,7 +67,7 @@ func TestRefToPurl(t *testing.T) {
// Test fix for https://github.com/docker/secure-artifacts-team-issues/issues/202
func TestImageDigestForPlatform(t *testing.T) {
idx, err := layout.ImageIndexFromPath(test.UnsignedTestImage)
idx, err := layout.ImageIndexFromPath(test.UnsignedTestImage(".."))
assert.NoError(t, err)
idxm, err := idx.IndexManifest()

View File

@@ -1,6 +1,7 @@
package oci
import (
"context"
"fmt"
"os"
@@ -13,18 +14,18 @@ import (
)
// PushImageToRegistry pushes an image to the registry with the specified name.
func PushImageToRegistry(image v1.Image, imageName string) error {
func PushImageToRegistry(ctx context.Context, image v1.Image, imageName string) error {
ref, err := name.ParseReference(imageName)
if err != nil {
return fmt.Errorf("Failed to parse image name '%s': %w", imageName, err)
}
// Push the image to the registry
return remote.Write(ref, image, MultiKeychainOption())
return remote.Write(ref, image, WithOptions(ctx, nil)...)
}
// PushIndexToRegistry pushes an index to the registry with the specified name.
func PushIndexToRegistry(index v1.ImageIndex, imageName string) error {
func PushIndexToRegistry(ctx context.Context, index v1.ImageIndex, imageName string) error {
// Parse the index name
ref, err := name.ParseReference(imageName)
if err != nil {
@@ -32,7 +33,7 @@ func PushIndexToRegistry(index v1.ImageIndex, imageName string) error {
}
// Push the index to the registry
return remote.WriteIndex(ref, index, MultiKeychainOption())
return remote.WriteIndex(ref, index, WithOptions(ctx, nil)...)
}
// SaveIndexAsOCILayout saves an image as an OCI layout to the specified path.
@@ -66,7 +67,7 @@ func SaveIndexAsOCILayout(image v1.ImageIndex, path string) error {
}
// SaveIndex saves an index to the specified outputs.
func SaveIndex(outputs []*ImageSpec, index v1.ImageIndex, indexName string) error {
func SaveIndex(ctx context.Context, outputs []*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 {
@@ -84,7 +85,7 @@ func SaveIndex(outputs []*ImageSpec, index v1.ImageIndex, indexName string) erro
return fmt.Errorf("failed to write signed image: %w", err)
}
} else {
err := PushIndexToRegistry(index, output.Identifier)
err := PushIndexToRegistry(ctx, index, output.Identifier)
if err != nil {
return fmt.Errorf("failed to push signed image: %w", err)
}
@@ -94,7 +95,7 @@ func SaveIndex(outputs []*ImageSpec, index v1.ImageIndex, indexName string) erro
}
// SaveImage saves an image to the specified output.
func SaveImage(output *ImageSpec, image v1.Image, imageName string) error {
func SaveImage(ctx context.Context, output *ImageSpec, image v1.Image, imageName string) error {
if output.Type == OCI {
idx := v1.ImageIndex(empty.Index)
idx = mutate.AppendManifests(idx, mutate.IndexAddendum{
@@ -110,7 +111,7 @@ func SaveImage(output *ImageSpec, image v1.Image, imageName string) error {
return fmt.Errorf("failed to write signed image: %w", err)
}
} else {
err := PushImageToRegistry(image, output.Identifier)
err := PushImageToRegistry(ctx, image, output.Identifier)
if err != nil {
return fmt.Errorf("failed to push signed image: %w", err)
}
@@ -119,7 +120,7 @@ func SaveImage(output *ImageSpec, image v1.Image, imageName string) error {
}
// SaveImagesNoTag saves a list of images by digest to the specified outputs.
func SaveImagesNoTag(images []v1.Image, outputs []*ImageSpec) error {
func SaveImagesNoTag(ctx context.Context, images []v1.Image, outputs []*ImageSpec) error {
for _, output := range outputs {
// OCI layout output not supported
if output.Type == OCI {
@@ -134,7 +135,7 @@ func SaveImagesNoTag(images []v1.Image, outputs []*ImageSpec) error {
if err != nil {
return fmt.Errorf("failed to create image spec: %w", err)
}
err = PushImageToRegistry(image, spec.Identifier)
err = PushImageToRegistry(ctx, image, spec.Identifier)
if err != nil {
return fmt.Errorf("failed to push image: %w", err)
}

View File

@@ -1,14 +1,14 @@
package oci_test
import (
"context"
"fmt"
"net/http/httptest"
"net/url"
"testing"
"github.com/docker/attest/attestation"
"github.com/docker/attest/internal/test"
"github.com/docker/attest/pkg/attestation"
"github.com/docker/attest/pkg/oci"
"github.com/docker/attest/oci"
"github.com/google/go-containerregistry/pkg/registry"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/empty"
@@ -18,24 +18,25 @@ import (
func TestSavingIndex(t *testing.T) {
outputLayout := test.CreateTempDir(t, "", "mirror-test")
attIdx, err := oci.IndexFromPath(test.UnsignedTestImage)
attIdx, err := oci.IndexFromPath(test.UnsignedTestImage(".."))
require.NoError(t, err)
server := httptest.NewServer(registry.New())
defer server.Close()
ctx := context.Background()
regServer := test.NewLocalRegistry(ctx)
defer regServer.Close()
u, err := url.Parse(server.URL)
u, err := url.Parse(regServer.URL)
require.NoError(t, err)
indexName := fmt.Sprintf("%s/repo:root", u.Host)
output, err := oci.ParseImageSpecs(indexName)
require.NoError(t, err)
err = oci.SaveIndex(output, attIdx.Index, indexName)
err = oci.SaveIndex(ctx, output, attIdx.Index, indexName)
require.NoError(t, err)
ociOutput, err := oci.ParseImageSpecs(oci.LocalPrefix + outputLayout)
require.NoError(t, err)
err = oci.SaveIndex(ociOutput, attIdx.Index, indexName)
err = oci.SaveIndex(ctx, ociOutput, attIdx.Index, indexName)
require.NoError(t, err)
}
@@ -44,21 +45,22 @@ func TestSavingImage(t *testing.T) {
img := empty.Image
server := httptest.NewServer(registry.New())
defer server.Close()
ctx := context.Background()
regServer := test.NewLocalRegistry(ctx)
defer regServer.Close()
u, err := url.Parse(server.URL)
u, err := url.Parse(regServer.URL)
require.NoError(t, err)
indexName := fmt.Sprintf("%s/repo:root", u.Host)
output, err := oci.ParseImageSpec(indexName)
require.NoError(t, err)
err = oci.SaveImage(output, img, indexName)
err = oci.SaveImage(ctx, output, img, indexName)
require.NoError(t, err)
ociOutput, err := oci.ParseImageSpec(oci.LocalPrefix + outputLayout)
require.NoError(t, err)
err = oci.SaveImage(ociOutput, img, indexName)
err = oci.SaveImage(ctx, ociOutput, img, indexName)
require.NoError(t, err)
}
@@ -81,10 +83,10 @@ func TestSavingReferrers(t *testing.T) {
require.NoError(t, err)
err = manifest.Add(ctx, signer, statement, opts)
require.NoError(t, err)
server := httptest.NewServer(registry.New(registry.WithReferrersSupport(true)))
defer server.Close()
regServer := test.NewLocalRegistry(ctx, registry.WithReferrersSupport(true))
defer regServer.Close()
u, err := url.Parse(server.URL)
u, err := url.Parse(regServer.URL)
require.NoError(t, err)
indexName := fmt.Sprintf("%s/repo:root", u.Host)
@@ -92,7 +94,7 @@ func TestSavingReferrers(t *testing.T) {
require.NoError(t, err)
artifacts, err := manifest.BuildReferringArtifacts()
require.NoError(t, err)
err = oci.SaveImagesNoTag(artifacts, output)
err = oci.SaveImagesNoTag(ctx, artifacts, output)
require.NoError(t, err)
reg := &attestation.MockRegistryResolver{

View File

@@ -9,6 +9,9 @@ import (
"github.com/google/go-containerregistry/pkg/v1/remote"
)
// ensure RegistryImageDetailsResolver implements ImageDetailsResolver.
var _ ImageDetailsResolver = &RegistryImageDetailsResolver{}
type RegistryImageDetailsResolver struct {
*ImageSpec
descriptor *v1.Descriptor

View File

@@ -2,6 +2,7 @@ package oci
import (
"bytes"
"context"
"encoding/json"
"fmt"
"strings"
@@ -61,14 +62,14 @@ func IndexFromPath(path string) (*NamedIndex, error) {
}, nil
}
func IndexFromRemote(image string) (*NamedIndex, error) {
func IndexFromRemote(ctx context.Context, 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)
}
// Pull the image from the registry
idx, err := remote.Index(ref, MultiKeychainOption())
idx, err := remote.Index(ref, WithOptions(ctx, nil)...)
if err != nil {
return nil, fmt.Errorf("failed to pull image %s: %w", image, err)
}
@@ -78,11 +79,11 @@ func IndexFromRemote(image string) (*NamedIndex, error) {
}, nil
}
func LoadIndex(input *ImageSpec) (*NamedIndex, error) {
func LoadIndex(ctx context.Context, input *ImageSpec) (*NamedIndex, error) {
if input.Type == OCI {
return IndexFromPath(input.Identifier)
}
return IndexFromRemote(input.Identifier)
return IndexFromRemote(ctx, input.Identifier)
}
func (i *ImageSpec) ForPlatforms(platform string) ([]*ImageSpec, error) {

View File

@@ -1,2 +0,0 @@
## attest
This package implements the top-level signing and verification methods.

View File

@@ -1,77 +0,0 @@
package config
import (
"fmt"
"os"
"path/filepath"
"regexp"
"github.com/docker/attest/pkg/tuf"
"sigs.k8s.io/yaml"
)
const (
MappingFilename = "mapping.yaml"
)
func LoadLocalMappings(configDir string) (*PolicyMappings, error) {
if configDir == "" {
return nil, nil
}
mappings := &policyMappingsFile{}
path := filepath.Join(configDir, MappingFilename)
mappingFile, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("failed to read local policy mapping file %s: %w", path, err)
}
err = yaml.Unmarshal(mappingFile, mappings)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal policy mapping file %s: %w", path, err)
}
return expandMappingFile(mappings)
}
func LoadTUFMappings(tufClient tuf.Downloader, localTargetsDir string) (*PolicyMappings, error) {
if tufClient == nil {
return nil, fmt.Errorf("tuf client not set")
}
filename := MappingFilename
file, err := tufClient.DownloadTarget(filename, filepath.Join(localTargetsDir, filename))
if err != nil {
return nil, fmt.Errorf("failed to download policy mapping file %s: %w", filename, err)
}
mappings := &policyMappingsFile{}
err = yaml.Unmarshal(file.Data, mappings)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal policy mapping file %s: %w", filename, err)
}
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,18 +0,0 @@
package mirror
import (
"fmt"
"github.com/docker/attest/pkg/tuf"
)
func NewTUFMirror(root []byte, tufPath, metadataURL, targetsURL string, versionChecker tuf.VersionChecker) (*TUFMirror, error) {
if root == nil {
root = tuf.DockerTUFRootDefault.Data
}
tufClient, err := tuf.NewClient(&tuf.ClientOptions{InitialRoot: root, Path: tufPath, MetadataSource: metadataURL, TargetsSource: targetsURL, VersionChecker: versionChecker})
if err != nil {
return nil, fmt.Errorf("failed to create TUF client: %w", err)
}
return &TUFMirror{TUFClient: tufClient, tufPath: tufPath, metadataURL: metadataURL, targetsURL: targetsURL}, nil
}

View File

@@ -1,27 +0,0 @@
package oci
import (
"net/http"
"github.com/hashicorp/go-cleanhttp"
)
type userAgentTransporter struct {
userAgent string
roundTripper http.RoundTripper
}
type Option = func(*http.Client)
func (u *userAgentTransporter) RoundTrip(req *http.Request) (*http.Response, error) {
req.Header.Set("User-Agent", u.userAgent)
return u.roundTripper.RoundTrip(req)
}
func HTTPTransport() http.RoundTripper {
return &userAgentTransporter{
userAgent: "Docker-Client",
roundTripper: cleanhttp.DefaultTransport(),
}
}

View File

@@ -1,30 +0,0 @@
package policy
import (
"context"
"fmt"
"github.com/docker/attest/pkg/attestation"
)
type policyEvaluatorCtxKeyType struct{}
var PolicyEvaluatorCtxKey policyEvaluatorCtxKeyType
// sets PolicyEvaluator in context.
func WithPolicyEvaluator(ctx context.Context, pe Evaluator) context.Context {
return context.WithValue(ctx, PolicyEvaluatorCtxKey, pe)
}
// gets PolicyEvaluator from context, defaults to Rego PolicyEvaluator if not set.
func GetPolicyEvaluator(ctx context.Context) (Evaluator, error) {
t, ok := ctx.Value(PolicyEvaluatorCtxKey).(Evaluator)
if !ok {
return nil, fmt.Errorf("no policy evaluator client set on context (set one with policy.WithPolicyEvaluator)")
}
return t, nil
}
type Evaluator interface {
Evaluate(ctx context.Context, resolver attestation.Resolver, pctx *Policy, input *Input) (*Result, error)
}

View File

@@ -1,38 +0,0 @@
package policy
import (
"fmt"
"github.com/docker/attest/pkg/attestation"
"github.com/docker/attest/pkg/config"
"github.com/docker/attest/pkg/oci"
)
func CreateImageDetailsResolver(imageSource *oci.ImageSpec) (oci.ImageDetailsResolver, error) {
switch imageSource.Type {
case oci.OCI:
return attestation.NewOCILayoutResolver(imageSource)
case oci.Docker:
return oci.NewRegistryImageDetailsResolver(imageSource)
}
return nil, fmt.Errorf("unsupported image source type: %s", imageSource.Type)
}
func CreateAttestationResolver(resolver oci.ImageDetailsResolver, mapping *config.PolicyMapping) (attestation.Resolver, error) {
if mapping.Attestations != nil {
if mapping.Attestations.Style == config.AttestationStyleAttached {
switch resolver := resolver.(type) {
case *oci.RegistryImageDetailsResolver:
return attestation.NewRegistryResolver(resolver)
case *attestation.LayoutResolver:
return resolver, nil
default:
return nil, fmt.Errorf("unsupported image details resolver type: %T", resolver)
}
}
if mapping.Attestations.Repo != "" {
return attestation.NewReferrersResolver(resolver, attestation.WithReferrersRepo(mapping.Attestations.Repo))
}
}
return attestation.NewReferrersResolver(resolver)
}

View File

@@ -1,175 +0,0 @@
package policy_test
import (
"encoding/json"
"os"
"path/filepath"
"testing"
"github.com/docker/attest/internal/test"
"github.com/docker/attest/pkg/attestation"
"github.com/docker/attest/pkg/config"
"github.com/docker/attest/pkg/oci"
"github.com/docker/attest/pkg/policy"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func loadAttestation(t *testing.T, path string) *attestation.Envelope {
ex, err := os.ReadFile(path)
if err != nil {
t.Fatal(err)
}
env := new(attestation.Envelope)
err = json.Unmarshal(ex, env)
if err != nil {
t.Fatal(err)
}
return env
}
func TestRegoEvaluator_Evaluate(t *testing.T) {
ctx, _ := test.Setup(t)
resolveErrorStr := "failed to resolve policy by id: policy with id non-existent-policy-id not found"
TestDataPath := filepath.Join("..", "..", "test", "testdata")
ExampleAttestation := filepath.Join(TestDataPath, "example_attestation.json")
re := policy.NewRegoEvaluator(true)
defaultResolver := attestation.MockResolver{
Envs: []*attestation.Envelope{loadAttestation(t, ExampleAttestation)},
}
testCases := []struct {
repo string
expectSuccess bool
isCanonical bool
resolver attestation.Resolver
opts *policy.Options
policyID string
resolveErrorStr string
}{
{repo: "testdata/policies/allow", expectSuccess: true, resolver: defaultResolver},
{repo: "testdata/policies/allow", expectSuccess: true, resolver: defaultResolver, policyID: "docker-official-images"},
{repo: "testdata/policies/allow", resolver: defaultResolver, policyID: "non-existent-policy-id", resolveErrorStr: resolveErrorStr},
{repo: "testdata/policies/deny", resolver: defaultResolver},
{repo: "testdata/policies/verify-sig", expectSuccess: true, resolver: defaultResolver},
{repo: "testdata/policies/wrong-key", resolver: defaultResolver},
{repo: "testdata/policies/allow-canonical", expectSuccess: true, isCanonical: true, resolver: defaultResolver},
{repo: "testdata/policies/allow-canonical", resolver: defaultResolver},
{repo: "testdata/policies/no-rego", resolver: defaultResolver, resolveErrorStr: "no policy file found in policy mapping"},
}
for _, tc := range testCases {
t.Run(tc.repo, func(t *testing.T) {
input := &policy.Input{
Digest: "sha256:test-digest",
PURL: "test-purl",
}
if !tc.isCanonical {
input.Tag = "test"
}
if tc.opts == nil {
tc.opts = &policy.Options{
LocalTargetsDir: test.CreateTempDir(t, "", "tuf-targets"),
PolicyID: tc.policyID,
LocalPolicyDir: tc.repo,
DisableTUF: true,
}
}
imageName, err := tc.resolver.ImageName(ctx)
require.NoError(t, err)
resolver := policy.NewResolver(nil, tc.opts)
policy, err := resolver.ResolvePolicy(ctx, imageName)
if tc.resolveErrorStr != "" {
require.Error(t, err)
assert.Contains(t, err.Error(), tc.resolveErrorStr)
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")
if tc.expectSuccess {
assert.True(t, result.Success, "Evaluate should have succeeded")
} else {
assert.False(t, result.Success, "Evaluate should have failed")
}
})
}
}
func TestLoadingMappings(t *testing.T) {
policyMappings, err := config.LoadLocalMappings(filepath.Join("testdata", "policies", "allow"))
require.NoError(t, err)
assert.Equal(t, len(policyMappings.Rules), 3)
for _, mirror := range policyMappings.Rules {
if mirror.PolicyID != "" {
assert.Equal(t, "docker-official-images", mirror.PolicyID)
}
}
}
func TestCreateAttestationResolver(t *testing.T) {
mockResolver := attestation.MockResolver{
Envs: []*attestation.Envelope{},
}
layoutResolver := &attestation.LayoutResolver{}
registryResolver := &oci.RegistryImageDetailsResolver{}
nilRepoReferrers := &config.PolicyMapping{
Attestations: &config.AttestationConfig{
Style: config.AttestationStyleReferrers,
},
}
referrers := &config.PolicyMapping{
Attestations: &config.AttestationConfig{
Repo: "localhost:5000/repo",
Style: config.AttestationStyleReferrers,
},
}
attached := &config.PolicyMapping{
Attestations: &config.AttestationConfig{
Style: config.AttestationStyleAttached,
},
}
testCases := []struct {
name string
resolver oci.ImageDetailsResolver
mapping *config.PolicyMapping
errorStr string
}{
{name: "referrers", resolver: layoutResolver, mapping: referrers},
{name: "referrers (no mapped repo)", resolver: layoutResolver, mapping: nilRepoReferrers},
{name: "referrers (no mapping)", resolver: layoutResolver, mapping: &config.PolicyMapping{Attestations: nil}},
{name: "attached (registry)", resolver: registryResolver, mapping: attached},
{name: "attached (layout)", resolver: layoutResolver, mapping: attached},
{name: "attached (unsupported)", resolver: mockResolver, mapping: attached, errorStr: "unsupported image details resolver type"},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
resolver, err := policy.CreateAttestationResolver(tc.resolver, tc.mapping)
if tc.errorStr == "" {
require.NoError(t, err)
} else {
assert.Contains(t, err.Error(), tc.errorStr)
}
if tc.mapping.Attestations == nil {
return
}
switch resolver.(type) {
case *attestation.ReferrersResolver:
assert.Equal(t, tc.mapping.Attestations.Style, config.AttestationStyleReferrers)
case *attestation.RegistryResolver:
assert.Equal(t, tc.mapping.Attestations.Style, config.AttestationStyleAttached)
case *attestation.LayoutResolver:
assert.Equal(t, tc.mapping.Attestations.Style, config.AttestationStyleAttached)
}
})
}
}

View File

@@ -1,13 +0,0 @@
package tuf
type MockVersionChecker struct {
err error
}
func NewMockVersionChecker() *MockVersionChecker {
return &MockVersionChecker{}
}
func (vc *MockVersionChecker) CheckVersion(_ Downloader) error {
return vc.err
}

View File

@@ -1,158 +0,0 @@
package tuf
import (
"context"
"fmt"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/theupdateframework/go-tuf/v2/metadata"
)
var (
HTTPTUFTestDataPath = filepath.Join("..", "..", "test", "testdata", "tuf", "test-repo")
OCITUFTestDataPath = filepath.Join("..", "..", "test", "testdata", "tuf", "test-repo-oci")
)
func CreateTempDir(t *testing.T, dir, pattern string) string {
// Create a temporary directory for output oci layout
tempDir, err := os.MkdirTemp(dir, pattern)
if err != nil {
t.Fatalf("Failed to create temp directory: %v", err)
}
// Register a cleanup function to delete the temp directory when the test exits
t.Cleanup(func() {
if err := os.RemoveAll(tempDir); err != nil {
t.Errorf("Failed to remove temp directory: %v", err)
}
})
return tempDir
}
// NewTufClient creates a new TUF client.
func TestRootInit(t *testing.T) {
tufPath := CreateTempDir(t, "", "tuf_temp")
// Start a test HTTP server to serve data from /test/testdata/tuf/test-repo/ paths
server := httptest.NewServer(http.FileServer(http.Dir(HTTPTUFTestDataPath)))
defer server.Close()
// run local registry
registry, regAddr := RunTestRegistry(t)
defer func() {
if err := registry.Terminate(context.Background()); err != nil {
t.Fatalf("failed to terminate container: %s", err) // nolint:gocritic
}
}()
LoadRegistryTestData(t, regAddr, OCITUFTestDataPath)
alwaysGoodVersionChecker := &MockVersionChecker{err: nil}
alwaysBadVersionChecker := &MockVersionChecker{err: assert.AnError}
testCases := []struct {
name string
metadataSource string
targetsSource string
}{
{"http", server.URL + "/metadata", server.URL + "/targets"},
{"oci", regAddr.Host + "/tuf-metadata:latest", regAddr.Host + "/tuf-targets"},
}
for _, tc := range testCases {
_, err := NewClient(&ClientOptions{DockerTUFRootDev.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 = NewClient(&ClientOptions{DockerTUFRootDev.Data, tufPath, tc.metadataSource, tc.targetsSource, alwaysGoodVersionChecker})
assert.NoErrorf(t, err, "Failed to recreate TUF client: %v", err)
_, err = NewClient(&ClientOptions{[]byte("broken"), tufPath, tc.metadataSource, tc.targetsSource, alwaysGoodVersionChecker})
assert.Errorf(t, err, "Expected error recreating TUF client with broken root: %v", err)
_, err = NewClient(&ClientOptions{DockerTUFRootDev.Data, tufPath, tc.metadataSource, tc.targetsSource, alwaysBadVersionChecker})
assert.Errorf(t, err, "Expected error recreating TUF client with bad version checker")
}
}
func TestDownloadTarget(t *testing.T) {
tufPath := CreateTempDir(t, "", "tuf_temp")
targetFile := "test.txt"
delegatedRole := testRole
delegatedTargetFile := fmt.Sprintf("%s/%s", delegatedRole, targetFile)
// Start a test HTTP server to serve data from /test/testdata/tuf/test-repo/ paths
server := httptest.NewServer(http.FileServer(http.Dir(HTTPTUFTestDataPath)))
defer server.Close()
// run local registry
registry, regAddr := RunTestRegistry(t)
defer func() {
if err := registry.Terminate(context.Background()); err != nil {
t.Fatalf("failed to terminate container: %s", err) // nolint:gocritic
}
}()
LoadRegistryTestData(t, regAddr, OCITUFTestDataPath)
alwaysGoodVersionChecker := &MockVersionChecker{err: nil}
testCases := []struct {
name string
metadataSource string
targetsSource string
}{
{"http", server.URL + "/metadata", server.URL + "/targets"},
{"oci", regAddr.Host + "/tuf-metadata:latest", regAddr.Host + "/tuf-targets"},
{"http, download before init", server.URL + "/metadata", server.URL + "/targets"},
}
for _, tc := range testCases {
tufClient, err := NewClient(&ClientOptions{DockerTUFRootDev.Data, tufPath, tc.metadataSource, tc.targetsSource, alwaysGoodVersionChecker})
require.NoErrorf(t, err, "Failed to create TUF client: %v", err)
require.NotNil(t, tufClient.updater, "Failed to create updater")
// get trusted tuf metadata
trustedMetadata := tufClient.updater.GetTrustedMetadataSet()
assert.NotNil(t, trustedMetadata, "Failed to get trusted metadata")
// download top-level target files
targets := trustedMetadata.Targets[metadata.TARGETS].Signed.Targets
for _, target := range targets {
// download target files
_, err := tufClient.DownloadTarget(target.Path, filepath.Join(tufPath, "download"))
assert.NoErrorf(t, err, "Failed to download target: %v", err)
}
// download delegated target
targetInfo, err := tufClient.updater.GetTargetInfo(delegatedTargetFile)
assert.NoError(t, err)
_, err = tufClient.DownloadTarget(targetInfo.Path, filepath.Join(tufPath, targetInfo.Path))
assert.NoError(t, err)
}
}
func TestGetEmbeddedTufRootBytes(t *testing.T) {
dev, err := GetEmbeddedRoot("dev")
assert.NoError(t, err)
staging, err := GetEmbeddedRoot("staging")
assert.NoError(t, err)
assert.NotEqual(t, dev.Data, staging.Data)
prod, err := GetEmbeddedRoot("prod")
assert.NoError(t, err)
assert.NotEqual(t, dev.Data, prod.Data)
assert.NotEqual(t, staging.Data, prod.Data)
def, err := GetEmbeddedRoot("")
assert.NoError(t, err)
assert.Equal(t, def.Data, prod.Data)
_, err = GetEmbeddedRoot("invalid")
assert.Error(t, err)
}

11
policy/evaluator.go Normal file
View File

@@ -0,0 +1,11 @@
package policy
import (
"context"
"github.com/docker/attest/attestation"
)
type Evaluator interface {
Evaluate(ctx context.Context, resolver attestation.Resolver, pctx *Policy, input *Input) (*Result, error)
}

View File

@@ -3,7 +3,7 @@ package policy
import (
"fmt"
"github.com/docker/attest/pkg/config"
"github.com/docker/attest/config"
)
type matchType string

View File

@@ -4,7 +4,7 @@ import (
"path/filepath"
"testing"
"github.com/docker/attest/pkg/config"
"github.com/docker/attest/config"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -15,10 +15,11 @@ func TestFindPolicyMatch(t *testing.T) {
imageName string
mappingDir string
expectError bool
expectedMatchType matchType
expectedPolicyID string
expectedImageName string
expectError bool
expectLoadingError bool
expectedMatchType matchType
expectedPolicyID string
expectedImageName string
}{
{
name: "alpine",
@@ -79,16 +80,6 @@ func TestFindPolicyMatch(t *testing.T) {
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",

View File

@@ -3,7 +3,7 @@ package policy
import (
"context"
"github.com/docker/attest/pkg/attestation"
"github.com/docker/attest/attestation"
)
type MockPolicyEvaluator struct {

96
policy/policy.go Normal file
View File

@@ -0,0 +1,96 @@
package policy
import (
"context"
"fmt"
"github.com/distribution/reference"
"github.com/docker/attest/attestation"
"github.com/docker/attest/config"
"github.com/docker/attest/oci"
intoto "github.com/in-toto/in-toto-golang/in_toto"
"github.com/package-url/packageurl-go"
)
func CreateImageDetailsResolver(imageSource *oci.ImageSpec) (oci.ImageDetailsResolver, error) {
switch imageSource.Type {
case oci.OCI:
return attestation.NewOCILayoutResolver(imageSource)
case oci.Docker:
return oci.NewRegistryImageDetailsResolver(imageSource)
}
return nil, fmt.Errorf("unsupported image source type: %s", imageSource.Type)
}
func CreateAttestationResolver(resolver oci.ImageDetailsResolver, mapping *config.PolicyMapping) (attestation.Resolver, error) {
if mapping.Attestations != nil {
if mapping.Attestations.Style == config.AttestationStyleAttached {
switch resolver := resolver.(type) {
case *oci.RegistryImageDetailsResolver:
return attestation.NewRegistryResolver(resolver)
case *attestation.LayoutResolver:
return resolver, nil
default:
return nil, fmt.Errorf("unsupported image details resolver type: %T", resolver)
}
}
if mapping.Attestations.Repo != "" {
return attestation.NewReferrersResolver(resolver, attestation.WithReferrersRepo(mapping.Attestations.Repo))
}
}
return attestation.NewReferrersResolver(resolver)
}
// VerifySubject verifies if any of the given subject PURLs matches the image name and platform from resolver.
// Tags are not taken into account when attempting to match because sometimes the user may not have specified a tag, and maybe there
// isn't a purl subject with that particular tag (because of post build tagging?).
func VerifySubject(ctx context.Context, subject []intoto.Subject, resolver attestation.Resolver) error {
img, err := resolver.ImageName(ctx)
if err != nil {
return err
}
inputName, err := reference.ParseNormalizedNamed(img)
if err != nil {
return err
}
descriptor, err := resolver.ImageDescriptor(ctx)
if err != nil {
return err
}
platform, err := resolver.ImagePlatform(ctx)
if err != nil {
return err
}
for _, sub := range subject {
if sub.Digest[descriptor.Digest.Algorithm] != descriptor.Digest.Hex {
continue
}
purl, err := packageurl.FromString(sub.Name)
if err != nil {
continue
}
if purl.Type != packageurl.TypeDocker {
continue
}
if purl.Qualifiers.Map()["platform"] != platform.String() {
continue
}
// ensure reference is normalized before comparing
withNamespace := purl.Name
if purl.Namespace != "" {
withNamespace = purl.Namespace + "/" + purl.Name
}
subjectName, err := reference.ParseNormalizedNamed(withNamespace)
if err != nil {
continue
}
// this assumes that domain is part of the package URL (some say it should be a qualifier)
// buildkit puts the domain in the name, e.g. pkg:docker/ecr.io/foobar/alpine@latest?platform=linux%2Famd64
if inputName.Name() == subjectName.Name() {
// found a match
return nil
}
}
return fmt.Errorf("no matching subject found for image: %s", img)
}

409
policy/policy_test.go Normal file
View File

@@ -0,0 +1,409 @@
package policy_test
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"testing"
"github.com/docker/attest/attestation"
"github.com/docker/attest/config"
"github.com/docker/attest/internal/test"
"github.com/docker/attest/oci"
"github.com/docker/attest/policy"
v1 "github.com/google/go-containerregistry/pkg/v1"
intoto "github.com/in-toto/in-toto-golang/in_toto"
"github.com/package-url/packageurl-go"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func loadAttestation(t *testing.T, path string) *attestation.Envelope {
ex, err := os.ReadFile(path)
if err != nil {
t.Fatal(err)
}
env := new(attestation.Envelope)
err = json.Unmarshal(ex, env)
if err != nil {
t.Fatal(err)
}
return env
}
func TestRegoEvaluator_Evaluate(t *testing.T) {
ctx, _ := test.Setup(t)
resolveErrorStr := "failed to resolve policy by id: policy with id non-existent-policy-id not found"
TestDataPath := filepath.Join("..", "test", "testdata")
ExampleAttestation := filepath.Join(TestDataPath, "example_attestation.json")
re := policy.NewRegoEvaluator(true)
defaultResolver := attestation.MockResolver{
Envs: []*attestation.Envelope{loadAttestation(t, ExampleAttestation)},
}
testCases := []struct {
policyPath string
expectSuccess bool
isCanonical bool
resolver attestation.Resolver
opts *policy.Options
policyID string
resolveErrorStr string
}{
{policyPath: "testdata/policies/allow", expectSuccess: true, resolver: defaultResolver},
{policyPath: "testdata/policies/allow", expectSuccess: true, resolver: defaultResolver, policyID: "docker-official-images"},
{policyPath: "testdata/policies/allow", resolver: defaultResolver, policyID: "non-existent-policy-id", resolveErrorStr: resolveErrorStr},
{policyPath: "testdata/policies/deny", resolver: defaultResolver},
{policyPath: "testdata/policies/verify-sig", expectSuccess: true, resolver: defaultResolver},
{policyPath: "testdata/policies/wrong-key", resolver: defaultResolver},
{policyPath: "testdata/policies/allow-canonical", expectSuccess: true, isCanonical: true, resolver: defaultResolver},
{policyPath: "testdata/policies/allow-canonical", resolver: defaultResolver},
{policyPath: "testdata/policies/no-rego", resolver: defaultResolver, resolveErrorStr: "no policy file found in policy mapping"},
}
for _, tc := range testCases {
t.Run(tc.policyPath, func(t *testing.T) {
input := &policy.Input{
Digest: "sha256:test-digest",
PURL: "test-purl",
}
if !tc.isCanonical {
input.Tag = "test"
}
if tc.opts == nil {
tc.opts = &policy.Options{
LocalTargetsDir: test.CreateTempDir(t, "", "tuf-targets"),
PolicyID: tc.policyID,
LocalPolicyDir: tc.policyPath,
DisableTUF: true,
}
}
imageName, err := tc.resolver.ImageName(ctx)
require.NoError(t, err)
resolver := policy.NewResolver(nil, tc.opts)
policy, err := resolver.ResolvePolicy(ctx, imageName)
if tc.resolveErrorStr != "" {
require.Error(t, err)
assert.Contains(t, err.Error(), tc.resolveErrorStr)
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")
if tc.expectSuccess {
assert.True(t, result.Success, "Evaluate should have succeeded")
} else {
assert.False(t, result.Success, "Evaluate should have failed")
}
})
}
}
func TestLoadingMappings(t *testing.T) {
policyMappings, err := config.LoadLocalMappings(filepath.Join("testdata", "policies", "allow"))
require.NoError(t, err)
assert.Equal(t, len(policyMappings.Rules), 3)
for _, mirror := range policyMappings.Rules {
if mirror.PolicyID != "" {
assert.Equal(t, "docker-official-images", mirror.PolicyID)
}
}
}
func TestCreateAttestationResolver(t *testing.T) {
mockResolver := attestation.MockResolver{
Envs: []*attestation.Envelope{},
}
layoutResolver := &attestation.LayoutResolver{}
registryResolver := &oci.RegistryImageDetailsResolver{}
nilRepoReferrers := &config.PolicyMapping{
Attestations: &config.AttestationConfig{
Style: config.AttestationStyleReferrers,
},
}
referrers := &config.PolicyMapping{
Attestations: &config.AttestationConfig{
Repo: "localhost:5000/repo",
Style: config.AttestationStyleReferrers,
},
}
attached := &config.PolicyMapping{
Attestations: &config.AttestationConfig{
Style: config.AttestationStyleAttached,
},
}
testCases := []struct {
name string
resolver oci.ImageDetailsResolver
mapping *config.PolicyMapping
errorStr string
}{
{name: "referrers", resolver: layoutResolver, mapping: referrers},
{name: "referrers (no mapped repo)", resolver: layoutResolver, mapping: nilRepoReferrers},
{name: "referrers (no mapping)", resolver: layoutResolver, mapping: &config.PolicyMapping{Attestations: nil}},
{name: "attached (registry)", resolver: registryResolver, mapping: attached},
{name: "attached (layout)", resolver: layoutResolver, mapping: attached},
{name: "attached (unsupported)", resolver: mockResolver, mapping: attached, errorStr: "unsupported image details resolver type"},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
resolver, err := policy.CreateAttestationResolver(tc.resolver, tc.mapping)
if tc.errorStr == "" {
require.NoError(t, err)
} else {
assert.Contains(t, err.Error(), tc.errorStr)
}
if tc.mapping.Attestations == nil {
return
}
switch resolver.(type) {
case *attestation.ReferrersResolver:
assert.Equal(t, tc.mapping.Attestations.Style, config.AttestationStyleReferrers)
case *attestation.RegistryResolver:
assert.Equal(t, tc.mapping.Attestations.Style, config.AttestationStyleAttached)
case *attestation.LayoutResolver:
assert.Equal(t, tc.mapping.Attestations.Style, config.AttestationStyleAttached)
}
})
}
}
func TestVerifySubject(t *testing.T) {
ctx, _ := test.Setup(t)
defaultResolver := attestation.MockResolver{}
hostWithPort := packageurl.QualifiersFromMap(map[string]string{"platform": "linux/amd64"})
withHost := packageurl.NewPackageURL(packageurl.TypeDocker, "localhost:1234", "alpine", "", hostWithPort, "")
testCases := []struct {
name string
subject []intoto.Subject
img string
expectError bool
digest string
}{
{
name: "library short",
subject: []intoto.Subject{
{
Name: "pkg:docker/alpine@latest?platform=linux%2Famd64",
},
},
img: "alpine",
},
{
name: "with domain and namespace",
subject: []intoto.Subject{
{
Name: "pkg:docker/docker.io/library/alpine@latest?platform=linux%2Famd64",
},
},
img: "alpine",
},
{
name: "with host and port",
subject: []intoto.Subject{
{
Name: withHost.ToString(),
},
},
img: "localhost:1234/alpine",
},
{
name: "with host and port (from image-signer-verifier tests)",
subject: []intoto.Subject{
{
Name: "pkg:docker/registry.local%3A5000/image-signer-verifier-test@10710107227?platform=linux%2Famd64",
},
},
img: "registry.local:5000/image-signer-verifier-test",
},
{
name: "with library",
subject: []intoto.Subject{
{
Name: "pkg:docker/library/alpine@latest?platform=linux%2Famd64",
},
},
img: "alpine",
},
{
name: "library short with tag",
subject: []intoto.Subject{
{
Name: "pkg:docker/alpine@latest?platform=linux%2Famd64",
},
},
img: "alpine:foo",
},
{
name: "library with namespace",
subject: []intoto.Subject{
{
Name: "pkg:docker/alpine@latest?platform=linux%2Famd64",
},
},
img: "library/alpine:foo",
},
{
name: "library with domain",
subject: []intoto.Subject{
{
Name: "pkg:docker/alpine@latest?platform=linux%2Famd64",
},
},
img: "docker.io/library/alpine:foo",
},
{
name: "domain mismatch",
subject: []intoto.Subject{
{
Name: "pkg:docker/alpine@latest?platform=linux%2Famd64",
},
},
img: "ecr.io/library/alpine:foo",
expectError: true,
},
{
name: "type mismatch",
subject: []intoto.Subject{
{
Name: "pkg:node/alpine@latest?platform=linux%2Famd64",
},
},
img: "alpine",
expectError: true,
},
{
name: "name mismatch",
subject: []intoto.Subject{
{
Name: "pkg:docker/alpine@latest?platform=linux%2Famd64",
},
},
img: "library/debian:latest",
expectError: true,
},
{
name: "namespace mismatch",
subject: []intoto.Subject{
{
Name: "pkg:docker/alpine@latest?platform=linux%2Famd64",
},
},
img: "unsupported/alpine:latest",
expectError: true,
},
{
name: "digest mismatch",
subject: []intoto.Subject{
{
Name: "pkg:docker/alpine@latest?platform=linux%2Famd64",
},
},
img: "alpine",
digest: "1234",
expectError: true,
},
{
name: "platform mismatch",
subject: []intoto.Subject{
{
Name: "pkg:docker/alpine@latest?platform=linux%2Farm64",
},
},
img: "alpine",
expectError: true,
},
{
name: "malformed purl",
subject: []intoto.Subject{
{
Name: "not-a-purl",
},
},
img: "alpine",
expectError: true,
},
{
name: "malformed image in valid purl",
subject: []intoto.Subject{
{
Name: "pkg:docker/alpine,bar@latest?platform=linux%2Famd64",
},
},
img: "alpine-broken",
expectError: true,
},
{
name: "malformed image name",
subject: []intoto.Subject{
{
Name: "pkg:docker/alpine@latest?platform=linux%2Famd64",
},
},
img: "foo bar",
expectError: true,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
defaultResolver.Image = tc.img
// make sure we're using a fixed platform vs a detected one
defaultResolver.PlatformFn = func() (*v1.Platform, error) {
return &v1.Platform{Architecture: "amd64", OS: "linux"}, nil
}
// digest from mock resolver
tc.subject[0].Digest = map[string]string{"sha256": "da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620"}
if tc.digest != "" {
tc.subject[0].Digest = map[string]string{"sha256": tc.digest}
}
err := policy.VerifySubject(ctx, tc.subject, defaultResolver)
if tc.expectError {
require.Error(t, err)
} else {
require.NoError(t, err)
}
})
}
defaultResolver.Image = "alpine"
subject := []intoto.Subject{
{
Name: "pkg:docker/alpine@latest?platform=linux%2Famd64",
Digest: map[string]string{"sha256": "da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620"},
},
}
// error getting descriptor
defaultResolver.DescriptorFn = func() (*v1.Descriptor, error) {
return nil, fmt.Errorf("error")
}
err := policy.VerifySubject(ctx, subject, defaultResolver)
require.Error(t, err)
// error getting platform
defaultResolver.DescriptorFn = nil
defaultResolver.PlatformFn = func() (*v1.Platform, error) {
return nil, fmt.Errorf("error")
}
err = policy.VerifySubject(ctx, subject, defaultResolver)
require.Error(t, err)
// error getting image name
defaultResolver.PlatformFn = nil
defaultResolver.Image = ""
defaultResolver.ImangeNameFn = func() (string, error) {
return "", fmt.Errorf("error")
}
err = policy.VerifySubject(ctx, subject, defaultResolver)
require.Error(t, err)
}

View File

@@ -7,7 +7,7 @@ import (
"os"
"path/filepath"
"github.com/docker/attest/pkg/attestation"
"github.com/docker/attest/attestation"
intoto "github.com/in-toto/in-toto-golang/in_toto"
"github.com/open-policy-agent/opa/ast"
"github.com/open-policy-agent/opa/rego"
@@ -163,9 +163,9 @@ func handleErrors1(f func(rCtx rego.BuiltinContext, a *ast.Term) (*ast.Term, err
}
}
func handleErrors2(f func(rCtx *rego.BuiltinContext, a, b *ast.Term) (*ast.Term, error)) rego.Builtin2 {
func handleErrors2(f func(rCtx rego.BuiltinContext, a, b *ast.Term) (*ast.Term, error)) rego.Builtin2 {
return func(rCtx rego.BuiltinContext, a, b *ast.Term) (*ast.Term, error) {
return wrapFunctionResult(f(&rCtx, a, b))
return wrapFunctionResult(f(rCtx, a, b))
}
}
@@ -180,7 +180,7 @@ func RegoFunctions(resolver attestation.Resolver) []*tester.Builtin {
Memoize: true,
Nondeterministic: verifyDecl.Nondeterministic,
},
handleErrors2(verifyInTotoEnvelope)),
handleErrors2(verifyInTotoEnvelope(resolver))),
},
{
Decl: attestDecl,
@@ -226,41 +226,48 @@ func fetchInTotoAttestations(resolver attestation.Resolver) rego.Builtin1 {
}
}
func verifyInTotoEnvelope(rCtx *rego.BuiltinContext, envTerm, optsTerm *ast.Term) (*ast.Term, error) {
env := new(attestation.Envelope)
opts := new(attestation.VerifyOptions)
err := ast.As(envTerm.Value, env)
if err != nil {
return nil, fmt.Errorf("failed to cast envelope: %w", err)
}
err = ast.As(optsTerm.Value, &opts)
if err != nil {
return nil, fmt.Errorf("failed to cast verifier options: %w", err)
}
payload, err := attestation.VerifyDSSE(rCtx.Context, env, opts)
if err != nil {
return nil, err
}
statement := new(intoto.Statement)
switch env.PayloadType {
case intoto.PayloadType:
err = json.Unmarshal(payload, statement)
func verifyInTotoEnvelope(resolver attestation.Resolver) rego.Builtin2 {
return func(rCtx rego.BuiltinContext, envTerm, optsTerm *ast.Term) (*ast.Term, error) {
env := new(attestation.Envelope)
opts := new(attestation.VerifyOptions)
err := ast.As(envTerm.Value, env)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal statement: %w", err)
return nil, fmt.Errorf("failed to cast envelope: %w", err)
}
err = ast.As(optsTerm.Value, &opts)
if err != nil {
return nil, fmt.Errorf("failed to cast verifier options: %w", err)
}
// TODO: implement other types of envelope
default:
return nil, fmt.Errorf("unsupported payload type: %s", env.PayloadType)
}
value, err := ast.InterfaceToValue(statement)
if err != nil {
return nil, err
payload, err := attestation.VerifyDSSE(rCtx.Context, env, opts)
if err != nil {
return nil, fmt.Errorf("failed to verify envelope: %w", err)
}
statement := new(intoto.Statement)
switch env.PayloadType {
case intoto.PayloadType:
err = json.Unmarshal(payload, statement)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal statement: %w", err)
}
// TODO: implement other types of envelope
default:
return nil, fmt.Errorf("unsupported payload type: %s", env.PayloadType)
}
err = VerifySubject(rCtx.Context, statement.Subject, resolver)
if err != nil {
return nil, fmt.Errorf("failed to verify subject: %w", err)
}
value, err := ast.InterfaceToValue(statement)
if err != nil {
return nil, err
}
return ast.NewTerm(value), nil
}
return ast.NewTerm(value), nil
}
func loadYAML(path string, bs []byte) (interface{}, error) {

View File

@@ -8,9 +8,9 @@ import (
"path/filepath"
"github.com/distribution/reference"
"github.com/docker/attest/config"
"github.com/docker/attest/internal/util"
"github.com/docker/attest/pkg/config"
"github.com/docker/attest/pkg/tuf"
"github.com/docker/attest/tuf"
)
type Resolver struct {

65
policy/resolver_test.go Normal file
View File

@@ -0,0 +1,65 @@
package policy_test
import (
"context"
"testing"
"github.com/docker/attest/internal/test"
"github.com/docker/attest/policy"
"github.com/docker/attest/tuf"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestResolvePolicy(t *testing.T) {
localPolicyPath := "testdata/policies/allow"
tufPolicyPath := "testdata/policies/allow-canonical"
noLocalPolicyPath := "testdata/policies/no-policy"
testPolicyID := "docker-official-images"
testImageName := "localhost:5001/test/repo:tag"
testCases := []struct {
name string
policyPath string
policyID string
localOverridesTUF bool // if a policy is provided locally, it should override TUF
DisableTUF bool
}{
{name: "resolve by id (TUF only)", policyID: testPolicyID, DisableTUF: false},
{name: "resolve by id (local mapping, TUF policy)", policyPath: noLocalPolicyPath, policyID: testPolicyID, DisableTUF: false},
{name: "resolve by id (local mapping, local policy, no TUF)", policyPath: localPolicyPath, policyID: testPolicyID, DisableTUF: true},
{name: "resolve by id (local mapping, local policy)", policyPath: localPolicyPath, policyID: testPolicyID, DisableTUF: false, localOverridesTUF: true},
{name: "resolve by match (TUF only)", DisableTUF: false},
{name: "resolve by match (local mapping, TUF policy)", policyPath: noLocalPolicyPath, DisableTUF: false},
{name: "resolve by match (local mapping, local policy, no TUF)", policyPath: localPolicyPath, DisableTUF: true},
{name: "resolve by match (local mapping, local policy)", policyPath: localPolicyPath, DisableTUF: false, localOverridesTUF: true},
}
var tufClient tuf.Downloader
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
opts := &policy.Options{}
tempDir := test.CreateTempDir(t, "", "tuf-dest")
if !tc.DisableTUF {
tufClient = tuf.NewMockTufClient(tufPolicyPath)
}
if tc.policyID != "" {
opts.PolicyID = tc.policyID
}
if tc.policyPath != "" {
opts.LocalPolicyDir = tc.policyPath
}
opts.DisableTUF = tc.DisableTUF
opts.LocalTargetsDir = tempDir
resolver := policy.NewResolver(tufClient, opts)
policy, err := resolver.ResolvePolicy(context.Background(), testImageName)
require.NoError(t, err)
assert.NotNil(t, policy)
if tc.DisableTUF || tc.localOverridesTUF {
assert.Contains(t, policy.URI, localPolicyPath)
} else {
assert.Contains(t, policy.URI, tufPolicyPath)
}
})
}
}

View File

@@ -0,0 +1,10 @@
# map repos to policies
version: v1
kind: policy-mapping
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

@@ -1,8 +1,8 @@
package policy
import (
"github.com/docker/attest/pkg/config"
"github.com/docker/attest/pkg/tuf"
"github.com/docker/attest/config"
"github.com/docker/attest/tuf"
intoto "github.com/in-toto/in-toto-golang/in_toto"
)
@@ -34,6 +34,7 @@ type Options struct {
PolicyID string
ReferrersRepo string
AttestationStyle config.AttestationStyle
Debug bool
}
type Policy struct {

View File

@@ -4,7 +4,7 @@ import (
"context"
"fmt"
"github.com/docker/attest/pkg/attestation"
"github.com/docker/attest/attestation"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/secure-systems-lab/go-securesystemslib/dsse"
)

View File

@@ -4,10 +4,10 @@ import (
"path/filepath"
"testing"
"github.com/docker/attest/attestation"
"github.com/docker/attest/internal/test"
"github.com/docker/attest/pkg/attestation"
"github.com/docker/attest/pkg/oci"
"github.com/docker/attest/pkg/policy"
"github.com/docker/attest/oci"
"github.com/docker/attest/policy"
intoto "github.com/in-toto/in-toto-golang/in_toto"
v02 "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.2"
"github.com/stretchr/testify/assert"
@@ -15,13 +15,13 @@ import (
)
var (
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")
InputsPolicyDir = filepath.Join("..", "..", "test", "testdata", "local-policy-inputs")
EmptyPolicyDir = filepath.Join("..", "..", "test", "testdata", "local-policy-no-policies")
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")
InputsPolicyDir = filepath.Join("test", "testdata", "local-policy-inputs")
EmptyPolicyDir = filepath.Join("test", "testdata", "local-policy-no-policies")
TestTempDir = "attest-sign-test"
)
@@ -35,8 +35,8 @@ func TestSignVerifyOCILayout(t *testing.T) {
expectedAttestations int
replace bool
}{
{"signed replaced", test.UnsignedTestImage, 0, 4, true},
{"without replace", test.UnsignedTestImage, 4, 4, false},
{"signed replaced", test.UnsignedTestImage(), 0, 4, true},
{"without replace", test.UnsignedTestImage(), 4, 4, false},
// image without provenance doesn't fail
{"no provenance (replace)", NoProvenanceImage, 0, 2, true},
{"no provenance (no replace)", NoProvenanceImage, 2, 2, false},
@@ -58,7 +58,7 @@ func TestSignVerifyOCILayout(t *testing.T) {
require.NoError(t, err)
spec, err := oci.ParseImageSpec(oci.LocalPrefix + outputLayout)
require.NoError(t, err)
err = oci.SaveIndex([]*oci.ImageSpec{spec}, signedIndex, attIdx.Name)
err = oci.SaveIndex(ctx, []*oci.ImageSpec{spec}, signedIndex, attIdx.Name)
require.NoError(t, err)
policy, err := Verify(ctx, spec, policyOpts)
require.NoError(t, err)

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