Compare commits

..

2 Commits

Author SHA1 Message Date
claude[bot]
853107da75 docs: add claude_env input documentation with clear syntax examples
Added comprehensive documentation for the new claude_env input including:
- Entry in the Inputs table with description
- Example in the basic workflow configuration
- Detailed section in Advanced Configuration with practical use cases

This makes it clear how users can pass custom environment variables
to Claude Code execution in YAML format for CI/test setups.

Co-authored-by: ashwin-ant <ashwin-ant@users.noreply.github.com>
2025-06-02 20:49:22 -07:00
claude[bot]
39c280bfdb feat: add claude_env input for custom environment variables
Co-authored-by: ashwin-ant <ashwin-ant@users.noreply.github.com>
2025-06-02 20:49:21 -07:00
15 changed files with 99 additions and 201 deletions

View File

@@ -23,20 +23,18 @@ jobs:
mkdir -p /tmp/mcp-config mkdir -p /tmp/mcp-config
cat > /tmp/mcp-config/mcp-servers.json << 'EOF' cat > /tmp/mcp-config/mcp-servers.json << 'EOF'
{ {
"mcpServers": { "github": {
"github": { "command": "docker",
"command": "docker", "args": [
"args": [ "run",
"run", "-i",
"-i", "--rm",
"--rm", "-e",
"-e", "GITHUB_PERSONAL_ACCESS_TOKEN",
"GITHUB_PERSONAL_ACCESS_TOKEN", "ghcr.io/github/github-mcp-server:sha-7aced2b"
"ghcr.io/github/github-mcp-server:sha-7aced2b" ],
], "env": {
"env": { "GITHUB_PERSONAL_ACCESS_TOKEN": "${{ secrets.GITHUB_TOKEN }}"
"GITHUB_PERSONAL_ACCESS_TOKEN": "${{ secrets.GITHUB_TOKEN }}"
}
} }
} }
} }

View File

@@ -83,14 +83,14 @@ runs:
- name: Install Dependencies - name: Install Dependencies
shell: bash shell: bash
run: | run: |
cd ${GITHUB_ACTION_PATH} cd ${{ github.action_path }}
bun install bun install
- name: Prepare action - name: Prepare action
id: prepare id: prepare
shell: bash shell: bash
run: | run: |
bun run ${GITHUB_ACTION_PATH}/src/entrypoints/prepare.ts bun run ${{ github.action_path }}/src/entrypoints/prepare.ts
env: env:
TRIGGER_PHRASE: ${{ inputs.trigger_phrase }} TRIGGER_PHRASE: ${{ inputs.trigger_phrase }}
ASSIGNEE_TRIGGER: ${{ inputs.assignee_trigger }} ASSIGNEE_TRIGGER: ${{ inputs.assignee_trigger }}
@@ -105,9 +105,9 @@ runs:
- name: Run Claude Code - name: Run Claude Code
id: claude-code id: claude-code
if: steps.prepare.outputs.contains_trigger == 'true' if: steps.prepare.outputs.contains_trigger == 'true'
uses: anthropics/claude-code-base-action@79b8cfc932eb13806c23905842145e6f05c89e2e # v0.0.13 uses: anthropics/claude-code-base-action@c8e31bd52d9a149b3f8309d7978c6edaa282688d # v0.0.8
with: with:
prompt_file: ${{ runner.temp }}/claude-prompts/claude-prompt.txt prompt_file: /tmp/claude-prompts/claude-prompt.txt
allowed_tools: ${{ env.ALLOWED_TOOLS }} allowed_tools: ${{ env.ALLOWED_TOOLS }}
disallowed_tools: ${{ env.DISALLOWED_TOOLS }} disallowed_tools: ${{ env.DISALLOWED_TOOLS }}
timeout_minutes: ${{ inputs.timeout_minutes }} timeout_minutes: ${{ inputs.timeout_minutes }}
@@ -147,7 +147,7 @@ runs:
if: steps.prepare.outputs.contains_trigger == 'true' && steps.prepare.outputs.claude_comment_id && always() if: steps.prepare.outputs.contains_trigger == 'true' && steps.prepare.outputs.claude_comment_id && always()
shell: bash shell: bash
run: | run: |
bun run ${GITHUB_ACTION_PATH}/src/entrypoints/update-comment-link.ts bun run ${{ github.action_path }}/src/entrypoints/update-comment-link.ts
env: env:
REPOSITORY: ${{ github.repository }} REPOSITORY: ${{ github.repository }}
PR_NUMBER: ${{ github.event.issue.number || github.event.pull_request.number }} PR_NUMBER: ${{ github.event.issue.number || github.event.pull_request.number }}

View File

@@ -2,7 +2,7 @@
"lockfileVersion": 1, "lockfileVersion": 1,
"workspaces": { "workspaces": {
"": { "": {
"name": "@anthropic-ai/claude-code-action", "name": "claude-pr-action",
"dependencies": { "dependencies": {
"@actions/core": "^1.10.1", "@actions/core": "^1.10.1",
"@actions/github": "^6.0.1", "@actions/github": "^6.0.1",

View File

@@ -1,5 +1,5 @@
{ {
"name": "@anthropic-ai/claude-code-action", "name": "claude-pr-action",
"version": "1.0.0", "version": "1.0.0",
"private": true, "private": true,
"scripts": { "scripts": {

View File

@@ -35,35 +35,38 @@ const BASE_ALLOWED_TOOLS = [
]; ];
const DISALLOWED_TOOLS = ["WebSearch", "WebFetch"]; const DISALLOWED_TOOLS = ["WebSearch", "WebFetch"];
export function buildAllowedToolsString(customAllowedTools?: string[]): string { export function buildAllowedToolsString(customAllowedTools?: string): string {
let baseTools = [...BASE_ALLOWED_TOOLS]; let baseTools = [...BASE_ALLOWED_TOOLS];
let allAllowedTools = baseTools.join(","); let allAllowedTools = baseTools.join(",");
if (customAllowedTools && customAllowedTools.length > 0) { if (customAllowedTools) {
allAllowedTools = `${allAllowedTools},${customAllowedTools.join(",")}`; allAllowedTools = `${allAllowedTools},${customAllowedTools}`;
} }
return allAllowedTools; return allAllowedTools;
} }
export function buildDisallowedToolsString( export function buildDisallowedToolsString(
customDisallowedTools?: string[], customDisallowedTools?: string,
allowedTools?: string[], allowedTools?: string,
): string { ): string {
let disallowedTools = [...DISALLOWED_TOOLS]; let disallowedTools = [...DISALLOWED_TOOLS];
// If user has explicitly allowed some hardcoded disallowed tools, remove them from disallowed list // If user has explicitly allowed some hardcoded disallowed tools, remove them from disallowed list
if (allowedTools && allowedTools.length > 0) { if (allowedTools) {
const allowedToolsArray = allowedTools
.split(",")
.map((tool) => tool.trim());
disallowedTools = disallowedTools.filter( disallowedTools = disallowedTools.filter(
(tool) => !allowedTools.includes(tool), (tool) => !allowedToolsArray.includes(tool),
); );
} }
let allDisallowedTools = disallowedTools.join(","); let allDisallowedTools = disallowedTools.join(",");
if (customDisallowedTools && customDisallowedTools.length > 0) { if (customDisallowedTools) {
if (allDisallowedTools) { if (allDisallowedTools) {
allDisallowedTools = `${allDisallowedTools},${customDisallowedTools.join(",")}`; allDisallowedTools = `${allDisallowedTools},${customDisallowedTools}`;
} else { } else {
allDisallowedTools = customDisallowedTools.join(","); allDisallowedTools = customDisallowedTools;
} }
} }
return allDisallowedTools; return allDisallowedTools;
@@ -117,10 +120,8 @@ export function prepareContext(
triggerPhrase, triggerPhrase,
...(triggerUsername && { triggerUsername }), ...(triggerUsername && { triggerUsername }),
...(customInstructions && { customInstructions }), ...(customInstructions && { customInstructions }),
...(allowedTools.length > 0 && { allowedTools: allowedTools.join(",") }), ...(allowedTools && { allowedTools }),
...(disallowedTools.length > 0 && { ...(disallowedTools && { disallowedTools }),
disallowedTools: disallowedTools.join(","),
}),
...(directPrompt && { directPrompt }), ...(directPrompt && { directPrompt }),
...(claudeBranch && { claudeBranch }), ...(claudeBranch && { claudeBranch }),
}; };
@@ -620,9 +621,7 @@ export async function createPrompt(
claudeBranch, claudeBranch,
); );
await mkdir(`${process.env.RUNNER_TEMP}/claude-prompts`, { await mkdir("/tmp/claude-prompts", { recursive: true });
recursive: true,
});
// Generate the prompt // Generate the prompt
const promptContent = generatePrompt(preparedContext, githubData); const promptContent = generatePrompt(preparedContext, githubData);
@@ -633,18 +632,15 @@ export async function createPrompt(
console.log("======================="); console.log("=======================");
// Write the prompt file // Write the prompt file
await writeFile( await writeFile("/tmp/claude-prompts/claude-prompt.txt", promptContent);
`${process.env.RUNNER_TEMP}/claude-prompts/claude-prompt.txt`,
promptContent,
);
// Set allowed tools // Set allowed tools
const allAllowedTools = buildAllowedToolsString( const allAllowedTools = buildAllowedToolsString(
context.inputs.allowedTools, preparedContext.allowedTools,
); );
const allDisallowedTools = buildDisallowedToolsString( const allDisallowedTools = buildDisallowedToolsString(
context.inputs.disallowedTools, preparedContext.disallowedTools,
context.inputs.allowedTools, preparedContext.allowedTools,
); );
core.exportVariable("ALLOWED_TOOLS", allAllowedTools); core.exportVariable("ALLOWED_TOOLS", allAllowedTools);

View File

@@ -92,7 +92,6 @@ async function run() {
branch: branchInfo.currentBranch, branch: branchInfo.currentBranch,
additionalMcpConfig, additionalMcpConfig,
claudeCommentId: commentId.toString(), claudeCommentId: commentId.toString(),
allowedTools: context.inputs.allowedTools,
}); });
core.setOutput("mcp_config", mcpConfig); core.setOutput("mcp_config", mcpConfig);
} catch (error) { } catch (error) {

View File

@@ -28,8 +28,8 @@ export type ParsedGitHubContext = {
inputs: { inputs: {
triggerPhrase: string; triggerPhrase: string;
assigneeTrigger: string; assigneeTrigger: string;
allowedTools: string[]; allowedTools: string;
disallowedTools: string[]; disallowedTools: string;
customInstructions: string; customInstructions: string;
directPrompt: string; directPrompt: string;
baseBranch?: string; baseBranch?: string;
@@ -52,14 +52,8 @@ export function parseGitHubContext(): ParsedGitHubContext {
inputs: { inputs: {
triggerPhrase: process.env.TRIGGER_PHRASE ?? "@claude", triggerPhrase: process.env.TRIGGER_PHRASE ?? "@claude",
assigneeTrigger: process.env.ASSIGNEE_TRIGGER ?? "", assigneeTrigger: process.env.ASSIGNEE_TRIGGER ?? "",
allowedTools: (process.env.ALLOWED_TOOLS ?? "") allowedTools: process.env.ALLOWED_TOOLS ?? "",
.split(",") disallowedTools: process.env.DISALLOWED_TOOLS ?? "",
.map((tool) => tool.trim())
.filter((tool) => tool.length > 0),
disallowedTools: (process.env.DISALLOWED_TOOLS ?? "")
.split(",")
.map((tool) => tool.trim())
.filter((tool) => tool.length > 0),
customInstructions: process.env.CUSTOM_INSTRUCTIONS ?? "", customInstructions: process.env.CUSTOM_INSTRUCTIONS ?? "",
directPrompt: process.env.DIRECT_PROMPT ?? "", directPrompt: process.env.DIRECT_PROMPT ?? "",
baseBranch: process.env.BASE_BRANCH, baseBranch: process.env.BASE_BRANCH,

View File

@@ -1,17 +1,17 @@
import { execSync } from "child_process"; import { execSync } from "child_process";
import type { Octokits } from "../api/client";
import { ISSUE_QUERY, PR_QUERY } from "../api/queries/github";
import type { import type {
GitHubPullRequest,
GitHubIssue,
GitHubComment, GitHubComment,
GitHubFile, GitHubFile,
GitHubIssue,
GitHubPullRequest,
GitHubReview, GitHubReview,
IssueQueryResponse,
PullRequestQueryResponse, PullRequestQueryResponse,
IssueQueryResponse,
} from "../types"; } from "../types";
import type { CommentWithImages } from "../utils/image-downloader"; import { PR_QUERY, ISSUE_QUERY } from "../api/queries/github";
import type { Octokits } from "../api/client";
import { downloadCommentImages } from "../utils/image-downloader"; import { downloadCommentImages } from "../utils/image-downloader";
import type { CommentWithImages } from "../utils/image-downloader";
type FetchDataParams = { type FetchDataParams = {
octokits: Octokits; octokits: Octokits;
@@ -101,14 +101,6 @@ export async function fetchGitHubData({
let changedFilesWithSHA: GitHubFileWithSHA[] = []; let changedFilesWithSHA: GitHubFileWithSHA[] = [];
if (isPR && changedFiles.length > 0) { if (isPR && changedFiles.length > 0) {
changedFilesWithSHA = changedFiles.map((file) => { changedFilesWithSHA = changedFiles.map((file) => {
// Don't compute SHA for deleted files
if (file.changeType === "DELETED") {
return {
...file,
sha: "deleted",
};
}
try { try {
// Use git hash-object to compute the SHA for the current file content // Use git hash-object to compute the SHA for the current file content
const sha = execSync(`git hash-object "${file.path}"`, { const sha = execSync(`git hash-object "${file.path}"`, {

View File

@@ -7,7 +7,6 @@ type PrepareConfigParams = {
branch: string; branch: string;
additionalMcpConfig?: string; additionalMcpConfig?: string;
claudeCommentId?: string; claudeCommentId?: string;
allowedTools: string[];
}; };
export async function prepareMcpConfig( export async function prepareMcpConfig(
@@ -20,17 +19,24 @@ export async function prepareMcpConfig(
branch, branch,
additionalMcpConfig, additionalMcpConfig,
claudeCommentId, claudeCommentId,
allowedTools,
} = params; } = params;
try { try {
const allowedToolsList = allowedTools || []; const baseMcpConfig = {
const hasGitHubMcpTools = allowedToolsList.some((tool) =>
tool.startsWith("mcp__github__"),
);
const baseMcpConfig: { mcpServers: Record<string, unknown> } = {
mcpServers: { mcpServers: {
github: {
command: "docker",
args: [
"run",
"-i",
"--rm",
"-e",
"GITHUB_PERSONAL_ACCESS_TOKEN",
"ghcr.io/anthropics/github-mcp-server:sha-7382253",
],
env: {
GITHUB_PERSONAL_ACCESS_TOKEN: githubToken,
},
},
github_file_ops: { github_file_ops: {
command: "bun", command: "bun",
args: [ args: [
@@ -51,23 +57,6 @@ export async function prepareMcpConfig(
}, },
}; };
if (hasGitHubMcpTools) {
baseMcpConfig.mcpServers.github = {
command: "docker",
args: [
"run",
"-i",
"--rm",
"-e",
"GITHUB_PERSONAL_ACCESS_TOKEN",
"ghcr.io/github/github-mcp-server:sha-e9f748f", // https://github.com/github/github-mcp-server/releases/tag/v0.4.0
],
env: {
GITHUB_PERSONAL_ACCESS_TOKEN: githubToken,
},
};
}
// Merge with additional MCP config if provided // Merge with additional MCP config if provided
if (additionalMcpConfig && additionalMcpConfig.trim()) { if (additionalMcpConfig && additionalMcpConfig.trim()) {
try { try {

View File

@@ -652,7 +652,7 @@ describe("buildAllowedToolsString", () => {
}); });
test("should append custom tools when provided", () => { test("should append custom tools when provided", () => {
const customTools = ["Tool1", "Tool2", "Tool3"]; const customTools = "Tool1,Tool2,Tool3";
const result = buildAllowedToolsString(customTools); const result = buildAllowedToolsString(customTools);
// Base tools should be present // Base tools should be present
@@ -683,7 +683,7 @@ describe("buildDisallowedToolsString", () => {
}); });
test("should append custom disallowed tools when provided", () => { test("should append custom disallowed tools when provided", () => {
const customDisallowedTools = ["BadTool1", "BadTool2"]; const customDisallowedTools = "BadTool1,BadTool2";
const result = buildDisallowedToolsString(customDisallowedTools); const result = buildDisallowedToolsString(customDisallowedTools);
// Base disallowed tools should be present // Base disallowed tools should be present
@@ -701,8 +701,8 @@ describe("buildDisallowedToolsString", () => {
}); });
test("should remove hardcoded disallowed tools if they are in allowed tools", () => { test("should remove hardcoded disallowed tools if they are in allowed tools", () => {
const customDisallowedTools = ["BadTool1", "BadTool2"]; const customDisallowedTools = "BadTool1,BadTool2";
const allowedTools = ["WebSearch", "SomeOtherTool"]; const allowedTools = "WebSearch,SomeOtherTool";
const result = buildDisallowedToolsString( const result = buildDisallowedToolsString(
customDisallowedTools, customDisallowedTools,
allowedTools, allowedTools,
@@ -720,7 +720,7 @@ describe("buildDisallowedToolsString", () => {
}); });
test("should remove all hardcoded disallowed tools if they are all in allowed tools", () => { test("should remove all hardcoded disallowed tools if they are all in allowed tools", () => {
const allowedTools = ["WebSearch", "WebFetch", "SomeOtherTool"]; const allowedTools = "WebSearch,WebFetch,SomeOtherTool";
const result = buildDisallowedToolsString(undefined, allowedTools); const result = buildDisallowedToolsString(undefined, allowedTools);
// Both hardcoded disallowed tools should be removed // Both hardcoded disallowed tools should be removed
@@ -732,8 +732,8 @@ describe("buildDisallowedToolsString", () => {
}); });
test("should handle custom disallowed tools when all hardcoded tools are overridden", () => { test("should handle custom disallowed tools when all hardcoded tools are overridden", () => {
const customDisallowedTools = ["BadTool1", "BadTool2"]; const customDisallowedTools = "BadTool1,BadTool2";
const allowedTools = ["WebSearch", "WebFetch"]; const allowedTools = "WebSearch,WebFetch";
const result = buildDisallowedToolsString( const result = buildDisallowedToolsString(
customDisallowedTools, customDisallowedTools,
allowedTools, allowedTools,

View File

@@ -24,19 +24,21 @@ describe("prepareMcpConfig", () => {
processExitSpy.mockRestore(); processExitSpy.mockRestore();
}); });
test("should return base config when no additional config is provided and no allowed_tools", async () => { test("should return base config when no additional config is provided", async () => {
const result = await prepareMcpConfig({ const result = await prepareMcpConfig({
githubToken: "test-token", githubToken: "test-token",
owner: "test-owner", owner: "test-owner",
repo: "test-repo", repo: "test-repo",
branch: "test-branch", branch: "test-branch",
allowedTools: [],
}); });
const parsed = JSON.parse(result); const parsed = JSON.parse(result);
expect(parsed.mcpServers).toBeDefined(); expect(parsed.mcpServers).toBeDefined();
expect(parsed.mcpServers.github).not.toBeDefined(); expect(parsed.mcpServers.github).toBeDefined();
expect(parsed.mcpServers.github_file_ops).toBeDefined(); expect(parsed.mcpServers.github_file_ops).toBeDefined();
expect(parsed.mcpServers.github.env.GITHUB_PERSONAL_ACCESS_TOKEN).toBe(
"test-token",
);
expect(parsed.mcpServers.github_file_ops.env.GITHUB_TOKEN).toBe( expect(parsed.mcpServers.github_file_ops.env.GITHUB_TOKEN).toBe(
"test-token", "test-token",
); );
@@ -47,60 +49,6 @@ describe("prepareMcpConfig", () => {
); );
}); });
test("should include github MCP server when mcp__github__ tools are allowed", async () => {
const result = await prepareMcpConfig({
githubToken: "test-token",
owner: "test-owner",
repo: "test-repo",
branch: "test-branch",
allowedTools: [
"mcp__github__create_issue",
"mcp__github_file_ops__commit_files",
],
});
const parsed = JSON.parse(result);
expect(parsed.mcpServers).toBeDefined();
expect(parsed.mcpServers.github).toBeDefined();
expect(parsed.mcpServers.github_file_ops).toBeDefined();
expect(parsed.mcpServers.github.env.GITHUB_PERSONAL_ACCESS_TOKEN).toBe(
"test-token",
);
});
test("should not include github MCP server when only file_ops tools are allowed", async () => {
const result = await prepareMcpConfig({
githubToken: "test-token",
owner: "test-owner",
repo: "test-repo",
branch: "test-branch",
allowedTools: [
"mcp__github_file_ops__commit_files",
"mcp__github_file_ops__update_claude_comment",
],
});
const parsed = JSON.parse(result);
expect(parsed.mcpServers).toBeDefined();
expect(parsed.mcpServers.github).not.toBeDefined();
expect(parsed.mcpServers.github_file_ops).toBeDefined();
});
test("should include file_ops server even when no GitHub tools are allowed", async () => {
const result = await prepareMcpConfig({
githubToken: "test-token",
owner: "test-owner",
repo: "test-repo",
branch: "test-branch",
allowedTools: ["Edit", "Read", "Write"],
});
const parsed = JSON.parse(result);
expect(parsed.mcpServers).toBeDefined();
expect(parsed.mcpServers.github).not.toBeDefined();
expect(parsed.mcpServers.github_file_ops).toBeDefined();
});
test("should return base config when additional config is empty string", async () => { test("should return base config when additional config is empty string", async () => {
const result = await prepareMcpConfig({ const result = await prepareMcpConfig({
githubToken: "test-token", githubToken: "test-token",
@@ -108,12 +56,11 @@ describe("prepareMcpConfig", () => {
repo: "test-repo", repo: "test-repo",
branch: "test-branch", branch: "test-branch",
additionalMcpConfig: "", additionalMcpConfig: "",
allowedTools: [],
}); });
const parsed = JSON.parse(result); const parsed = JSON.parse(result);
expect(parsed.mcpServers).toBeDefined(); expect(parsed.mcpServers).toBeDefined();
expect(parsed.mcpServers.github).not.toBeDefined(); expect(parsed.mcpServers.github).toBeDefined();
expect(parsed.mcpServers.github_file_ops).toBeDefined(); expect(parsed.mcpServers.github_file_ops).toBeDefined();
expect(consoleWarningSpy).not.toHaveBeenCalled(); expect(consoleWarningSpy).not.toHaveBeenCalled();
}); });
@@ -125,12 +72,11 @@ describe("prepareMcpConfig", () => {
repo: "test-repo", repo: "test-repo",
branch: "test-branch", branch: "test-branch",
additionalMcpConfig: " \n\t ", additionalMcpConfig: " \n\t ",
allowedTools: [],
}); });
const parsed = JSON.parse(result); const parsed = JSON.parse(result);
expect(parsed.mcpServers).toBeDefined(); expect(parsed.mcpServers).toBeDefined();
expect(parsed.mcpServers.github).not.toBeDefined(); expect(parsed.mcpServers.github).toBeDefined();
expect(parsed.mcpServers.github_file_ops).toBeDefined(); expect(parsed.mcpServers.github_file_ops).toBeDefined();
expect(consoleWarningSpy).not.toHaveBeenCalled(); expect(consoleWarningSpy).not.toHaveBeenCalled();
}); });
@@ -154,10 +100,6 @@ describe("prepareMcpConfig", () => {
repo: "test-repo", repo: "test-repo",
branch: "test-branch", branch: "test-branch",
additionalMcpConfig: additionalConfig, additionalMcpConfig: additionalConfig,
allowedTools: [
"mcp__github__create_issue",
"mcp__github_file_ops__commit_files",
],
}); });
const parsed = JSON.parse(result); const parsed = JSON.parse(result);
@@ -191,10 +133,6 @@ describe("prepareMcpConfig", () => {
repo: "test-repo", repo: "test-repo",
branch: "test-branch", branch: "test-branch",
additionalMcpConfig: additionalConfig, additionalMcpConfig: additionalConfig,
allowedTools: [
"mcp__github__create_issue",
"mcp__github_file_ops__commit_files",
],
}); });
const parsed = JSON.parse(result); const parsed = JSON.parse(result);
@@ -231,13 +169,12 @@ describe("prepareMcpConfig", () => {
repo: "test-repo", repo: "test-repo",
branch: "test-branch", branch: "test-branch",
additionalMcpConfig: additionalConfig, additionalMcpConfig: additionalConfig,
allowedTools: [],
}); });
const parsed = JSON.parse(result); const parsed = JSON.parse(result);
expect(parsed.customProperty).toBe("custom-value"); expect(parsed.customProperty).toBe("custom-value");
expect(parsed.anotherProperty).toEqual({ nested: "value" }); expect(parsed.anotherProperty).toEqual({ nested: "value" });
expect(parsed.mcpServers.github).not.toBeDefined(); expect(parsed.mcpServers.github).toBeDefined();
expect(parsed.mcpServers.custom_server).toBeDefined(); expect(parsed.mcpServers.custom_server).toBeDefined();
}); });
@@ -250,14 +187,13 @@ describe("prepareMcpConfig", () => {
repo: "test-repo", repo: "test-repo",
branch: "test-branch", branch: "test-branch",
additionalMcpConfig: invalidJson, additionalMcpConfig: invalidJson,
allowedTools: [],
}); });
const parsed = JSON.parse(result); const parsed = JSON.parse(result);
expect(consoleWarningSpy).toHaveBeenCalledWith( expect(consoleWarningSpy).toHaveBeenCalledWith(
expect.stringContaining("Failed to parse additional MCP config:"), expect.stringContaining("Failed to parse additional MCP config:"),
); );
expect(parsed.mcpServers.github).not.toBeDefined(); expect(parsed.mcpServers.github).toBeDefined();
expect(parsed.mcpServers.github_file_ops).toBeDefined(); expect(parsed.mcpServers.github_file_ops).toBeDefined();
}); });
@@ -270,7 +206,6 @@ describe("prepareMcpConfig", () => {
repo: "test-repo", repo: "test-repo",
branch: "test-branch", branch: "test-branch",
additionalMcpConfig: nonObjectJson, additionalMcpConfig: nonObjectJson,
allowedTools: [],
}); });
const parsed = JSON.parse(result); const parsed = JSON.parse(result);
@@ -280,7 +215,7 @@ describe("prepareMcpConfig", () => {
expect(consoleWarningSpy).toHaveBeenCalledWith( expect(consoleWarningSpy).toHaveBeenCalledWith(
expect.stringContaining("MCP config must be a valid JSON object"), expect.stringContaining("MCP config must be a valid JSON object"),
); );
expect(parsed.mcpServers.github).not.toBeDefined(); expect(parsed.mcpServers.github).toBeDefined();
expect(parsed.mcpServers.github_file_ops).toBeDefined(); expect(parsed.mcpServers.github_file_ops).toBeDefined();
}); });
@@ -293,7 +228,6 @@ describe("prepareMcpConfig", () => {
repo: "test-repo", repo: "test-repo",
branch: "test-branch", branch: "test-branch",
additionalMcpConfig: nullJson, additionalMcpConfig: nullJson,
allowedTools: [],
}); });
const parsed = JSON.parse(result); const parsed = JSON.parse(result);
@@ -303,7 +237,7 @@ describe("prepareMcpConfig", () => {
expect(consoleWarningSpy).toHaveBeenCalledWith( expect(consoleWarningSpy).toHaveBeenCalledWith(
expect.stringContaining("MCP config must be a valid JSON object"), expect.stringContaining("MCP config must be a valid JSON object"),
); );
expect(parsed.mcpServers.github).not.toBeDefined(); expect(parsed.mcpServers.github).toBeDefined();
expect(parsed.mcpServers.github_file_ops).toBeDefined(); expect(parsed.mcpServers.github_file_ops).toBeDefined();
}); });
@@ -316,7 +250,6 @@ describe("prepareMcpConfig", () => {
repo: "test-repo", repo: "test-repo",
branch: "test-branch", branch: "test-branch",
additionalMcpConfig: arrayJson, additionalMcpConfig: arrayJson,
allowedTools: [],
}); });
const parsed = JSON.parse(result); const parsed = JSON.parse(result);
@@ -325,7 +258,7 @@ describe("prepareMcpConfig", () => {
expect(consoleInfoSpy).toHaveBeenCalledWith( expect(consoleInfoSpy).toHaveBeenCalledWith(
"Merging additional MCP server configuration with built-in servers", "Merging additional MCP server configuration with built-in servers",
); );
expect(parsed.mcpServers.github).not.toBeDefined(); expect(parsed.mcpServers.github).toBeDefined();
expect(parsed.mcpServers.github_file_ops).toBeDefined(); expect(parsed.mcpServers.github_file_ops).toBeDefined();
// The array will be spread into the config (0: 1, 1: 2, 2: 3) // The array will be spread into the config (0: 1, 1: 2, 2: 3)
expect(parsed[0]).toBe(1); expect(parsed[0]).toBe(1);
@@ -362,13 +295,12 @@ describe("prepareMcpConfig", () => {
repo: "test-repo", repo: "test-repo",
branch: "test-branch", branch: "test-branch",
additionalMcpConfig: additionalConfig, additionalMcpConfig: additionalConfig,
allowedTools: [],
}); });
const parsed = JSON.parse(result); const parsed = JSON.parse(result);
expect(parsed.mcpServers.server1).toBeDefined(); expect(parsed.mcpServers.server1).toBeDefined();
expect(parsed.mcpServers.server2).toBeDefined(); expect(parsed.mcpServers.server2).toBeDefined();
expect(parsed.mcpServers.github).not.toBeDefined(); expect(parsed.mcpServers.github).toBeDefined();
expect(parsed.mcpServers.github_file_ops.command).toBe("overridden"); expect(parsed.mcpServers.github_file_ops.command).toBe("overridden");
expect(parsed.mcpServers.github_file_ops.env.CUSTOM).toBe("value"); expect(parsed.mcpServers.github_file_ops.env.CUSTOM).toBe("value");
expect(parsed.otherConfig.nested.deeply).toBe("value"); expect(parsed.otherConfig.nested.deeply).toBe("value");
@@ -383,7 +315,6 @@ describe("prepareMcpConfig", () => {
owner: "test-owner", owner: "test-owner",
repo: "test-repo", repo: "test-repo",
branch: "test-branch", branch: "test-branch",
allowedTools: [],
}); });
const parsed = JSON.parse(result); const parsed = JSON.parse(result);
@@ -403,7 +334,6 @@ describe("prepareMcpConfig", () => {
owner: "test-owner", owner: "test-owner",
repo: "test-repo", repo: "test-repo",
branch: "test-branch", branch: "test-branch",
allowedTools: [],
}); });
const parsed = JSON.parse(result); const parsed = JSON.parse(result);

View File

@@ -11,8 +11,8 @@ const defaultInputs = {
triggerPhrase: "/claude", triggerPhrase: "/claude",
assigneeTrigger: "", assigneeTrigger: "",
anthropicModel: "claude-3-7-sonnet-20250219", anthropicModel: "claude-3-7-sonnet-20250219",
allowedTools: [] as string[], allowedTools: "",
disallowedTools: [] as string[], disallowedTools: "",
customInstructions: "", customInstructions: "",
directPrompt: "", directPrompt: "",
useBedrock: false, useBedrock: false,

View File

@@ -62,8 +62,8 @@ describe("checkWritePermissions", () => {
inputs: { inputs: {
triggerPhrase: "@claude", triggerPhrase: "@claude",
assigneeTrigger: "", assigneeTrigger: "",
allowedTools: [], allowedTools: "",
disallowedTools: [], disallowedTools: "",
customInstructions: "", customInstructions: "",
directPrompt: "", directPrompt: "",
}, },

View File

@@ -242,7 +242,7 @@ describe("parseEnvVarsWithContext", () => {
...mockPullRequestCommentContext, ...mockPullRequestCommentContext,
inputs: { inputs: {
...mockPullRequestCommentContext.inputs, ...mockPullRequestCommentContext.inputs,
allowedTools: ["Tool1", "Tool2"], allowedTools: "Tool1,Tool2",
}, },
}); });
const result = prepareContext(contextWithAllowedTools, "12345"); const result = prepareContext(contextWithAllowedTools, "12345");

View File

@@ -30,8 +30,8 @@ describe("checkContainsTrigger", () => {
triggerPhrase: "/claude", triggerPhrase: "/claude",
assigneeTrigger: "", assigneeTrigger: "",
directPrompt: "Fix the bug in the login form", directPrompt: "Fix the bug in the login form",
allowedTools: [], allowedTools: "",
disallowedTools: [], disallowedTools: "",
customInstructions: "", customInstructions: "",
}, },
}); });
@@ -56,8 +56,8 @@ describe("checkContainsTrigger", () => {
triggerPhrase: "/claude", triggerPhrase: "/claude",
assigneeTrigger: "", assigneeTrigger: "",
directPrompt: "", directPrompt: "",
allowedTools: [], allowedTools: "",
disallowedTools: [], disallowedTools: "",
customInstructions: "", customInstructions: "",
}, },
}); });
@@ -228,8 +228,8 @@ describe("checkContainsTrigger", () => {
triggerPhrase: "@claude", triggerPhrase: "@claude",
assigneeTrigger: "", assigneeTrigger: "",
directPrompt: "", directPrompt: "",
allowedTools: [], allowedTools: "",
disallowedTools: [], disallowedTools: "",
customInstructions: "", customInstructions: "",
}, },
}); });
@@ -255,8 +255,8 @@ describe("checkContainsTrigger", () => {
triggerPhrase: "@claude", triggerPhrase: "@claude",
assigneeTrigger: "", assigneeTrigger: "",
directPrompt: "", directPrompt: "",
allowedTools: [], allowedTools: "",
disallowedTools: [], disallowedTools: "",
customInstructions: "", customInstructions: "",
}, },
}); });
@@ -282,8 +282,8 @@ describe("checkContainsTrigger", () => {
triggerPhrase: "@claude", triggerPhrase: "@claude",
assigneeTrigger: "", assigneeTrigger: "",
directPrompt: "", directPrompt: "",
allowedTools: [], allowedTools: "",
disallowedTools: [], disallowedTools: "",
customInstructions: "", customInstructions: "",
}, },
}); });