Skip to content
Closed
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
89 changes: 89 additions & 0 deletions .github/workflows/auto-approve-risto.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
name: Auto-approve Risto's reviews

# Fires when Risto requests Carmen's review on a PR he authored.
# Generates a one-sentence approval in Carmen's voice via Anthropic API and
# posts it as Carmen's review (via CARMEN_REVIEW_PAT) so SOC 2 / ISO 27001
# audit trails see Carmen as the approver, not github-actions[bot].
# Does NOT merge, does NOT delete the branch.
#
# Also supports workflow_dispatch for manual validation: pass a PR number,
# the workflow runs the diff → AI → comment pipeline end-to-end but skips
# the actual approval post (dry run). Use to validate against any PR
# without leaving stray approval artifacts.

on:
pull_request:
types: [review_requested]
workflow_dispatch:
inputs:
pr_number:
description: "PR number to dry-run against (no approval is posted)"
required: true
type: string

permissions:
contents: read
pull-requests: read

jobs:
approve:
if: >
github.event_name == 'workflow_dispatch' ||
(github.event.requested_reviewer.login == 'ckivisild-elnora-ai' &&
github.event.pull_request.user.login == 'rjamul-elnora-ai')
runs-on: ubuntu-latest
env:
PR_NUMBER: ${{ github.event.pull_request.number || inputs.pr_number }}
REPO: ${{ github.repository }}
steps:
- name: Fetch PR title and diff
id: pr
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
TITLE=$(gh pr view "$PR_NUMBER" --repo "$REPO" --json title -q .title)
echo "title=$TITLE" >> "$GITHUB_OUTPUT"
gh pr diff "$PR_NUMBER" --repo "$REPO" > /tmp/diff.patch || echo "(diff unavailable)" > /tmp/diff.patch
# Truncate at 50KB to stay within token budget for the generation step
head -c 50000 /tmp/diff.patch > /tmp/diff.trunc
mv /tmp/diff.trunc /tmp/diff.patch
echo "Diff size: $(wc -c < /tmp/diff.patch) bytes"

- name: Generate Carmen-voice approval comment
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
PR_TITLE: ${{ steps.pr.outputs.title }}
run: |
DIFF_CONTENT=$(cat /tmp/diff.patch)
jq -n \
--arg diff "$DIFF_CONTENT" \
--arg title "$PR_TITLE" \
'{
model: "claude-haiku-4-5-20251001",
max_tokens: 80,
system: "You are Carmen Kivisild approving Risto'\''s PR. Write ONE short sentence in her voice: direct, plain prose, no em-dashes, no emojis, no filler, no rhetorical questions. Examples of the register: \"reviewed and approved, looks good\" / \"reviewed and approved, the loop fix was clever\" / \"reviewed and approved, clean refactor\". If something specific in the diff is genuinely clever or notable, mention it briefly. Otherwise default to a generic looks-good sentence. Output ONLY the sentence, no preamble.",
messages: [{
role: "user",
content: ("PR title: " + $title + "\n\nDiff:\n" + $diff)
}]
}' > /tmp/request.json
curl -sS https://api.anthropic.com/v1/messages \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
--data-binary @/tmp/request.json > /tmp/response.json
jq -r '.content[0].text // "reviewed and approved, looks good"' /tmp/response.json > /tmp/comment.txt
echo "--- generated comment ---"
cat /tmp/comment.txt
echo ""

- name: Post approval as Carmen
# Skipped on workflow_dispatch — that path is dry-run-only
if: github.event_name == 'pull_request'
env:
GH_TOKEN: ${{ secrets.CARMEN_REVIEW_PAT }}
run: gh pr review "$PR_NUMBER" --repo "$REPO" --approve --body-file /tmp/comment.txt

- name: Dry-run notice (workflow_dispatch only)
if: github.event_name == 'workflow_dispatch'
run: echo "::notice::Dry run — comment generated above but NOT posted as approval. Real review_requested events post for real."