Files
attest/mirror/targets.go
James Carnegie 8982778507 refactor! remove pkg directory (#145)
* refactor!: remove pkg directory

* chore: include breaking changes in draft
2024-09-02 16:17:50 +01:00

112 lines
4.1 KiB
Go

package mirror
import (
"fmt"
"path/filepath"
"strings"
"github.com/docker/attest/oci"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/empty"
"github.com/google/go-containerregistry/pkg/v1/mutate"
"github.com/google/go-containerregistry/pkg/v1/static"
"github.com/google/go-containerregistry/pkg/v1/types"
"github.com/theupdateframework/go-tuf/v2/metadata"
)
// GetTUFTargetMirrors returns a list of top-level target files as MirrorImages (image with tag).
func (m *TUFMirror) GetTUFTargetMirrors() ([]*Image, error) {
targetMirrors := []*Image{}
md := m.TUFClient.GetMetadata()
// for each top-level target file, create an image with the target file as a layer
targets := md.Targets[metadata.TARGETS].Signed.Targets
for _, t := range targets {
// download target file
file, err := m.TUFClient.DownloadTarget(t.Path, filepath.Join(m.tufPath, "download"))
if err != nil {
return nil, fmt.Errorf("failed to download target %s: %w", t.Path, err)
}
// create image with target file as layer
img := empty.Image
img = mutate.MediaType(img, types.OCIManifestSchema1)
img = mutate.ConfigMediaType(img, types.OCIConfigJSON)
// annotate layer
hash, ok := t.Hashes["sha256"]
if !ok {
return nil, fmt.Errorf("missing sha256 hash for target %s", t.Path)
}
name := hash.String() + "." + t.Path
ann := map[string]string{tufFileAnnotation: name}
layer := mutate.Addendum{Layer: static.NewLayer(file.Data, tufTargetMediaType), Annotations: ann}
img, err = mutate.Append(img, layer)
if err != nil {
return nil, fmt.Errorf("failed to append role layer to image: %w", err)
}
targetMirrors = append(targetMirrors, &Image{Image: &oci.EmptyConfigImage{Image: img}, Tag: name})
}
return targetMirrors, nil
}
// GetDelegatedTargetMirrors returns a list of delegated target files as MirrorIndexes (image index with tag)
// each image in the index contains a delegated target file.
func (m *TUFMirror) GetDelegatedTargetMirrors() ([]*Index, error) {
mirror := []*Index{}
md := m.TUFClient.GetMetadata()
// for each delegated role, create an image index with target files as images
roles := md.Targets[metadata.TARGETS].Signed.Delegations.Roles
for _, role := range roles {
// create an image index
index := v1.ImageIndex(empty.Index)
// get delegated targets metadata for role
roleMeta, err := m.TUFClient.LoadDelegatedTargets(role.Name, metadata.TARGETS)
if err != nil {
return nil, fmt.Errorf("failed to load delegated targets metadata: %w", err)
}
// for each target file, create an image with the target file as a layer
for _, target := range roleMeta.Signed.Targets {
// download target file
file, err := m.TUFClient.DownloadTarget(target.Path, filepath.Join(m.tufPath, "download"))
if err != nil {
return nil, fmt.Errorf("failed to download target %s: %w", target.Path, err)
}
// create image with target file as layer
img := empty.Image
img = mutate.MediaType(img, types.OCIManifestSchema1)
img = mutate.ConfigMediaType(img, types.OCIConfigJSON)
// annotate layer
hash, ok := target.Hashes["sha256"]
if !ok {
return nil, fmt.Errorf("missing sha256 hash for target %s", target.Path)
}
filename := filepath.Base(target.Path)
subdir, ok := strings.CutSuffix(target.Path, "/"+filename)
if !ok {
return nil, fmt.Errorf("failed to find target subdirectory [%s] in path: %s", subdir, target.Path)
}
name := hash.String() + "." + filename
ann := map[string]string{tufFileAnnotation: name}
layer := mutate.Addendum{Layer: static.NewLayer(file.Data, tufTargetMediaType), Annotations: ann}
img, err = mutate.Append(img, layer)
if err != nil {
return nil, fmt.Errorf("failed to append role layer to image: %w", err)
}
emptyConfigImage := &oci.EmptyConfigImage{Image: img}
// append image to index with annotation
index = mutate.AppendManifests(index, mutate.IndexAddendum{
Add: emptyConfigImage,
Descriptor: v1.Descriptor{
Annotations: map[string]string{
tufFileAnnotation: fmt.Sprintf("%s/%s", subdir, name),
},
},
})
}
mirror = append(mirror, &Index{Index: index, Tag: role.Name})
}
return mirror, nil
}