This commit is contained in:
github-actions[bot]
2025-09-04 11:28:30 -07:00
parent cc47c8baef
commit 59a49d170c
11 changed files with 89 additions and 112 deletions

View File

@@ -74,9 +74,13 @@ inputs:
required: false required: false
default: "false" default: "false"
bot_id: bot_id:
description: "GitHub user ID to use for git operations when authenticated user cannot be fetched (defaults to github-actions[bot] ID)" description: "GitHub user ID to use for git operations (defaults to github-actions[bot] ID)"
required: false required: false
default: "41898282" # github-actions[bot] ID - see src/github/constants.ts default: "41898282" # github-actions[bot] ID - see src/github/constants.ts
bot_name:
description: "GitHub username to use for git operations (defaults to github-actions[bot])"
required: false
default: "github-actions[bot]"
track_progress: 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." 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 required: false
@@ -149,6 +153,7 @@ runs:
DEFAULT_WORKFLOW_TOKEN: ${{ github.token }} DEFAULT_WORKFLOW_TOKEN: ${{ github.token }}
USE_COMMIT_SIGNING: ${{ inputs.use_commit_signing }} USE_COMMIT_SIGNING: ${{ inputs.use_commit_signing }}
BOT_ID: ${{ inputs.bot_id }} BOT_ID: ${{ inputs.bot_id }}
BOT_NAME: ${{ inputs.bot_name }}
TRACK_PROGRESS: ${{ inputs.track_progress }} TRACK_PROGRESS: ${{ inputs.track_progress }}
ADDITIONAL_PERMISSIONS: ${{ inputs.additional_permissions }} ADDITIONAL_PERMISSIONS: ${{ inputs.additional_permissions }}
CLAUDE_ARGS: ${{ inputs.claude_args }} CLAUDE_ARGS: ${{ inputs.claude_args }}

View File

@@ -32,13 +32,25 @@ The OIDC token is required in order for the Claude GitHub app to function. If yo
This error occurs when the action tries to fetch the authenticated user information using a GitHub App installation token. GitHub App tokens have limited access and cannot access the `/user` endpoint, which causes this 403 error. This error occurs when the action tries to fetch the authenticated user information using a GitHub App installation token. GitHub App tokens have limited access and cannot access the `/user` endpoint, which causes this 403 error.
**Solution**: The action now includes a `bot_id` input that defaults to the github-actions[bot] ID (41898282). This avoids the need to fetch user information. If you need to use a different bot user, you can specify a custom bot_id: **Solution**: The action now includes `bot_id` and `bot_name` inputs that default to github-actions[bot]. This avoids the need to fetch user information from the API.
For the default github-actions[bot]:
```yaml ```yaml
- uses: anthropics/claude-code-action@v1 - uses: anthropics/claude-code-action@v1
with: with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
bot_id: "12345678" # Custom bot user ID # bot_id and bot_name have sensible defaults, no need to specify
```
For custom bots, specify both:
```yaml
- uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
bot_id: "12345678" # Your bot's GitHub user ID
bot_name: "my-bot" # Your bot's username
``` ```
This issue typically only affects agent/automation mode workflows. Interactive workflows (with @claude mentions) don't encounter this issue as they use the comment author's information. This issue typically only affects agent/automation mode workflows. Interactive workflows (with @claude mentions) don't encounter this issue as they use the comment author's information.

View File

@@ -47,29 +47,30 @@ jobs:
## Inputs ## Inputs
| Input | Description | Required | Default | | Input | Description | Required | Default |
| ------------------------------ | ----------------------------------------------------------------------------------------------------------------------- | -------- | ---------- | | ------------------------------ | -------------------------------------------------------------------------------------------------------------------- | -------- | --------------------- |
| `anthropic_api_key` | Anthropic API key (required for direct API, not needed for Bedrock/Vertex) | No\* | - | | `anthropic_api_key` | Anthropic API key (required for direct API, not needed for Bedrock/Vertex) | No\* | - |
| `claude_code_oauth_token` | Claude Code OAuth token (alternative to anthropic_api_key) | No\* | - | | `claude_code_oauth_token` | Claude Code OAuth token (alternative to anthropic_api_key) | No\* | - |
| `prompt` | Instructions for Claude. Can be a direct prompt or custom template for automation workflows | No | - | | `prompt` | Instructions for Claude. Can be a direct prompt or custom template for automation workflows | No | - |
| `track_progress` | Force tag mode with tracking comments. Only works with specific PR/issue events. Preserves GitHub context | No | `false` | | `track_progress` | Force tag mode with tracking comments. Only works with specific PR/issue events. Preserves GitHub context | No | `false` |
| `claude_args` | Additional arguments to pass directly to Claude CLI (e.g., `--max-turns 10 --model claude-4-0-sonnet-20250805`) | No | "" | | `claude_args` | Additional arguments to pass directly to Claude CLI (e.g., `--max-turns 10 --model claude-4-0-sonnet-20250805`) | No | "" |
| `base_branch` | The base branch to use for creating new branches (e.g., 'main', 'develop') | No | - | | `base_branch` | The base branch to use for creating new branches (e.g., 'main', 'develop') | No | - |
| `use_sticky_comment` | Use just one comment to deliver PR comments (only applies for pull_request event workflows) | No | `false` | | `use_sticky_comment` | Use just one comment to deliver PR comments (only applies for pull_request event workflows) | No | `false` |
| `github_token` | GitHub token for Claude to operate with. **Only include this if you're connecting a custom GitHub app of your own!** | No | - | | `github_token` | GitHub token for Claude to operate with. **Only include this if you're connecting a custom GitHub app of your own!** | No | - |
| `use_bedrock` | Use Amazon Bedrock with OIDC authentication instead of direct Anthropic API | No | `false` | | `use_bedrock` | Use Amazon Bedrock with OIDC authentication instead of direct Anthropic API | No | `false` |
| `use_vertex` | Use Google Vertex AI with OIDC authentication instead of direct Anthropic API | No | `false` | | `use_vertex` | Use Google Vertex AI with OIDC authentication instead of direct Anthropic API | No | `false` |
| `mcp_config` | Additional MCP configuration (JSON string) that merges with the built-in GitHub MCP servers | No | "" | | `mcp_config` | Additional MCP configuration (JSON string) that merges with the built-in GitHub MCP servers | No | "" |
| `assignee_trigger` | The assignee username that triggers the action (e.g. @claude). Only used for issue assignment | No | - | | `assignee_trigger` | The assignee username that triggers the action (e.g. @claude). Only used for issue assignment | No | - |
| `label_trigger` | The label name that triggers the action when applied to an issue (e.g. "claude") | No | - | | `label_trigger` | The label name that triggers the action when applied to an issue (e.g. "claude") | No | - |
| `trigger_phrase` | The trigger phrase to look for in comments, issue/PR bodies, and issue titles | No | `@claude` | | `trigger_phrase` | The trigger phrase to look for in comments, issue/PR bodies, and issue titles | No | `@claude` |
| `branch_prefix` | The prefix to use for Claude branches (defaults to 'claude/', use 'claude-' for dash format) | No | `claude/` | | `branch_prefix` | The prefix to use for Claude branches (defaults to 'claude/', use 'claude-' for dash format) | No | `claude/` |
| `settings` | Claude Code settings as JSON string or path to settings JSON file | No | "" | | `settings` | Claude Code settings as JSON string or path to settings JSON file | No | "" |
| `additional_permissions` | Additional permissions to enable. Currently supports 'actions: read' for viewing workflow results | No | "" | | `additional_permissions` | Additional permissions to enable. Currently supports 'actions: read' for viewing workflow results | No | "" |
| `experimental_allowed_domains` | Restrict network access to these domains only (newline-separated). | No | "" | | `experimental_allowed_domains` | Restrict network access to these domains only (newline-separated). | No | "" |
| `use_commit_signing` | Enable commit signing using GitHub's commit signature verification. When false, Claude uses standard git commands | No | `false` | | `use_commit_signing` | Enable commit signing using GitHub's commit signature verification. When false, Claude uses standard git commands | No | `false` |
| `bot_id` | GitHub user ID to use for git operations when authenticated user cannot be fetched (defaults to github-actions[bot] ID) | No | `41898282` | | `bot_id` | GitHub user ID to use for git operations (defaults to github-actions[bot] ID) | No | `41898282` |
| `allowed_bots` | Comma-separated list of allowed bot usernames, or '\*' to allow all bots. Empty string (default) allows no bots | No | "" | | `bot_name` | GitHub username to use for git operations (defaults to github-actions[bot]) | No | `github-actions[bot]` |
| `allowed_bots` | Comma-separated list of allowed bot usernames, or '\*' to allow all bots. Empty string (default) allows no bots | No | "" |
### Deprecated Inputs ### Deprecated Inputs

View File

@@ -3,10 +3,9 @@
*/ */
/** /**
* GitHub Actions bot user ID * Claude App bot user ID
* This is the official ID for github-actions[bot] used in GitHub repositories
*/ */
export const GITHUB_ACTIONS_BOT_ID = 41898282; export const CLAUDE_APP_BOT_ID = 41898282;
/** /**
* GitHub Actions bot username * GitHub Actions bot username

View File

@@ -8,7 +8,7 @@ import type {
PullRequestReviewCommentEvent, PullRequestReviewCommentEvent,
WorkflowRunEvent, WorkflowRunEvent,
} from "@octokit/webhooks-types"; } from "@octokit/webhooks-types";
import { GITHUB_ACTIONS_BOT_ID } from "./constants"; import { CLAUDE_APP_BOT_ID, GITHUB_ACTIONS_BOT_LOGIN } from "./constants";
// Custom types for GitHub Actions events that aren't webhooks // Custom types for GitHub Actions events that aren't webhooks
export type WorkflowDispatchEvent = { export type WorkflowDispatchEvent = {
action?: never; action?: never;
@@ -76,6 +76,7 @@ type BaseContext = {
useStickyComment: boolean; useStickyComment: boolean;
useCommitSigning: boolean; useCommitSigning: boolean;
botId: string; botId: string;
botName: string;
allowedBots: string; allowedBots: string;
trackProgress: boolean; trackProgress: boolean;
}; };
@@ -124,7 +125,8 @@ export function parseGitHubContext(): GitHubContext {
branchPrefix: process.env.BRANCH_PREFIX ?? "claude/", branchPrefix: process.env.BRANCH_PREFIX ?? "claude/",
useStickyComment: process.env.USE_STICKY_COMMENT === "true", useStickyComment: process.env.USE_STICKY_COMMENT === "true",
useCommitSigning: process.env.USE_COMMIT_SIGNING === "true", useCommitSigning: process.env.USE_COMMIT_SIGNING === "true",
botId: process.env.BOT_ID ?? String(GITHUB_ACTIONS_BOT_ID), botId: process.env.BOT_ID ?? String(CLAUDE_APP_BOT_ID),
botName: process.env.BOT_NAME ?? GITHUB_ACTIONS_BOT_LOGIN,
allowedBots: process.env.ALLOWED_BOTS ?? "", allowedBots: process.env.ALLOWED_BOTS ?? "",
trackProgress: process.env.TRACK_PROGRESS === "true", trackProgress: process.env.TRACK_PROGRESS === "true",
}, },

View File

@@ -8,7 +8,6 @@
import { $ } from "bun"; import { $ } from "bun";
import type { GitHubContext } from "../context"; import type { GitHubContext } from "../context";
import { GITHUB_SERVER_URL } from "../api/config"; import { GITHUB_SERVER_URL } from "../api/config";
import { GITHUB_ACTIONS_BOT_ID, GITHUB_ACTIONS_BOT_LOGIN } from "../constants";
type GitUser = { type GitUser = {
login: string; login: string;
@@ -18,7 +17,7 @@ type GitUser = {
export async function configureGitAuth( export async function configureGitAuth(
githubToken: string, githubToken: string,
context: GitHubContext, context: GitHubContext,
user: GitUser | null, user: GitUser,
) { ) {
console.log("Configuring git authentication for non-signing mode"); console.log("Configuring git authentication for non-signing mode");
@@ -29,20 +28,14 @@ export async function configureGitAuth(
? "users.noreply.github.com" ? "users.noreply.github.com"
: `users.noreply.${serverUrl.hostname}`; : `users.noreply.${serverUrl.hostname}`;
// Configure git user based on the comment creator // Configure git user
console.log("Configuring git user..."); console.log("Configuring git user...");
if (user) { const botName = user.login;
const botName = user.login; const botId = user.id;
const botId = user.id; console.log(`Setting git user as ${botName}...`);
console.log(`Setting git user as ${botName}...`); await $`git config user.name "${botName}"`;
await $`git config user.name "${botName}"`; await $`git config user.email "${botId}+${botName}@${noreplyDomain}"`;
await $`git config user.email "${botId}+${botName}@${noreplyDomain}"`; console.log(`✓ Set git user as ${botName}`);
console.log(`✓ Set git user as ${botName}`);
} else {
console.log("No user data in comment, using default bot user");
await $`git config user.name "${GITHUB_ACTIONS_BOT_LOGIN}"`;
await $`git config user.email "${GITHUB_ACTIONS_BOT_ID}+${GITHUB_ACTIONS_BOT_LOGIN}@${noreplyDomain}"`;
}
// Remove the authorization header that actions/checkout sets // Remove the authorization header that actions/checkout sets
console.log("Removing existing git authentication headers..."); console.log("Removing existing git authentication headers...");

View File

@@ -7,7 +7,6 @@ import { parseAllowedTools } from "./parse-tools";
import { configureGitAuth } from "../../github/operations/git-config"; import { configureGitAuth } from "../../github/operations/git-config";
import type { GitHubContext } from "../../github/context"; import type { GitHubContext } from "../../github/context";
import { isEntityContext } from "../../github/context"; import { isEntityContext } from "../../github/context";
import { GITHUB_ACTIONS_BOT_ID } from "../../github/constants";
/** /**
* Extract GitHub context as environment variables for agent mode * Extract GitHub context as environment variables for agent mode
@@ -78,66 +77,14 @@ export const agentMode: Mode = {
return false; return false;
}, },
async prepare({ async prepare({ context, githubToken }: ModeOptions): Promise<ModeResult> {
context,
githubToken,
octokit,
}: ModeOptions): Promise<ModeResult> {
// Configure git authentication for agent mode (same as tag mode) // Configure git authentication for agent mode (same as tag mode)
if (!context.inputs.useCommitSigning) { if (!context.inputs.useCommitSigning) {
let user = null; // Use bot_id and bot_name from inputs directly
const user = {
// Check if bot_id is provided login: context.inputs.botName,
console.log("yolobot", context.inputs.botId); id: parseInt(context.inputs.botId),
const botId = context.inputs.botId; };
if (botId && botId !== String(GITHUB_ACTIONS_BOT_ID)) {
// Use custom bot_id - try to fetch user info
try {
const { data: userData } = await octokit.rest.users.getByUsername({
username: context.actor,
});
user = {
login: userData.login,
id: userData.id,
};
console.log("yolo user", user);
} catch (error) {
console.log(
`Could not fetch user info for ${context.actor}, using bot_id ${botId}`,
);
user = {
login: context.actor,
id: parseInt(botId),
};
}
} else {
// Try to get authenticated user, but don't fail if using GitHub App token
try {
const { data: authenticatedUser } =
await octokit.rest.users.getAuthenticated();
user = {
login: authenticatedUser.login,
id: authenticatedUser.id,
};
console.log("yolo user auth", user);
} catch (error: any) {
// Check if this is a GitHub App token limitation
if (
error?.status === 403 &&
error?.message?.includes("Resource not accessible by integration")
) {
console.log(
"Using GitHub App token - defaulting to github-actions[bot] for git operations",
);
} else {
console.error(
"Failed to get authenticated user:",
error?.message || error,
);
}
// User will remain null, which will trigger default behavior in configureGitAuth
}
}
try { try {
// Use the shared git configuration function // Use the shared git configuration function

View File

@@ -89,8 +89,14 @@ export const tagMode: Mode = {
// Configure git authentication if not using commit signing // Configure git authentication if not using commit signing
if (!context.inputs.useCommitSigning) { if (!context.inputs.useCommitSigning) {
// Use bot_id and bot_name from inputs directly
const user = {
login: context.inputs.botName,
id: parseInt(context.inputs.botId),
};
try { try {
await configureGitAuth(githubToken, context, commentData.user); await configureGitAuth(githubToken, context, user);
} catch (error) { } catch (error) {
console.error("Failed to configure git authentication:", error); console.error("Failed to configure git authentication:", error);
throw error; throw error;

View File

@@ -2,7 +2,10 @@ import { describe, test, expect, beforeEach, afterEach, spyOn } from "bun:test";
import { prepareMcpConfig } from "../src/mcp/install-mcp-server"; import { prepareMcpConfig } from "../src/mcp/install-mcp-server";
import * as core from "@actions/core"; import * as core from "@actions/core";
import type { ParsedGitHubContext } from "../src/github/context"; import type { ParsedGitHubContext } from "../src/github/context";
import { GITHUB_ACTIONS_BOT_ID } from "../src/github/constants"; import {
CLAUDE_APP_BOT_ID,
GITHUB_ACTIONS_BOT_LOGIN,
} from "../src/github/constants";
describe("prepareMcpConfig", () => { describe("prepareMcpConfig", () => {
let consoleInfoSpy: any; let consoleInfoSpy: any;
@@ -32,7 +35,8 @@ describe("prepareMcpConfig", () => {
branchPrefix: "", branchPrefix: "",
useStickyComment: false, useStickyComment: false,
useCommitSigning: false, useCommitSigning: false,
botId: String(GITHUB_ACTIONS_BOT_ID), botId: String(CLAUDE_APP_BOT_ID),
botName: GITHUB_ACTIONS_BOT_LOGIN,
allowedBots: "", allowedBots: "",
trackProgress: false, trackProgress: false,
}, },

View File

@@ -9,7 +9,10 @@ import type {
PullRequestReviewEvent, PullRequestReviewEvent,
PullRequestReviewCommentEvent, PullRequestReviewCommentEvent,
} from "@octokit/webhooks-types"; } from "@octokit/webhooks-types";
import { GITHUB_ACTIONS_BOT_ID } from "../src/github/constants"; import {
CLAUDE_APP_BOT_ID,
GITHUB_ACTIONS_BOT_LOGIN,
} from "../src/github/constants";
const defaultInputs = { const defaultInputs = {
prompt: "", prompt: "",
@@ -19,7 +22,8 @@ const defaultInputs = {
branchPrefix: "claude/", branchPrefix: "claude/",
useStickyComment: false, useStickyComment: false,
useCommitSigning: false, useCommitSigning: false,
botId: String(GITHUB_ACTIONS_BOT_ID), botId: String(CLAUDE_APP_BOT_ID),
botName: GITHUB_ACTIONS_BOT_LOGIN,
allowedBots: "", allowedBots: "",
trackProgress: false, trackProgress: false,
}; };

View File

@@ -2,7 +2,10 @@ import { describe, expect, test, spyOn, beforeEach, afterEach } from "bun:test";
import * as core from "@actions/core"; import * as core from "@actions/core";
import { checkWritePermissions } from "../src/github/validation/permissions"; import { checkWritePermissions } from "../src/github/validation/permissions";
import type { ParsedGitHubContext } from "../src/github/context"; import type { ParsedGitHubContext } from "../src/github/context";
import { GITHUB_ACTIONS_BOT_ID } from "../src/github/constants"; import {
CLAUDE_APP_BOT_ID,
GITHUB_ACTIONS_BOT_LOGIN,
} from "../src/github/constants";
describe("checkWritePermissions", () => { describe("checkWritePermissions", () => {
let coreInfoSpy: any; let coreInfoSpy: any;
@@ -68,7 +71,8 @@ describe("checkWritePermissions", () => {
branchPrefix: "claude/", branchPrefix: "claude/",
useStickyComment: false, useStickyComment: false,
useCommitSigning: false, useCommitSigning: false,
botId: String(GITHUB_ACTIONS_BOT_ID), botId: String(CLAUDE_APP_BOT_ID),
botName: GITHUB_ACTIONS_BOT_LOGIN,
allowedBots: "", allowedBots: "",
trackProgress: false, trackProgress: false,
}, },