Running with full hardening¶
The compose-lint Docker image is safe-by-default (distroless, nonroot, read-only attack surface), so the simple docker run --rm -v "$(pwd):/src" composelint/compose-lint form is fine for most use.
If you want to dogfood compose-lint's own rules against the container that runs it, the fully-hardened invocation is:
docker run --rm \
--read-only \
--cap-drop ALL \
--security-opt no-new-privileges:true \
--network none \
--user 65532:65532 \
--memory 256m \
--cpus 0.5 \
--pids-limit 256 \
-v "$(pwd):/src:ro" \
composelint/compose-lint:0.17.0
| Flag | Rule satisfied |
|---|---|
--security-opt no-new-privileges:true |
CL-0003 |
--cap-drop ALL |
CL-0006 |
--read-only |
CL-0007 |
--memory 256m + --cpus 0.5 |
CL-0026 |
--user 65532:65532 |
CL-0018 (matches the image's existing default) |
--pids-limit 256 |
— defence in depth; no rule flags its absence. CL-0012 used to, and was removed: on a mainstream systemd host the limit is bounded by DefaultTasksMax whether or not you set it |
--network none and :ro on the bind mount are extra hardening — compose-lint never reaches the network and only reads its inputs.
For full supply-chain reproducibility (and to satisfy CL-0004 / CL-0019), replace the version tag with a digest pin: composelint/compose-lint@sha256:<digest>. Get the current digest from Docker Hub or with docker buildx imagetools inspect composelint/compose-lint:0.17.0 --format '{{json .Manifest}}' | jq -r '.digest'.
A Compose-form equivalent that lints clean across every rule lives in tests/compose_files/safe_self_hosted.yml.