Skip to content

Commit

Permalink
Merge pull request #45124 from vvoland/c8d-list-ignore-attestations
Browse files Browse the repository at this point in the history
c8d/list: Ignore attestation manifests
  • Loading branch information
thaJeztah committed Apr 3, 2023
2 parents d2a5948 + 92e38b6 commit 781740c
Showing 1 changed file with 111 additions and 27 deletions.
138 changes: 111 additions & 27 deletions daemon/containerd/image_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,21 @@ package containerd

import (
"context"
"encoding/json"

"github.com/containerd/containerd"
"github.com/containerd/containerd/content"
cerrdefs "github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/images"
cplatforms "github.com/containerd/containerd/platforms"
"github.com/containerd/containerd/platforms"
"github.com/docker/distribution/reference"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/moby/buildkit/util/attestation"
"github.com/opencontainers/go-digest"
"github.com/opencontainers/image-spec/identity"
v1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)

Expand Down Expand Up @@ -77,29 +80,77 @@ func (i *ImageService) Images(ctx context.Context, opts types.ImageListOptions)
continue
}

platforms, err := images.Platforms(ctx, contentStore, img.Target)
if err != nil {
return nil, err
}

for _, platform := range platforms {
image, chainIDs, err := i.singlePlatformImage(ctx, contentStore, img, platform)
if err != nil {
return nil, err
}
if image == nil {
continue
err := images.Walk(ctx, images.HandlerFunc(func(ctx context.Context, desc v1.Descriptor) ([]v1.Descriptor, error) {
if images.IsIndexType(desc.MediaType) {
return images.Children(ctx, contentStore, desc)
}

summaries = append(summaries, image)
if images.IsManifestType(desc.MediaType) {
// Ignore buildkit attestation manifests
// https://github.com/moby/buildkit/blob/v0.11.4/docs/attestations/attestation-storage.md
// This would have also been caught by the isImageManifest call below, but it requires
// an additional content read and deserialization of Manifest.
if _, has := desc.Annotations[attestation.DockerAnnotationReferenceType]; has {
return nil, nil
}

mfst, err := images.Manifest(ctx, contentStore, desc, platforms.All)
if err != nil {
if cerrdefs.IsNotFound(err) {
return nil, nil
}
return nil, err
}

if !isImageManifest(mfst) {
return nil, nil
}

platform, err := getManifestPlatform(ctx, contentStore, desc, mfst.Config)
if err != nil {
if cerrdefs.IsNotFound(err) {
return nil, nil
}
return nil, err
}

pm := platforms.OnlyStrict(platform)
available, _, _, missing, err := images.Check(ctx, contentStore, img.Target, pm)
if err != nil {
logrus.WithFields(logrus.Fields{
logrus.ErrorKey: err,
"platform": platform,
"image": img.Target,
}).Warn("checking availability of platform content failed")
return nil, nil
}
if !available || len(missing) > 0 {
return nil, nil
}

if opts.SharedSize {
root = append(root, &chainIDs)
for _, id := range chainIDs {
layers[id] = layers[id] + 1
c8dImage := containerd.NewImageWithPlatform(i.client, img, pm)
image, chainIDs, err := i.singlePlatformImage(ctx, contentStore, c8dImage)
if err != nil {
return nil, err
}

summaries = append(summaries, image)

if opts.SharedSize {
root = append(root, &chainIDs)
for _, id := range chainIDs {
layers[id] = layers[id] + 1
}
}
}

return nil, nil
}), img.Target)

if err != nil {
return nil, err
}

}

if opts.SharedSize {
Expand All @@ -115,15 +166,7 @@ func (i *ImageService) Images(ctx context.Context, opts types.ImageListOptions)
return summaries, nil
}

func (i *ImageService) singlePlatformImage(ctx context.Context, contentStore content.Store, img images.Image, platform v1.Platform) (*types.ImageSummary, []digest.Digest, error) {
platformMatcher := cplatforms.OnlyStrict(platform)
available, _, _, missing, err := images.Check(ctx, contentStore, img.Target, platformMatcher)
if !available || err != nil || len(missing) > 0 {
return nil, nil, nil
}

image := containerd.NewImageWithPlatform(i.client, img, platformMatcher)

func (i *ImageService) singlePlatformImage(ctx context.Context, contentStore content.Store, image containerd.Image) (*types.ImageSummary, []digest.Digest, error) {
diffIDs, err := image.RootFS(ctx)
if err != nil {
return nil, nil, err
Expand Down Expand Up @@ -303,3 +346,44 @@ func computeSharedSize(chainIDs []digest.Digest, layers map[digest.Digest]int, s
}
return sharedSize, nil
}

// getManifestPlatform returns a platform specified by the manifest descriptor
// or reads it from its config.
func getManifestPlatform(ctx context.Context, store content.Provider, manifestDesc, configDesc v1.Descriptor) (v1.Platform, error) {
var platform v1.Platform
if manifestDesc.Platform != nil {
platform = *manifestDesc.Platform
} else {
// Config is technically a v1.Image, but it has the same member as v1.Platform
// which makes the v1.Platform a subset of Image so we can unmarshal directly.
if err := readConfig(ctx, store, configDesc, &platform); err != nil {
return platform, err
}
}
return platforms.Normalize(platform), nil
}

// isImageManifests returns true if the manifest has any layer that is a known image layer.
// Some manifests use the image media type for compatibility, even if they are not a real image.
func isImageManifest(mfst v1.Manifest) bool {
for _, l := range mfst.Layers {
if images.IsLayerType(l.MediaType) {
return true
}
}
return false
}

// readConfig reads content pointed by the descriptor and unmarshals it into a specified output.
func readConfig(ctx context.Context, store content.Provider, desc v1.Descriptor, out interface{}) error {
data, err := content.ReadBlob(ctx, store, desc)
if err != nil {
return errors.Wrapf(err, "failed to read config content")
}
err = json.Unmarshal(data, out)
if err != nil {
return errors.Wrapf(err, "could not deserialize image config")
}

return nil
}

0 comments on commit 781740c

Please sign in to comment.