* fix: standardize casing of initialisms * fix: rename intoto -> inToto and Intoto to InToto * fix: fix all linting errors
142 lines
4.3 KiB
Go
142 lines
4.3 KiB
Go
package oci
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/docker/attest/pkg/attestation"
|
|
att "github.com/docker/attest/pkg/attestation"
|
|
"github.com/google/go-containerregistry/pkg/name"
|
|
v1 "github.com/google/go-containerregistry/pkg/v1"
|
|
"github.com/google/go-containerregistry/pkg/v1/remote"
|
|
)
|
|
|
|
type RegistryResolver struct {
|
|
*RegistryImageDetailsResolver
|
|
*attestation.Manifest
|
|
}
|
|
|
|
type RegistryImageDetailsResolver struct {
|
|
*ImageSpec
|
|
descriptor *v1.Descriptor
|
|
}
|
|
|
|
func NewRegistryImageDetailsResolver(src *ImageSpec) (*RegistryImageDetailsResolver, error) {
|
|
return &RegistryImageDetailsResolver{
|
|
ImageSpec: src,
|
|
}, nil
|
|
}
|
|
|
|
func NewRegistryAttestationResolver(src *RegistryImageDetailsResolver) (*RegistryResolver, error) {
|
|
return &RegistryResolver{
|
|
RegistryImageDetailsResolver: src,
|
|
}, nil
|
|
}
|
|
|
|
func (r *RegistryImageDetailsResolver) ImageName(_ context.Context) (string, error) {
|
|
return r.Identifier, nil
|
|
}
|
|
|
|
func (r *RegistryImageDetailsResolver) ImagePlatform(_ context.Context) (*v1.Platform, error) {
|
|
return r.Platform, nil
|
|
}
|
|
|
|
func (r *RegistryImageDetailsResolver) ImageDescriptor(ctx context.Context) (*v1.Descriptor, error) {
|
|
if r.descriptor == nil {
|
|
subjectRef, err := name.ParseReference(r.Identifier)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to parse reference: %w", err)
|
|
}
|
|
options := WithOptions(ctx, r.Platform)
|
|
image, err := remote.Image(subjectRef, options...)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get image manifest: %w", err)
|
|
}
|
|
digest, err := image.Digest()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get image digest: %w", err)
|
|
}
|
|
size, err := image.Size()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get image size: %w", err)
|
|
}
|
|
mediaType, err := image.MediaType()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get image media type: %w", err)
|
|
}
|
|
r.descriptor = &v1.Descriptor{
|
|
Digest: digest,
|
|
Size: size,
|
|
MediaType: mediaType,
|
|
}
|
|
}
|
|
return r.descriptor, nil
|
|
}
|
|
|
|
func (r *RegistryResolver) Attestations(ctx context.Context, predicateType string) ([]*att.Envelope, error) {
|
|
if r.Manifest == nil {
|
|
attest, err := FetchAttestationManifest(ctx, r.Identifier, r.ImageSpec.Platform)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
r.Manifest = attest
|
|
}
|
|
return ExtractEnvelopes(r.Manifest, predicateType)
|
|
}
|
|
|
|
func FetchAttestationManifest(ctx context.Context, image string, platform *v1.Platform) (*attestation.Manifest, error) {
|
|
// we want to get to the image index, so ignoring platform for now
|
|
options := WithOptions(ctx, nil)
|
|
ref, err := name.ParseReference(image)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to parse reference: %w", err)
|
|
}
|
|
index, err := remote.Index(ref, options...)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get index: %w", err)
|
|
}
|
|
indexManifest, err := index.IndexManifest()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get index manifest: %w", err)
|
|
}
|
|
subjectDescriptor, err := imageDescriptor(indexManifest, platform)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to obtain image for platform: %w", err)
|
|
}
|
|
|
|
digest := subjectDescriptor.Digest.String()
|
|
ref, err = name.ParseReference(fmt.Sprintf("%s@%s", ref.Context().Name(), digest))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to parse attestation reference: %w", err)
|
|
}
|
|
|
|
attestationDigest, err := attestationDigestForDigest(indexManifest, digest, "attestation-manifest")
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to obtain attestation for image: %w", err)
|
|
}
|
|
ref, err = name.ParseReference(fmt.Sprintf("%s@%s", ref.Context().Name(), attestationDigest))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to parse attestation reference: %w", err)
|
|
}
|
|
remoteDescriptor, err := remote.Get(ref, options...)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get attestation: %w", err)
|
|
}
|
|
attestationImage, err := remoteDescriptor.Image()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get attestation image: %w", err)
|
|
}
|
|
|
|
layers, err := attestation.GetAttestationsFromImage(attestationImage)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get attestations from image: %w", err)
|
|
}
|
|
attest := &attestation.Manifest{
|
|
OriginalLayers: layers,
|
|
OriginalDescriptor: &remoteDescriptor.Descriptor,
|
|
SubjectName: image,
|
|
SubjectDescriptor: subjectDescriptor,
|
|
}
|
|
return attest, nil
|
|
}
|