Skip to content

Commit

Permalink
Update to add SLSA provenance copy support
Browse files Browse the repository at this point in the history
  • Loading branch information
STARRY-S committed Aug 15, 2024
1 parent 2c04b14 commit cdf8206
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 46 deletions.
19 changes: 10 additions & 9 deletions pkg/hangar/archive/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,16 @@ type Image struct {
}

type ImageSpec struct {
Arch string `json:"arch,omitempty" yaml:"arch,omitempty"`
OS string `json:"os,omitempty" yaml:"os,omitempty"`
OSVersion string `json:"osVersion,omitempty" yaml:"osVersion,omitempty"`
OSFeatures []string `json:"osFeatures,omitempty" yaml:"osFeatures,omitempty"`
Variant string `json:"variant,omitempty" yaml:"variant,omitempty"`
MediaType string `json:"mediaType,omitempty" yaml:"mime,omitempty"`
Layers []digest.Digest `json:"layers,omitempty" yaml:"layers,omitempty"`
Config digest.Digest `json:"config,omitempty" yaml:"config,omitempty"`
Digest digest.Digest `json:"digest,omitempty" yaml:"digest,omitempty"`
Arch string `json:"arch,omitempty" yaml:"arch,omitempty"`
OS string `json:"os,omitempty" yaml:"os,omitempty"`
OSVersion string `json:"osVersion,omitempty" yaml:"osVersion,omitempty"`
OSFeatures []string `json:"osFeatures,omitempty" yaml:"osFeatures,omitempty"`
Variant string `json:"variant,omitempty" yaml:"variant,omitempty"`
MediaType string `json:"mediaType,omitempty" yaml:"mime,omitempty"`
Layers []digest.Digest `json:"layers,omitempty" yaml:"layers,omitempty"`
Config digest.Digest `json:"config,omitempty" yaml:"config,omitempty"`
Digest digest.Digest `json:"digest,omitempty" yaml:"digest,omitempty"`
Annotations map[string]string `json:"annotations,omitempty" yaml:"annotations,omitempty"`
}

func NewIndex() *Index {
Expand Down
3 changes: 2 additions & 1 deletion pkg/hangar/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,7 @@ func (l *Loader) worker(ctx context.Context, o any) {
}
mi.UpdatePlatform(
img.Arch, img.Variant, img.OS, img.OSVersion, img.OSFeatures)
mi.Annotations = img.Annotations
manifestImages = append(manifestImages, mi)
}

Expand All @@ -436,7 +437,7 @@ func (l *Loader) worker(ctx context.Context, o any) {
// If no new image copied to destination registry, skip re-create
// manifest index for destination image.
var skipBuildManifest = true
for _, img := range manifestImages {
for _, img := range destManifestImages {
if !manifestImages.Contains(img) {
skipBuildManifest = false
break
Expand Down
1 change: 1 addition & 0 deletions pkg/hangar/mirrorer.go
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,7 @@ func (m *Mirrorer) worker(ctx context.Context, o any) {
}
mi.UpdatePlatform(
image.Arch, image.Variant, image.OS, image.OSVersion, image.OSFeatures)
mi.Annotations = image.Annotations
manifestImages = append(manifestImages, mi)
}
destManifestImages := obj.destination.ManifestImages()
Expand Down
4 changes: 2 additions & 2 deletions pkg/image/destination/destination.go
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ func (d *Destination) ManifestImages() manifest.Images {
switch d.mime {
case manifestv5.DockerV2ListMediaType:
for _, m := range d.schema2List.Manifests {
mi := manifest.NewImage(m.Digest, m.MediaType, m.Size)
mi := manifest.NewImage(m.Digest, m.MediaType, m.Size, nil)
mi.UpdatePlatform(
m.Platform.Architecture,
m.Platform.Variant,
Expand All @@ -438,7 +438,7 @@ func (d *Destination) ManifestImages() manifest.Images {
}
case imgspecv1.MediaTypeImageIndex:
for _, m := range d.ociIndex.Manifests {
mi := manifest.NewImage(m.Digest, m.MediaType, m.Size)
mi := manifest.NewImage(m.Digest, m.MediaType, m.Size, m.Annotations)
mi.UpdatePlatform(
m.Platform.Architecture,
m.Platform.Variant,
Expand Down
36 changes: 22 additions & 14 deletions pkg/image/manifest/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ import (
"github.com/cnrancher/hangar/pkg/image/internal/private"

"github.com/containers/common/pkg/retry"
manifestv5 "github.com/containers/image/v5/manifest"
alltransportsv5 "github.com/containers/image/v5/transports/alltransports"
typesv5 "github.com/containers/image/v5/types"
imgspec "github.com/opencontainers/image-spec/specs-go"
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
)

// Builder is the builder to build DockerV2ListMediaType manifest.
Expand Down Expand Up @@ -60,6 +61,7 @@ func (b *Builder) Add(p *Image) {
// Replace if digest already exists
if i := b.images.FindDigestIndex(p); i >= 0 {
b.images = append(b.images[:i], b.images[i+1:]...)
return
}
b.images = append(b.images, p)
}
Expand All @@ -72,28 +74,34 @@ func (b *Builder) Push(ctx context.Context) error {
if len(b.images) == 0 {
return fmt.Errorf("manifest builder: no images added to builder")
}
list := manifestv5.Schema2List{
SchemaVersion: 2,
MediaType: manifestv5.DockerV2ListMediaType,
Manifests: make([]manifestv5.Schema2ManifestDescriptor, 0),
// list := manifestv5.Schema2List{
// SchemaVersion: 2,
// MediaType: manifestv5.DockerV2ListMediaType,
// Manifests: make([]manifestv5.Schema2ManifestDescriptor, 0),
// }
list := imgspecv1.Index{
Versioned: imgspec.Versioned{
SchemaVersion: 2,
},
MediaType: imgspecv1.MediaTypeImageIndex,
Manifests: make([]imgspecv1.Descriptor, 0),
}

for _, img := range b.images {
s2desc := manifestv5.Schema2ManifestDescriptor{
Schema2Descriptor: manifestv5.Schema2Descriptor{
MediaType: img.MediaType,
Size: img.Size,
Digest: img.Digest,
},
Platform: manifestv5.Schema2PlatformSpec{
m := imgspecv1.Descriptor{
MediaType: img.MediaType,
Size: img.Size,
Digest: img.Digest,
Annotations: img.Annotations,
Platform: &imgspecv1.Platform{
Architecture: img.platform.arch,
OS: img.platform.os,
Variant: img.platform.variant,
OSVersion: img.platform.osVersion,
OSFeatures: img.platform.osFeatures,
Variant: img.platform.variant,
},
}
list.Manifests = append(list.Manifests, s2desc)
list.Manifests = append(list.Manifests, m)
}
d, err := json.MarshalIndent(list, "", " ")
if err != nil {
Expand Down
34 changes: 23 additions & 11 deletions pkg/image/manifest/struct.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"encoding/json"
"fmt"
"reflect"
"slices"

manifestv5 "github.com/containers/image/v5/manifest"
Expand All @@ -15,10 +16,11 @@ import (
type Images []*Image

type Image struct {
Size int64
Digest digest.Digest
MediaType string
platform manifestPlatform
Size int64
Digest digest.Digest
MediaType string
Annotations map[string]string // OCI image index v1 supports annotations
platform manifestPlatform
}

func NewImageByInspect(
Expand Down Expand Up @@ -55,9 +57,10 @@ func NewImageByInspect(
return nil, fmt.Errorf("failed to get image config: %w", err)
}
mi := &Image{
Size: int64(len(b)),
Digest: digest,
MediaType: mime,
Size: int64(len(b)),
Digest: digest,
MediaType: mime,
Annotations: map[string]string{},
platform: manifestPlatform{
arch: config.Architecture,
os: config.OS,
Expand All @@ -70,11 +73,17 @@ func NewImageByInspect(
return mi, nil
}

func NewImage(digest digest.Digest, mime string, size int64) *Image {
func NewImage(
digest digest.Digest, mime string, size int64, annotations map[string]string,
) *Image {
mi := &Image{
Digest: digest,
MediaType: mime,
Size: size,
Digest: digest,
MediaType: mime,
Size: size,
Annotations: map[string]string{},
}
if len(annotations) != 0 {
mi.Annotations = annotations
}

return mi
Expand Down Expand Up @@ -127,6 +136,9 @@ func (p *Image) Equal(d *Image) bool {
if p.Digest != d.Digest {
return false
}
if !reflect.DeepEqual(p.Annotations, d.Annotations) {
return false
}
if p.platform.arch != d.platform.arch {
return false
}
Expand Down
44 changes: 35 additions & 9 deletions pkg/image/source/copy.go
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,23 @@ func (s *Source) copyMediaTypeImageIndex(
) (int, error) {
var copiedNum int
var errs []error

// Filter allowed image digests
allowedDigests := map[string]bool{}
for _, m := range s.ociIndex.Manifests {
dig := m.Digest
arch := m.Platform.Architecture
osInfo := m.Platform.OS
variant := m.Platform.Variant
if !opts.Set.Allow(arch, osInfo, variant) {
continue
}
if arch == "unknown" || osInfo == "unknown" {
continue
}
allowedDigests[dig.String()] = true
}

for _, m := range s.ociIndex.Manifests {
mime := m.MediaType
arch := m.Platform.Architecture
Expand All @@ -267,11 +284,19 @@ func (s *Source) copyMediaTypeImageIndex(
osFeatures := m.Platform.OSFeatures
variant := m.Platform.Variant
dig := m.Digest
annotations := m.Annotations

// Skip image
if !opts.Set.Allow(arch, osInfo, variant) {
continue
}
if len(annotations) != 0 {
// Skip uncopied image SLSA provenance
referenceDigest := annotations["vnd.docker.reference.digest"]
if referenceDigest != "" && !allowedDigests[referenceDigest] {
continue
}
}

sourceRef, err := alltransportsv5.ParseImageName(fmt.Sprintf(
"%s%s/%s/%s@%s",
Expand Down Expand Up @@ -362,15 +387,16 @@ func (s *Source) copyMediaTypeImageIndex(
continue
}
spec := archive.ImageSpec{
Arch: arch,
OS: osInfo,
OSVersion: osVersion,
OSFeatures: osFeatures,
Variant: variant,
MediaType: mime,
Layers: nil,
Config: "",
Digest: manifestDigest,
Arch: arch,
OS: osInfo,
OSVersion: osVersion,
OSFeatures: osFeatures,
Variant: variant,
MediaType: mime,
Layers: nil,
Config: "",
Digest: manifestDigest,
Annotations: annotations,
}
switch imageMIME {
case manifestv5.DockerV2Schema2MediaType:
Expand Down

0 comments on commit cdf8206

Please sign in to comment.