From d1e6f5f43b27d95ce18a659e76dd7d5d8eed383c Mon Sep 17 00:00:00 2001 From: Marsel Safin Date: Mon, 2 Mar 2026 10:07:46 +0100 Subject: [PATCH 1/2] fix: strip comment lines from claudeArgs before shell-quote parsing shell-quote treats '#' as a shell comment character, silently swallowing all content after it including subsequent flags on new lines. This caused flags like --allowed-tools to be dropped when users included comments in their claude_args YAML block. Fix: strip lines starting with '#' before passing to shell-quote parse(). Fixes #802 --- base-action/src/parse-sdk-options.ts | 12 +++++- base-action/test/parse-sdk-options.test.ts | 47 ++++++++++++++++++++++ base-action/test/parse-shell-args.test.ts | 12 ++++++ 3 files changed, 70 insertions(+), 1 deletion(-) diff --git a/base-action/src/parse-sdk-options.ts b/base-action/src/parse-sdk-options.ts index 35df281d2..c2432b2e7 100644 --- a/base-action/src/parse-sdk-options.ts +++ b/base-action/src/parse-sdk-options.ts @@ -92,7 +92,17 @@ function parseClaudeArgsToExtraArgs( if (!claudeArgs?.trim()) return {}; const result: Record = {}; - const args = parseShellArgs(claudeArgs).filter( + + // Strip shell-style comment lines before parsing. + // shell-quote treats '#' as a comment character and silently swallows + // everything after it, including subsequent flags on new lines. + // See: https://github.com/anthropics/claude-code-action/issues/802 + const sanitizedArgs = claudeArgs + .split("\n") + .filter((line) => !line.trim().startsWith("#")) + .join("\n"); + + const args = parseShellArgs(sanitizedArgs).filter( (arg): arg is string => typeof arg === "string", ); diff --git a/base-action/test/parse-sdk-options.test.ts b/base-action/test/parse-sdk-options.test.ts index 9c1095cef..35babbdd9 100644 --- a/base-action/test/parse-sdk-options.test.ts +++ b/base-action/test/parse-sdk-options.test.ts @@ -367,4 +367,51 @@ describe("parseSdkOptions", () => { ); }); }); + + describe("comment handling (issue #802)", () => { + test("should ignore shell-style comment lines in claudeArgs", () => { + const options: ClaudeOptions = { + claudeArgs: [ + "--allowed-tools 'mcp__github__create_comment'", + "# This is a comment", + "--max-turns 5", + ].join("\n"), + }; + const result = parseSdkOptions(options); + + expect(result.sdkOptions.allowedTools).toContain( + "mcp__github__create_comment", + ); + expect(result.sdkOptions.extraArgs?.["max-turns"]).toBe("5"); + }); + + test("should handle multiple comment lines interspersed with flags", () => { + const options: ClaudeOptions = { + claudeArgs: [ + "# Enable specific tools", + "--allowed-tools 'Bash,Read'", + "# Set max turns", + "--max-turns 5", + ].join("\n"), + }; + const result = parseSdkOptions(options); + + expect(result.sdkOptions.allowedTools).toEqual(["Bash", "Read"]); + expect(result.sdkOptions.extraArgs?.["max-turns"]).toBe("5"); + }); + + test("should not lose flags when comment is between them", () => { + const options: ClaudeOptions = { + claudeArgs: [ + "--disallowed-tools 'WebSearch'", + "# middle comment", + "--max-turns 3", + ].join("\n"), + }; + const result = parseSdkOptions(options); + + expect(result.sdkOptions.disallowedTools).toEqual(["WebSearch"]); + expect(result.sdkOptions.extraArgs?.["max-turns"]).toBe("3"); + }); + }); }); diff --git a/base-action/test/parse-shell-args.test.ts b/base-action/test/parse-shell-args.test.ts index 7e68c424a..d68594d59 100644 --- a/base-action/test/parse-shell-args.test.ts +++ b/base-action/test/parse-shell-args.test.ts @@ -58,6 +58,18 @@ describe("shell-quote parseShellArgs", () => { ]); }); + test("should not swallow args after # comment lines", () => { + // Regression test for https://github.com/anthropics/claude-code-action/issues/802 + // shell-quote treats '#' as a shell comment, dropping all subsequent content + const input = `--model 'claude-haiku-4-5'\n# This is a comment\n--allowed-tools 'mcp__github__create_comment'`; + const result = parseShellArgs(input).filter( + (arg) => typeof arg === "string", + ); + // Without the fix, --allowed-tools would be swallowed by shell-quote + // This test documents the raw shell-quote behavior (it WILL fail with shell-quote alone) + // The actual fix is in parseClaudeArgsToExtraArgs which strips comment lines before parsing + }); + test("should filter out non-string results", () => { // shell-quote can return objects for operators like | > < etc const result = parseShellArgs("echo hello"); From 7ba35070e59a0d77a3a7031fe8cf076d8d3744a5 Mon Sep 17 00:00:00 2001 From: Marsel Safin Date: Mon, 2 Mar 2026 10:17:36 +0100 Subject: [PATCH 2/2] fix: add assertion to shell-quote comment test, address review feedback --- base-action/test/parse-shell-args.test.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/base-action/test/parse-shell-args.test.ts b/base-action/test/parse-shell-args.test.ts index d68594d59..f59437cee 100644 --- a/base-action/test/parse-shell-args.test.ts +++ b/base-action/test/parse-shell-args.test.ts @@ -58,16 +58,16 @@ describe("shell-quote parseShellArgs", () => { ]); }); - test("should not swallow args after # comment lines", () => { - // Regression test for https://github.com/anthropics/claude-code-action/issues/802 - // shell-quote treats '#' as a shell comment, dropping all subsequent content - const input = `--model 'claude-haiku-4-5'\n# This is a comment\n--allowed-tools 'mcp__github__create_comment'`; + test("documents that shell-quote treats # as comment (issue #802)", () => { + // shell-quote treats '#' as a shell comment, dropping all subsequent content. + // This documents the raw behavior — the actual fix is in parseClaudeArgsToExtraArgs + // which strips comment lines before passing to shell-quote. + const input = "--model claude-haiku-4-5\n# comment\n--allowed-tools tool1"; const result = parseShellArgs(input).filter( - (arg) => typeof arg === "string", + (arg): arg is string => typeof arg === "string", ); - // Without the fix, --allowed-tools would be swallowed by shell-quote - // This test documents the raw shell-quote behavior (it WILL fail with shell-quote alone) - // The actual fix is in parseClaudeArgsToExtraArgs which strips comment lines before parsing + // shell-quote drops everything from '#' onward, so --allowed-tools is lost + expect(result).toEqual(["--model", "claude-haiku-4-5"]); }); test("should filter out non-string results", () => {