Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions .github/workflows/auto-approve-claude-lgtm.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Auto-approves a PR when a trusted review bot posts an LGTM verdict.
#
# Two review bots are trusted, and neither can submit an APPROVE review
# itself (GitHub rejects self/app approvals for those integrations), so each
# posts a COMMENT-state review whose body starts with an "LGTM" verdict.
# This workflow turns that signal into a real approval from
# github-actions[bot].
#
# * claude[bot] — Claude Code's review sessions (verdict
# contract in REVIEW.md)
# * coreplane-switchboard[bot] — Switchboard's `review` agent
# (github.com/coreplanelabs/switchboard).
# Its "LGTM" line is written by the bot
# process from a structured verdict, never by
# the model's prose (fail-closed: no verdict
# → not approving).
#
# Inert until a repo admin enables "Allow GitHub Actions to create and
# approve pull requests" under Settings -> Actions -> General; without
# that setting the approval POST fails with 422.
#
# Guards:
# * Only fires for reviews authored by one of the two bots, matched by
# both login and immutable numeric user id, in state "commented", whose
# body starts with "LGTM" (a mention elsewhere in the body never
# fires).
# * Skips if the review is pinned to a commit that is no longer the
# PR head (a push landed after the bot reviewed).
# * The approval itself is pinned to the reviewed commit via
# commit_id, so it cannot silently attach to a newer head.
#
# Known residual risk: pull_request_review runs this workflow from the
# PR's merge ref, so a PR that edits this file runs its edited copy.
# Branch protection ("Dismiss stale approvals" + required human review)
# is the real backstop.
name: Auto-approve review-bot LGTM

on:
pull_request_review:
types: [submitted]

permissions: {}

jobs:
approve:
runs-on: ubuntu-latest
if: >-
(
(github.event.review.user.login == 'claude[bot]' && github.event.review.user.id == 209825114) ||
(github.event.review.user.login == 'coreplane-switchboard[bot]' && github.event.review.user.id == 318072483)
) &&
github.event.review.state == 'commented' &&
startsWith(github.event.review.body, 'LGTM')
permissions:
pull-requests: write
steps:
- name: Approve PR
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
PR: ${{ github.event.pull_request.number }}
REVIEWER: ${{ github.event.review.user.login }}
REVIEW_COMMIT: ${{ github.event.review.commit_id }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
set -euo pipefail
if [ "$REVIEW_COMMIT" != "$HEAD_SHA" ]; then
echo "Review is pinned to $REVIEW_COMMIT but PR head is $HEAD_SHA; stale review, skipping."
exit 0
fi
body="Auto-approved: $REVIEWER reviewed this PR and posted an LGTM verdict (see its review). A repo admin enabled this via the auto-approve workflow."
gh api "repos/$GH_REPO/pulls/$PR/reviews" \
-f event=APPROVE \
-f commit_id="$REVIEW_COMMIT" \
-f body="$body"
Loading