feat(automerge): add Claude-author auto-merge reusable workflow#20
Conversation
Auto-enables 'gh pr merge --auto --squash' on PRs detected as
Claude-authored (branch claude/*, Co-Authored-By: Claude trailer, or
'auto-merge' label) unless the diff touches risk-tier paths from the
global CLAUDE.md policy:
- auth / login / session / oauth / sso
- secrets / .env / keychain / credentials
- migrations / *.sql
- billing / payment / pricing / invoice
- production infra (Dockerfile, .github/workflows, infra/, terraform/,
pulumi/, deploy scripts)
Risk matches post a sticky comment and skip auto-merge — manual
click-merge still works. Branch protection (required Claude Review
check) still applies; this only flips the auto-merge toggle.
Pairs with new install-automerge-policy.sh in dotclaude.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
| fi | ||
|
|
||
| - name: Enable auto-merge | ||
| if: steps.detect.outputs.claude_authored == '1' && steps.risk.outputs.risky != '1' |
There was a problem hiding this comment.
Bug: risk-step failure silently enables auto-merge
When if: is specified with a custom expression, GitHub Actions drops the implicit success() guard. If the risk step fails for any reason (network error, API rate limit, gh auth failure), steps.risk.outputs.risky is never written. '' != '1' evaluates to true, so this step fires — enabling auto-merge on a PR whose risk tier was never validated.
| if: steps.detect.outputs.claude_authored == '1' && steps.risk.outputs.risky != '1' | |
| if: success() && steps.detect.outputs.claude_authored == '1' && steps.risk.outputs.risky != '1' |
Same fix needed on line 156 for the "Comment + skip" step's condition.
| existing=$(gh api "/repos/${{ github.repository }}/issues/$PR/comments" \ | ||
| --jq ".[] | select(.body | contains(\"$marker\")) | .id" | head -1) |
There was a problem hiding this comment.
Race condition: TOCTOU between read and write
If this workflow fires twice concurrently (e.g., opened + labeled events in quick succession), both runs fetch the comment list, both find no existing marker comment, and both POST a new one — producing two identical sticky comments. This is minor (cosmetic noise, not a security issue), but worth noting if the calling workflow triggers on multiple event types.
|
Flagged 2 issues inline — see comments. One real security bug (risk-step failure silently enables auto-merge due to missing |
Summary
Adds
.github/workflows/claude-author-automerge.ymlreusable workflow that auto-enablesgh pr merge --auto --squashon PRs detected as Claude-authored — unless the diff touches risk-tier paths.Detection signals (any of)
claude/*Co-Authored-By: Claudetrailerauto-mergelabelRisk-tier path filter (encodes global CLAUDE.md policy)
Auto-merge is skipped when changed files match any of:
auth/login/session/oauth/ssosecrets/.env*/keychain*/credentials*migrations//*.sqlbilling/payment*/pricing*/invoice*Dockerfile,.github/workflows/**,infra/,terraform/,pulumi/,deploy*.{sh,yml,yaml}On match: posts a sticky comment + skips. Manual click-merge still works.
Branch protection still applies
This only flips the auto-merge toggle. Required checks (Claude Review) must still pass before GitHub merges. The risk-tier filter is an extra circuit breaker on top.
Companion
Pairs with new
install-automerge-policy.shintopcoder1/dotclaudefor fleet rollout.Auto-merge rationale: workflow file in this repo (
.github/workflows/**) — installer modifies CI config, deserves manual review; not auto-merging.Codex pre-review: skipped (workflow-only change, ~190 lines, no business logic — Claude Review covers this category sufficiently).
Test plan
install-automerge-policy.sh topcoder1/attaxion_dev(the install PR itself touches.github/workflows/**so it WILL be in the risk-tier list — expected behavior; manual-merge that one)claude/*branch with no risk paths — verify auto-merge firesinfra/— verify the workflow posts the sticky comment and does NOT enable auto-merge🤖 Generated with Claude Code
Co-Authored-By: Claude Opus 4.7 (1M context) [email protected]