copySingleImage copies a single (non-manifest-list) image unparsedImage, using c.policyContext to validate source image admissibility.
(ctx context.Context, unparsedImage *image.UnparsedImage, targetInstance *digest.Digest, opts copySingleImageOptions)
| 61 | // copySingleImage copies a single (non-manifest-list) image unparsedImage, using c.policyContext to validate |
| 62 | // source image admissibility. |
| 63 | func (c *copier) copySingleImage(ctx context.Context, unparsedImage *image.UnparsedImage, targetInstance *digest.Digest, opts copySingleImageOptions) (copySingleImageResult, error) { |
| 64 | // The caller is handling manifest lists; this could happen only if a manifest list contains a manifest list. |
| 65 | // Make sure we fail cleanly in such cases. |
| 66 | multiImage, err := isMultiImage(ctx, unparsedImage) |
| 67 | if err != nil { |
| 68 | // FIXME FIXME: How to name a reference for the sub-image? |
| 69 | return copySingleImageResult{}, fmt.Errorf("determining manifest MIME type for %s: %w", transports.ImageName(unparsedImage.Reference()), err) |
| 70 | } |
| 71 | if multiImage { |
| 72 | return copySingleImageResult{}, fmt.Errorf("Unexpectedly received a manifest list instead of a manifest for a single image") |
| 73 | } |
| 74 | |
| 75 | // Please keep this policy check BEFORE reading any other information about the image. |
| 76 | // (The multiImage check above only matches the MIME type, which we have received anyway. |
| 77 | // Actual parsing of anything should be deferred.) |
| 78 | if allowed, err := c.policyContext.IsRunningImageAllowed(ctx, unparsedImage); !allowed || err != nil { // Be paranoid and fail if either return value indicates so. |
| 79 | return copySingleImageResult{}, fmt.Errorf("Source image rejected: %w", err) |
| 80 | } |
| 81 | src, err := image.FromUnparsedImage(ctx, c.options.SourceCtx, unparsedImage) |
| 82 | if err != nil { |
| 83 | return copySingleImageResult{}, fmt.Errorf("initializing image from source %s: %w", transports.ImageName(c.rawSource.Reference()), err) |
| 84 | } |
| 85 | |
| 86 | // If the destination is a digested reference, make a note of that, determine what digest value we're |
| 87 | // expecting, and check that the source manifest matches it. If the source manifest doesn't, but it's |
| 88 | // one item from a manifest list that matches it, accept that as a match. |
| 89 | destIsDigestedReference := false |
| 90 | if named := c.dest.Reference().DockerReference(); named != nil { |
| 91 | if digested, ok := named.(reference.Digested); ok { |
| 92 | destIsDigestedReference = true |
| 93 | matches, err := manifest.MatchesDigest(src.ManifestBlob, digested.Digest()) |
| 94 | if err != nil { |
| 95 | return copySingleImageResult{}, fmt.Errorf("computing digest of source image's manifest: %w", err) |
| 96 | } |
| 97 | if !matches { |
| 98 | manifestList, _, err := c.unparsedToplevel.Manifest(ctx) |
| 99 | if err != nil { |
| 100 | return copySingleImageResult{}, fmt.Errorf("reading manifest from source image: %w", err) |
| 101 | } |
| 102 | matches, err = manifest.MatchesDigest(manifestList, digested.Digest()) |
| 103 | if err != nil { |
| 104 | return copySingleImageResult{}, fmt.Errorf("computing digest of source image's manifest: %w", err) |
| 105 | } |
| 106 | if !matches { |
| 107 | return copySingleImageResult{}, errors.New("Digest of source image's manifest would not match destination reference") |
| 108 | } |
| 109 | } |
| 110 | } |
| 111 | } |
| 112 | |
| 113 | if err := prepareImageConfigForDest(ctx, c.options.DestinationCtx, src, c.dest); err != nil { |
| 114 | return copySingleImageResult{}, err |
| 115 | } |
| 116 | |
| 117 | sigs, err := c.sourceSignatures(ctx, src, |
| 118 | "Getting image source signatures", |
| 119 | "Checking if image destination supports signatures") |
| 120 | if err != nil { |
no test coverage detected