Skip to content

build: detect zstd-compressed context from stdin - #4079

Open
nrvate wants to merge 1 commit into
docker:masterfrom
nrvate:build-detect-zstd
Open

nrvate wants to merge 1 commit into
docker:masterfrom
nrvate:build-detect-zstd

Conversation

@nrvate

@nrvate nrvate commented Sep 15, 2026

Copy link
Copy Markdown

Problem

docker build - decides whether stdin carries a build context or a raw Dockerfile by sniffing magic bytes (isArchive in build/utils.go). The table knows bzip2, gzip, xz and plain tar — but not zstd. A zstd-compressed context on stdin is therefore parsed as a Dockerfile and the build fails immediately:

$ tar cf ctx.tar Dockerfile && zstd -q ctx.tar -o ctx.tar.zst
$ docker build --check - < ctx.tar.zst
1 | >>> (▒/▒d '5 ▒F`i...

gzip and plain tar on the same path work.

Fix

Add the zstd frame magic (0x28, 0xB5, 0x2F, 0xFD) to the table. Nothing else changes: for the default docker driver the stream is passed through to the daemon, and the daemon already decompresses zstd build contexts — verified against Docker Engine 29.7.2 by building the same tar.zst context through the /build API directly (it succeeds today; only this client-side sniff rejects it).

Testing

  • new TestIsArchive covering plain tar, gzip, bzip2, xz, zstd, a Dockerfile-from-stdin negative, and a truncated-magic negative
  • go test ./build/ -run TestIsArchive passes (Go 1.26, per go.mod)

Related: moby/go-archive#13 (broader zstd support in the archive library — this PR is the narrower client-side sniff gap).

isArchive() decides whether stdin carries a build context or a raw
Dockerfile by sniffing magic bytes. The table knows bzip2, gzip, xz and
plain tar, but not zstd, so a zstd-compressed context piped to
'docker build -' is parsed as a Dockerfile and the build fails on line 1:

    $ echo 'FROM scratch' > Dockerfile
    $ tar cf ctx.tar Dockerfile && zstd -q ctx.tar -o ctx.tar.zst
    $ docker build --check - < ctx.tar.zst
    1 | >>> (\u2572/\u2572d '5 \u2572F`i...
    gzip and plain tar on the same path work.

The daemon already decompresses zstd build contexts - verified against
Docker Engine 29.7.2 by building the same tar.zst context through the
/build API directly - so only the client-side sniff rejects it today.
This adds the zstd frame magic to the table and a unit test covering
all supported formats.

Related: moby/go-archive#13
Signed-off-by: nrvate <11264848+nrvate@users.noreply.github.com>

@crazy-max crazy-max left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I initially thought moby/buildkit#7069 covered this, but Buildx needs to recognize the archive before uploading it, so this fix is needed.

I’ve extracted a shared compression.IsArchive helper from moby/buildkit#7034 in moby/buildkit#7148, including zstd skippable-frame support. Once that lands and we vendor it here, we can replace Buildx local detector with the shared helper and cover zstd contexts with a stdin integration test. That should keep the two implementations from drifting again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants