Dockerfile Linter Pro
Lint Dockerfiles for security, cache and bloat issues with rule ids and line numbers.
Overview
A deeper Dockerfile linter that reports rule IDs and line numbers alongside each finding - friendly output for CI pipelines that need to grep for specific rule codes or fail builds on certain severities. Covers security (root user, exposed secrets), cache efficiency (instruction order, package manager cleanup), and image bloat (forgotten dev dependencies, multi-stage opportunities).
It's for teams enforcing Dockerfile quality as part of code review or CI, where "looks fine" isn't enough and you need machine-readable diagnostics. Reach for it when standing up a security baseline, codifying a base-image policy, or chasing down why a supposedly "thin" image ballooned to a gigabyte.
How it works
The linter walks each instruction with a rule engine modelled on hadolint's coverage. Rules have stable IDs (e.g. DL3007 for latest tag, DL3008 for unpinned apt packages) and three severity tiers (info, warning, error). Each finding records the instruction's line in the source, the offending text, and a short rationale.
Multi-stage builds are tracked across stages so warnings about leftover dev dependencies fire only in the final stage. BuildKit-specific syntax (# syntax=, --mount=type=) is recognised so it isn't flagged as unknown.
Examples
- Unpinned apt package:
RUN apt-get install -y curl # DL3008 [warning, line 5]: pin package version - Useless
cdin RUN:RUN cd /app && npm install # DL3003 [warning, line 7]: use WORKDIR instead of cd - Add over Copy:
ADD ./src /app # DL3020 [info, line 9]: use COPY for local files - Missing healthcheck (informational):
# DL3057 [info]: HEALTHCHECK not declared
FAQ
Can I disable a specific rule?
The output is informational - filter by severity or rule ID in your CI script. For project-wide policy, integrate the linter's JSON output with a rules ignore-list.
Are the rule IDs compatible with hadolint?
Most overlap deliberately, so you can carry over a hadolint ignore file. A handful of rules are unique to this linter and use a TB#### prefix to avoid collisions.
Does it follow # hadolint inline directives?
Yes - # hadolint ignore=DL3008 and # hadolint shell= are honoured for compatibility.
Why does it flag my entrypoint shell form?
ENTRYPOINT cmd ... (shell form) wraps in /bin/sh -c, which doesn't forward signals correctly and breaks docker stop. Use the exec form ENTRYPOINT ["cmd", "arg"] instead.