Skip to content

Commit 3b37699

Browse files
authored
Allow npm build/lint/format in Claude workflows (#793)
Add npm run build, prettier, and eslint (including :fix variants) to the --allowed-tools allowlist in both the upstream-release-docs and @claude mention workflows, so agents can validate their own changes without hitting sandbox denials. The mention workflow also gains Node + deps via the shared ./.github/actions/setup composite, since it previously had no npm tooling at all. Clarify CLAUDE.md/AGENTS.md: the pre-commit hook silently no-ops in CI, unattended agents, and local environments without npm install, so agents should run prettier:fix and eslint:fix explicitly after editing content. Co-authored-by: Dan Barr <6922515+danbarr@users.noreply.github.com>
1 parent a8b756d commit 3b37699

3 files changed

Lines changed: 32 additions & 8 deletions

File tree

.github/workflows/claude.yml

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,23 @@ on:
1212

1313
jobs:
1414
claude:
15+
# Only run for trusted actors. Fork PRs can modify package.json
16+
# scripts; without this gate, an @claude mention on such a PR
17+
# would execute attacker-controlled code under our secrets and
18+
# write permissions.
1519
if: |
16-
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
17-
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
18-
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
19-
(github.event_name == 'issues' && contains(github.event.issue.body, '@claude'))
20+
(github.event_name == 'issue_comment' &&
21+
contains(github.event.comment.body, '@claude') &&
22+
contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association)) ||
23+
(github.event_name == 'pull_request_review_comment' &&
24+
contains(github.event.comment.body, '@claude') &&
25+
contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association)) ||
26+
(github.event_name == 'pull_request_review' &&
27+
contains(github.event.review.body, '@claude') &&
28+
contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.review.author_association)) ||
29+
(github.event_name == 'issues' &&
30+
contains(github.event.issue.body, '@claude') &&
31+
contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.issue.author_association))
2032
runs-on: ubuntu-latest
2133
timeout-minutes: 20
2234
permissions:
@@ -26,10 +38,20 @@ jobs:
2638
id-token: write
2739
actions: read # Required for Claude to read CI results on PRs
2840
steps:
41+
# Initial checkout so GitHub Actions can resolve the local
42+
# composite action below. The composite re-checks out the
43+
# repo itself; this first checkout only needs the .github
44+
# directory.
2945
- name: Checkout repository
3046
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
3147
with:
3248
fetch-depth: 1
49+
sparse-checkout: .github
50+
51+
# Checkout + Node + deps so Claude can run build/lint/format
52+
# scripts when asked.
53+
- name: Set up repo and dependencies
54+
uses: ./.github/actions/setup
3355

3456
- name: Run Claude Code
3557
id: claude
@@ -38,3 +60,5 @@ jobs:
3860
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
3961
additional_permissions: |
4062
actions: read
63+
claude_args: |
64+
--allowed-tools "Bash(npm run build:*) Bash(npm run prettier:*) Bash(npm run eslint:*)"

.github/workflows/upstream-release-docs.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -558,7 +558,7 @@ jobs:
558558
claude_args: |
559559
--model claude-opus-4-7
560560
--max-turns 1000
561-
--allowed-tools "Bash(gh:*)"
561+
--allowed-tools "Bash(gh:*) Bash(npm run build:*) Bash(npm run prettier:*) Bash(npm run eslint:*)"
562562
prompt: |
563563
You are running in GitHub Actions with no interactive user. Follow
564564
these steps exactly and do NOT ask clarifying questions -- proceed
@@ -752,7 +752,7 @@ jobs:
752752
claude_args: |
753753
--model claude-opus-4-7
754754
--max-turns 200
755-
--allowed-tools "Bash(gh:*)"
755+
--allowed-tools "Bash(gh:*) Bash(npm run build:*) Bash(npm run prettier:*) Bash(npm run eslint:*)"
756756
prompt: |
757757
You are running in GitHub Actions with no interactive user. Follow
758758
these steps exactly and do NOT ask clarifying questions -- proceed

AGENTS.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,9 @@ The project uses automated tooling to enforce code quality and formatting standa
5555

5656
- **Pre-commit hooks**: lint-staged runs automatically on `git commit`, applying Prettier and appropriate linters to staged files.
5757
- **GitHub Actions**: All PRs trigger automated checks (ESLint, Prettier).
58-
- **No manual formatting needed**: The pre-commit hook handles formatting automatically - you do not need to run formatters manually.
58+
- **Don't rely on the pre-commit hook**: lint-staged only fires on `git commit` when Node, dependencies, and husky are all set up. It silently no-ops in CI and unattended contexts (GitHub Actions, scheduled agents) and in local environments where `npm install` hasn't been run. If you edited content, run `npm run prettier:fix` and `npm run eslint:fix` yourself to avoid lint failures on PR CI.
5959

60-
File type to linter mapping (handled automatically by pre-commit hooks):
60+
File type to linter mapping (run manually if the pre-commit hook doesn't fire):
6161

6262
- `.md` files: Prettier only
6363
- `.mdx` files: Prettier + ESLint

0 commit comments

Comments
 (0)