Skip to content

fix(daemon): mask the API token in the startup config log #277

fix(daemon): mask the API token in the startup config log

fix(daemon): mask the API token in the startup config log #277

name: Claude Code Review
on:
pull_request:
types: [opened, synchronize, ready_for_review, reopened]
# Optional: Only run on specific file changes
# paths:
# - "src/**/*.ts"
# - "src/**/*.tsx"
# - "src/**/*.js"
# - "src/**/*.jsx"
# A push while a review is still running replaces it, rather than stacking a
# second review of a diff that is already stale.
concurrency:
group: claude-review-${{ github.event.pull_request.number }}
cancel-in-progress: true
jobs:
claude-review:
# Drafts are reviewed once they are marked ready. Bot PRs (release-please)
# need no review and only queue up as action_required.
if: github.event.pull_request.draft == false && github.event.pull_request.user.type != 'Bot'
runs-on: blacksmith-2vcpu-ubuntu-2404
permissions:
contents: read
pull-requests: write
issues: write
id-token: write
checks: read
statuses: read
actions: read # Required for Claude to read CI results on PRs
steps:
- name: Checkout repository
uses: actions/checkout@v7
with:
# Full history, so the review can diff, log and blame against the base
# branch instead of piecing the PR together from `gh pr diff`.
fetch-depth: 0
# - name: Trust workspace directory
# run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
- name: Run Claude Code Review
id: claude-review
uses: anthropics/claude-code-action@v1
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
# Print Claude's messages to the job log. Without it a run that stops
# early or skims gives no reason. This repository's Actions logs are public.
show_full_output: true
# anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
# The built-in /code-review, not the code-review@claude-code-plugins
# command. The plugin's procedure (eligibility check, four parallel
# reviewers, validators) was routinely skipped by its Sonnet main loop:
# on #654 it said "I didn't launch the subagents the review steps
# describe", read a few line ranges of a diff too big for one tool
# result, and posted "No issues found" after 16s. Since Claude Code
# 2.1.x the built-in takes a PR number, an effort level and --comment,
# and verifies its findings before posting them.
prompt: '/code-review high ${{ github.event.pull_request.number }} --comment'
# See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
# or https://code.claude.com/docs/en/cli-reference for available options
additional_permissions: |
actions: read
claude_args: |
--allowedTools "Bash(gh:*),Bash(git:*),mcp__github_inline_comment__create_inline_comment"
# The action reports success whenever the SDK returns is_error: false, even
# if Claude never did anything (unresolved slash command, missing plugin,
# empty prompt). That failure mode hid behind months of green runs, so
# assert that work actually happened.
#
# Check cost as well as turns: a real review delegates to subagents and can
# legitimately report num_turns 0 while spending several dollars. Only a run
# that is zero on BOTH counts truly did nothing.
#
# A run that did work but never delegated is the quieter failure: one
# agent skimming the diff and calling it clean. That only warns, because a
# tiny diff may not need subagents.
- name: Assert the review actually ran
if: always() && steps.claude-review.conclusion == 'success'
run: |
file="${{ steps.claude-review.outputs.execution_file }}"
if [ -z "$file" ] || [ ! -f "$file" ]; then
echo "::warning::No execution file — the action exited before starting Claude. Expected on PRs that modify this workflow (the action requires it to match the default branch); investigate otherwise."
exit 0
fi
result=$(jq -r '[.. | objects | select(.type == "result")] | last' "$file")
turns=$(jq -r '.num_turns // 0' <<<"$result")
cost=$(jq -r '.total_cost_usd // 0' <<<"$result")
delegations=$(jq -r '[.. | objects | select(.type == "tool_use" and (.name == "Agent" or .name == "Task" or .name == "Workflow"))] | length' "$file")
echo "Claude turns: $turns, cost: \$$cost, subagent launches: $delegations"
if [ "$turns" -eq 0 ] && [ "$(jq -rn --argjson c "$cost" '$c > 0')" = "false" ]; then
echo "::error::Claude did no work — 0 turns and \$0 spent. The review was a no-op (bad prompt or unresolved slash command)."
exit 1
fi
if [ "$delegations" -eq 0 ]; then
echo "::warning::The review launched no subagents. On anything but a tiny diff that means one agent skimmed it, so treat a clean result with suspicion."
fi