Use UnparsedInstance.Manifest instead of ImageSource.GetManifest

... to validate that the manifests match expected digests, if any.

In some cases, using an UnparsedInstance can also avoid redundant I/O.

Do this everywhere, even where we read local storage which is
mostly trusted, because it is cheap enough and being consistent
makes it less likely for the code to be copied into other
contexts where the sources are not trusted.

Signed-off-by: Miloslav Trmač <mitr@redhat.com>
This commit is contained in:
Miloslav Trmač 2025-02-28 19:56:09 +01:00
parent c2e6d012d4
commit cc4cca08d4
7 changed files with 24 additions and 14 deletions

View File

@ -170,7 +170,8 @@ func getDateAndDigestAndSize(ctx context.Context, sys *types.SystemContext, stor
if sizeErr != nil {
imgSize = -1
}
manifestBytes, _, manifestErr := img.GetManifest(ctx, nil)
unparsedInstance := image.UnparsedInstance(img, nil)
manifestBytes, _, manifestErr := unparsedInstance.Manifest(ctx)
manifestDigest := ""
if manifestErr == nil && len(manifestBytes) > 0 {
mDigest, err := manifest.Digest(manifestBytes)
@ -179,7 +180,7 @@ func getDateAndDigestAndSize(ctx context.Context, sys *types.SystemContext, stor
manifestDigest = mDigest.String()
}
}
inspectable, inspectableErr := image.FromUnparsedImage(ctx, sys, image.UnparsedInstance(img, nil))
inspectable, inspectableErr := image.FromUnparsedImage(ctx, sys, unparsedInstance)
if inspectableErr == nil {
inspectInfo, inspectErr := inspectable.Inspect(ctx)
if inspectErr == nil && inspectInfo != nil && inspectInfo.Created != nil {

View File

@ -17,6 +17,7 @@ import (
"github.com/containers/common/libimage/manifests"
"github.com/containers/common/pkg/auth"
cp "github.com/containers/image/v5/copy"
"github.com/containers/image/v5/image"
"github.com/containers/image/v5/manifest"
"github.com/containers/image/v5/pkg/compression"
"github.com/containers/image/v5/transports"
@ -686,7 +687,7 @@ func manifestRemoveCmd(c *cobra.Command, args []string, _ manifestRemoveOpts) er
return fmt.Errorf("Reading image instance: %w", err)
}
defer instanceImg.Close()
manifestBytes, _, err := instanceImg.GetManifest(ctx, nil)
manifestBytes, _, err := image.UnparsedInstance(instanceImg, nil).Manifest(ctx)
if err != nil {
return fmt.Errorf("Reading image instance manifest: %w", err)
}
@ -826,7 +827,7 @@ func manifestAnnotateCmd(c *cobra.Command, args []string, opts manifestAnnotateO
return fmt.Errorf("Reading image instance: %w", err)
}
defer instanceImg.Close()
manifestBytes, _, err := instanceImg.GetManifest(ctx, nil)
manifestBytes, _, err := image.UnparsedInstance(instanceImg, nil).Manifest(ctx)
if err != nil {
return fmt.Errorf("Reading image instance manifest: %w", err)
}
@ -922,7 +923,7 @@ func manifestAnnotateCmd(c *cobra.Command, args []string, opts manifestAnnotateO
}
defer src.Close()
manifestBytes, manifestType, err := src.GetManifest(ctx, nil)
manifestBytes, manifestType, err := image.UnparsedInstance(src, nil).Manifest(ctx)
if err != nil {
logrus.Errorf("Error while trying to read artifact subject manifest: %v", err)
return err
@ -1063,7 +1064,7 @@ func manifestInspect(ctx context.Context, store storage.Store, systemContext *ty
}
defer src.Close()
manifestBytes, manifestType, err := src.GetManifest(ctx, nil)
manifestBytes, manifestType, err := image.UnparsedInstance(src, nil).Manifest(ctx)
if err != nil {
appendErr(fmt.Errorf("loading manifest %q: %w", transports.ImageName(ref), err))
continue

View File

@ -28,6 +28,7 @@ import (
"github.com/containers/common/pkg/config"
"github.com/containers/image/v5/docker"
"github.com/containers/image/v5/docker/reference"
"github.com/containers/image/v5/image"
"github.com/containers/image/v5/manifest"
"github.com/containers/image/v5/pkg/shortnames"
istorage "github.com/containers/image/v5/storage"
@ -369,7 +370,7 @@ func BuildDockerfiles(ctx context.Context, store storage.Store, options define.B
return "", nil, err
}
defer imgSource.Close()
manifestBytes, _, err := imgSource.GetManifest(ctx, nil)
manifestBytes, _, err := image.UnparsedInstance(imgSource, nil).Manifest(ctx)
if err != nil {
return "", nil, err
}
@ -569,7 +570,7 @@ func platformsForBaseImages(ctx context.Context, logger *logrus.Logger, dockerfi
logrus.Debugf("preparing to read image manifest for %q: %v", baseImage, err)
continue
}
candidateBytes, candidateType, err := src.GetManifest(ctx, nil)
candidateBytes, candidateType, err := image.UnparsedInstance(src, nil).Manifest(ctx)
_ = src.Close()
if err != nil {
logrus.Debugf("reading image manifest for %q: %v", baseImage, err)

View File

@ -39,7 +39,8 @@ func importBuilderDataFromImage(ctx context.Context, store storage.Store, system
defer src.Close()
imageDigest := ""
manifestBytes, manifestType, err := src.GetManifest(ctx, nil)
unparsedTop := image.UnparsedInstance(src, nil)
manifestBytes, manifestType, err := unparsedTop.Manifest(ctx)
if err != nil {
return nil, fmt.Errorf("loading image manifest for %q: %w", transports.ImageName(ref), err)
}
@ -48,6 +49,7 @@ func importBuilderDataFromImage(ctx context.Context, store storage.Store, system
}
var instanceDigest *digest.Digest
unparsedInstance := unparsedTop // for instanceDigest
if manifest.MIMETypeIsMultiImage(manifestType) {
list, err := manifest.ListFromBlob(manifestBytes, manifestType)
if err != nil {
@ -58,9 +60,10 @@ func importBuilderDataFromImage(ctx context.Context, store storage.Store, system
return nil, fmt.Errorf("finding an appropriate image in manifest list %q: %w", transports.ImageName(ref), err)
}
instanceDigest = &instance
unparsedInstance = image.UnparsedInstance(src, instanceDigest)
}
image, err := image.FromUnparsedImage(ctx, systemContext, image.UnparsedInstance(src, instanceDigest))
image, err := image.FromUnparsedImage(ctx, systemContext, unparsedInstance)
if err != nil {
return nil, fmt.Errorf("instantiating image for %q instance %q: %w", transports.ImageName(ref), instanceDigest, err)
}

View File

@ -10,6 +10,7 @@ import (
"strings"
"time"
"github.com/containers/image/v5/image"
"github.com/containers/image/v5/oci/layout"
"github.com/containers/image/v5/types"
"github.com/opencontainers/go-digest"
@ -47,7 +48,7 @@ func writeManifest(ctx context.Context, manifest *specV1.Manifest, ociDest types
// readManifestFromImageSource reads the manifest from the specified image
// source. Note that the manifest is expected to be an OCI v1 manifest.
func readManifestFromImageSource(ctx context.Context, src types.ImageSource) (*specV1.Manifest, *digest.Digest, int64, error) {
rawData, mimeType, err := src.GetManifest(ctx, nil)
rawData, mimeType, err := image.UnparsedInstance(src, nil).Manifest(ctx)
if err != nil {
return nil, nil, -1, err
}

7
new.go
View File

@ -195,7 +195,8 @@ func newBuilder(ctx context.Context, store storage.Store, options BuilderOptions
return nil, fmt.Errorf("instantiating image for %q: %w", transports.ImageName(ref), err)
}
defer srcSrc.Close()
manifestBytes, manifestType, err := srcSrc.GetManifest(ctx, nil)
unparsedTop := image.UnparsedInstance(srcSrc, nil)
manifestBytes, manifestType, err := unparsedTop.Manifest(ctx)
if err != nil {
return nil, fmt.Errorf("loading image manifest for %q: %w", transports.ImageName(ref), err)
}
@ -203,6 +204,7 @@ func newBuilder(ctx context.Context, store storage.Store, options BuilderOptions
imageDigest = manifestDigest.String()
}
var instanceDigest *digest.Digest
unparsedInstance := unparsedTop // for instanceDigest
if manifest.MIMETypeIsMultiImage(manifestType) {
list, err := manifest.ListFromBlob(manifestBytes, manifestType)
if err != nil {
@ -213,8 +215,9 @@ func newBuilder(ctx context.Context, store storage.Store, options BuilderOptions
return nil, fmt.Errorf("finding an appropriate image in manifest list %q: %w", transports.ImageName(ref), err)
}
instanceDigest = &instance
unparsedInstance = image.UnparsedInstance(srcSrc, instanceDigest)
}
src, err = image.FromUnparsedImage(ctx, systemContext, image.UnparsedInstance(srcSrc, instanceDigest))
src, err = image.FromUnparsedImage(ctx, systemContext, unparsedInstance)
if err != nil {
return nil, fmt.Errorf("instantiating image for %q instance %q: %w", transports.ImageName(ref), instanceDigest, err)
}

View File

@ -971,7 +971,7 @@ func saveReport(ctx context.Context, t *testing.T, ref types.ImageReference, dir
require.NoErrorf(t, err, "error opening image %q to read its configuration", imageName)
closer = img
// read the manifest in its original form
rawManifest, _, err := src.GetManifest(ctx, nil)
rawManifest, _, err := img.Manifest(ctx)
require.NoErrorf(t, err, "error reading raw manifest from image %q", imageName)
// read the config blob in its original form
rawConfig, err := img.ConfigBlob(ctx)