Add a lint workflow covering all five languages - #10
Merged
Merged
Conversation
Six parallel jobs, one per language plus the workflows themselves, so a failure points straight at the area that broke. Together they run in well under a minute. shell shellcheck -x -S warning c gcc -Wall -Wextra -Werror -fanalyzer, then cppcheck python ruff, then bandit yaml yamllint --strict docker hadolint workflows actionlint Conventions follow the Ares2 workflows: empty top-level permissions with a read-only grant per job, checkout without persisted credentials, actions pinned to a commit SHA, external binaries verified against a checksum, a timeout on every job, and concurrency cancellation for pull requests only. Some choices worth stating: - shellcheck runs with -x so it follows the "source" directives. Without it the shared library file is analysed in isolation and every caller reports findings that do not exist. - The C job discovers sources with find rather than listing them. A hard-coded list breaks as soon as a file is added or removed on another branch. - cppcheck runs with --enable=warning only. The "style" category is largely taste, and its findings differ between cppcheck versions, which would make the gate fail depending on the runner image rather than on the code. - bandit is configured through --ini: its --configfile expects YAML, while .bandit is an INI file, and passing the wrong one fails the run outright. - The thresholds and exceptions live in .hadolint.yaml, .yamllint and .bandit rather than in this workflow, so a local run behaves like CI. Every job was simulated locally against the actual commands before this was committed, and all six pass on this branch.
8 tasks
MarkusPaulsen
pushed a commit
that referenced
this pull request
Sep 8, 2026
Two corrections to the previous commit, both found by comparing against the Ares2 originals rather than by reading my own version again. Section 4 had lost its fill-in scaffold. Ares2 ends the section with Prerequisites, Steps, Expected result, Negative case and the modes exercised, so an author is asked for the negative case in the body of the pull request, where a reviewer looks for it. My version dropped all of it and then reintroduced the same idea as a checklist tick, which is weaker: a tick claims the case was covered, the scaffold makes the author write down what it was. The scaffold is back, with the four Ares enforcement combinations replaced by the three layers this project composes, each of which can be disabled on its own. Section 4 had also lost both recurring meta-rules, its character limit and the "simple words" paragraph, even though the template states in its own header that they are repeated in every section where they apply. The counts now match Ares2 exactly: seven limits, six "simple words" paragraphs, eleven "always required" statements. The template check itself is adopted, which is what makes the template binding rather than advisory: - .github/scripts/CheckPullRequestTemplate.java differs from the Ares2 version in a single line, the escape phrase for section 5, because this repository has no production Java code to report coverage for and answers that section with "No behaviour covered by the suites changed". - .github/workflows/pullrequest-template.yml is taken over unchanged. It runs the checker in single-file source mode, so there is no build step, exempts Renovate and Dependabot at step level so a required check never hangs pending, and passes the pull request body through the environment rather than interpolating it into the shell, since a fork author controls it verbatim. Running the checker locally against the open pull requests: #11 and #12 pass, #8, #9 and #10 do not yet, and their descriptions are being brought into shape separately.
10 tasks
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Summary
Second of two, on top of #9 which clears the findings so this starts green. Six parallel jobs cover the five languages in the repository plus the workflows themselves: shellcheck, gcc with cppcheck, ruff with bandit, yamllint, hadolint and actionlint. All of it finishes in well under a minute.
Linked issues
No linked issues.
1. Problem
The repository has no CI at all. 2900 lines of shell, C and Python that define the sandbox boundary are checked by nobody before merge, and the two suites under
tests/only run when somebody remembers to run them.For a sandbox this matters more than usual: the defects that count are unquoted expansions on attacker-influenced paths, a shell invocation assembled from data, and a workflow that hands secrets to untrusted pull request code. All three are exactly what these linters find.
2. Improvement from the user's perspective
No Improvement from the user's perspective. This changes no behaviour a run can observe.
3. Improvement from the maintainer's perspective
A reviewer stops spending attention on quoting and formatting, and a failure names the language it came from, so it points straight at the area that broke. Thresholds and exceptions live in
.hadolint.yaml,.yamllintand.bandit, so a local run behaves exactly like CI.4. Testing manual
Prerequisites
Steps
find . -name '*.sh' -print0 | xargs -0 docker run --rm -v "$PWD:/mnt" -w /mnt koalaman/shellcheck:v0.11.0 -x -S warning.ubuntu:24.04,gcc -fsyntax-only -Wall -Wextra -Werror -fanalyzerover every.cfile, thencppcheck --enable=warning --error-exitcode=1.ruff check --no-cache ., thenbandit --recursive --ini .bandit --severity-level medium docker/prune_phase/orchestrate var/tmp/helpers.yamllint --strict .,hadolint --config .hadolint.yamlper Dockerfile, andactionlint.Expected result
Every command exits zero and prints nothing beyond informational hadolint output, which sits below the configured threshold. After merge, the same six jobs appear on a pull request and the workflow itself is checked by actionlint.
Negative case (what must still be rejected)
Each gate must fail on a real defect rather than merely pass on a clean tree. Verified by construction while writing it: a hard-coded C file list failed as soon as a file existed only on another branch,
--enable=stylefailed depending on the cppcheck version rather than on the code, and--configfileaborted bandit outright because.banditis INI while that flag expects YAML. All three are fixed in this branch.Layers exercised
No layer-specific behaviour changed.
5. Test case coverage regarding this PR
No behaviour covered by the suites changed. The three suites that #8 adds under
tests/landlock-acceptance/were checked against the shell job and are clean, so this stays green when #8 merges.Breaking changes and migration
No breaking changes or migration.
Checklist
--privileged,--cap-addor--security-opt, or the manual says why that was not possible.README.md, the comments incore/) was updated where the change is user-facing.Review progress