mirror of
https://github.com/moby/buildkit.git
synced 2026-08-09 09:11:45 +00:00
Add solve-wide compatibility-version support for image and oci exports, with historical goldens and release compatibility tests. Backfill version 10 for v0.13-v0.14 git artifact behavior, keep version 20 as current, and reject unsupported zstd on v10. Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
618 lines
16 KiB
Go
618 lines
16 KiB
Go
package http
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/containerd/containerd/v2/core/diff/apply"
|
|
ctdmetadata "github.com/containerd/containerd/v2/core/metadata"
|
|
"github.com/containerd/containerd/v2/core/snapshots"
|
|
"github.com/containerd/containerd/v2/plugins/content/local"
|
|
"github.com/containerd/containerd/v2/plugins/diff/walking"
|
|
"github.com/containerd/containerd/v2/plugins/snapshots/native"
|
|
"github.com/moby/buildkit/cache"
|
|
"github.com/moby/buildkit/cache/metadata"
|
|
"github.com/moby/buildkit/client"
|
|
"github.com/moby/buildkit/identity"
|
|
"github.com/moby/buildkit/session"
|
|
"github.com/moby/buildkit/snapshot"
|
|
containerdsnapshot "github.com/moby/buildkit/snapshot/containerd"
|
|
"github.com/moby/buildkit/solver"
|
|
"github.com/moby/buildkit/source"
|
|
"github.com/moby/buildkit/util/leaseutil"
|
|
"github.com/moby/buildkit/util/testutil/httpserver"
|
|
"github.com/moby/buildkit/util/winlayers"
|
|
digest "github.com/opencontainers/go-digest"
|
|
"github.com/stretchr/testify/require"
|
|
bolt "go.etcd.io/bbolt"
|
|
)
|
|
|
|
const signFixturesPathEnv = "BUILDKIT_TEST_SIGN_FIXTURES"
|
|
|
|
func TestHTTPSource(t *testing.T) {
|
|
t.Parallel()
|
|
ctx := context.TODO()
|
|
|
|
hs, err := newHTTPSource(t)
|
|
require.NoError(t, err)
|
|
|
|
resp := &httpserver.Response{
|
|
Etag: identity.NewID(),
|
|
Content: []byte("content1"),
|
|
}
|
|
server := httpserver.NewTestServer(map[string]*httpserver.Response{
|
|
"/foo": resp,
|
|
})
|
|
defer server.Close()
|
|
|
|
id := &HTTPIdentifier{URL: server.URL + "/foo"}
|
|
|
|
h, err := hs.Resolve(ctx, id, nil, nil)
|
|
require.NoError(t, err)
|
|
|
|
k, p, _, _, err := h.CacheKey(ctx, nil, 0)
|
|
require.NoError(t, err)
|
|
|
|
expectedPin1 := digest.FromBytes(resp.Content).String()
|
|
plaintext1 := `{"Filename":"foo","Perm":0,"UID":0,"GID":0,"Checksum":"` + expectedPin1 + `"}`
|
|
expectedContent1 := digest.FromBytes([]byte(plaintext1)).String()
|
|
|
|
require.Equal(t, expectedContent1, k)
|
|
require.Equal(t, expectedPin1, p)
|
|
require.Equal(t, 1, server.Stats("/foo").AllRequests)
|
|
require.Equal(t, 0, server.Stats("/foo").CachedRequests)
|
|
|
|
ref, err := h.Snapshot(ctx, nil)
|
|
require.NoError(t, err)
|
|
defer func() {
|
|
if ref != nil {
|
|
ref.Release(context.WithoutCancel(ctx))
|
|
ref = nil
|
|
}
|
|
}()
|
|
|
|
dt, err := readFile(ctx, ref, "foo")
|
|
require.NoError(t, err)
|
|
require.Equal(t, dt, []byte("content1"))
|
|
|
|
ref.Release(context.TODO())
|
|
ref = nil
|
|
|
|
// repeat, should use the etag
|
|
h, err = hs.Resolve(ctx, id, nil, nil)
|
|
require.NoError(t, err)
|
|
|
|
k, p, _, _, err = h.CacheKey(ctx, nil, 0)
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, expectedContent1, k)
|
|
require.Equal(t, expectedPin1, p)
|
|
require.Equal(t, 2, server.Stats("/foo").AllRequests)
|
|
require.Equal(t, 1, server.Stats("/foo").CachedRequests)
|
|
|
|
ref, err = h.Snapshot(ctx, nil)
|
|
require.NoError(t, err)
|
|
defer func() {
|
|
if ref != nil {
|
|
ref.Release(context.WithoutCancel(ctx))
|
|
ref = nil
|
|
}
|
|
}()
|
|
|
|
dt, err = readFile(ctx, ref, "foo")
|
|
require.NoError(t, err)
|
|
require.Equal(t, dt, []byte("content1"))
|
|
|
|
ref.Release(context.TODO())
|
|
ref = nil
|
|
|
|
resp2 := &httpserver.Response{
|
|
Etag: identity.NewID(),
|
|
Content: []byte("content2"),
|
|
}
|
|
|
|
expectedPin2 := digest.FromBytes(resp2.Content).String()
|
|
plaintext2 := `{"Filename":"foo","Perm":0,"UID":0,"GID":0,"Checksum":"` + expectedPin2 + `"}`
|
|
expectedContent2 := digest.FromBytes([]byte(plaintext2)).String()
|
|
|
|
// update etag, downloads again
|
|
server.SetRoute("/foo", resp2)
|
|
|
|
h, err = hs.Resolve(ctx, id, nil, nil)
|
|
require.NoError(t, err)
|
|
|
|
k, p, _, _, err = h.CacheKey(ctx, nil, 0)
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, expectedContent2, k)
|
|
require.Equal(t, expectedPin2, p)
|
|
require.Equal(t, 4, server.Stats("/foo").AllRequests)
|
|
require.Equal(t, 1, server.Stats("/foo").CachedRequests)
|
|
|
|
ref, err = h.Snapshot(ctx, nil)
|
|
require.NoError(t, err)
|
|
defer func() {
|
|
if ref != nil {
|
|
ref.Release(context.WithoutCancel(ctx))
|
|
ref = nil
|
|
}
|
|
}()
|
|
|
|
dt, err = readFile(ctx, ref, "foo")
|
|
require.NoError(t, err)
|
|
require.Equal(t, dt, []byte("content2"))
|
|
|
|
ref.Release(context.TODO())
|
|
ref = nil
|
|
}
|
|
|
|
func TestHTTPDefaultName(t *testing.T) {
|
|
t.Parallel()
|
|
ctx := context.TODO()
|
|
|
|
hs, err := newHTTPSource(t)
|
|
require.NoError(t, err)
|
|
|
|
resp := &httpserver.Response{
|
|
Etag: identity.NewID(),
|
|
Content: []byte("content1"),
|
|
}
|
|
server := httpserver.NewTestServer(map[string]*httpserver.Response{
|
|
"/": resp,
|
|
})
|
|
defer server.Close()
|
|
|
|
id := &HTTPIdentifier{URL: server.URL}
|
|
|
|
h, err := hs.Resolve(ctx, id, nil, nil)
|
|
require.NoError(t, err)
|
|
|
|
k, p, _, _, err := h.CacheKey(ctx, nil, 0)
|
|
require.NoError(t, err)
|
|
|
|
expectedPin := digest.FromBytes(resp.Content).String()
|
|
plaintext := `{"Filename":"download","Perm":0,"UID":0,"GID":0,"Checksum":"` + expectedPin + `"}`
|
|
expectedContent := digest.FromBytes([]byte(plaintext)).String()
|
|
|
|
require.Equal(t, expectedContent, k)
|
|
require.Equal(t, expectedPin, p)
|
|
require.Equal(t, 1, server.Stats("/").AllRequests)
|
|
require.Equal(t, 0, server.Stats("/").CachedRequests)
|
|
|
|
ref, err := h.Snapshot(ctx, nil)
|
|
require.NoError(t, err)
|
|
defer func() {
|
|
if ref != nil {
|
|
ref.Release(context.WithoutCancel(ctx))
|
|
ref = nil
|
|
}
|
|
}()
|
|
|
|
dt, err := readFile(ctx, ref, "download")
|
|
require.NoError(t, err)
|
|
require.Equal(t, dt, []byte("content1"))
|
|
|
|
ref.Release(context.TODO())
|
|
ref = nil
|
|
}
|
|
|
|
func TestHTTPInvalidURL(t *testing.T) {
|
|
t.Parallel()
|
|
ctx := context.TODO()
|
|
|
|
hs, err := newHTTPSource(t)
|
|
require.NoError(t, err)
|
|
|
|
server := httpserver.NewTestServer(map[string]*httpserver.Response{})
|
|
defer server.Close()
|
|
|
|
id := &HTTPIdentifier{URL: server.URL + "/foo"}
|
|
|
|
h, err := hs.Resolve(ctx, id, nil, nil)
|
|
require.NoError(t, err)
|
|
|
|
_, _, _, _, err = h.CacheKey(ctx, nil, 0)
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "invalid response")
|
|
}
|
|
|
|
func TestHTTPChecksum(t *testing.T) {
|
|
t.Parallel()
|
|
ctx := context.TODO()
|
|
|
|
hs, err := newHTTPSource(t)
|
|
require.NoError(t, err)
|
|
|
|
resp := &httpserver.Response{
|
|
Etag: identity.NewID(),
|
|
Content: []byte("content-correct"),
|
|
}
|
|
server := httpserver.NewTestServer(map[string]*httpserver.Response{
|
|
"/foo": resp,
|
|
})
|
|
defer server.Close()
|
|
|
|
expectedPinDifferent := digest.FromBytes([]byte("content-different"))
|
|
id := &HTTPIdentifier{URL: server.URL + "/foo", Checksum: expectedPinDifferent}
|
|
|
|
h, err := hs.Resolve(ctx, id, nil, nil)
|
|
require.NoError(t, err)
|
|
|
|
k, p, _, _, err := h.CacheKey(ctx, nil, 0)
|
|
require.NoError(t, err)
|
|
|
|
plaintextDifferent := `{"Filename":"foo","Perm":0,"UID":0,"GID":0,"Checksum":"` + expectedPinDifferent + `"}`
|
|
expectedContentDifferent := digest.FromBytes([]byte(plaintextDifferent)).String()
|
|
|
|
expectedPinCorrect := digest.FromBytes(resp.Content).String()
|
|
plaintextCorrect := `{"Filename":"foo","Perm":0,"UID":0,"GID":0,"Checksum":"` + expectedPinCorrect + `"}`
|
|
expectedContentCorrect := digest.FromBytes([]byte(plaintextCorrect)).String()
|
|
|
|
require.Equal(t, expectedContentDifferent, k)
|
|
require.Equal(t, expectedPinDifferent.String(), p)
|
|
require.Equal(t, 0, server.Stats("/foo").AllRequests)
|
|
require.Equal(t, 0, server.Stats("/foo").CachedRequests)
|
|
|
|
_, err = h.Snapshot(ctx, nil)
|
|
require.Error(t, err)
|
|
|
|
require.Equal(t, expectedContentDifferent, k)
|
|
require.Equal(t, expectedPinDifferent.String(), p)
|
|
require.Equal(t, 1, server.Stats("/foo").AllRequests)
|
|
require.Equal(t, 0, server.Stats("/foo").CachedRequests)
|
|
|
|
id = &HTTPIdentifier{URL: server.URL + "/foo", Checksum: digest.FromBytes([]byte("content-correct"))}
|
|
|
|
h, err = hs.Resolve(ctx, id, nil, nil)
|
|
require.NoError(t, err)
|
|
|
|
k, p, _, _, err = h.CacheKey(ctx, nil, 0)
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, expectedContentCorrect, k)
|
|
require.Equal(t, expectedPinCorrect, p)
|
|
require.Equal(t, 1, server.Stats("/foo").AllRequests)
|
|
require.Equal(t, 0, server.Stats("/foo").CachedRequests)
|
|
|
|
ref, err := h.Snapshot(ctx, nil)
|
|
require.NoError(t, err)
|
|
defer func() {
|
|
if ref != nil {
|
|
ref.Release(context.WithoutCancel(ctx))
|
|
ref = nil
|
|
}
|
|
}()
|
|
|
|
dt, err := readFile(ctx, ref, "foo")
|
|
require.NoError(t, err)
|
|
require.Equal(t, dt, []byte("content-correct"))
|
|
|
|
require.Equal(t, expectedContentCorrect, k)
|
|
require.Equal(t, expectedPinCorrect, p)
|
|
require.Equal(t, 2, server.Stats("/foo").AllRequests)
|
|
require.Equal(t, 0, server.Stats("/foo").CachedRequests)
|
|
|
|
ref.Release(context.TODO())
|
|
ref = nil
|
|
}
|
|
|
|
func TestHTTPSignatureVerification(t *testing.T) {
|
|
t.Parallel()
|
|
ctx := context.TODO()
|
|
|
|
fixturesPath, ok := os.LookupEnv(signFixturesPathEnv)
|
|
if !ok {
|
|
t.Skip("missing BUILDKIT_TEST_SIGN_FIXTURES")
|
|
}
|
|
|
|
payload := readSignFixture(t, fixturesPath, "user1.http.artifact")
|
|
signature := readSignFixture(t, fixturesPath, "user1.http.artifact.asc")
|
|
pubKeyUser1 := readSignFixture(t, fixturesPath, "user1.gpg.pub")
|
|
pubKeyUser2 := readSignFixture(t, fixturesPath, "user2.gpg.pub")
|
|
|
|
hs, err := newHTTPSource(t)
|
|
require.NoError(t, err)
|
|
|
|
server := httpserver.NewTestServer(map[string]*httpserver.Response{
|
|
"/artifact": {
|
|
Etag: identity.NewID(),
|
|
Content: payload,
|
|
},
|
|
})
|
|
defer server.Close()
|
|
|
|
t.Run("valid-signature", func(t *testing.T) {
|
|
id := &HTTPIdentifier{
|
|
URL: server.URL + "/artifact",
|
|
VerifySignature: &HTTPSignatureVerifyOptions{
|
|
PubKey: pubKeyUser1,
|
|
Signature: signature,
|
|
},
|
|
}
|
|
h, err := hs.Resolve(ctx, id, nil, nil)
|
|
require.NoError(t, err)
|
|
_, _, _, _, err = h.CacheKey(ctx, nil, 0)
|
|
require.NoError(t, err)
|
|
})
|
|
|
|
t.Run("wrong-pubkey", func(t *testing.T) {
|
|
id := &HTTPIdentifier{
|
|
URL: server.URL + "/artifact",
|
|
VerifySignature: &HTTPSignatureVerifyOptions{
|
|
PubKey: pubKeyUser2,
|
|
Signature: signature,
|
|
},
|
|
}
|
|
h, err := hs.Resolve(ctx, id, nil, nil)
|
|
require.NoError(t, err)
|
|
_, _, _, _, err = h.CacheKey(ctx, nil, 0)
|
|
require.Error(t, err)
|
|
require.ErrorContains(t, err, "failed to verify pgp signature")
|
|
})
|
|
|
|
t.Run("multiblock-pubkey", func(t *testing.T) {
|
|
merged := append(append([]byte{}, pubKeyUser2...), '\n')
|
|
merged = append(merged, pubKeyUser1...)
|
|
id := &HTTPIdentifier{
|
|
URL: server.URL + "/artifact",
|
|
VerifySignature: &HTTPSignatureVerifyOptions{
|
|
PubKey: merged,
|
|
Signature: signature,
|
|
},
|
|
}
|
|
h, err := hs.Resolve(ctx, id, nil, nil)
|
|
require.NoError(t, err)
|
|
_, _, _, _, err = h.CacheKey(ctx, nil, 0)
|
|
require.NoError(t, err)
|
|
})
|
|
|
|
t.Run("missing-signature", func(t *testing.T) {
|
|
id := &HTTPIdentifier{
|
|
URL: server.URL + "/artifact",
|
|
VerifySignature: &HTTPSignatureVerifyOptions{
|
|
PubKey: pubKeyUser1,
|
|
},
|
|
}
|
|
h, err := hs.Resolve(ctx, id, nil, nil)
|
|
require.NoError(t, err)
|
|
_, _, _, _, err = h.CacheKey(ctx, nil, 0)
|
|
require.Error(t, err)
|
|
require.ErrorContains(t, err, "requires both pubkey and signature")
|
|
})
|
|
}
|
|
|
|
func TestPruneAfterCacheKey(t *testing.T) {
|
|
t.Parallel()
|
|
ctx := context.TODO()
|
|
|
|
cm, err := newCacheManager(t)
|
|
require.NoError(t, err)
|
|
|
|
hs, err := NewSource(Opt{
|
|
CacheAccessor: cm,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
resp := &httpserver.Response{
|
|
Etag: identity.NewID(),
|
|
Content: []byte("content-correct"),
|
|
}
|
|
server := httpserver.NewTestServer(map[string]*httpserver.Response{
|
|
"/foo": resp,
|
|
})
|
|
defer server.Close()
|
|
|
|
id := &HTTPIdentifier{URL: server.URL + "/foo"}
|
|
|
|
h, err := hs.Resolve(ctx, id, nil, nil)
|
|
require.NoError(t, err)
|
|
|
|
jc := &simpleJobContext{}
|
|
|
|
k, p, _, _, err := h.CacheKey(ctx, jc, 0)
|
|
require.NoError(t, err)
|
|
|
|
expectedPin := digest.FromBytes(resp.Content).String()
|
|
plaintextCacheKey := `{"Filename":"foo","Perm":0,"UID":0,"GID":0,"Checksum":"` + expectedPin + `"}`
|
|
expectedCacheKey := digest.FromBytes([]byte(plaintextCacheKey)).String()
|
|
|
|
require.Equal(t, expectedCacheKey, k)
|
|
require.Equal(t, expectedPin, p)
|
|
require.Equal(t, 1, server.Stats("/foo").AllRequests)
|
|
require.Equal(t, 0, server.Stats("/foo").CachedRequests)
|
|
|
|
err = cm.Prune(ctx, nil, client.PruneInfo{
|
|
All: true,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
du, err := cm.DiskUsage(ctx, client.DiskUsageInfo{})
|
|
require.NoError(t, err)
|
|
require.Len(t, du, 1)
|
|
for _, u := range du {
|
|
require.Equal(t, "http url "+id.URL, u.Description)
|
|
}
|
|
|
|
resp.Etag = identity.NewID()
|
|
resp.Content = []byte("content-updated")
|
|
|
|
ref, err := h.Snapshot(ctx, jc)
|
|
require.NoError(t, err)
|
|
ref.Release(context.TODO())
|
|
|
|
dt, err := readFile(ctx, ref, "foo")
|
|
require.NoError(t, err)
|
|
require.Equal(t, dt, []byte("content-correct"))
|
|
|
|
require.Equal(t, 1, server.Stats("/foo").AllRequests)
|
|
require.Equal(t, 0, server.Stats("/foo").CachedRequests)
|
|
|
|
du, err = cm.DiskUsage(ctx, client.DiskUsageInfo{})
|
|
require.NoError(t, err)
|
|
require.Len(t, du, 1)
|
|
|
|
err = cm.Prune(ctx, nil, client.PruneInfo{
|
|
All: true,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
du, err = cm.DiskUsage(ctx, client.DiskUsageInfo{})
|
|
require.NoError(t, err)
|
|
require.Len(t, du, 1)
|
|
|
|
err = jc.Release()
|
|
require.NoError(t, err)
|
|
|
|
err = cm.Prune(ctx, nil, client.PruneInfo{
|
|
All: true,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
du, err = cm.DiskUsage(ctx, client.DiskUsageInfo{})
|
|
require.NoError(t, err)
|
|
for _, u := range du {
|
|
t.Logf("du: %+v", *u)
|
|
}
|
|
require.Len(t, du, 0)
|
|
}
|
|
|
|
func readFile(ctx context.Context, ref cache.ImmutableRef, fp string) ([]byte, error) {
|
|
mount, err := ref.Mount(ctx, true, nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
lm := snapshot.LocalMounter(mount)
|
|
dir, err := lm.Mount()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
defer lm.Unmount()
|
|
|
|
dt, err := os.ReadFile(filepath.Join(dir, fp))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return dt, nil
|
|
}
|
|
|
|
func newHTTPSource(t *testing.T) (source.Source, error) {
|
|
cm, err := newCacheManager(t)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return NewSource(Opt{
|
|
CacheAccessor: cm,
|
|
})
|
|
}
|
|
|
|
func newCacheManager(t *testing.T) (cache.Manager, error) {
|
|
tmpdir := t.TempDir()
|
|
|
|
snapshotter, err := native.NewSnapshotter(filepath.Join(tmpdir, "snapshots"))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
t.Cleanup(func() {
|
|
require.NoError(t, snapshotter.Close())
|
|
})
|
|
|
|
store, err := local.NewStore(tmpdir)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
db, err := bolt.Open(filepath.Join(tmpdir, "containerdmeta.db"), 0644, nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
t.Cleanup(func() {
|
|
require.NoError(t, db.Close())
|
|
})
|
|
|
|
mdb := ctdmetadata.NewDB(db, store, map[string]snapshots.Snapshotter{
|
|
"native": snapshotter,
|
|
})
|
|
|
|
md, err := metadata.NewStore(filepath.Join(tmpdir, "metadata.db"))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
t.Cleanup(func() {
|
|
require.NoError(t, md.Close())
|
|
})
|
|
|
|
lm := leaseutil.WithNamespace(ctdmetadata.NewLeaseManager(mdb), "buildkit")
|
|
c := mdb.ContentStore()
|
|
applier := winlayers.NewFileSystemApplierWithWindows(c, apply.NewFileSystemApplier(c))
|
|
differ := winlayers.NewWalkingDiffWithWindows(c, walking.NewWalkingDiff(c))
|
|
|
|
cm, err := cache.NewManager(cache.ManagerOpt{
|
|
Snapshotter: snapshot.FromContainerdSnapshotter("native", containerdsnapshot.NSSnapshotter("buildkit", mdb.Snapshotter("native")), nil),
|
|
MetadataStore: md,
|
|
LeaseManager: lm,
|
|
ContentStore: c,
|
|
Applier: applier,
|
|
Differ: differ,
|
|
GarbageCollect: mdb.GarbageCollect,
|
|
Root: tmpdir,
|
|
MountPoolRoot: filepath.Join(tmpdir, "cachemounts"),
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
t.Cleanup(func() {
|
|
require.NoError(t, cm.Close())
|
|
})
|
|
|
|
return cm, nil
|
|
}
|
|
|
|
type simpleJobContext struct {
|
|
releasers []func() error
|
|
}
|
|
|
|
func (s *simpleJobContext) Session() session.Group {
|
|
return nil
|
|
}
|
|
func (s *simpleJobContext) Cleanup(f func() error) error {
|
|
s.releasers = append(s.releasers, f)
|
|
return nil
|
|
}
|
|
|
|
func (s *simpleJobContext) Release() error {
|
|
var firstErr error
|
|
for _, r := range s.releasers {
|
|
if err := r(); err != nil && firstErr == nil {
|
|
firstErr = err
|
|
}
|
|
}
|
|
s.releasers = nil
|
|
return firstErr
|
|
}
|
|
|
|
func (s *simpleJobContext) ResolverCache() solver.ResolverCache {
|
|
return nil
|
|
}
|
|
|
|
func (s *simpleJobContext) CompatibilityVersion() (int, error) {
|
|
return 0, nil
|
|
}
|
|
|
|
func readSignFixture(t *testing.T, fixturesPath, name string) []byte {
|
|
t.Helper()
|
|
p := filepath.Join(fixturesPath, name)
|
|
dt, err := os.ReadFile(p)
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
t.Skipf("missing signing fixture at %s", p)
|
|
}
|
|
require.NoError(t, err)
|
|
}
|
|
return dt
|
|
}
|