Support images as well as indexes in ImageDetailResolvers (#183)

* build: Generate test data for unsigned and no provenance image indexes
* feat: Add function to build index without SBOM or provenance for linux/amd64 platform
* feat: add build_image function to build image without SBOM or provenance for linux/amd64
* feat: Rename NO_SBOM_NO_PROVENANCE_INDEX_DIR to UNSIGNED_IMAGE_DIR
* feat: support images in details resolvers
This commit is contained in:
James Carnegie
2024-09-30 20:53:13 +01:00
committed by GitHub
parent 5e16b97e02
commit c0510fb76c
78 changed files with 159 additions and 86 deletions

View File

@@ -12,7 +12,7 @@ import (
const ExpectedStatements = 4
func TestExtractAnnotatedStatements(t *testing.T) {
statements, err := attestation.ExtractAnnotatedStatements(test.UnsignedTestImage(".."), intoto.PayloadType)
statements, err := attestation.ExtractAnnotatedStatements(test.UnsignedTestIndex(".."), intoto.PayloadType)
assert.NoError(t, err)
assert.Equalf(t, len(statements), ExpectedStatements, "expected %d statement, got %d", ExpectedStatements, len(statements))
}

View File

@@ -31,7 +31,7 @@ func ExampleManifest() {
ref := "docker/image-signer-verifier:latest"
digest, err := v1.NewHash("sha256:da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620")
digest, err := v1.NewHash("sha256:7ae6b41655929ad8e1848064874a98ac3f68884996c79907f6525e3045f75390")
if err != nil {
panic(err)
}

View File

@@ -14,6 +14,9 @@ import (
)
// implementation of Resolver that closes over attestations from an oci layout.
var _ Resolver = (*LayoutResolver)(nil)
type LayoutResolver struct {
*Manifest
*oci.ImageSpec
@@ -86,38 +89,49 @@ func (r *LayoutResolver) ImagePlatform(_ context.Context) (*v1.Platform, error)
}
func manifestFromOCILayout(path string, platform *v1.Platform) (*Manifest, error) {
idx, err := layout.ImageIndexFromPath(path)
layoutIndex, err := layout.ImageIndexFromPath(path)
if err != nil {
return nil, err
}
idxm, err := idx.IndexManifest()
layoutIndexManifest, err := layoutIndex.IndexManifest()
if err != nil {
return nil, fmt.Errorf("failed to get digest: %w", err)
}
idxDescriptor := idxm.Manifests[0]
idxDigest := idxDescriptor.Digest
subjectName := idxDescriptor.Annotations[ocispec.AnnotationRefName]
layoutDescriptor := layoutIndexManifest.Manifests[0]
layoutDescriptorDigest := layoutDescriptor.Digest
subjectName := layoutDescriptor.Annotations[ocispec.AnnotationRefName]
if _, err := reference.ParseNamed(subjectName); err != nil {
// try the containerd annotation if the org.opencontainers.image.ref.name is not a full name
subjectName = idxDescriptor.Annotations[containerd.AnnotationImageName]
subjectName = layoutDescriptor.Annotations[containerd.AnnotationImageName]
if _, err := reference.ParseNamed(subjectName); err != nil {
return nil, fmt.Errorf("failed to find subject name in annotations")
}
}
mfs, err := idx.ImageIndex(idxDigest)
if err != nil {
return nil, fmt.Errorf("failed to extract ImageIndex for digest %s: %w", idxDigest.String(), err)
// check if digest refers to an image or an index
_, err = layoutIndex.Image(layoutDescriptorDigest)
if err == nil {
return &Manifest{
OriginalLayers: nil,
OriginalDescriptor: nil,
SubjectName: subjectName,
SubjectDescriptor: &layoutDescriptor,
}, nil
}
mfs2, err := mfs.IndexManifest()
subjectIndex, err := layoutIndex.ImageIndex(layoutDescriptorDigest)
if err != nil {
return nil, fmt.Errorf("failed to extract ImageIndex for digest %s: %w", layoutDescriptorDigest.String(), err)
}
subjectIndexManifest, err := subjectIndex.IndexManifest()
if err != nil {
return nil, fmt.Errorf("failed to extract IndexManifest from ImageIndex: %w", err)
}
var subjectDescriptor *v1.Descriptor
for i := range mfs2.Manifests {
manifest := &mfs2.Manifests[i]
for i := range subjectIndexManifest.Manifests {
manifest := &subjectIndexManifest.Manifests[i]
if manifest.Platform != nil {
if manifest.Platform.Equals(*platform) {
subjectDescriptor = manifest
@@ -128,8 +142,8 @@ func manifestFromOCILayout(path string, platform *v1.Platform) (*Manifest, error
if subjectDescriptor == nil {
return nil, fmt.Errorf("platform not found in index")
}
for i := range mfs2.Manifests {
mf := &mfs2.Manifests[i]
for i := range subjectIndexManifest.Manifests {
mf := &subjectIndexManifest.Manifests[i]
if mf.Annotations[DockerReferenceType] != AttestationManifestType {
continue
}
@@ -138,7 +152,7 @@ func manifestFromOCILayout(path string, platform *v1.Platform) (*Manifest, error
continue
}
attestationImage, err := mfs.Image(mf.Digest)
attestationImage, err := subjectIndex.Image(mf.Digest)
if err != nil {
return nil, fmt.Errorf("failed to extract attestation image with digest %s: %w", mf.Digest.String(), err)
}

View File

@@ -1,6 +1,7 @@
package attestation_test
import (
"context"
"path/filepath"
"strings"
"testing"
@@ -25,7 +26,7 @@ func TestAttestationFromOCILayout(t *testing.T) {
}
opts := &attestation.SigningOptions{}
attIdx, err := oci.IndexFromPath(test.UnsignedTestImage(".."))
attIdx, err := oci.IndexFromPath(test.UnsignedTestIndex(".."))
require.NoError(t, err)
signedManifests, err := attest.SignStatements(ctx, attIdx.Index, signer, opts)
require.NoError(t, err)
@@ -74,7 +75,7 @@ func TestSubjectNameAnnotations(t *testing.T) {
ociLayoutPath string
errorStr string
}{
{name: "oci annotation", ociLayoutPath: test.UnsignedTestImage("..")},
{name: "oci annotation", ociLayoutPath: test.UnsignedTestIndex("..")},
{name: "containerd annotation", ociLayoutPath: filepath.Join("..", "test", "testdata", "containerd-subject-layout")},
{name: "missing subject name", ociLayoutPath: filepath.Join("..", "test", "testdata", "missing-subject-layout"), errorStr: "failed to find subject name in annotations"},
}
@@ -93,3 +94,14 @@ func TestSubjectNameAnnotations(t *testing.T) {
})
}
}
func TestImageDetailsFromImageLayout(t *testing.T) {
spec, err := oci.ParseImageSpec(oci.LocalPrefix+test.UnsignedTestImage(".."), oci.WithPlatform("linux/arm64"))
require.NoError(t, err)
resolver, err := policy.CreateImageDetailsResolver(spec)
require.NoError(t, err)
desc, err := resolver.ImageDescriptor(context.Background())
require.NoError(t, err)
digest := desc.Digest.String()
assert.Equal(t, "sha256:7ae6b41655929ad8e1848064874a98ac3f68884996c79907f6525e3045f75390", digest)
}

View File

@@ -3,6 +3,7 @@ package attestation
import (
"context"
"github.com/docker/attest/internal/test"
"github.com/docker/attest/oci"
v1 "github.com/google/go-containerregistry/pkg/v1"
)
@@ -36,7 +37,7 @@ func (r MockResolver) ImageDescriptor(_ context.Context) (*v1.Descriptor, error)
if r.DescriptorFn != nil {
return r.DescriptorFn()
}
digest, err := v1.NewHash("sha256:da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620")
digest, err := v1.NewHash(test.UnsignedLinuxAMD64ImageDigest)
if err != nil {
return nil, err
}

View File

@@ -89,7 +89,7 @@ func TestAttestationReferenceTypes(t *testing.T) {
require.NoError(t, err)
opts := &attestation.SigningOptions{}
attIdx, err := oci.IndexFromPath(test.UnsignedTestImage(".."))
attIdx, err := oci.IndexFromPath(test.UnsignedTestIndex(".."))
require.NoError(t, err)
indexName := fmt.Sprintf("%s/repo:root", u.Host)
@@ -209,7 +209,7 @@ func TestReferencesInDifferentRepo(t *testing.T) {
require.NoError(t, err)
opts := &attestation.SigningOptions{}
attIdx, err := oci.IndexFromPath(test.UnsignedTestImage(".."))
attIdx, err := oci.IndexFromPath(test.UnsignedTestIndex(".."))
require.NoError(t, err)
indexName := fmt.Sprintf("%s/%s:latest", serverURL.Host, repoName)
@@ -233,7 +233,7 @@ func TestReferencesInDifferentRepo(t *testing.T) {
require.NoError(t, err)
opts := &attestation.SigningOptions{}
attIdx, err := oci.IndexFromPath(test.UnsignedTestImage(".."))
attIdx, err := oci.IndexFromPath(test.UnsignedTestIndex(".."))
require.NoError(t, err)
indexName := fmt.Sprintf("%s/%s:latest", serverURL.Host, repoName)
@@ -286,7 +286,7 @@ func TestCorrectArtifactTypeInTagFallback(t *testing.T) {
repoName := "repo"
opts := &attestation.SigningOptions{}
attIdx, err := oci.IndexFromPath(test.UnsignedTestImage(".."))
attIdx, err := oci.IndexFromPath(test.UnsignedTestIndex(".."))
require.NoError(t, err)
indexName := fmt.Sprintf("%s/%s:latest", serverURL.Host, repoName)

View File

@@ -24,7 +24,7 @@ func TestRegistry(t *testing.T) {
require.NoError(t, err)
opts := &attestation.SigningOptions{}
attIdx, err := oci.IndexFromPath(test.UnsignedTestImage(".."))
attIdx, err := oci.IndexFromPath(test.UnsignedTestIndex(".."))
require.NoError(t, err)
signedManifests, err := attest.SignStatements(ctx, attIdx.Index, signer, opts)
require.NoError(t, err)
@@ -46,4 +46,14 @@ func TestRegistry(t *testing.T) {
require.NoError(t, err)
digest := desc.Digest.String()
assert.True(t, strings.Contains(digest, "sha256:"))
// resolver also works with platform specific digest
spec, err = oci.ParseImageSpec(fmt.Sprintf("%s@%s", indexName, digest))
require.NoError(t, err)
resolver, err = policy.CreateImageDetailsResolver(spec)
require.NoError(t, err)
desc, err = resolver.ImageDescriptor(ctx)
require.NoError(t, err)
assert.Equal(t, desc.Digest.String(), digest)
}

View File

@@ -249,7 +249,7 @@ func TestSimpleStatementSigning(t *testing.T) {
PredicateType: attestation.VSAPredicateType,
},
}
digest, err := v1.NewHash("sha256:da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620")
digest, err := v1.NewHash(test.UnsignedLinuxAMD64ImageDigest)
require.NoError(t, err)
subject := &v1.Descriptor{
MediaType: "application/vnd.oci.image.manifest.v1+json",

View File

@@ -23,14 +23,20 @@ import (
)
const (
UseMockKMS = true
AWSRegion = "us-east-1"
AWSKMSKeyARN = "arn:aws:kms:us-east-1:175142243308:alias/doi-signing" // sandbox
UseMockKMS = true
AWSRegion = "us-east-1"
AWSKMSKeyARN = "arn:aws:kms:us-east-1:175142243308:alias/doi-signing" // sandbox
UnsignedLinuxAMD64ImageDigest = "sha256:da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620"
UnsignedLinuxArm64ImageDigest = "sha256:7a76cec943853f9f7105b1976afa1bf7cd5bb6afc4e9d5852dd8da7cf81ae86e"
)
func UnsignedTestIndex(rel ...string) string {
rel = append(rel, "test", "testdata", "unsigned-index")
return filepath.Join(rel...)
}
func UnsignedTestImage(rel ...string) string {
rel = append(rel, "test", "testdata", "unsigned-test-image")
rel = append(rel, "test", "testdata", "unsigned-image")
return filepath.Join(rel...)
}

View File

@@ -12,7 +12,7 @@ import (
)
func TestRegistryAuth(t *testing.T) {
attIdx, err := oci.IndexFromPath(test.UnsignedTestImage(".."))
attIdx, err := oci.IndexFromPath(test.UnsignedTestIndex(".."))
require.NoError(t, err)
// test cases for ecr, gcr and dockerhub
testCases := []struct {

View File

@@ -67,7 +67,7 @@ func TestRefToPurl(t *testing.T) {
// Test fix for https://github.com/docker/secure-artifacts-team-issues/issues/202
func TestImageDigestForPlatform(t *testing.T) {
idx, err := layout.ImageIndexFromPath(test.UnsignedTestImage(".."))
idx, err := layout.ImageIndexFromPath(test.UnsignedTestIndex(".."))
assert.NoError(t, err)
idxm, err := idx.IndexManifest()
@@ -86,14 +86,14 @@ func TestImageDigestForPlatform(t *testing.T) {
desc, err := oci.ImageDescriptor(mfs2, p)
assert.NoError(t, err)
digest := desc.Digest.String()
assert.Equal(t, "sha256:da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620", digest)
assert.Equal(t, test.UnsignedLinuxAMD64ImageDigest, digest)
p, err = oci.ParsePlatform("linux/arm64")
assert.NoError(t, err)
desc, err = oci.ImageDescriptor(mfs2, p)
assert.NoError(t, err)
digest = desc.Digest.String()
assert.Equal(t, "sha256:7a76cec943853f9f7105b1976afa1bf7cd5bb6afc4e9d5852dd8da7cf81ae86e", digest)
assert.Equal(t, test.UnsignedLinuxArm64ImageDigest, digest)
}
func TestWithoutTag(t *testing.T) {

View File

@@ -18,7 +18,7 @@ import (
func TestSavingIndex(t *testing.T) {
outputLayout := test.CreateTempDir(t, "", "mirror-test")
attIdx, err := oci.IndexFromPath(test.UnsignedTestImage(".."))
attIdx, err := oci.IndexFromPath(test.UnsignedTestIndex(".."))
require.NoError(t, err)
ctx := context.Background()
@@ -73,7 +73,7 @@ func TestSavingReferrers(t *testing.T) {
},
}
digest, err := v1.NewHash("sha256:da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620")
digest, err := v1.NewHash(test.UnsignedLinuxAMD64ImageDigest)
require.NoError(t, err)
subject := &v1.Descriptor{
MediaType: "application/vnd.oci.image.manifest.v1+json",

View File

@@ -5,6 +5,7 @@ import (
"fmt"
"os"
"path/filepath"
"strings"
"testing"
"github.com/docker/attest/attestation"
@@ -357,6 +358,7 @@ func TestVerifySubject(t *testing.T) {
},
}
digestHex := strings.TrimPrefix(test.UnsignedLinuxAMD64ImageDigest, "sha256:")
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
defaultResolver.Image = tc.img
@@ -365,7 +367,7 @@ func TestVerifySubject(t *testing.T) {
return &v1.Platform{Architecture: "amd64", OS: "linux"}, nil
}
// digest from mock resolver
tc.subject[0].Digest = map[string]string{"sha256": "da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620"}
tc.subject[0].Digest = map[string]string{"sha256": digestHex}
if tc.digest != "" {
tc.subject[0].Digest = map[string]string{"sha256": tc.digest}
}
@@ -381,7 +383,7 @@ func TestVerifySubject(t *testing.T) {
subject := []intoto.Subject{
{
Name: "pkg:docker/alpine@latest?platform=linux%2Famd64",
Digest: map[string]string{"sha256": "da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620"},
Digest: map[string]string{"sha256": digestHex},
},
}

View File

@@ -10,36 +10,45 @@ function check_command () {
function cleanup_testdata () {
echo "Cleaning up existing testdata..."
rm -rf "${TESTDATA_PATH:?}/${UNSIGNED_INDEX_DIR:?}"
rm -rf "${TESTDATA_PATH:?}/${NO_PROVENANCE_INDEX_DIR:?}"
rm -rf "${TESTDATA_PATH:?}/${UNSIGNED_IMAGE_DIR:?}"
rm -rf "${TESTDATA_PATH:?}/${NO_PROVENANCE_IMAGE_DIR:?}"
}
function build_unsigned_image () {
function build_unsigned_index () {
echo "Building $UNSIGNED_INDEX_DIR..."
docker buildx build "$TEST_INDEX_DOCKERFILE_PATH" --sbom true --provenance true --platform linux/amd64,linux/arm64 \
--output type=oci,tar=false,name="$TEST_INDEX_REPO:$TEST_INDEX_TAG",dest="$TESTDATA_PATH/$UNSIGNED_INDEX_DIR"
}
function build_no_provenance_index () {
echo "Building unsigned $NO_PROVENANCE_INDEX_DIR..."
docker buildx build "$TEST_INDEX_DOCKERFILE_PATH" --sbom true --provenance false --platform linux/amd64,linux/arm64 \
--output type=oci,tar=false,name="$TEST_INDEX_REPO:$TEST_INDEX_TAG",dest="$TESTDATA_PATH/$NO_PROVENANCE_INDEX_DIR"
}
function build_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"
docker buildx build "$TEST_INDEX_DOCKERFILE_PATH" --sbom false --provenance false --platform linux/amd64 \
--output type=oci,tar=false,name="$TEST_INDEX_REPO:$TEST_INDEX_TAG",dest="$TESTDATA_PATH/$UNSIGNED_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"
TEST_INDEX_DOCKERFILE_PATH="../test"
TEST_INDEX_REPO="test-image"
TEST_INDEX_TAG="test"
UNSIGNED_INDEX_DIR="unsigned-index"
NO_PROVENANCE_INDEX_DIR="no-provenance-index"
UNSIGNED_IMAGE_DIR="unsigned-image"
ATTESTATION_PAYLOADTYPE="application/vnd.in-toto+json"
# Run steps
cleanup_testdata
build_unsigned_image
build_no_provenance_image
build_unsigned_index
build_no_provenance_index
build_image
echo "Process completed successfully."

View File

@@ -15,7 +15,7 @@ import (
)
var (
NoProvenanceImage = filepath.Join("test", "testdata", "no-provenance-image")
NoProvenanceImage = filepath.Join("test", "testdata", "no-provenance-index")
PassPolicyDir = filepath.Join("test", "testdata", "local-policy-pass")
PassMirrorPolicyDir = filepath.Join("test", "testdata", "local-policy-mirror")
PassNoTLPolicyDir = filepath.Join("test", "testdata", "local-policy-no-tl")
@@ -35,8 +35,8 @@ func TestSignVerifyOCILayout(t *testing.T) {
expectedAttestations int
replace bool
}{
{"signed replaced", test.UnsignedTestImage(), 0, 4, true},
{"without replace", test.UnsignedTestImage(), 4, 4, false},
{"signed replaced", test.UnsignedTestIndex(), 0, 4, true},
{"without replace", test.UnsignedTestIndex(), 4, 4, false},
// image without provenance doesn't fail
{"no provenance (replace)", NoProvenanceImage, 0, 2, true},
{"no provenance (no replace)", NoProvenanceImage, 2, 2, false},

View File

@@ -1 +0,0 @@
{"architecture":"unknown","os":"unknown","config":{},"rootfs":{"type":"layers","diff_ids":["sha256:da5651e8877b960aa30f32f317fbeba28f5e06f1ce4d3895b3b8770140280a2e"]}}

View File

@@ -1 +0,0 @@
{"architecture":"unknown","os":"unknown","config":{},"rootfs":{"type":"layers","diff_ids":["sha256:a9646604f9522bf59d203a86ac5c2354a573ea041b8846409c4fc0f8c4a70850"]}}

View File

@@ -1 +0,0 @@
{"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"}}]}

View File

@@ -3,13 +3,13 @@
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"config": {
"mediaType": "application/vnd.oci.image.config.v1+json",
"digest": "sha256:b6ef78de3633e45d1c08019fbabb4464fabd6dd32e82c67ea2b2a3c4e8bacdf5",
"digest": "sha256:bb0ed50656ccdb2eb114407de579554426777d6dc0e4206a6f746afb4ee5237e",
"size": 167
},
"layers": [
{
"mediaType": "application/vnd.in-toto+json",
"digest": "sha256:a9646604f9522bf59d203a86ac5c2354a573ea041b8846409c4fc0f8c4a70850",
"digest": "sha256:618f1e2f903648dde23cc38dc0ed7eed83d5394a6902bb7bfae8fa707c2e5c33",
"size": 946,
"annotations": {
"in-toto.io/predicate-type": "https://spdx.dev/Document"

View File

@@ -3,13 +3,13 @@
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"config": {
"mediaType": "application/vnd.oci.image.config.v1+json",
"digest": "sha256:2e82727457f04f320b643cb6e13bcbafb8e0dc0adc0443f1a25666f9518c5071",
"digest": "sha256:816b20ea86474dcfb2906ffaf4410262dfcb0d49fdfb60698775f7bc10aad7fb",
"size": 167
},
"layers": [
{
"mediaType": "application/vnd.in-toto+json",
"digest": "sha256:da5651e8877b960aa30f32f317fbeba28f5e06f1ce4d3895b3b8770140280a2e",
"digest": "sha256:f0dac65dd0ff6a656c419c654ac672c38029a3f1a4b4acce062bd2f5a923ffae",
"size": 946,
"annotations": {
"in-toto.io/predicate-type": "https://spdx.dev/Document"

View File

@@ -4,7 +4,7 @@
"manifests": [
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620",
"digest": "sha256:7ae6b41655929ad8e1848064874a98ac3f68884996c79907f6525e3045f75390",
"size": 476,
"platform": {
"architecture": "amd64",
@@ -13,7 +13,7 @@
},
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:7a76cec943853f9f7105b1976afa1bf7cd5bb6afc4e9d5852dd8da7cf81ae86e",
"digest": "sha256:52f7a760b9322aa1af76d998763868b7d1bfec2331a2574a438ef44c92c0c46d",
"size": 476,
"platform": {
"architecture": "arm64",
@@ -22,10 +22,10 @@
},
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:2aaebbb079957470e7c0adddbb054b2b4c01f717d408efba753da2bf6e8905da",
"digest": "sha256:059eea09507d0f904b8892ee59fcd3ddec1a637fc40fb7c83c432c6ff27e2f91",
"size": 558,
"annotations": {
"vnd.docker.reference.digest": "sha256:da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620",
"vnd.docker.reference.digest": "sha256:7ae6b41655929ad8e1848064874a98ac3f68884996c79907f6525e3045f75390",
"vnd.docker.reference.type": "attestation-manifest"
},
"platform": {
@@ -35,10 +35,10 @@
},
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:9b009d6b84b1ed941070b3f919823446286a674ad669d0baa8ab2c358aeb3a82",
"digest": "sha256:0b1ee0f360b073d2f76ceed15a63e291659fbcc6c3caf3be39e437d8344b520e",
"size": 558,
"annotations": {
"vnd.docker.reference.digest": "sha256:7a76cec943853f9f7105b1976afa1bf7cd5bb6afc4e9d5852dd8da7cf81ae86e",
"vnd.docker.reference.digest": "sha256:52f7a760b9322aa1af76d998763868b7d1bfec2331a2574a438ef44c92c0c46d",
"vnd.docker.reference.type": "attestation-manifest"
},
"platform": {

View File

@@ -0,0 +1 @@
{"architecture":"amd64","config":{"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"WorkingDir":"/"},"created":"2024-09-27T16:10:13.292759474Z","history":[{"created":"2024-09-27T16:10:13.292759474Z","created_by":"COPY /tmp/hello.txt / # buildkit","comment":"buildkit.dockerfile.v0"}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:81a78ab7aa0b72d665a9c203b4c30f0423e434b789ed95b2d418e60a1b726470"]}}

View File

@@ -3,13 +3,13 @@
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"config": {
"mediaType": "application/vnd.oci.image.config.v1+json",
"digest": "sha256:d85d624a324422194b43cccd975b5752cf0acaedd668bb525fcd40c3587cc460",
"size": 453
"digest": "sha256:c0bd7799c46e00830b4d7cb8c1f622d14aae81643a90be5ec38c9be4bdd70f6c",
"size": 438
},
"layers": [
{
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
"digest": "sha256:97a548f8d65d9ab617f608dd621f59e0d43a3b346f34c34eb58da31f00a9b0ad",
"digest": "sha256:07d9a868932bd092fa0a4c4df943785a7ba9cee12dbf446d02488319a5fbf336",
"size": 116
}
]

View File

@@ -1 +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"}]}}
{"_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":"7ae6b41655929ad8e1848064874a98ac3f68884996c79907f6525e3045f75390"}}],"predicate":{"spdxVersion":"SPDX-2.3","dataLicense":"CC0-1.0","SPDXID":"SPDXRef-DOCUMENT","name":"sbom","documentNamespace":"https://anchore.com/syft/dir/sbom-b92d7d2e-7ffe-4d0a-8194-9af68e80e169","creationInfo":{"licenseListVersion":"3.23","creators":["Organization: Anchore, Inc","Tool: syft-v0.105.0","Tool: buildkit-v0.15.2"],"created":"2024-09-27T16:10:21Z"},"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"}]}}

View File

@@ -3,13 +3,13 @@
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"config": {
"mediaType": "application/vnd.oci.image.config.v1+json",
"digest": "sha256:1c70b3e7c3a57801501ec127aa6c918c390c373294ec4fc48f2c6fe703fcc6fe",
"size": 453
"digest": "sha256:363133d587b90ff7a21f7b32a96be8422c6799683f0e1e6d71de5c03a82ab35e",
"size": 438
},
"layers": [
{
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
"digest": "sha256:97a548f8d65d9ab617f608dd621f59e0d43a3b346f34c34eb58da31f00a9b0ad",
"digest": "sha256:07d9a868932bd092fa0a4c4df943785a7ba9cee12dbf446d02488319a5fbf336",
"size": 116
}
]

View File

@@ -0,0 +1 @@
{"architecture":"unknown","os":"unknown","config":{},"rootfs":{"type":"layers","diff_ids":["sha256:f0dac65dd0ff6a656c419c654ac672c38029a3f1a4b4acce062bd2f5a923ffae"]}}

View File

@@ -0,0 +1 @@
{"architecture":"unknown","os":"unknown","config":{},"rootfs":{"type":"layers","diff_ids":["sha256:618f1e2f903648dde23cc38dc0ed7eed83d5394a6902bb7bfae8fa707c2e5c33"]}}

View File

@@ -0,0 +1 @@
{"architecture":"arm64","config":{"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"WorkingDir":"/"},"created":"2024-09-27T16:10:13.292759474Z","history":[{"created":"2024-09-27T16:10:13.292759474Z","created_by":"COPY /tmp/hello.txt / # buildkit","comment":"buildkit.dockerfile.v0"}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:81a78ab7aa0b72d665a9c203b4c30f0423e434b789ed95b2d418e60a1b726470"]}}

View File

@@ -1 +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"}]}}
{"_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":"52f7a760b9322aa1af76d998763868b7d1bfec2331a2574a438ef44c92c0c46d"}}],"predicate":{"spdxVersion":"SPDX-2.3","dataLicense":"CC0-1.0","SPDXID":"SPDXRef-DOCUMENT","name":"sbom","documentNamespace":"https://anchore.com/syft/dir/sbom-b92d7d2e-7ffe-4d0a-8194-9af68e80e169","creationInfo":{"licenseListVersion":"3.23","creators":["Organization: Anchore, Inc","Tool: syft-v0.105.0","Tool: buildkit-v0.15.2"],"created":"2024-09-27T16:10:21Z"},"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"}]}}

View File

@@ -0,0 +1 @@
{"schemaVersion":2,"manifests":[{"mediaType":"application/vnd.oci.image.index.v1+json","digest":"sha256:1e3839ac14fba8c5e4db574df2046ce21a9e012e4030305cea97ad3f07f81a4a","size":1607,"annotations":{"org.opencontainers.image.created":"2024-09-27T20:22:06Z","org.opencontainers.image.ref.name":"docker.io/library/test-image:test"}}]}

View File

@@ -0,0 +1 @@
{"architecture":"amd64","config":{"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"WorkingDir":"/"},"created":"2024-09-27T16:10:13.292759474Z","history":[{"created":"2024-09-27T16:10:13.292759474Z","created_by":"COPY /tmp/hello.txt / # buildkit","comment":"buildkit.dockerfile.v0"}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:81a78ab7aa0b72d665a9c203b4c30f0423e434b789ed95b2d418e60a1b726470"]}}

View File

@@ -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:363133d587b90ff7a21f7b32a96be8422c6799683f0e1e6d71de5c03a82ab35e",
"size": 438
},
"layers": [
{
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
"digest": "sha256:07d9a868932bd092fa0a4c4df943785a7ba9cee12dbf446d02488319a5fbf336",
"size": 116
}
]
}

View File

@@ -0,0 +1 @@
{"schemaVersion":2,"manifests":[{"mediaType":"application/vnd.oci.image.manifest.v1+json","digest":"sha256:7ae6b41655929ad8e1848064874a98ac3f68884996c79907f6525e3045f75390","size":476,"annotations":{"org.opencontainers.image.created":"2024-09-27T20:22:07Z","org.opencontainers.image.ref.name":"docker.io/library/test-image:test"},"platform":{"architecture":"amd64","os":"linux"}}]}

View File

@@ -0,0 +1 @@
{"imageLayoutVersion":"1.0.0"}

View File

@@ -1 +0,0 @@
{"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"]}}

View File

@@ -1 +0,0 @@
{"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"]}}

View File

@@ -80,7 +80,7 @@ func TestVSA(t *testing.T) {
opts := &attestation.SigningOptions{
TransparencyLog: tlog.GetMockTL(),
}
attIdx, err := oci.IndexFromPath(test.UnsignedTestImage())
attIdx, err := oci.IndexFromPath(test.UnsignedTestIndex())
assert.NoError(t, err)
signedManifests, err := SignStatements(ctx, attIdx.Index, signer, opts)
require.NoError(t, err)
@@ -106,7 +106,7 @@ func TestVSA(t *testing.T) {
assert.Empty(t, results.Violations)
if assert.NotNil(t, results.Input) {
assert.Equal(t, "sha256:da8b190665956ea07890a0273e2a9c96bfe291662f08e2860e868eef69c34620", results.Input.Digest)
assert.Equal(t, test.UnsignedLinuxAMD64ImageDigest, results.Input.Digest)
assert.NotNil(t, results.Input.Tag)
}
@@ -135,7 +135,7 @@ func TestVerificationFailure(t *testing.T) {
opts := &attestation.SigningOptions{
TransparencyLog: tlog.GetMockTL(),
}
attIdx, err := oci.IndexFromPath(test.UnsignedTestImage())
attIdx, err := oci.IndexFromPath(test.UnsignedTestIndex())
assert.NoError(t, err)
signedManifests, err := SignStatements(ctx, attIdx.Index, signer, opts)
require.NoError(t, err)
@@ -216,7 +216,7 @@ func TestSignVerify(t *testing.T) {
{name: "mirror with verification", signTL: false, policyDir: LocalKeysPolicy, imageName: "mirror.org/library/test-image:test"},
}
attIdx, err := oci.IndexFromPath(test.UnsignedTestImage())
attIdx, err := oci.IndexFromPath(test.UnsignedTestIndex())
assert.NoError(t, err)
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {