diff --git a/README.md b/README.md index 792a1e8..d8d9b02 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,130 @@ # attest -Library to create, verify, and evaluate policy for attestations on container images +library to create, verify, and evaluate policy for attestations on container images + +# usage +## verifying attestations +1. create a TUF client + * using OCI registry for TUF + ```go + tufOutputPath = "/.docker/tuf" + metadataURI = "docker/tuf-metadata:latest" + targetsURI = "docker/tuf-targets" + tufClient, err := tuf.NewTufClient(embed.DefaultRoot, tufOutputPath, metadataURI, targetsURI) + ``` + * using HTTPS for TUF + ```go + tufOutputPath = "/.docker/tuf" + metadataURI = "https://docker.github.io/tuf/metadata" + targetsURI = "https://docker.github.io/tuf/targets" + tufClient, err := tuf.NewTufClient(embed.DefaultRoot, tufOutputPath, metadataURI, targetsURI) + ``` + +1. configure an attestation resolver + * using OCI registry + ```go + var resolver oci.AttestationResolver + resolver = &oci.RegistryResolver{ + Image: image, // path to image index in OCI registry containing image attestations (e.g. docker/nginx:latest) + Platform: platform, // platform of subject image (image that attestations are being verified against) + } + ``` + * using local OCI layout + ```go + var resolver oci.AttestationResolver + resolver = &oci.OCILayoutResolver{ + Path: path, // file path to OCI layout containing image attestations (e.g. /myimage) + Platform: platform, // platform of subject image (image that attestations are being verified against) + } + ``` + +1. configure policy options + ```go + opts := &policy.PolicyOptions{ + TufClient: tufClient, + LocalTargetsDir: "/.docker/policy", // location to store policy files downloaded from TUF + LocalPolicyDir: "", // overrides TUF policy for local policy files + } + ``` + +1. verify attestations + ```go + policy, err := attest.Verify(ctx, opts, resolver) + if err != nil { + return false // failed policy or attestation signature verification + } + if policy { + return true // passed policy + } + return true // no policy for image + ``` + +## signing attestations +1. generate an image with intoto Statements (optional) + ```sh + docker buildx build --sbom true --provenance true --output type=oci,tar=false,name=:,dest= + ``` + +1. confgiure a `dsse.SignerVerifier` + ```go + var signer dsse.SignerVerifier + signer, err = signerverifier.GetAWSSigner(cmd.Context(), aws_arn, aws_region) + ``` + +1. configure signing options + ```go + opts := &attest.SigningOptions{ + Replace: true, // replace unsigned intoto statements with signed intoto attestations, otherwise leave in place + } + ``` + * add [Verification Summary Attestation (VSA)](https://slsa.dev/spec/v1.0/verification_summary) for all intoto attestations (optional) + ```go + opts.VSAOptions = &attestation.VSAOptions{ + BuildLevel: "SLSA_BUILD_LEVEL_" + slsaBuildLevel, + PolicyURI: slsaPolicyUri, + VerifierID: slsaVerifierId, + } + ``` +1. load attestations + * oci registry + ```go + ref := "docker/attest:latest" + att, err := oci.AttestationIndexFromRemote(ref) + ``` + * local filepath + ```go + path := "/test-image" + att, err := oci.AttestationIndexFromPath(path) + ``` + +1. sign attestations + ```go + signedImageIndex, err := attest.Sign(ctx, att, signer, opts) + ``` + `attest.Sign()` iterates over attestation manifests in the image index and signs all intoto statements (optionally generates a VSA), returning a mutated ImageIndex with all intoto statements signed as attestations. + +1. save output (optional) + * push to oci registry + ```go + err = mirror.PushToRegistry(signedImageIndex, ref) + ``` + * save to local filesystem + ```go + idx := v1.ImageIndex(empty.Index) + idx = mutate.AppendManifests(idx, mutate.IndexAddendum{ + Add: signedImageIndex, + Descriptor: v1.Descriptor{ + Annotations: map[string]string{ + oci.OciReferenceTarget: att.Name, + }, + }, + }) + err = mirror.SaveAsOCILayout(idx, path) + ``` + +## mirroring TUF repositories +TODO: write content for this outline +### mirroring TUF metadata to OCI +#### delegated metadata +### mirroring TUF targets to OCI +#### delegated targets +### using `go-tuf` OCI registry client diff --git a/internal/test/test.go b/internal/test/test.go index 87533d7..10baf71 100644 --- a/internal/test/test.go +++ b/internal/test/test.go @@ -2,13 +2,22 @@ package test import ( "context" + "encoding/base64" + "encoding/json" + "fmt" "os" + "strings" "testing" + "github.com/docker/attest/pkg/attestation" "github.com/docker/attest/pkg/oci" "github.com/docker/attest/pkg/policy" "github.com/docker/attest/pkg/signerverifier" "github.com/docker/attest/pkg/tlog" + v1 "github.com/google/go-containerregistry/pkg/v1" + "github.com/google/go-containerregistry/pkg/v1/layout" + "github.com/google/go-containerregistry/pkg/v1/partial" + intoto "github.com/in-toto/in-toto-golang/in_toto" "github.com/secure-systems-lab/go-securesystemslib/dsse" ) @@ -77,10 +86,121 @@ func GetMockSigner(ctx context.Context) (dsse.SignerVerifier, error) { return signerverifier.GenKeyPair() } +type MockPolicyEvaluator struct { + EvaluateFunc func(ctx context.Context, resolver oci.AttestationResolver, policy []*policy.PolicyFile, input *policy.PolicyInput) error +} + +func (pe *MockPolicyEvaluator) Evaluate(ctx context.Context, resolver oci.AttestationResolver, policy []*policy.PolicyFile, input *policy.PolicyInput) error { + if pe.EvaluateFunc != nil { + return pe.EvaluateFunc(ctx, resolver, policy, input) + } + return nil +} + func GetMockPolicy() policy.PolicyEvaluator { - return &policy.MockPolicyEvaluator{ + return &MockPolicyEvaluator{ EvaluateFunc: func(ctx context.Context, resolver oci.AttestationResolver, policy []*policy.PolicyFile, input *policy.PolicyInput) error { return nil }, } } + +type AnnotatedStatement struct { + OCIDescriptor *v1.Descriptor + InTotoStatement *intoto.Statement + Annotations map[string]string +} + +func ExtractAnnotatedStatements(path string, mediaType string) ([]*AnnotatedStatement, error) { + idx, err := layout.ImageIndexFromPath(path) + if err != nil { + return nil, fmt.Errorf("failed to load image index: %w", err) + } + + idxm, err := idx.IndexManifest() + if err != nil { + return nil, fmt.Errorf("failed to get digest: %w", err) + } + idxDigest := idxm.Manifests[0].Digest + + mfs, err := idx.ImageIndex(idxDigest) + if err != nil { + return nil, fmt.Errorf("failed to extract ImageIndex for digest %s: %w", idxDigest.String(), err) + } + mfs2, err := mfs.IndexManifest() + if err != nil { + return nil, fmt.Errorf("failed to extract IndexManifest from ImageIndex: %w", err) + } + + var statements []*AnnotatedStatement + + for _, mf := range mfs2.Manifests { + if mf.Annotations["vnd.docker.reference.type"] != "attestation-manifest" { + continue + } + + attestationImage, err := mfs.Image(mf.Digest) + if err != nil { + return nil, fmt.Errorf("failed to extract attestation image with digest %s: %w", mf.Digest.String(), err) + } + layers, err := attestationImage.Layers() + if err != nil { + return nil, fmt.Errorf("failed to extract layers from attestation image: %w", err) + } + + for _, layer := range layers { + // parse layer blob as json + mt, err := layer.MediaType() + if err != nil { + return nil, fmt.Errorf("failed to get layer media type: %w", err) + } + + if string(mt) != mediaType { + continue + } + r, err := layer.Uncompressed() + if err != nil { + return nil, fmt.Errorf("failed to get layer contents: %w", err) + } + defer r.Close() + var intotoStatement = new(intoto.Statement) + var desc *v1.Descriptor + if strings.HasSuffix(string(mt), "+dsse") { + var env = new(attestation.Envelope) + err = json.NewDecoder(r).Decode(env) + if err != nil { + return nil, fmt.Errorf("failed to decode env: %w", err) + } + payload, err := base64.StdEncoding.Strict().DecodeString(env.Payload) + if err != nil { + return nil, fmt.Errorf("failed to decode payload: %w", err) + } + err = json.Unmarshal([]byte(payload), intotoStatement) + if err != nil { + return nil, fmt.Errorf("failed to decode %s statement: %w", mediaType, err) + } + } else { + desc := new(v1.Descriptor) + err = json.NewDecoder(r).Decode(desc) + if err != nil { + return nil, fmt.Errorf("failed to decode statement: %w", err) + } + } + + layerDesc, err := partial.Descriptor(layer) + if err != nil { + return nil, fmt.Errorf("failed to get descriptor for layer: %w", err) + } + annotations := make(map[string]string) + for k, v := range layerDesc.Annotations { + annotations[k] = v + } + statements = append(statements, &AnnotatedStatement{ + OCIDescriptor: desc, + InTotoStatement: intotoStatement, + Annotations: annotations, + }) + } + } + return statements, nil +} diff --git a/internal/test/test_test.go b/internal/test/test_test.go new file mode 100644 index 0000000..812c019 --- /dev/null +++ b/internal/test/test_test.go @@ -0,0 +1,23 @@ +package test + +import ( + "path/filepath" + "testing" + + intoto "github.com/in-toto/in-toto-golang/in_toto" + "github.com/stretchr/testify/assert" +) + +var ( + UnsignedTestImage = filepath.Join("..", "..", "test", "testdata", "unsigned-test-image") +) + +const ( + ExpectedStatements = 4 +) + +func TestExtractAnnotatedStatements(t *testing.T) { + statements, err := ExtractAnnotatedStatements(UnsignedTestImage, intoto.PayloadType) + assert.NoError(t, err) + assert.Equalf(t, len(statements), ExpectedStatements, "expected %d statement, got %d", ExpectedStatements, len(statements)) +} diff --git a/pkg/attest/sign.go b/pkg/attest/sign.go new file mode 100644 index 0000000..dd63183 --- /dev/null +++ b/pkg/attest/sign.go @@ -0,0 +1,139 @@ +package attest + +import ( + "context" + "encoding/json" + "fmt" + + "github.com/docker/attest/pkg/attestation" + v1 "github.com/google/go-containerregistry/pkg/v1" + "github.com/google/go-containerregistry/pkg/v1/empty" + "github.com/google/go-containerregistry/pkg/v1/match" + "github.com/google/go-containerregistry/pkg/v1/mutate" + "github.com/google/go-containerregistry/pkg/v1/partial" + "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/secure-systems-lab/go-securesystemslib/dsse" +) + +func Sign(ctx context.Context, idx v1.ImageIndex, signer dsse.SignerVerifier, opts *SigningOptions) (v1.ImageIndex, error) { + // extract attestation manifests from index + attestationManifests, err := attestation.GetAttestationManifestsFromIndex(idx) + if err != nil { + return nil, fmt.Errorf("failed to get attestation manifests: %w", err) + } + + // sign every attestation layer in each manifest + for _, manifest := range attestationManifests { + attestationLayers, err := attestation.GetAttestationsFromImage(manifest.Attestation.Image) + if err != nil { + return nil, fmt.Errorf("failed to get attestations from image: %w", err) + } + signedLayers, err := signLayers(ctx, attestationLayers, signer) + if err != nil { + return nil, fmt.Errorf("failed to sign attestations: %w", err) + } + if opts.VSAOptions != nil { + newLayer, err := generateVSA(ctx, manifest, signer, opts) + if err != nil { + return nil, fmt.Errorf("failed to generate VSA: %w", err) + } + signedLayers = append(signedLayers, *newLayer) + } + newImg, err := addSignedLayers(signedLayers, manifest, opts) + if err != nil { + return nil, fmt.Errorf("failed to add signed layers: %w", err) + } + newDesc, err := partial.Descriptor(newImg) + if err != nil { + return nil, fmt.Errorf("failed to get descriptor: %w", err) + } + cf, err := manifest.Attestation.Image.ConfigFile() + if err != nil { + return nil, fmt.Errorf("failed to get config file: %w", err) + } + newDesc.Platform = cf.Platform() + newDesc.MediaType = manifest.MediaType + newDesc.Annotations = manifest.Annotations + idx = mutate.RemoveManifests(idx, match.Digests(manifest.Digest)) + idx = mutate.AppendManifests(idx, mutate.IndexAddendum{ + Add: newImg, + Descriptor: *newDesc, + }) + } + return idx, nil +} + +// signLayers signs each intoto attestation layer with the given signer +func signLayers(ctx context.Context, layers []attestation.AttestationLayer, signer dsse.SignerVerifier) ([]mutate.Addendum, error) { + var signedLayers []mutate.Addendum + for _, layer := range layers { + // only sign intoto layers + if layer.MediaType != types.MediaType(intoto.PayloadType) { + continue + } + // mark attestation as experimental + layer.Annotations[InTotoReferenceLifecycleStage] = LifecycleStageExperimental + + // sign the statement + payload, err := json.Marshal(layer.Statement) + if err != nil { + return nil, fmt.Errorf("failed to marshal statement: %w", err) + } + env, err := attestation.SignDSSE(ctx, payload, intoto.PayloadType, signer) + if err != nil { + return nil, fmt.Errorf("failed to sign statement: %w", err) + } + mediaType, err := attestation.DSSEMediaType(layer.Statement.PredicateType) + if err != nil { + return nil, fmt.Errorf("failed to get DSSE media type: %w", err) + } + data, err := json.Marshal(env) + if err != nil { + return nil, fmt.Errorf("failed to marshal envelope: %w", err) + } + newLayer := static.NewLayer(data, types.MediaType(mediaType)) + withAnnotations := mutate.Addendum{ + Layer: newLayer, + Annotations: layer.Annotations, + } + signedLayers = append(signedLayers, withAnnotations) + } + return signedLayers, nil +} + +// addSignedLayers adds signed layers to a new or existing attestation image +func addSignedLayers(signedLayers []mutate.Addendum, manifest attestation.AttestationManifest, opts *SigningOptions) (v1.Image, error) { + var err error + if opts.Replace { + // create a new attestation image with only signed layers + newImg := empty.Image + newImg = mutate.MediaType(newImg, manifest.MediaType) + newImg = mutate.ConfigMediaType(newImg, "application/vnd.oci.image.config.v1+json") + for _, layer := range signedLayers { + newImg, err = mutate.Append(newImg, layer) + if err != nil { + return nil, fmt.Errorf("failed to append signed layer: %w", err) + } + } + // add any existing unsigned (non-intoto) layers to the new image + for _, layer := range manifest.Attestation.Layers { + if layer.MediaType != types.MediaType(intoto.PayloadType) { + newImg, err = mutate.AppendLayers(newImg, layer.Layer) + if err != nil { + return nil, fmt.Errorf("failed to append unsigned layer: %w", err) + } + } + } + return newImg, nil + } + // Add signed layers to the existing image + for _, layer := range signedLayers { + manifest.Attestation.Image, err = mutate.Append(manifest.Attestation.Image, layer) + if err != nil { + return nil, fmt.Errorf("failed to append layer: %w", err) + } + } + return manifest.Attestation.Image, nil +} diff --git a/pkg/attest/sign_test.go b/pkg/attest/sign_test.go new file mode 100644 index 0000000..f2f6787 --- /dev/null +++ b/pkg/attest/sign_test.go @@ -0,0 +1,165 @@ +package attest + +import ( + "encoding/json" + "path/filepath" + "testing" + + "github.com/docker/attest/internal/test" + "github.com/docker/attest/pkg/attestation" + "github.com/docker/attest/pkg/oci" + "github.com/docker/attest/pkg/policy" + v1 "github.com/google/go-containerregistry/pkg/v1" + "github.com/google/go-containerregistry/pkg/v1/empty" + "github.com/google/go-containerregistry/pkg/v1/layout" + "github.com/google/go-containerregistry/pkg/v1/mutate" + "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" +) + +var ( + UnsignedTestImage = filepath.Join("..", "..", "test", "testdata", "unsigned-test-image") + NoProvenanceImage = filepath.Join("..", "..", "test", "testdata", "no-provenance-image") + LocalPolicyDir = filepath.Join("..", "..", "test", "testdata", "local-policy") + TestTempDir = "attest-sign-test" +) + +func TestSignVerifyOCILayout(t *testing.T) { + ctx, signer := test.Setup(t) + + testCases := []struct { + name string + TestImage string + expectedStatements int + expectedAttestations int + replace bool + }{ + + {"signed replaced (does nothing)", UnsignedTestImage, 0, 6, true}, + {"without replace", UnsignedTestImage, 4, 6, false}, + // image without provenance doesn't fail + {"no provenance (replace)", NoProvenanceImage, 0, 4, true}, + {"no provenance (no replace)", NoProvenanceImage, 2, 4, false}, + } + policyResolver := &policy.PolicyOptions{ + LocalPolicyDir: LocalPolicyDir, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + tempDir := test.CreateTempDir(t, "", TestTempDir) + outputLayout := tempDir + opts := &SigningOptions{ + Replace: tc.replace, + VSAOptions: &attestation.VSAOptions{ + BuildLevel: "SLSA_BUILD_LEVEL_3", + PolicyURI: "https://docker.com/attest/policy", + VerifierID: "https://docker.com", + }, + } + attIdx, err := oci.AttestationIndexFromPath(tc.TestImage) + assert.NoError(t, err) + signedIndex, err := Sign(ctx, attIdx.Index, signer, opts) + assert.NoError(t, err) + + // output signed attestations + idx := v1.ImageIndex(empty.Index) + idx = mutate.AppendManifests(idx, mutate.IndexAddendum{ + Add: signedIndex, + Descriptor: v1.Descriptor{ + Annotations: map[string]string{ + oci.OciReferenceTarget: attIdx.Name, + }, + }, + }) + _, err = layout.Write(outputLayout, idx) + assert.NoError(t, err) + + resolver := &oci.OCILayoutResolver{ + Path: outputLayout, + Platform: "", + } + policy, err := Verify(ctx, policyResolver, resolver) + assert.NoError(t, err) + assert.Truef(t, policy, "Policy should have been found") + + mt, _ := attestation.DSSEMediaType(attestation.VSAPredicateType) + vsas, err := test.ExtractAnnotatedStatements(tempDir, mt) + assert.NoError(t, err) + assert.Equalf(t, len(vsas), 2, "expected %d vsa statement, got %d", 2, len(vsas)) + var allEnvelopes []*test.AnnotatedStatement + for _, predicate := range []string{intoto.PredicateSPDX, v02.PredicateSLSAProvenance, attestation.VSAPredicateType} { + mt, _ := attestation.DSSEMediaType(predicate) + statements, err := test.ExtractAnnotatedStatements(tempDir, mt) + assert.NoError(t, err) + allEnvelopes = append(allEnvelopes, statements...) + + for _, stmt := range statements { + assert.Equalf(t, predicate, stmt.Annotations[oci.InTotoPredicateType], "expected predicate-type annotation to be set to %s, got %s", predicate, stmt.Annotations[oci.InTotoPredicateType]) + assert.Equalf(t, LifecycleStageExperimental, stmt.Annotations[InTotoReferenceLifecycleStage], "expected reference lifecycle stage annotation to be set to %s, got %s", LifecycleStageExperimental, stmt.Annotations[InTotoReferenceLifecycleStage]) + } + } + assert.Equalf(t, tc.expectedAttestations, len(allEnvelopes), "expected %d attestations, got %d", tc.expectedAttestations, len(allEnvelopes)) + statements, err := test.ExtractAnnotatedStatements(tempDir, intoto.PayloadType) + assert.NoError(t, err) + assert.Equalf(t, tc.expectedStatements, len(statements), "expected %d statement, got %d", tc.expectedStatements, len(statements)) + }) + } +} + +func TestAddSignedLayerAnnotations(t *testing.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") + signedLayer := static.NewLayer(data, types.MediaType(intoto.PayloadType)) + signedLayers := []mutate.Addendum{ + { + Layer: signedLayer, + Annotations: map[string]string{"test": "test"}, + }, + } + data = []byte("test") + testLayer := static.NewLayer(data, types.MediaType(intoto.PayloadType)) + mediaType := types.OCIManifestSchema1 + opts := &SigningOptions{ + Replace: tc.replace, + } + manifest := attestation.AttestationManifest{ + MediaType: mediaType, + Attestation: attestation.AttestationImage{ + Image: empty.Image, + Layers: []attestation.AttestationLayer{ + { + Layer: testLayer, + Statement: &intoto.Statement{}, + }, + }, + }, + } + newImg, err := addSignedLayers(signedLayers, manifest, opts) + assert.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) + assert.NoError(t, err) + _, ok := l.Layers[0].Annotations["test"] + assert.Truef(t, ok, "missing annotations") + }) + } +} diff --git a/pkg/attest/types.go b/pkg/attest/types.go new file mode 100644 index 0000000..a837e8d --- /dev/null +++ b/pkg/attest/types.go @@ -0,0 +1,15 @@ +package attest + +import ( + "github.com/docker/attest/pkg/attestation" +) + +const ( + InTotoReferenceLifecycleStage = "vnd.docker.lifecycle-stage" + LifecycleStageExperimental = "experimental" +) + +type SigningOptions struct { + Replace bool + VSAOptions *attestation.VSAOptions +} diff --git a/pkg/attest/verify.go b/pkg/attest/verify.go new file mode 100644 index 0000000..52f05c6 --- /dev/null +++ b/pkg/attest/verify.go @@ -0,0 +1,55 @@ +package attest + +import ( + "context" + "fmt" + + "github.com/docker/attest/pkg/oci" + "github.com/docker/attest/pkg/policy" +) + +func VerifyAttestations(ctx context.Context, resolver oci.AttestationResolver, files []*policy.PolicyFile) error { + digest, err := resolver.ImageDigest(ctx) + if err != nil { + return fmt.Errorf("failed to get image digest: %w", err) + } + name, err := resolver.ImageName(ctx) + if err != nil { + return fmt.Errorf("failed to get image name: %w", err) + } + purl, canonical, err := oci.RefToPURL(name, resolver.ImagePlatformStr()) + if err != nil { + return fmt.Errorf("failed to convert ref to purl: %w", err) + } + input := &policy.PolicyInput{ + Digest: digest, + Purl: purl, + IsCanonical: canonical, + } + + evaluator, err := policy.GetPolicyEvaluator(ctx) + if err != nil { + return err + } + err = evaluator.Evaluate(ctx, resolver, files, input) + if err != nil { + return fmt.Errorf("policy evaluation failed: %w", err) + } + + return nil +} + +func Verify(ctx context.Context, opts *policy.PolicyOptions, resolver oci.AttestationResolver) (policyFound bool, err error) { + policyFiles, err := policy.ResolvePolicy(ctx, resolver, opts) + if err != nil { + return false, fmt.Errorf("failed to resolve policy: %w", err) + } + + // no policy for image -> success + if policyFiles == nil { + return false, nil + } + + // policy found -> verify + return true, VerifyAttestations(ctx, resolver, policyFiles) +} diff --git a/pkg/attest/verify_test.go b/pkg/attest/verify_test.go new file mode 100644 index 0000000..5751da0 --- /dev/null +++ b/pkg/attest/verify_test.go @@ -0,0 +1,61 @@ +package attest + +import ( + "context" + "encoding/json" + "fmt" + "os" + "path/filepath" + "testing" + + "github.com/docker/attest/internal/test" + "github.com/docker/attest/pkg/attestation" + "github.com/docker/attest/pkg/oci" + "github.com/docker/attest/pkg/policy" + "github.com/stretchr/testify/assert" +) + +var ( + ExampleAttestation = filepath.Join("..", "..", "test", "testdata", "example_attestation.json") +) + +func TestVerifyAttestations(t *testing.T) { + ex, err := os.ReadFile(ExampleAttestation) + assert.NoError(t, err) + + var env = new(attestation.Envelope) + err = json.Unmarshal(ex, env) + assert.NoError(t, err) + resolver := &oci.MockResolver{ + Envs: []*attestation.Envelope{env}, + } + + testCases := []struct { + name string + policyEvaluationError error + expectedError error + }{ + {"policy ok", nil, nil}, + {"policy error", fmt.Errorf("policy error"), fmt.Errorf("policy evaluation failed: policy error")}, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + + mockPE := test.MockPolicyEvaluator{ + EvaluateFunc: func(ctx context.Context, resolver oci.AttestationResolver, pfs []*policy.PolicyFile, input *policy.PolicyInput) error { + return tc.policyEvaluationError + }, + } + + ctx := policy.WithPolicyEvaluator(context.Background(), &mockPE) + err = VerifyAttestations(ctx, resolver, nil) + if tc.expectedError != nil { + assert.Error(t, err) + assert.Equal(t, tc.expectedError.Error(), err.Error()) + } else { + assert.NoError(t, err) + } + }) + } +} diff --git a/pkg/attest/vsa.go b/pkg/attest/vsa.go new file mode 100644 index 0000000..015ea0a --- /dev/null +++ b/pkg/attest/vsa.go @@ -0,0 +1,96 @@ +package attest + +import ( + "context" + "encoding/json" + "fmt" + "strings" + "time" + + "github.com/docker/attest/pkg/attestation" + "github.com/docker/attest/pkg/oci" + "github.com/google/go-containerregistry/pkg/v1/mutate" + "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/secure-systems-lab/go-securesystemslib/dsse" +) + +// generateVSA generates a VSA from the attestation manifest +// TODO: remove signing logic and move generateVSA to attestation/vsa.go +func generateVSA(ctx context.Context, manifest attestation.AttestationManifest, signer dsse.SignerVerifier, opts *SigningOptions) (*mutate.Addendum, error) { + if len(manifest.Attestation.Layers) == 0 { + return nil, fmt.Errorf("no attestations found to generate VSA from") + } + sub := manifest.Attestation.Layers[0].Statement.Subject[0] + stype := manifest.Attestation.Layers[0].Statement.Type + + uri, err := attestation.ToVSAResourceURI(sub) + if err != nil { + return nil, fmt.Errorf("failed to generate VSA resource URI: %w", err) + } + + inputs := make([]attestation.VSAInputAttestation, 0, len(manifest.Attestation.Layers)) + for _, att := range manifest.Attestation.Layers { + mt, err := att.Layer.MediaType() + if err != nil { + return nil, fmt.Errorf("failed to get layer media type: %w", err) + } + if !strings.HasSuffix(string(mt), "+dsse") { + continue + } + dgst, err := att.Layer.Digest() + if err != nil { + return nil, fmt.Errorf("failed to get layer digest: %w", err) + } + inputs = append(inputs, attestation.VSAInputAttestation{ + Digest: map[string]string{"sha256": dgst.Hex}, + MediaType: string(mt), + }) + } + vsaStatement := &intoto.Statement{ + StatementHeader: intoto.StatementHeader{ + PredicateType: attestation.VSAPredicateType, + Type: stype, + Subject: manifest.Attestation.Layers[0].Statement.Subject, + }, + Predicate: attestation.VSAPredicate{ + Verifier: attestation.VSAVerifier{ + ID: opts.VSAOptions.VerifierID, + }, + TimeVerified: time.Now().UTC().Format(time.RFC3339), + ResourceUri: uri, + Policy: attestation.VSAPolicy{URI: opts.VSAOptions.PolicyURI}, + VerificationResult: "PASSED", + VerifiedLevels: []string{opts.VSAOptions.BuildLevel}, + InputAttestations: inputs, + }, + } + payload, err := json.Marshal(vsaStatement) + if err != nil { + return nil, fmt.Errorf("failed to marshal statement: %w", err) + } + env, err := attestation.SignDSSE(ctx, payload, intoto.PayloadType, signer) + if err != nil { + return nil, fmt.Errorf("failed to sign statement: %w", err) + } + mediaType, err := attestation.DSSEMediaType(vsaStatement.PredicateType) + if err != nil { + return nil, fmt.Errorf("failed to get DSSE media type: %w", err) + } + + data, err := json.Marshal(env) + if err != nil { + return nil, fmt.Errorf("failed to marshal envelope: %w", err) + } + mt := types.MediaType(mediaType) + newLayer := static.NewLayer(data, mt) + ann := make(map[string]string) + ann[InTotoReferenceLifecycleStage] = LifecycleStageExperimental + ann[oci.InTotoPredicateType] = attestation.VSAPredicateType + withAnnotations := mutate.Addendum{ + Layer: newLayer, + Annotations: ann, + } + return &withAnnotations, nil +} diff --git a/pkg/attestation/attestation.go b/pkg/attestation/attestation.go new file mode 100644 index 0000000..81e3f5e --- /dev/null +++ b/pkg/attestation/attestation.go @@ -0,0 +1,82 @@ +package attestation + +import ( + "encoding/json" + "fmt" + + v1 "github.com/google/go-containerregistry/pkg/v1" + "github.com/google/go-containerregistry/pkg/v1/partial" + "github.com/google/go-containerregistry/pkg/v1/types" + intoto "github.com/in-toto/in-toto-golang/in_toto" +) + +// GetAttestationManifestsFromIndex extracts all attestation manifests from an index +func GetAttestationManifestsFromIndex(index v1.ImageIndex) ([]AttestationManifest, error) { + idx, err := index.IndexManifest() + if err != nil { + return nil, fmt.Errorf("failed to extract IndexManifest from ImageIndex: %w", err) + } + var attestationManifests []AttestationManifest + for _, manifest := range idx.Manifests { + if manifest.Annotations[DockerReferenceType] == AttestationManifestType { + attestationImage, err := index.Image(manifest.Digest) + if err != nil { + return nil, fmt.Errorf("failed to extract attestation image with digest %s: %w", manifest.Digest.String(), err) + } + attestationLayers, err := GetAttestationsFromImage(attestationImage) + if err != nil { + return nil, fmt.Errorf("failed to get attestations from image: %w", err) + } + attestationManifests = append(attestationManifests, + AttestationManifest{ + Manifest: manifest, + Attestation: AttestationImage{ + Layers: attestationLayers, + Image: attestationImage}, + MediaType: manifest.MediaType, + Annotations: manifest.Annotations, + Digest: manifest.Digest}) + } + } + return attestationManifests, nil +} + +// GetAttestationsFromImage extracts all attestation layers from an image +func GetAttestationsFromImage(image v1.Image) ([]AttestationLayer, error) { + layers, err := image.Layers() + if err != nil { + return nil, fmt.Errorf("failed to extract layers from image: %w", err) + } + var attestationLayers []AttestationLayer + for _, layer := range layers { + // parse layer blob as json + r, err := layer.Uncompressed() + if err != nil { + return nil, fmt.Errorf("failed to get layer contents: %w", err) + } + defer r.Close() + mt, err := layer.MediaType() + if err != nil { + return nil, fmt.Errorf("failed to get layer media type: %w", err) + } + layerDesc, err := partial.Descriptor(layer) + if err != nil { + return nil, fmt.Errorf("failed to get descriptor for layer: %w", err) + } + // copy original annotations + ann := make(map[string]string) + for k, v := range layerDesc.Annotations { + ann[k] = v + } + // only decode intoto statements + var stmt = new(intoto.Statement) + if mt == types.MediaType(intoto.PayloadType) { + err = json.NewDecoder(r).Decode(&stmt) + if err != nil { + return nil, fmt.Errorf("failed to decode statement layer contents: %w", err) + } + } + attestationLayers = append(attestationLayers, AttestationLayer{Layer: layer, MediaType: mt, Statement: stmt, Annotations: ann}) + } + return attestationLayers, nil +} diff --git a/pkg/attestation/types.go b/pkg/attestation/types.go index 7292e8d..5ee6717 100644 --- a/pkg/attestation/types.go +++ b/pkg/attestation/types.go @@ -1,14 +1,46 @@ package attestation -import "encoding/base64" +import ( + "encoding/base64" + "fmt" + + v1 "github.com/google/go-containerregistry/pkg/v1" + "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" + ociv1 "github.com/opencontainers/image-spec/specs-go/v1" +) const ( - DockerDsseExtKind = "application/vnd.docker.attestation-verification.v1+json" - RekorTlExtKind = "Rekor" + DockerReferenceType = "vnd.docker.reference.type" + AttestationManifestType = "attestation-manifest" + DockerDsseExtKind = "application/vnd.docker.attestation-verification.v1+json" + RekorTlExtKind = "Rekor" + OCIDescriptorDSSEMediaType = ociv1.MediaTypeDescriptor + "+dsse" ) var base64Encoding = base64.StdEncoding.Strict() +type AttestationLayer struct { + Statement *intoto.Statement + Layer v1.Layer + MediaType types.MediaType + Annotations map[string]string +} + +type AttestationImage struct { + Layers []AttestationLayer + Image v1.Image +} + +type AttestationManifest struct { + Manifest v1.Descriptor + Attestation AttestationImage + MediaType types.MediaType + Annotations map[string]string + Digest v1.Hash +} + // the following types are needed until https://github.com/secure-systems-lab/dsse/pull/61 is merged type Envelope struct { PayloadType string `json:"payloadType"` @@ -33,3 +65,20 @@ type DockerTlExtension struct { Kind string `json:"kind"` Data any `json:"data"` } + +func DSSEMediaType(predicateType string) (string, error) { + var predicateName string + switch predicateType { + case v02.PredicateSLSAProvenance: + predicateName = "provenance" + case intoto.PredicateSPDX: + predicateName = "spdx" + case VSAPredicateType: + predicateName = "verification_summary" + + default: + return "", fmt.Errorf("unknown predicate type %q", predicateType) + } + + return fmt.Sprintf("application/vnd.in-toto.%s+dsse", predicateName), nil +} diff --git a/pkg/attestation/vsa.go b/pkg/attestation/vsa.go new file mode 100644 index 0000000..4e0c59d --- /dev/null +++ b/pkg/attestation/vsa.go @@ -0,0 +1,55 @@ +package attestation + +import ( + "fmt" + + intoto "github.com/in-toto/in-toto-golang/in_toto" + "github.com/package-url/packageurl-go" +) + +const ( + VSAPredicateType = "https://slsa.dev/verification_summary/v1" +) + +type VSAPredicate struct { + Verifier VSAVerifier `json:"verifier"` + TimeVerified string `json:"timeVerified"` + ResourceUri string `json:"resourceUri"` + Policy VSAPolicy `json:"policy"` + InputAttestations []VSAInputAttestation `json:"inputAttestations"` + VerificationResult string `json:"verificationResult"` + VerifiedLevels []string `json:"verifiedLevels"` +} + +type VSAVerifier struct { + ID string `json:"id"` +} + +type VSAPolicy struct { + URI string `json:"uri"` +} + +type VSAInputAttestation struct { + Digest map[string]string `json:"digest"` + MediaType string `json:"mediaType"` +} + +type VSAOptions struct { + BuildLevel string + PolicyURI string + VerifierID string +} + +func ToVSAResourceURI(sub intoto.Subject) (string, error) { + //parse purl + purl, err := packageurl.FromString(sub.Name) + if err != nil { + return "", fmt.Errorf("failed to parse package url: %w", err) + } + quals := purl.Qualifiers.Map() + if quals["digest"] == "" { + quals["digest"] = "sha256:" + sub.Digest["sha256"] + } + purl.Qualifiers = packageurl.QualifiersFromMap(quals) + return purl.String(), nil +} diff --git a/pkg/mirror/mirror.go b/pkg/mirror/mirror.go index 04508eb..3abf107 100644 --- a/pkg/mirror/mirror.go +++ b/pkg/mirror/mirror.go @@ -48,7 +48,9 @@ func PushToRegistry(image any, imageName string) error { return fmt.Errorf("failed to push image index %s: %w", imageName, err) } default: - return fmt.Errorf("unknown image type: %T", image) + if err := remote.WriteIndex(ref, image.(v1.ImageIndex), remote.WithAuth(auth)); err != nil { + return fmt.Errorf("failed to push image index %s: %w", imageName, err) + } } return nil } @@ -76,7 +78,10 @@ func SaveAsOCILayout(image any, path string) error { return fmt.Errorf("failed to create index: %w", err) } default: - return fmt.Errorf("unknown image type: %T", image) + _, err := layout.Write(path, image.(v1.ImageIndex)) + if err != nil { + return fmt.Errorf("failed to create index: %w", err) + } } return nil } diff --git a/pkg/oci/types.go b/pkg/oci/types.go index 5af15eb..268ba1a 100644 --- a/pkg/oci/types.go +++ b/pkg/oci/types.go @@ -1,8 +1,69 @@ package oci +import ( + "fmt" + "log" + + "github.com/google/go-containerregistry/pkg/authn" + "github.com/google/go-containerregistry/pkg/name" + v1 "github.com/google/go-containerregistry/pkg/v1" + "github.com/google/go-containerregistry/pkg/v1/layout" + "github.com/google/go-containerregistry/pkg/v1/remote" +) + const ( DockerReferenceType = "vnd.docker.reference.type" DockerReferenceDigest = "vnd.docker.reference.digest" AttestationManifestType = "attestation-manifest" InTotoPredicateType = "in-toto.io/predicate-type" + OciReferenceTarget = "org.opencontainers.image.ref.name" ) + +type AttestationIndex struct { + Index v1.ImageIndex + Name string +} + +func AttestationIndexFromPath(path string) (*AttestationIndex, error) { + wrapperIdx, err := layout.ImageIndexFromPath(path) + if err != nil { + return nil, fmt.Errorf("failed to load image index: %w", err) + } + + idxm, err := wrapperIdx.IndexManifest() + if err != nil { + return nil, fmt.Errorf("failed to get digest: %w", err) + } + imageName := idxm.Manifests[0].Annotations[OciReferenceTarget] + idxDigest := idxm.Manifests[0].Digest + + idx, err := wrapperIdx.ImageIndex(idxDigest) + if err != nil { + return nil, fmt.Errorf("failed to extract ImageIndex for digest %s: %w", idxDigest.String(), err) + } + return &AttestationIndex{ + Index: idx, + Name: imageName, + }, nil +} + +func AttestationIndexFromRemote(image string) (*AttestationIndex, error) { + ref, err := name.ParseReference(image) + if err != nil { + log.Fatalf("Failed to parse image name: %v", err) + } + // Get the authenticator from the default Docker keychain + auth, err := authn.DefaultKeychain.Resolve(ref.Context()) + if err != nil { + log.Fatalf("Failed to get authenticator: %v", err) + } + // Pull the image from the registry + idx, err := remote.Index(ref, remote.WithAuth(auth)) + if err != nil { + return nil, fmt.Errorf("failed to pull image %s: %w", image, err) + } + return &AttestationIndex{ + Index: idx, + Name: image, + }, nil +} diff --git a/pkg/policy/evaluator.go b/pkg/policy/evaluator.go index 42cce24..35a34cb 100644 --- a/pkg/policy/evaluator.go +++ b/pkg/policy/evaluator.go @@ -28,14 +28,3 @@ func GetPolicyEvaluator(ctx context.Context) (PolicyEvaluator, error) { type PolicyEvaluator interface { Evaluate(ctx context.Context, resolver oci.AttestationResolver, policy []*PolicyFile, input *PolicyInput) error } - -type MockPolicyEvaluator struct { - EvaluateFunc func(ctx context.Context, resolver oci.AttestationResolver, policy []*PolicyFile, input *PolicyInput) error -} - -func (pe *MockPolicyEvaluator) Evaluate(ctx context.Context, resolver oci.AttestationResolver, policy []*PolicyFile, input *PolicyInput) error { - if pe.EvaluateFunc != nil { - return pe.EvaluateFunc(ctx, resolver, policy, input) - } - return nil -} diff --git a/pkg/policy/policy_test.go b/pkg/policy/policy_test.go index 9e404b8..2665cf7 100644 --- a/pkg/policy/policy_test.go +++ b/pkg/policy/policy_test.go @@ -98,7 +98,6 @@ func TestRegoEvaluator_Evaluate(t *testing.T) { policyFiles, err := policy.ResolvePolicy(ctx, tc.resolver, tc.policy) assert.NoErrorf(t, err, "failed to resolve policy") err = re.Evaluate(ctx, tc.resolver, policyFiles, tc.input) - if tc.expectSuccess { assert.NoErrorf(t, err, "Evaluate failed") } else { diff --git a/pkg/policy/rego.go b/pkg/policy/rego.go index fc9141a..78f3de3 100644 --- a/pkg/policy/rego.go +++ b/pkg/policy/rego.go @@ -23,6 +23,7 @@ import ( type regoEvaluator struct { debug bool + query string } func NewRegoEvaluator(debug bool) PolicyEvaluator { diff --git a/scripts/gen-testdata.sh b/scripts/gen-testdata.sh new file mode 100755 index 0000000..815f1c1 --- /dev/null +++ b/scripts/gen-testdata.sh @@ -0,0 +1,45 @@ +#!/bin/bash +set -eo pipefail + +echo "Starting the process to generate testdata..." + +# Define functions +function check_command () { + command -v "$1" >/dev/null 2>&1 || { echo >&2 "This script requires $1 but it's not installed. Aborting."; exit 1; } +} + +function cleanup_testdata () { + echo "Cleaning up existing testdata..." + rm -rf "${TESTDATA_PATH:?}/${UNSIGNED_IMAGE_DIR:?}" + rm -rf "${TESTDATA_PATH:?}/${NO_PROVENANCE_IMAGE_DIR:?}" +} + +function build_unsigned_image () { + echo "Building $UNSIGNED_IMAGE_DIR..." + docker buildx build "$TEST_IMAGE_DOCKERFILE_PATH" --sbom true --provenance true --platform linux/amd64,linux/arm64 \ + --output type=oci,tar=false,name="$TEST_IMAGE_REPO:$TEST_IMAGE_TAG",dest="$TESTDATA_PATH/$UNSIGNED_IMAGE_DIR" +} + +function build_no_provenance_image () { + echo "Building unsigned $NO_PROVENANCE_IMAGE_DIR..." + docker buildx build "$TEST_IMAGE_DOCKERFILE_PATH" --sbom true --provenance false --platform linux/amd64,linux/arm64 \ + --output type=oci,tar=false,name="$TEST_IMAGE_REPO:$TEST_IMAGE_TAG",dest="$TESTDATA_PATH/$NO_PROVENANCE_IMAGE_DIR" +} + +# Check required commands +check_command docker + +TESTDATA_PATH="../test/testdata" +TEST_IMAGE_DOCKERFILE_PATH="../test" +TEST_IMAGE_REPO="test-image" +TEST_IMAGE_TAG="test" +UNSIGNED_IMAGE_DIR="unsigned-test-image" +NO_PROVENANCE_IMAGE_DIR="no-provenance-image" +ATTESTATION_PAYLOADTYPE="application/vnd.in-toto+json" + +# Run steps +cleanup_testdata +build_unsigned_image +build_no_provenance_image + +echo "Process completed successfully." diff --git a/test/Dockerfile b/test/Dockerfile new file mode 100644 index 0000000..274a7c6 --- /dev/null +++ b/test/Dockerfile @@ -0,0 +1,5 @@ +FROM alpine AS build +RUN echo "hello world" > /tmp/hello.txt + +FROM scratch +COPY --from=build /tmp/hello.txt / diff --git a/test/testdata/no-provenance-image/blobs/sha256/1c70b3e7c3a57801501ec127aa6c918c390c373294ec4fc48f2c6fe703fcc6fe b/test/testdata/no-provenance-image/blobs/sha256/1c70b3e7c3a57801501ec127aa6c918c390c373294ec4fc48f2c6fe703fcc6fe new file mode 100644 index 0000000..d2651b3 --- /dev/null +++ b/test/testdata/no-provenance-image/blobs/sha256/1c70b3e7c3a57801501ec127aa6c918c390c373294ec4fc48f2c6fe703fcc6fe @@ -0,0 +1 @@ +{"architecture":"amd64","config":{"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"WorkingDir":"/","OnBuild":null},"created":"2024-03-08T16:42:30.065465358Z","history":[{"created":"2024-03-08T16:42:30.065465358Z","created_by":"COPY /tmp/hello.txt / # buildkit","comment":"buildkit.dockerfile.v0"}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:b842af8c2f1451ffc802ae4139819eaea8441223357642548d8a25ab5c52cff7"]}} \ No newline at end of file diff --git a/test/testdata/no-provenance-image/blobs/sha256/1effe3a77c594e579388dc4553dbbe762e4457a099ab8b706e67f5f9fc934701 b/test/testdata/no-provenance-image/blobs/sha256/1effe3a77c594e579388dc4553dbbe762e4457a099ab8b706e67f5f9fc934701 new file mode 100644 index 0000000..19c50eb --- /dev/null +++ b/test/testdata/no-provenance-image/blobs/sha256/1effe3a77c594e579388dc4553dbbe762e4457a099ab8b706e67f5f9fc934701 @@ -0,0 +1,50 @@ +{ + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.index.v1+json", + "manifests": [ + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620", + "size": 476, + "platform": { + "architecture": "amd64", + "os": "linux" + } + }, + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:7a76cec943853f9f7105b1976afa1bf7cd5bb6afc4e9d5852dd8da7cf81ae86e", + "size": 476, + "platform": { + "architecture": "arm64", + "os": "linux" + } + }, + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:2aaebbb079957470e7c0adddbb054b2b4c01f717d408efba753da2bf6e8905da", + "size": 558, + "annotations": { + "vnd.docker.reference.digest": "sha256:da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620", + "vnd.docker.reference.type": "attestation-manifest" + }, + "platform": { + "architecture": "unknown", + "os": "unknown" + } + }, + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:9b009d6b84b1ed941070b3f919823446286a674ad669d0baa8ab2c358aeb3a82", + "size": 558, + "annotations": { + "vnd.docker.reference.digest": "sha256:7a76cec943853f9f7105b1976afa1bf7cd5bb6afc4e9d5852dd8da7cf81ae86e", + "vnd.docker.reference.type": "attestation-manifest" + }, + "platform": { + "architecture": "unknown", + "os": "unknown" + } + } + ] +} \ No newline at end of file diff --git a/test/testdata/no-provenance-image/blobs/sha256/2aaebbb079957470e7c0adddbb054b2b4c01f717d408efba753da2bf6e8905da b/test/testdata/no-provenance-image/blobs/sha256/2aaebbb079957470e7c0adddbb054b2b4c01f717d408efba753da2bf6e8905da new file mode 100644 index 0000000..da3a9d6 --- /dev/null +++ b/test/testdata/no-provenance-image/blobs/sha256/2aaebbb079957470e7c0adddbb054b2b4c01f717d408efba753da2bf6e8905da @@ -0,0 +1,19 @@ +{ + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "config": { + "mediaType": "application/vnd.oci.image.config.v1+json", + "digest": "sha256:b6ef78de3633e45d1c08019fbabb4464fabd6dd32e82c67ea2b2a3c4e8bacdf5", + "size": 167 + }, + "layers": [ + { + "mediaType": "application/vnd.in-toto+json", + "digest": "sha256:a9646604f9522bf59d203a86ac5c2354a573ea041b8846409c4fc0f8c4a70850", + "size": 946, + "annotations": { + "in-toto.io/predicate-type": "https://spdx.dev/Document" + } + } + ] +} \ No newline at end of file diff --git a/test/testdata/no-provenance-image/blobs/sha256/2e82727457f04f320b643cb6e13bcbafb8e0dc0adc0443f1a25666f9518c5071 b/test/testdata/no-provenance-image/blobs/sha256/2e82727457f04f320b643cb6e13bcbafb8e0dc0adc0443f1a25666f9518c5071 new file mode 100644 index 0000000..49c9cbe --- /dev/null +++ b/test/testdata/no-provenance-image/blobs/sha256/2e82727457f04f320b643cb6e13bcbafb8e0dc0adc0443f1a25666f9518c5071 @@ -0,0 +1 @@ +{"architecture":"unknown","os":"unknown","config":{},"rootfs":{"type":"layers","diff_ids":["sha256:da5651e8877b960aa30f32f317fbeba28f5e06f1ce4d3895b3b8770140280a2e"]}} \ No newline at end of file diff --git a/test/testdata/no-provenance-image/blobs/sha256/7a76cec943853f9f7105b1976afa1bf7cd5bb6afc4e9d5852dd8da7cf81ae86e b/test/testdata/no-provenance-image/blobs/sha256/7a76cec943853f9f7105b1976afa1bf7cd5bb6afc4e9d5852dd8da7cf81ae86e new file mode 100644 index 0000000..1e9ebfd --- /dev/null +++ b/test/testdata/no-provenance-image/blobs/sha256/7a76cec943853f9f7105b1976afa1bf7cd5bb6afc4e9d5852dd8da7cf81ae86e @@ -0,0 +1,16 @@ +{ + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "config": { + "mediaType": "application/vnd.oci.image.config.v1+json", + "digest": "sha256:d85d624a324422194b43cccd975b5752cf0acaedd668bb525fcd40c3587cc460", + "size": 453 + }, + "layers": [ + { + "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", + "digest": "sha256:97a548f8d65d9ab617f608dd621f59e0d43a3b346f34c34eb58da31f00a9b0ad", + "size": 116 + } + ] +} \ No newline at end of file diff --git a/test/testdata/no-provenance-image/blobs/sha256/97a548f8d65d9ab617f608dd621f59e0d43a3b346f34c34eb58da31f00a9b0ad b/test/testdata/no-provenance-image/blobs/sha256/97a548f8d65d9ab617f608dd621f59e0d43a3b346f34c34eb58da31f00a9b0ad new file mode 100644 index 0000000..48e62f9 Binary files /dev/null and b/test/testdata/no-provenance-image/blobs/sha256/97a548f8d65d9ab617f608dd621f59e0d43a3b346f34c34eb58da31f00a9b0ad differ diff --git a/test/testdata/no-provenance-image/blobs/sha256/9b009d6b84b1ed941070b3f919823446286a674ad669d0baa8ab2c358aeb3a82 b/test/testdata/no-provenance-image/blobs/sha256/9b009d6b84b1ed941070b3f919823446286a674ad669d0baa8ab2c358aeb3a82 new file mode 100644 index 0000000..0c57870 --- /dev/null +++ b/test/testdata/no-provenance-image/blobs/sha256/9b009d6b84b1ed941070b3f919823446286a674ad669d0baa8ab2c358aeb3a82 @@ -0,0 +1,19 @@ +{ + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "config": { + "mediaType": "application/vnd.oci.image.config.v1+json", + "digest": "sha256:2e82727457f04f320b643cb6e13bcbafb8e0dc0adc0443f1a25666f9518c5071", + "size": 167 + }, + "layers": [ + { + "mediaType": "application/vnd.in-toto+json", + "digest": "sha256:da5651e8877b960aa30f32f317fbeba28f5e06f1ce4d3895b3b8770140280a2e", + "size": 946, + "annotations": { + "in-toto.io/predicate-type": "https://spdx.dev/Document" + } + } + ] +} \ No newline at end of file diff --git a/test/testdata/no-provenance-image/blobs/sha256/a9646604f9522bf59d203a86ac5c2354a573ea041b8846409c4fc0f8c4a70850 b/test/testdata/no-provenance-image/blobs/sha256/a9646604f9522bf59d203a86ac5c2354a573ea041b8846409c4fc0f8c4a70850 new file mode 100644 index 0000000..f765564 --- /dev/null +++ b/test/testdata/no-provenance-image/blobs/sha256/a9646604f9522bf59d203a86ac5c2354a573ea041b8846409c4fc0f8c4a70850 @@ -0,0 +1 @@ +{"_type":"https://in-toto.io/Statement/v0.1","predicateType":"https://spdx.dev/Document","subject":[{"name":"pkg:docker/test-image@test?platform=linux%2Famd64","digest":{"sha256":"da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620"}}],"predicate":{"spdxVersion":"SPDX-2.3","dataLicense":"CC0-1.0","SPDXID":"SPDXRef-DOCUMENT","name":"sbom","documentNamespace":"https://anchore.com/syft/dir/sbom-6d900ae6-587d-4695-9c01-511801a85b65","creationInfo":{"licenseListVersion":"3.23","creators":["Organization: Anchore, Inc","Tool: syft-v0.105.0","Tool: buildkit-v0.12.4"],"created":"2024-03-08T16:42:30Z"},"packages":[{"name":"sbom","SPDXID":"SPDXRef-DocumentRoot-Directory-sbom","supplier":"NOASSERTION","downloadLocation":"NOASSERTION","filesAnalyzed":false,"primaryPackagePurpose":"FILE"}],"relationships":[{"spdxElementId":"SPDXRef-DOCUMENT","relatedSpdxElement":"SPDXRef-DocumentRoot-Directory-sbom","relationshipType":"DESCRIBES"}]}} \ No newline at end of file diff --git a/test/testdata/no-provenance-image/blobs/sha256/b6ef78de3633e45d1c08019fbabb4464fabd6dd32e82c67ea2b2a3c4e8bacdf5 b/test/testdata/no-provenance-image/blobs/sha256/b6ef78de3633e45d1c08019fbabb4464fabd6dd32e82c67ea2b2a3c4e8bacdf5 new file mode 100644 index 0000000..38c4ab1 --- /dev/null +++ b/test/testdata/no-provenance-image/blobs/sha256/b6ef78de3633e45d1c08019fbabb4464fabd6dd32e82c67ea2b2a3c4e8bacdf5 @@ -0,0 +1 @@ +{"architecture":"unknown","os":"unknown","config":{},"rootfs":{"type":"layers","diff_ids":["sha256:a9646604f9522bf59d203a86ac5c2354a573ea041b8846409c4fc0f8c4a70850"]}} \ No newline at end of file diff --git a/test/testdata/no-provenance-image/blobs/sha256/d85d624a324422194b43cccd975b5752cf0acaedd668bb525fcd40c3587cc460 b/test/testdata/no-provenance-image/blobs/sha256/d85d624a324422194b43cccd975b5752cf0acaedd668bb525fcd40c3587cc460 new file mode 100644 index 0000000..e37f3ea --- /dev/null +++ b/test/testdata/no-provenance-image/blobs/sha256/d85d624a324422194b43cccd975b5752cf0acaedd668bb525fcd40c3587cc460 @@ -0,0 +1 @@ +{"architecture":"arm64","config":{"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"WorkingDir":"/","OnBuild":null},"created":"2024-03-08T16:42:30.065465358Z","history":[{"created":"2024-03-08T16:42:30.065465358Z","created_by":"COPY /tmp/hello.txt / # buildkit","comment":"buildkit.dockerfile.v0"}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:b842af8c2f1451ffc802ae4139819eaea8441223357642548d8a25ab5c52cff7"]}} \ No newline at end of file diff --git a/test/testdata/no-provenance-image/blobs/sha256/da5651e8877b960aa30f32f317fbeba28f5e06f1ce4d3895b3b8770140280a2e b/test/testdata/no-provenance-image/blobs/sha256/da5651e8877b960aa30f32f317fbeba28f5e06f1ce4d3895b3b8770140280a2e new file mode 100644 index 0000000..c18e28f --- /dev/null +++ b/test/testdata/no-provenance-image/blobs/sha256/da5651e8877b960aa30f32f317fbeba28f5e06f1ce4d3895b3b8770140280a2e @@ -0,0 +1 @@ +{"_type":"https://in-toto.io/Statement/v0.1","predicateType":"https://spdx.dev/Document","subject":[{"name":"pkg:docker/test-image@test?platform=linux%2Farm64","digest":{"sha256":"7a76cec943853f9f7105b1976afa1bf7cd5bb6afc4e9d5852dd8da7cf81ae86e"}}],"predicate":{"spdxVersion":"SPDX-2.3","dataLicense":"CC0-1.0","SPDXID":"SPDXRef-DOCUMENT","name":"sbom","documentNamespace":"https://anchore.com/syft/dir/sbom-6d900ae6-587d-4695-9c01-511801a85b65","creationInfo":{"licenseListVersion":"3.23","creators":["Organization: Anchore, Inc","Tool: syft-v0.105.0","Tool: buildkit-v0.12.4"],"created":"2024-03-08T16:42:30Z"},"packages":[{"name":"sbom","SPDXID":"SPDXRef-DocumentRoot-Directory-sbom","supplier":"NOASSERTION","downloadLocation":"NOASSERTION","filesAnalyzed":false,"primaryPackagePurpose":"FILE"}],"relationships":[{"spdxElementId":"SPDXRef-DOCUMENT","relatedSpdxElement":"SPDXRef-DocumentRoot-Directory-sbom","relationshipType":"DESCRIBES"}]}} \ No newline at end of file diff --git a/test/testdata/no-provenance-image/blobs/sha256/da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620 b/test/testdata/no-provenance-image/blobs/sha256/da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620 new file mode 100644 index 0000000..e68961b --- /dev/null +++ b/test/testdata/no-provenance-image/blobs/sha256/da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620 @@ -0,0 +1,16 @@ +{ + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "config": { + "mediaType": "application/vnd.oci.image.config.v1+json", + "digest": "sha256:1c70b3e7c3a57801501ec127aa6c918c390c373294ec4fc48f2c6fe703fcc6fe", + "size": 453 + }, + "layers": [ + { + "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", + "digest": "sha256:97a548f8d65d9ab617f608dd621f59e0d43a3b346f34c34eb58da31f00a9b0ad", + "size": 116 + } + ] +} \ No newline at end of file diff --git a/test/testdata/no-provenance-image/index.json b/test/testdata/no-provenance-image/index.json new file mode 100644 index 0000000..09786f4 --- /dev/null +++ b/test/testdata/no-provenance-image/index.json @@ -0,0 +1 @@ +{"schemaVersion":2,"manifests":[{"mediaType":"application/vnd.oci.image.index.v1+json","digest":"sha256:1effe3a77c594e579388dc4553dbbe762e4457a099ab8b706e67f5f9fc934701","size":1607,"annotations":{"org.opencontainers.image.created":"2024-04-29T10:23:48Z","org.opencontainers.image.ref.name":"docker.io/library/test-image:test"}}]} \ No newline at end of file diff --git a/test/testdata/no-provenance-image/oci-layout b/test/testdata/no-provenance-image/oci-layout new file mode 100644 index 0000000..1343d37 --- /dev/null +++ b/test/testdata/no-provenance-image/oci-layout @@ -0,0 +1 @@ +{"imageLayoutVersion":"1.0.0"} \ No newline at end of file diff --git a/test/testdata/unsigned-test-image/blobs/sha256/0f2ee9a338149a5a1435a7383582e5ef981b8a6bb7415d07d8d70c90d8cfd326 b/test/testdata/unsigned-test-image/blobs/sha256/0f2ee9a338149a5a1435a7383582e5ef981b8a6bb7415d07d8d70c90d8cfd326 new file mode 100644 index 0000000..38efdce --- /dev/null +++ b/test/testdata/unsigned-test-image/blobs/sha256/0f2ee9a338149a5a1435a7383582e5ef981b8a6bb7415d07d8d70c90d8cfd326 @@ -0,0 +1,50 @@ +{ + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.index.v1+json", + "manifests": [ + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620", + "size": 476, + "platform": { + "architecture": "amd64", + "os": "linux" + } + }, + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:7a76cec943853f9f7105b1976afa1bf7cd5bb6afc4e9d5852dd8da7cf81ae86e", + "size": 476, + "platform": { + "architecture": "arm64", + "os": "linux" + } + }, + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:aeca14119e3242c51633a899438518217417e01414d18189a3cf71c07f2a02c3", + "size": 836, + "annotations": { + "vnd.docker.reference.digest": "sha256:da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620", + "vnd.docker.reference.type": "attestation-manifest" + }, + "platform": { + "architecture": "unknown", + "os": "unknown" + } + }, + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:6658b8ba1e1221a6288bf50cd7813f814e2baad70141a3e315b7c3476b0f476f", + "size": 836, + "annotations": { + "vnd.docker.reference.digest": "sha256:7a76cec943853f9f7105b1976afa1bf7cd5bb6afc4e9d5852dd8da7cf81ae86e", + "vnd.docker.reference.type": "attestation-manifest" + }, + "platform": { + "architecture": "unknown", + "os": "unknown" + } + } + ] +} \ No newline at end of file diff --git a/test/testdata/unsigned-test-image/blobs/sha256/1c70b3e7c3a57801501ec127aa6c918c390c373294ec4fc48f2c6fe703fcc6fe b/test/testdata/unsigned-test-image/blobs/sha256/1c70b3e7c3a57801501ec127aa6c918c390c373294ec4fc48f2c6fe703fcc6fe new file mode 100644 index 0000000..d2651b3 --- /dev/null +++ b/test/testdata/unsigned-test-image/blobs/sha256/1c70b3e7c3a57801501ec127aa6c918c390c373294ec4fc48f2c6fe703fcc6fe @@ -0,0 +1 @@ +{"architecture":"amd64","config":{"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"WorkingDir":"/","OnBuild":null},"created":"2024-03-08T16:42:30.065465358Z","history":[{"created":"2024-03-08T16:42:30.065465358Z","created_by":"COPY /tmp/hello.txt / # buildkit","comment":"buildkit.dockerfile.v0"}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:b842af8c2f1451ffc802ae4139819eaea8441223357642548d8a25ab5c52cff7"]}} \ No newline at end of file diff --git a/test/testdata/unsigned-test-image/blobs/sha256/26da286bbc886aa14d191808db8fcbbd5d8ec68cf0047f954133e76d8e73d71c b/test/testdata/unsigned-test-image/blobs/sha256/26da286bbc886aa14d191808db8fcbbd5d8ec68cf0047f954133e76d8e73d71c new file mode 100644 index 0000000..596880e --- /dev/null +++ b/test/testdata/unsigned-test-image/blobs/sha256/26da286bbc886aa14d191808db8fcbbd5d8ec68cf0047f954133e76d8e73d71c @@ -0,0 +1,27 @@ +{ + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "config": { + "mediaType": "application/vnd.oci.image.config.v1+json", + "digest": "sha256:2953164d6cc6c8bb8271f78f9fb2003318350a8026ea082b63a249cfa60918a3", + "size": 241 + }, + "layers": [ + { + "mediaType": "application/vnd.in-toto+json", + "digest": "sha256:a9646604f9522bf59d203a86ac5c2354a573ea041b8846409c4fc0f8c4a70850", + "size": 946, + "annotations": { + "in-toto.io/predicate-type": "https://spdx.dev/Document" + } + }, + { + "mediaType": "application/vnd.in-toto+json", + "digest": "sha256:c6dd08ccc92ab60a87648a6b61fbf88d9287a936b285a8b4dde8893a1f4ffedf", + "size": 3944, + "annotations": { + "in-toto.io/predicate-type": "https://slsa.dev/provenance/v0.2" + } + } + ] +} \ No newline at end of file diff --git a/test/testdata/unsigned-test-image/blobs/sha256/2953164d6cc6c8bb8271f78f9fb2003318350a8026ea082b63a249cfa60918a3 b/test/testdata/unsigned-test-image/blobs/sha256/2953164d6cc6c8bb8271f78f9fb2003318350a8026ea082b63a249cfa60918a3 new file mode 100644 index 0000000..5d63600 --- /dev/null +++ b/test/testdata/unsigned-test-image/blobs/sha256/2953164d6cc6c8bb8271f78f9fb2003318350a8026ea082b63a249cfa60918a3 @@ -0,0 +1 @@ +{"architecture":"unknown","os":"unknown","config":{},"rootfs":{"type":"layers","diff_ids":["sha256:a9646604f9522bf59d203a86ac5c2354a573ea041b8846409c4fc0f8c4a70850","sha256:c6dd08ccc92ab60a87648a6b61fbf88d9287a936b285a8b4dde8893a1f4ffedf"]}} \ No newline at end of file diff --git a/test/testdata/unsigned-test-image/blobs/sha256/2a9b671f3fc9bc5ca967b616d96cbbdb6493e32d4f6abd8f7a191990e8efb289 b/test/testdata/unsigned-test-image/blobs/sha256/2a9b671f3fc9bc5ca967b616d96cbbdb6493e32d4f6abd8f7a191990e8efb289 new file mode 100644 index 0000000..65cb27a --- /dev/null +++ b/test/testdata/unsigned-test-image/blobs/sha256/2a9b671f3fc9bc5ca967b616d96cbbdb6493e32d4f6abd8f7a191990e8efb289 @@ -0,0 +1 @@ +{"architecture":"unknown","os":"unknown","config":{},"rootfs":{"type":"layers","diff_ids":["sha256:a9646604f9522bf59d203a86ac5c2354a573ea041b8846409c4fc0f8c4a70850","sha256:8f94b6e2a8be82e2e5b562d73212578bb3a02e8c0da7fc175c79045e73519375"]}} \ No newline at end of file diff --git a/test/testdata/unsigned-test-image/blobs/sha256/371954672cfaa92735d6fbd70a787aac618a41d4c8ec8d6e12bd12d0cc601706 b/test/testdata/unsigned-test-image/blobs/sha256/371954672cfaa92735d6fbd70a787aac618a41d4c8ec8d6e12bd12d0cc601706 new file mode 100644 index 0000000..72c55db --- /dev/null +++ b/test/testdata/unsigned-test-image/blobs/sha256/371954672cfaa92735d6fbd70a787aac618a41d4c8ec8d6e12bd12d0cc601706 @@ -0,0 +1 @@ +{"_type":"https://in-toto.io/Statement/v0.1","predicateType":"https://slsa.dev/provenance/v0.2","subject":[{"name":"pkg:docker/test-image@test?platform=linux%2Farm64","digest":{"sha256":"7a76cec943853f9f7105b1976afa1bf7cd5bb6afc4e9d5852dd8da7cf81ae86e"}}],"predicate":{"builder":{"id":""},"buildType":"https://mobyproject.org/buildkit@v1","materials":[{"uri":"pkg:docker/docker/buildkit-syft-scanner@stable-1","digest":{"sha256":"176e0869c38aeaede37e594fcf182c91d44391a932e1d71e99ec204873445a33"}},{"uri":"pkg:docker/alpine@latest?platform=linux%2Farm64","digest":{"sha256":"c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b"}}],"invocation":{"configSource":{"entryPoint":"Dockerfile"},"parameters":{"frontend":"dockerfile.v0","locals":[{"name":"context"},{"name":"dockerfile"}]},"environment":{"platform":"linux/amd64"}},"buildConfig":{"llbDefinition":[{"id":"step0","op":{"Op":{"source":{"identifier":"docker-image://docker.io/library/alpine:latest@sha256:c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b"}},"platform":{"Architecture":"arm64","OS":"linux"},"constraints":{}}},{"id":"step1","op":{"Op":{"exec":{"meta":{"args":["/bin/sh","-c","echo \"hello world\" \u003e /tmp/hello.txt"],"env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"cwd":"/","removeMountStubsRecursive":true},"mounts":[{"input":0,"dest":"/","output":0}]}},"platform":{"Architecture":"arm64","OS":"linux"},"constraints":{}},"inputs":["step0:0"]},{"id":"step2","op":{"Op":{"file":{"actions":[{"input":-1,"secondaryInput":0,"output":0,"Action":{"copy":{"src":"/tmp/hello.txt","dest":"/","mode":-1,"followSymlink":true,"dirCopyContents":true,"createDestPath":true,"allowWildcard":true,"allowEmptyWildcard":true,"timestamp":-1}}}]}},"constraints":{}},"inputs":["step1:0"]},{"id":"step3","op":{"Op":null},"inputs":["step2:0"]}],"digestMapping":{"sha256:9ef7beaea047309185047764e3aa0d4f29979dacc88e573daa9d0f82050b4ab1":"step0","sha256:c3529d59c164c4bc6fd97482020a2147fa20b991d48916315d80504673c871bf":"step2","sha256:c99cf7ecacd148d653fcacb51c2eadf68504a4d32c870f6de26706635b08df28":"step1","sha256:f9acdec24273860ab573e08a5e75a6cb8c4baef6602571df599b3d9b745b7b0f":"step3"}},"metadata":{"buildInvocationID":"jckf4dzdrb4i99ygsshezjtsq","buildStartedOn":"2024-04-29T10:23:45.125886079Z","buildFinishedOn":"2024-04-29T10:23:46.287890106Z","completeness":{"parameters":true,"environment":true,"materials":false},"reproducible":false,"https://mobyproject.org/buildkit@v1#metadata":{"vcs":{"revision":"ba33451b352942e366f12662f2c3a0c8ac54d696","source":"git@github.com:docker/image-signer-verifier.git"},"source":{"locations":{"step0":{"locations":[{"ranges":[{"start":{"line":1},"end":{"line":1}}]}]},"step1":{"locations":[{"ranges":[{"start":{"line":2},"end":{"line":2}}]}]},"step2":{"locations":[{"ranges":[{"start":{"line":5},"end":{"line":5}}]}]}},"infos":[{"filename":"Dockerfile","language":"Dockerfile","data":"RlJPTSBhbHBpbmUgQVMgYnVpbGQKUlVOIGVjaG8gImhlbGxvIHdvcmxkIiA+IC90bXAvaGVsbG8udHh0CgpGUk9NIHNjcmF0Y2gKQ09QWSAtLWZyb209YnVpbGQgL3RtcC9oZWxsby50eHQgLwo=","llbDefinition":[{"id":"step0","op":{"Op":{"source":{"identifier":"local://dockerfile","attrs":{"local.differ":"none","local.followpaths":"[\"Dockerfile\",\"Dockerfile.dockerignore\",\"dockerfile\"]","local.sharedkeyhint":"dockerfile"}}},"constraints":{}}},{"id":"step1","op":{"Op":null},"inputs":["step0:0"]}],"digestMapping":{"sha256:4efcb3fab1b18d9764b436e8f9430f56dd8fee0f811ae064f8ec051e7ac5dec4":"step0","sha256:5c08b537da7192a6909348620c571138948f7874016718afc6d6d4e1569453d3":"step1"}}]},"layers":{"step0:0":[[{"mediaType":"application/vnd.docker.image.rootfs.diff.tar.gzip","digest":"sha256:bca4290a96390d7a6fc6f2f9929370d06f8dfcacba591c76e3d5c5044e7f420c","size":3347715}]],"step2:0":[[{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:97a548f8d65d9ab617f608dd621f59e0d43a3b346f34c34eb58da31f00a9b0ad","size":116}]]}}}}} \ No newline at end of file diff --git a/test/testdata/unsigned-test-image/blobs/sha256/3883faf6acc3cae029364ed17ec2ce917fc9a500aab72f813d26fed8404e7162 b/test/testdata/unsigned-test-image/blobs/sha256/3883faf6acc3cae029364ed17ec2ce917fc9a500aab72f813d26fed8404e7162 new file mode 100644 index 0000000..162856c --- /dev/null +++ b/test/testdata/unsigned-test-image/blobs/sha256/3883faf6acc3cae029364ed17ec2ce917fc9a500aab72f813d26fed8404e7162 @@ -0,0 +1,27 @@ +{ + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "config": { + "mediaType": "application/vnd.oci.image.config.v1+json", + "digest": "sha256:2a9b671f3fc9bc5ca967b616d96cbbdb6493e32d4f6abd8f7a191990e8efb289", + "size": 241 + }, + "layers": [ + { + "mediaType": "application/vnd.in-toto+json", + "digest": "sha256:a9646604f9522bf59d203a86ac5c2354a573ea041b8846409c4fc0f8c4a70850", + "size": 946, + "annotations": { + "in-toto.io/predicate-type": "https://spdx.dev/Document" + } + }, + { + "mediaType": "application/vnd.in-toto+json", + "digest": "sha256:8f94b6e2a8be82e2e5b562d73212578bb3a02e8c0da7fc175c79045e73519375", + "size": 3944, + "annotations": { + "in-toto.io/predicate-type": "https://slsa.dev/provenance/v0.2" + } + } + ] +} \ No newline at end of file diff --git a/test/testdata/unsigned-test-image/blobs/sha256/3e64f9d2888ed9211fbf2c6b5853ea559248fdb4ab711bcea34b65c62f0e026b b/test/testdata/unsigned-test-image/blobs/sha256/3e64f9d2888ed9211fbf2c6b5853ea559248fdb4ab711bcea34b65c62f0e026b new file mode 100644 index 0000000..71fba30 --- /dev/null +++ b/test/testdata/unsigned-test-image/blobs/sha256/3e64f9d2888ed9211fbf2c6b5853ea559248fdb4ab711bcea34b65c62f0e026b @@ -0,0 +1 @@ +{"architecture":"unknown","os":"unknown","config":{},"rootfs":{"type":"layers","diff_ids":["sha256:a9646604f9522bf59d203a86ac5c2354a573ea041b8846409c4fc0f8c4a70850","sha256:8f2f55fc493890c2482a1220844157f4b0c8a6445d220af741e9fee8099bf532"]}} \ No newline at end of file diff --git a/test/testdata/unsigned-test-image/blobs/sha256/4e5988d06eee647cb901d4435830fbf13cf3ab1ae27ec91246b280514e6a7b33 b/test/testdata/unsigned-test-image/blobs/sha256/4e5988d06eee647cb901d4435830fbf13cf3ab1ae27ec91246b280514e6a7b33 new file mode 100644 index 0000000..d2e2697 --- /dev/null +++ b/test/testdata/unsigned-test-image/blobs/sha256/4e5988d06eee647cb901d4435830fbf13cf3ab1ae27ec91246b280514e6a7b33 @@ -0,0 +1 @@ +{"architecture":"unknown","os":"unknown","config":{},"rootfs":{"type":"layers","diff_ids":["sha256:a9646604f9522bf59d203a86ac5c2354a573ea041b8846409c4fc0f8c4a70850","sha256:c01e5307ec84299048d76f162abec6f8bee4c463103161ab772c774e7ae9dd6d"]}} \ No newline at end of file diff --git a/test/testdata/unsigned-test-image/blobs/sha256/5171425b78a2aedb43eb4e95083e64d3764c798507596ceded776c4ab038c224 b/test/testdata/unsigned-test-image/blobs/sha256/5171425b78a2aedb43eb4e95083e64d3764c798507596ceded776c4ab038c224 new file mode 100644 index 0000000..2d1769e --- /dev/null +++ b/test/testdata/unsigned-test-image/blobs/sha256/5171425b78a2aedb43eb4e95083e64d3764c798507596ceded776c4ab038c224 @@ -0,0 +1 @@ +{"_type":"https://in-toto.io/Statement/v0.1","predicateType":"https://slsa.dev/provenance/v0.2","subject":[{"name":"pkg:docker/test-image@test?platform=linux%2Farm64","digest":{"sha256":"7a76cec943853f9f7105b1976afa1bf7cd5bb6afc4e9d5852dd8da7cf81ae86e"}}],"predicate":{"builder":{"id":""},"buildType":"https://mobyproject.org/buildkit@v1","materials":[{"uri":"pkg:docker/docker/buildkit-syft-scanner@stable-1","digest":{"sha256":"176e0869c38aeaede37e594fcf182c91d44391a932e1d71e99ec204873445a33"}},{"uri":"pkg:docker/alpine@latest?platform=linux%2Farm64","digest":{"sha256":"c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b"}}],"invocation":{"configSource":{"entryPoint":"Dockerfile"},"parameters":{"frontend":"dockerfile.v0","locals":[{"name":"context"},{"name":"dockerfile"}]},"environment":{"platform":"linux/amd64"}},"buildConfig":{"llbDefinition":[{"id":"step0","op":{"Op":{"source":{"identifier":"docker-image://docker.io/library/alpine:latest@sha256:c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b"}},"platform":{"Architecture":"arm64","OS":"linux"},"constraints":{}}},{"id":"step1","op":{"Op":{"exec":{"meta":{"args":["/bin/sh","-c","echo \"hello world\" \u003e /tmp/hello.txt"],"env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"cwd":"/","removeMountStubsRecursive":true},"mounts":[{"input":0,"dest":"/","output":0}]}},"platform":{"Architecture":"arm64","OS":"linux"},"constraints":{}},"inputs":["step0:0"]},{"id":"step2","op":{"Op":{"file":{"actions":[{"input":-1,"secondaryInput":0,"output":0,"Action":{"copy":{"src":"/tmp/hello.txt","dest":"/","mode":-1,"followSymlink":true,"dirCopyContents":true,"createDestPath":true,"allowWildcard":true,"allowEmptyWildcard":true,"timestamp":-1}}}]}},"constraints":{}},"inputs":["step1:0"]},{"id":"step3","op":{"Op":null},"inputs":["step2:0"]}],"digestMapping":{"sha256:9ef7beaea047309185047764e3aa0d4f29979dacc88e573daa9d0f82050b4ab1":"step0","sha256:c3529d59c164c4bc6fd97482020a2147fa20b991d48916315d80504673c871bf":"step2","sha256:c99cf7ecacd148d653fcacb51c2eadf68504a4d32c870f6de26706635b08df28":"step1","sha256:f9acdec24273860ab573e08a5e75a6cb8c4baef6602571df599b3d9b745b7b0f":"step3"}},"metadata":{"buildInvocationID":"nkbtpuurp2ogre7j5hlfdrvma","buildStartedOn":"2024-04-26T14:24:49.386895737Z","buildFinishedOn":"2024-04-26T14:24:50.962885799Z","completeness":{"parameters":true,"environment":true,"materials":false},"reproducible":false,"https://mobyproject.org/buildkit@v1#metadata":{"vcs":{"revision":"77b839051c1796c77a5383f1570585c7f3ff70ea","source":"git@github.com:docker/image-signer-verifier.git"},"source":{"locations":{"step0":{"locations":[{"ranges":[{"start":{"line":1},"end":{"line":1}}]}]},"step1":{"locations":[{"ranges":[{"start":{"line":2},"end":{"line":2}}]}]},"step2":{"locations":[{"ranges":[{"start":{"line":5},"end":{"line":5}}]}]}},"infos":[{"filename":"Dockerfile","language":"Dockerfile","data":"RlJPTSBhbHBpbmUgQVMgYnVpbGQKUlVOIGVjaG8gImhlbGxvIHdvcmxkIiA+IC90bXAvaGVsbG8udHh0CgpGUk9NIHNjcmF0Y2gKQ09QWSAtLWZyb209YnVpbGQgL3RtcC9oZWxsby50eHQgLwo=","llbDefinition":[{"id":"step0","op":{"Op":{"source":{"identifier":"local://dockerfile","attrs":{"local.differ":"none","local.followpaths":"[\"Dockerfile\",\"Dockerfile.dockerignore\",\"dockerfile\"]","local.sharedkeyhint":"dockerfile"}}},"constraints":{}}},{"id":"step1","op":{"Op":null},"inputs":["step0:0"]}],"digestMapping":{"sha256:41e476230918469ca0be3275c43594cc0a909d01fdf0fe8b73f59c50d2c2d1b9":"step0","sha256:f1bd0b5d897e59fc7a5775b7082658676e06cc12674666e1713b56c38f7d1c0a":"step1"}}]},"layers":{"step0:0":[[{"mediaType":"application/vnd.docker.image.rootfs.diff.tar.gzip","digest":"sha256:bca4290a96390d7a6fc6f2f9929370d06f8dfcacba591c76e3d5c5044e7f420c","size":3347715}]],"step2:0":[[{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:97a548f8d65d9ab617f608dd621f59e0d43a3b346f34c34eb58da31f00a9b0ad","size":116}]]}}}}} \ No newline at end of file diff --git a/test/testdata/unsigned-test-image/blobs/sha256/6658b8ba1e1221a6288bf50cd7813f814e2baad70141a3e315b7c3476b0f476f b/test/testdata/unsigned-test-image/blobs/sha256/6658b8ba1e1221a6288bf50cd7813f814e2baad70141a3e315b7c3476b0f476f new file mode 100644 index 0000000..afaa051 --- /dev/null +++ b/test/testdata/unsigned-test-image/blobs/sha256/6658b8ba1e1221a6288bf50cd7813f814e2baad70141a3e315b7c3476b0f476f @@ -0,0 +1,27 @@ +{ + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "config": { + "mediaType": "application/vnd.oci.image.config.v1+json", + "digest": "sha256:fed2c8841731e2cf1ceb53c49c6440fcd6d565a8658141914a8a07c127e00d7e", + "size": 241 + }, + "layers": [ + { + "mediaType": "application/vnd.in-toto+json", + "digest": "sha256:da5651e8877b960aa30f32f317fbeba28f5e06f1ce4d3895b3b8770140280a2e", + "size": 946, + "annotations": { + "in-toto.io/predicate-type": "https://spdx.dev/Document" + } + }, + { + "mediaType": "application/vnd.in-toto+json", + "digest": "sha256:92d3311aa91737ff81e2a4c8e269e78c3c95df611b44580426c384d3f5057776", + "size": 3944, + "annotations": { + "in-toto.io/predicate-type": "https://slsa.dev/provenance/v0.2" + } + } + ] +} \ No newline at end of file diff --git a/test/testdata/unsigned-test-image/blobs/sha256/6c3da8eeaba64ce5acfcbaeb1f2c06af73879adba0fcb4743339c9a54b377635 b/test/testdata/unsigned-test-image/blobs/sha256/6c3da8eeaba64ce5acfcbaeb1f2c06af73879adba0fcb4743339c9a54b377635 new file mode 100644 index 0000000..06473ef --- /dev/null +++ b/test/testdata/unsigned-test-image/blobs/sha256/6c3da8eeaba64ce5acfcbaeb1f2c06af73879adba0fcb4743339c9a54b377635 @@ -0,0 +1,50 @@ +{ + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.index.v1+json", + "manifests": [ + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620", + "size": 476, + "platform": { + "architecture": "amd64", + "os": "linux" + } + }, + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:7a76cec943853f9f7105b1976afa1bf7cd5bb6afc4e9d5852dd8da7cf81ae86e", + "size": 476, + "platform": { + "architecture": "arm64", + "os": "linux" + } + }, + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:9638ca53d2795806cf51b7461575c51e4a626a091dc2842b35cac18c787ff80f", + "size": 836, + "annotations": { + "vnd.docker.reference.digest": "sha256:da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620", + "vnd.docker.reference.type": "attestation-manifest" + }, + "platform": { + "architecture": "unknown", + "os": "unknown" + } + }, + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:8049aa9ad3479085066b31d02b74310803129c3eb1e22d2e62279f8c72340b55", + "size": 836, + "annotations": { + "vnd.docker.reference.digest": "sha256:7a76cec943853f9f7105b1976afa1bf7cd5bb6afc4e9d5852dd8da7cf81ae86e", + "vnd.docker.reference.type": "attestation-manifest" + }, + "platform": { + "architecture": "unknown", + "os": "unknown" + } + } + ] +} \ No newline at end of file diff --git a/test/testdata/unsigned-test-image/blobs/sha256/7a76cec943853f9f7105b1976afa1bf7cd5bb6afc4e9d5852dd8da7cf81ae86e b/test/testdata/unsigned-test-image/blobs/sha256/7a76cec943853f9f7105b1976afa1bf7cd5bb6afc4e9d5852dd8da7cf81ae86e new file mode 100644 index 0000000..1e9ebfd --- /dev/null +++ b/test/testdata/unsigned-test-image/blobs/sha256/7a76cec943853f9f7105b1976afa1bf7cd5bb6afc4e9d5852dd8da7cf81ae86e @@ -0,0 +1,16 @@ +{ + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "config": { + "mediaType": "application/vnd.oci.image.config.v1+json", + "digest": "sha256:d85d624a324422194b43cccd975b5752cf0acaedd668bb525fcd40c3587cc460", + "size": 453 + }, + "layers": [ + { + "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", + "digest": "sha256:97a548f8d65d9ab617f608dd621f59e0d43a3b346f34c34eb58da31f00a9b0ad", + "size": 116 + } + ] +} \ No newline at end of file diff --git a/test/testdata/unsigned-test-image/blobs/sha256/8049aa9ad3479085066b31d02b74310803129c3eb1e22d2e62279f8c72340b55 b/test/testdata/unsigned-test-image/blobs/sha256/8049aa9ad3479085066b31d02b74310803129c3eb1e22d2e62279f8c72340b55 new file mode 100644 index 0000000..88ced07 --- /dev/null +++ b/test/testdata/unsigned-test-image/blobs/sha256/8049aa9ad3479085066b31d02b74310803129c3eb1e22d2e62279f8c72340b55 @@ -0,0 +1,27 @@ +{ + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "config": { + "mediaType": "application/vnd.oci.image.config.v1+json", + "digest": "sha256:f634c4c53b03bf8ff917b61165631fda0cfe691a383e7b333269a53bf9a79c34", + "size": 241 + }, + "layers": [ + { + "mediaType": "application/vnd.in-toto+json", + "digest": "sha256:da5651e8877b960aa30f32f317fbeba28f5e06f1ce4d3895b3b8770140280a2e", + "size": 946, + "annotations": { + "in-toto.io/predicate-type": "https://spdx.dev/Document" + } + }, + { + "mediaType": "application/vnd.in-toto+json", + "digest": "sha256:9fe102c03d71d47a24cd7fc7db8e7affc05fd9bf98eb027038b7daf176861e85", + "size": 3943, + "annotations": { + "in-toto.io/predicate-type": "https://slsa.dev/provenance/v0.2" + } + } + ] +} \ No newline at end of file diff --git a/test/testdata/unsigned-test-image/blobs/sha256/8f2f55fc493890c2482a1220844157f4b0c8a6445d220af741e9fee8099bf532 b/test/testdata/unsigned-test-image/blobs/sha256/8f2f55fc493890c2482a1220844157f4b0c8a6445d220af741e9fee8099bf532 new file mode 100644 index 0000000..6234c35 --- /dev/null +++ b/test/testdata/unsigned-test-image/blobs/sha256/8f2f55fc493890c2482a1220844157f4b0c8a6445d220af741e9fee8099bf532 @@ -0,0 +1 @@ +{"_type":"https://in-toto.io/Statement/v0.1","predicateType":"https://slsa.dev/provenance/v0.2","subject":[{"name":"pkg:docker/test-image@test?platform=linux%2Famd64","digest":{"sha256":"da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620"}}],"predicate":{"builder":{"id":""},"buildType":"https://mobyproject.org/buildkit@v1","materials":[{"uri":"pkg:docker/docker/buildkit-syft-scanner@stable-1","digest":{"sha256":"176e0869c38aeaede37e594fcf182c91d44391a932e1d71e99ec204873445a33"}},{"uri":"pkg:docker/alpine@latest?platform=linux%2Famd64","digest":{"sha256":"c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b"}}],"invocation":{"configSource":{"entryPoint":"Dockerfile"},"parameters":{"frontend":"dockerfile.v0","locals":[{"name":"context"},{"name":"dockerfile"}]},"environment":{"platform":"linux/amd64"}},"buildConfig":{"llbDefinition":[{"id":"step0","op":{"Op":{"source":{"identifier":"docker-image://docker.io/library/alpine:latest@sha256:c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b"}},"platform":{"Architecture":"amd64","OS":"linux"},"constraints":{}}},{"id":"step1","op":{"Op":{"exec":{"meta":{"args":["/bin/sh","-c","echo \"hello world\" \u003e /tmp/hello.txt"],"env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"cwd":"/","removeMountStubsRecursive":true},"mounts":[{"input":0,"dest":"/","output":0}]}},"platform":{"Architecture":"amd64","OS":"linux"},"constraints":{}},"inputs":["step0:0"]},{"id":"step2","op":{"Op":{"file":{"actions":[{"input":-1,"secondaryInput":0,"output":0,"Action":{"copy":{"src":"/tmp/hello.txt","dest":"/","mode":-1,"followSymlink":true,"dirCopyContents":true,"createDestPath":true,"allowWildcard":true,"allowEmptyWildcard":true,"timestamp":-1}}}]}},"constraints":{}},"inputs":["step1:0"]},{"id":"step3","op":{"Op":null},"inputs":["step2:0"]}],"digestMapping":{"sha256:46a51bd96c5f07c63901007f7fc78b5cbc14d05c2f2b1ec8e206d0f72a8d077a":"step2","sha256:a99a5b91a7644662f368e8bc1c6ca7fad2ea98ce130fd2d2ca648a42e8f9cca9":"step1","sha256:db2976cd1ada912761fd8495e52cdb659606c87e1b2d529926b859b4b7df140c":"step3","sha256:faa2314417184f0f81e21fe46ef9c04da17b8fc0d629ac5f017dd02a596697bb":"step0"}},"metadata":{"buildInvocationID":"4sdluz1285kjezq148xqo3fcr","buildStartedOn":"2024-04-29T10:20:54.451240475Z","buildFinishedOn":"2024-04-29T10:20:56.48203241Z","completeness":{"parameters":true,"environment":true,"materials":false},"reproducible":false,"https://mobyproject.org/buildkit@v1#metadata":{"vcs":{"revision":"ba33451b352942e366f12662f2c3a0c8ac54d696","source":"git@github.com:docker/image-signer-verifier.git"},"source":{"locations":{"step0":{"locations":[{"ranges":[{"start":{"line":1},"end":{"line":1}}]}]},"step1":{"locations":[{"ranges":[{"start":{"line":2},"end":{"line":2}}]}]},"step2":{"locations":[{"ranges":[{"start":{"line":5},"end":{"line":5}}]}]}},"infos":[{"filename":"Dockerfile","language":"Dockerfile","data":"RlJPTSBhbHBpbmUgQVMgYnVpbGQKUlVOIGVjaG8gImhlbGxvIHdvcmxkIiA+IC90bXAvaGVsbG8udHh0CgpGUk9NIHNjcmF0Y2gKQ09QWSAtLWZyb209YnVpbGQgL3RtcC9oZWxsby50eHQgLwo=","llbDefinition":[{"id":"step0","op":{"Op":{"source":{"identifier":"local://dockerfile","attrs":{"local.differ":"none","local.followpaths":"[\"Dockerfile\",\"Dockerfile.dockerignore\",\"dockerfile\"]","local.sharedkeyhint":"dockerfile"}}},"constraints":{}}},{"id":"step1","op":{"Op":null},"inputs":["step0:0"]}],"digestMapping":{"sha256:8c30f94c18660dd82452640583d991e007708a353546172a422418107a360f48":"step1","sha256:e1d9e97f2a2942f94811bc5453568509de77e86328036ef73562ba0b56137db6":"step0"}}]},"layers":{"step0:0":[[{"mediaType":"application/vnd.docker.image.rootfs.diff.tar.gzip","digest":"sha256:4abcf20661432fb2d719aaf90656f55c287f8ca915dc1c92ec14ff61e67fbaf8","size":3408729}]],"step2:0":[[{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:97a548f8d65d9ab617f608dd621f59e0d43a3b346f34c34eb58da31f00a9b0ad","size":116}]]}}}}} \ No newline at end of file diff --git a/test/testdata/unsigned-test-image/blobs/sha256/8f94b6e2a8be82e2e5b562d73212578bb3a02e8c0da7fc175c79045e73519375 b/test/testdata/unsigned-test-image/blobs/sha256/8f94b6e2a8be82e2e5b562d73212578bb3a02e8c0da7fc175c79045e73519375 new file mode 100644 index 0000000..a5dd69f --- /dev/null +++ b/test/testdata/unsigned-test-image/blobs/sha256/8f94b6e2a8be82e2e5b562d73212578bb3a02e8c0da7fc175c79045e73519375 @@ -0,0 +1 @@ +{"_type":"https://in-toto.io/Statement/v0.1","predicateType":"https://slsa.dev/provenance/v0.2","subject":[{"name":"pkg:docker/test-image@test?platform=linux%2Famd64","digest":{"sha256":"da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620"}}],"predicate":{"builder":{"id":""},"buildType":"https://mobyproject.org/buildkit@v1","materials":[{"uri":"pkg:docker/docker/buildkit-syft-scanner@stable-1","digest":{"sha256":"176e0869c38aeaede37e594fcf182c91d44391a932e1d71e99ec204873445a33"}},{"uri":"pkg:docker/alpine@latest?platform=linux%2Famd64","digest":{"sha256":"c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b"}}],"invocation":{"configSource":{"entryPoint":"Dockerfile"},"parameters":{"frontend":"dockerfile.v0","locals":[{"name":"context"},{"name":"dockerfile"}]},"environment":{"platform":"linux/amd64"}},"buildConfig":{"llbDefinition":[{"id":"step0","op":{"Op":{"source":{"identifier":"docker-image://docker.io/library/alpine:latest@sha256:c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b"}},"platform":{"Architecture":"amd64","OS":"linux"},"constraints":{}}},{"id":"step1","op":{"Op":{"exec":{"meta":{"args":["/bin/sh","-c","echo \"hello world\" \u003e /tmp/hello.txt"],"env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"cwd":"/","removeMountStubsRecursive":true},"mounts":[{"input":0,"dest":"/","output":0}]}},"platform":{"Architecture":"amd64","OS":"linux"},"constraints":{}},"inputs":["step0:0"]},{"id":"step2","op":{"Op":{"file":{"actions":[{"input":-1,"secondaryInput":0,"output":0,"Action":{"copy":{"src":"/tmp/hello.txt","dest":"/","mode":-1,"followSymlink":true,"dirCopyContents":true,"createDestPath":true,"allowWildcard":true,"allowEmptyWildcard":true,"timestamp":-1}}}]}},"constraints":{}},"inputs":["step1:0"]},{"id":"step3","op":{"Op":null},"inputs":["step2:0"]}],"digestMapping":{"sha256:46a51bd96c5f07c63901007f7fc78b5cbc14d05c2f2b1ec8e206d0f72a8d077a":"step2","sha256:a99a5b91a7644662f368e8bc1c6ca7fad2ea98ce130fd2d2ca648a42e8f9cca9":"step1","sha256:db2976cd1ada912761fd8495e52cdb659606c87e1b2d529926b859b4b7df140c":"step3","sha256:faa2314417184f0f81e21fe46ef9c04da17b8fc0d629ac5f017dd02a596697bb":"step0"}},"metadata":{"buildInvocationID":"nkbtpuurp2ogre7j5hlfdrvma","buildStartedOn":"2024-04-26T14:24:49.386895737Z","buildFinishedOn":"2024-04-26T14:24:50.962885799Z","completeness":{"parameters":true,"environment":true,"materials":false},"reproducible":false,"https://mobyproject.org/buildkit@v1#metadata":{"vcs":{"revision":"77b839051c1796c77a5383f1570585c7f3ff70ea","source":"git@github.com:docker/image-signer-verifier.git"},"source":{"locations":{"step0":{"locations":[{"ranges":[{"start":{"line":1},"end":{"line":1}}]}]},"step1":{"locations":[{"ranges":[{"start":{"line":2},"end":{"line":2}}]}]},"step2":{"locations":[{"ranges":[{"start":{"line":5},"end":{"line":5}}]}]}},"infos":[{"filename":"Dockerfile","language":"Dockerfile","data":"RlJPTSBhbHBpbmUgQVMgYnVpbGQKUlVOIGVjaG8gImhlbGxvIHdvcmxkIiA+IC90bXAvaGVsbG8udHh0CgpGUk9NIHNjcmF0Y2gKQ09QWSAtLWZyb209YnVpbGQgL3RtcC9oZWxsby50eHQgLwo=","llbDefinition":[{"id":"step0","op":{"Op":{"source":{"identifier":"local://dockerfile","attrs":{"local.differ":"none","local.followpaths":"[\"Dockerfile\",\"Dockerfile.dockerignore\",\"dockerfile\"]","local.sharedkeyhint":"dockerfile"}}},"constraints":{}}},{"id":"step1","op":{"Op":null},"inputs":["step0:0"]}],"digestMapping":{"sha256:41e476230918469ca0be3275c43594cc0a909d01fdf0fe8b73f59c50d2c2d1b9":"step0","sha256:f1bd0b5d897e59fc7a5775b7082658676e06cc12674666e1713b56c38f7d1c0a":"step1"}}]},"layers":{"step0:0":[[{"mediaType":"application/vnd.docker.image.rootfs.diff.tar.gzip","digest":"sha256:4abcf20661432fb2d719aaf90656f55c287f8ca915dc1c92ec14ff61e67fbaf8","size":3408729}]],"step2:0":[[{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:97a548f8d65d9ab617f608dd621f59e0d43a3b346f34c34eb58da31f00a9b0ad","size":116}]]}}}}} \ No newline at end of file diff --git a/test/testdata/unsigned-test-image/blobs/sha256/92d3311aa91737ff81e2a4c8e269e78c3c95df611b44580426c384d3f5057776 b/test/testdata/unsigned-test-image/blobs/sha256/92d3311aa91737ff81e2a4c8e269e78c3c95df611b44580426c384d3f5057776 new file mode 100644 index 0000000..ed7f598 --- /dev/null +++ b/test/testdata/unsigned-test-image/blobs/sha256/92d3311aa91737ff81e2a4c8e269e78c3c95df611b44580426c384d3f5057776 @@ -0,0 +1 @@ +{"_type":"https://in-toto.io/Statement/v0.1","predicateType":"https://slsa.dev/provenance/v0.2","subject":[{"name":"pkg:docker/test-image@test?platform=linux%2Farm64","digest":{"sha256":"7a76cec943853f9f7105b1976afa1bf7cd5bb6afc4e9d5852dd8da7cf81ae86e"}}],"predicate":{"builder":{"id":""},"buildType":"https://mobyproject.org/buildkit@v1","materials":[{"uri":"pkg:docker/docker/buildkit-syft-scanner@stable-1","digest":{"sha256":"176e0869c38aeaede37e594fcf182c91d44391a932e1d71e99ec204873445a33"}},{"uri":"pkg:docker/alpine@latest?platform=linux%2Farm64","digest":{"sha256":"c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b"}}],"invocation":{"configSource":{"entryPoint":"Dockerfile"},"parameters":{"frontend":"dockerfile.v0","locals":[{"name":"context"},{"name":"dockerfile"}]},"environment":{"platform":"linux/amd64"}},"buildConfig":{"llbDefinition":[{"id":"step0","op":{"Op":{"source":{"identifier":"docker-image://docker.io/library/alpine:latest@sha256:c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b"}},"platform":{"Architecture":"arm64","OS":"linux"},"constraints":{}}},{"id":"step1","op":{"Op":{"exec":{"meta":{"args":["/bin/sh","-c","echo \"hello world\" \u003e /tmp/hello.txt"],"env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"cwd":"/","removeMountStubsRecursive":true},"mounts":[{"input":0,"dest":"/","output":0}]}},"platform":{"Architecture":"arm64","OS":"linux"},"constraints":{}},"inputs":["step0:0"]},{"id":"step2","op":{"Op":{"file":{"actions":[{"input":-1,"secondaryInput":0,"output":0,"Action":{"copy":{"src":"/tmp/hello.txt","dest":"/","mode":-1,"followSymlink":true,"dirCopyContents":true,"createDestPath":true,"allowWildcard":true,"allowEmptyWildcard":true,"timestamp":-1}}}]}},"constraints":{}},"inputs":["step1:0"]},{"id":"step3","op":{"Op":null},"inputs":["step2:0"]}],"digestMapping":{"sha256:9ef7beaea047309185047764e3aa0d4f29979dacc88e573daa9d0f82050b4ab1":"step0","sha256:c3529d59c164c4bc6fd97482020a2147fa20b991d48916315d80504673c871bf":"step2","sha256:c99cf7ecacd148d653fcacb51c2eadf68504a4d32c870f6de26706635b08df28":"step1","sha256:f9acdec24273860ab573e08a5e75a6cb8c4baef6602571df599b3d9b745b7b0f":"step3"}},"metadata":{"buildInvocationID":"oufyhd0aciw714m1i5y6l09xz","buildStartedOn":"2024-04-19T16:25:04.209111656Z","buildFinishedOn":"2024-04-19T16:25:05.831440763Z","completeness":{"parameters":true,"environment":true,"materials":false},"reproducible":false,"https://mobyproject.org/buildkit@v1#metadata":{"vcs":{"revision":"5914df2930aba701d6ddc3ba9272a5732dfe8ab4","source":"git@github.com:docker/image-signer-verifier.git"},"source":{"locations":{"step0":{"locations":[{"ranges":[{"start":{"line":1},"end":{"line":1}}]}]},"step1":{"locations":[{"ranges":[{"start":{"line":2},"end":{"line":2}}]}]},"step2":{"locations":[{"ranges":[{"start":{"line":5},"end":{"line":5}}]}]}},"infos":[{"filename":"Dockerfile","language":"Dockerfile","data":"RlJPTSBhbHBpbmUgQVMgYnVpbGQKUlVOIGVjaG8gImhlbGxvIHdvcmxkIiA+IC90bXAvaGVsbG8udHh0CgpGUk9NIHNjcmF0Y2gKQ09QWSAtLWZyb209YnVpbGQgL3RtcC9oZWxsby50eHQgLwo=","llbDefinition":[{"id":"step0","op":{"Op":{"source":{"identifier":"local://dockerfile","attrs":{"local.differ":"none","local.followpaths":"[\"Dockerfile\",\"Dockerfile.dockerignore\",\"dockerfile\"]","local.sharedkeyhint":"dockerfile"}}},"constraints":{}}},{"id":"step1","op":{"Op":null},"inputs":["step0:0"]}],"digestMapping":{"sha256:18b166b594df5270bf6a4aa8dcd0a96b3635d0a23106d819620cbab2f3f5cf22":"step0","sha256:31d6cbba3f437cfb5933e60d5f4d2be69109c2fae9ed5ffe04da16931a459cca":"step1"}}]},"layers":{"step0:0":[[{"mediaType":"application/vnd.docker.image.rootfs.diff.tar.gzip","digest":"sha256:bca4290a96390d7a6fc6f2f9929370d06f8dfcacba591c76e3d5c5044e7f420c","size":3347715}]],"step2:0":[[{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:97a548f8d65d9ab617f608dd621f59e0d43a3b346f34c34eb58da31f00a9b0ad","size":116}]]}}}}} \ No newline at end of file diff --git a/test/testdata/unsigned-test-image/blobs/sha256/9638ca53d2795806cf51b7461575c51e4a626a091dc2842b35cac18c787ff80f b/test/testdata/unsigned-test-image/blobs/sha256/9638ca53d2795806cf51b7461575c51e4a626a091dc2842b35cac18c787ff80f new file mode 100644 index 0000000..09d726b --- /dev/null +++ b/test/testdata/unsigned-test-image/blobs/sha256/9638ca53d2795806cf51b7461575c51e4a626a091dc2842b35cac18c787ff80f @@ -0,0 +1,27 @@ +{ + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "config": { + "mediaType": "application/vnd.oci.image.config.v1+json", + "digest": "sha256:3e64f9d2888ed9211fbf2c6b5853ea559248fdb4ab711bcea34b65c62f0e026b", + "size": 241 + }, + "layers": [ + { + "mediaType": "application/vnd.in-toto+json", + "digest": "sha256:a9646604f9522bf59d203a86ac5c2354a573ea041b8846409c4fc0f8c4a70850", + "size": 946, + "annotations": { + "in-toto.io/predicate-type": "https://spdx.dev/Document" + } + }, + { + "mediaType": "application/vnd.in-toto+json", + "digest": "sha256:8f2f55fc493890c2482a1220844157f4b0c8a6445d220af741e9fee8099bf532", + "size": 3943, + "annotations": { + "in-toto.io/predicate-type": "https://slsa.dev/provenance/v0.2" + } + } + ] +} \ No newline at end of file diff --git a/test/testdata/unsigned-test-image/blobs/sha256/97a548f8d65d9ab617f608dd621f59e0d43a3b346f34c34eb58da31f00a9b0ad b/test/testdata/unsigned-test-image/blobs/sha256/97a548f8d65d9ab617f608dd621f59e0d43a3b346f34c34eb58da31f00a9b0ad new file mode 100644 index 0000000..48e62f9 Binary files /dev/null and b/test/testdata/unsigned-test-image/blobs/sha256/97a548f8d65d9ab617f608dd621f59e0d43a3b346f34c34eb58da31f00a9b0ad differ diff --git a/test/testdata/unsigned-test-image/blobs/sha256/98e06f6b48edd74e21e8504c5538aec56315874a6db860fbf6874cd7a830e3c8 b/test/testdata/unsigned-test-image/blobs/sha256/98e06f6b48edd74e21e8504c5538aec56315874a6db860fbf6874cd7a830e3c8 new file mode 100644 index 0000000..658ff6e --- /dev/null +++ b/test/testdata/unsigned-test-image/blobs/sha256/98e06f6b48edd74e21e8504c5538aec56315874a6db860fbf6874cd7a830e3c8 @@ -0,0 +1,50 @@ +{ + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.index.v1+json", + "manifests": [ + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620", + "size": 476, + "platform": { + "architecture": "amd64", + "os": "linux" + } + }, + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:7a76cec943853f9f7105b1976afa1bf7cd5bb6afc4e9d5852dd8da7cf81ae86e", + "size": 476, + "platform": { + "architecture": "arm64", + "os": "linux" + } + }, + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:3883faf6acc3cae029364ed17ec2ce917fc9a500aab72f813d26fed8404e7162", + "size": 836, + "annotations": { + "vnd.docker.reference.digest": "sha256:da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620", + "vnd.docker.reference.type": "attestation-manifest" + }, + "platform": { + "architecture": "unknown", + "os": "unknown" + } + }, + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:f2b95cecafef9c22a5d059fac8f20e3645a45370e52abf9581dd4eedd152fce0", + "size": 836, + "annotations": { + "vnd.docker.reference.digest": "sha256:7a76cec943853f9f7105b1976afa1bf7cd5bb6afc4e9d5852dd8da7cf81ae86e", + "vnd.docker.reference.type": "attestation-manifest" + }, + "platform": { + "architecture": "unknown", + "os": "unknown" + } + } + ] +} \ No newline at end of file diff --git a/test/testdata/unsigned-test-image/blobs/sha256/9fe102c03d71d47a24cd7fc7db8e7affc05fd9bf98eb027038b7daf176861e85 b/test/testdata/unsigned-test-image/blobs/sha256/9fe102c03d71d47a24cd7fc7db8e7affc05fd9bf98eb027038b7daf176861e85 new file mode 100644 index 0000000..74dd618 --- /dev/null +++ b/test/testdata/unsigned-test-image/blobs/sha256/9fe102c03d71d47a24cd7fc7db8e7affc05fd9bf98eb027038b7daf176861e85 @@ -0,0 +1 @@ +{"_type":"https://in-toto.io/Statement/v0.1","predicateType":"https://slsa.dev/provenance/v0.2","subject":[{"name":"pkg:docker/test-image@test?platform=linux%2Farm64","digest":{"sha256":"7a76cec943853f9f7105b1976afa1bf7cd5bb6afc4e9d5852dd8da7cf81ae86e"}}],"predicate":{"builder":{"id":""},"buildType":"https://mobyproject.org/buildkit@v1","materials":[{"uri":"pkg:docker/docker/buildkit-syft-scanner@stable-1","digest":{"sha256":"176e0869c38aeaede37e594fcf182c91d44391a932e1d71e99ec204873445a33"}},{"uri":"pkg:docker/alpine@latest?platform=linux%2Farm64","digest":{"sha256":"c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b"}}],"invocation":{"configSource":{"entryPoint":"Dockerfile"},"parameters":{"frontend":"dockerfile.v0","locals":[{"name":"context"},{"name":"dockerfile"}]},"environment":{"platform":"linux/amd64"}},"buildConfig":{"llbDefinition":[{"id":"step0","op":{"Op":{"source":{"identifier":"docker-image://docker.io/library/alpine:latest@sha256:c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b"}},"platform":{"Architecture":"arm64","OS":"linux"},"constraints":{}}},{"id":"step1","op":{"Op":{"exec":{"meta":{"args":["/bin/sh","-c","echo \"hello world\" \u003e /tmp/hello.txt"],"env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"cwd":"/","removeMountStubsRecursive":true},"mounts":[{"input":0,"dest":"/","output":0}]}},"platform":{"Architecture":"arm64","OS":"linux"},"constraints":{}},"inputs":["step0:0"]},{"id":"step2","op":{"Op":{"file":{"actions":[{"input":-1,"secondaryInput":0,"output":0,"Action":{"copy":{"src":"/tmp/hello.txt","dest":"/","mode":-1,"followSymlink":true,"dirCopyContents":true,"createDestPath":true,"allowWildcard":true,"allowEmptyWildcard":true,"timestamp":-1}}}]}},"constraints":{}},"inputs":["step1:0"]},{"id":"step3","op":{"Op":null},"inputs":["step2:0"]}],"digestMapping":{"sha256:9ef7beaea047309185047764e3aa0d4f29979dacc88e573daa9d0f82050b4ab1":"step0","sha256:c3529d59c164c4bc6fd97482020a2147fa20b991d48916315d80504673c871bf":"step2","sha256:c99cf7ecacd148d653fcacb51c2eadf68504a4d32c870f6de26706635b08df28":"step1","sha256:f9acdec24273860ab573e08a5e75a6cb8c4baef6602571df599b3d9b745b7b0f":"step3"}},"metadata":{"buildInvocationID":"4sdluz1285kjezq148xqo3fcr","buildStartedOn":"2024-04-29T10:20:54.451240475Z","buildFinishedOn":"2024-04-29T10:20:56.48203241Z","completeness":{"parameters":true,"environment":true,"materials":false},"reproducible":false,"https://mobyproject.org/buildkit@v1#metadata":{"vcs":{"revision":"ba33451b352942e366f12662f2c3a0c8ac54d696","source":"git@github.com:docker/image-signer-verifier.git"},"source":{"locations":{"step0":{"locations":[{"ranges":[{"start":{"line":1},"end":{"line":1}}]}]},"step1":{"locations":[{"ranges":[{"start":{"line":2},"end":{"line":2}}]}]},"step2":{"locations":[{"ranges":[{"start":{"line":5},"end":{"line":5}}]}]}},"infos":[{"filename":"Dockerfile","language":"Dockerfile","data":"RlJPTSBhbHBpbmUgQVMgYnVpbGQKUlVOIGVjaG8gImhlbGxvIHdvcmxkIiA+IC90bXAvaGVsbG8udHh0CgpGUk9NIHNjcmF0Y2gKQ09QWSAtLWZyb209YnVpbGQgL3RtcC9oZWxsby50eHQgLwo=","llbDefinition":[{"id":"step0","op":{"Op":{"source":{"identifier":"local://dockerfile","attrs":{"local.differ":"none","local.followpaths":"[\"Dockerfile\",\"Dockerfile.dockerignore\",\"dockerfile\"]","local.sharedkeyhint":"dockerfile"}}},"constraints":{}}},{"id":"step1","op":{"Op":null},"inputs":["step0:0"]}],"digestMapping":{"sha256:8c30f94c18660dd82452640583d991e007708a353546172a422418107a360f48":"step1","sha256:e1d9e97f2a2942f94811bc5453568509de77e86328036ef73562ba0b56137db6":"step0"}}]},"layers":{"step0:0":[[{"mediaType":"application/vnd.docker.image.rootfs.diff.tar.gzip","digest":"sha256:bca4290a96390d7a6fc6f2f9929370d06f8dfcacba591c76e3d5c5044e7f420c","size":3347715}]],"step2:0":[[{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:97a548f8d65d9ab617f608dd621f59e0d43a3b346f34c34eb58da31f00a9b0ad","size":116}]]}}}}} \ No newline at end of file diff --git a/test/testdata/unsigned-test-image/blobs/sha256/a4cf4b24f3fa8cd49a59e8fd4ef5ce285f0aa928d2651f7ec3d5a78276249dec b/test/testdata/unsigned-test-image/blobs/sha256/a4cf4b24f3fa8cd49a59e8fd4ef5ce285f0aa928d2651f7ec3d5a78276249dec new file mode 100644 index 0000000..be03cec --- /dev/null +++ b/test/testdata/unsigned-test-image/blobs/sha256/a4cf4b24f3fa8cd49a59e8fd4ef5ce285f0aa928d2651f7ec3d5a78276249dec @@ -0,0 +1 @@ +{"architecture":"unknown","os":"unknown","config":{},"rootfs":{"type":"layers","diff_ids":["sha256:da5651e8877b960aa30f32f317fbeba28f5e06f1ce4d3895b3b8770140280a2e","sha256:371954672cfaa92735d6fbd70a787aac618a41d4c8ec8d6e12bd12d0cc601706"]}} \ No newline at end of file diff --git a/test/testdata/unsigned-test-image/blobs/sha256/a9646604f9522bf59d203a86ac5c2354a573ea041b8846409c4fc0f8c4a70850 b/test/testdata/unsigned-test-image/blobs/sha256/a9646604f9522bf59d203a86ac5c2354a573ea041b8846409c4fc0f8c4a70850 new file mode 100644 index 0000000..f765564 --- /dev/null +++ b/test/testdata/unsigned-test-image/blobs/sha256/a9646604f9522bf59d203a86ac5c2354a573ea041b8846409c4fc0f8c4a70850 @@ -0,0 +1 @@ +{"_type":"https://in-toto.io/Statement/v0.1","predicateType":"https://spdx.dev/Document","subject":[{"name":"pkg:docker/test-image@test?platform=linux%2Famd64","digest":{"sha256":"da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620"}}],"predicate":{"spdxVersion":"SPDX-2.3","dataLicense":"CC0-1.0","SPDXID":"SPDXRef-DOCUMENT","name":"sbom","documentNamespace":"https://anchore.com/syft/dir/sbom-6d900ae6-587d-4695-9c01-511801a85b65","creationInfo":{"licenseListVersion":"3.23","creators":["Organization: Anchore, Inc","Tool: syft-v0.105.0","Tool: buildkit-v0.12.4"],"created":"2024-03-08T16:42:30Z"},"packages":[{"name":"sbom","SPDXID":"SPDXRef-DocumentRoot-Directory-sbom","supplier":"NOASSERTION","downloadLocation":"NOASSERTION","filesAnalyzed":false,"primaryPackagePurpose":"FILE"}],"relationships":[{"spdxElementId":"SPDXRef-DOCUMENT","relatedSpdxElement":"SPDXRef-DocumentRoot-Directory-sbom","relationshipType":"DESCRIBES"}]}} \ No newline at end of file diff --git a/test/testdata/unsigned-test-image/blobs/sha256/aeca14119e3242c51633a899438518217417e01414d18189a3cf71c07f2a02c3 b/test/testdata/unsigned-test-image/blobs/sha256/aeca14119e3242c51633a899438518217417e01414d18189a3cf71c07f2a02c3 new file mode 100644 index 0000000..4ba3cd7 --- /dev/null +++ b/test/testdata/unsigned-test-image/blobs/sha256/aeca14119e3242c51633a899438518217417e01414d18189a3cf71c07f2a02c3 @@ -0,0 +1,27 @@ +{ + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "config": { + "mediaType": "application/vnd.oci.image.config.v1+json", + "digest": "sha256:4e5988d06eee647cb901d4435830fbf13cf3ab1ae27ec91246b280514e6a7b33", + "size": 241 + }, + "layers": [ + { + "mediaType": "application/vnd.in-toto+json", + "digest": "sha256:a9646604f9522bf59d203a86ac5c2354a573ea041b8846409c4fc0f8c4a70850", + "size": 946, + "annotations": { + "in-toto.io/predicate-type": "https://spdx.dev/Document" + } + }, + { + "mediaType": "application/vnd.in-toto+json", + "digest": "sha256:c01e5307ec84299048d76f162abec6f8bee4c463103161ab772c774e7ae9dd6d", + "size": 3944, + "annotations": { + "in-toto.io/predicate-type": "https://slsa.dev/provenance/v0.2" + } + } + ] +} \ No newline at end of file diff --git a/test/testdata/unsigned-test-image/blobs/sha256/c01e5307ec84299048d76f162abec6f8bee4c463103161ab772c774e7ae9dd6d b/test/testdata/unsigned-test-image/blobs/sha256/c01e5307ec84299048d76f162abec6f8bee4c463103161ab772c774e7ae9dd6d new file mode 100644 index 0000000..cca62ed --- /dev/null +++ b/test/testdata/unsigned-test-image/blobs/sha256/c01e5307ec84299048d76f162abec6f8bee4c463103161ab772c774e7ae9dd6d @@ -0,0 +1 @@ +{"_type":"https://in-toto.io/Statement/v0.1","predicateType":"https://slsa.dev/provenance/v0.2","subject":[{"name":"pkg:docker/test-image@test?platform=linux%2Famd64","digest":{"sha256":"da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620"}}],"predicate":{"builder":{"id":""},"buildType":"https://mobyproject.org/buildkit@v1","materials":[{"uri":"pkg:docker/docker/buildkit-syft-scanner@stable-1","digest":{"sha256":"176e0869c38aeaede37e594fcf182c91d44391a932e1d71e99ec204873445a33"}},{"uri":"pkg:docker/alpine@latest?platform=linux%2Famd64","digest":{"sha256":"c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b"}}],"invocation":{"configSource":{"entryPoint":"Dockerfile"},"parameters":{"frontend":"dockerfile.v0","locals":[{"name":"context"},{"name":"dockerfile"}]},"environment":{"platform":"linux/amd64"}},"buildConfig":{"llbDefinition":[{"id":"step0","op":{"Op":{"source":{"identifier":"docker-image://docker.io/library/alpine:latest@sha256:c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b"}},"platform":{"Architecture":"amd64","OS":"linux"},"constraints":{}}},{"id":"step1","op":{"Op":{"exec":{"meta":{"args":["/bin/sh","-c","echo \"hello world\" \u003e /tmp/hello.txt"],"env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"cwd":"/","removeMountStubsRecursive":true},"mounts":[{"input":0,"dest":"/","output":0}]}},"platform":{"Architecture":"amd64","OS":"linux"},"constraints":{}},"inputs":["step0:0"]},{"id":"step2","op":{"Op":{"file":{"actions":[{"input":-1,"secondaryInput":0,"output":0,"Action":{"copy":{"src":"/tmp/hello.txt","dest":"/","mode":-1,"followSymlink":true,"dirCopyContents":true,"createDestPath":true,"allowWildcard":true,"allowEmptyWildcard":true,"timestamp":-1}}}]}},"constraints":{}},"inputs":["step1:0"]},{"id":"step3","op":{"Op":null},"inputs":["step2:0"]}],"digestMapping":{"sha256:46a51bd96c5f07c63901007f7fc78b5cbc14d05c2f2b1ec8e206d0f72a8d077a":"step2","sha256:a99a5b91a7644662f368e8bc1c6ca7fad2ea98ce130fd2d2ca648a42e8f9cca9":"step1","sha256:db2976cd1ada912761fd8495e52cdb659606c87e1b2d529926b859b4b7df140c":"step3","sha256:faa2314417184f0f81e21fe46ef9c04da17b8fc0d629ac5f017dd02a596697bb":"step0"}},"metadata":{"buildInvocationID":"oufyhd0aciw714m1i5y6l09xz","buildStartedOn":"2024-04-19T16:25:04.209111656Z","buildFinishedOn":"2024-04-19T16:25:05.831440763Z","completeness":{"parameters":true,"environment":true,"materials":false},"reproducible":false,"https://mobyproject.org/buildkit@v1#metadata":{"vcs":{"revision":"5914df2930aba701d6ddc3ba9272a5732dfe8ab4","source":"git@github.com:docker/image-signer-verifier.git"},"source":{"locations":{"step0":{"locations":[{"ranges":[{"start":{"line":1},"end":{"line":1}}]}]},"step1":{"locations":[{"ranges":[{"start":{"line":2},"end":{"line":2}}]}]},"step2":{"locations":[{"ranges":[{"start":{"line":5},"end":{"line":5}}]}]}},"infos":[{"filename":"Dockerfile","language":"Dockerfile","data":"RlJPTSBhbHBpbmUgQVMgYnVpbGQKUlVOIGVjaG8gImhlbGxvIHdvcmxkIiA+IC90bXAvaGVsbG8udHh0CgpGUk9NIHNjcmF0Y2gKQ09QWSAtLWZyb209YnVpbGQgL3RtcC9oZWxsby50eHQgLwo=","llbDefinition":[{"id":"step0","op":{"Op":{"source":{"identifier":"local://dockerfile","attrs":{"local.differ":"none","local.followpaths":"[\"Dockerfile\",\"Dockerfile.dockerignore\",\"dockerfile\"]","local.sharedkeyhint":"dockerfile"}}},"constraints":{}}},{"id":"step1","op":{"Op":null},"inputs":["step0:0"]}],"digestMapping":{"sha256:18b166b594df5270bf6a4aa8dcd0a96b3635d0a23106d819620cbab2f3f5cf22":"step0","sha256:31d6cbba3f437cfb5933e60d5f4d2be69109c2fae9ed5ffe04da16931a459cca":"step1"}}]},"layers":{"step0:0":[[{"mediaType":"application/vnd.docker.image.rootfs.diff.tar.gzip","digest":"sha256:4abcf20661432fb2d719aaf90656f55c287f8ca915dc1c92ec14ff61e67fbaf8","size":3408729}]],"step2:0":[[{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:97a548f8d65d9ab617f608dd621f59e0d43a3b346f34c34eb58da31f00a9b0ad","size":116}]]}}}}} \ No newline at end of file diff --git a/test/testdata/unsigned-test-image/blobs/sha256/c6dd08ccc92ab60a87648a6b61fbf88d9287a936b285a8b4dde8893a1f4ffedf b/test/testdata/unsigned-test-image/blobs/sha256/c6dd08ccc92ab60a87648a6b61fbf88d9287a936b285a8b4dde8893a1f4ffedf new file mode 100644 index 0000000..6d6f8bf --- /dev/null +++ b/test/testdata/unsigned-test-image/blobs/sha256/c6dd08ccc92ab60a87648a6b61fbf88d9287a936b285a8b4dde8893a1f4ffedf @@ -0,0 +1 @@ +{"_type":"https://in-toto.io/Statement/v0.1","predicateType":"https://slsa.dev/provenance/v0.2","subject":[{"name":"pkg:docker/test-image@test?platform=linux%2Famd64","digest":{"sha256":"da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620"}}],"predicate":{"builder":{"id":""},"buildType":"https://mobyproject.org/buildkit@v1","materials":[{"uri":"pkg:docker/docker/buildkit-syft-scanner@stable-1","digest":{"sha256":"176e0869c38aeaede37e594fcf182c91d44391a932e1d71e99ec204873445a33"}},{"uri":"pkg:docker/alpine@latest?platform=linux%2Famd64","digest":{"sha256":"c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b"}}],"invocation":{"configSource":{"entryPoint":"Dockerfile"},"parameters":{"frontend":"dockerfile.v0","locals":[{"name":"context"},{"name":"dockerfile"}]},"environment":{"platform":"linux/amd64"}},"buildConfig":{"llbDefinition":[{"id":"step0","op":{"Op":{"source":{"identifier":"docker-image://docker.io/library/alpine:latest@sha256:c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b"}},"platform":{"Architecture":"amd64","OS":"linux"},"constraints":{}}},{"id":"step1","op":{"Op":{"exec":{"meta":{"args":["/bin/sh","-c","echo \"hello world\" \u003e /tmp/hello.txt"],"env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"cwd":"/","removeMountStubsRecursive":true},"mounts":[{"input":0,"dest":"/","output":0}]}},"platform":{"Architecture":"amd64","OS":"linux"},"constraints":{}},"inputs":["step0:0"]},{"id":"step2","op":{"Op":{"file":{"actions":[{"input":-1,"secondaryInput":0,"output":0,"Action":{"copy":{"src":"/tmp/hello.txt","dest":"/","mode":-1,"followSymlink":true,"dirCopyContents":true,"createDestPath":true,"allowWildcard":true,"allowEmptyWildcard":true,"timestamp":-1}}}]}},"constraints":{}},"inputs":["step1:0"]},{"id":"step3","op":{"Op":null},"inputs":["step2:0"]}],"digestMapping":{"sha256:46a51bd96c5f07c63901007f7fc78b5cbc14d05c2f2b1ec8e206d0f72a8d077a":"step2","sha256:a99a5b91a7644662f368e8bc1c6ca7fad2ea98ce130fd2d2ca648a42e8f9cca9":"step1","sha256:db2976cd1ada912761fd8495e52cdb659606c87e1b2d529926b859b4b7df140c":"step3","sha256:faa2314417184f0f81e21fe46ef9c04da17b8fc0d629ac5f017dd02a596697bb":"step0"}},"metadata":{"buildInvocationID":"jckf4dzdrb4i99ygsshezjtsq","buildStartedOn":"2024-04-29T10:23:45.125886079Z","buildFinishedOn":"2024-04-29T10:23:46.287890106Z","completeness":{"parameters":true,"environment":true,"materials":false},"reproducible":false,"https://mobyproject.org/buildkit@v1#metadata":{"vcs":{"revision":"ba33451b352942e366f12662f2c3a0c8ac54d696","source":"git@github.com:docker/image-signer-verifier.git"},"source":{"locations":{"step0":{"locations":[{"ranges":[{"start":{"line":1},"end":{"line":1}}]}]},"step1":{"locations":[{"ranges":[{"start":{"line":2},"end":{"line":2}}]}]},"step2":{"locations":[{"ranges":[{"start":{"line":5},"end":{"line":5}}]}]}},"infos":[{"filename":"Dockerfile","language":"Dockerfile","data":"RlJPTSBhbHBpbmUgQVMgYnVpbGQKUlVOIGVjaG8gImhlbGxvIHdvcmxkIiA+IC90bXAvaGVsbG8udHh0CgpGUk9NIHNjcmF0Y2gKQ09QWSAtLWZyb209YnVpbGQgL3RtcC9oZWxsby50eHQgLwo=","llbDefinition":[{"id":"step0","op":{"Op":{"source":{"identifier":"local://dockerfile","attrs":{"local.differ":"none","local.followpaths":"[\"Dockerfile\",\"Dockerfile.dockerignore\",\"dockerfile\"]","local.sharedkeyhint":"dockerfile"}}},"constraints":{}}},{"id":"step1","op":{"Op":null},"inputs":["step0:0"]}],"digestMapping":{"sha256:4efcb3fab1b18d9764b436e8f9430f56dd8fee0f811ae064f8ec051e7ac5dec4":"step0","sha256:5c08b537da7192a6909348620c571138948f7874016718afc6d6d4e1569453d3":"step1"}}]},"layers":{"step0:0":[[{"mediaType":"application/vnd.docker.image.rootfs.diff.tar.gzip","digest":"sha256:4abcf20661432fb2d719aaf90656f55c287f8ca915dc1c92ec14ff61e67fbaf8","size":3408729}]],"step2:0":[[{"mediaType":"application/vnd.oci.image.layer.v1.tar+gzip","digest":"sha256:97a548f8d65d9ab617f608dd621f59e0d43a3b346f34c34eb58da31f00a9b0ad","size":116}]]}}}}} \ No newline at end of file diff --git a/test/testdata/unsigned-test-image/blobs/sha256/c9f436179969b60ec0bbd406b1340c501e59376a658b14b53c1828924c0ac668 b/test/testdata/unsigned-test-image/blobs/sha256/c9f436179969b60ec0bbd406b1340c501e59376a658b14b53c1828924c0ac668 new file mode 100644 index 0000000..56780cc --- /dev/null +++ b/test/testdata/unsigned-test-image/blobs/sha256/c9f436179969b60ec0bbd406b1340c501e59376a658b14b53c1828924c0ac668 @@ -0,0 +1 @@ +{"architecture":"unknown","os":"unknown","config":{},"rootfs":{"type":"layers","diff_ids":["sha256:da5651e8877b960aa30f32f317fbeba28f5e06f1ce4d3895b3b8770140280a2e","sha256:5171425b78a2aedb43eb4e95083e64d3764c798507596ceded776c4ab038c224"]}} \ No newline at end of file diff --git a/test/testdata/unsigned-test-image/blobs/sha256/d85d624a324422194b43cccd975b5752cf0acaedd668bb525fcd40c3587cc460 b/test/testdata/unsigned-test-image/blobs/sha256/d85d624a324422194b43cccd975b5752cf0acaedd668bb525fcd40c3587cc460 new file mode 100644 index 0000000..e37f3ea --- /dev/null +++ b/test/testdata/unsigned-test-image/blobs/sha256/d85d624a324422194b43cccd975b5752cf0acaedd668bb525fcd40c3587cc460 @@ -0,0 +1 @@ +{"architecture":"arm64","config":{"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"WorkingDir":"/","OnBuild":null},"created":"2024-03-08T16:42:30.065465358Z","history":[{"created":"2024-03-08T16:42:30.065465358Z","created_by":"COPY /tmp/hello.txt / # buildkit","comment":"buildkit.dockerfile.v0"}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:b842af8c2f1451ffc802ae4139819eaea8441223357642548d8a25ab5c52cff7"]}} \ No newline at end of file diff --git a/test/testdata/unsigned-test-image/blobs/sha256/da5651e8877b960aa30f32f317fbeba28f5e06f1ce4d3895b3b8770140280a2e b/test/testdata/unsigned-test-image/blobs/sha256/da5651e8877b960aa30f32f317fbeba28f5e06f1ce4d3895b3b8770140280a2e new file mode 100644 index 0000000..c18e28f --- /dev/null +++ b/test/testdata/unsigned-test-image/blobs/sha256/da5651e8877b960aa30f32f317fbeba28f5e06f1ce4d3895b3b8770140280a2e @@ -0,0 +1 @@ +{"_type":"https://in-toto.io/Statement/v0.1","predicateType":"https://spdx.dev/Document","subject":[{"name":"pkg:docker/test-image@test?platform=linux%2Farm64","digest":{"sha256":"7a76cec943853f9f7105b1976afa1bf7cd5bb6afc4e9d5852dd8da7cf81ae86e"}}],"predicate":{"spdxVersion":"SPDX-2.3","dataLicense":"CC0-1.0","SPDXID":"SPDXRef-DOCUMENT","name":"sbom","documentNamespace":"https://anchore.com/syft/dir/sbom-6d900ae6-587d-4695-9c01-511801a85b65","creationInfo":{"licenseListVersion":"3.23","creators":["Organization: Anchore, Inc","Tool: syft-v0.105.0","Tool: buildkit-v0.12.4"],"created":"2024-03-08T16:42:30Z"},"packages":[{"name":"sbom","SPDXID":"SPDXRef-DocumentRoot-Directory-sbom","supplier":"NOASSERTION","downloadLocation":"NOASSERTION","filesAnalyzed":false,"primaryPackagePurpose":"FILE"}],"relationships":[{"spdxElementId":"SPDXRef-DOCUMENT","relatedSpdxElement":"SPDXRef-DocumentRoot-Directory-sbom","relationshipType":"DESCRIBES"}]}} \ No newline at end of file diff --git a/test/testdata/unsigned-test-image/blobs/sha256/da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620 b/test/testdata/unsigned-test-image/blobs/sha256/da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620 new file mode 100644 index 0000000..e68961b --- /dev/null +++ b/test/testdata/unsigned-test-image/blobs/sha256/da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620 @@ -0,0 +1,16 @@ +{ + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "config": { + "mediaType": "application/vnd.oci.image.config.v1+json", + "digest": "sha256:1c70b3e7c3a57801501ec127aa6c918c390c373294ec4fc48f2c6fe703fcc6fe", + "size": 453 + }, + "layers": [ + { + "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip", + "digest": "sha256:97a548f8d65d9ab617f608dd621f59e0d43a3b346f34c34eb58da31f00a9b0ad", + "size": 116 + } + ] +} \ No newline at end of file diff --git a/test/testdata/unsigned-test-image/blobs/sha256/db8f2a6e112ea6396f57d073269ecfac61e8dcdad3a4a643dcb577522492f898 b/test/testdata/unsigned-test-image/blobs/sha256/db8f2a6e112ea6396f57d073269ecfac61e8dcdad3a4a643dcb577522492f898 new file mode 100644 index 0000000..2500f81 --- /dev/null +++ b/test/testdata/unsigned-test-image/blobs/sha256/db8f2a6e112ea6396f57d073269ecfac61e8dcdad3a4a643dcb577522492f898 @@ -0,0 +1,50 @@ +{ + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.index.v1+json", + "manifests": [ + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620", + "size": 476, + "platform": { + "architecture": "amd64", + "os": "linux" + } + }, + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:7a76cec943853f9f7105b1976afa1bf7cd5bb6afc4e9d5852dd8da7cf81ae86e", + "size": 476, + "platform": { + "architecture": "arm64", + "os": "linux" + } + }, + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:26da286bbc886aa14d191808db8fcbbd5d8ec68cf0047f954133e76d8e73d71c", + "size": 836, + "annotations": { + "vnd.docker.reference.digest": "sha256:da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620", + "vnd.docker.reference.type": "attestation-manifest" + }, + "platform": { + "architecture": "unknown", + "os": "unknown" + } + }, + { + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "digest": "sha256:e0a9b9404ac2691b9b1c9ef217f22bb1e106efd5ee791640411764e1cf39ea2c", + "size": 836, + "annotations": { + "vnd.docker.reference.digest": "sha256:7a76cec943853f9f7105b1976afa1bf7cd5bb6afc4e9d5852dd8da7cf81ae86e", + "vnd.docker.reference.type": "attestation-manifest" + }, + "platform": { + "architecture": "unknown", + "os": "unknown" + } + } + ] +} \ No newline at end of file diff --git a/test/testdata/unsigned-test-image/blobs/sha256/e0a9b9404ac2691b9b1c9ef217f22bb1e106efd5ee791640411764e1cf39ea2c b/test/testdata/unsigned-test-image/blobs/sha256/e0a9b9404ac2691b9b1c9ef217f22bb1e106efd5ee791640411764e1cf39ea2c new file mode 100644 index 0000000..ac75840 --- /dev/null +++ b/test/testdata/unsigned-test-image/blobs/sha256/e0a9b9404ac2691b9b1c9ef217f22bb1e106efd5ee791640411764e1cf39ea2c @@ -0,0 +1,27 @@ +{ + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "config": { + "mediaType": "application/vnd.oci.image.config.v1+json", + "digest": "sha256:a4cf4b24f3fa8cd49a59e8fd4ef5ce285f0aa928d2651f7ec3d5a78276249dec", + "size": 241 + }, + "layers": [ + { + "mediaType": "application/vnd.in-toto+json", + "digest": "sha256:da5651e8877b960aa30f32f317fbeba28f5e06f1ce4d3895b3b8770140280a2e", + "size": 946, + "annotations": { + "in-toto.io/predicate-type": "https://spdx.dev/Document" + } + }, + { + "mediaType": "application/vnd.in-toto+json", + "digest": "sha256:371954672cfaa92735d6fbd70a787aac618a41d4c8ec8d6e12bd12d0cc601706", + "size": 3944, + "annotations": { + "in-toto.io/predicate-type": "https://slsa.dev/provenance/v0.2" + } + } + ] +} \ No newline at end of file diff --git a/test/testdata/unsigned-test-image/blobs/sha256/f2b95cecafef9c22a5d059fac8f20e3645a45370e52abf9581dd4eedd152fce0 b/test/testdata/unsigned-test-image/blobs/sha256/f2b95cecafef9c22a5d059fac8f20e3645a45370e52abf9581dd4eedd152fce0 new file mode 100644 index 0000000..b55918a --- /dev/null +++ b/test/testdata/unsigned-test-image/blobs/sha256/f2b95cecafef9c22a5d059fac8f20e3645a45370e52abf9581dd4eedd152fce0 @@ -0,0 +1,27 @@ +{ + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "config": { + "mediaType": "application/vnd.oci.image.config.v1+json", + "digest": "sha256:c9f436179969b60ec0bbd406b1340c501e59376a658b14b53c1828924c0ac668", + "size": 241 + }, + "layers": [ + { + "mediaType": "application/vnd.in-toto+json", + "digest": "sha256:da5651e8877b960aa30f32f317fbeba28f5e06f1ce4d3895b3b8770140280a2e", + "size": 946, + "annotations": { + "in-toto.io/predicate-type": "https://spdx.dev/Document" + } + }, + { + "mediaType": "application/vnd.in-toto+json", + "digest": "sha256:5171425b78a2aedb43eb4e95083e64d3764c798507596ceded776c4ab038c224", + "size": 3944, + "annotations": { + "in-toto.io/predicate-type": "https://slsa.dev/provenance/v0.2" + } + } + ] +} \ No newline at end of file diff --git a/test/testdata/unsigned-test-image/blobs/sha256/f634c4c53b03bf8ff917b61165631fda0cfe691a383e7b333269a53bf9a79c34 b/test/testdata/unsigned-test-image/blobs/sha256/f634c4c53b03bf8ff917b61165631fda0cfe691a383e7b333269a53bf9a79c34 new file mode 100644 index 0000000..70ff6e9 --- /dev/null +++ b/test/testdata/unsigned-test-image/blobs/sha256/f634c4c53b03bf8ff917b61165631fda0cfe691a383e7b333269a53bf9a79c34 @@ -0,0 +1 @@ +{"architecture":"unknown","os":"unknown","config":{},"rootfs":{"type":"layers","diff_ids":["sha256:da5651e8877b960aa30f32f317fbeba28f5e06f1ce4d3895b3b8770140280a2e","sha256:9fe102c03d71d47a24cd7fc7db8e7affc05fd9bf98eb027038b7daf176861e85"]}} \ No newline at end of file diff --git a/test/testdata/unsigned-test-image/blobs/sha256/fed2c8841731e2cf1ceb53c49c6440fcd6d565a8658141914a8a07c127e00d7e b/test/testdata/unsigned-test-image/blobs/sha256/fed2c8841731e2cf1ceb53c49c6440fcd6d565a8658141914a8a07c127e00d7e new file mode 100644 index 0000000..f04ad30 --- /dev/null +++ b/test/testdata/unsigned-test-image/blobs/sha256/fed2c8841731e2cf1ceb53c49c6440fcd6d565a8658141914a8a07c127e00d7e @@ -0,0 +1 @@ +{"architecture":"unknown","os":"unknown","config":{},"rootfs":{"type":"layers","diff_ids":["sha256:da5651e8877b960aa30f32f317fbeba28f5e06f1ce4d3895b3b8770140280a2e","sha256:92d3311aa91737ff81e2a4c8e269e78c3c95df611b44580426c384d3f5057776"]}} \ No newline at end of file diff --git a/test/testdata/unsigned-test-image/index.json b/test/testdata/unsigned-test-image/index.json new file mode 100644 index 0000000..026629c --- /dev/null +++ b/test/testdata/unsigned-test-image/index.json @@ -0,0 +1 @@ +{"schemaVersion":2,"manifests":[{"mediaType":"application/vnd.oci.image.index.v1+json","digest":"sha256:db8f2a6e112ea6396f57d073269ecfac61e8dcdad3a4a643dcb577522492f898","size":1607,"annotations":{"org.opencontainers.image.created":"2024-04-29T10:23:46Z","org.opencontainers.image.ref.name":"docker.io/library/test-image:test"}}]} \ No newline at end of file diff --git a/test/testdata/unsigned-test-image/oci-layout b/test/testdata/unsigned-test-image/oci-layout new file mode 100644 index 0000000..1343d37 --- /dev/null +++ b/test/testdata/unsigned-test-image/oci-layout @@ -0,0 +1 @@ +{"imageLayoutVersion":"1.0.0"} \ No newline at end of file