Repository navigation
Conversation
bake --progress rawjson now enforces filesystem entitlements. Compose only allowed the context, so a dockerfile path outside it fails the check. Signed-off-by: Dean Chen <862469039@qq.com>
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
ndeloof
left a comment
There was a problem hiding this comment.
Thanks for tackling this. These notes come from a static read of the diff (AI-assisted review): I did not run a bake build against them, so please treat the first point as "to verify" rather than established.
The main concern is the scope of the grant: bake reads the Dockerfile's directory (the dockerfile local source plus the .dockerignore files next to it), so granting only the Dockerfile file path may not make the reported error go away for a Dockerfile outside the context. Details inline.
One more general remark: the entitlement set is rebuilt by hand from the compose fields (context, additional contexts, dockerfile). Other local inputs (secrets: file:, cache_from: type=local, ...) will need the same kind of special case later. Deriving the paths from the generated bake definition, or from buildx's own entitlement detection, would be more future-proof — probably out of scope here, but worth keeping in mind.
| if contextType == build.ContextTypeGit || contextType == build.ContextTypeRemote || strings.Contains(buildConfig.Context, "://") { | ||
| return "" | ||
| } | ||
| return dockerFilePath(buildConfig.Context, buildConfig.Dockerfile) |
There was a problem hiding this comment.
I believe the grant needs to be the Dockerfile's directory, not the file: with context: ./app and dockerfile: ../docker/Dockerfile.prod, bake loads the dockerfile local source from /proj/docker (and reads Dockerfile.prod.dockerignore / .dockerignore there). --allow fs.read=/proj/docker/Dockerfile.prod would not cover that directory, so the build could still fail with the same entitlement error. Something like filepath.Dir(...) on the resolved path looks needed — could you confirm with a real bake run for that layout?
There was a problem hiding this comment.
I got this one wrong, sorry — the recommendation to grant the Dockerfile's directory doesn't hold up. I ran a real bake with the layout from my comment (context: ./app, dockerfile: ../docker/Dockerfile.prod), from a working directory that contains neither (buildx implicitly allows the cwd subtree, so the failure only shows when the Dockerfile is outside it). buildx v0.37.2, default builder:
| grants | result |
|---|---|
| context only | fails: Pass "--allow=fs.read=../docker/Dockerfile.prod" to grant requested privileges |
context + docker/Dockerfile.prod (the file) |
builds |
context + docker/ (the directory) |
builds |
So the entitlement buildx asks for is the Dockerfile file, not its directory. The dockerfile local source doesn't need a directory-level grant.
The sibling ignore files don't change that either. With a docker/Dockerfile.prod.dockerignore excluding g and a COPY g, the file grant and the directory grant behave identically: the ignore file is honored (CopyIgnoredFile warning, then "/g": not found) in both cases. A plain docker/.dockerignore next to the Dockerfile isn't read at all in either case. Only the context's .dockerignore and <dockerfile>.dockerignore are picked up.
Granting the directory is therefore broader than needed, and it can matter: dockerfile: ~/Dockerfile or a Dockerfile in a shared tmp dir would open $HOME or /tmp to the build, where before this change only the context was granted.
Suggestion: grant the resolved file instead of its parent.
localDockerfileDir→ return the output ofdockerFilePathas is (drop thefilepath.Dir); update its comment, which currently says bake reads the directory including the.dockerignore.dirCoveredalready works on a file path (thefilepath.Relcontainment check), so a Dockerfile inside the context is still skipped.- In the test, flip the assertions: expect
filepath.Join(resolvedDir, "Dockerfile")in the list and the bare directory out (the current!containsPath(got, wantFile)pins the wrong grant).
Caveat: I only checked buildx v0.37.2 with the docker driver — worth a quick run with a docker-container builder before settling.
| return "" | ||
| } | ||
| contextType, _ := build.DetectContextType(buildConfig.Context) | ||
| if contextType == build.ContextTypeGit || contextType == build.ContextTypeRemote || strings.Contains(buildConfig.Context, "://") { |
There was a problem hiding this comment.
This remote/git context detection is a copy of the one at the top of dockerFilePath (which is then called on the next line and repeats it). The two copies can drift apart. A small shared isRemoteContext(ctx) helper, or having dockerFilePath tell the caller whether it resolved a local path, would avoid that.
| for _, path := range buildConfig.AdditionalContexts { | ||
| paths = append(paths, path) | ||
| } | ||
| if df := localDockerfilePath(buildConfig); df != "" { |
There was a problem hiding this comment.
In the common case (context: ., Dockerfile inside it) this now adds a second --allow fs.read= per service for a path the context grant already covers, and localPaths is not deduplicated, so N services carry 2N flags. Could we skip the Dockerfile entry when it is under the context, and/or dedupe the final list?
| } | ||
| var local []string | ||
| for _, path := range paths { | ||
| if _, _, err := gitutil.ParseGitRef(path); !strings.Contains(path, "://") && err != nil { |
There was a problem hiding this comment.
Minor: this filter (ParseGitRef + ://) was designed for contexts and now also sees a resolved host Dockerfile path. A path like /work/github.com/org/repo/Dockerfile might parse as a git ref and be silently dropped, which would bring the entitlement error back. Worth checking, or classifying each path by type up front instead of filtering after the fact.
| }, | ||
| }) | ||
| assert.Assert(t, containsPath(got, ctxDir)) | ||
| assert.Assert(t, containsPath(got, wantDF)) |
There was a problem hiding this comment.
This only checks that the Dockerfile file path is in the returned list, so it would pass with the wrong grant (file instead of directory, see my comment on build_bake.go). Once the expected grant is settled, the assertion should pin it, and ideally an e2e / bakeArgs-level case should exercise a Dockerfile outside the context so bake's acceptance of the grant is actually covered.
Bake reads the dockerfile source from that directory, so a file grant misses a sibling dockerignore. Skip the extra allow when the directory is already inside a context, and keep the git-ref filter off host paths. Signed-off-by: Dean Chen <862469039@qq.com>
|
yeah, the file grant was too narrow. bake reads that directory (the dockerignore sits next to the Dockerfile), so the extra --allow is the directory now, and only when it isn't already covered by the context. left the git-ref check on contexts only. an absolute host path doesn't parse as a git ref today, but a directory with github.com in the name shouldn't have to depend on that. the test pins the directory, and checks the --allow bake actually gets. |
Buildx 0.37.2 (GHSA-gwr2-q96m-6682) makes bake enforce filesystem entitlements under `--progress rawjson`, which Compose always uses. Compose grants fs.read only for the build context, but the Dev Containers CLI points `dockerfile:` at a temp Dockerfile-with-features outside it, so every build-mode `devcontainer up` in the smoke jobs now fails. Set BUILDX_BAKE_ENTITLEMENTS_FS=0 on the smoke job of both workflows. The scope is CI-only and the inputs are this repository's own fixtures. Remove it once docker/compose#14286 ships in the runner image. Refs: docker/compose#14285 Refs: devcontainers/cli#1320
ndeloof
left a comment
There was a problem hiding this comment.
Thanks for tackling this. Requesting changes on two points, both checked with a real buildx bake (v0.37.2, default builder, run from a directory unrelated to the files so the implicit cwd grant doesn't hide anything).
1. The grant should be the Dockerfile file, not its directory.
buildx asks for the file (Pass "--allow=fs.read=../docker/Dockerfile.prod"), and a file-level grant is enough: a sibling <dockerfile>.dockerignore is honored with the file grant exactly as with the directory grant, and a plain .dockerignore next to the Dockerfile isn't read in either case. Granting the parent directory is broader than needed (dockerfile: ~/Dockerfile opens $HOME) and the comment on localDockerfileDir claiming bake reads the directory is inaccurate. My earlier recommendation of the directory was wrong — details and the suggested change in this thread.
2. Other host paths trigger the same entitlement error and aren't covered.
As noted in this comment on #14285, the failure isn't specific to dockerfile:. With only the context granted, buildx rejects each of these:
| build option | requested grant |
|---|---|
ssh: [my_id=/path/to/key] |
fs.read=<key path> |
secrets: with file: (type=file,src=…) |
fs.read=<file> |
cache_from: [type=local,src=…] |
fs.read=<dir> |
cache_to: [type=local,dest=…] |
fs.write=<dir> — bakeArgs can't emit fs.write at all today |
So a project with a key-path ssh: or a file secret still breaks after this PR with the same additional privileges requested error. Could you either extend the grants to these (the file secret and ssh key path are the most common), or state explicitly that this PR is scoped to the Dockerfile and track the rest in a follow-up so #14285 isn't closed as fully fixed?
buildx 0.37.2 started checking fs.read even for
bake --progress rawjson, which is how compose always invokes bake. We only granted the context, so a dockerfile outside it dies with "additional privileges requested". That's the devcontainer case, where the CLI points dockerfile: at a temp Dockerfile-with-features.This adds that local path to the allow list. Git and remote contexts are left alone.
Fixes #14285