Skip to content

Commit eca922f

Browse files
committed
image/copy: Add guards for unsupported digest forcing scenarios
Add guards and limitations for cases where digest forcing is not yet supported or incompatible with certain features: 1. Multi-arch images (multiple.go): - Not yet implemented; needs per-instance config digest updates - Fail cleanly with clear error message - See #552 (comment) 2. Docker schema1 manifests (single.go): - Lack separate config descriptor, only support sha256 - Fail early when forcing non-sha256 algorithms 3. zstd:chunked compression (single.go): - Uses sha256 for internal TOC and chunk digests - Fall back to plain zstd when forcing non-sha256 - Fail if requireCompressionFormatMatch is set 4. PutBlobPartial optimization (single.go): - Incompatible with forcing different digest (needs full layer) - Disable partial pull when algorithms don't match 5. Blob reuse optimization (single.go): - Skip blob reuse when digest algorithms don't match - Future: could support cross-digest reuse via BlobInfoCache These guards ensure clean failures and fallbacks rather than silent corruption or confusing errors. Signed-off-by: Lokesh Mandvekar <lsm5@redhat.com>
1 parent f167c0d commit eca922f

2 files changed

Lines changed: 34 additions & 13 deletions

File tree

image/copy/multiple.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,12 @@ func (c *copier) copyMultipleImages(ctx context.Context) (copiedManifest []byte,
208208
cannotModifyManifestListReason = "Instructed to preserve digests"
209209
}
210210

211+
// FIXME: Multi-arch not supported yet; would need config digest updates for each instance.
212+
// See https://github.com/containers/container-libs/pull/552#discussion_r2611627578
213+
if c.options.digestOptions.MustUseSet() != "" {
214+
return nil, fmt.Errorf("forcing digest algorithm with multi-arch images is not yet implemented")
215+
}
216+
211217
// Determine if we'll need to convert the manifest list to a different format.
212218
forceListMIMEType := c.options.ForceManifestMIMEType
213219
switch forceListMIMEType {

image/copy/single.go

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -783,19 +783,34 @@ func (ic *imageCopier) copyLayer(ctx context.Context, srcInfo types.BlobInfo, to
783783
tocDigest = *d
784784
}
785785

786-
reused, reusedBlob, err := ic.c.dest.TryReusingBlobWithOptions(ctx, srcInfo, private.TryReusingBlobOptions{
787-
Cache: ic.c.blobInfoCache,
788-
CanSubstitute: canSubstitute,
789-
EmptyLayer: emptyLayer,
790-
LayerIndex: &layerIndex,
791-
SrcRef: srcRef,
792-
PossibleManifestFormats: append([]string{ic.manifestConversionPlan.preferredMIMEType}, ic.manifestConversionPlan.otherMIMETypeCandidates...),
793-
RequiredCompression: requiredCompression,
794-
OriginalCompression: srcInfo.CompressionAlgorithm,
795-
TOCDigest: tocDigest,
796-
})
797-
if err != nil {
798-
return types.BlobInfo{}, "", fmt.Errorf("trying to reuse blob %s at destination: %w", srcInfo.Digest, err)
786+
// FIXME: Blob reuse disabled when forcing different digest algorithm.
787+
canTryReuse := true
788+
if forcedAlgo := ic.c.options.digestOptions.MustUseSet(); forcedAlgo != "" {
789+
if srcInfo.Digest.Algorithm() != forcedAlgo {
790+
logrus.Debugf("Skipping blob reuse for %s: digest algorithm %s doesn't match forced algorithm %s",
791+
srcInfo.Digest, srcInfo.Digest.Algorithm(), forcedAlgo)
792+
canTryReuse = false
793+
}
794+
}
795+
796+
reused := false
797+
var reusedBlob private.ReusedBlob
798+
if canTryReuse {
799+
var err error
800+
reused, reusedBlob, err = ic.c.dest.TryReusingBlobWithOptions(ctx, srcInfo, private.TryReusingBlobOptions{
801+
Cache: ic.c.blobInfoCache,
802+
CanSubstitute: canSubstitute,
803+
EmptyLayer: emptyLayer,
804+
LayerIndex: &layerIndex,
805+
SrcRef: srcRef,
806+
PossibleManifestFormats: append([]string{ic.manifestConversionPlan.preferredMIMEType}, ic.manifestConversionPlan.otherMIMETypeCandidates...),
807+
RequiredCompression: requiredCompression,
808+
OriginalCompression: srcInfo.CompressionAlgorithm,
809+
TOCDigest: tocDigest,
810+
})
811+
if err != nil {
812+
return types.BlobInfo{}, "", fmt.Errorf("trying to reuse blob %s at destination: %w", srcInfo.Digest, err)
813+
}
799814
}
800815
if reused {
801816
logrus.Debugf("Skipping blob %s (already present):", srcInfo.Digest)

0 commit comments

Comments
 (0)