feat: support containerd subject annotations

This commit is contained in:
mrjoelkamp
2024-09-19 14:59:54 -05:00
parent 2ace988b1c
commit fd4e741a1f
78 changed files with 1034 additions and 23 deletions

View File

@@ -5,9 +5,12 @@ import (
"encoding/json"
"fmt"
containerd "github.com/containerd/containerd/v2/core/images"
"github.com/distribution/reference"
"github.com/docker/attest/oci"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/layout"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
)
// implementation of Resolver that closes over attestations from an oci layout.
@@ -95,6 +98,14 @@ func manifestFromOCILayout(path string, platform *v1.Platform) (*Manifest, error
idxDescriptor := idxm.Manifests[0]
idxDigest := idxDescriptor.Digest
subjectName := idxDescriptor.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]
if _, err := reference.ParseNamed(subjectName); err != nil {
return nil, fmt.Errorf("failed to parse subject name from annotations")
}
}
mfs, err := idx.ImageIndex(idxDigest)
if err != nil {
@@ -138,7 +149,7 @@ func manifestFromOCILayout(path string, platform *v1.Platform) (*Manifest, error
attest := &Manifest{
OriginalLayers: layers,
OriginalDescriptor: mf,
SubjectName: idxDescriptor.Annotations["org.opencontainers.image.ref.name"],
SubjectName: subjectName,
SubjectDescriptor: subjectDescriptor,
}
return attest, nil

View File

@@ -1,6 +1,7 @@
package attestation_test
import (
"path/filepath"
"strings"
"testing"
@@ -33,7 +34,7 @@ func TestAttestationFromOCILayout(t *testing.T) {
require.NoError(t, err)
spec, err := oci.ParseImageSpec(oci.LocalPrefix + outputLayout)
require.NoError(t, err)
err = oci.SaveIndex(ctx, []*oci.ImageSpec{spec}, signedIndex, outputLayout)
err = oci.SaveIndex(ctx, []*oci.ImageSpec{spec}, signedIndex, "docker.io/library/test-image:test")
require.NoError(t, err)
testCases := []struct {
@@ -66,3 +67,29 @@ func TestAttestationFromOCILayout(t *testing.T) {
})
}
}
func TestSubjectNameAnnotations(t *testing.T) {
testCases := []struct {
name string
ociLayoutPath string
errorStr string
}{
{name: "oci annotation", ociLayoutPath: test.UnsignedTestImage("..")},
{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 parse subject name from annotations"},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
spec, err := oci.ParseImageSpec(oci.LocalPrefix + tc.ociLayoutPath)
require.NoError(t, err)
_, err = policy.CreateImageDetailsResolver(spec)
if tc.errorStr != "" {
require.Error(t, err)
assert.Contains(t, err.Error(), tc.errorStr)
return
}
require.NoError(t, err)
})
}
}