Invoke the formatter directly from the format hook (#1594)

* Invoke the formatter directly from the format hook

The PostToolUse format hook now runs prettier directly with a pinned
version and --no-config instead of going through the package.json
"format" script, so the hook resolves the same way regardless of the
scripts and formatter config in the checked-out tree. Output matches
the previous "bun run format" (both .prettierrc files are empty).

Also documents which paths the action restores from the PR base branch
and recommends keeping base-branch hooks self-contained.

No-Verification-Needed: config, comment, and doc-only change

* Qualify the self-contained hook guidance for Bun-only runners

Note in docs/security.md and the restore-config JSDoc that bunx runs the
tool under node when node is on PATH, but on a Bun-only runner Bun runs
the script itself and reads bunfig.toml (preload etc.) from the
checkout, so that file and .npmrc are runtime config from the PR head.

No-Verification-Needed: comment- and doc-only change

* Exclude .claude-pr from prettier

No-Verification-Needed: prettierignore-only change
This commit is contained in:
Ashwin Bhat 2026-08-05 15:38:47 -07:00 committed by GitHub
parent 9db594c7a0
commit 4c04887769
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 25 additions and 2 deletions

View File

@ -5,7 +5,7 @@
"hooks": [
{
"type": "command",
"command": "bun run format"
"command": "bunx prettier@3.5.3 --no-config --write ."
}
],
"matcher": "Edit|Write|MultiEdit"

View File

@ -1,2 +1,4 @@
# Test fixtures should not be formatted to preserve exact output matching
test/fixtures/
test/fixtures/
# Snapshot of PR-authored config kept for review; do not reformat
.claude-pr/

View File

@ -51,6 +51,14 @@ For `workflow_run` events, the action checks the repository access of the actor
This is general guidance for these event types — see [GitHub's documentation](https://securitylab.github.com/research/github-actions-preventing-pwn-requests/).
### Which files come from the base branch on pull requests
When the action runs against a pull request, it restores a fixed list of Claude configuration paths from the PR base branch before starting Claude: `.claude/`, `.mcp.json`, `.claude.json`, `.gitmodules`, `.ripgreprc`, `CLAUDE.md`, `CLAUDE.local.md`, and `.husky/`. Paths in that list that do not exist on the base branch are removed, and the PR-authored versions are kept under `.claude-pr/` for reference only.
Everything else in the working tree — including `package.json`, lockfiles, `Makefile`, `node_modules/`, and formatter/linter config files — stays at the PR head. If a hook, `apiKeyHelper`, or `statusLine` command in your base-branch `.claude/settings.json` runs a package-manager script (`bun run …`, `npm run …`, `yarn …`, `pnpm run …`), a `make` target, a repo-relative script, or a tool that loads executable project config, that command resolves through files the pull request supplies. Keep such commands self-contained: invoke the tool directly with a pinned version and pass its configuration on the command line (for example `bunx prettier@3.5.3 --no-config --write .` rather than `bun run format`).
Note that the runtime executing the tool also reads project config. `bunx <tool>` runs the tool's script under `node` when `node` is on `PATH` (as it is on GitHub-hosted runners); when only Bun is available, Bun executes the script itself and reads `bunfig.toml` from the checkout — including `preload` entries — which comes from the PR head. On such runners, make sure `node` is on `PATH` for the hook, and treat `bunfig.toml` and `.npmrc` in the checkout as PR-controlled runtime config.
### `claude-code-action` vs `claude-code-base-action`
`claude-code-base-action` is a lower-level building block that installs and runs Claude Code with the inputs you provide. It does not perform actor permission checks or restore project configuration from the base ref. If you need those behaviors, use this action (`claude-code-action`). See the [base-action README](../base-action/README.md#trust-model) for details.

View File

@ -86,6 +86,19 @@ function ensureClaudePrExcludedFromGit(): void {
* commits with `git add -A`, the revert will be included in that commit. This
* is a narrow UX tradeoff for closing the RCE surface.
*
* Only the paths listed in SENSITIVE_PATHS come from the base branch; the rest
* of the working tree stays at the PR head. A base-branch hook or setting that
* calls out through files a PR can change package-manager scripts
* (`bun run`, `npm run`, `yarn`, `pnpm run`), Makefile or task-runner targets,
* repo-relative script paths, or tools that load executable project config
* therefore runs whatever the PR head provides. Keep restored hooks
* self-contained: invoke the tool binary directly, pin its version, and pass
* config on the command line rather than reading it from the checkout. This
* extends to the runtime itself: `bunx <tool>` runs the tool under `node` when
* `node` is on PATH, but on a Bun-only runner Bun executes the script and reads
* `bunfig.toml` (e.g. `preload`) from the checkout, so `bunfig.toml` and
* `.npmrc` there are PR-controlled runtime config too.
*
* @param baseBranch - PR base branch name. Must be pre-validated (branch.ts
* calls validateBranchName on it before returning).
*/