From 5395bd7c938b80b6bdcbedc7bb54f9443630fb50 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 27 Jan 2026 18:01:15 +0000 Subject: [PATCH 1/4] Initial plan From 912cdc899faf3ad6ee4488426b58e0b8d868d2e3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 27 Jan 2026 18:12:58 +0000 Subject: [PATCH 2/4] Consolidate shell utilities: move functions from mcp_utilities to shell.go Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- pkg/workflow/mcp_setup_generator.go | 6 +- pkg/workflow/mcp_utilities.go | 44 ------- pkg/workflow/mcp_utilities_test.go | 189 ---------------------------- pkg/workflow/shell.go | 32 +++++ pkg/workflow/shell_test.go | 108 +++++++++++++++- 5 files changed, 142 insertions(+), 237 deletions(-) delete mode 100644 pkg/workflow/mcp_utilities.go delete mode 100644 pkg/workflow/mcp_utilities_test.go diff --git a/pkg/workflow/mcp_setup_generator.go b/pkg/workflow/mcp_setup_generator.go index 8d4a28df54..180e17cf0e 100644 --- a/pkg/workflow/mcp_setup_generator.go +++ b/pkg/workflow/mcp_setup_generator.go @@ -630,20 +630,20 @@ func (c *Compiler) generateMCPSetup(yaml *strings.Builder, tools map[string]any, // Add entrypoint override if specified if gatewayConfig.Entrypoint != "" { - containerCmd += " --entrypoint " + shellQuote(gatewayConfig.Entrypoint) + containerCmd += " --entrypoint " + shellEscapeArg(gatewayConfig.Entrypoint) } containerCmd += " " + containerImage if len(gatewayConfig.EntrypointArgs) > 0 { for _, arg := range gatewayConfig.EntrypointArgs { - containerCmd += " " + shellQuote(arg) + containerCmd += " " + shellEscapeArg(arg) } } if len(gatewayConfig.Args) > 0 { for _, arg := range gatewayConfig.Args { - containerCmd += " " + shellQuote(arg) + containerCmd += " " + shellEscapeArg(arg) } } diff --git a/pkg/workflow/mcp_utilities.go b/pkg/workflow/mcp_utilities.go deleted file mode 100644 index 28fafa4da0..0000000000 --- a/pkg/workflow/mcp_utilities.go +++ /dev/null @@ -1,44 +0,0 @@ -package workflow - -import ( - "strings" -) - -// shellQuote adds shell quoting to a string if needed -func shellQuote(s string) string { - if strings.ContainsAny(s, " \t\n'\"\\$`") { - // Escape single quotes and wrap in single quotes - s = strings.ReplaceAll(s, "'", "'\\''") - return "'" + s + "'" - } - return s -} - -// buildDockerCommandWithExpandableVars builds a properly quoted docker command -// that allows ${GITHUB_WORKSPACE} and $GITHUB_WORKSPACE to be expanded at runtime -func buildDockerCommandWithExpandableVars(cmd string) string { - // Replace ${GITHUB_WORKSPACE} with a placeholder that we'll handle specially - // We want: 'docker run ... -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ...' - // This closes the single quote, adds the variable in double quotes, then reopens single quote - - // Split on ${GITHUB_WORKSPACE} to handle it specially - if strings.Contains(cmd, "${GITHUB_WORKSPACE}") { - parts := strings.Split(cmd, "${GITHUB_WORKSPACE}") - var result strings.Builder - result.WriteString("'") - for i, part := range parts { - if i > 0 { - // Add the variable expansion outside of single quotes - result.WriteString("'\"${GITHUB_WORKSPACE}\"'") - } - // Escape single quotes in the part - escapedPart := strings.ReplaceAll(part, "'", "'\\''") - result.WriteString(escapedPart) - } - result.WriteString("'") - return result.String() - } - - // No GITHUB_WORKSPACE variable, use normal quoting - return shellQuote(cmd) -} diff --git a/pkg/workflow/mcp_utilities_test.go b/pkg/workflow/mcp_utilities_test.go deleted file mode 100644 index 1f15c610c2..0000000000 --- a/pkg/workflow/mcp_utilities_test.go +++ /dev/null @@ -1,189 +0,0 @@ -package workflow - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestShellQuote(t *testing.T) { - tests := []struct { - name string - input string - expected string - }{ - { - name: "simple string without special chars", - input: "hello", - expected: "hello", - }, - { - name: "string with space", - input: "hello world", - expected: "'hello world'", - }, - { - name: "string with single quote", - input: "it's", - expected: "'it'\\''s'", - }, - { - name: "string with double quote", - input: "hello \"world\"", - expected: "'hello \"world\"'", - }, - { - name: "string with dollar sign", - input: "$PATH", - expected: "'$PATH'", - }, - { - name: "string with backtick", - input: "`command`", - expected: "'`command`'", - }, - { - name: "string with backslash", - input: "path\\to\\file", - expected: "'path\\to\\file'", - }, - { - name: "string with tab", - input: "hello\tworld", - expected: "'hello\tworld'", - }, - { - name: "string with newline", - input: "hello\nworld", - expected: "'hello\nworld'", - }, - { - name: "empty string", - input: "", - expected: "", - }, - { - name: "complex string with multiple special chars", - input: "echo 'hello' \"world\" $VAR `cmd`", - expected: "'echo '\\''hello'\\'' \"world\" $VAR `cmd`'", - }, - { - name: "command injection attempt with semicolon", - input: "file; rm -rf /", - expected: "'file; rm -rf /'", - }, - { - name: "command injection attempt with pipe", - input: "file | cat /etc/passwd", - expected: "'file | cat /etc/passwd'", - }, - { - name: "multiple single quotes", - input: "it's a test's file", - expected: "'it'\\''s a test'\\''s file'", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result := shellQuote(tt.input) - assert.Equal(t, tt.expected, result, "Shell quote result should match expected") - }) - } -} - -func TestBuildDockerCommandWithExpandableVars(t *testing.T) { - tests := []struct { - name string - input string - expected string - }{ - { - name: "simple command without GITHUB_WORKSPACE", - input: "docker run hello", - expected: "'docker run hello'", - }, - { - name: "command with single GITHUB_WORKSPACE", - input: "docker run -v ${GITHUB_WORKSPACE}:${GITHUB_WORKSPACE}", - expected: "'docker run -v '\"${GITHUB_WORKSPACE}\"':'\"${GITHUB_WORKSPACE}\"''", - }, - { - name: "command with GITHUB_WORKSPACE at the start", - input: "${GITHUB_WORKSPACE}/file", - expected: "''\"${GITHUB_WORKSPACE}\"'/file'", - }, - { - name: "command with GITHUB_WORKSPACE at the end", - input: "path/to/${GITHUB_WORKSPACE}", - expected: "'path/to/'\"${GITHUB_WORKSPACE}\"''", - }, - { - name: "command with multiple GITHUB_WORKSPACE references", - input: "${GITHUB_WORKSPACE}/src:${GITHUB_WORKSPACE}/dst", - expected: "''\"${GITHUB_WORKSPACE}\"'/src:'\"${GITHUB_WORKSPACE}\"'/dst'", - }, - { - name: "command with GITHUB_WORKSPACE and single quote", - input: "it's in ${GITHUB_WORKSPACE}", - expected: "'it'\\''s in '\"${GITHUB_WORKSPACE}\"''", - }, - { - name: "complex docker command", - input: "docker run -v ${GITHUB_WORKSPACE}:${GITHUB_WORKSPACE}:rw image", - expected: "'docker run -v '\"${GITHUB_WORKSPACE}\"':'\"${GITHUB_WORKSPACE}\"':rw image'", - }, - { - name: "command with spaces and no GITHUB_WORKSPACE", - input: "docker run hello world", - expected: "'docker run hello world'", - }, - { - name: "empty command", - input: "", - expected: "", - }, - { - name: "injection attempt in GITHUB_WORKSPACE context", - input: "${GITHUB_WORKSPACE}; rm -rf /", - expected: "''\"${GITHUB_WORKSPACE}\"'; rm -rf /'", - }, - { - name: "multiple variables mixed with GITHUB_WORKSPACE", - input: "${GITHUB_WORKSPACE}/src ${OTHER_VAR}/dst", - expected: "''\"${GITHUB_WORKSPACE}\"'/src ${OTHER_VAR}/dst'", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result := buildDockerCommandWithExpandableVars(tt.input) - assert.Equal(t, tt.expected, result, "Docker command with expandable vars should match expected") - }) - } -} - -func TestBuildDockerCommandWithExpandableVars_PreservesVariableExpansion(t *testing.T) { - // Test that ${GITHUB_WORKSPACE} is properly preserved for shell expansion - input := "docker run -v ${GITHUB_WORKSPACE}:/workspace" - result := buildDockerCommandWithExpandableVars(input) - - // Use require.* for the first critical check (fail-fast) - require.Contains(t, result, "${GITHUB_WORKSPACE}", "Result should preserve GITHUB_WORKSPACE variable for expansion") - - // Use assert.* for the second check (still runs if we get here) - assert.Contains(t, result, "\"${GITHUB_WORKSPACE}\"", "GITHUB_WORKSPACE should be in double quotes for safe expansion") -} - -func TestBuildDockerCommandWithExpandableVars_UnbracedVariable(t *testing.T) { - // Test that $GITHUB_WORKSPACE (without braces) is handled - // The current implementation only handles ${GITHUB_WORKSPACE} (with braces) - // and treats $GITHUB_WORKSPACE as a regular shell character that gets quoted - input := "docker run -v $GITHUB_WORKSPACE:/workspace" - result := buildDockerCommandWithExpandableVars(input) - - // Document current behavior: unbraced $GITHUB_WORKSPACE is quoted normally - assert.Equal(t, "'docker run -v $GITHUB_WORKSPACE:/workspace'", result, - "Unbraced $GITHUB_WORKSPACE should be quoted normally (not preserved for expansion)") -} diff --git a/pkg/workflow/shell.go b/pkg/workflow/shell.go index 9c0baafa2b..d992b04c33 100644 --- a/pkg/workflow/shell.go +++ b/pkg/workflow/shell.go @@ -69,3 +69,35 @@ func shellEscapeCommandString(cmd string) string { // Wrap in double quotes return "\"" + escaped + "\"" } + +// buildDockerCommandWithExpandableVars builds a properly quoted docker command +// that allows ${GITHUB_WORKSPACE} and $GITHUB_WORKSPACE to be expanded at runtime +func buildDockerCommandWithExpandableVars(cmd string) string { + shellLog.Printf("Building docker command with expandable vars (length: %d)", len(cmd)) + // Replace ${GITHUB_WORKSPACE} with a placeholder that we'll handle specially + // We want: 'docker run ... -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ...' + // This closes the single quote, adds the variable in double quotes, then reopens single quote + + // Split on ${GITHUB_WORKSPACE} to handle it specially + if strings.Contains(cmd, "${GITHUB_WORKSPACE}") { + parts := strings.Split(cmd, "${GITHUB_WORKSPACE}") + var result strings.Builder + result.WriteString("'") + for i, part := range parts { + if i > 0 { + // Add the variable expansion outside of single quotes + result.WriteString("'\"${GITHUB_WORKSPACE}\"'") + } + // Escape single quotes in the part + escapedPart := strings.ReplaceAll(part, "'", "'\\''") + result.WriteString(escapedPart) + } + result.WriteString("'") + shellLog.Print("Docker command built with expandable GITHUB_WORKSPACE variables") + return result.String() + } + + // No GITHUB_WORKSPACE variable, use normal quoting + shellLog.Print("No GITHUB_WORKSPACE variable found, using normal escaping") + return shellEscapeArg(cmd) +} diff --git a/pkg/workflow/shell_test.go b/pkg/workflow/shell_test.go index eb57aecaaf..005ab3648b 100644 --- a/pkg/workflow/shell_test.go +++ b/pkg/workflow/shell_test.go @@ -1,6 +1,9 @@ package workflow -import "testing" +import ( + "strings" + "testing" +) func TestShellEscapeArg(t *testing.T) { tests := []struct { @@ -190,3 +193,106 @@ func TestShellEscapeCommandString(t *testing.T) { }) } } + +func TestBuildDockerCommandWithExpandableVars(t *testing.T) { + tests := []struct { + name string + input string + expected string + }{ + { + name: "simple command without GITHUB_WORKSPACE", + input: "docker run hello", + expected: "'docker run hello'", + }, + { + name: "command with single GITHUB_WORKSPACE", + input: "docker run -v ${GITHUB_WORKSPACE}:${GITHUB_WORKSPACE}", + expected: "'docker run -v '\"${GITHUB_WORKSPACE}\"':'\"${GITHUB_WORKSPACE}\"''", + }, + { + name: "command with GITHUB_WORKSPACE at the start", + input: "${GITHUB_WORKSPACE}/file", + expected: "''\"${GITHUB_WORKSPACE}\"'/file'", + }, + { + name: "command with GITHUB_WORKSPACE at the end", + input: "path/to/${GITHUB_WORKSPACE}", + expected: "'path/to/'\"${GITHUB_WORKSPACE}\"''", + }, + { + name: "command with multiple GITHUB_WORKSPACE references", + input: "${GITHUB_WORKSPACE}/src:${GITHUB_WORKSPACE}/dst", + expected: "''\"${GITHUB_WORKSPACE}\"'/src:'\"${GITHUB_WORKSPACE}\"'/dst'", + }, + { + name: "command with GITHUB_WORKSPACE and single quote", + input: "it's in ${GITHUB_WORKSPACE}", + expected: "'it'\\''s in '\"${GITHUB_WORKSPACE}\"''", + }, + { + name: "complex docker command", + input: "docker run -v ${GITHUB_WORKSPACE}:${GITHUB_WORKSPACE}:rw image", + expected: "'docker run -v '\"${GITHUB_WORKSPACE}\"':'\"${GITHUB_WORKSPACE}\"':rw image'", + }, + { + name: "command with spaces and no GITHUB_WORKSPACE", + input: "docker run hello world", + expected: "'docker run hello world'", + }, + { + name: "empty command", + input: "", + expected: "", + }, + { + name: "injection attempt in GITHUB_WORKSPACE context", + input: "${GITHUB_WORKSPACE}; rm -rf /", + expected: "''\"${GITHUB_WORKSPACE}\"'; rm -rf /'", + }, + { + name: "multiple variables mixed with GITHUB_WORKSPACE", + input: "${GITHUB_WORKSPACE}/src ${OTHER_VAR}/dst", + expected: "''\"${GITHUB_WORKSPACE}\"'/src ${OTHER_VAR}/dst'", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := buildDockerCommandWithExpandableVars(tt.input) + if result != tt.expected { + t.Errorf("buildDockerCommandWithExpandableVars(%q) = %q, expected %q", tt.input, result, tt.expected) + } + }) + } +} + +func TestBuildDockerCommandWithExpandableVars_PreservesVariableExpansion(t *testing.T) { + // Test that ${GITHUB_WORKSPACE} is properly preserved for shell expansion + input := "docker run -v ${GITHUB_WORKSPACE}:/workspace" + result := buildDockerCommandWithExpandableVars(input) + + // The result should preserve GITHUB_WORKSPACE variable for expansion + if !strings.Contains(result, "${GITHUB_WORKSPACE}") { + t.Errorf("Result should preserve GITHUB_WORKSPACE variable for expansion, got: %q", result) + } + + // GITHUB_WORKSPACE should be in double quotes for safe expansion + if !strings.Contains(result, "\"${GITHUB_WORKSPACE}\"") { + t.Errorf("GITHUB_WORKSPACE should be in double quotes for safe expansion, got: %q", result) + } +} + +func TestBuildDockerCommandWithExpandableVars_UnbracedVariable(t *testing.T) { + // Test that $GITHUB_WORKSPACE (without braces) is handled + // The current implementation only handles ${GITHUB_WORKSPACE} (with braces) + // and treats $GITHUB_WORKSPACE as a regular shell character that gets quoted + input := "docker run -v $GITHUB_WORKSPACE:/workspace" + result := buildDockerCommandWithExpandableVars(input) + + // Document current behavior: unbraced $GITHUB_WORKSPACE is quoted normally + expected := "'docker run -v $GITHUB_WORKSPACE:/workspace'" + if result != expected { + t.Errorf("Unbraced $GITHUB_WORKSPACE should be quoted normally (not preserved for expansion), got %q, expected %q", result, expected) + } +} From 9da8f7ec3cc7c3016c7ac382075dc7849241b3c5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 27 Jan 2026 18:56:12 +0000 Subject: [PATCH 3/4] Merge main and recompile workflows Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .github/workflows/security-guard.lock.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/security-guard.lock.yml b/.github/workflows/security-guard.lock.yml index 9e57c3b4dd..11c8f38bdf 100644 --- a/.github/workflows/security-guard.lock.yml +++ b/.github/workflows/security-guard.lock.yml @@ -777,8 +777,9 @@ jobs: timeout-minutes: 15 run: | set -o pipefail - sudo -E awf --env-all --container-workdir "${GITHUB_WORKSPACE}" --mount /tmp:/tmp:rw --mount "${GITHUB_WORKSPACE}:${GITHUB_WORKSPACE}:rw" --mount /usr/bin/date:/usr/bin/date:ro --mount /usr/bin/gh:/usr/bin/gh:ro --mount /usr/bin/yq:/usr/bin/yq:ro --mount /usr/local/bin/copilot:/usr/local/bin/copilot:ro --mount /home/runner/.copilot:/home/runner/.copilot:rw --mount /opt/hostedtoolcache:/opt/hostedtoolcache:ro --mount /opt/gh-aw:/opt/gh-aw:ro --allow-domains api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.11.2 --agent-image act \ - -- 'export PATH="$(find /opt/hostedtoolcache -maxdepth 4 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH" && /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --add-dir "${GITHUB_WORKSPACE}" --disable-builtin-mcps --allow-all-tools --allow-all-paths --share /tmp/gh-aw/sandbox/agent/logs/conversation.md --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"${GH_AW_MODEL_AGENT_COPILOT:+ --model "$GH_AW_MODEL_AGENT_COPILOT"}' \ + GH_AW_TOOL_BINS=""; [ -n "$GOROOT" ] && GH_AW_TOOL_BINS="$GOROOT/bin:$GH_AW_TOOL_BINS"; [ -n "$JAVA_HOME" ] && GH_AW_TOOL_BINS="$JAVA_HOME/bin:$GH_AW_TOOL_BINS"; [ -n "$CARGO_HOME" ] && GH_AW_TOOL_BINS="$CARGO_HOME/bin:$GH_AW_TOOL_BINS"; [ -n "$GEM_HOME" ] && GH_AW_TOOL_BINS="$GEM_HOME/bin:$GH_AW_TOOL_BINS"; [ -n "$CONDA" ] && GH_AW_TOOL_BINS="$CONDA/bin:$GH_AW_TOOL_BINS"; [ -n "$PIPX_BIN_DIR" ] && GH_AW_TOOL_BINS="$PIPX_BIN_DIR:$GH_AW_TOOL_BINS"; [ -n "$SWIFT_PATH" ] && GH_AW_TOOL_BINS="$SWIFT_PATH:$GH_AW_TOOL_BINS"; [ -n "$DOTNET_ROOT" ] && GH_AW_TOOL_BINS="$DOTNET_ROOT:$GH_AW_TOOL_BINS"; export GH_AW_TOOL_BINS + sudo -E awf --env-all --env 'ANDROID_HOME=${ANDROID_HOME}' --env 'ANDROID_NDK=${ANDROID_NDK}' --env 'ANDROID_NDK_HOME=${ANDROID_NDK_HOME}' --env 'ANDROID_NDK_LATEST_HOME=${ANDROID_NDK_LATEST_HOME}' --env 'ANDROID_NDK_ROOT=${ANDROID_NDK_ROOT}' --env 'ANDROID_SDK_ROOT=${ANDROID_SDK_ROOT}' --env 'AZURE_EXTENSION_DIR=${AZURE_EXTENSION_DIR}' --env 'CARGO_HOME=${CARGO_HOME}' --env 'CHROMEWEBDRIVER=${CHROMEWEBDRIVER}' --env 'CONDA=${CONDA}' --env 'DOTNET_ROOT=${DOTNET_ROOT}' --env 'EDGEWEBDRIVER=${EDGEWEBDRIVER}' --env 'GECKOWEBDRIVER=${GECKOWEBDRIVER}' --env 'GEM_HOME=${GEM_HOME}' --env 'GEM_PATH=${GEM_PATH}' --env 'GOPATH=${GOPATH}' --env 'GOROOT=${GOROOT}' --env 'HOMEBREW_CELLAR=${HOMEBREW_CELLAR}' --env 'HOMEBREW_PREFIX=${HOMEBREW_PREFIX}' --env 'HOMEBREW_REPOSITORY=${HOMEBREW_REPOSITORY}' --env 'JAVA_HOME=${JAVA_HOME}' --env 'JAVA_HOME_11_X64=${JAVA_HOME_11_X64}' --env 'JAVA_HOME_17_X64=${JAVA_HOME_17_X64}' --env 'JAVA_HOME_21_X64=${JAVA_HOME_21_X64}' --env 'JAVA_HOME_25_X64=${JAVA_HOME_25_X64}' --env 'JAVA_HOME_8_X64=${JAVA_HOME_8_X64}' --env 'NVM_DIR=${NVM_DIR}' --env 'PIPX_BIN_DIR=${PIPX_BIN_DIR}' --env 'PIPX_HOME=${PIPX_HOME}' --env 'RUSTUP_HOME=${RUSTUP_HOME}' --env 'SELENIUM_JAR_PATH=${SELENIUM_JAR_PATH}' --env 'SWIFT_PATH=${SWIFT_PATH}' --env 'VCPKG_INSTALLATION_ROOT=${VCPKG_INSTALLATION_ROOT}' --env 'GH_AW_TOOL_BINS=$GH_AW_TOOL_BINS' --container-workdir "${GITHUB_WORKSPACE}" --mount /tmp:/tmp:rw --mount "${GITHUB_WORKSPACE}:${GITHUB_WORKSPACE}:rw" --mount /usr/bin/date:/usr/bin/date:ro --mount /usr/bin/gh:/usr/bin/gh:ro --mount /usr/bin/yq:/usr/bin/yq:ro --mount /usr/local/bin/copilot:/usr/local/bin/copilot:ro --mount /home/runner/.copilot:/home/runner/.copilot:rw --mount /opt/hostedtoolcache:/opt/hostedtoolcache:ro --mount /opt/gh-aw:/opt/gh-aw:ro --allow-domains api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,github.com,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com --log-level info --proxy-logs-dir /tmp/gh-aw/sandbox/firewall/logs --enable-host-access --image-tag 0.11.2 --agent-image act \ + -- 'export PATH="$GH_AW_TOOL_BINS$(find /opt/hostedtoolcache -maxdepth 4 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')$PATH" && /usr/local/bin/copilot --add-dir /tmp/gh-aw/ --log-level all --log-dir /tmp/gh-aw/sandbox/agent/logs/ --add-dir "${GITHUB_WORKSPACE}" --disable-builtin-mcps --allow-all-tools --allow-all-paths --share /tmp/gh-aw/sandbox/agent/logs/conversation.md --prompt "$(cat /tmp/gh-aw/aw-prompts/prompt.txt)"${GH_AW_MODEL_AGENT_COPILOT:+ --model "$GH_AW_MODEL_AGENT_COPILOT"}' \ 2>&1 | tee /tmp/gh-aw/agent-stdio.log env: COPILOT_AGENT_RUNNER_TYPE: STANDALONE From 228125e3356129f58b72e3c6fd529d002519a8b3 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 27 Jan 2026 19:09:54 +0000 Subject: [PATCH 4/4] Add changeset [skip-ci] --- .changeset/patch-consolidate-shell-utils.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/patch-consolidate-shell-utils.md diff --git a/.changeset/patch-consolidate-shell-utils.md b/.changeset/patch-consolidate-shell-utils.md new file mode 100644 index 0000000000..4d54fd006c --- /dev/null +++ b/.changeset/patch-consolidate-shell-utils.md @@ -0,0 +1,5 @@ +--- +"gh-aw": patch +--- + +Consolidate shell escaping utilities into `shell.go` and remove the duplicate helpers in `mcp_utilities.go` so the generator and tests use a single source of truth.