Auto-Cleanup Fixup #151
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
| # Reacts to CI failures on the auto-cleanup PR and attempts a minimal fix. | |
| # Companion to auto-cleanup.yml, so it uses the same dedicated Anthropic key to | |
| # keep auto-cleanup spend isolated from terminal-bench. | |
| # Prompt lives in: .github/prompts/auto-cleanup-fixup.md | |
| name: Auto-Cleanup Fixup | |
| on: | |
| workflow_run: | |
| workflows: ["PR"] | |
| types: [completed] | |
| branches: [auto-cleanup] | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| actions: read | |
| jobs: | |
| fixup: | |
| # Only run for failed PR workflow runs from this repository's own | |
| # auto-cleanup branch. This blocks untrusted fork-origin runs from | |
| # reaching token creation and mux execution. | |
| if: ${{ github.event.workflow_run.conclusion == 'failure' && github.event.workflow_run.head_repository.full_name == github.repository && github.event.workflow_run.head_branch == 'auto-cleanup' }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Check required secrets | |
| id: precheck | |
| env: | |
| # Keep the runtime env name stable while routing spend to a dedicated key. | |
| ANTHROPIC_API_KEY: ${{ secrets.AUTO_CLEANUP_ANTHROPIC_API_KEY }} | |
| MUX_APP_ID: ${{ secrets.MUX_APP_ID }} | |
| MUX_APP_PRIVATE_KEY: ${{ secrets.MUX_APP_PRIVATE_KEY }} | |
| run: | | |
| missing=0 | |
| [ -z "$ANTHROPIC_API_KEY" ] && echo "Skipping (missing AUTO_CLEANUP_ANTHROPIC_API_KEY)." && missing=1 | |
| [ -z "$MUX_APP_ID" ] && echo "Skipping (missing MUX_APP_ID)." && missing=1 | |
| [ -z "$MUX_APP_PRIVATE_KEY" ] && echo "Skipping (missing MUX_APP_PRIVATE_KEY)." && missing=1 | |
| if [ "$missing" -eq 1 ]; then | |
| echo "enabled=false" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "enabled=true" >> "$GITHUB_OUTPUT" | |
| fi | |
| - uses: actions/create-github-app-token@d72941d797fd3113feb6b93fd0dec494b13a2547 # v1.12.0 | |
| id: app-token | |
| if: ${{ steps.precheck.outputs.enabled == 'true' }} | |
| with: | |
| app-id: ${{ secrets.MUX_APP_ID }} | |
| private-key: ${{ secrets.MUX_APP_PRIVATE_KEY }} | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 | |
| if: ${{ steps.precheck.outputs.enabled == 'true' }} | |
| with: | |
| # Diagnose/fix the exact failed run revision, not a moving branch tip. | |
| ref: ${{ github.event.workflow_run.head_sha }} | |
| fetch-depth: 0 | |
| token: ${{ steps.app-token.outputs.token }} | |
| - name: Attach auto-cleanup branch to failed revision | |
| if: ${{ steps.precheck.outputs.enabled == 'true' }} | |
| env: | |
| FAILED_HEAD_SHA: ${{ github.event.workflow_run.head_sha }} | |
| run: | | |
| git checkout -B auto-cleanup "$FAILED_HEAD_SHA" | |
| actual_sha=$(git rev-parse HEAD) | |
| if [ "$actual_sha" != "$FAILED_HEAD_SHA" ]; then | |
| echo "❌ Expected HEAD to match failed run SHA" | |
| echo "expected=$FAILED_HEAD_SHA actual=$actual_sha" | |
| exit 1 | |
| fi | |
| - uses: oven-sh/setup-bun@b7a1c7ccf290d58743029c4f6903da283811b979 # v2.1.0 | |
| if: ${{ steps.precheck.outputs.enabled == 'true' }} | |
| with: | |
| bun-version: 1.3.5 | |
| # Pin the git identity so the AI agent doesn't invent its own. | |
| - name: Configure git identity | |
| if: ${{ steps.precheck.outputs.enabled == 'true' }} | |
| run: | | |
| git config user.name "mux-bot[bot]" | |
| git config user.email "264182336+mux-bot[bot]@users.noreply.github.com" | |
| # Circuit breaker: if the last commit is already a fixup, we already | |
| # retried once and should stop to prevent an infinite failure loop. | |
| - name: Circuit breaker - skip if already retried | |
| id: circuit | |
| if: ${{ steps.precheck.outputs.enabled == 'true' }} | |
| run: | | |
| last_msg=$(git log -1 --format='%s') | |
| if [[ "$last_msg" == fix:* ]] || [[ "$last_msg" == "fix(ci):"* ]]; then | |
| echo "⚠️ Last commit is already a fixup ('$last_msg'). Skipping to prevent loop." | |
| echo "should_run=false" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "should_run=true" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Comment on PR when circuit breaker triggers | |
| if: ${{ steps.precheck.outputs.enabled == 'true' && steps.circuit.outputs.should_run == 'false' }} | |
| env: | |
| GH_TOKEN: ${{ steps.app-token.outputs.token }} | |
| run: | | |
| pr_number=$(gh pr list --state open --head auto-cleanup --json number -q '.[0].number') | |
| if [ -n "$pr_number" ] && [ "$pr_number" != "null" ]; then | |
| gh pr comment "$pr_number" --body \ | |
| "⚠️ Auto-fixup circuit breaker triggered: the previous fixup commit also failed CI. Manual intervention needed." | |
| else | |
| echo "No open auto-cleanup PR found; skipping circuit-breaker comment." | |
| fi | |
| - name: Fix CI failure with mux | |
| if: ${{ steps.precheck.outputs.enabled == 'true' && steps.circuit.outputs.should_run == 'true' }} | |
| env: | |
| ANTHROPIC_API_KEY: ${{ secrets.AUTO_CLEANUP_ANTHROPIC_API_KEY }} | |
| GH_TOKEN: ${{ steps.app-token.outputs.token }} | |
| FAILED_RUN_ID: ${{ github.event.workflow_run.id }} | |
| run: | | |
| bunx mux@next run \ | |
| --model anthropic:claude-opus-4-7 \ | |
| --thinking xhigh \ | |
| < .github/prompts/auto-cleanup-fixup.md |