Follow-up to #1695 / PR #1697, which restored the pre-commit gate by pinning the hadolint image to the v2.14.0 digest.
That was the right call for unblocking the queue, and the digest pin is the durable half of the fix. But it leaves one thing open, which this issue tracks.
What is still open
The four findings that reddened CI are un-seen, not fixed. hadolint 2.14.0 reports nothing on these Dockerfiles only because it predates the rules; 2.15.1 reports:
Dockerfile:149 DL3066 info: Non-numeric user-id may not be resolvable by host system
Dockerfile:165 DL3025 warning: Use arguments JSON notation for CMD and ENTRYPOINT arguments
Dockerfile.dev:62 DL3066 info: Non-numeric user-id may not be resolvable by host system
Dockerfile.test:21 DL3066 info: Non-numeric user-id may not be resolvable by host system
Both are real, and one is worth more than its info severity suggests:
- DL3066 matters because a name-form
USER cannot be verified by Kubernetes runAsNonRoot and similar admission checks, which see only the numeric id. A cluster policy that requires a non-root uid cannot confirm the container satisfies it.
- DL3025 is flagged on the
HEALTHCHECK CMD, not the container ENTRYPOINT/CMD (both already exec form).
Staying on 2.14.0 indefinitely also means never picking up new hadolint rules, which is the slower version of the same problem #1695 was about: the linter and the thing it lints drift apart silently.
Fix direction
Bump the digest pin to 2.15.1 and fix all four, without .hadolint.yaml ignore entries and without inline # hadolint ignore= directives.
Specifics that matter, since two of these have real runtime consequences:
Dockerfile and Dockerfile.test already pin their uids explicitly (adduser -u 1000, adduser -u 10001), so USER cudly -> USER 1000:1000 and USER e2e -> USER 10001 are pure substitutions.
Dockerfile.dev uses adduser -S, which takes the first free system id and therefore varies with the base image. Its uid/gid need pinning before a numeric USER is meaningful.
Dockerfile:165 must not be converted naively. The line is CMD curl -f http://localhost:8080/health || exit 1, and || is a shell operator. A bare exec-form list would pass || and exit to curl as literal arguments and the healthcheck would stop reporting unhealthy correctly. The correct form is ["/bin/sh", "-c", "curl -f http://localhost:8080/health || exit 1"], which satisfies DL3025 and preserves the process tree.
Status
PR #1700 implements exactly this and is open. It was written against the pre-#1697 tree, has been rebased onto current main, and its duplicate pin commit dropped out automatically as already-upstream. It is verified with Docker: hadolint 2.15.1 exits 0, all three images build, runtime identities resolve (uid=1000(cudly), uid=10001(e2e), uid=1001(devuser)), and the healthcheck is exercised in both directions.
This issue exists so that work is tracked against something, rather than against the already-closed #1695.
Follow-up to #1695 / PR #1697, which restored the
pre-commitgate by pinning the hadolint image to the v2.14.0 digest.That was the right call for unblocking the queue, and the digest pin is the durable half of the fix. But it leaves one thing open, which this issue tracks.
What is still open
The four findings that reddened CI are un-seen, not fixed. hadolint 2.14.0 reports nothing on these Dockerfiles only because it predates the rules; 2.15.1 reports:
Both are real, and one is worth more than its
infoseverity suggests:USERcannot be verified by KubernetesrunAsNonRootand similar admission checks, which see only the numeric id. A cluster policy that requires a non-root uid cannot confirm the container satisfies it.HEALTHCHECKCMD, not the containerENTRYPOINT/CMD(both already exec form).Staying on 2.14.0 indefinitely also means never picking up new hadolint rules, which is the slower version of the same problem #1695 was about: the linter and the thing it lints drift apart silently.
Fix direction
Bump the digest pin to 2.15.1 and fix all four, without
.hadolint.yamlignore entries and without inline# hadolint ignore=directives.Specifics that matter, since two of these have real runtime consequences:
DockerfileandDockerfile.testalready pin their uids explicitly (adduser -u 1000,adduser -u 10001), soUSER cudly->USER 1000:1000andUSER e2e->USER 10001are pure substitutions.Dockerfile.devusesadduser -S, which takes the first free system id and therefore varies with the base image. Its uid/gid need pinning before a numericUSERis meaningful.Dockerfile:165must not be converted naively. The line isCMD curl -f http://localhost:8080/health || exit 1, and||is a shell operator. A bare exec-form list would pass||andexitto curl as literal arguments and the healthcheck would stop reporting unhealthy correctly. The correct form is["/bin/sh", "-c", "curl -f http://localhost:8080/health || exit 1"], which satisfies DL3025 and preserves the process tree.Status
PR #1700 implements exactly this and is open. It was written against the pre-#1697 tree, has been rebased onto current
main, and its duplicate pin commit dropped out automatically as already-upstream. It is verified with Docker: hadolint 2.15.1 exits 0, all three images build, runtime identities resolve (uid=1000(cudly),uid=10001(e2e),uid=1001(devuser)), and the healthcheck is exercised in both directions.This issue exists so that work is tracked against something, rather than against the already-closed #1695.