From 5162cfa404aedd94f4765303b53276706a639ffc Mon Sep 17 00:00:00 2001 From: mrjoelkamp Date: Tue, 13 Aug 2024 10:03:33 -0500 Subject: [PATCH] refactor: ensure tests are in correct pkg --- pkg/attest/sign_test.go | 151 ------------------ pkg/attest/verify.go | 11 -- pkg/attestation/attestation.go | 11 ++ .../example_attestation_manifest_test.go | 3 +- pkg/attestation/sign_test.go | 150 +++++++++++++++++ pkg/oci/output_test.go | 3 +- pkg/tuf/registry_test.go | 13 +- 7 files changed, 170 insertions(+), 172 deletions(-) diff --git a/pkg/attest/sign_test.go b/pkg/attest/sign_test.go index ac3f9df..3d6a602 100644 --- a/pkg/attest/sign_test.go +++ b/pkg/attest/sign_test.go @@ -1,10 +1,6 @@ package attest import ( - "encoding/json" - "fmt" - "net/http/httptest" - "net/url" "path/filepath" "testing" @@ -12,10 +8,6 @@ import ( "github.com/docker/attest/pkg/attestation" "github.com/docker/attest/pkg/oci" "github.com/docker/attest/pkg/policy" - "github.com/google/go-containerregistry/pkg/registry" - v1 "github.com/google/go-containerregistry/pkg/v1" - "github.com/google/go-containerregistry/pkg/v1/static" - "github.com/google/go-containerregistry/pkg/v1/types" intoto "github.com/in-toto/in-toto-golang/in_toto" v02 "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.2" "github.com/stretchr/testify/assert" @@ -88,146 +80,3 @@ func TestSignVerifyOCILayout(t *testing.T) { }) } } - -func TestAddSignedLayerAnnotations(t *testing.T) { - ctx, signer := test.Setup(t) - testCases := []struct { - name string - replace bool - }{ - {"replaced", true}, - {"not replaced", false}, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - data := []byte("signed") - testLayer := static.NewLayer(data, types.MediaType(intoto.PayloadType)) - mediaType := types.OCIManifestSchema1 - opts := &attestation.SigningOptions{} - originalLayer := &attestation.Layer{ - Layer: testLayer, - Statement: &intoto.Statement{ - StatementHeader: intoto.StatementHeader{ - PredicateType: attestation.VSAPredicateType, - }, - }, - Annotations: map[string]string{"test": "test"}, - } - - manifest := &attestation.Manifest{ - OriginalDescriptor: &v1.Descriptor{ - MediaType: mediaType, - }, - OriginalLayers: []*attestation.Layer{ - originalLayer, - }, - SubjectDescriptor: &v1.Descriptor{}, - } - err := manifest.Add(ctx, signer, originalLayer.Statement, opts) - require.NoError(t, err) - - newImg, err := manifest.BuildImage(attestation.WithReplacedLayers(tc.replace)) - require.NoError(t, err) - mf, _ := newImg.RawManifest() - type Annotations struct { - Annotations map[string]string `json:"annotations"` - } - type Layers struct { - Layers []Annotations `json:"layers"` - } - l := &Layers{} - err = json.Unmarshal(mf, l) - require.NoError(t, err) - _, ok := l.Layers[0].Annotations["test"] - assert.Truef(t, ok, "missing annotations") - }) - } -} - -func TestSimpleStatementSigning(t *testing.T) { - ctx, signer := test.Setup(t) - empty := types.MediaType("application/vnd.oci.empty.v1+json") - testCases := []struct { - name string - replace bool - }{ - {"replaced", true}, - {"not replaced", false}, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - opts := &attestation.SigningOptions{} - statement := &intoto.Statement{ - StatementHeader: intoto.StatementHeader{ - PredicateType: attestation.VSAPredicateType, - }, - } - statement2 := &intoto.Statement{ - StatementHeader: intoto.StatementHeader{ - PredicateType: attestation.VSAPredicateType, - }, - } - digest, err := v1.NewHash("sha256:da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620") - require.NoError(t, err) - subject := &v1.Descriptor{ - MediaType: "application/vnd.oci.image.manifest.v1+json", - Digest: digest, - } - manifest, err := NewAttestationManifest(subject) - require.NoError(t, err) - err = manifest.Add(ctx, signer, statement, opts) - require.NoError(t, err) - - err = manifest.Add(ctx, signer, statement2, opts) - require.NoError(t, err) - - // fake that the manfifest was loaded from a real image - manifest.OriginalLayers = manifest.SignedLayers - envelopes, err := attestation.ExtractEnvelopes(manifest, attestation.VSAPredicateType) - require.NoError(t, err) - assert.Len(t, envelopes, 2) - - newImg, err := manifest.BuildImage(attestation.WithReplacedLayers(tc.replace)) - require.NoError(t, err) - layers, err := newImg.Layers() - require.NoError(t, err) - if tc.replace { - assert.Len(t, layers, 2) - } else { - assert.Len(t, layers, 4) - } - - newImgs, err := manifest.BuildReferringArtifacts() - require.NoError(t, err) - assert.Len(t, newImgs, 2) - for _, img := range newImgs { - mf, err := img.Manifest() - require.NoError(t, err) - assert.Contains(t, mf.ArtifactType, "application/vnd.in-toto") - assert.Contains(t, mf.ArtifactType, "+dsse") - assert.Equal(t, subject.MediaType, mf.MediaType) - assert.Equal(t, empty, mf.Config.MediaType) - assert.Equal(t, int64(2), mf.Config.Size) - assert.Equal(t, "{}", string(mf.Config.Data)) - layers, err := img.Layers() - require.NoError(t, err) - assert.Len(t, layers, 1) - } - server := httptest.NewServer(registry.New(registry.WithReferrersSupport(true))) - defer server.Close() - - u, err := url.Parse(server.URL) - require.NoError(t, err) - - indexName := fmt.Sprintf("%s/repo:root", u.Host) - output, err := oci.ParseImageSpecs(indexName) - require.NoError(t, err) - artifacts, err := manifest.BuildReferringArtifacts() - require.NoError(t, err) - err = oci.SaveImagesNoTag(artifacts, output) - require.NoError(t, err) - }) - } -} diff --git a/pkg/attest/verify.go b/pkg/attest/verify.go index 963570c..c1d6540 100644 --- a/pkg/attest/verify.go +++ b/pkg/attest/verify.go @@ -11,7 +11,6 @@ import ( "github.com/docker/attest/pkg/config" "github.com/docker/attest/pkg/oci" "github.com/docker/attest/pkg/policy" - v1 "github.com/google/go-containerregistry/pkg/v1" intoto "github.com/in-toto/in-toto-golang/in_toto" ) @@ -164,13 +163,3 @@ func VerifyAttestations(ctx context.Context, resolver attestation.Resolver, pctx verificationResult.SubjectDescriptor = desc return verificationResult, nil } - -func NewAttestationManifest(subject *v1.Descriptor) (*attestation.Manifest, error) { - return &attestation.Manifest{ - OriginalDescriptor: &v1.Descriptor{ - MediaType: "application/vnd.oci.image.manifest.v1+json", - }, - OriginalLayers: []*attestation.Layer{}, - SubjectDescriptor: subject, - }, nil -} diff --git a/pkg/attestation/attestation.go b/pkg/attestation/attestation.go index 4a2dc3d..a3a1f0e 100644 --- a/pkg/attestation/attestation.go +++ b/pkg/attestation/attestation.go @@ -21,6 +21,17 @@ import ( "github.com/secure-systems-lab/go-securesystemslib/dsse" ) +// NewManifest creates a new attestation manifest from a descriptor. +func NewManifest(subject *v1.Descriptor) (*Manifest, error) { + return &Manifest{ + OriginalDescriptor: &v1.Descriptor{ + MediaType: "application/vnd.oci.image.manifest.v1+json", + }, + OriginalLayers: []*Layer{}, + SubjectDescriptor: subject, + }, nil +} + // ManifestsFromIndex extracts all attestation manifests from an index. func ManifestsFromIndex(index v1.ImageIndex) ([]*Manifest, error) { idx, err := index.IndexManifest() diff --git a/pkg/attestation/example_attestation_manifest_test.go b/pkg/attestation/example_attestation_manifest_test.go index 4b21229..79dffc3 100644 --- a/pkg/attestation/example_attestation_manifest_test.go +++ b/pkg/attestation/example_attestation_manifest_test.go @@ -4,7 +4,6 @@ import ( "context" "time" - "github.com/docker/attest/pkg/attest" "github.com/docker/attest/pkg/attestation" "github.com/docker/attest/pkg/oci" "github.com/docker/attest/pkg/signerverifier" @@ -62,7 +61,7 @@ func ExampleManifest() { } // create a new manifest to hold the attestation - manifest, err := attest.NewAttestationManifest(desc) + manifest, err := attestation.NewManifest(desc) if err != nil { panic(err) } diff --git a/pkg/attestation/sign_test.go b/pkg/attestation/sign_test.go index d586c3e..2c18184 100644 --- a/pkg/attestation/sign_test.go +++ b/pkg/attestation/sign_test.go @@ -6,12 +6,19 @@ import ( "crypto/rand" "encoding/json" "fmt" + "net/http/httptest" + "net/url" "testing" "time" "github.com/docker/attest/internal/test" "github.com/docker/attest/pkg/attestation" + "github.com/docker/attest/pkg/oci" "github.com/docker/attest/pkg/signerverifier" + "github.com/google/go-containerregistry/pkg/registry" + v1 "github.com/google/go-containerregistry/pkg/v1" + "github.com/google/go-containerregistry/pkg/v1/static" + "github.com/google/go-containerregistry/pkg/v1/types" intoto "github.com/in-toto/in-toto-golang/in_toto" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -149,3 +156,146 @@ func TestSignVerifyAttestation(t *testing.T) { }) } } + +func TestAddSignedLayerAnnotations(t *testing.T) { + ctx, signer := test.Setup(t) + testCases := []struct { + name string + replace bool + }{ + {"replaced", true}, + {"not replaced", false}, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + data := []byte("signed") + testLayer := static.NewLayer(data, types.MediaType(intoto.PayloadType)) + mediaType := types.OCIManifestSchema1 + opts := &attestation.SigningOptions{} + originalLayer := &attestation.Layer{ + Layer: testLayer, + Statement: &intoto.Statement{ + StatementHeader: intoto.StatementHeader{ + PredicateType: attestation.VSAPredicateType, + }, + }, + Annotations: map[string]string{"test": "test"}, + } + + manifest := &attestation.Manifest{ + OriginalDescriptor: &v1.Descriptor{ + MediaType: mediaType, + }, + OriginalLayers: []*attestation.Layer{ + originalLayer, + }, + SubjectDescriptor: &v1.Descriptor{}, + } + err := manifest.Add(ctx, signer, originalLayer.Statement, opts) + require.NoError(t, err) + + newImg, err := manifest.BuildImage(attestation.WithReplacedLayers(tc.replace)) + require.NoError(t, err) + mf, _ := newImg.RawManifest() + type Annotations struct { + Annotations map[string]string `json:"annotations"` + } + type Layers struct { + Layers []Annotations `json:"layers"` + } + l := &Layers{} + err = json.Unmarshal(mf, l) + require.NoError(t, err) + _, ok := l.Layers[0].Annotations["test"] + assert.Truef(t, ok, "missing annotations") + }) + } +} + +func TestSimpleStatementSigning(t *testing.T) { + ctx, signer := test.Setup(t) + empty := types.MediaType("application/vnd.oci.empty.v1+json") + testCases := []struct { + name string + replace bool + }{ + {"replaced", true}, + {"not replaced", false}, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + opts := &attestation.SigningOptions{} + statement := &intoto.Statement{ + StatementHeader: intoto.StatementHeader{ + PredicateType: attestation.VSAPredicateType, + }, + } + statement2 := &intoto.Statement{ + StatementHeader: intoto.StatementHeader{ + PredicateType: attestation.VSAPredicateType, + }, + } + digest, err := v1.NewHash("sha256:da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620") + require.NoError(t, err) + subject := &v1.Descriptor{ + MediaType: "application/vnd.oci.image.manifest.v1+json", + Digest: digest, + } + manifest, err := attestation.NewManifest(subject) + require.NoError(t, err) + err = manifest.Add(ctx, signer, statement, opts) + require.NoError(t, err) + + err = manifest.Add(ctx, signer, statement2, opts) + require.NoError(t, err) + + // fake that the manfifest was loaded from a real image + manifest.OriginalLayers = manifest.SignedLayers + envelopes, err := attestation.ExtractEnvelopes(manifest, attestation.VSAPredicateType) + require.NoError(t, err) + assert.Len(t, envelopes, 2) + + newImg, err := manifest.BuildImage(attestation.WithReplacedLayers(tc.replace)) + require.NoError(t, err) + layers, err := newImg.Layers() + require.NoError(t, err) + if tc.replace { + assert.Len(t, layers, 2) + } else { + assert.Len(t, layers, 4) + } + + newImgs, err := manifest.BuildReferringArtifacts() + require.NoError(t, err) + assert.Len(t, newImgs, 2) + for _, img := range newImgs { + mf, err := img.Manifest() + require.NoError(t, err) + assert.Contains(t, mf.ArtifactType, "application/vnd.in-toto") + assert.Contains(t, mf.ArtifactType, "+dsse") + assert.Equal(t, subject.MediaType, mf.MediaType) + assert.Equal(t, empty, mf.Config.MediaType) + assert.Equal(t, int64(2), mf.Config.Size) + assert.Equal(t, "{}", string(mf.Config.Data)) + layers, err := img.Layers() + require.NoError(t, err) + assert.Len(t, layers, 1) + } + server := httptest.NewServer(registry.New(registry.WithReferrersSupport(true))) + defer server.Close() + + u, err := url.Parse(server.URL) + require.NoError(t, err) + + indexName := fmt.Sprintf("%s/repo:root", u.Host) + output, err := oci.ParseImageSpecs(indexName) + require.NoError(t, err) + artifacts, err := manifest.BuildReferringArtifacts() + require.NoError(t, err) + err = oci.SaveImagesNoTag(artifacts, output) + require.NoError(t, err) + }) + } +} diff --git a/pkg/oci/output_test.go b/pkg/oci/output_test.go index 53784c6..27fc546 100644 --- a/pkg/oci/output_test.go +++ b/pkg/oci/output_test.go @@ -7,7 +7,6 @@ import ( "testing" "github.com/docker/attest/internal/test" - "github.com/docker/attest/pkg/attest" "github.com/docker/attest/pkg/attestation" "github.com/docker/attest/pkg/oci" "github.com/google/go-containerregistry/pkg/registry" @@ -78,7 +77,7 @@ func TestSavingReferrers(t *testing.T) { MediaType: "application/vnd.oci.image.manifest.v1+json", Digest: digest, } - manifest, err := attest.NewAttestationManifest(subject) + manifest, err := attestation.NewManifest(subject) require.NoError(t, err) err = manifest.Add(ctx, signer, statement, opts) require.NoError(t, err) diff --git a/pkg/tuf/registry_test.go b/pkg/tuf/registry_test.go index 16418c6..45ead27 100644 --- a/pkg/tuf/registry_test.go +++ b/pkg/tuf/registry_test.go @@ -32,6 +32,9 @@ const ( tufTargetMediaType = "application/vnd.tuf.target" testRole = "test-role" tufMetadataRepo = "tuf-metadata" + targetsPath = "/tuf-targets" + metadataPath = "/tuf-metadata" + targetsRepo = "test" + targetsPath ) func TestRegistryFetcher(t *testing.T) { @@ -44,9 +47,9 @@ func TestRegistryFetcher(t *testing.T) { }() LoadRegistryTestData(t, regAddr, OCITUFTestDataPath) - metadataRepo := regAddr.Host + "/tuf-metadata" + metadataRepo := regAddr.Host + metadataPath metadataImgTag := LatestTag - targetsRepo := regAddr.Host + "/tuf-targets" + targetsRepo := regAddr.Host + targetsPath targetFile := "test.txt" delegatedRole := testRole dir := CreateTempDir(t, "", "tuf_temp") @@ -122,7 +125,7 @@ func TestFindFileInManifest(t *testing.T) { // make test image manifest file := "test.json" data := []byte("test") - hash := v1.Hash{Algorithm: "sha256", Hex: util.SHA256Hex(data)} + hash := v1.Hash{Hex: util.SHA256Hex(data)} img := empty.Image img = mutate.MediaType(img, types.OCIManifestSchema1) img = mutate.ConfigMediaType(img, types.OCIConfigJSON) @@ -150,7 +153,6 @@ func TestFindFileInManifest(t *testing.T) { indexManifest, err := idx.RawManifest() assert.NoError(t, err) // cache image layer - targetsRepo := "test/tuf-targets" d := &RegistryFetcher{ cache: NewImageCache(), targetsRepo: targetsRepo, @@ -183,9 +185,8 @@ func TestFindFileInManifest(t *testing.T) { } func TestParseImgRef(t *testing.T) { - metadataRepo := "test/tuf-metadata" + metadataRepo := "test" + metadataPath metadataTag := LatestTag - targetsRepo := "test/tuf-targets" delegatedRole := testRole testCases := []struct { name string