buildctl: read a valueless build-arg from the environment - #7030
Conversation
| continue | ||
| } | ||
| if v, ok := os.LookupEnv(name); ok { | ||
| m[opt] = v |
There was a problem hiding this comment.
This can mess up the order of the what opt wins on duplicates. Should still add to rest.
| rest := make([]string, 0, len(opts)) | ||
| for _, opt := range opts { | ||
| name, ok := strings.CutPrefix(opt, buildArgPrefix) | ||
| if !ok || name == "" || strings.Contains(name, "=") { |
There was a problem hiding this comment.
nit: this reads better if conditions are reversed.
2aed2d1 to
f9503ce
Compare
|
Both fixed, thanks. The ordering one was a real bug rather than just a style issue: with Reversing the conditions fell out of the same rewrite. One case I had to pick a behaviour for, happy to change it: |
| }, | ||
| { | ||
| name: "a build arg missing from the environment is dropped", | ||
| opts: []string{"build-arg:IMAGE"}, |
There was a problem hiding this comment.
just to be safe these test should clear IMAGE or use some env that is specific enough to never be accidentally defined by env
There was a problem hiding this comment.
Good point, that was a real hole. With IMAGE set in the ambient environment two
cases failed: "a build arg missing from the environment is dropped" picked up the
ambient value, and "a valueless build arg missing from the environment does not
clear an earlier value" returned it instead of busybox.
Extended the existing SOURCE_DATE_EPOCH guard to clear IMAGE as well, so the
cases are hermetic regardless of what the caller has exported. Went with clearing
rather than a more specific variable name so it stays correct if the name is ever
changed.
--opt build-arg:FOO failed the whole build with "invalid value build-arg:FOO" instead of taking FOO from the client environment, so callers had to spell out --opt build-arg:FOO=$FOO. "docker buildx build --build-arg FOO" reads the environment, and buildctl already propagates SOURCE_DATE_EPOCH from the environment into a build arg in loadOptEnv, so the valueless form was the odd one out. Resolve it in ParseOpt rather than in attrMap: attrMap is shared with --local, where a value is still required. A variable that is not present in the environment is left out of the frontend attributes entirely rather than sent as an empty string, so a default in the Dockerfile still applies. Signed-off-by: Ravi Arnan <raviarnankeren@gmail.com>
f9503ce to
92f2efe
Compare
Closes #7028
--opt build-arg:FOOfailed the whole build withinvalid opt: invalid value build-arg:FOOinstead of takingFOOfrom the client environment, so callers had to spell out--opt build-arg:FOO=$FOO.Why this is a consistency fix rather than a new feature
buildctlalready sources a build arg from the environment:loadOptEnv(cmd/buildctl/build/util.go) propagatesSOURCE_DATE_EPOCHintobuild-arg:SOURCE_DATE_EPOCH.docker buildx build --build-arg FOOreads the environment as well. The valueless--opt build-arg:FOOwas the only form that did not.Scope
The change is in
ParseOpt, not inattrMap.attrMapis shared withParseLocal, where--local namewithout a value should keep failing, so relaxing it there would be too broad. There is a second, unrelated copy ofattrMapatcmd/buildkitd/main.go:1003that parses daemon flags; it is deliberately untouched.Only the
build-arg:prefix is affected. A bare--opt targetstill errors, and so does--opt build-arg:with no name.A variable that is not present in the environment is left out of the frontend attributes entirely rather than sent as an empty string, so a default in the Dockerfile still applies. That matches buildx.
Verification
New unit tests in
cmd/buildctl/build/opt_test.go, 8 cases. The 3 that cover the new behaviour fail on master with exactly the reported error; the 5 regression cases pass on both.End to end against a real
buildkitd(moby/buildkit:latestin a container, reached overdocker-container://), using the reporter's Dockerfile:And the unset case, confirming the Dockerfile default is what applies rather than an empty value:
gofmt -s,go vetandgo test ./cmd/buildctl/build/are clean.Docs updated in
docs/reference/buildctl.md.