Add setting_sources input and default base-action to user-only
Project and local settings additively merge their permissions with whatever
allowed_tools a workflow specifies. A workflow author writing a restrictive
allowlist reasonably expects it to be the complete allow-set, but
.claude/settings.json can silently expand it.
Changes:
- Add setting_sources as a first-class input to both actions (previously
only reachable via --setting-sources in claude_args)
- base-action now defaults to settingSources: ['user'] — workflows that want
project/local settings must opt in explicitly
- Main action defaults to 'user,project,local' since .claude/ is restored
from the PR base branch before execution, so project settings are
maintainer-trusted in that context
- Precedence: setting_sources input > --setting-sources in claude_args > default
Breaking change for base-action: workflows relying on .claude/settings.json
being loaded automatically need to add setting_sources: 'user,project,local'.
🏠 Remote-Dev: homespace
This commit is contained in:
parent
6ee201f023
commit
8dfb31d8a5
@ -62,6 +62,10 @@ inputs:
|
|||||||
description: "Claude Code settings as JSON string or path to settings JSON file"
|
description: "Claude Code settings as JSON string or path to settings JSON file"
|
||||||
required: false
|
required: false
|
||||||
default: ""
|
default: ""
|
||||||
|
setting_sources:
|
||||||
|
description: "Comma-separated list of setting sources to load (user, project, local). Defaults to 'user,project,local' — project settings are safe here because .claude/ is restored from the PR base branch before execution. Set to 'user' to ignore in-repo settings entirely."
|
||||||
|
required: false
|
||||||
|
default: "user,project,local"
|
||||||
|
|
||||||
# Auth configuration
|
# Auth configuration
|
||||||
anthropic_api_key:
|
anthropic_api_key:
|
||||||
@ -279,6 +283,7 @@ runs:
|
|||||||
# Base-action inputs
|
# Base-action inputs
|
||||||
INPUT_PROMPT_FILE: ${{ runner.temp }}/claude-prompts/claude-prompt.txt
|
INPUT_PROMPT_FILE: ${{ runner.temp }}/claude-prompts/claude-prompt.txt
|
||||||
INPUT_SETTINGS: ${{ inputs.settings }}
|
INPUT_SETTINGS: ${{ inputs.settings }}
|
||||||
|
INPUT_SETTING_SOURCES: ${{ inputs.setting_sources }}
|
||||||
INPUT_EXPERIMENTAL_SLASH_COMMANDS_DIR: ${{ github.action_path }}/slash-commands
|
INPUT_EXPERIMENTAL_SLASH_COMMANDS_DIR: ${{ github.action_path }}/slash-commands
|
||||||
INPUT_PATH_TO_CLAUDE_CODE_EXECUTABLE: ${{ inputs.path_to_claude_code_executable }}
|
INPUT_PATH_TO_CLAUDE_CODE_EXECUTABLE: ${{ inputs.path_to_claude_code_executable }}
|
||||||
INPUT_PATH_TO_BUN_EXECUTABLE: ${{ inputs.path_to_bun_executable }}
|
INPUT_PATH_TO_BUN_EXECUTABLE: ${{ inputs.path_to_bun_executable }}
|
||||||
|
|||||||
@ -94,6 +94,7 @@ Add the following to your workflow file:
|
|||||||
| `max_turns` | Maximum number of conversation turns (default: no limit) | No | '' |
|
| `max_turns` | Maximum number of conversation turns (default: no limit) | No | '' |
|
||||||
| `mcp_config` | Path to the MCP configuration JSON file, or MCP configuration JSON string | No | '' |
|
| `mcp_config` | Path to the MCP configuration JSON file, or MCP configuration JSON string | No | '' |
|
||||||
| `settings` | Path to Claude Code settings JSON file, or settings JSON string | No | '' |
|
| `settings` | Path to Claude Code settings JSON file, or settings JSON string | No | '' |
|
||||||
|
| `setting_sources` | Comma-separated setting sources to load (`user`, `project`, `local`). Project/local merge permissions additively. | No | 'user' |
|
||||||
| `system_prompt` | Override system prompt | No | '' |
|
| `system_prompt` | Override system prompt | No | '' |
|
||||||
| `append_system_prompt` | Append to system prompt | No | '' |
|
| `append_system_prompt` | Append to system prompt | No | '' |
|
||||||
| `claude_env` | Custom environment variables to pass to Claude Code execution (YAML multiline format) | No | '' |
|
| `claude_env` | Custom environment variables to pass to Claude Code execution (YAML multiline format) | No | '' |
|
||||||
|
|||||||
@ -18,6 +18,10 @@ inputs:
|
|||||||
description: "Claude Code settings as JSON string or path to settings JSON file"
|
description: "Claude Code settings as JSON string or path to settings JSON file"
|
||||||
required: false
|
required: false
|
||||||
default: ""
|
default: ""
|
||||||
|
setting_sources:
|
||||||
|
description: "Comma-separated list of setting sources to load (user, project, local). Defaults to 'user' only. Project/local settings additively merge permissions with allowed_tools — set to 'user,project,local' to opt in."
|
||||||
|
required: false
|
||||||
|
default: ""
|
||||||
|
|
||||||
# Action settings
|
# Action settings
|
||||||
claude_args:
|
claude_args:
|
||||||
@ -165,6 +169,7 @@ runs:
|
|||||||
INPUT_PROMPT: ${{ inputs.prompt }}
|
INPUT_PROMPT: ${{ inputs.prompt }}
|
||||||
INPUT_PROMPT_FILE: ${{ inputs.prompt_file }}
|
INPUT_PROMPT_FILE: ${{ inputs.prompt_file }}
|
||||||
INPUT_SETTINGS: ${{ inputs.settings }}
|
INPUT_SETTINGS: ${{ inputs.settings }}
|
||||||
|
INPUT_SETTING_SOURCES: ${{ inputs.setting_sources }}
|
||||||
INPUT_CLAUDE_ARGS: ${{ inputs.claude_args }}
|
INPUT_CLAUDE_ARGS: ${{ inputs.claude_args }}
|
||||||
INPUT_PATH_TO_CLAUDE_CODE_EXECUTABLE: ${{ inputs.path_to_claude_code_executable }}
|
INPUT_PATH_TO_CLAUDE_CODE_EXECUTABLE: ${{ inputs.path_to_claude_code_executable }}
|
||||||
INPUT_PATH_TO_BUN_EXECUTABLE: ${{ inputs.path_to_bun_executable }}
|
INPUT_PATH_TO_BUN_EXECUTABLE: ${{ inputs.path_to_bun_executable }}
|
||||||
|
|||||||
@ -48,6 +48,7 @@ async function run() {
|
|||||||
model: process.env.ANTHROPIC_MODEL,
|
model: process.env.ANTHROPIC_MODEL,
|
||||||
pathToClaudeCodeExecutable: claudeExecutable,
|
pathToClaudeCodeExecutable: claudeExecutable,
|
||||||
showFullOutput: process.env.INPUT_SHOW_FULL_OUTPUT,
|
showFullOutput: process.env.INPUT_SHOW_FULL_OUTPUT,
|
||||||
|
settingSources: process.env.INPUT_SETTING_SOURCES,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Set outputs for the standalone base-action
|
// Set outputs for the standalone base-action
|
||||||
|
|||||||
@ -271,13 +271,15 @@ export function parseSdkOptions(options: ClaudeOptions): ParsedSdkOptions {
|
|||||||
extraArgs,
|
extraArgs,
|
||||||
env,
|
env,
|
||||||
|
|
||||||
// Load settings from sources - prefer user's --setting-sources if provided, otherwise use all sources
|
// Setting sources precedence: direct input > --setting-sources in claude_args > default.
|
||||||
// This ensures users can override the default behavior (e.g., --setting-sources user to avoid in-repo configs)
|
// Default is ["user"] only: project/local settings additively merge permissions with
|
||||||
settingSources: extraArgs["setting-sources"]
|
// allowedTools, which silently expands a workflow's intended allow-set. Workflows that
|
||||||
? (extraArgs["setting-sources"].split(
|
// want project settings must opt in explicitly.
|
||||||
",",
|
settingSources: (options.settingSources
|
||||||
) as SdkOptions["settingSources"])
|
? options.settingSources.split(",").map((s) => s.trim())
|
||||||
: ["user", "project", "local"],
|
: extraArgs["setting-sources"]
|
||||||
|
? extraArgs["setting-sources"].split(",").map((s) => s.trim())
|
||||||
|
: ["user"]) as SdkOptions["settingSources"],
|
||||||
};
|
};
|
||||||
|
|
||||||
// Remove setting-sources from extraArgs to avoid passing it twice
|
// Remove setting-sources from extraArgs to avoid passing it twice
|
||||||
|
|||||||
@ -14,6 +14,7 @@ export type ClaudeOptions = {
|
|||||||
appendSystemPrompt?: string;
|
appendSystemPrompt?: string;
|
||||||
fallbackModel?: string;
|
fallbackModel?: string;
|
||||||
showFullOutput?: string;
|
showFullOutput?: string;
|
||||||
|
settingSources?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function runClaude(
|
export async function runClaude(
|
||||||
|
|||||||
@ -422,4 +422,59 @@ describe("parseSdkOptions", () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("settingSources", () => {
|
||||||
|
test("should default to ['user'] when not specified", () => {
|
||||||
|
const options: ClaudeOptions = {};
|
||||||
|
const result = parseSdkOptions(options);
|
||||||
|
|
||||||
|
expect(result.sdkOptions.settingSources).toEqual(["user"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should use direct settingSources input when provided", () => {
|
||||||
|
const options: ClaudeOptions = {
|
||||||
|
settingSources: "user,project,local",
|
||||||
|
};
|
||||||
|
const result = parseSdkOptions(options);
|
||||||
|
|
||||||
|
expect(result.sdkOptions.settingSources).toEqual([
|
||||||
|
"user",
|
||||||
|
"project",
|
||||||
|
"local",
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should use --setting-sources from claudeArgs when no direct input", () => {
|
||||||
|
const options: ClaudeOptions = {
|
||||||
|
claudeArgs: "--setting-sources user,project",
|
||||||
|
};
|
||||||
|
const result = parseSdkOptions(options);
|
||||||
|
|
||||||
|
expect(result.sdkOptions.settingSources).toEqual(["user", "project"]);
|
||||||
|
expect(result.sdkOptions.extraArgs?.["setting-sources"]).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("direct input should take precedence over claudeArgs", () => {
|
||||||
|
const options: ClaudeOptions = {
|
||||||
|
settingSources: "user",
|
||||||
|
claudeArgs: "--setting-sources user,project,local",
|
||||||
|
};
|
||||||
|
const result = parseSdkOptions(options);
|
||||||
|
|
||||||
|
expect(result.sdkOptions.settingSources).toEqual(["user"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should trim whitespace in comma-separated values", () => {
|
||||||
|
const options: ClaudeOptions = {
|
||||||
|
settingSources: "user, project , local",
|
||||||
|
};
|
||||||
|
const result = parseSdkOptions(options);
|
||||||
|
|
||||||
|
expect(result.sdkOptions.settingSources).toEqual([
|
||||||
|
"user",
|
||||||
|
"project",
|
||||||
|
"local",
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -278,6 +278,7 @@ async function run() {
|
|||||||
model: process.env.ANTHROPIC_MODEL,
|
model: process.env.ANTHROPIC_MODEL,
|
||||||
pathToClaudeCodeExecutable: claudeExecutable,
|
pathToClaudeCodeExecutable: claudeExecutable,
|
||||||
showFullOutput: process.env.INPUT_SHOW_FULL_OUTPUT,
|
showFullOutput: process.env.INPUT_SHOW_FULL_OUTPUT,
|
||||||
|
settingSources: process.env.INPUT_SETTING_SOURCES,
|
||||||
});
|
});
|
||||||
|
|
||||||
claudeSuccess = claudeResult.conclusion === "success";
|
claudeSuccess = claudeResult.conclusion === "success";
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user