feat: support containerd subject annotations
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user