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
This commit is contained in:
James Carnegie
2024-09-09 14:22:17 +01:00
committed by GitHub
parent ed0ae8ecf6
commit b4e6767cc6
33 changed files with 307 additions and 340 deletions

View File

@@ -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:<DELEGATED_ROLE>
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)...)
}