Gate copyleft base images in Dockerfiles - #579
Open
haiyanmeng wants to merge 1 commit into
Open
Conversation
Add container-licenses.sh, picked up automatically by verify-all.sh, which fails a Dockerfile that bakes a denied base image into an image we build, via either FROM or COPY --from=. The distinction the check encodes is between referencing and conveying. Pulling an image at runtime -- the busybox:1.36 init container in manifests/ate-install/atenet-dns.yaml, the workload images under benchmarking, the fixture strings in actortemplate_validation_test.go -- is not distribution: the cluster fetches the image from its upstream registry and we never hand over the binary. Baking one into an image we publish does make us a distributor of whatever that base contains, and for a GPL-2.0 base that obligation cannot be discharged once a release image is public. Only the latter path is gated. A repo-wide grep for the string would fail on the runtime references, which are fine, and would teach the wrong rule. DENY_IMAGES starts with busybox (GPL-2.0-only) and alpine (bundles busybox, so it carries the same obligation). Distro bases such as debian and ubuntu are deliberately absent: they ship GPL userland too, but are redistributed verbatim with the distro's own corresponding-source availability. That line is a policy choice rather than a derived legal one, and the script says so; adjust the list to whatever the project's license policy settles on. Parsing handles what a grep gets wrong: --platform and other FROM flags, registry prefixes and digests during normalization, stage aliases and numeric indices in COPY --from=, scratch, unresolvable build args, and comments. Matching on the exact repository name keeps a reference such as mycorp/busybox-tools from tripping it. The check self-tests before each scan, because its failure mode is otherwise silent: if an edit breaks the parsing so that nothing ever matches, it does not error, it prints that the tree is clean and exits 0, forever. A gate that has quietly stopped gating is worse than no gate, because it carries exactly the false confidence the check was written to avoid. So the parser runs against a fixture with a known answer first, and refuses to report a clean tree if it no longer behaves. That fixture is a heredoc written to a temporary file rather than a checked-in testdata/Dockerfile, because a real one would be matched by this script's own git ls-files glob and would need an exclusion -- and that exclusion would be a place to hide a Dockerfile from the check. Its last two lines name a build stage `alpine` and copy from it; that case looks redundant next to the existing `build` alias but is the only one that makes losing stage tracking observable, since an alias that is not itself a denied name normalizes to a harmless string. Mutation testing confirms the fixture catches removal of the digest strip, the registry-prefix strip, the tag strip, the FROM flag skip, stage-alias tracking, the comment skip, the scratch and build-arg skips, and a widening of the exact repository-name match to a substring match. Dropping the numeric stage-index guard is deliberately not caught: an index normalizes to a number that can never equal a denied name, so the guard documents intent rather than carrying logic. No Dockerfile in tree is affected; the three present base on python-slim, golang-bookworm, distroless, node-slim and ubuntu. No test framework is introduced; the repository has none for its 67 hack scripts, and one script does not justify one. Verified clean under shellcheck at the repo's pinned 0.9.0 and under boilerplate.sh.
haiyanmeng
requested review from
Benjamin Elder (BenTheElder) and
Bowei Du (bowei)
July 29, 2026 13:03
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.
Add container-licenses.sh, picked up automatically by verify-all.sh, which fails a Dockerfile that bakes a denied base image into an image we build, via either FROM or COPY --from=.
The distinction the check encodes is between referencing and conveying.
DENY_IMAGES starts with busybox (GPL-2.0-only) and alpine (bundles busybox, so it carries the same obligation). Distro bases such as debian and ubuntu are deliberately absent: they ship GPL userland too, but are redistributed verbatim with the distro's own corresponding-source availability. That line is a policy choice rather than a derived legal one, and the script says so; adjust the list to whatever the project's license policy settles on.
The check self-tests before each scan.
No Dockerfile in tree is affected; the three present base on python-slim, golang-bookworm, distroless, node-slim and ubuntu.