[NOT READY FOR REVIEW][TEST] Introduce a sentinel layer variant for zstd:chunked pulls#681
[NOT READY FOR REVIEW][TEST] Introduce a sentinel layer variant for zstd:chunked pulls#681giuseppe wants to merge 4 commits intocontainers:mainfrom
Conversation
62a4a6a to
ed03b46
Compare
|
Packit jobs failed. @containers/packit-build please check. |
| } | ||
|
|
||
| // Create zstd:chunked sentinel variants for instances where any layer uses zstd:chunked. | ||
| if cannotModifyManifestListReason == "" { |
There was a problem hiding this comment.
Initially, I would expect this decision to happen in prepareInstanceCopies (future prepareInstanceOps), and unit-tested there.
OTOH this seems to be happening later because we collect the pushed manifests… that might be a good reason.
|
|
||
| // hasZstdChunkedLayers returns true if any non-empty layer in the manifest has | ||
| // zstd:chunked TOC annotations. | ||
| func hasZstdChunkedLayers(ociMan *manifest.OCI1) bool { |
There was a problem hiding this comment.
I wonder about correct layering / abstractions, but that can be decided a bit later.
| sentinelManifestDigest := digest.FromBytes(sentinelManifestBlob) | ||
|
|
||
| // Push sentinel manifest. | ||
| if err := c.dest.PutManifest(ctx, sentinelManifestBlob, &sentinelManifestDigest); err != nil { |
There was a problem hiding this comment.
The rules say: push each blob ~in order, then do PutManifest. Pushing only the extra blob works for docker:// but not for other transports.
I think this should probably be an “almost ordinary” copy from the one image on the destination to another, using copySingleImage with an “add a layer” flag. That would naturally trigger the API-required TryReusingBlob calls, and we don’t need a special code path creating an updated manifest here.
… or maybe, actually, “remove a layer” flag? Do we start with slow-pulling zstd-chunked and TOC annotations, and add the "fast pull" marker only, or do we start with "fast pull zstd-chunked with TOC", and turn that into "~ordinary zstd with no TOC annotations at all"?
There was a problem hiding this comment.
Yet another aspect to this: When decompressing or re-compressing (to gzip), we need to strip the sentinel.
So, in this sense, the “copy single instance” code needs to be compression-sentinel aware whatever we do. It might then be elegant for the “create a zstd:chunked” code path to add the sentinel as part of an “ordinary compression”, and we would then clone that “fast pull” image into a compatible one, per the “remove a layer” option in the comment above.
storage/pkg/chunked/toc/toc.go
Outdated
| // ZstdChunkedSentinelContent is the well-known content of the sentinel layer | ||
| // used to signal that a manifest's zstd:chunked layers can be used without | ||
| // the full-digest mitigation. | ||
| const ZstdChunkedSentinelContent = "zstd:chunked" |
There was a problem hiding this comment.
- Make very sure this is not valid tar. I guess that means including enough for a tar header, but with a non-tar magic and invalid v7 checksum?
- Ensure there is a at least one binary 0 close to the start to mark it as a non-text format
- “This image must be consumed using the TOC digests and NEVER as a tar archive", perhaps link to some future documentation.
| ) | ||
|
|
||
| // SkipMitigation is a no-op on unsupported platforms. | ||
| func SkipMitigation(d graphdriver.Differ) {} |
There was a problem hiding this comment.
Ultimately it would be cleaner for NewDiffer to return a struct that implements graphdriver.Differ; we could just add a method. (But now that would be an API break…)
| // that should be treated as empty. For c/storage, this detects the zstd:chunked | ||
| // sentinel layer and records that the full-digest mitigation can be skipped. | ||
| func (s *storageImageDestination) FilterLayers(layerInfos []manifest.LayerInfo) []int { | ||
| if len(layerInfos) > 0 && layerInfos[0].Digest == toc.ZstdChunkedSentinelDigest { |
There was a problem hiding this comment.
PutBlob (for layer with a TOC?, or for all?), and this almost certainly also affects TryReusingBlob. Perhaps more code around trustedLayerIdentityData also needs updating (hopefully that is already set up to correctly handle insecureAllowUnpredictableImageContents)
[Layer copies happen in parallel, and we need to enforce this for the very first (well, second, after the sentinel) layer, so this really needs to be either a new private.ImageDestination… operation, or an extension of the existing NoteOriginalOCIConfig to also provide a manifest or layer data.)
There was a problem hiding this comment.
Another aspect to this: We need to disable the makeConvertFromRawDiffer fallback.
536bf3d to
d7973eb
Compare
Add sentinel layer constants (ZstdChunkedSentinelContent and ZstdChunkedSentinelDigest) to the toc package and introduce SkipMitigation() to disable full-digest verification when a zstd:chunked sentinel layer is detected. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
…election Add annotation constants for identifying zstd:chunked sentinel layers in OCI manifests. Extend instance candidate selection to prefer manifests with sentinel annotations when available. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
…ion during pull When pulling an image, the storage destination's FilterLayers method detects the zstd:chunked sentinel layer, marks it as empty, and internally records that SkipMitigation() should be called to bypass unnecessary full-digest verification. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
When pushing images, generate zstd:chunked sentinel variant manifests. For manifest lists, create sentinel variants for each instance after copying. For single images, wrap the result in an OCI index with a sentinel variant when the destination supports it. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
d7973eb to
8cfcfca
Compare
Introduce a sentinel layer variant to safely skip the full-digest mitigation for zstd:chunked pulls.
This PR eliminates the duality by creating a separate manifest variant with a non-tar sentinel layer prepended. Unaware clients and scanners cannot process the sentinel variant so the image no longer has two possible interpretations.
Aware clients recognize the sentinel, skip it, and pull without the expensive full-digest recomputation safely because no unaware tool can be tricked into validating the wrong content. Data layers are reused by digest so there is no duplication.
I've pushed an image with the new format here: quay.io/giuseppe/zstd-chunked:sentinel
@mtrmac @actionmancan this is a PoC for the idea we have discussed on how to relax the mitigation