build(deps): bump dtolnay/rust-toolchain from 1.93.0 to 1.100.0 #3764
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: Claude Assistant | |
| on: | |
| pull_request: | |
| types: [opened, synchronize] | |
| issue_comment: | |
| types: [created] | |
| pull_request_review_comment: | |
| types: [created] | |
| workflow_run: | |
| workflows: ["CI"] | |
| types: [completed] | |
| # Filter to find non-member, non-bot comments (for prompt injection prevention) | |
| env: | |
| NONMEMBER_FILTER: '[.[] | select(.user.type != "Bot" and .author_association != "OWNER" and .author_association != "MEMBER" and .author_association != "COLLABORATOR")] | length' | |
| # Note: We use a GitHub App token instead of GITHUB_TOKEN so that: | |
| # 1. All actions appear as "Claude" bot | |
| # 2. PRs created by Claude can trigger CI workflows | |
| # Required: CLAUDE_APP_ID (variable), CLAUDE_APP_PRIVATE_KEY (secret) | |
| jobs: | |
| # Gatekeeper: Check for non-member commits, comments, and author association | |
| safety-check: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| safe: ${{ steps.check.outputs.safe }} | |
| pr_number: ${{ steps.get-pr.outputs.number }} | |
| author_ok: ${{ steps.author.outputs.ok }} | |
| commits_ok: ${{ steps.commits.outputs.ok }} | |
| steps: | |
| - name: Generate token | |
| id: token | |
| uses: actions/create-github-app-token@v2 | |
| with: | |
| app-id: ${{ vars.CLAUDE_APP_ID }} | |
| private-key: ${{ secrets.CLAUDE_APP_PRIVATE_KEY }} | |
| - name: Get PR number | |
| id: get-pr | |
| env: | |
| GH_TOKEN: ${{ steps.token.outputs.token }} | |
| run: | | |
| if [ "${{ github.event_name }}" = "pull_request" ]; then | |
| echo "number=${{ github.event.pull_request.number }}" >> $GITHUB_OUTPUT | |
| elif [ "${{ github.event_name }}" = "issue_comment" ]; then | |
| echo "number=${{ github.event.issue.number }}" >> $GITHUB_OUTPUT | |
| elif [ "${{ github.event_name }}" = "pull_request_review_comment" ]; then | |
| echo "number=${{ github.event.pull_request.number }}" >> $GITHUB_OUTPUT | |
| elif [ "${{ github.event_name }}" = "workflow_run" ]; then | |
| BRANCH="${{ github.event.workflow_run.head_branch }}" | |
| if [ "$BRANCH" = "main" ] || [ "$BRANCH" = "master" ]; then | |
| echo "number=0" >> $GITHUB_OUTPUT | |
| else | |
| PR_NUM=$(gh pr list --repo ${{ github.repository }} --head "$BRANCH" --json number --jq '.[0].number // 0') | |
| echo "number=$PR_NUM" >> $GITHUB_OUTPUT | |
| fi | |
| else | |
| echo "number=0" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Get PR author association | |
| id: get-author | |
| env: | |
| GH_TOKEN: ${{ steps.token.outputs.token }} | |
| run: | | |
| PR_NUM="${{ steps.get-pr.outputs.number }}" | |
| if [ -z "$PR_NUM" ] || [ "$PR_NUM" = "0" ]; then | |
| # No PR (e.g., main branch CI) - treat as owner | |
| echo "assoc=OWNER" >> $GITHUB_OUTPUT | |
| else | |
| ASSOC=$(gh api repos/${{ github.repository }}/pulls/$PR_NUM --jq '.author_association') | |
| echo "assoc=$ASSOC" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Check author is member | |
| id: author | |
| run: | | |
| ASSOC="${{ steps.get-author.outputs.assoc }}" | |
| if [ "$ASSOC" = "OWNER" ] || [ "$ASSOC" = "MEMBER" ] || [ "$ASSOC" = "COLLABORATOR" ]; then | |
| echo "ok=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "::warning::Blocking Claude - PR author association is $ASSOC (not member)" | |
| echo "ok=false" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Check for non-member commits | |
| id: commits | |
| env: | |
| GH_TOKEN: ${{ steps.token.outputs.token }} | |
| run: | | |
| PR_NUM="${{ steps.get-pr.outputs.number }}" | |
| if [ -z "$PR_NUM" ] || [ "$PR_NUM" = "0" ]; then | |
| echo "ok=true" >> $GITHUB_OUTPUT | |
| exit 0 | |
| fi | |
| # Check each commit author's association | |
| NON_MEMBER=$(gh api repos/${{ github.repository }}/pulls/$PR_NUM/commits --jq \ | |
| '[.[] | select(.author.type != "Bot" and .author.login != null) | .author.login] | unique | .[]' | while read -r LOGIN; do | |
| if [ -n "$LOGIN" ]; then | |
| ASSOC=$(gh api repos/${{ github.repository }}/collaborators/$LOGIN/permission --jq '.permission' 2>/dev/null || echo "none") | |
| # Block if not a collaborator (permission = none) | |
| if [ "$ASSOC" = "none" ]; then | |
| echo "$LOGIN" | |
| fi | |
| fi | |
| done | head -1) | |
| if [ -n "$NON_MEMBER" ]; then | |
| echo "::warning::Blocking Claude - non-member commit author: $NON_MEMBER" | |
| echo "ok=false" >> $GITHUB_OUTPUT | |
| else | |
| echo "ok=true" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Check for non-member comments | |
| id: check | |
| env: | |
| GH_TOKEN: ${{ steps.token.outputs.token }} | |
| run: | | |
| PR_NUM="${{ steps.get-pr.outputs.number }}" | |
| if [ -z "$PR_NUM" ] || [ "$PR_NUM" = "0" ]; then | |
| echo "safe=true" >> $GITHUB_OUTPUT | |
| exit 0 | |
| fi | |
| ISSUE=$(gh api repos/${{ github.repository }}/issues/$PR_NUM/comments --jq "$NONMEMBER_FILTER" 2>/dev/null || echo 0) | |
| REVIEW=$(gh api repos/${{ github.repository }}/pulls/$PR_NUM/comments --jq "$NONMEMBER_FILTER" 2>/dev/null || echo 0) | |
| TOTAL=$((ISSUE + REVIEW)) | |
| if [ "$TOTAL" -gt 0 ]; then | |
| echo "::warning::Blocking Claude - $TOTAL non-member comment(s) detected" | |
| echo "safe=false" >> $GITHUB_OUTPUT | |
| else | |
| echo "safe=true" >> $GITHUB_OUTPUT | |
| fi | |
| # Review PRs from org members, auto-fix medium/critical issues | |
| review: | |
| needs: safety-check | |
| if: | | |
| needs.safety-check.outputs.safe == 'true' && | |
| needs.safety-check.outputs.author_ok == 'true' && | |
| needs.safety-check.outputs.commits_ok == 'true' && | |
| github.event_name == 'pull_request' && | |
| !startsWith(github.event.pull_request.head.ref, 'claude/fix-') | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 60 | |
| concurrency: | |
| group: claude-review-${{ github.event.pull_request.number }} | |
| cancel-in-progress: true | |
| steps: | |
| - name: Generate Claude token | |
| id: claude-token | |
| uses: actions/create-github-app-token@v2 | |
| with: | |
| app-id: ${{ vars.CLAUDE_APP_ID }} | |
| private-key: ${{ secrets.CLAUDE_APP_PRIVATE_KEY }} | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| token: ${{ steps.claude-token.outputs.token }} | |
| path: fcvm | |
| - uses: ./fcvm/.github/actions/checkout-deps | |
| - name: Install Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| components: rustfmt, clippy | |
| - name: Install build dependencies | |
| run: sudo apt-get update && sudo apt-get install -y libfuse3-dev libclang-dev clang | |
| - uses: actions/setup-node@v6 | |
| with: | |
| node-version: '20' | |
| - uses: pnpm/action-setup@v4 | |
| with: | |
| version: 9 | |
| - name: Install dependencies | |
| run: cd fcvm/scripts/claude-assistant && pnpm install | |
| - name: Run Claude review | |
| working-directory: fcvm | |
| env: | |
| GH_TOKEN: ${{ steps.claude-token.outputs.token }} | |
| CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} | |
| MODE: review | |
| GITHUB_REPOSITORY: ${{ github.repository }} | |
| PR_NUMBER: ${{ github.event.pull_request.number }} | |
| HEAD_BRANCH: ${{ github.event.pull_request.head.ref }} | |
| HEAD_SHA: ${{ github.event.pull_request.head.sha }} | |
| BASE_BRANCH: ${{ github.event.pull_request.base.ref }} | |
| RUN_ID: ${{ github.run_id }} | |
| RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} | |
| FUSE_BACKEND_RS: ${{ github.workspace }}/fuse-backend-rs | |
| FUSER: ${{ github.workspace }}/fuser | |
| run: | | |
| cd scripts/claude-assistant && pnpm exec tsx index.ts 2>&1 | tee /tmp/claude-output.log | |
| # Verify completion marker exists (detects if process was killed mid-execution) | |
| if ! grep -q "CLAUDE_ASSISTANT_COMPLETE" /tmp/claude-output.log; then | |
| echo "ERROR: Claude assistant did not complete - process may have been killed" | |
| exit 1 | |
| fi | |
| # Manual review via /claude-review comment | |
| manual-review: | |
| needs: safety-check | |
| if: | | |
| needs.safety-check.outputs.safe == 'true' && | |
| needs.safety-check.outputs.author_ok == 'true' && | |
| needs.safety-check.outputs.commits_ok == 'true' && | |
| github.event_name == 'issue_comment' && | |
| github.event.issue.pull_request && | |
| contains(github.event.comment.body, '/claude-review') | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 60 | |
| concurrency: | |
| group: claude-manual-${{ github.event.issue.number }} | |
| cancel-in-progress: true | |
| steps: | |
| - name: Generate Claude token | |
| id: claude-token | |
| uses: actions/create-github-app-token@v2 | |
| with: | |
| app-id: ${{ vars.CLAUDE_APP_ID }} | |
| private-key: ${{ secrets.CLAUDE_APP_PRIVATE_KEY }} | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| ref: refs/pull/${{ github.event.issue.number }}/head | |
| token: ${{ steps.claude-token.outputs.token }} | |
| path: fcvm | |
| - uses: ./fcvm/.github/actions/checkout-deps | |
| - name: Install Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| components: rustfmt, clippy | |
| - name: Install build dependencies | |
| run: sudo apt-get update && sudo apt-get install -y libfuse3-dev libclang-dev clang | |
| - uses: actions/setup-node@v6 | |
| with: | |
| node-version: '20' | |
| - uses: pnpm/action-setup@v4 | |
| with: | |
| version: 9 | |
| - name: Install dependencies | |
| run: cd fcvm/scripts/claude-assistant && pnpm install | |
| - name: Get PR info | |
| id: pr | |
| working-directory: fcvm | |
| run: | | |
| PR_DATA=$(gh pr view ${{ github.event.issue.number }} --json headRefName,headRefOid,baseRefName) | |
| echo "head_branch=$(echo $PR_DATA | jq -r .headRefName)" >> $GITHUB_OUTPUT | |
| echo "head_sha=$(echo $PR_DATA | jq -r .headRefOid)" >> $GITHUB_OUTPUT | |
| echo "base_branch=$(echo $PR_DATA | jq -r .baseRefName)" >> $GITHUB_OUTPUT | |
| env: | |
| GH_TOKEN: ${{ steps.claude-token.outputs.token }} | |
| - name: Run Claude review | |
| working-directory: fcvm | |
| env: | |
| GH_TOKEN: ${{ steps.claude-token.outputs.token }} | |
| CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} | |
| MODE: review | |
| GITHUB_REPOSITORY: ${{ github.repository }} | |
| PR_NUMBER: ${{ github.event.issue.number }} | |
| HEAD_BRANCH: ${{ steps.pr.outputs.head_branch }} | |
| HEAD_SHA: ${{ steps.pr.outputs.head_sha }} | |
| BASE_BRANCH: ${{ steps.pr.outputs.base_branch }} | |
| RUN_ID: ${{ github.run_id }} | |
| RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} | |
| FUSE_BACKEND_RS: ${{ github.workspace }}/fuse-backend-rs | |
| FUSER: ${{ github.workspace }}/fuser | |
| run: | | |
| cd scripts/claude-assistant && pnpm exec tsx index.ts 2>&1 | tee /tmp/claude-output.log | |
| if ! grep -q "CLAUDE_ASSISTANT_COMPLETE" /tmp/claude-output.log; then | |
| echo "ERROR: Claude assistant did not complete - process may have been killed" | |
| exit 1 | |
| fi | |
| # Respond to @claude mentions | |
| respond: | |
| needs: safety-check | |
| if: | | |
| needs.safety-check.outputs.safe == 'true' && | |
| needs.safety-check.outputs.author_ok == 'true' && | |
| needs.safety-check.outputs.commits_ok == 'true' && | |
| !contains(github.event.comment.body, '/claude-review') && | |
| ((github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) || | |
| (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude'))) | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| concurrency: | |
| group: claude-respond-${{ github.event.comment.id }} | |
| cancel-in-progress: false | |
| steps: | |
| - name: Generate Claude token | |
| id: claude-token | |
| uses: actions/create-github-app-token@v2 | |
| with: | |
| app-id: ${{ vars.CLAUDE_APP_ID }} | |
| private-key: ${{ secrets.CLAUDE_APP_PRIVATE_KEY }} | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| token: ${{ steps.claude-token.outputs.token }} | |
| path: fcvm | |
| - uses: ./fcvm/.github/actions/checkout-deps | |
| - name: Install Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| components: rustfmt, clippy | |
| - name: Install build dependencies | |
| run: sudo apt-get update && sudo apt-get install -y libfuse3-dev libclang-dev clang | |
| - uses: actions/setup-node@v6 | |
| with: | |
| node-version: '20' | |
| - uses: pnpm/action-setup@v4 | |
| with: | |
| version: 9 | |
| - name: Install dependencies | |
| run: cd fcvm/scripts/claude-assistant && pnpm install | |
| - name: Get PR info | |
| id: pr | |
| working-directory: fcvm | |
| env: | |
| GH_TOKEN: ${{ steps.claude-token.outputs.token }} | |
| run: | | |
| PR_NUM="${{ needs.safety-check.outputs.pr_number }}" | |
| if [ -n "$PR_NUM" ] && [ "$PR_NUM" != "0" ]; then | |
| PR_DATA=$(gh pr view $PR_NUM --json headRefName,headRefOid,baseRefName) | |
| echo "head_branch=$(echo $PR_DATA | jq -r .headRefName)" >> $GITHUB_OUTPUT | |
| echo "head_sha=$(echo $PR_DATA | jq -r .headRefOid)" >> $GITHUB_OUTPUT | |
| echo "base_branch=$(echo $PR_DATA | jq -r .baseRefName)" >> $GITHUB_OUTPUT | |
| else | |
| echo "head_branch=" >> $GITHUB_OUTPUT | |
| echo "head_sha=" >> $GITHUB_OUTPUT | |
| echo "base_branch=" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Run Claude respond | |
| working-directory: fcvm | |
| env: | |
| GH_TOKEN: ${{ steps.claude-token.outputs.token }} | |
| CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} | |
| MODE: respond | |
| GITHUB_REPOSITORY: ${{ github.repository }} | |
| PR_NUMBER: ${{ needs.safety-check.outputs.pr_number }} | |
| HEAD_BRANCH: ${{ steps.pr.outputs.head_branch }} | |
| HEAD_SHA: ${{ steps.pr.outputs.head_sha }} | |
| BASE_BRANCH: ${{ steps.pr.outputs.base_branch }} | |
| RUN_ID: ${{ github.run_id }} | |
| RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} | |
| COMMENT_BODY: ${{ github.event.comment.body }} | |
| FUSE_BACKEND_RS: ${{ github.workspace }}/fuse-backend-rs | |
| FUSER: ${{ github.workspace }}/fuser | |
| run: | | |
| cd scripts/claude-assistant && pnpm exec tsx index.ts 2>&1 | tee /tmp/claude-output.log | |
| if ! grep -q "CLAUDE_ASSISTANT_COMPLETE" /tmp/claude-output.log; then | |
| echo "ERROR: Claude assistant did not complete - process may have been killed" | |
| exit 1 | |
| fi | |
| # Auto-fix CI failures | |
| ci-fix: | |
| needs: safety-check | |
| if: | | |
| needs.safety-check.outputs.safe == 'true' && | |
| needs.safety-check.outputs.author_ok == 'true' && | |
| needs.safety-check.outputs.commits_ok == 'true' && | |
| github.event_name == 'workflow_run' && | |
| github.event.workflow_run.conclusion == 'failure' && | |
| !startsWith(github.event.workflow_run.head_branch, 'claude/fix-') && | |
| github.event.workflow_run.name != 'Claude Assistant' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 60 | |
| concurrency: | |
| group: claude-cifix-${{ github.event.workflow_run.head_branch }} | |
| cancel-in-progress: true | |
| steps: | |
| - name: Generate Claude token | |
| id: claude-token | |
| uses: actions/create-github-app-token@v2 | |
| with: | |
| app-id: ${{ vars.CLAUDE_APP_ID }} | |
| private-key: ${{ secrets.CLAUDE_APP_PRIVATE_KEY }} | |
| - uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ github.event.workflow_run.head_sha }} | |
| fetch-depth: 0 | |
| token: ${{ steps.claude-token.outputs.token }} | |
| path: fcvm | |
| - uses: ./fcvm/.github/actions/checkout-deps | |
| - name: Install Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| components: rustfmt, clippy | |
| - name: Install build dependencies | |
| run: sudo apt-get update && sudo apt-get install -y libfuse3-dev libclang-dev clang | |
| - uses: actions/setup-node@v6 | |
| with: | |
| node-version: '20' | |
| - uses: pnpm/action-setup@v4 | |
| with: | |
| version: 9 | |
| - name: Install dependencies | |
| run: cd fcvm/scripts/claude-assistant && pnpm install | |
| - name: Run Claude CI fix | |
| working-directory: fcvm | |
| env: | |
| GH_TOKEN: ${{ steps.claude-token.outputs.token }} | |
| CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} | |
| MODE: ci-fix | |
| GITHUB_REPOSITORY: ${{ github.repository }} | |
| PR_NUMBER: ${{ needs.safety-check.outputs.pr_number }} | |
| HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }} | |
| HEAD_SHA: ${{ github.event.workflow_run.head_sha }} | |
| BASE_BRANCH: main | |
| RUN_ID: ${{ github.run_id }} | |
| RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} | |
| FAILED_RUN_ID: ${{ github.event.workflow_run.id }} | |
| FAILED_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.event.workflow_run.id }} | |
| WORKFLOW_NAME: ${{ github.event.workflow_run.name }} | |
| FUSE_BACKEND_RS: ${{ github.workspace }}/fuse-backend-rs | |
| FUSER: ${{ github.workspace }}/fuser | |
| run: | | |
| cd scripts/claude-assistant && pnpm exec tsx index.ts 2>&1 | tee /tmp/claude-output.log | |
| if ! grep -q "CLAUDE_ASSISTANT_COMPLETE" /tmp/claude-output.log; then | |
| echo "ERROR: Claude assistant did not complete - process may have been killed" | |
| exit 1 | |
| fi |