feat(signing): key_origins check + brand.json chain error codes (#350 stage 4) #22
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: AI PR Review (Argus) | |
| # Argus is an LLM PR reviewer that posts an `--approve`, `--comment`, or | |
| # `--request-changes` review on every non-dependabot PR. It reads the diff, | |
| # delegates to subagents when relevant (ad-tech-protocol-expert, | |
| # security-reviewer, code-reviewer, python-expert, etc.), and writes the | |
| # review in bokelley's voice. | |
| # | |
| # Reviews are posted as the AAO release/triage GitHub App, so they count | |
| # toward the "1 review required" branch-protection check the same way a | |
| # human approval does. | |
| # | |
| # Required secrets: | |
| # IPR_APP_ID — GitHub App ID (shared with ipr-agreement.yml) | |
| # IPR_APP_PRIVATE_KEY — GitHub App private key PEM (shared with ipr-agreement.yml) | |
| # ANTHROPIC_API_KEY — Anthropic API key for claude-code-action | |
| # | |
| # Ported from adcontextprotocol/adcp's Argus workflow. | |
| on: | |
| pull_request: | |
| types: | |
| - opened | |
| - labeled | |
| - ready_for_review | |
| - synchronize | |
| paths-ignore: | |
| - '.github/workflows/ai-review.yml' | |
| - '.github/ai-review/**' | |
| jobs: | |
| code_review: | |
| if: github.actor != 'dependabot[bot]' && github.event.pull_request.draft == false | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| id-token: write | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| # ───────────────────────────────────────────────────────────────────── | |
| # Mint an installation token from the AAO release/triage GitHub App. | |
| # Reviews posted with this token appear as the App's bot user and | |
| # count toward branch-protection's required-approvals check. | |
| # ───────────────────────────────────────────────────────────────────── | |
| - name: Mint App token | |
| id: app-token | |
| uses: actions/create-github-app-token@v1 | |
| with: | |
| app-id: ${{ secrets.IPR_APP_ID }} | |
| private-key: ${{ secrets.IPR_APP_PRIVATE_KEY }} | |
| # ───────────────────────────────────────────────────────────────────── | |
| # Skip re-runs on `synchronize` when the last bot review on this PR | |
| # was APPROVED and the new commits only touch trivial paths (docs, | |
| # tests, generated files). Cuts thrash on rebases and docs/test | |
| # follow-up pushes. Force-pushes fall back to full review because | |
| # the prior SHA may be unreachable. | |
| # ───────────────────────────────────────────────────────────────────── | |
| - name: Check for skippable re-run | |
| id: skip-check | |
| if: github.event.action == 'synchronize' | |
| continue-on-error: true | |
| shell: bash | |
| env: | |
| GH_TOKEN: ${{ steps.app-token.outputs.token }} | |
| PR_NUMBER: ${{ github.event.pull_request.number }} | |
| REPO: ${{ github.repository }} | |
| HEAD_SHA: ${{ github.event.pull_request.head.sha }} | |
| run: | | |
| set -euo pipefail | |
| LATEST_APPROVED="$(gh api "/repos/${REPO}/pulls/${PR_NUMBER}/reviews" \ | |
| --jq '[.[] | select(.user.type == "Bot" and .state == "APPROVED")] | sort_by(.submitted_at) | last // {}')" | |
| PRIOR_SHA="$(echo "$LATEST_APPROVED" | jq -r '.commit_id // ""')" | |
| if [ -z "$PRIOR_SHA" ]; then | |
| echo "skip=false" >> "$GITHUB_OUTPUT" | |
| echo "No prior bot APPROVED review — running full review." | |
| exit 0 | |
| fi | |
| if ! git cat-file -e "$PRIOR_SHA" 2>/dev/null; then | |
| git fetch --quiet origin "$PRIOR_SHA" 2>/dev/null || true | |
| fi | |
| if ! git cat-file -e "$PRIOR_SHA" 2>/dev/null; then | |
| echo "skip=false" >> "$GITHUB_OUTPUT" | |
| echo "Prior review SHA $PRIOR_SHA unreachable (likely force-pushed) — running full review." | |
| exit 0 | |
| fi | |
| CHANGED="$(git diff --name-only "$PRIOR_SHA" "$HEAD_SHA")" | |
| if [ -z "$CHANGED" ]; then | |
| echo "skip=true" >> "$GITHUB_OUTPUT" | |
| echo "No file changes since prior approval at $PRIOR_SHA — skipping." | |
| exit 0 | |
| fi | |
| # Trivial paths in adcp-client-python — re-pushes touching only these | |
| # skip re-review. Source under src/adcp/ (excluding generated_poc) is | |
| # NEVER trivial. | |
| is_trivial() { | |
| case "$1" in | |
| *.md|*.mdx) return 0 ;; | |
| docs/*) return 0 ;; | |
| examples/*) return 0 ;; | |
| src/adcp/types/generated_poc/*) return 0 ;; | |
| src/adcp/types/_generated.py) return 0 ;; | |
| tests/*) return 0 ;; | |
| test_*.py|*_test.py) return 0 ;; | |
| CHANGELOG.md) return 0 ;; | |
| schemas/*) return 0 ;; | |
| llms.txt) return 0 ;; | |
| esac | |
| return 1 | |
| } | |
| NON_TRIVIAL="" | |
| while IFS= read -r f; do | |
| [ -z "$f" ] && continue | |
| if ! is_trivial "$f"; then | |
| NON_TRIVIAL="${NON_TRIVIAL}${f}"$'\n' | |
| fi | |
| done <<< "$CHANGED" | |
| if [ -z "$NON_TRIVIAL" ]; then | |
| echo "skip=true" >> "$GITHUB_OUTPUT" | |
| echo "All changes since $PRIOR_SHA are trivial — skipping re-review. Changed files:" | |
| echo "$CHANGED" | |
| else | |
| echo "skip=false" >> "$GITHUB_OUTPUT" | |
| echo "Non-trivial changes since $PRIOR_SHA — running full review:" | |
| echo "$NON_TRIVIAL" | |
| fi | |
| - name: Build Argus review prompt | |
| if: steps.skip-check.outputs.skip != 'true' | |
| id: build-prompt | |
| shell: bash | |
| env: | |
| PR_NUMBER: ${{ github.event.pull_request.number }} | |
| PR_BASE_REF: ${{ github.event.pull_request.base.ref }} | |
| REPO: ${{ github.repository }} | |
| run: | | |
| set -euo pipefail | |
| PROMPT_BODY="$(cat .github/ai-review/expert-adcp-reviewer.md)" | |
| { | |
| echo 'ARGUS_PROMPT<<ARGUS_EOF' | |
| echo "$PROMPT_BODY" | |
| echo '' | |
| echo '---' | |
| echo '' | |
| echo '## Pre-computed inputs for this PR' | |
| echo '' | |
| echo "- PR_NUMBER: $PR_NUMBER" | |
| echo "- REPO: $REPO" | |
| echo "- PR_BASE_REF: $PR_BASE_REF" | |
| echo 'ARGUS_EOF' | |
| } >> "$GITHUB_OUTPUT" | |
| - name: Run Argus PR Review | |
| id: ai-review | |
| if: steps.skip-check.outputs.skip != 'true' | |
| continue-on-error: true | |
| uses: anthropics/claude-code-action@v1 | |
| with: | |
| prompt: ${{ steps.build-prompt.outputs.ARGUS_PROMPT }} | |
| anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} | |
| github_token: ${{ steps.app-token.outputs.token }} | |
| use_sticky_comment: false | |
| track_progress: false | |
| claude_args: | | |
| --allowedTools "Bash(gh pr view:*),Bash(gh pr diff:*),Bash(gh pr review:*),Bash(gh api:*),Read,Glob,Grep,Task" | |
| --max-turns 60 | |
| --model claude-opus-4-7 | |
| - name: Verify Argus posted a review | |
| id: verify | |
| if: always() && steps.app-token.outcome == 'success' && steps.skip-check.outputs.skip != 'true' | |
| shell: bash | |
| env: | |
| GH_TOKEN: ${{ steps.app-token.outputs.token }} | |
| PR_NUMBER: ${{ github.event.pull_request.number }} | |
| REPO: ${{ github.repository }} | |
| run: | | |
| set -euo pipefail | |
| LATEST="$(gh api "/repos/${REPO}/pulls/${PR_NUMBER}/reviews" \ | |
| --jq '[.[] | select(.user.type == "Bot")] | sort_by(.submitted_at) | last // {}')" | |
| STATE="$(echo "$LATEST" | jq -r '.state // ""')" | |
| AUTHOR="$(echo "$LATEST" | jq -r '.user.login // ""')" | |
| SUBMITTED="$(echo "$LATEST" | jq -r '.submitted_at // ""')" | |
| echo "Latest bot review — author: $AUTHOR, state: $STATE, submitted: $SUBMITTED" | |
| if [ -z "$STATE" ]; then | |
| echo "review_posted=false" >> "$GITHUB_OUTPUT" | |
| echo "::warning::No bot review found on PR #$PR_NUMBER" | |
| exit 0 | |
| fi | |
| SUBMITTED_TS="$(date -u -d "$SUBMITTED" +%s 2>/dev/null || date -u -j -f '%Y-%m-%dT%H:%M:%SZ' "$SUBMITTED" +%s)" | |
| NOW_TS="$(date -u +%s)" | |
| if [ $((NOW_TS - SUBMITTED_TS)) -gt 600 ]; then | |
| echo "review_posted=false" >> "$GITHUB_OUTPUT" | |
| echo "::warning::Latest bot review is older than 10 minutes — Argus didn't post in this run" | |
| exit 0 | |
| fi | |
| echo "review_posted=true" >> "$GITHUB_OUTPUT" | |
| echo "review_state=$STATE" >> "$GITHUB_OUTPUT" | |
| - name: Comment on PR if Argus review failed | |
| if: steps.skip-check.outputs.skip != 'true' && (steps.ai-review.outcome == 'failure' || steps.verify.outputs.review_posted != 'true') | |
| uses: actions/github-script@v7 | |
| env: | |
| RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} | |
| with: | |
| github-token: ${{ steps.app-token.outputs.token }} | |
| script: | | |
| const runUrl = process.env.RUN_URL; | |
| github.rest.issues.createComment({ | |
| issue_number: context.issue.number, | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| body: `⚠️ **Argus review could not complete**\n\nThe automated review encountered an issue (possibly reached max turns, timed out, or failed to post the final \`gh pr review\`). A human reviewer should take this PR.\n\n[View workflow run](${runUrl})\n\n<sub>This is an automated message from the Argus AI review workflow.</sub>` | |
| }) |