Skip to content

feat: add hadolint for dockerfiles #4002

Merged
arkid15r merged 11 commits into
OWASP:mainfrom
hassaansaleem28:feat/add-docker-files-linting
Feb 21, 2026
Merged

feat: add hadolint for dockerfiles #4002
arkid15r merged 11 commits into
OWASP:mainfrom
hassaansaleem28:feat/add-docker-files-linting

Conversation

@hassaansaleem28
Copy link
Copy Markdown
Contributor

Proposed change

Resolves #3983

This pr adds hadolint to lint all Docker files; the linter is python wrapper, so we don't need to install any other dependencies in CI. Some other warnings are ignored by placing that in the hadolint YAML file. Locally, we can simply run pre-commit run --all-files to test it, and pre-commit already runs in CI.

Checklist

  • Required: I followed the contributing workflow
  • Required: I verified that my code works as intended and resolves the issue as described
  • Required: I ran make check-test locally: all warnings addressed, tests passed
  • I used AI for code, documentation, tests, or communication related to this PR

Signed-off-by: Muhammad Hassaan Saleem <iamhassaans@gmail.com>
@github-actions github-actions Bot added the docker Pull requests that update Docker code label Feb 19, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 19, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds Hadolint config and a pre-commit Hadolint hook; updates Dependabot; switches many Dockerfiles to use corepack/pnpm and to install Python deps via a build requirements file; adjusts frontend packageManager version and cspell metadata; introduces fuzz schemathesis dependency.

Changes

Cohort / File(s) Summary
Hadolint & pre-commit
\.hadolint.yaml, .pre-commit-config.yaml
Add .hadolint.yaml ignoring DL3042, DL3013, DL3016; add hadolint-py pre-commit hook (repo AleksaC/hadolint-py, rev v2.14.0) with --failure-threshold=warning.
Frontend & cspell package metadata
frontend/package.json, cspell/package.json
Bump packageManager in frontend/package.json to pnpm@10.30.1; add packageManager: "pnpm@10.30.1" to cspell/package.json.
Corepack / pnpm changes across Dockerfiles
docker/frontend/Dockerfile, docker/frontend/Dockerfile.*.test, docker/frontend/Dockerfile.local, cspell/Dockerfile, docker/cspell/Dockerfile
Replace NPM_CACHE → NPM_CONFIG_CACHE; remove explicit global pnpm/npm install steps; add corepack enable + corepack install and run pnpm install --frozen-lockfile --ignore-scripts.
Backend Dockerfile variants (requirements.build integration)
docker/backend/Dockerfile, docker/backend/Dockerfile.* (video, fuzz, local, test)
Copy backend/requirements.build.txt into build image and install Python deps via pip --requirement /tmp/requirements.build.txt; adjust Poetry usage to exclude fuzz and other groups; reorganize WORKDIR/USER and multi-stage runtime in fuzz image.
Build tooling / manifests
backend/pyproject.toml, backend/requirements.build.txt, .github/dependabot.yml
Add group.fuzz.dependencies.schemathesis = "^4.10.2" to pyproject; add poetry==2.3.2 to backend/requirements.build.txt; add Dependabot npm entry for cspell directory.
Docs/docker local build
docker/docs/Dockerfile.local
Copy backend/requirements.build.txt to /tmp/ and switch pip install to use that requirements file instead of Poetry.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

ci, backend, frontend

Suggested reviewers

  • kasya
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning Multiple out-of-scope changes detected: updates to Docker build configurations, package managers, dependency versions, and backend/frontend package.json modifications that go beyond the Hadolint linting scope. Remove or justify non-linting changes: Dockerfile build modifications, corepack/pnpm updates, dependency version changes, and packageManager field updates should be addressed in separate PRs if unrelated to Hadolint linting.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: adding Hadolint for Docker file linting, which aligns with the primary objective of the PR.
Description check ✅ Passed The description is directly related to the changeset, explaining the addition of Hadolint for Docker file linting and referencing the resolved issue #3983.
Linked Issues check ✅ Passed The PR successfully implements both objectives from issue #3983: it adds Hadolint to pre-commit hooks via .pre-commit-config.yaml and adds a .hadolint.yaml configuration file to manage linting rules.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
.pre-commit-config.yaml (1)

3-3: Bump hadolint-py to v2.14.0

The latest version is v2.14.0 (released Sep 22, 2025). The pinned v2.12.0.2 (released Apr 24, 2024) is ~17 months outdated, missing new rules like DL3062 and improvements to existing rules.

♻️ Proposed update
-    rev: v2.12.0.2
+    rev: v2.14.0
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.pre-commit-config.yaml at line 3, Update the pinned hadolint-py pre-commit
hook version: replace the existing rev value "v2.12.0.2" with "v2.14.0" in the
.pre-commit-config.yaml entry for hadolint-py so the project picks up DL3062 and
other rule improvements; ensure the change only modifies the rev field for the
hadolint-py hook and run pre-commit autoupdate or a quick local hook run to
verify compatibility.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.hadolint.yaml:
- Around line 2-4: Remove the global ignores for DL3013, DL3016, and DL3018 from
.hadolint.yaml (leave DL3042 if desired) and instead add targeted inline
suppressions in the specific Dockerfiles: use comments like “# hadolint
ignore=DL3013” on the RUN line that executes pip (e.g., the RUN python -m pip
install ...), “# hadolint ignore=DL3018” on the RUN lines that use apk add, and
only add “# hadolint ignore=DL3016” where npm installs intentionally omit
pinning (the npm install -g pnpm@10.30.0 already pins so needs no suppression);
this keeps hadolint active globally while documenting and scoping any
intentional exceptions.

---

Nitpick comments:
In @.pre-commit-config.yaml:
- Line 3: Update the pinned hadolint-py pre-commit hook version: replace the
existing rev value "v2.12.0.2" with "v2.14.0" in the .pre-commit-config.yaml
entry for hadolint-py so the project picks up DL3062 and other rule
improvements; ensure the change only modifies the rev field for the hadolint-py
hook and run pre-commit autoupdate or a quick local hook run to verify
compatibility.

Comment thread .hadolint.yaml Outdated
Copy link
Copy Markdown
Collaborator

@arkid15r arkid15r left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might work, is there a way to make it more verbose for the error output? It fails but doesn't indicate why when I test it locally.

Comment thread .hadolint.yaml Outdated
Comment thread docker/frontend/Dockerfile Outdated
coderabbitai[bot]
coderabbitai Bot previously approved these changes Feb 20, 2026
Signed-off-by: Muhammad Hassaan Saleem <iamhassaans@gmail.com>
Signed-off-by: Muhammad Hassaan Saleem <iamhassaans@gmail.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
.pre-commit-config.yaml (1)

2-9: --format=tty is redundant and produces ANSI codes in CI logs

tty is hadolint's default output format, so the --format=tty arg is a no-op. More importantly, the TTY format emits ANSI escape codes that clutter CI log output. hadolint supports several formats via --format ARG — consider using --format=json or --format=checkstyle for CI-friendly output that can be parsed by tooling, or simply drop the arg to accept the default.

The --verbose flag similarly adds per-file scanning noise to CI runs; unless the extra output is actively useful, it can be omitted.

🔧 Suggested cleanup
       - id: hadolint
         args:
-          - --verbose
-          - --format=tty
           - --failure-threshold=error # fail only on errors, not warnings
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.pre-commit-config.yaml around lines 2 - 9, Remove the CI-unfriendly
hadolint arguments in the pre-commit hook: delete the --format=tty arg (it is
redundant and emits ANSI codes) and remove --verbose to reduce noisy per-file
output; either replace --format=tty with a CI-friendly format such as
--format=json or --format=checkstyle if structured output is needed, or omit the
--format arg entirely to use the default. Target the hadolint hook block (repo:
https://github.com/AleksaC/hadolint-py and hook id: hadolint) and update the
args list accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.pre-commit-config.yaml:
- Line 72: Revert the change that sets language: system for the
igorshubovych/markdownlint-cli pre-commit hook: remove the language: system line
so pre-commit can create and manage an isolated environment for the pinned rev:
v0.47.0, restoring hermetic behavior (locate the markdownlint hook entry
referencing rev: v0.47.0 / igorshubovych/markdownlint-cli and delete the
language: system key).

---

Nitpick comments:
In @.pre-commit-config.yaml:
- Around line 2-9: Remove the CI-unfriendly hadolint arguments in the pre-commit
hook: delete the --format=tty arg (it is redundant and emits ANSI codes) and
remove --verbose to reduce noisy per-file output; either replace --format=tty
with a CI-friendly format such as --format=json or --format=checkstyle if
structured output is needed, or omit the --format arg entirely to use the
default. Target the hadolint hook block (repo:
https://github.com/AleksaC/hadolint-py and hook id: hadolint) and update the
args list accordingly.

Comment thread .pre-commit-config.yaml Outdated
coderabbitai[bot]
coderabbitai Bot previously approved these changes Feb 20, 2026
@hassaansaleem28
Copy link
Copy Markdown
Contributor Author

I'm not really sure if inline ignore is preferred for those warnings or global. Let me know and I will update accordingly.

Signed-off-by: Muhammad Hassaan Saleem <iamhassaans@gmail.com>
coderabbitai[bot]
coderabbitai Bot previously approved these changes Feb 20, 2026
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 20 files (changes from recent commits).

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="docker/backend/Dockerfile">

<violation number="1" location="docker/backend/Dockerfile:27">
P1: Dockerfile now copies requirements.build.txt, but the file does not exist in the repo. This will make the image build fail at the COPY step (before poetry install).</violation>
</file>

<file name="docker/backend/Dockerfile.fuzz">

<violation number="1" location="docker/backend/Dockerfile.fuzz:22">
P2: Poetry venv path is assumed to be /home/owasp/.venv, but this Dockerfile never sets POETRY_VIRTUALENVS_IN_PROJECT. If Poetry creates the venv in its cache (default), /home/owasp/.venv won’t exist and the COPY/ PATH will break the image.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread docker/backend/Dockerfile
Comment thread docker/backend/Dockerfile.fuzz
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (5)
docker/frontend/Dockerfile.a11y.test (1)

14-17: Same corepack binary cache opportunity as Dockerfile.unit.test.

Consider adding --mount=type=cache,id=corepack,target=/root/.cache/node/corepack to avoid re-downloading the pnpm binary on cold builds.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docker/frontend/Dockerfile.a11y.test` around lines 14 - 17, The RUN layer
that installs corepack/pnpm (the RUN
--mount=type=cache,id=pnpm,target=/pnpm/store ... corepack enable && corepack
install && pnpm install ...) should reuse a cache for the corepack binary; add
an additional buildkit mount
--mount=type=cache,id=corepack,target=/root/.cache/node/corepack to the same RUN
instruction so the pnpm/corepack binary is cached across cold builds (use the
same cache id convention as Dockerfile.unit.test to share behavior).
.pre-commit-config.yaml (1)

2-9: Redundant name: hadolint override.

The name: key on line 8 re-declares the same name already defined in hadolint-py's .pre-commit-hooks.yaml, adding noise without effect.

♻️ Remove redundant name override
   - repo: https://github.com/AleksaC/hadolint-py
     rev: v2.14.0
     hooks:
       - id: hadolint
         args:
           - --failure-threshold=warning
-        name: hadolint
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.pre-commit-config.yaml around lines 2 - 9, Remove the redundant name
override by deleting the "name: hadolint" entry under the hadolint hook; keep
the repo: https://github.com/AleksaC/hadolint-py, rev: v2.14.0, hooks: and the
hook with id: hadolint and args: --failure-threshold=warning intact so the hook
relies on the canonical name from the hadolint-py .pre-commit-hooks.yaml.
cspell/Dockerfile (1)

12-14: Same corepack binary cache opportunity applies here.

As noted in docker/frontend/Dockerfile.unit.test, adding --mount=type=cache,id=corepack,target=/root/.cache/node/corepack to this RUN block avoids re-downloading the pnpm binary on each cold build.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cspell/Dockerfile` around lines 12 - 14, The RUN step that enables corepack
and installs pnpm should reuse a corepack cache to avoid re-downloading the pnpm
binary; update the RUN command that currently calls "corepack enable && corepack
install && pnpm install --frozen-lockfile --ignore-scripts" to include the
corepack cache mount option (use
--mount=type=cache,id=corepack,target=/root/.cache/node/corepack) so corepack
enable/install reuses the cached binary across builds; keep the existing pnpm
store cache mount (id=pnpm,target=/pnpm/store) and ensure both mounts are
specified on the same RUN invocation.
docker/frontend/Dockerfile.unit.test (1)

14-17: Consider caching the corepack binary store to avoid re-downloading pnpm on cold builds.

The --mount=type=cache,id=pnpm,target=/pnpm/store caches pnpm's package store, but corepack install downloads the pnpm binary into its own cache (~/.cache/node/corepack by default). Without a mount for it, every cache-cold build triggers a fresh binary download.

♻️ Proposed corepack cache mount (same pattern applies to all affected Dockerfiles)
 RUN --mount=type=cache,id=pnpm,target=/pnpm/store \
+    --mount=type=cache,id=corepack,target=/root/.cache/node/corepack \
     corepack enable && corepack install && \
     pnpm install --frozen-lockfile --ignore-scripts && \
     chown node:node /app
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docker/frontend/Dockerfile.unit.test` around lines 14 - 17, The RUN step
currently mounts pnpm's package store but not Corepack's binary cache, causing
pnpm to be re-downloaded on cold builds; update the RUN that calls "corepack
enable && corepack install" to add a cache mount for Corepack's binary cache
(e.g., --mount=type=cache,id=corepack,target=/root/.cache/node/corepack or the
appropriate user cache path) alongside the existing
--mount=type=cache,id=pnpm,target=/pnpm/store so Corepack's download is
persisted across builds.
docker/frontend/Dockerfile.local (1)

50-51: Consider adding a corepack cache mount to avoid re-downloading pnpm on every cache miss.

RUN corepack enable && corepack install in the final stage has no --mount=type=cache, whereas the builder stage mounts the pnpm store. When package.json changes (invalidating this layer), corepack will re-download the pnpm binary from the registry unconditionally.

⚡ Proposed cache mount for corepack in the final stage
-RUN corepack enable && corepack install
+RUN --mount=type=cache,id=corepack,target=/root/.cache/node/corepack \
+    corepack enable && corepack install
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docker/frontend/Dockerfile.local` around lines 50 - 51, The RUN step in the
final stage using "corepack enable && corepack install" re-downloads pnpm
whenever the package.json layer is invalidated; update that RUN invocation in
the final Dockerfile stage to use a buildkit cache mount for corepack (e.g., add
a --mount=type=cache pointing to a pnpm/corepack cache) so the pnpm binary/store
is persisted across builds, matching the builder stage’s pnpm store mount and
preventing unconditional redownloads when package.json changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docker/backend/Dockerfile.fuzz`:
- Around line 5-9: The builder stage ENV block is missing
POETRY_VIRTUALENVS_IN_PROJECT=true causing poetry to create virtualenvs in the
cache instead of /home/owasp/.venv; add POETRY_VIRTUALENVS_IN_PROJECT=true to
the same ENV list that defines APK_CACHE_DIR, PIP_CACHE_DIR, POETRY_CACHE_DIR
and PYTHONUNBUFFERED so that the subsequent poetry install (referenced in the
Dockerfile builder stage) will create /home/owasp/.venv and the later COPY
--from=builder /home/owasp/.venv and PATH setup will reference the correct
directory.

---

Nitpick comments:
In @.pre-commit-config.yaml:
- Around line 2-9: Remove the redundant name override by deleting the "name:
hadolint" entry under the hadolint hook; keep the repo:
https://github.com/AleksaC/hadolint-py, rev: v2.14.0, hooks: and the hook with
id: hadolint and args: --failure-threshold=warning intact so the hook relies on
the canonical name from the hadolint-py .pre-commit-hooks.yaml.

In `@cspell/Dockerfile`:
- Around line 12-14: The RUN step that enables corepack and installs pnpm should
reuse a corepack cache to avoid re-downloading the pnpm binary; update the RUN
command that currently calls "corepack enable && corepack install && pnpm
install --frozen-lockfile --ignore-scripts" to include the corepack cache mount
option (use --mount=type=cache,id=corepack,target=/root/.cache/node/corepack) so
corepack enable/install reuses the cached binary across builds; keep the
existing pnpm store cache mount (id=pnpm,target=/pnpm/store) and ensure both
mounts are specified on the same RUN invocation.

In `@docker/frontend/Dockerfile.a11y.test`:
- Around line 14-17: The RUN layer that installs corepack/pnpm (the RUN
--mount=type=cache,id=pnpm,target=/pnpm/store ... corepack enable && corepack
install && pnpm install ...) should reuse a cache for the corepack binary; add
an additional buildkit mount
--mount=type=cache,id=corepack,target=/root/.cache/node/corepack to the same RUN
instruction so the pnpm/corepack binary is cached across cold builds (use the
same cache id convention as Dockerfile.unit.test to share behavior).

In `@docker/frontend/Dockerfile.local`:
- Around line 50-51: The RUN step in the final stage using "corepack enable &&
corepack install" re-downloads pnpm whenever the package.json layer is
invalidated; update that RUN invocation in the final Dockerfile stage to use a
buildkit cache mount for corepack (e.g., add a --mount=type=cache pointing to a
pnpm/corepack cache) so the pnpm binary/store is persisted across builds,
matching the builder stage’s pnpm store mount and preventing unconditional
redownloads when package.json changes.

In `@docker/frontend/Dockerfile.unit.test`:
- Around line 14-17: The RUN step currently mounts pnpm's package store but not
Corepack's binary cache, causing pnpm to be re-downloaded on cold builds; update
the RUN that calls "corepack enable && corepack install" to add a cache mount
for Corepack's binary cache (e.g.,
--mount=type=cache,id=corepack,target=/root/.cache/node/corepack or the
appropriate user cache path) alongside the existing
--mount=type=cache,id=pnpm,target=/pnpm/store so Corepack's download is
persisted across builds.

Comment thread docker/backend/Dockerfile.fuzz
@codecov
Copy link
Copy Markdown

codecov Bot commented Feb 21, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.79%. Comparing base (5029bd2) to head (57bc3b6).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##             main    #4002   +/-   ##
=======================================
  Coverage   99.79%   99.79%           
=======================================
  Files         518      518           
  Lines       15939    15939           
  Branches     2171     2129   -42     
=======================================
  Hits        15907    15907           
  Misses          3        3           
  Partials       29       29           
Flag Coverage Δ
backend 100.00% <ø> (ø)
frontend 99.19% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 5029bd2...57bc3b6. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@sonarqubecloud
Copy link
Copy Markdown

@arkid15r arkid15r enabled auto-merge February 21, 2026 03:37
@arkid15r arkid15r added this pull request to the merge queue Feb 21, 2026
Merged via the queue into OWASP:main with commit 2f28f74 Feb 21, 2026
36 checks passed
@coderabbitai coderabbitai Bot mentioned this pull request Feb 21, 2026
4 tasks
@coderabbitai coderabbitai Bot mentioned this pull request May 10, 2026
4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend docker Pull requests that update Docker code frontend

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Dockerfile Linting

2 participants