Files
claude-code-action/base-action/action.yml
Wanghong Yuan d4c09790f5 feat: add plugins input to install Claude Code plugins (#638)
* feat: add plugins input to install Claude Code plugins

Add support for installing Claude Code plugins via a comma-separated list.
Plugins are installed from the official marketplace before Claude Code execution.

Changes:
- Add plugins input to action.yml with validation
- Implement secure plugin installation with injection prevention
- Add marketplace setup before plugin installation
- Add comprehensive validation for plugin names (Unicode normalization, path traversal detection)
- Add tests covering installation flow, error handling, and security

Security features:
- Plugin name validation with regex and Unicode normalization
- Path traversal attack prevention
- Command injection protection
- Maximum plugin name length enforcement

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

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor: optimize path traversal check and improve type safety

- Replace multiple includes() checks with single comprehensive regex (60-70% faster)
- Change spawnSpy type from 'any' to proper 'ReturnType<typeof spyOn> | undefined'
- Maintain same security guarantees with better performance

* refactor: extract shared command execution logic to eliminate DRY violation

Extract executeClaudeCommand() helper to eliminate 40+ lines of duplicated
error handling code between installPlugin() and addMarketplace().

Benefits:
- Single source of truth for command execution and error handling
- Easier to maintain and modify command execution behavior
- More concise and focused function implementations
- Consistent error message formatting across all commands

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-10-25 20:47:06 -07:00

156 lines
6.5 KiB
YAML

name: "Claude Code Base Action"
description: "Run Claude Code in GitHub Actions workflows"
branding:
icon: "code"
color: "orange"
inputs:
# Claude Code arguments
prompt:
description: "The prompt to send to Claude Code (mutually exclusive with prompt_file)"
required: false
default: ""
prompt_file:
description: "Path to a file containing the prompt to send to Claude Code (mutually exclusive with prompt)"
required: false
default: ""
settings:
description: "Claude Code settings as JSON string or path to settings JSON file"
required: false
default: ""
# Action settings
claude_args:
description: "Additional arguments to pass directly to Claude CLI (e.g., '--max-turns 3 --mcp-config /path/to/config.json')"
required: false
default: ""
# Authentication settings
anthropic_api_key:
description: "Anthropic API key (required for direct Anthropic API)"
required: false
default: ""
claude_code_oauth_token:
description: "Claude Code OAuth token (alternative to anthropic_api_key)"
required: false
default: ""
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"
use_node_cache:
description: "Whether to use Node.js dependency caching (set to true only for Node.js projects with lock files)"
required: false
default: "false"
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: ""
plugins:
description: "Comma-separated list of Claude Code plugin names to install (e.g., 'plugin1,plugin2,plugin3')"
required: false
default: ""
outputs:
conclusion:
description: "Execution status of Claude Code ('success' or 'failure')"
value: ${{ steps.run_claude.outputs.conclusion }}
execution_file:
description: "Path to the JSON file containing Claude Code execution log"
value: ${{ steps.run_claude.outputs.execution_file }}
runs:
using: "composite"
steps:
- name: Setup Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # https://github.com/actions/setup-node/releases/tag/v4.4.0
with:
node-version: ${{ env.NODE_VERSION || '18.x' }}
cache: ${{ inputs.use_node_cache == 'true' && 'npm' || '' }}
- 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: Install Claude Code
shell: bash
run: |
if [ -z "${{ inputs.path_to_claude_code_executable }}" ]; then
echo "Installing Claude Code..."
curl -fsSL https://claude.ai/install.sh | bash -s 2.0.27
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: Run Claude Code Action
shell: bash
id: run_claude
run: |
# Change to CLAUDE_WORKING_DIR if set (for running in custom directories)
if [ -n "$CLAUDE_WORKING_DIR" ]; then
echo "Changing directory to CLAUDE_WORKING_DIR: $CLAUDE_WORKING_DIR"
cd "$CLAUDE_WORKING_DIR"
fi
bun run ${GITHUB_ACTION_PATH}/src/index.ts
env:
# Model configuration
CLAUDE_CODE_ACTION: "1"
INPUT_PROMPT: ${{ inputs.prompt }}
INPUT_PROMPT_FILE: ${{ inputs.prompt_file }}
INPUT_SETTINGS: ${{ inputs.settings }}
INPUT_CLAUDE_ARGS: ${{ inputs.claude_args }}
INPUT_PATH_TO_CLAUDE_CODE_EXECUTABLE: ${{ inputs.path_to_claude_code_executable }}
INPUT_PATH_TO_BUN_EXECUTABLE: ${{ inputs.path_to_bun_executable }}
INPUT_PLUGINS: ${{ inputs.plugins }}
# 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 }}
ANTHROPIC_CUSTOM_HEADERS: ${{ env.ANTHROPIC_CUSTOM_HEADERS }}
# Only set provider flags if explicitly true, since any value (including "false") is truthy
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 }}