|
76 | 76 | # Write-access gating happens twice: the first step fails fast for |
77 | 77 | # non-write actors, and claude-code-action enforces it again internally — |
78 | 78 | # this `if` just avoids spinning a runner on unrelated comments. |
79 | | - if: contains(github.event.comment.body, '@bullock') |
| 79 | + # The Bot filter matters because GITHUB_TOKEN comments never retrigger |
| 80 | + # workflows (GitHub anti-recursion) but GitHub-App comments DO: a claude.yml |
| 81 | + # review quoting "@bullock" from the thread would otherwise spin a runner |
| 82 | + # and die red at the access gate — noise on the PR, wasted runner. |
| 83 | + if: contains(github.event.comment.body, '@bullock') && github.event.comment.user.type != 'Bot' |
80 | 84 | runs-on: ubuntu-24.04 |
81 | 85 | # analyze_and_test's checks job needs ~30min for setup + `make checks` alone; |
82 | 86 | # Bullock adds Claude's implement/verify loop on top of the same prefix. |
@@ -213,6 +217,13 @@ jobs: |
213 | 217 | # format, and Write the verdict sentinel. |
214 | 218 | - name: Bullock (Claude Code) |
215 | 219 | if: steps.src.outputs.cross != 'true' |
| 220 | + # Step-level timeout on purpose: the job-level 60min timeout CANCELS the |
| 221 | + # job, and "Act on Bullock's verdict" is guarded by !cancelled() — so a |
| 222 | + # job timeout would be a silent red run with no comment. A step timeout |
| 223 | + # merely FAILS this step, which degrades to the no-valid-verdict comment. |
| 224 | + # Budget: ~6min gate+setup before this step + 45 here + ~2 of git/PR |
| 225 | + # plumbing after stays under the job's 60. |
| 226 | + timeout-minutes: 45 |
216 | 227 | uses: anthropics/claude-code-action@v1 |
217 | 228 | with: |
218 | 229 | anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} |
@@ -272,6 +283,7 @@ jobs: |
272 | 283 |
|
273 | 284 | ## Step 4 — Implement (ONLY if sufficient) |
274 | 285 | - Change ONLY what was requested. No opportunistic refactors, no unrelated cleanup. |
| 286 | + - NEVER modify anything under `.github/` (workflows, actions, CI config) — the workflow refuses to commit such changes. If the request requires a CI change, treat it as insufficient and say so in "question". |
275 | 287 | - Follow AGENTS.md strictly: use `fvm`; respect the layer/facade/failure/naming rules; NEVER log or expose secrets (mnemonic/seed/xpriv/PIN); no hardcoded user-facing strings (use `context.loc.*`); no raw colors. |
276 | 288 | - After editing, format your new/changed Dart files so the CI format gate can't fail on untracked files: |
277 | 289 | run `fvm dart format` on the files you touched, then `git add -A` for the changed source (do NOT add `.bullock/`). |
@@ -332,22 +344,27 @@ jobs: |
332 | 344 | git config user.name "bullock[bot]" |
333 | 345 | git config user.email "bullock@users.noreply.github.com" |
334 | 346 |
|
335 | | - # GITHUB_TOKEN cannot push changes under .github/workflows/ — the push |
336 | | - # (below) would be rejected AFTER commit, going red with no feedback. |
337 | | - # Bail early with an explanation. This is also a deliberate backstop |
338 | | - # against Bullock modifying its own workflow. `git status --porcelain` |
339 | | - # reports both tracked edits and new untracked files, and is checked |
340 | | - # before staging so a workflow-file change never enters the commit. |
341 | | - if [ -n "$(git status --porcelain -- .github/workflows)" ]; then |
342 | | - comment "🐂 Bullock's changes touch \`.github/workflows/\`, which a bot token isn't allowed to push. Please make workflow changes manually." |
343 | | - echo "Workflow files touched — declined (GITHUB_TOKEN cannot push workflows)." |
| 347 | + # ALL of .github/ is off-limits to Bullock, for two distinct reasons: |
| 348 | + # - .github/workflows/: GITHUB_TOKEN cannot push these — the push |
| 349 | + # (below) would be rejected AFTER commit, going red with no feedback. |
| 350 | + # - the rest (.github/actions/ composite, CI config): the token CAN |
| 351 | + # push them, but they execute in future CI runs with secrets — a |
| 352 | + # prompt-injected change here must be blocked mechanically, not just |
| 353 | + # by the prompt's SECURITY section. Bullock has no legitimate reason |
| 354 | + # to touch CI; a maintainer changes it manually. |
| 355 | + # `git status --porcelain` reports both tracked edits and new |
| 356 | + # untracked files, and is checked before staging so a CI-file change |
| 357 | + # never enters the commit. |
| 358 | + if [ -n "$(git status --porcelain -- .github)" ]; then |
| 359 | + comment "🐂 Bullock's changes touch \`.github/\` (workflows or CI config), which Bullock isn't allowed to modify. Please make CI changes manually." |
| 360 | + echo "CI files touched — declined (.github/ is off-limits to Bullock)." |
344 | 361 | exit 0 |
345 | 362 | fi |
346 | 363 |
|
347 | 364 | # Stage only source changes; never sweep the whole tree (build_runner |
348 | 365 | # drift, make side effects, stray artifacts) into the stacked PR, and |
349 | | - # never stage workflow files (guarded above). |
350 | | - git add -A -- ':(exclude).github/workflows' |
| 366 | + # never stage CI files (guarded above). |
| 367 | + git add -A -- ':(exclude).github' |
351 | 368 |
|
352 | 369 | if git diff --cached --quiet; then |
353 | 370 | comment "🐂 Bullock judged the request actionable but produced no changes. Please re-summon with a more specific instruction." |
|
0 commit comments