diff --git a/action.yml b/action.yml index 51ea521..bb573a3 100644 --- a/action.yml +++ b/action.yml @@ -63,9 +63,9 @@ inputs: required: false 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." + description: "Comma-separated list of setting sources to load (user, project, local). When unset, the action applies 'user,project,local' at runtime — 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" + default: "" # Auth configuration anthropic_api_key: diff --git a/base-action/src/parse-sdk-options.ts b/base-action/src/parse-sdk-options.ts index 0fd33c4..7aab9b7 100644 --- a/base-action/src/parse-sdk-options.ts +++ b/base-action/src/parse-sdk-options.ts @@ -272,14 +272,16 @@ export function parseSdkOptions(options: ClaudeOptions): ParsedSdkOptions { env, // Setting sources precedence: direct input > --setting-sources in claude_args > default. - // Default is ["user"] only: project/local settings additively merge permissions with - // allowedTools, which silently expands a workflow's intended allow-set. Workflows that - // want project settings must opt in explicitly. + // The default is supplied by the caller (base-action uses ["user"]; the wrapper action + // uses ["user","project","local"]). Both action.yml files leave the YAML default empty + // so that --setting-sources in claude_args is reachable when the input is not set. settingSources: (options.settingSources ? options.settingSources.split(",").map((s) => s.trim()) : extraArgs["setting-sources"] ? extraArgs["setting-sources"].split(",").map((s) => s.trim()) - : ["user"]) as SdkOptions["settingSources"], + : (options.defaultSettingSources ?? [ + "user", + ])) as SdkOptions["settingSources"], }; // Remove setting-sources from extraArgs to avoid passing it twice diff --git a/base-action/src/run-claude.ts b/base-action/src/run-claude.ts index 4b4e777..46860be 100644 --- a/base-action/src/run-claude.ts +++ b/base-action/src/run-claude.ts @@ -1,6 +1,7 @@ import { runClaudeWithSdk } from "./run-claude-sdk"; import type { ClaudeRunResult } from "./run-claude-sdk"; import { parseSdkOptions } from "./parse-sdk-options"; +import type { Options as SdkOptions } from "@anthropic-ai/claude-agent-sdk"; export type ClaudeOptions = { claudeArgs?: string; @@ -15,6 +16,7 @@ export type ClaudeOptions = { fallbackModel?: string; showFullOutput?: string; settingSources?: string; + defaultSettingSources?: SdkOptions["settingSources"]; }; export async function runClaude( diff --git a/base-action/test/parse-sdk-options.test.ts b/base-action/test/parse-sdk-options.test.ts index 0d279e2..898379b 100644 --- a/base-action/test/parse-sdk-options.test.ts +++ b/base-action/test/parse-sdk-options.test.ts @@ -476,5 +476,40 @@ describe("parseSdkOptions", () => { "local", ]); }); + + test("should use defaultSettingSources when nothing else is set", () => { + const options: ClaudeOptions = { + defaultSettingSources: ["user", "project", "local"], + }; + const result = parseSdkOptions(options); + + expect(result.sdkOptions.settingSources).toEqual([ + "user", + "project", + "local", + ]); + }); + + test("--setting-sources in claudeArgs should win over defaultSettingSources", () => { + const options: ClaudeOptions = { + claudeArgs: "--setting-sources user", + defaultSettingSources: ["user", "project", "local"], + }; + const result = parseSdkOptions(options); + + expect(result.sdkOptions.settingSources).toEqual(["user"]); + }); + + test("empty-string settingSources falls through to claudeArgs then default", () => { + // YAML default: "" — INPUT_SETTING_SOURCES is "" when the user doesn't set the input + const options: ClaudeOptions = { + settingSources: "", + claudeArgs: "--setting-sources user,project", + defaultSettingSources: ["user", "project", "local"], + }; + const result = parseSdkOptions(options); + + expect(result.sdkOptions.settingSources).toEqual(["user", "project"]); + }); }); }); diff --git a/src/entrypoints/run.ts b/src/entrypoints/run.ts index 11200ae..1bf674c 100644 --- a/src/entrypoints/run.ts +++ b/src/entrypoints/run.ts @@ -279,6 +279,7 @@ async function run() { pathToClaudeCodeExecutable: claudeExecutable, showFullOutput: process.env.INPUT_SHOW_FULL_OUTPUT, settingSources: process.env.INPUT_SETTING_SOURCES, + defaultSettingSources: ["user", "project", "local"], }); claudeSuccess = claudeResult.conclusion === "success";