Files
claude-code-action/action.yml
Ashwin Bhat 63f1c772bd feat: add bot_id input to handle GitHub App authentication errors (#534)
Adds a new optional bot_id input parameter that defaults to the github-actions[bot] ID (41898282). This resolves the "403 Resource not accessible by integration" error that occurs when using GitHub App installation tokens, which cannot access the /user endpoint.

Changes:
- Add bot_id input to action.yml with default value
- Update context parsing to include bot_id from environment
- Modify agent mode to use bot_id when available, avoiding API calls that fail with GitHub App tokens
- Add clear error handling for GitHub App token limitations
- Update documentation in usage.md and faq.md
- Fix test mocks to include bot_id field

This allows users to specify a custom bot user ID or use the default github-actions[bot] ID automatically, preventing 403 errors in automation workflows.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
2025-09-04 14:55:25 -07:00

294 lines
13 KiB
YAML

name: "Claude Code Action v1.0"
description: "Flexible GitHub automation platform with Claude. Auto-detects mode based on event type: PR reviews, @claude mentions, or custom automation."
branding:
icon: "at-sign"
color: "orange"
inputs:
trigger_phrase:
description: "The trigger phrase to look for in comments or issue body"
required: false
default: "@claude"
assignee_trigger:
description: "The assignee username that triggers the action (e.g. @claude)"
required: false
label_trigger:
description: "The label that triggers the action (e.g. claude)"
required: false
default: "claude"
base_branch:
description: "The branch to use as the base/source when creating new branches (defaults to repository default branch)"
required: false
branch_prefix:
description: "The prefix to use for Claude branches (defaults to 'claude/', use 'claude-' for dash format)"
required: false
default: "claude/"
allowed_bots:
description: "Comma-separated list of allowed bot usernames, or '*' to allow all bots. Empty string (default) allows no bots."
required: false
default: ""
# Claude Code configuration
prompt:
description: "Instructions for Claude. Can be a direct prompt or custom template."
required: false
default: ""
settings:
description: "Claude Code settings as JSON string or path to settings JSON file"
required: false
default: ""
# Auth configuration
anthropic_api_key:
description: "Anthropic API key (required for direct API, not needed for Bedrock/Vertex)"
required: false
claude_code_oauth_token:
description: "Claude Code OAuth token (alternative to anthropic_api_key)"
required: false
github_token:
description: "GitHub token with repo and pull request permissions (optional if using GitHub App)"
required: false
use_bedrock:
description: "Use Amazon Bedrock with OIDC authentication instead of direct Anthropic API"
required: false
default: "false"
use_vertex:
description: "Use Google Vertex AI with OIDC authentication instead of direct Anthropic API"
required: false
default: "false"
claude_args:
description: "Additional arguments to pass directly to Claude CLI"
required: false
default: ""
additional_permissions:
description: "Additional GitHub permissions to request (e.g., 'actions: read')"
required: false
default: ""
use_sticky_comment:
description: "Use just one comment to deliver issue/PR comments"
required: false
default: "false"
use_commit_signing:
description: "Enable commit signing using GitHub's commit signature verification. When false, Claude uses standard git commands"
required: false
default: "false"
bot_id:
description: "GitHub user ID to use for git operations (defaults to Claude's bot ID)"
required: false
default: "41898282" # Claude's bot ID - see src/github/constants.ts
bot_name:
description: "GitHub username to use for git operations (defaults to Claude's bot name)"
required: false
default: "claude[bot]"
track_progress:
description: "Force tag mode with tracking comments for pull_request and issue events. Only applicable to pull_request (opened, synchronize, ready_for_review, reopened) and issue (opened, edited, labeled, assigned) events."
required: false
default: "false"
experimental_allowed_domains:
description: "Restrict network access to these domains only (newline-separated). If not set, no restrictions are applied. Provider domains are auto-detected."
required: false
default: ""
path_to_claude_code_executable:
description: "Optional path to a custom Claude Code executable. If provided, skips automatic installation and uses this executable instead. WARNING: Using an older version may cause problems if the action begins taking advantage of new Claude Code features. This input is typically not needed unless you're debugging something specific or have unique needs in your environment."
required: false
default: ""
path_to_bun_executable:
description: "Optional path to a custom Bun executable. If provided, skips automatic Bun installation and uses this executable instead. WARNING: Using an incompatible version may cause problems if the action requires specific Bun features. This input is typically not needed unless you're debugging something specific or have unique needs in your environment."
required: false
default: ""
outputs:
execution_file:
description: "Path to the Claude Code execution output file"
value: ${{ steps.claude-code.outputs.execution_file }}
branch_name:
description: "The branch created by Claude Code for this execution"
value: ${{ steps.prepare.outputs.CLAUDE_BRANCH }}
github_token:
description: "The GitHub token used by the action (Claude App token if available)"
value: ${{ steps.prepare.outputs.github_token }}
runs:
using: "composite"
steps:
- name: Install Bun
if: inputs.path_to_bun_executable == ''
uses: oven-sh/setup-bun@735343b667d3e6f658f44d0eca948eb6282f2b76 # https://github.com/oven-sh/setup-bun/releases/tag/v2.0.2
with:
bun-version: 1.2.11
- name: Setup Custom Bun Path
if: inputs.path_to_bun_executable != ''
shell: bash
run: |
echo "Using custom Bun executable: ${{ inputs.path_to_bun_executable }}"
# Add the directory containing the custom executable to PATH
BUN_DIR=$(dirname "${{ inputs.path_to_bun_executable }}")
echo "$BUN_DIR" >> "$GITHUB_PATH"
- name: Install Dependencies
shell: bash
run: |
cd ${GITHUB_ACTION_PATH}
bun install
- name: Prepare action
id: prepare
shell: bash
run: |
bun run ${GITHUB_ACTION_PATH}/src/entrypoints/prepare.ts
env:
MODE: ${{ inputs.mode }}
PROMPT: ${{ inputs.prompt }}
TRIGGER_PHRASE: ${{ inputs.trigger_phrase }}
ASSIGNEE_TRIGGER: ${{ inputs.assignee_trigger }}
LABEL_TRIGGER: ${{ inputs.label_trigger }}
BASE_BRANCH: ${{ inputs.base_branch }}
BRANCH_PREFIX: ${{ inputs.branch_prefix }}
OVERRIDE_GITHUB_TOKEN: ${{ inputs.github_token }}
ALLOWED_BOTS: ${{ inputs.allowed_bots }}
GITHUB_RUN_ID: ${{ github.run_id }}
USE_STICKY_COMMENT: ${{ inputs.use_sticky_comment }}
DEFAULT_WORKFLOW_TOKEN: ${{ github.token }}
USE_COMMIT_SIGNING: ${{ inputs.use_commit_signing }}
BOT_ID: ${{ inputs.bot_id }}
BOT_NAME: ${{ inputs.bot_name }}
TRACK_PROGRESS: ${{ inputs.track_progress }}
ADDITIONAL_PERMISSIONS: ${{ inputs.additional_permissions }}
CLAUDE_ARGS: ${{ inputs.claude_args }}
ALL_INPUTS: ${{ toJson(inputs) }}
- name: Install Base Action Dependencies
if: steps.prepare.outputs.contains_trigger == 'true'
shell: bash
run: |
echo "Installing base-action dependencies..."
cd ${GITHUB_ACTION_PATH}/base-action
bun install
echo "Base-action dependencies installed"
cd -
# Install Claude Code if no custom executable is provided
if [ -z "${{ inputs.path_to_claude_code_executable }}" ]; then
echo "Installing Claude Code..."
curl -fsSL https://claude.ai/install.sh | bash -s 1.0.105
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
else
echo "Using custom Claude Code executable: ${{ inputs.path_to_claude_code_executable }}"
# Add the directory containing the custom executable to PATH
CLAUDE_DIR=$(dirname "${{ inputs.path_to_claude_code_executable }}")
echo "$CLAUDE_DIR" >> "$GITHUB_PATH"
fi
- name: Setup Network Restrictions
if: steps.prepare.outputs.contains_trigger == 'true' && inputs.experimental_allowed_domains != ''
shell: bash
run: |
chmod +x ${GITHUB_ACTION_PATH}/scripts/setup-network-restrictions.sh
${GITHUB_ACTION_PATH}/scripts/setup-network-restrictions.sh
env:
EXPERIMENTAL_ALLOWED_DOMAINS: ${{ inputs.experimental_allowed_domains }}
- name: Run Claude Code
id: claude-code
if: steps.prepare.outputs.contains_trigger == 'true'
shell: bash
run: |
# Run the base-action
bun run ${GITHUB_ACTION_PATH}/base-action/src/index.ts
env:
# Base-action inputs
CLAUDE_CODE_ACTION: "1"
INPUT_PROMPT_FILE: ${{ runner.temp }}/claude-prompts/claude-prompt.txt
INPUT_SETTINGS: ${{ inputs.settings }}
INPUT_CLAUDE_ARGS: ${{ steps.prepare.outputs.claude_args }}
INPUT_EXPERIMENTAL_SLASH_COMMANDS_DIR: ${{ github.action_path }}/slash-commands
INPUT_ACTION_INPUTS_PRESENT: ${{ steps.prepare.outputs.action_inputs_present }}
INPUT_PATH_TO_CLAUDE_CODE_EXECUTABLE: ${{ inputs.path_to_claude_code_executable }}
INPUT_PATH_TO_BUN_EXECUTABLE: ${{ inputs.path_to_bun_executable }}
# Model configuration
GITHUB_TOKEN: ${{ steps.prepare.outputs.GITHUB_TOKEN }}
NODE_VERSION: ${{ env.NODE_VERSION }}
DETAILED_PERMISSION_MESSAGES: "1"
# Provider configuration
ANTHROPIC_API_KEY: ${{ inputs.anthropic_api_key }}
CLAUDE_CODE_OAUTH_TOKEN: ${{ inputs.claude_code_oauth_token }}
ANTHROPIC_BASE_URL: ${{ env.ANTHROPIC_BASE_URL }}
CLAUDE_CODE_USE_BEDROCK: ${{ inputs.use_bedrock == 'true' && '1' || '' }}
CLAUDE_CODE_USE_VERTEX: ${{ inputs.use_vertex == 'true' && '1' || '' }}
# AWS configuration
AWS_REGION: ${{ env.AWS_REGION }}
AWS_ACCESS_KEY_ID: ${{ env.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ env.AWS_SECRET_ACCESS_KEY }}
AWS_SESSION_TOKEN: ${{ env.AWS_SESSION_TOKEN }}
ANTHROPIC_BEDROCK_BASE_URL: ${{ env.ANTHROPIC_BEDROCK_BASE_URL || (env.AWS_REGION && format('https://bedrock-runtime.{0}.amazonaws.com', env.AWS_REGION)) }}
# GCP configuration
ANTHROPIC_VERTEX_PROJECT_ID: ${{ env.ANTHROPIC_VERTEX_PROJECT_ID }}
CLOUD_ML_REGION: ${{ env.CLOUD_ML_REGION }}
GOOGLE_APPLICATION_CREDENTIALS: ${{ env.GOOGLE_APPLICATION_CREDENTIALS }}
ANTHROPIC_VERTEX_BASE_URL: ${{ env.ANTHROPIC_VERTEX_BASE_URL }}
# Model-specific regions for Vertex
VERTEX_REGION_CLAUDE_3_5_HAIKU: ${{ env.VERTEX_REGION_CLAUDE_3_5_HAIKU }}
VERTEX_REGION_CLAUDE_3_5_SONNET: ${{ env.VERTEX_REGION_CLAUDE_3_5_SONNET }}
VERTEX_REGION_CLAUDE_3_7_SONNET: ${{ env.VERTEX_REGION_CLAUDE_3_7_SONNET }}
- name: Update comment with job link
if: steps.prepare.outputs.contains_trigger == 'true' && steps.prepare.outputs.claude_comment_id && always()
shell: bash
run: |
bun run ${GITHUB_ACTION_PATH}/src/entrypoints/update-comment-link.ts
env:
REPOSITORY: ${{ github.repository }}
PR_NUMBER: ${{ github.event.issue.number || github.event.pull_request.number }}
CLAUDE_COMMENT_ID: ${{ steps.prepare.outputs.claude_comment_id }}
GITHUB_RUN_ID: ${{ github.run_id }}
GITHUB_TOKEN: ${{ steps.prepare.outputs.GITHUB_TOKEN }}
GITHUB_EVENT_NAME: ${{ github.event_name }}
TRIGGER_COMMENT_ID: ${{ github.event.comment.id }}
CLAUDE_BRANCH: ${{ steps.prepare.outputs.CLAUDE_BRANCH }}
IS_PR: ${{ github.event.issue.pull_request != null || github.event_name == 'pull_request_review_comment' }}
BASE_BRANCH: ${{ steps.prepare.outputs.BASE_BRANCH }}
CLAUDE_SUCCESS: ${{ steps.claude-code.outputs.conclusion == 'success' }}
OUTPUT_FILE: ${{ steps.claude-code.outputs.execution_file || '' }}
TRIGGER_USERNAME: ${{ github.event.comment.user.login || github.event.issue.user.login || github.event.pull_request.user.login || github.event.sender.login || github.triggering_actor || github.actor || '' }}
PREPARE_SUCCESS: ${{ steps.prepare.outcome == 'success' }}
PREPARE_ERROR: ${{ steps.prepare.outputs.prepare_error || '' }}
USE_STICKY_COMMENT: ${{ inputs.use_sticky_comment }}
USE_COMMIT_SIGNING: ${{ inputs.use_commit_signing }}
TRACK_PROGRESS: ${{ inputs.track_progress }}
- name: Display Claude Code Report
if: steps.prepare.outputs.contains_trigger == 'true' && steps.claude-code.outputs.execution_file != ''
shell: bash
run: |
# Try to format the turns, but if it fails, dump the raw JSON
if bun run ${{ github.action_path }}/src/entrypoints/format-turns.ts "${{ steps.claude-code.outputs.execution_file }}" >> $GITHUB_STEP_SUMMARY 2>/dev/null; then
echo "Successfully formatted Claude Code report"
else
echo "## Claude Code Report (Raw Output)" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Failed to format output (please report). Here's the raw JSON:" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo '```json' >> $GITHUB_STEP_SUMMARY
cat "${{ steps.claude-code.outputs.execution_file }}" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
fi
- name: Revoke app token
if: always() && inputs.github_token == '' && steps.prepare.outputs.skipped_due_to_workflow_validation_mismatch != 'true'
shell: bash
run: |
curl -L \
-X DELETE \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${{ steps.prepare.outputs.GITHUB_TOKEN }}" \
-H "X-GitHub-Api-Version: 2022-11-28" \
${GITHUB_API_URL:-https://api.github.com}/installation/token