From b4e6767cc6cf2eaef37a0b9be822603cd03cbaad Mon Sep 17 00:00:00 2001 From: James Carnegie Date: Mon, 9 Sep 2024 14:22:17 +0100 Subject: [PATCH] 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 --- .gitignore | 1 + .../example_attestation_manifest_test.go | 3 +- attestation/layout_test.go | 2 +- attestation/referrers_test.go | 50 ++++----- attestation/registry_test.go | 9 +- attestation/sign_test.go | 9 +- example_sign_test.go | 4 +- go.mod | 30 +---- go.sum | 77 ------------- internal/test/test.go | 18 +++ internal/useragent/useragent.go | 31 ++++++ internal/useragent/useragent_test.go | 19 ++++ internal/version/version.go | 39 +++++++ mirror/example_mirror_test.go | 16 +-- mirror/metadata_test.go | 7 +- mirror/mirror.go | 5 +- mirror/targets_test.go | 7 +- oci/authn_test.go | 6 +- oci/http.go | 27 ----- oci/oci.go | 7 +- oci/output.go | 21 ++-- oci/output_test.go | 32 +++--- oci/types.go | 9 +- sign_test.go | 2 +- tlog/tl.go | 3 +- tuf/example_registry_test.go | 3 +- tuf/registry.go | 15 ++- tuf/registry_test.go | 104 ++++++++---------- tuf/tuf.go | 5 +- tuf/tuf_test.go | 43 ++++---- tuf/version.go | 31 +----- verify.go | 6 +- verify_test.go | 6 +- 33 files changed, 307 insertions(+), 340 deletions(-) create mode 100644 internal/useragent/useragent.go create mode 100644 internal/useragent/useragent_test.go create mode 100644 internal/version/version.go delete mode 100644 oci/http.go diff --git a/.gitignore b/.gitignore index 3b735ec..0f49fba 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,4 @@ # Go workspace file go.work +.aider* diff --git a/attestation/example_attestation_manifest_test.go b/attestation/example_attestation_manifest_test.go index c61f7dd..1c21697 100644 --- a/attestation/example_attestation_manifest_test.go +++ b/attestation/example_attestation_manifest_test.go @@ -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) } diff --git a/attestation/layout_test.go b/attestation/layout_test.go index c9885b8..1f7b2d8 100644 --- a/attestation/layout_test.go +++ b/attestation/layout_test.go @@ -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 { diff --git a/attestation/referrers_test.go b/attestation/referrers_test.go index 87a86ab..60c2f7c 100644 --- a/attestation/referrers_test.go +++ b/attestation/referrers_test.go @@ -44,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) { @@ -109,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 @@ -118,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) } @@ -190,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 @@ -216,7 +217,7 @@ func TestReferencesInDifferentRepo(t *testing.T) { 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) @@ -227,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 @@ -242,7 +243,7 @@ func TestReferencesInDifferentRepo(t *testing.T) { 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) @@ -254,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) } } @@ -283,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" @@ -298,7 +298,7 @@ func TestCorrectArtifactTypeInTagFallback(t *testing.T) { 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) @@ -309,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) diff --git a/attestation/registry_test.go b/attestation/registry_test.go index 6af9842..15d37a2 100644 --- a/attestation/registry_test.go +++ b/attestation/registry_test.go @@ -2,7 +2,6 @@ package attestation_test import ( "fmt" - "net/http/httptest" "net/url" "strings" "testing" @@ -19,9 +18,9 @@ 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{} @@ -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) diff --git a/attestation/sign_test.go b/attestation/sign_test.go index 7c7b79d..110c596 100644 --- a/attestation/sign_test.go +++ b/attestation/sign_test.go @@ -6,7 +6,6 @@ import ( "crypto/rand" "encoding/json" "fmt" - "net/http/httptest" "net/url" "testing" "time" @@ -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) }) } diff --git a/example_sign_test.go b/example_sign_test.go index d196166..e89b0e0 100644 --- a/example_sign_test.go +++ b/example_sign_test.go @@ -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) } diff --git a/go.mod b/go.mod index a88567a..5e3785e 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,6 @@ require ( github.com/go-openapi/runtime v0.28.0 github.com/go-openapi/strfmt v0.23.0 github.com/google/go-containerregistry v0.20.2 - github.com/hashicorp/go-cleanhttp v0.5.2 github.com/in-toto/in-toto-golang v0.9.0 github.com/open-policy-agent/opa v0.68.0 github.com/opencontainers/image-spec v1.1.0 @@ -22,7 +21,6 @@ require ( 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.196.0 sigs.k8s.io/yaml v1.4.0 @@ -39,9 +37,6 @@ require ( 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 - 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 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 @@ -63,23 +58,17 @@ require ( 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.21 // 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,7 +86,6 @@ 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 @@ -107,6 +94,7 @@ require ( github.com/googleapis/enterprise-certificate-proxy v0.3.3 // 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 @@ -116,18 +104,10 @@ require ( github.com/josharian/intern v1.0.0 // 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.3.0 // indirect - github.com/moby/sys/userns 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 @@ -136,7 +116,6 @@ 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.20.2 // indirect github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.55.0 // indirect @@ -146,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 @@ -161,17 +138,13 @@ 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.54.0 // indirect @@ -200,5 +173,6 @@ require ( 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 ) diff --git a/go.sum b/go.sum index 04c81c2..4ce3798 100644 --- a/go.sum +++ b/go.sum @@ -17,12 +17,8 @@ cuelabs.dev/go/oci/ociregistry v0.0.0-20240404174027-a39bec0462d2 h1:BnG6pr9TTr6 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= @@ -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.21 h1:USGXRK1eOC/SX0L195YgxTHb0a00anxajOzgfN0qrCA= -github.com/containerd/containerd v1.7.21/go.mod h1:e3Jz1rYRUZ2Lt51YrH9Rz0zPyJBOlSvB3ghr2jbVD8g= 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= @@ -417,8 +395,6 @@ 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.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -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,24 +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.3.0 h1:9ni5DlcW5an3SvRSx4MouotOygvzaXbaSrc/wGDFWPo= -github.com/moby/sys/user v0.3.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs= -github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g= -github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= -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= @@ -514,9 +473,6 @@ 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.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= @@ -549,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= @@ -615,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= @@ -629,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= @@ -647,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= @@ -670,8 +607,6 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9RO 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.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= @@ -702,7 +637,6 @@ golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQ 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= @@ -715,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= @@ -735,7 +668,6 @@ golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbht 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= @@ -746,31 +678,24 @@ 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/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -797,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= diff --git a/internal/test/test.go b/internal/test/test.go index 8e07025..f432b6d 100644 --- a/internal/test/test.go +++ b/internal/test/test.go @@ -7,14 +7,19 @@ import ( _ "embed" "encoding/pem" "fmt" + "net/http" + "net/http/httptest" "os" "path/filepath" + "strings" "testing" "time" "github.com/docker/attest/attestation" + "github.com/docker/attest/internal/useragent" "github.com/docker/attest/signerverifier" "github.com/docker/attest/tlog" + "github.com/google/go-containerregistry/pkg/registry" "github.com/secure-systems-lab/go-securesystemslib/dsse" ) @@ -81,6 +86,19 @@ 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 { diff --git a/internal/useragent/useragent.go b/internal/useragent/useragent.go new file mode 100644 index 0000000..f173865 --- /dev/null +++ b/internal/useragent/useragent.go @@ -0,0 +1,31 @@ +package useragent + +import ( + "context" + + "github.com/docker/attest/internal/version" +) + +type userAgentKeyType string + +const ( + userAgentKey userAgentKeyType = "attest-user-agent" + defaultUserAgent string = "attest/unknown (docker)" +) + +func Set(ctx context.Context, userAgent string) context.Context { + return context.WithValue(ctx, userAgentKey, userAgent) +} + +// Get retrieves the HTTP user agent from the context. +func Get(ctx context.Context) string { + if ua, ok := ctx.Value(userAgentKey).(string); ok { + return ua + } + version, err := version.Get() + if err != nil || version == nil { + return defaultUserAgent + } + + return "attest/" + version.String() + " (docker)" +} diff --git a/internal/useragent/useragent_test.go b/internal/useragent/useragent_test.go new file mode 100644 index 0000000..3cc8d92 --- /dev/null +++ b/internal/useragent/useragent_test.go @@ -0,0 +1,19 @@ +package useragent + +import ( + "context" + "testing" +) + +// test the user agent setting and getting. +func TestSetUserAgent(t *testing.T) { + ctx := context.Background() + if Get(ctx) != defaultUserAgent { + t.Errorf("expected user agent to be '%s', got %q", defaultUserAgent, Get(ctx)) + } + + ctx = Set(ctx, "test-agent") + if Get(ctx) != "test-agent" { + t.Errorf("expected user agent to be 'test-agent', got %q", Get(ctx)) + } +} diff --git a/internal/version/version.go b/internal/version/version.go new file mode 100644 index 0000000..14fda73 --- /dev/null +++ b/internal/version/version.go @@ -0,0 +1,39 @@ +package version + +import ( + "fmt" + "runtime/debug" + + "github.com/Masterminds/semver/v3" +) + +const ThisModulePath = "github.com/docker/attest" + +// Get returns the version of the attest module. +// this can return nil if the version can't be determined (without an error). +func Get() (*semver.Version, error) { + var attestMod *debug.Module + bi, ok := debug.ReadBuildInfo() + if !ok { + return nil, nil + } + if bi.Main.Path == ThisModulePath { + attestMod = &bi.Main + } else { + for _, dep := range bi.Deps { + if dep.Path == ThisModulePath { + attestMod = dep + break + } + } + } + if attestMod == nil { + return nil, nil + } + + attestVersion, err := semver.NewVersion(attestMod.Version) + if err != nil { + return nil, fmt.Errorf("failed to parse version %s: %w", attestMod.Version, err) + } + return attestVersion, nil +} diff --git a/mirror/example_mirror_test.go b/mirror/example_mirror_test.go index d0aea09..51ca46d 100644 --- a/mirror/example_mirror_test.go +++ b/mirror/example_mirror_test.go @@ -1,6 +1,7 @@ package mirror_test import ( + "context" "fmt" "os" "path/filepath" @@ -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 } diff --git a/mirror/metadata_test.go b/mirror/metadata_test.go index d7eb43b..fed45d3 100644 --- a/mirror/metadata_test.go +++ b/mirror/metadata_test.go @@ -1,6 +1,7 @@ package mirror import ( + "context" "encoding/json" "net/http" "net/http/httptest" @@ -25,7 +26,7 @@ func TestGetTufMetadataMirror(t *testing.T) { 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) @@ -43,7 +44,7 @@ func TestGetMetadataManifest(t *testing.T) { 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) @@ -82,7 +83,7 @@ func TestGetDelegatedMetadataMirrors(t *testing.T) { 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() diff --git a/mirror/mirror.go b/mirror/mirror.go index 6024703..90d1fcf 100644 --- a/mirror/mirror.go +++ b/mirror/mirror.go @@ -1,16 +1,17 @@ package mirror import ( + "context" "fmt" "github.com/docker/attest/tuf" ) -func NewTUFMirror(root []byte, tufPath, metadataURL, targetsURL string, versionChecker tuf.VersionChecker) (*TUFMirror, error) { +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(&tuf.ClientOptions{InitialRoot: root, Path: tufPath, MetadataSource: metadataURL, TargetsSource: targetsURL, VersionChecker: versionChecker}) + tufClient, err := tuf.NewClient(ctx, &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) } diff --git a/mirror/targets_test.go b/mirror/targets_test.go index 6b50d6b..22dc7d2 100644 --- a/mirror/targets_test.go +++ b/mirror/targets_test.go @@ -1,6 +1,7 @@ package mirror import ( + "context" "encoding/json" "net/http" "net/http/httptest" @@ -26,7 +27,7 @@ func TestGetTufTargetsMirror(t *testing.T) { 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() @@ -60,7 +61,7 @@ func TestTargetDelegationMetadata(t *testing.T) { 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") @@ -73,7 +74,7 @@ func TestGetDelegatedTargetMirrors(t *testing.T) { 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() diff --git a/oci/authn_test.go b/oci/authn_test.go index 71a9ec5..0803f10 100644 --- a/oci/authn_test.go +++ b/oci/authn_test.go @@ -3,6 +3,7 @@ package oci_test import ( + "context" "testing" "github.com/docker/attest/internal/test" @@ -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) }) } diff --git a/oci/http.go b/oci/http.go deleted file mode 100644 index 5578a0b..0000000 --- a/oci/http.go +++ /dev/null @@ -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(), - } -} diff --git a/oci/oci.go b/oci/oci.go index 436526f..f42dbe2 100644 --- a/oci/oci.go +++ b/oci/oci.go @@ -7,6 +7,7 @@ import ( "github.com/containerd/platforms" "github.com/distribution/reference" + "github.com/docker/attest/internal/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 { diff --git a/oci/output.go b/oci/output.go index 059cadb..66399eb 100644 --- a/oci/output.go +++ b/oci/output.go @@ -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) } diff --git a/oci/output_test.go b/oci/output_test.go index 32feb6c..5b4fc24 100644 --- a/oci/output_test.go +++ b/oci/output_test.go @@ -1,8 +1,8 @@ package oci_test import ( + "context" "fmt" - "net/http/httptest" "net/url" "testing" @@ -21,21 +21,22 @@ func TestSavingIndex(t *testing.T) { 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{ diff --git a/oci/types.go b/oci/types.go index edb5c3e..78e6f62 100644 --- a/oci/types.go +++ b/oci/types.go @@ -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) { diff --git a/sign_test.go b/sign_test.go index 5df17ab..81c6d9a 100644 --- a/sign_test.go +++ b/sign_test.go @@ -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) diff --git a/tlog/tl.go b/tlog/tl.go index 52276df..b6b8ada 100644 --- a/tlog/tl.go +++ b/tlog/tl.go @@ -14,6 +14,7 @@ import ( "strings" "time" + "github.com/docker/attest/internal/useragent" "github.com/docker/attest/internal/util" "github.com/docker/attest/signerverifier" "github.com/go-openapi/runtime" @@ -112,7 +113,7 @@ func (tl *RekorTL) UploadLogEntry(ctx context.Context, subject string, payload, hasher.Write(payload) // upload entry - rekorClient, err := rclient.GetRekorClient(DefaultRekorURL) + rekorClient, err := rclient.GetRekorClient(DefaultRekorURL, rclient.WithUserAgent(useragent.Get(ctx))) if err != nil { return nil, fmt.Errorf("Error creating rekor client: %w", err) } diff --git a/tuf/example_registry_test.go b/tuf/example_registry_test.go index e21d110..900c1f1 100644 --- a/tuf/example_registry_test.go +++ b/tuf/example_registry_test.go @@ -1,6 +1,7 @@ package tuf_test import ( + "context" "os" "path/filepath" @@ -20,7 +21,7 @@ func ExampleNewClient_registry() { metadataURI := "registry-1.docker.io/docker/tuf-metadata:latest" targetsURI := "registry-1.docker.io/docker/tuf-targets" - registryClient, err := tuf.NewClient(&tuf.ClientOptions{tuf.DockerTUFRootStaging.Data, tufOutputPath, metadataURI, targetsURI, tuf.NewMockVersionChecker()}) + registryClient, err := tuf.NewClient(context.Background(), &tuf.ClientOptions{tuf.DockerTUFRootStaging.Data, tufOutputPath, metadataURI, targetsURI, tuf.NewMockVersionChecker()}) if err != nil { panic(err) } diff --git a/tuf/registry.go b/tuf/registry.go index a772588..4f67fc4 100644 --- a/tuf/registry.go +++ b/tuf/registry.go @@ -1,6 +1,7 @@ package tuf import ( + "context" "encoding/json" "fmt" "io" @@ -11,6 +12,7 @@ import ( "time" "github.com/distribution/reference" + "github.com/docker/attest/internal/useragent" "github.com/docker/attest/oci" "github.com/google/go-containerregistry/pkg/authn" "github.com/google/go-containerregistry/pkg/crane" @@ -70,7 +72,7 @@ type Layers struct { MediaType string `json:"mediaType"` } -func NewRegistryFetcher(cfg *config.UpdaterConfig) (*RegistryFetcher, error) { +func NewRegistryFetcher(ctx context.Context, cfg *config.UpdaterConfig) (*RegistryFetcher, error) { ref, err := reference.ParseNormalizedNamed(cfg.RemoteMetadataURL) if err != nil { return nil, fmt.Errorf("failed to parse metadata repo: %w", err) @@ -89,11 +91,12 @@ func NewRegistryFetcher(cfg *config.UpdaterConfig) (*RegistryFetcher, error) { targetsRepo := targetsRef.Name() return &RegistryFetcher{ // we need to keep these reference so that we can unmangle the URL paths when downloading files - cfg: cfg, - metadataRepo: metadataRepo, - metadataTag: metadataTag, - targetsRepo: targetsRepo, - cache: NewImageCache(), + cfg: cfg, + metadataRepo: metadataRepo, + metadataTag: metadataTag, + targetsRepo: targetsRepo, + cache: NewImageCache(), + httpUserAgent: useragent.Get(ctx), }, nil } diff --git a/tuf/registry_test.go b/tuf/registry_test.go index 0a3a579..207c6aa 100644 --- a/tuf/registry_test.go +++ b/tuf/registry_test.go @@ -9,6 +9,8 @@ import ( "strings" "testing" + "github.com/docker/attest/internal/test" + "github.com/docker/attest/internal/useragent" "github.com/docker/attest/internal/util" "github.com/docker/attest/oci" "github.com/google/go-containerregistry/pkg/crane" @@ -22,7 +24,6 @@ import ( "github.com/google/go-containerregistry/pkg/v1/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/testcontainers/testcontainers-go/modules/registry" "github.com/theupdateframework/go-tuf/v2/metadata" "github.com/theupdateframework/go-tuf/v2/metadata/config" "github.com/theupdateframework/go-tuf/v2/metadata/updater" @@ -38,14 +39,14 @@ const ( ) func TestRegistryFetcher(t *testing.T) { - // 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) + ctx := context.Background() + regServer := test.NewLocalRegistry(ctx) + defer regServer.Close() + + regAddr, err := url.Parse(regServer.URL) + require.NoError(t, err) + + LoadRegistryTestData(ctx, t, regAddr, OCITUFTestDataPath) metadataRepo := regAddr.Host + metadataPath targetsRepo := regAddr.Host + targetsPath @@ -62,7 +63,7 @@ func TestRegistryFetcher(t *testing.T) { cfg.LocalTargetsDir = dir cfg.RemoteTargetsURL = targetsRepo cfg.RemoteMetadataURL = metadataRepo - cfg.Fetcher, err = NewRegistryFetcher(cfg) + cfg.Fetcher, err = NewRegistryFetcher(context.Background(), cfg) require.NoError(t, err) // create a new Updater instance @@ -228,7 +229,7 @@ func TestParseImgRef(t *testing.T) { RemoteMetadataURL: repo, RemoteTargetsURL: targets, } - d, err := NewRegistryFetcher(cfg) + d, err := NewRegistryFetcher(context.Background(), cfg) if tc.expectedConstructorError != "" { assert.ErrorContains(t, err, tc.expectedConstructorError) } else { @@ -272,13 +273,12 @@ func TestGetDataFromLayer(t *testing.T) { } func TestPullFileLayer(t *testing.T) { - // run local registry - registry, url := RunTestRegistry(t) - defer func() { - if err := registry.Terminate(context.Background()); err != nil { - t.Fatalf("failed to terminate container: %s", err) // nolint:gocritic - } - }() + ctx := context.Background() + regServer := test.NewLocalRegistry(ctx) + defer regServer.Close() + + url, err := url.Parse(regServer.URL) + require.NoError(t, err) // make test layer repo := tufMetadataRepo @@ -288,10 +288,13 @@ func TestPullFileLayer(t *testing.T) { assert.NoError(t, err) layerRef := fmt.Sprintf("%s/%s@%s", url.Host, repo, hash.String()) - // cache test layer - d := &RegistryFetcher{ - cache: NewImageCache(), - } + // cache test manifest + d, err := NewRegistryFetcher(context.Background(), &config.UpdaterConfig{ + RemoteMetadataURL: tufMetadataRepo, + RemoteTargetsURL: tufMetadataRepo, + }) + require.NoError(t, err) + d.cache.Put(layerRef, data) // push uncached image layer to local registry @@ -303,7 +306,7 @@ func TestPullFileLayer(t *testing.T) { img := empty.Image img, err = mutate.Append(img, mutate.Addendum{Layer: uncachedTestLayer}) assert.NoError(t, err) - err = crane.Push(img, fmt.Sprintf("%s/%s", url.Host, fmt.Sprintf("%s:latest", repo))) + err = crane.Push(img, fmt.Sprintf("%s/%s", url.Host, fmt.Sprintf("%s:latest", repo)), crane.WithUserAgent(useragent.Get(ctx))) assert.NoError(t, err) testCases := []struct { @@ -329,13 +332,12 @@ func TestPullFileLayer(t *testing.T) { } func TestGetManifest(t *testing.T) { - // run local registry - registry, url := RunTestRegistry(t) - defer func() { - if err := registry.Terminate(context.Background()); err != nil { - t.Fatalf("failed to terminate container: %s", err) // nolint:gocritic - } - }() + ctx := context.Background() + regServer := test.NewLocalRegistry(ctx) + defer regServer.Close() + + url, err := url.Parse(regServer.URL) + require.NoError(t, err) // make test manifest repo := tufMetadataRepo @@ -345,16 +347,19 @@ func TestGetManifest(t *testing.T) { imgRef := fmt.Sprintf("%s/%s:latest", url.Host, repo) // cache test manifest - d := &RegistryFetcher{ - cache: NewImageCache(), - } + d, err := NewRegistryFetcher(context.Background(), &config.UpdaterConfig{ + RemoteMetadataURL: tufMetadataRepo, + RemoteTargetsURL: tufMetadataRepo, + }) + require.NoError(t, err) + mf, err := img.RawManifest() assert.NoError(t, err) d.cache.Put(imgRef, mf) // push test image to local registry unchachedImgRef := fmt.Sprintf("%s/%s:unchached", url.Host, repo) - err = crane.Push(img, unchachedImgRef) + err = crane.Push(img, unchachedImgRef, crane.WithUserAgent(useragent.Get(ctx))) assert.NoError(t, err) testCases := []struct { @@ -374,38 +379,21 @@ func TestGetManifest(t *testing.T) { } } -// RunTestRegistry starts a registry testcontainer for TUF on OCI testdata. -func RunTestRegistry(t *testing.T) (*registry.RegistryContainer, *url.URL) { - registryContainer, err := registry.Run(context.Background(), "registry:2.8.3") - if err != nil { - t.Fatalf("failed to start container: %s", err) - } - httpAddress, err := registryContainer.Address(context.Background()) - if err != nil { - t.Fatalf("failed to get container address: %s", err) - } - addr, err := url.Parse(httpAddress) - if err != nil { - t.Fatalf("failed to parse container address: %s", err) - } - return registryContainer, addr -} - // LoadRegistryTestData pushes TUF metadata and targets to an OCI registry. -func LoadRegistryTestData(t *testing.T, registry *url.URL, path string) { +func LoadRegistryTestData(ctx context.Context, t *testing.T, registry *url.URL, path string) { // push tuf metadata and targets to local registry MetadataRepo := tufMetadataRepo TargetsRepo := "tuf-targets" DelegatedRole := testRole // push top-level metadata -> metadata:latest - err := LoadMetadata(filepath.Join(path, "metadata"), registry.Host, MetadataRepo, LatestTag) + err := LoadMetadata(ctx, filepath.Join(path, "metadata"), registry.Host, MetadataRepo, LatestTag) if err != nil { t.Fatal(err) } // push delegated metadata -> metadata: - err = LoadMetadata(filepath.Join(path, "metadata", DelegatedRole), registry.Host, MetadataRepo, DelegatedRole) + err = LoadMetadata(ctx, filepath.Join(path, "metadata", DelegatedRole), registry.Host, MetadataRepo, DelegatedRole) if err != nil { t.Fatal(err) } @@ -438,13 +426,13 @@ func LoadRegistryTestData(t *testing.T, registry *url.URL, path string) { if err != nil { t.Fatal(err) } - err = remote.Write(ref, img, oci.MultiKeychainOption()) + err = remote.Write(ref, img, oci.WithOptions(ctx, nil)...) if err != nil { t.Fatal(err) } case 2: // delegated target - err = remote.WriteIndex(ref, tIdx, oci.MultiKeychainOption()) + err = remote.WriteIndex(ref, tIdx, oci.WithOptions(ctx, nil)...) if err != nil { t.Fatal(err) } @@ -455,7 +443,7 @@ func LoadRegistryTestData(t *testing.T, registry *url.URL, path string) { } // LoadMetadata loads TUF metadata from a local path and pushes to a registry. -func LoadMetadata(path, host, repo, tag string) error { +func LoadMetadata(ctx context.Context, path, host, repo, tag string) error { mIdx, err := layout.ImageIndexFromPath(path) if err != nil { return err @@ -472,5 +460,5 @@ func LoadMetadata(path, host, repo, tag string) error { if err != nil { return err } - return remote.Write(ref, img, oci.MultiKeychainOption()) + return remote.Write(ref, img, oci.WithOptions(ctx, nil)...) } diff --git a/tuf/tuf.go b/tuf/tuf.go index c3715ea..03cb6c0 100644 --- a/tuf/tuf.go +++ b/tuf/tuf.go @@ -1,6 +1,7 @@ package tuf import ( + "context" "errors" "fmt" "io/fs" @@ -75,7 +76,7 @@ func NewDockerDefaultClientOptions(tufPath string) *ClientOptions { } // NewClient creates a new TUF client. -func NewClient(opts *ClientOptions) (*Client, error) { +func NewClient(ctx context.Context, opts *ClientOptions) (*Client, error) { var tufSource Source if strings.HasPrefix(opts.MetadataSource, "https://") || strings.HasPrefix(opts.MetadataSource, "http://") { tufSource = HTTPSource @@ -119,7 +120,7 @@ func NewClient(opts *ClientOptions) (*Client, error) { cfg.RemoteTargetsURL = opts.TargetsSource if tufSource == OCISource { - cfg.Fetcher, err = NewRegistryFetcher(cfg) + cfg.Fetcher, err = NewRegistryFetcher(ctx, cfg) if err != nil { return nil, fmt.Errorf("failed to create registry fetcher: %w", err) } diff --git a/tuf/tuf_test.go b/tuf/tuf_test.go index f7c77cf..ef4a697 100644 --- a/tuf/tuf_test.go +++ b/tuf/tuf_test.go @@ -5,10 +5,12 @@ import ( "fmt" "net/http" "net/http/httptest" + "net/url" "os" "path/filepath" "testing" + "github.com/docker/attest/internal/test" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/theupdateframework/go-tuf/v2/metadata" @@ -43,14 +45,13 @@ func TestRootInit(t *testing.T) { 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) + ctx := context.Background() + regServer := test.NewLocalRegistry(ctx) + defer regServer.Close() + + regAddr, err := url.Parse(regServer.URL) + require.NoError(t, err) + LoadRegistryTestData(ctx, t, regAddr, OCITUFTestDataPath) alwaysGoodVersionChecker := &MockVersionChecker{err: nil} alwaysBadVersionChecker := &MockVersionChecker{err: assert.AnError} @@ -63,19 +64,18 @@ func TestRootInit(t *testing.T) { {"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}) + _, err := NewClient(ctx, &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}) + _, err = NewClient(ctx, &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}) + _, err = NewClient(ctx, &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}) + _, err = NewClient(ctx, &ClientOptions{DockerTUFRootDev.Data, tufPath, tc.metadataSource, tc.targetsSource, alwaysBadVersionChecker}) assert.Errorf(t, err, "Expected error recreating TUF client with bad version checker") } } @@ -90,14 +90,13 @@ func TestDownloadTarget(t *testing.T) { 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) + ctx := context.Background() + regServer := test.NewLocalRegistry(ctx) + defer regServer.Close() + + regAddr, err := url.Parse(regServer.URL) + require.NoError(t, err) + LoadRegistryTestData(ctx, t, regAddr, OCITUFTestDataPath) alwaysGoodVersionChecker := &MockVersionChecker{err: nil} @@ -113,7 +112,7 @@ func TestDownloadTarget(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - tufClient, err := NewClient(&ClientOptions{DockerTUFRootDev.Data, tufPath, tc.metadataSource, tc.targetsSource, alwaysGoodVersionChecker}) + tufClient, err := NewClient(ctx, &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") diff --git a/tuf/version.go b/tuf/version.go index 3c96563..969250d 100644 --- a/tuf/version.go +++ b/tuf/version.go @@ -2,10 +2,10 @@ package tuf import ( "fmt" - "runtime/debug" "strings" "github.com/Masterminds/semver/v3" + "github.com/docker/attest/internal/version" ) const ThisModulePath = "github.com/docker/attest" @@ -39,32 +39,13 @@ func NewDefaultVersionChecker() *DefaultVersionChecker { type DefaultVersionChecker struct{} func (vc *DefaultVersionChecker) CheckVersion(client Downloader) error { - var attestMod *debug.Module - bi, ok := debug.ReadBuildInfo() - if !ok { - // if we can't read the build info, assume we're good. this should only happen if we're not running in a module - return nil - } - if bi.Main.Path == ThisModulePath { - attestMod = &bi.Main - } else { - for _, dep := range bi.Deps { - if dep.Path == ThisModulePath { - attestMod = dep - break - } - } - } - if attestMod == nil { - // if we can't find the attest dep, assume we're good. this should only happen in a test - return nil - } - - attestVersion, err := semver.NewVersion(attestMod.Version) + attestVersion, err := version.Get() if err != nil { - return fmt.Errorf("failed to parse version %s: %w", attestMod.Version, err) + return fmt.Errorf("failed to get version: %w", err) + } + if attestVersion == nil { + return nil } - // see https://github.com/Masterminds/semver/blob/v3.2.1/README.md#checking-version-constraints // for more information on the expected format of the version constraints in the TUF repo target, err := client.DownloadTarget("version-constraints", "") diff --git a/verify.go b/verify.go index 5b231d8..873953c 100644 --- a/verify.go +++ b/verify.go @@ -26,14 +26,14 @@ type tufVerifier struct { tufClient tuf.Downloader } -func NewVerifier(opts *policy.Options) (Verifier, error) { +func NewVerifier(ctx context.Context, opts *policy.Options) (Verifier, error) { err := populateDefaultOptions(opts) if err != nil { return nil, err } var tufClient tuf.Downloader if !opts.DisableTUF { - tufClient, err = tuf.NewClient(opts.TUFClientOptions) + tufClient, err = tuf.NewClient(ctx, opts.TUFClientOptions) if err != nil { return nil, fmt.Errorf("failed to create TUF client: %w", err) } @@ -91,7 +91,7 @@ func (verifier *tufVerifier) Verify(ctx context.Context, src *oci.ImageSpec) (re } func Verify(ctx context.Context, src *oci.ImageSpec, opts *policy.Options) (result *VerificationResult, err error) { - verifier, err := NewVerifier(opts) + verifier, err := NewVerifier(ctx, opts) if err != nil { return nil, err } diff --git a/verify_test.go b/verify_test.go index ce52f5c..a13d61b 100644 --- a/verify_test.go +++ b/verify_test.go @@ -86,7 +86,7 @@ func TestVSA(t *testing.T) { // output signed attestations spec, err := oci.ParseImageSpec(oci.LocalPrefix+outputLayout, oci.WithPlatform(LinuxAMD64)) require.NoError(t, err) - err = oci.SaveIndex([]*oci.ImageSpec{spec}, signedIndex, attIdx.Name) + err = oci.SaveIndex(ctx, []*oci.ImageSpec{spec}, signedIndex, attIdx.Name) assert.NoError(t, err) // mocked vsa query should pass @@ -138,7 +138,7 @@ func TestVerificationFailure(t *testing.T) { // output signed attestations spec, err := oci.ParseImageSpec(oci.LocalPrefix+outputLayout, oci.WithPlatform(LinuxAMD64)) require.NoError(t, err) - err = oci.SaveIndex([]*oci.ImageSpec{spec}, signedIndex, attIdx.Name) + err = oci.SaveIndex(ctx, []*oci.ImageSpec{spec}, signedIndex, attIdx.Name) assert.NoError(t, err) // mocked vsa query should fail @@ -230,7 +230,7 @@ func TestSignVerify(t *testing.T) { // output signed attestations spec, err := oci.ParseImageSpec(oci.LocalPrefix+outputLayout, oci.WithPlatform(LinuxAMD64)) require.NoError(t, err) - err = oci.SaveIndex([]*oci.ImageSpec{spec}, signedIndex, imageName) + err = oci.SaveIndex(ctx, []*oci.ImageSpec{spec}, signedIndex, imageName) require.NoError(t, err) policyOpts := &policy.Options{