Compare commits

...

5 Commits

Author SHA1 Message Date
Claude
80591ffc11 fix: prevent path traversal in delete_files MCP tool
The delete_files tool only validated absolute paths starting with "/",
allowing relative paths with traversal sequences like "./../../sensitive"
to bypass validation.

Now all paths are normalized using path.resolve() before validation,
ensuring both absolute and relative paths with ".." sequences are
properly blocked from accessing files outside the repository root.
2025-12-12 00:14:12 +00:00
GitHub Actions
f0c8eb2980 chore: bump Claude Code version to 2.0.62 2025-12-09 02:12:14 +00:00
ant-soumitr
68a0348c20 fix: Replace direct template expansion of inputs in shell scripts with environment variables (#729)
Replace direct template expansion of user inputs in shell scripts with
environment variables to prevent potential command injection attacks.

Changes:
- sync-base-action.yml: Use $GITHUB_EVENT_NAME and $GITHUB_ACTOR instead of template expansion
- action.yml: Pass path_to_bun_executable and path_to_claude_code_executable through env vars
- base-action/action.yml: Same env var changes for path inputs

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

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-08 12:08:44 -08:00
GitHub Actions
dc06a34646 chore: bump Claude Code version to 2.0.61 2025-12-07 10:47:47 +00:00
Ashwin Bhat
a3bb51dac1 Fix SDK path: add settingSources and default system prompt (#726)
Two fixes for the Agent SDK path (USE_AGENT_SDK=true):

1. Add settingSources to load filesystem settings
   - Without this, CLI-installed plugins aren't available to the SDK
   - Also needed to load CLAUDE.md files from the project

2. Default systemPrompt to claude_code preset
   - Without an explicit systemPrompt, the SDK would use no system prompt
   - Now defaults to { type: "preset", preset: "claude_code" } to match CLI behavior

Also adds logging of SDK options (excluding env) for debugging.

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

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-06 16:52:26 -08:00
6 changed files with 48 additions and 27 deletions

View File

@@ -94,5 +94,5 @@ jobs:
echo "✅ Successfully synced \`base-action\` directory to [anthropics/claude-code-base-action](https://github.com/anthropics/claude-code-base-action)" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "- **Source commit**: [\`${GITHUB_SHA:0:7}\`](https://github.com/anthropics/claude-code-action/commit/${GITHUB_SHA})" >> $GITHUB_STEP_SUMMARY
echo "- **Triggered by**: ${{ github.event_name }}" >> $GITHUB_STEP_SUMMARY
echo "- **Actor**: @${{ github.actor }}" >> $GITHUB_STEP_SUMMARY
echo "- **Triggered by**: $GITHUB_EVENT_NAME" >> $GITHUB_STEP_SUMMARY
echo "- **Actor**: @$GITHUB_ACTOR" >> $GITHUB_STEP_SUMMARY

View File

@@ -140,10 +140,12 @@ runs:
- name: Setup Custom Bun Path
if: inputs.path_to_bun_executable != ''
shell: bash
env:
PATH_TO_BUN_EXECUTABLE: ${{ inputs.path_to_bun_executable }}
run: |
echo "Using custom Bun executable: ${{ inputs.path_to_bun_executable }}"
echo "Using custom Bun executable: $PATH_TO_BUN_EXECUTABLE"
# Add the directory containing the custom executable to PATH
BUN_DIR=$(dirname "${{ inputs.path_to_bun_executable }}")
BUN_DIR=$(dirname "$PATH_TO_BUN_EXECUTABLE")
echo "$BUN_DIR" >> "$GITHUB_PATH"
- name: Install Dependencies
@@ -182,6 +184,8 @@ runs:
- name: Install Base Action Dependencies
if: steps.prepare.outputs.contains_trigger == 'true'
shell: bash
env:
PATH_TO_CLAUDE_CODE_EXECUTABLE: ${{ inputs.path_to_claude_code_executable }}
run: |
echo "Installing base-action dependencies..."
cd ${GITHUB_ACTION_PATH}/base-action
@@ -190,8 +194,8 @@ runs:
cd -
# Install Claude Code if no custom executable is provided
if [ -z "${{ inputs.path_to_claude_code_executable }}" ]; then
CLAUDE_CODE_VERSION="2.0.60"
if [ -z "$PATH_TO_CLAUDE_CODE_EXECUTABLE" ]; then
CLAUDE_CODE_VERSION="2.0.62"
echo "Installing Claude Code v${CLAUDE_CODE_VERSION}..."
for attempt in 1 2 3; do
echo "Installation attempt $attempt..."
@@ -210,9 +214,9 @@ runs:
echo "Claude Code installed successfully"
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
else
echo "Using custom Claude Code executable: ${{ inputs.path_to_claude_code_executable }}"
echo "Using custom Claude Code executable: $PATH_TO_CLAUDE_CODE_EXECUTABLE"
# Add the directory containing the custom executable to PATH
CLAUDE_DIR=$(dirname "${{ inputs.path_to_claude_code_executable }}")
CLAUDE_DIR=$(dirname "$PATH_TO_CLAUDE_CODE_EXECUTABLE")
echo "$CLAUDE_DIR" >> "$GITHUB_PATH"
fi

View File

@@ -101,10 +101,12 @@ runs:
- name: Setup Custom Bun Path
if: inputs.path_to_bun_executable != ''
shell: bash
env:
PATH_TO_BUN_EXECUTABLE: ${{ inputs.path_to_bun_executable }}
run: |
echo "Using custom Bun executable: ${{ inputs.path_to_bun_executable }}"
echo "Using custom Bun executable: $PATH_TO_BUN_EXECUTABLE"
# Add the directory containing the custom executable to PATH
BUN_DIR=$(dirname "${{ inputs.path_to_bun_executable }}")
BUN_DIR=$(dirname "$PATH_TO_BUN_EXECUTABLE")
echo "$BUN_DIR" >> "$GITHUB_PATH"
- name: Install Dependencies
@@ -115,9 +117,11 @@ runs:
- name: Install Claude Code
shell: bash
env:
PATH_TO_CLAUDE_CODE_EXECUTABLE: ${{ inputs.path_to_claude_code_executable }}
run: |
if [ -z "${{ inputs.path_to_claude_code_executable }}" ]; then
CLAUDE_CODE_VERSION="2.0.60"
if [ -z "$PATH_TO_CLAUDE_CODE_EXECUTABLE" ]; then
CLAUDE_CODE_VERSION="2.0.62"
echo "Installing Claude Code v${CLAUDE_CODE_VERSION}..."
for attempt in 1 2 3; do
echo "Installation attempt $attempt..."
@@ -135,9 +139,9 @@ runs:
done
echo "Claude Code installed successfully"
else
echo "Using custom Claude Code executable: ${{ inputs.path_to_claude_code_executable }}"
echo "Using custom Claude Code executable: $PATH_TO_CLAUDE_CODE_EXECUTABLE"
# Add the directory containing the custom executable to PATH
CLAUDE_DIR=$(dirname "${{ inputs.path_to_claude_code_executable }}")
CLAUDE_DIR=$(dirname "$PATH_TO_CLAUDE_CODE_EXECUTABLE")
echo "$CLAUDE_DIR" >> "$GITHUB_PATH"
fi

View File

@@ -101,7 +101,7 @@ export function parseSdkOptions(options: ClaudeOptions): ParsedSdkOptions {
env.GITHUB_ACTION_INPUTS = process.env.INPUT_ACTION_INPUTS_PRESENT;
}
// Build system prompt option
// Build system prompt option - default to claude_code preset
let systemPrompt: SdkOptions["systemPrompt"];
if (options.systemPrompt) {
systemPrompt = options.systemPrompt;
@@ -111,6 +111,12 @@ export function parseSdkOptions(options: ClaudeOptions): ParsedSdkOptions {
preset: "claude_code",
append: options.appendSystemPrompt,
};
} else {
// Default to claude_code preset when no custom prompt is specified
systemPrompt = {
type: "preset",
preset: "claude_code",
};
}
// Build SDK options - use merged tools from both direct options and claudeArgs
@@ -130,6 +136,9 @@ export function parseSdkOptions(options: ClaudeOptions): ParsedSdkOptions {
// Note: allowedTools and disallowedTools have been removed from extraArgs to prevent duplicates
extraArgs,
env,
// Load settings from all sources to pick up CLI-installed plugins, CLAUDE.md, etc.
settingSources: ["user", "project", "local"],
};
return {

View File

@@ -75,6 +75,9 @@ export async function runClaudeWithSdk(
}
console.log(`Running Claude with prompt from file: ${promptPath}`);
// Log SDK options without env (which could contain sensitive data)
const { env, ...optionsToLog } = sdkOptions;
console.log("SDK options:", JSON.stringify(optionsToLog, null, 2));
const messages: SDKMessage[] = [];
let resultMessage: SDKResultMessage | undefined;

View File

@@ -4,7 +4,7 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import { readFile, stat } from "fs/promises";
import { join } from "path";
import { join, resolve, sep } from "path";
import { constants } from "fs";
import fetch from "node-fetch";
import { GITHUB_API_URL } from "../github/api/config";
@@ -474,20 +474,21 @@ server.tool(
throw new Error("GITHUB_TOKEN environment variable is required");
}
// Convert absolute paths to relative if they match CWD
// Normalize all paths and validate they're within the repository root
const cwd = process.cwd();
const processedPaths = paths.map((filePath) => {
if (filePath.startsWith("/")) {
if (filePath.startsWith(cwd)) {
// Strip CWD from absolute path
return filePath.slice(cwd.length + 1);
} else {
throw new Error(
`Path '${filePath}' must be relative to repository root or within current working directory`,
);
}
// Normalize the path to resolve any .. or . sequences
const normalizedPath = resolve(cwd, filePath);
// Validate the normalized path is within the current working directory
if (!normalizedPath.startsWith(cwd + sep)) {
throw new Error(
`Path '${filePath}' resolves outside the repository root`,
);
}
return filePath;
// Convert to relative path by stripping the cwd prefix
return normalizedPath.slice(cwd.length + 1);
});
// 1. Get the branch reference (create if doesn't exist)