-
Notifications
You must be signed in to change notification settings - Fork 55
feat: add hadolint linting step to container workflow #2028
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
josecelano
merged 11 commits into
torrust:develop
from
josecelano:1460-add-hadolint-to-container-workflow
Jul 24, 2026
Merged
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
e0fe75d
docs(draft): add issue spec for hadolint container workflow (#1460)
josecelano 447004d
chore(cspell): add Dockerfiles
josecelano a7094bf
docs(semantic-links): document real-world placement syntax for non-Ma…
josecelano 227163e
feat(ci): add hadolint linting step to container workflow with global…
josecelano c37e53f
chore(ci): pin hadolint to digest, improve DL4006 rationale, fix yaml…
josecelano 4a5695a
docs(semantic-links): remove orphan backslash from marker table
josecelano e9e1d24
refactor(dev-tools): extract sensor scripts into contrib/dev-tools/ch…
josecelano da1b4f3
chore(dev-tools): remove format-project-words.sh from old git/ location
josecelano ffa2aa2
fix(ci): address Copilot review: DL4006 rationale, staged linting, mo…
josecelano 8845906
docs(dev-tools): add test file references to sensor scripts and test …
josecelano 3d98c36
fix(ci): address Copilot review: git diff error handling, echo pipe, …
josecelano File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| # ----- hadolint global ignore configuration ----- | ||
| # | ||
| # Rationale for each globally ignored rule is documented below. | ||
| # When adding a new inline `# hadolint ignore=` comment, also add rationale | ||
| # alongside it explaining why it's safe to ignore. | ||
| # | ||
| # Global ignores keep the Containerfile clean by avoiding repetitive | ||
| # `# hadolint ignore=` comments for rules that are systematically | ||
| # inapplicable to this project's build strategy. | ||
|
|
||
| ignored: | ||
| # DL3008: Pin versions in apt-get install. | ||
| # | ||
| # We do not pin package versions in intermediate build stages (chef, tester, | ||
| # gcc) because: | ||
| # - These stages are development/build-time only, not production runtime images | ||
| # - Pinning would require constant manual maintenance as base images update | ||
| # - The base image tag (e.g. `slim-trixie`) tracks the latest Debian trixie | ||
| # point release. Tags are not immutable — upstream can publish security | ||
| # rebuilds under the same tag. We accept this tag drift and rely on the | ||
| # CI rebuild cycle to pick up fixes. | ||
| - DL3008 | ||
|
|
||
| # DL3059: Multiple consecutive RUN instructions. | ||
| # | ||
| # We intentionally use separate RUN instructions for Docker layer caching. | ||
| # Each RUN creates a cacheable layer, which speeds up rebuilds when only | ||
| # specific steps change. Consolidating them would reduce cache efficiency | ||
| # and increase rebuild times during development. | ||
| - DL3059 | ||
|
|
||
| # DL4006: set -o pipefail is not available. | ||
| # | ||
| # Debian-based images use /bin/sh symlinked to /bin/dash, which does not | ||
| # support the `pipefail` option. Switching to `SHELL ["/bin/bash", "-o", | ||
| # "pipefail", "-c"]` would require installing bash in every build stage, | ||
| # adding unnecessary image size and build time. | ||
| # | ||
| # The pipe operations in this Containerfile are: | ||
| # - `curl -L --proto '=https' --tlsv1.2 -sSf https://... | bash`: downloads | ||
| # the cargo-binstall installer script from a GitHub raw URL (`/main/` branch). | ||
| # The URL points to a branch, not a pinned commit. The risk is that an | ||
| # upstream compromise could inject malicious content. However, the `-sSf` | ||
| # flags already make curl return a non-zero exit code on HTTP/download | ||
| # failures, and the downstream `cargo binstall` step will fail if the | ||
| # script produced no binary. This is a known trade-off accepted by the | ||
| # project: pinning to a specific commit would require manual updates on | ||
| # every upstream release and the upstream is a trusted dependency. | ||
| # - `ldd ... | grep ... | awk ...`: simple text processing for single-file | ||
| # library discovery. If the pipe fails, the `cp` target is empty and the | ||
| # subsequent build step (or runtime) will fail immediately. | ||
| - DL4006 | ||
|
|
||
| # SC2046: Quote to prevent word splitting. | ||
| # | ||
| # The unquoted `$(realpath ...)` expansion is used as the source argument | ||
| # for `cp` in a specific pattern where word splitting is intentional and | ||
| # safe: the output of `realpath` is a single path, and the `ldd | grep` | ||
| # pipeline it wraps also produces a single path. The ShellCheck warning | ||
| # is a false positive in this context. | ||
| # | ||
| # This is kept as a global ignore rather than inline because: | ||
| # - The pattern is identical in both debug and release stages (same | ||
| # `$(realpath $(ldd ... | grep ... | awk ...))` expression) | ||
| # - Inline `# hadolint ignore=SC2046` comments for ShellCheck rules in | ||
| # Dockerfiles have inconsistent behavior across hadolint versions | ||
| # - A global rule with documented rationale is cleaner and avoids | ||
| # duplicating the same inline comment with rationale in two places | ||
| - SC2046 | ||
|
josecelano marked this conversation as resolved.
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| #!/usr/bin/env bash | ||
| # Lint the Containerfile with hadolint. | ||
| # | ||
| # Tests: (no automated tests yet — EPIC #2003) | ||
| # | ||
| # This sensor is a standalone check: it can be triggered by any orchestrator | ||
| # (pre-commit hook, CI, Copilot file hooks, manual invocation). It only runs | ||
| # hadolint when the Containerfile has been staged for commit (git diff check). | ||
| # See EPIC #2003 for the long-term harness/sensor architecture design. | ||
| # | ||
| # Usage: | ||
| # ./contrib/dev-tools/checks/lint-containerfile.sh | ||
|
|
||
| set -uo pipefail | ||
|
|
||
| SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd) | ||
| PROJECT_ROOT=$(cd -- "${SCRIPT_DIR}/../../.." && pwd) | ||
| CONTAINERFILE="${PROJECT_ROOT}/Containerfile" | ||
| CONFIG="${PROJECT_ROOT}/.hadolint.yaml" | ||
| HADOLINT_IMAGE="hadolint/hadolint@sha256:27086352fd5e1907ea2b934eb1023f217c5ae087992eb59fde121dce9c9ff21e" | ||
|
|
||
| # Skip if Containerfile wasn't changed (staged). | ||
| # Use a separate check so that a non-zero exit from `git diff` (e.g. running | ||
| # outside a git work tree) is not silently swallowed by `!`. | ||
| if git diff --cached --name-only --diff-filter=ACM 2>/dev/null | grep -q '^Containerfile$'; then | ||
| : # Containerfile is staged — proceed | ||
| elif [[ $? -eq 1 ]]; then | ||
| # grep exited 1: Containerfile not found in staged changes | ||
| echo "Containerfile unchanged, skipping hadolint" | ||
| exit 0 | ||
| else | ||
| # git diff or grep failed (e.g. not a git repository) | ||
| echo "Error: cannot check staged changes (not a git repository?)." >&2 | ||
| exit 2 | ||
| fi | ||
|
|
||
| # Lint the staged version of the Containerfile to avoid false positives | ||
| # from unstaged working-tree changes. This ensures the sensor checks exactly | ||
| # what will be committed, not the current working tree. | ||
| # Use `git show` piped directly to avoid shell mangling from `echo`. | ||
| if [[ ! -f "${CONFIG}" ]]; then | ||
| echo "Warning: hadolint config '${CONFIG}' not found, running without." >&2 | ||
| git show :./"${CONTAINERFILE##*/}" 2>/dev/null | docker run --rm -i --entrypoint hadolint "${HADOLINT_IMAGE}" - | ||
| exit $? | ||
| fi | ||
|
|
||
| git show :./"${CONTAINERFILE##*/}" 2>/dev/null | docker run --rm -i \ | ||
| -v "${CONFIG}:/.hadolint.yaml" \ | ||
| --entrypoint hadolint \ | ||
| "${HADOLINT_IMAGE}" \ | ||
| --config /.hadolint.yaml \ | ||
| - | ||
|
|
||
| # Capture the exit code from the pipeline (last command: hadolint) | ||
| exit "${PIPESTATUS[0]}" | ||
|
josecelano marked this conversation as resolved.
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.