Lint a Dockerfile with a Mock Hadolint in Python

A lightweight Python script that simulates hadolint by scanning Dockerfile text for common lint rules and printing violations.

Easy Python 3.9+ Aug 9, 2026 Modern tooling 14 views 0 copies

Python code

48 lines
Python 3.9+
import subprocess
import tempfile
from pathlib import Path


def lint_dockerfile(content: str) -> list[str]:
    """Mock hadolint by checking a few rules and returning violations."""
    violations = []
    lines = content.splitlines()

    for idx, line in enumerate(lines, start=1):
        stripped = line.strip()
        if not stripped or stripped.startswith("#"):
            continue

        if stripped.upper().startswith("FROM"):
            if ":" not in stripped and "@" not in stripped:
                violations.append(f"DL3006: Always tag the version of an image explicitly (line {idx})")

        if stripped.upper().startswith("RUN") and ("curl" in stripped.lower() or "wget" in stripped.lower()):
            if "--no-cache" not in stripped.lower():
                violations.append(f"DL3009: Delete the apt-get lists after installing something (line {idx})")

        if stripped.upper().startswith("CMD") and not stripped.startswith("CMD ["):
            violations.append(f"DL3025: Use JSON array syntax for CMD (line {idx})")

    return violations


if __name__ == "__main__":
    dockerfile_content = """
FROM ubuntu
RUN apt-get update && apt-get install -y curl
CMD echo "hello"
"""
    with tempfile.NamedTemporaryFile(mode="w", suffix=".dockerfile", delete=False) as f:
        f.write(dockerfile_content)
        temp_path = Path(f.name)

    print(f"Linting {temp_path.name}:")
    result = lint_dockerfile(dockerfile_content)
    if result:
        for violation in result:
            print(violation)
    else:
        print("No violations found")

    temp_path.unlink(missing_ok=True)

Output

stdout
Linting tmpXXXXXXXX.dockerfile:
DL3006: Always tag the version of an image explicitly (line 2)
DL3009: Delete the apt-get lists after installing something (line 3)
DL3025: Use JSON array syntax for CMD (line 4)

How it works

This mock linter parses the Dockerfile line by line, skipping blanks and comments, then checks for specific patterns: untagged FROM images, RUN commands with curl/wget lacking --no-cache, and CMD instructions not using JSON array syntax. Each rule appends a violation string with a line number. The if __name__ == "__main__" block writes the Dockerfile to a temporary file to simulate a real file operation, then prints violations or a clean message. This gives you a lightweight, dependency-free way to test linting logic locally or in CI without installing hadolint.

Common mistakes

  • Assuming all violations are caught — this mock covers only a few rules, not the full hadolint suite.
  • Forgetting that `--no-cache` is case‑sensitive in the check (lowercased only).
  • Not handling quoted or multiline RUN commands correctly.
  • Skipping the temporary file cleanup if an exception occurs.

Variations

  1. Use `requests` to call the hadolint Docker image via a shell command instead of a pure mock.
  2. Parse the Dockerfile with a parser library like `dockerfile-parse` for more accurate rules.

Real-world use cases

  • Running a pre‑commit hook that quickly flags common Dockerfile mistakes without installing external tools.
  • Validating Dockerfiles in a CI pipeline as a lightweight smoke test before full hadolint.
  • Teaching Docker best practices in a workshop or tutorial with an illustrated mock example.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Modern tooling

Related tutorials and quizzes for this topic.