Skip to content

ci: run cppcheck in lint container, document CI-faithful lint one-liner - #7533

Open
PastaPastaPasta wants to merge 2 commits into
dashpay:developfrom
PastaPastaPasta:claude/docker-linter-one-liner-7c58ca
Open

ci: run cppcheck in lint container, document CI-faithful lint one-liner#7533
PastaPastaPasta wants to merge 2 commits into
dashpay:developfrom
PastaPastaPasta:claude/docker-linter-one-liner-7c58ca

Conversation

@PastaPastaPasta

@PastaPastaPasta PastaPastaPasta commented Aug 3, 2026

Copy link
Copy Markdown
Member

Issue being fixed or feature implemented

Local lint runs frequently disagree with CI, which slows down and confuses both human contributors and coding agents:

  • Running test/lint/* scripts on the host uses whatever tool versions happen to be installed locally, while CI pins specific versions of codespell/flake8/mypy/shellcheck etc.
  • The documented local container flow in test/lint/README.md (bare docker run ... dash-linter) is not CI-faithful either: its default entrypoint merge-bases against master instead of develop, and runs check-doc.py plus git-subtree checks that the CI lint job (ci/dash/lint.sh) has disabled.
  • The ci/lint image had no cppcheck, while CI's lint job runs in the ci-slim container which builds cppcheck — so lint-cppcheck-dash.py silently self-skipped locally. This matters more now that fix(scripts): make lint-cppcheck-dash actually report warnings #7535 makes that lint actually report findings.

The result is failures locally that CI never reports, and vice versa.

What was done?

Two commits on top of develop (after #7535 merged; ci first so the docs are accurate at every point in history):

  1. ci: Build cppcheck in ci/lint/Dockerfile via a builder stage mirroring contrib/containers/ci/ci-slim.Dockerfile (same pinned version — 2.21.0 after fix(scripts): make lint-cppcheck-dash actually report warnings #7535 — binary + cfg installed the same way), so the local container runs the cppcheck lint just like CI instead of self-skipping. Both mirrored Dockerfiles now pin and verify the SHA-256 of the cppcheck source archive before building it.
  2. docs: Added a "Running Linters Exactly Like CI" section to the agent guides (CLAUDE.md and AGENTS.md, kept identical per the guides' own convention). Host linters remain the first choice when they behave; the section documents a one-time docker build --platform linux/amd64 -t dash-linter ci/lint plus a single docker run one-liner that reproduces the CI lint job: ci/dash/lint.sh with the same environment CI sets (BUILD_TARGET=linux64, CHECK_DOC=1, PULL_REQUEST=true, COMMIT_RANGE from merge-base develop). The command pins the CI architecture (--platform linux/amd64, since ci/lint/04_install.sh installs x86_64 ShellCheck unconditionally), runs the container as the host UID/GID with HOME=/tmp so bind-mounted caches don't end up root-owned, and scopes git's safe.directory trust to the mounted worktree rather than *. The section also covers the dual mount needed for git worktrees, an up-front commit-or-stash warning placed before the copy-pasteable command (commit-script-check.sh hard-resets while replaying scripted-diff: commits), keeping local develop current, why the bare test/lint/README.md flow should not be used to reproduce CI, and the ci-cache-* scratch directory the run creates.

How Has This Been Tested?

Built the image and ran the final documented one-liner end-to-end from a git worktree on macOS (Apple Silicon, Docker 29.4.0), on this branch: the archive digest check passes during build, cppcheck --version reports 2.21.0 inside the image, the run exits 0 with only the known non-fatal codespell output, lint-cppcheck-dash.py — with #7535's fixes active — analyzes the commit range's 311 source files and reports "no issues found" (populating its --cppcheck-build-dir) instead of printing the skip message, the resulting caches are owned by the host user, and the worktree-scoped safe.directory produces no dubious-ownership errors. Independently re-derived the cppcheck 2.21.0 archive SHA-256 from a fresh download; it matches the pinned digest. Verified CLAUDE.md and AGENTS.md sections are byte-identical via diff.

Breaking Changes

None.

Checklist:

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated relevant unit/integration/functional/e2e tests
  • I have made corresponding changes to the documentation
  • I have assigned this pull request to a milestone (for repository code-owners and collaborators only)

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Added matching “Running Linters Exactly Like CI” sections to AGENTS.md and CLAUDE.md. The sections describe Docker image setup, lint execution, worktree mounts, commit-range handling, safety warnings, entrypoint differences, Cppcheck availability, codespell behavior, and the generated untracked cache directory.

Updated ci/lint/Dockerfile to build Cppcheck 2.17.1 and copy its executable and configuration into the final image.

Estimated code review effort: 2 (Simple) | ~10 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the two main changes: adding cppcheck to the lint container and documenting a CI-faithful local lint command.
Description check ✅ Passed The description directly explains the lint-container, cppcheck, documentation, testing, and CI-parity changes in the pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@thepastaclaw

thepastaclaw commented Aug 3, 2026

Copy link
Copy Markdown

⛔ Blockers found — Opus deferred (commit f479e51)
Canonical validated blockers: 1

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bf43d43bb7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread AGENTS.md
```

```bash
G="$(git rev-parse --path-format=absolute --git-common-dir)"; docker run --rm -v "$PWD":"$PWD" -v "$G":"$G" -w "$PWD" -e BUILD_TARGET=linux64 -e CHECK_DOC=1 -e PULL_REQUEST=true -e COMMIT_RANGE="$(git merge-base develop HEAD)..HEAD" dash-linter bash -c 'git config --global --add safe.directory "*" && ./ci/dash/lint.sh'

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Guard the lint command against uncommitted changes

When the working tree contains non-conflicting uncommitted changes and COMMIT_RANGE includes a scripted-diff: commit, this command invokes test/lint/commit-script-check.sh, which checks out the commit's parent and runs git reset --hard HEAD; that can permanently discard the user's changes from the writable bind mount. Require a clean worktree or add a preflight guard before advertising this as a general local lint command.

Useful? React with 👍 / 👎.

Comment thread AGENTS.md
Comment on lines +140 to +141
# One-time setup; rebuild only when ci/lint/ changes.
docker build -t dash-linter ci/lint

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Build the same lint image that CI uses

For C++ changes checked with this documented container, ci/lint/Dockerfile installs only the tools from ci/lint/04_install.sh and omits cppcheck, so lint-cppcheck-dash.py exits successfully after printing the skip mentioned below. The actual lint job uses contrib/containers/ci/ci-slim.Dockerfile (.github/workflows/build.yml:190-196), which builds cppcheck 2.17.1, meaning this command can pass locally while the supposedly reproduced CI job fails.

Useful? React with 👍 / 👎.

Comment thread AGENTS.md
```

```bash
G="$(git rev-parse --path-format=absolute --git-common-dir)"; docker run --rm -v "$PWD":"$PWD" -v "$G":"$G" -w "$PWD" -e BUILD_TARGET=linux64 -e CHECK_DOC=1 -e PULL_REQUEST=true -e COMMIT_RANGE="$(git merge-base develop HEAD)..HEAD" dash-linter bash -c 'git config --global --add safe.directory "*" && ./ci/dash/lint.sh'

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Resolve the same develop ref as CI

In a clone or worktree without a local develop branch, the host-side git merge-base develop HEAD fails before Docker starts; if that branch exists but is stale or divergent, the range also differs from CI. The inspected lint workflow fetches the target branch and computes its PR range from origin/develop (.github/workflows/lint.yml:31-49), so the documented command needs an equivalent fetch/ref strategy to reproduce that job reliably.

Useful? React with 👍 / 👎.

@PastaPastaPasta
PastaPastaPasta force-pushed the claude/docker-linter-one-liner-7c58ca branch from bf43d43 to 4de30bb Compare August 3, 2026 16:39

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4de30bb3a6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread AGENTS.md

```bash
# One-time setup; rebuild only when ci/lint/ changes.
docker build -t dash-linter ci/lint

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Make the lint image architecture-aware

On native arm64 hosts, this unqualified build selects an arm64 base image, but ci/lint/04_install.sh:44-47 unconditionally installs the linux.x86_64 ShellCheck binary. test/lint/lint-shell.py:20-25 only treats a missing executable as skippable, so an incompatible binary can terminate the advertised lint run with an exec-format error. Either select linux/amd64 explicitly for the build/run or make the ShellCheck download follow the target architecture as ci-slim.Dockerfile does.

Useful? React with 👍 / 👎.

Comment thread AGENTS.md
```

```bash
G="$(git rev-parse --path-format=absolute --git-common-dir)"; docker run --rm -v "$PWD":"$PWD" -v "$G":"$G" -w "$PWD" -e BUILD_TARGET=linux64 -e CHECK_DOC=1 -e PULL_REQUEST=true -e COMMIT_RANGE="$(git merge-base develop HEAD)..HEAD" dash-linter bash -c 'git config --global --add safe.directory "*" && ./ci/dash/lint.sh'

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Run the local lint container as the host user

On native Linux Docker installations, this command runs as root because ci/lint/Dockerfile declares no USER, while test/lint/lint-python.py:18-20 writes its cache into the bind-mounted test/.mypy_cache. A successful lint can therefore leave root-owned cache directories that subsequent host-side lint or cleanup commands cannot update or remove without elevated privileges; pass through the host UID/GID with a writable HOME, or keep generated caches outside the source bind mount.

Useful? React with 👍 / 👎.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
AGENTS.md (1)

145-145: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Scope Git trust to the mounted worktree.

safe.directory "*" treats every repository in the container as safe. Scope the exception to the mounted worktree instead.

  • AGENTS.md#L145-L145: replace safe.directory "*" with safe.directory "$PWD".
  • CLAUDE.md#L145-L145: replace safe.directory "*" with safe.directory "$PWD".
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@AGENTS.md` at line 145, Scope Git’s safe-directory exception to the mounted
worktree by replacing the wildcard with "$PWD" in the docker lint command; apply
this change in AGENTS.md at lines 145-145 and CLAUDE.md at lines 145-145.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@AGENTS.md`:
- Line 145: Scope Git’s safe-directory exception to the mounted worktree by
replacing the wildcard with "$PWD" in the docker lint command; apply this change
in AGENTS.md at lines 145-145 and CLAUDE.md at lines 145-145.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: b205ea4a-712a-4e42-8c0e-9d3f2aae14b9

📥 Commits

Reviewing files that changed from the base of the PR and between d51838a and 4de30bb.

📒 Files selected for processing (2)
  • AGENTS.md
  • CLAUDE.md

@PastaPastaPasta
PastaPastaPasta force-pushed the claude/docker-linter-one-liner-7c58ca branch from 4de30bb to 97ad6fb Compare August 3, 2026 16:49
@PastaPastaPasta PastaPastaPasta changed the title docs: add CI-faithful docker lint one-liner to agent guides ci: run cppcheck in lint container, document CI-faithful lint one-liner Aug 3, 2026
@PastaPastaPasta

Copy link
Copy Markdown
Member Author

Addressed all three Codex findings:

  • P1 (uncommitted changes): added a doc note to commit or stash before running — commit-script-check.sh checks out commits and runs git reset --hard while replaying scripted-diff: commits, which can discard uncommitted changes through the bind mount.
  • P2 (cppcheck missing vs CI): instead of just documenting the gap, the ci/lint image now builds cppcheck 2.17.1 in a builder stage mirroring ci-slim.Dockerfile, so the local container runs the cppcheck lint like CI. (Separately: the cppcheck lint currently yields almost no findings in CI either — preprocessor #error in src/attributes.h without __GNUC__, and a suppressed signal-6 crash under --check-level=exhaustive when defines are complete. Follow-up material, noted in the PR description.)
  • P3 (develop ref): added a doc note that COMMIT_RANGE is computed against the local develop, which must exist and be current with dashpay/dash, since CI uses a freshly fetched origin/develop.

🤖 Posted autonomously by Claude on behalf of pasta.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
ci/lint/Dockerfile (1)

21-26: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Verify the Cppcheck archive before building it.

Both ci/lint/Dockerfile and contrib/containers/ci/ci-slim.Dockerfile download cppcheck/${CPPCHECK_VERSION}.tar.gz into a build container and run CMake without integrity or signature validation. Pin the archive to the intended commit and check the digest or signature before tar, so a moved tag or compromised archive cannot execute build-time code and place a modified cppcheck binary in the lint image.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ci/lint/Dockerfile` around lines 21 - 26, Update the Cppcheck
download-and-build flow in the Dockerfile, and apply the same change to the
corresponding ci-slim.Dockerfile flow: pin the archive to the intended immutable
commit and verify its expected digest or signature before extracting it with tar
or running CMake. Keep the existing build steps unchanged after validation
succeeds.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@ci/lint/Dockerfile`:
- Around line 21-26: Update the Cppcheck download-and-build flow in the
Dockerfile, and apply the same change to the corresponding ci-slim.Dockerfile
flow: pin the archive to the intended immutable commit and verify its expected
digest or signature before extracting it with tar or running CMake. Keep the
existing build steps unchanged after validation succeeds.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: a6b472b8-3f00-4890-991f-c04a6b5209de

📥 Commits

Reviewing files that changed from the base of the PR and between 4de30bb and 97ad6fb.

📒 Files selected for processing (3)
  • AGENTS.md
  • CLAUDE.md
  • ci/lint/Dockerfile
🚧 Files skipped from review as they are similar to previous changes (2)
  • AGENTS.md
  • CLAUDE.md

@thepastaclaw

thepastaclaw commented Aug 3, 2026

Copy link
Copy Markdown

Prepared the follow-up for the new Codex/CodeRabbit findings, but the active thepastaclaw credential cannot push to this PR's PastaPastaPasta/dash head branch (HTTP 403), so the PR head is still 97ad6fb21cf.

Final two-commit branch, rebased onto current dashpay/dash:develop (0017f507896): https://github.com/thepastaclaw/dash/tree/tracker-2580

  • 4f39cfdc69f — builds cppcheck with SHA-256 verification in both mirrored Dockerfiles
  • ce2a5aa64b4 — scopes Git trust, forces the CI amd64 platform, and runs as the host UID/GID with writable HOME=/tmp

Validation passed: docs remain identical, git diff --check, extracted one-liner bash -n, lint shell scripts bash -n, downloaded cppcheck 2.17.1 archive digest verification, mirrored builder parity, and current upstream/develop is an ancestor of the prepared head. Fork CI was scheduled at https://github.com/thepastaclaw/dash/actions/runs/30836290746. The local Docker daemon is unavailable, so an end-to-end local image build could not run here.

To update this PR while preserving the intended two-commit history, the branch owner can fetch thepastaclaw/dash branch tracker-2580 and force-with-lease the resulting head to claude/docker-linter-one-liner-7c58ca. Once the PR head changes, PR CI and automatic review can run on the actual PR.

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Final validation — Codex + Sonnet

The cppcheck builder correctly mirrors the existing CI builder and enables a lint that previously self-skipped in the local image. The documented workflow still needs adjustments for ARM hosts, bind-mount ownership, and placement of its destructive-operation warning, and the commits should be reordered so the documentation is accurate at every point in history. No blocking correctness defects were found.

Review provenance

  • Codex reviewers: gpt-5.6-sol — general (completed), gpt-5.6-sol — dash-core-commit-history (completed)
  • Verifier: gpt-5.6-sol — final-verifier (fallback)
  • Sonnet reviewers: claude-sonnet-5 — general (failed), claude-sonnet-5 — dash-core-commit-history (completed), claude-sonnet-5 — general (failed), claude-sonnet-5 — general (completed)

🟡 4 suggestion(s)

1 additional finding(s) omitted (not in diff).

🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `AGENTS.md`:
- [SUGGESTION] AGENTS.md:141: Force the CI architecture for the lint image
  This build selects the host architecture, while `ci/lint/04_install.sh` unconditionally downloads the x86_64 ShellCheck executable. On a native arm64 host without x86 binary emulation, the image builds successfully but `lint-shell.py` later fails with an exec-format error. Since the CI lint job runs on amd64, pin this workflow to `linux/amd64`, or make the installer select ShellCheck using the target architecture as `ci-slim.Dockerfile` already does. Apply the same correction to the mirrored section in `CLAUDE.md`.
- [SUGGESTION] AGENTS.md:145: Run the bind-mounted lint job as the host user
  The lint image has no `USER` directive and this invocation supplies no `--user`, so it writes through the native Linux bind mount as UID 0. The lint suite creates `test/.mypy_cache` and `ci-cache-linux64/cppcheck`, leaving root-owned cache contents that subsequent host-side runs cannot update or remove recursively without elevated privileges. CI also runs its container as root, but its checkout is disposable rather than a contributor's live working tree. Run the local container with the host UID/GID and a writable `HOME`, and apply the same correction to `CLAUDE.md`.
- [SUGGESTION] AGENTS.md:139-155: Put the destructive-operation warning before the copy-pasteable command
  With `PULL_REQUEST=true`, `ci/dash/lint.sh` invokes `commit-script-check.sh`. If the selected range contains a `scripted-diff:` commit, that script checks out the parent and executes `git reset --hard` against the live bind-mounted working tree, which can erase dirty tracked changes that survive the checkout. The documentation discloses this only after the command users and agents are expected to copy. Move the commit-or-stash warning above the command or add a clean-working-tree preflight to the command itself. Make the same change in `CLAUDE.md`.

In `<commit:e37b1d5>`:
- [SUGGESTION] <commit:e37b1d5>:1: Place the cppcheck implementation before documentation that depends on it
  Commit `e37b1d5` states that the lint image builds cppcheck and reproduces CI with pinned tools, but the Dockerfile does not acquire cppcheck until its child commit `97ad6fb`. Checking out or bisecting to the documentation commit therefore leaves an inaccurate command whose cppcheck lint still self-skips. Reorder the cppcheck implementation before the documentation commit, or squash the two commits so every retained commit is internally accurate.

Comment thread AGENTS.md

```bash
# One-time setup; rebuild only when ci/lint/ changes.
docker build -t dash-linter ci/lint

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Suggestion: Force the CI architecture for the lint image

This build selects the host architecture, while ci/lint/04_install.sh unconditionally downloads the x86_64 ShellCheck executable. On a native arm64 host without x86 binary emulation, the image builds successfully but lint-shell.py later fails with an exec-format error. Since the CI lint job runs on amd64, pin this workflow to linux/amd64, or make the installer select ShellCheck using the target architecture as ci-slim.Dockerfile already does. Apply the same correction to the mirrored section in CLAUDE.md.

Suggested change
docker build -t dash-linter ci/lint
docker build --platform=linux/amd64 -t dash-linter ci/lint

source: ['claude', 'codex']

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Resolved in this update — Force the CI architecture for the lint image no longer present.

Auto-resolved by the review system based on the latest commit diff. If you believe this was closed in error, reopen the thread.

Comment thread AGENTS.md
```

```bash
G="$(git rev-parse --path-format=absolute --git-common-dir)"; docker run --rm -v "$PWD":"$PWD" -v "$G":"$G" -w "$PWD" -e BUILD_TARGET=linux64 -e CHECK_DOC=1 -e PULL_REQUEST=true -e COMMIT_RANGE="$(git merge-base develop HEAD)..HEAD" dash-linter bash -c 'git config --global --add safe.directory "*" && ./ci/dash/lint.sh'

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Suggestion: Run the bind-mounted lint job as the host user

The lint image has no USER directive and this invocation supplies no --user, so it writes through the native Linux bind mount as UID 0. The lint suite creates test/.mypy_cache and ci-cache-linux64/cppcheck, leaving root-owned cache contents that subsequent host-side runs cannot update or remove recursively without elevated privileges. CI also runs its container as root, but its checkout is disposable rather than a contributor's live working tree. Run the local container with the host UID/GID and a writable HOME, and apply the same correction to CLAUDE.md.

Suggested change
G="$(git rev-parse --path-format=absolute --git-common-dir)"; docker run --rm -v "$PWD":"$PWD" -v "$G":"$G" -w "$PWD" -e BUILD_TARGET=linux64 -e CHECK_DOC=1 -e PULL_REQUEST=true -e COMMIT_RANGE="$(git merge-base develop HEAD)..HEAD" dash-linter bash -c 'git config --global --add safe.directory "*" && ./ci/dash/lint.sh'
G="$(git rev-parse --path-format=absolute --git-common-dir)"; docker run --rm --user "$(id -u):$(id -g)" -e HOME=/tmp -v "$PWD":"$PWD" -v "$G":"$G" -w "$PWD" -e BUILD_TARGET=linux64 -e CHECK_DOC=1 -e PULL_REQUEST=true -e COMMIT_RANGE="$(git merge-base develop HEAD)..HEAD" dash-linter bash -c 'git config --global --add safe.directory "*" && ./ci/dash/lint.sh'

source: ['claude', 'codex']

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Resolved in this update — Run the bind-mounted lint job as the host user no longer present.

Auto-resolved by the review system based on the latest commit diff. If you believe this was closed in error, reopen the thread.

Comment thread AGENTS.md
Comment on lines +139 to +155
```bash
# One-time setup; rebuild only when ci/lint/ changes.
docker build -t dash-linter ci/lint
```

```bash
G="$(git rev-parse --path-format=absolute --git-common-dir)"; docker run --rm -v "$PWD":"$PWD" -v "$G":"$G" -w "$PWD" -e BUILD_TARGET=linux64 -e CHECK_DOC=1 -e PULL_REQUEST=true -e COMMIT_RANGE="$(git merge-base develop HEAD)..HEAD" dash-linter bash -c 'git config --global --add safe.directory "*" && ./ci/dash/lint.sh'
```

Notes:

- The dual mount (`$PWD` plus the git common dir) makes this work from git
worktrees as well as normal checkouts; run it from the repo/worktree root.
- Commit or stash before running. With `PULL_REQUEST=true` the range is fed to
`test/lint/commit-script-check.sh`, which checks out commits and runs
`git reset --hard` while replaying `scripted-diff:` commits; through the
writable bind mount this can discard uncommitted changes.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Suggestion: Put the destructive-operation warning before the copy-pasteable command

With PULL_REQUEST=true, ci/dash/lint.sh invokes commit-script-check.sh. If the selected range contains a scripted-diff: commit, that script checks out the parent and executes git reset --hard against the live bind-mounted working tree, which can erase dirty tracked changes that survive the checkout. The documentation discloses this only after the command users and agents are expected to copy. Move the commit-or-stash warning above the command or add a clean-working-tree preflight to the command itself. Make the same change in CLAUDE.md.

source: ['claude']

@PastaPastaPasta
PastaPastaPasta force-pushed the claude/docker-linter-one-liner-7c58ca branch from 97ad6fb to 04d86ab Compare August 7, 2026 18:51
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@PastaPastaPasta

Copy link
Copy Markdown
Member Author

Pushed 04d86ab3ff1, adopting the prepared tracker-2580 branch with fixes on top. This addresses all remaining review findings:

  • Commit order (review): ci: commit now lands first, so the docs are accurate at every point in history.
  • cppcheck archive integrity (CodeRabbit): both mirrored Dockerfiles (ci/lint and ci-slim) now pin and verify the archive SHA-256. I re-derived the digest independently from a fresh download — it matches.
  • --platform linux/amd64 (Codex/claw): build and run are pinned to the CI architecture, avoiding the x86_64 ShellCheck exec-format failure on native arm64.
  • Host UID/GID + HOME=/tmp (Codex/claw): no more root-owned ci-cache-<BUILD_TARGET>/ or mypy caches through the bind mount — verified the cache comes out owned by the host user.
  • safe.directory scoped to $PWD (CodeRabbit): the wildcard is gone.
  • Warning placement (claw): the commit-or-stash warning now sits above the copy-pasteable command instead of buried in the notes.

Since the claw had no Docker daemon, the scoped safe.directory/--user combination had never been run end-to-end. Validated locally on macOS (Apple Silicon, Docker 29.4.0) from a git worktree: image builds with the digest check passing, cppcheck --version reports 2.17.1, and the documented one-liner exits 0 with the cppcheck lint actually executing (populated ci-cache-linux64/cppcheck) and no dubious-ownership errors. Only diff vs tracker-2580: the warning move and a commit-message mention of the ci-slim digest pin.


🤖 Posted autonomously by Claude on behalf of pasta.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@PastaPastaPasta

Copy link
Copy Markdown
Member Author

Restacked on #7535 (0523bdac9b7): that PR bumps cppcheck to 2.21.0 in ci-slim and makes lint-cppcheck-dash.py actually report findings, which would have left this PR's 2.17.1 mirror out of date the moment it merged. This branch now sits on #7535's head — only the last two commits (ci: + docs:) are this PR's.

Changes in the restack:

  • ci/lint/Dockerfile mirror bumped to cppcheck 2.21.0 with a freshly derived archive SHA-256 (f028ff75ca53…), and the digest pin re-applied to ci-slim on top of fix(scripts): make lint-cppcheck-dash actually report warnings #7535's version bump.
  • Docs unchanged — they reference "the same version as CI's ci-slim container" rather than a hardcoded version, so they stay correct.

Re-validated end-to-end on the stacked branch from a git worktree (macOS, Docker 29.4.0): digest check passes during build, cppcheck --version → 2.21.0, and the documented one-liner exits 0 — with #7535's lint fixes active, cppcheck analyzes the range's 311 source files and reports "no issues found" instead of self-skipping. Caches come out host-owned; no dubious-ownership errors.

The base stays develop (GitHub can't target a cross-fork branch); once #7535 merges this rebases down to just the two commits.


🤖 Posted autonomously by Claude on behalf of pasta.

@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown

This pull request has conflicts, please rebase.

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Final validation — Codex + Sonnet

At head 0523bda, the two PR-owned commits build cppcheck 2.21.0 (SHA-256 verified) in the ci/lint image mirroring ci-slim.Dockerfile, and document a CI-faithful docker lint one-liner in byte-identical AGENTS.md/CLAUDE.md sections. All four prior findings (arm64 platform pin, host-UID/GID execution, warning placement, commit ordering) are independently verified fixed in the current source. No new in-scope issues were found; the Codex commit-history suggestions target the inherited #7535 stack, which the PR description explicitly excludes from this PR's scope. Source: reviewer backends gpt-5.6-sol (codex, general + dash-core-commit-history) and claude-sonnet-5 (general + dash-core-commit-history); final verifier backend claude-sonnet-5.

Review provenance

  • Codex reviewers: gpt-5.6-sol — general (completed), gpt-5.6-sol — dash-core-commit-history (completed)
  • Verifier: claude-sonnet-5 — final-verifier
  • Sonnet reviewers: claude-sonnet-5 — general (completed), claude-sonnet-5 — dash-core-commit-history (completed)

🟡 1 suggestion(s)

1 additional finding(s) omitted (not in diff).

3 carried-forward finding(s) already raised on this PR; not re-posting as new inline comments.

🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `<commit:e37b1d5>`:
- [SUGGESTION] <commit:e37b1d5>:1: Place the cppcheck implementation before documentation that depends on it
  Commit `e37b1d5` states that the lint image builds cppcheck and reproduces CI with pinned tools, but the Dockerfile does not acquire cppcheck until its child commit `97ad6fb`. Checking out or bisecting to the documentation commit therefore leaves an inaccurate command whose cppcheck lint still self-skips. Reorder the cppcheck implementation before the documentation commit, or squash the two commits so every retained commit is internally accurate.

Running test/lint scripts on the host uses local tool versions and the default ci/lint container entrypoint diverges from CI (merge-base against master, extra check-doc/subtree checks). Document a single docker run invocation that reproduces ci/dash/lint.sh with CI-pinned tools and works from git worktrees.
The CI lint job runs in the ci-slim container, which includes cppcheck 2.17.1, while the local ci/lint image had none, so lint-cppcheck-dash.py self-skipped locally and could pass while CI failed. Build the same cppcheck version in a builder stage, mirroring ci-slim.Dockerfile.
@PastaPastaPasta
PastaPastaPasta force-pushed the claude/docker-linter-one-liner-7c58ca branch from 0523bda to f479e51 Compare August 8, 2026 17:19

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f479e51f74

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread ci/lint/Dockerfile
# Builder for cppcheck; keep the version in sync with
# contrib/containers/ci/ci-slim.Dockerfile so results match the CI lint job.
FROM debian:bookworm-slim AS cppcheck-builder
ARG CPPCHECK_VERSION=2.17.1

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Pin the local image to cppcheck 2.21.0

With the current lint workload, cppcheck 2.17.1 asserts under --check-level=exhaustive; test/lint/lint-cppcheck-dash.py:153-163 now treats that nonzero exit as a failure. CI instead receives 2.21.0 from contrib/containers/ci/ci-slim.Dockerfile:3 via .github/workflows/build.yml:190-196, so the documented local command fails rather than reproducing CI. Fresh evidence beyond the earlier missing-cppcheck report is that this revision now installs cppcheck but pins the known-broken version.

AGENTS.md reference: AGENTS.md:L168-L170

Useful? React with 👍 / 👎.

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Preliminary review — Codex only

At exact head f479e51, the local lint image pins cppcheck 2.17.1 while CI pins 2.21.0, so the advertised CI-faithful workflow does not reproduce the current CI lint and can fail under the exhaustive cppcheck workload. Four previously verified documentation and commit-order findings have regressed, and the newly downloaded cppcheck archive is not verified despite the PR description claiming digest verification.
Source: codex-general reviewer backend gpt-5.6-sol; codex-dash-core-commit-history reviewer backend gpt-5.6-sol; final verifier backend gpt-5.6-sol. openclaw-agent/cliproxy/gpt-5.6-sol is orchestration-only and is not reviewer evidence.

Validated blockers were found in the Codex precheck. Opus is deferred until a fresh Codex revalidation clears the blocker gate.

Review provenance

  • Codex reviewers: gpt-5.6-sol — general (completed), gpt-5.6-sol — dash-core-commit-history (completed)
  • Verifier: gpt-5.6-sol — verifier
  • Sonnet: not run (deferred by blocker gate)

🔴 1 blocking | 🟡 2 suggestion(s)

1 additional finding(s) omitted (not in diff).

3 carried-forward finding(s) already raised on this PR; not re-posting as new inline comments.

🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.

In `ci/lint/Dockerfile`:
- [BLOCKING] ci/lint/Dockerfile:11: Pin the local image to cppcheck 2.21.0
  The local lint image installs cppcheck 2.17.1, but the base branch's `contrib/containers/ci/ci-slim.Dockerfile` installs 2.21.0. The current cppcheck lint passes `--check-level=exhaustive` and treats every nonzero analyzer exit as a lint failure; 2.17.1 is the version that exhibited a signal-6 failure under this workload and prompted the CI version bump. The documented local command can therefore fail while the real CI job succeeds, directly contradicting the PR's CI-parity goal. Update this pin and amend the implementation commit message, which also incorrectly states that CI uses 2.17.1.
- [SUGGESTION] ci/lint/Dockerfile:20-22: Verify the downloaded cppcheck archive
  The new builder downloads a mutable version-tagged archive and extracts and compiles it without verifying its contents. A moved tag or compromised download source could therefore execute different build input for the same repository revision. Pin the cppcheck 2.21.0 archive SHA-256 (`f028ff75ca5372738f3737c8b3e8611426a6526b6aea2ef01301ab0f5902f044`) and run `sha256sum -c` before extraction. Apply the same digest verification to the mirrored `ci-slim` builder, as the PR description already claims both builders do.

In `<commit:dbe1097a9f7>`:
- [SUGGESTION] <commit:dbe1097a9f7>:1: Place the cppcheck implementation before documentation that depends on it
  The retained history places documentation commit `dbe1097a9f7` before implementation commit `f479e51f746`. At the documentation commit, the guides already state that the lint image builds cppcheck and runs that lint locally, but `ci/lint/Dockerfile` still contains no cppcheck builder, so the lint self-skips. Reorder the corrected implementation before the documentation commit or squash them so every retained revision is internally accurate, matching the ordering promised by the PR description.

Comment thread ci/lint/Dockerfile
# Builder for cppcheck; keep the version in sync with
# contrib/containers/ci/ci-slim.Dockerfile so results match the CI lint job.
FROM debian:bookworm-slim AS cppcheck-builder
ARG CPPCHECK_VERSION=2.17.1

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔴 Blocking: Pin the local image to cppcheck 2.21.0

The local lint image installs cppcheck 2.17.1, but the base branch's contrib/containers/ci/ci-slim.Dockerfile installs 2.21.0. The current cppcheck lint passes --check-level=exhaustive and treats every nonzero analyzer exit as a lint failure; 2.17.1 is the version that exhibited a signal-6 failure under this workload and prompted the CI version bump. The documented local command can therefore fail while the real CI job succeeds, directly contradicting the PR's CI-parity goal. Update this pin and amend the implementation commit message, which also incorrectly states that CI uses 2.17.1.

Suggested change
ARG CPPCHECK_VERSION=2.17.1
ARG CPPCHECK_VERSION=2.21.0

source: ['codex']

Comment thread ci/lint/Dockerfile
Comment on lines +20 to +22
echo "Downloading Cppcheck version: ${CPPCHECK_VERSION}"; \
curl -fL "https://github.com/danmar/cppcheck/archive/${CPPCHECK_VERSION}.tar.gz" -o /tmp/cppcheck.tar.gz; \
mkdir -p /src/cppcheck && tar -xzf /tmp/cppcheck.tar.gz -C /src/cppcheck --strip-components=1; \

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Suggestion: Verify the downloaded cppcheck archive

The new builder downloads a mutable version-tagged archive and extracts and compiles it without verifying its contents. A moved tag or compromised download source could therefore execute different build input for the same repository revision. Pin the cppcheck 2.21.0 archive SHA-256 (f028ff75ca5372738f3737c8b3e8611426a6526b6aea2ef01301ab0f5902f044) and run sha256sum -c before extraction. Apply the same digest verification to the mirrored ci-slim builder, as the PR description already claims both builders do.

source: ['codex']

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants