Detect layer compression by content, not media type#405
Open
mattpollock wants to merge 1 commit into
Open
Conversation
extractLayer routed decompression off the layer's declared media type: only types.OCILayerZStd was treated as zstd, everything else defaulted to gzip. But layers can be zstd-compressed while labeled with a non-OCI media type -- e.g. BuildKit pushing with Docker schema2 emits application/vnd.docker.image.rootfs.diff.tar.zstd -- which the switch mis-routes to gzip and fails with 'gzip: invalid header'. Sniff the layer's leading magic bytes instead, so gzip, zstd, and uncompressed tar all unpack regardless of how the layer is labeled. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
taylorsilva
requested changes
Jun 26, 2026
Comment on lines
+214
to
216
| // uncompressed tar regardless of how the layer is labeled. mediaType is kept | ||
| // for signature compatibility but no longer drives the decision. | ||
| func compressionReader(layer io.ReadCloser, mediaType types.MediaType, bar *mpb.Bar) (*tar.Reader, compressReaderClose, error) { |
Member
There was a problem hiding this comment.
This func is private and only used in one place. Let's just update the signature and update where it's called, which should be higher up in this file.
Suggested change
| // uncompressed tar regardless of how the layer is labeled. mediaType is kept | |
| // for signature compatibility but no longer drives the decision. | |
| func compressionReader(layer io.ReadCloser, mediaType types.MediaType, bar *mpb.Bar) (*tar.Reader, compressReaderClose, error) { | |
| // uncompressed tar regardless of how the layer is labeled. mediaType is kept | |
| // for signature compatibility but no longer drives the decision. | |
| func compressionReader(layer io.ReadCloser, bar *mpb.Bar) (*tar.Reader, compressReaderClose, error) { |
And update here:
registry-image-resource/commands/rootfs.go
Lines 83 to 91 in 1627112
|
|
||
| type compressReaderClose func() error | ||
|
|
||
| // Layer compression magic numbers. |
Member
There was a problem hiding this comment.
nit: for easy lookup reference in the future link to https://en.wikipedia.org/wiki/List_of_file_signatures
Suggested change
| // Layer compression magic numbers. | |
| // Layer compression magic numbers. Can find more at: | |
| // https://en.wikipedia.org/wiki/List_of_file_signatures |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
extractLayerchose the decompressor from the layer's declared media type: onlytypes.OCILayerZStdwas treated as zstd, and everything else fell through to gzip. That breaks for zstd layers labeled with a non-OCI media type — most commonly BuildKit pushing with Docker schema2, which emitsapplication/vnd.docker.image.rootfs.diff.tar.zstd. The media-type switch routes those togzip.NewReader, soinfails with:This is increasingly common as people adopt zstd-layer base images (e.g. hardened/minimal bases) and push them through standard
docker/build-push-actionwithout forcing OCI media types.Fix
Detect the compression from the layer's own leading magic bytes instead of trusting the media-type label:
28 b5 2f fd1f 8bSo gzip, zstd, and uncompressed layers all unpack regardless of whether they're labeled OCI or Docker media types.
mediaTypeis kept in the signature for compatibility but no longer drives the decision.Repro
getof$IMGfails withgzip: invalid headerbefore this change; succeeds after.Notes
commands/rootfs.go). Happy to add a regression test fixture (a Docker-schema2 zstd image alongside the existing OCI-zstd one intestdata/setup-images) if you'd like it in this PR.