diff --git a/.changeset/patch-log-gh-cli-version.md b/.changeset/patch-log-gh-cli-version.md new file mode 100644 index 0000000000..22476d5817 --- /dev/null +++ b/.changeset/patch-log-gh-cli-version.md @@ -0,0 +1,5 @@ +--- +"gh-aw": patch +--- + +Log the host gh CLI availability when starting `gh aw mcp-server` and ensure the agentic-workflows MCP configuration mounts the host `gh` binary so in-container tools can invoke it. diff --git a/.github/workflows/agent-performance-analyzer.lock.yml b/.github/workflows/agent-performance-analyzer.lock.yml index 483fd76cc2..6eba39295d 100644 --- a/.github/workflows/agent-performance-analyzer.lock.yml +++ b/.github/workflows/agent-performance-analyzer.lock.yml @@ -547,7 +547,7 @@ jobs: "container": "alpine:latest", "entrypoint": "/opt/gh-aw/gh-aw", "entrypointArgs": ["mcp-server"], - "mounts": ["/opt/gh-aw:/opt/gh-aw:ro", "${{ github.workspace }}:${{ github.workspace }}:rw", "/tmp/gh-aw:/tmp/gh-aw:rw"], + "mounts": ["/opt/gh-aw:/opt/gh-aw:ro", "/usr/bin/gh:/usr/bin/gh:ro", "${{ github.workspace }}:${{ github.workspace }}:rw", "/tmp/gh-aw:/tmp/gh-aw:rw"], "env": { "GITHUB_TOKEN": "\${GITHUB_TOKEN}" } diff --git a/.github/workflows/agent-persona-explorer.lock.yml b/.github/workflows/agent-persona-explorer.lock.yml index c2f2ee294a..503ca0e036 100644 --- a/.github/workflows/agent-persona-explorer.lock.yml +++ b/.github/workflows/agent-persona-explorer.lock.yml @@ -441,7 +441,7 @@ jobs: "container": "alpine:latest", "entrypoint": "/opt/gh-aw/gh-aw", "entrypointArgs": ["mcp-server"], - "mounts": ["/opt/gh-aw:/opt/gh-aw:ro", "${{ github.workspace }}:${{ github.workspace }}:rw", "/tmp/gh-aw:/tmp/gh-aw:rw"], + "mounts": ["/opt/gh-aw:/opt/gh-aw:ro", "/usr/bin/gh:/usr/bin/gh:ro", "${{ github.workspace }}:${{ github.workspace }}:rw", "/tmp/gh-aw:/tmp/gh-aw:rw"], "env": { "GITHUB_TOKEN": "\${GITHUB_TOKEN}" } diff --git a/.github/workflows/audit-workflows.lock.yml b/.github/workflows/audit-workflows.lock.yml index 1003428216..f221c5f0e2 100644 --- a/.github/workflows/audit-workflows.lock.yml +++ b/.github/workflows/audit-workflows.lock.yml @@ -508,7 +508,7 @@ jobs: "container": "alpine:latest", "entrypoint": "/opt/gh-aw/gh-aw", "entrypointArgs": ["mcp-server"], - "mounts": ["/opt/gh-aw:/opt/gh-aw:ro", "${{ github.workspace }}:${{ github.workspace }}:rw", "/tmp/gh-aw:/tmp/gh-aw:rw"], + "mounts": ["/opt/gh-aw:/opt/gh-aw:ro", "/usr/bin/gh:/usr/bin/gh:ro", "${{ github.workspace }}:${{ github.workspace }}:rw", "/tmp/gh-aw:/tmp/gh-aw:rw"], "env": { "GITHUB_TOKEN": "$GITHUB_TOKEN" } diff --git a/.github/workflows/cloclo.lock.yml b/.github/workflows/cloclo.lock.yml index 719a5db037..544e46478d 100644 --- a/.github/workflows/cloclo.lock.yml +++ b/.github/workflows/cloclo.lock.yml @@ -555,7 +555,7 @@ jobs: "container": "alpine:latest", "entrypoint": "/opt/gh-aw/gh-aw", "entrypointArgs": ["mcp-server"], - "mounts": ["/opt/gh-aw:/opt/gh-aw:ro", "${{ github.workspace }}:${{ github.workspace }}:rw", "/tmp/gh-aw:/tmp/gh-aw:rw"], + "mounts": ["/opt/gh-aw:/opt/gh-aw:ro", "/usr/bin/gh:/usr/bin/gh:ro", "${{ github.workspace }}:${{ github.workspace }}:rw", "/tmp/gh-aw:/tmp/gh-aw:rw"], "env": { "GITHUB_TOKEN": "$GITHUB_TOKEN" } diff --git a/.github/workflows/daily-firewall-report.lock.yml b/.github/workflows/daily-firewall-report.lock.yml index 973f5090cc..512117bea1 100644 --- a/.github/workflows/daily-firewall-report.lock.yml +++ b/.github/workflows/daily-firewall-report.lock.yml @@ -494,7 +494,7 @@ jobs: "container": "alpine:latest", "entrypoint": "/opt/gh-aw/gh-aw", "entrypointArgs": ["mcp-server"], - "mounts": ["/opt/gh-aw:/opt/gh-aw:ro", "${{ github.workspace }}:${{ github.workspace }}:rw", "/tmp/gh-aw:/tmp/gh-aw:rw"], + "mounts": ["/opt/gh-aw:/opt/gh-aw:ro", "/usr/bin/gh:/usr/bin/gh:ro", "${{ github.workspace }}:${{ github.workspace }}:rw", "/tmp/gh-aw:/tmp/gh-aw:rw"], "env": { "GITHUB_TOKEN": "\${GITHUB_TOKEN}" } diff --git a/.github/workflows/daily-observability-report.lock.yml b/.github/workflows/daily-observability-report.lock.yml index e9259f4490..4b37309885 100644 --- a/.github/workflows/daily-observability-report.lock.yml +++ b/.github/workflows/daily-observability-report.lock.yml @@ -523,7 +523,7 @@ jobs: "container": "alpine:latest", "entrypoint": "/opt/gh-aw/gh-aw", "entrypointArgs": ["mcp-server"], - "mounts": ["/opt/gh-aw:/opt/gh-aw:ro", "${{ github.workspace }}:${{ github.workspace }}:rw", "/tmp/gh-aw:/tmp/gh-aw:rw"], + "mounts": ["/opt/gh-aw:/opt/gh-aw:ro", "/usr/bin/gh:/usr/bin/gh:ro", "${{ github.workspace }}:${{ github.workspace }}:rw", "/tmp/gh-aw:/tmp/gh-aw:rw"], "env": { "GITHUB_TOKEN": "$GITHUB_TOKEN" } diff --git a/.github/workflows/daily-safe-output-optimizer.lock.yml b/.github/workflows/daily-safe-output-optimizer.lock.yml index 08dad0149e..c30b9e3dc3 100644 --- a/.github/workflows/daily-safe-output-optimizer.lock.yml +++ b/.github/workflows/daily-safe-output-optimizer.lock.yml @@ -474,7 +474,7 @@ jobs: "container": "alpine:latest", "entrypoint": "/opt/gh-aw/gh-aw", "entrypointArgs": ["mcp-server"], - "mounts": ["/opt/gh-aw:/opt/gh-aw:ro", "${{ github.workspace }}:${{ github.workspace }}:rw", "/tmp/gh-aw:/tmp/gh-aw:rw"], + "mounts": ["/opt/gh-aw:/opt/gh-aw:ro", "/usr/bin/gh:/usr/bin/gh:ro", "${{ github.workspace }}:${{ github.workspace }}:rw", "/tmp/gh-aw:/tmp/gh-aw:rw"], "env": { "GITHUB_TOKEN": "$GITHUB_TOKEN" } diff --git a/.github/workflows/deep-report.lock.yml b/.github/workflows/deep-report.lock.yml index 813f67ae21..b09d078ed9 100644 --- a/.github/workflows/deep-report.lock.yml +++ b/.github/workflows/deep-report.lock.yml @@ -597,7 +597,7 @@ jobs: "container": "alpine:latest", "entrypoint": "/opt/gh-aw/gh-aw", "entrypointArgs": ["mcp-server"], - "mounts": ["/opt/gh-aw:/opt/gh-aw:ro", "${{ github.workspace }}:${{ github.workspace }}:rw", "/tmp/gh-aw:/tmp/gh-aw:rw"], + "mounts": ["/opt/gh-aw:/opt/gh-aw:ro", "/usr/bin/gh:/usr/bin/gh:ro", "${{ github.workspace }}:${{ github.workspace }}:rw", "/tmp/gh-aw:/tmp/gh-aw:rw"], "env": { "GITHUB_TOKEN": "$GITHUB_TOKEN" } diff --git a/.github/workflows/dev-hawk.lock.yml b/.github/workflows/dev-hawk.lock.yml index d22de4630f..1ce4c0b835 100644 --- a/.github/workflows/dev-hawk.lock.yml +++ b/.github/workflows/dev-hawk.lock.yml @@ -415,7 +415,7 @@ jobs: "container": "alpine:latest", "entrypoint": "/opt/gh-aw/gh-aw", "entrypointArgs": ["mcp-server"], - "mounts": ["/opt/gh-aw:/opt/gh-aw:ro", "${{ github.workspace }}:${{ github.workspace }}:rw", "/tmp/gh-aw:/tmp/gh-aw:rw"], + "mounts": ["/opt/gh-aw:/opt/gh-aw:ro", "/usr/bin/gh:/usr/bin/gh:ro", "${{ github.workspace }}:${{ github.workspace }}:rw", "/tmp/gh-aw:/tmp/gh-aw:rw"], "env": { "GITHUB_TOKEN": "\${GITHUB_TOKEN}" } diff --git a/.github/workflows/example-workflow-analyzer.lock.yml b/.github/workflows/example-workflow-analyzer.lock.yml index b95256b230..9ccb2a7235 100644 --- a/.github/workflows/example-workflow-analyzer.lock.yml +++ b/.github/workflows/example-workflow-analyzer.lock.yml @@ -431,7 +431,7 @@ jobs: "container": "alpine:latest", "entrypoint": "/opt/gh-aw/gh-aw", "entrypointArgs": ["mcp-server"], - "mounts": ["/opt/gh-aw:/opt/gh-aw:ro", "${{ github.workspace }}:${{ github.workspace }}:rw", "/tmp/gh-aw:/tmp/gh-aw:rw"], + "mounts": ["/opt/gh-aw:/opt/gh-aw:ro", "/usr/bin/gh:/usr/bin/gh:ro", "${{ github.workspace }}:${{ github.workspace }}:rw", "/tmp/gh-aw:/tmp/gh-aw:rw"], "env": { "GITHUB_TOKEN": "$GITHUB_TOKEN" } diff --git a/.github/workflows/mcp-inspector.lock.yml b/.github/workflows/mcp-inspector.lock.yml index 1df4f54bbf..4a5c7f4656 100644 --- a/.github/workflows/mcp-inspector.lock.yml +++ b/.github/workflows/mcp-inspector.lock.yml @@ -509,7 +509,7 @@ jobs: "container": "alpine:latest", "entrypoint": "/opt/gh-aw/gh-aw", "entrypointArgs": ["mcp-server"], - "mounts": ["/opt/gh-aw:/opt/gh-aw:ro", "${{ github.workspace }}:${{ github.workspace }}:rw", "/tmp/gh-aw:/tmp/gh-aw:rw"], + "mounts": ["/opt/gh-aw:/opt/gh-aw:ro", "/usr/bin/gh:/usr/bin/gh:ro", "${{ github.workspace }}:${{ github.workspace }}:rw", "/tmp/gh-aw:/tmp/gh-aw:rw"], "env": { "GITHUB_TOKEN": "\${GITHUB_TOKEN}" } diff --git a/.github/workflows/metrics-collector.lock.yml b/.github/workflows/metrics-collector.lock.yml index b9966d89c8..57b56c0e90 100644 --- a/.github/workflows/metrics-collector.lock.yml +++ b/.github/workflows/metrics-collector.lock.yml @@ -212,7 +212,7 @@ jobs: "container": "alpine:latest", "entrypoint": "/opt/gh-aw/gh-aw", "entrypointArgs": ["mcp-server"], - "mounts": ["/opt/gh-aw:/opt/gh-aw:ro", "${{ github.workspace }}:${{ github.workspace }}:rw", "/tmp/gh-aw:/tmp/gh-aw:rw"], + "mounts": ["/opt/gh-aw:/opt/gh-aw:ro", "/usr/bin/gh:/usr/bin/gh:ro", "${{ github.workspace }}:${{ github.workspace }}:rw", "/tmp/gh-aw:/tmp/gh-aw:rw"], "env": { "GITHUB_TOKEN": "\${GITHUB_TOKEN}" } diff --git a/.github/workflows/portfolio-analyst.lock.yml b/.github/workflows/portfolio-analyst.lock.yml index eccc48b054..8c74d3b349 100644 --- a/.github/workflows/portfolio-analyst.lock.yml +++ b/.github/workflows/portfolio-analyst.lock.yml @@ -501,7 +501,7 @@ jobs: "container": "alpine:latest", "entrypoint": "/opt/gh-aw/gh-aw", "entrypointArgs": ["mcp-server"], - "mounts": ["/opt/gh-aw:/opt/gh-aw:ro", "${{ github.workspace }}:${{ github.workspace }}:rw", "/tmp/gh-aw:/tmp/gh-aw:rw"], + "mounts": ["/opt/gh-aw:/opt/gh-aw:ro", "/usr/bin/gh:/usr/bin/gh:ro", "${{ github.workspace }}:${{ github.workspace }}:rw", "/tmp/gh-aw:/tmp/gh-aw:rw"], "env": { "GITHUB_TOKEN": "\${GITHUB_TOKEN}" } diff --git a/.github/workflows/prompt-clustering-analysis.lock.yml b/.github/workflows/prompt-clustering-analysis.lock.yml index b39cd255b7..9e9841441f 100644 --- a/.github/workflows/prompt-clustering-analysis.lock.yml +++ b/.github/workflows/prompt-clustering-analysis.lock.yml @@ -498,7 +498,7 @@ jobs: "container": "alpine:latest", "entrypoint": "/opt/gh-aw/gh-aw", "entrypointArgs": ["mcp-server"], - "mounts": ["/opt/gh-aw:/opt/gh-aw:ro", "${{ github.workspace }}:${{ github.workspace }}:rw", "/tmp/gh-aw:/tmp/gh-aw:rw"], + "mounts": ["/opt/gh-aw:/opt/gh-aw:ro", "/usr/bin/gh:/usr/bin/gh:ro", "${{ github.workspace }}:${{ github.workspace }}:rw", "/tmp/gh-aw:/tmp/gh-aw:rw"], "env": { "GITHUB_TOKEN": "$GITHUB_TOKEN" } diff --git a/.github/workflows/python-data-charts.lock.yml b/.github/workflows/python-data-charts.lock.yml index 1a95d0250e..ac61c8da4f 100644 --- a/.github/workflows/python-data-charts.lock.yml +++ b/.github/workflows/python-data-charts.lock.yml @@ -489,7 +489,7 @@ jobs: "container": "alpine:latest", "entrypoint": "/opt/gh-aw/gh-aw", "entrypointArgs": ["mcp-server"], - "mounts": ["/opt/gh-aw:/opt/gh-aw:ro", "${{ github.workspace }}:${{ github.workspace }}:rw", "/tmp/gh-aw:/tmp/gh-aw:rw"], + "mounts": ["/opt/gh-aw:/opt/gh-aw:ro", "/usr/bin/gh:/usr/bin/gh:ro", "${{ github.workspace }}:${{ github.workspace }}:rw", "/tmp/gh-aw:/tmp/gh-aw:rw"], "env": { "GITHUB_TOKEN": "\${GITHUB_TOKEN}" } diff --git a/.github/workflows/q.lock.yml b/.github/workflows/q.lock.yml index 7397252ffc..410c210483 100644 --- a/.github/workflows/q.lock.yml +++ b/.github/workflows/q.lock.yml @@ -538,7 +538,7 @@ jobs: "container": "alpine:latest", "entrypoint": "/opt/gh-aw/gh-aw", "entrypointArgs": ["mcp-server"], - "mounts": ["/opt/gh-aw:/opt/gh-aw:ro", "${{ github.workspace }}:${{ github.workspace }}:rw", "/tmp/gh-aw:/tmp/gh-aw:rw"], + "mounts": ["/opt/gh-aw:/opt/gh-aw:ro", "/usr/bin/gh:/usr/bin/gh:ro", "${{ github.workspace }}:${{ github.workspace }}:rw", "/tmp/gh-aw:/tmp/gh-aw:rw"], "env": { "GITHUB_TOKEN": "\${GITHUB_TOKEN}" } diff --git a/.github/workflows/safe-output-health.lock.yml b/.github/workflows/safe-output-health.lock.yml index b1035de863..d0a0fd64be 100644 --- a/.github/workflows/safe-output-health.lock.yml +++ b/.github/workflows/safe-output-health.lock.yml @@ -450,7 +450,7 @@ jobs: "container": "alpine:latest", "entrypoint": "/opt/gh-aw/gh-aw", "entrypointArgs": ["mcp-server"], - "mounts": ["/opt/gh-aw:/opt/gh-aw:ro", "${{ github.workspace }}:${{ github.workspace }}:rw", "/tmp/gh-aw:/tmp/gh-aw:rw"], + "mounts": ["/opt/gh-aw:/opt/gh-aw:ro", "/usr/bin/gh:/usr/bin/gh:ro", "${{ github.workspace }}:${{ github.workspace }}:rw", "/tmp/gh-aw:/tmp/gh-aw:rw"], "env": { "GITHUB_TOKEN": "$GITHUB_TOKEN" } diff --git a/.github/workflows/security-review.lock.yml b/.github/workflows/security-review.lock.yml index d64732e0a3..6bce31c825 100644 --- a/.github/workflows/security-review.lock.yml +++ b/.github/workflows/security-review.lock.yml @@ -529,7 +529,7 @@ jobs: "container": "alpine:latest", "entrypoint": "/opt/gh-aw/gh-aw", "entrypointArgs": ["mcp-server"], - "mounts": ["/opt/gh-aw:/opt/gh-aw:ro", "${{ github.workspace }}:${{ github.workspace }}:rw", "/tmp/gh-aw:/tmp/gh-aw:rw"], + "mounts": ["/opt/gh-aw:/opt/gh-aw:ro", "/usr/bin/gh:/usr/bin/gh:ro", "${{ github.workspace }}:${{ github.workspace }}:rw", "/tmp/gh-aw:/tmp/gh-aw:rw"], "env": { "GITHUB_TOKEN": "\${GITHUB_TOKEN}" } diff --git a/.github/workflows/smoke-claude.lock.yml b/.github/workflows/smoke-claude.lock.yml index 77f7702046..1b2e75a027 100644 --- a/.github/workflows/smoke-claude.lock.yml +++ b/.github/workflows/smoke-claude.lock.yml @@ -1132,7 +1132,7 @@ jobs: "container": "alpine:latest", "entrypoint": "/opt/gh-aw/gh-aw", "entrypointArgs": ["mcp-server"], - "mounts": ["/opt/gh-aw:/opt/gh-aw:ro", "${{ github.workspace }}:${{ github.workspace }}:rw", "/tmp/gh-aw:/tmp/gh-aw:rw"], + "mounts": ["/opt/gh-aw:/opt/gh-aw:ro", "/usr/bin/gh:/usr/bin/gh:ro", "${{ github.workspace }}:${{ github.workspace }}:rw", "/tmp/gh-aw:/tmp/gh-aw:rw"], "env": { "GITHUB_TOKEN": "$GITHUB_TOKEN" } diff --git a/.github/workflows/smoke-copilot.lock.yml b/.github/workflows/smoke-copilot.lock.yml index 19748cdccb..f176938575 100644 --- a/.github/workflows/smoke-copilot.lock.yml +++ b/.github/workflows/smoke-copilot.lock.yml @@ -1121,7 +1121,7 @@ jobs: "container": "alpine:latest", "entrypoint": "/opt/gh-aw/gh-aw", "entrypointArgs": ["mcp-server"], - "mounts": ["/opt/gh-aw:/opt/gh-aw:ro", "${{ github.workspace }}:${{ github.workspace }}:rw", "/tmp/gh-aw:/tmp/gh-aw:rw"], + "mounts": ["/opt/gh-aw:/opt/gh-aw:ro", "/usr/bin/gh:/usr/bin/gh:ro", "${{ github.workspace }}:${{ github.workspace }}:rw", "/tmp/gh-aw:/tmp/gh-aw:rw"], "env": { "GITHUB_TOKEN": "\${GITHUB_TOKEN}" } diff --git a/.github/workflows/static-analysis-report.lock.yml b/.github/workflows/static-analysis-report.lock.yml index d5ba799f06..5c102382a8 100644 --- a/.github/workflows/static-analysis-report.lock.yml +++ b/.github/workflows/static-analysis-report.lock.yml @@ -449,7 +449,7 @@ jobs: "container": "alpine:latest", "entrypoint": "/opt/gh-aw/gh-aw", "entrypointArgs": ["mcp-server"], - "mounts": ["/opt/gh-aw:/opt/gh-aw:ro", "${{ github.workspace }}:${{ github.workspace }}:rw", "/tmp/gh-aw:/tmp/gh-aw:rw"], + "mounts": ["/opt/gh-aw:/opt/gh-aw:ro", "/usr/bin/gh:/usr/bin/gh:ro", "${{ github.workspace }}:${{ github.workspace }}:rw", "/tmp/gh-aw:/tmp/gh-aw:rw"], "env": { "GITHUB_TOKEN": "$GITHUB_TOKEN" } diff --git a/.github/workflows/workflow-normalizer.lock.yml b/.github/workflows/workflow-normalizer.lock.yml index 7e0a1bb42b..ebd4e3b914 100644 --- a/.github/workflows/workflow-normalizer.lock.yml +++ b/.github/workflows/workflow-normalizer.lock.yml @@ -448,7 +448,7 @@ jobs: "container": "alpine:latest", "entrypoint": "/opt/gh-aw/gh-aw", "entrypointArgs": ["mcp-server"], - "mounts": ["/opt/gh-aw:/opt/gh-aw:ro", "${{ github.workspace }}:${{ github.workspace }}:rw", "/tmp/gh-aw:/tmp/gh-aw:rw"], + "mounts": ["/opt/gh-aw:/opt/gh-aw:ro", "/usr/bin/gh:/usr/bin/gh:ro", "${{ github.workspace }}:${{ github.workspace }}:rw", "/tmp/gh-aw:/tmp/gh-aw:rw"], "env": { "GITHUB_TOKEN": "\${GITHUB_TOKEN}" } diff --git a/pkg/cli/mcp_server.go b/pkg/cli/mcp_server.go index 6452f22459..fbb316d73c 100644 --- a/pkg/cli/mcp_server.go +++ b/pkg/cli/mcp_server.go @@ -80,6 +80,26 @@ Examples: return cmd } +// checkAndLogGHVersion checks if gh CLI is available and logs its version +func checkAndLogGHVersion() { + cmd := workflow.ExecGH("version") + output, err := cmd.CombinedOutput() + + if err != nil { + mcpLog.Print("WARNING: gh CLI not found in PATH") + fmt.Fprintln(os.Stderr, console.FormatWarningMessage("gh CLI not found in PATH - some MCP server operations may fail")) + return + } + + // Parse and log the version + versionOutput := strings.TrimSpace(string(output)) + mcpLog.Printf("gh CLI version: %s", versionOutput) + + // Extract just the first line for cleaner logging to stderr + firstLine := strings.Split(versionOutput, "\n")[0] + fmt.Fprintln(os.Stderr, console.FormatInfoMessage(fmt.Sprintf("gh CLI: %s", firstLine))) +} + // runMCPServer starts the MCP server on stdio or HTTP transport func runMCPServer(port int, cmdPath string) error { if port > 0 { @@ -88,6 +108,9 @@ func runMCPServer(port int, cmdPath string) error { mcpLog.Print("Starting MCP server with stdio transport") } + // Check and log gh CLI version + checkAndLogGHVersion() + // Validate that the CLI and secrets are properly configured // Note: Validation failures are logged as warnings but don't prevent server startup // This allows the server to start in test environments or non-repository directories diff --git a/pkg/constants/constants.go b/pkg/constants/constants.go index 980b410c44..c670ed08ee 100644 --- a/pkg/constants/constants.go +++ b/pkg/constants/constants.go @@ -387,6 +387,10 @@ const DefaultAlpineImage = "alpine:latest" // The gh-aw binary and supporting files are mounted read-only from /opt/gh-aw const DefaultGhAwMount = "/opt/gh-aw:/opt/gh-aw:ro" +// DefaultGhBinaryMount is the mount path for the gh CLI binary in containerized MCP servers +// The gh CLI is required for agentic-workflows MCP server to run gh commands +const DefaultGhBinaryMount = "/usr/bin/gh:/usr/bin/gh:ro" + // DefaultTmpGhAwMount is the mount path for temporary gh-aw files in containerized MCP servers // Used for logs, cache, and other runtime data that needs read-write access const DefaultTmpGhAwMount = "/tmp/gh-aw:/tmp/gh-aw:rw" diff --git a/pkg/workflow/mcp_config_builtin.go b/pkg/workflow/mcp_config_builtin.go index 5826b30d26..0e4b1df40c 100644 --- a/pkg/workflow/mcp_config_builtin.go +++ b/pkg/workflow/mcp_config_builtin.go @@ -176,8 +176,8 @@ func renderAgenticWorkflowsMCPConfigWithOptions(yaml *strings.Builder, isLast bo yaml.WriteString(" \"container\": \"" + constants.DefaultAlpineImage + "\",\n") yaml.WriteString(" \"entrypoint\": \"/opt/gh-aw/gh-aw\",\n") yaml.WriteString(" \"entrypointArgs\": [\"mcp-server\"],\n") - // Mount gh-aw binary (read-only), workspace (read-write for status/compile), and temp directory (read-write for logs) - yaml.WriteString(" \"mounts\": [\"" + constants.DefaultGhAwMount + "\", \"" + constants.DefaultWorkspaceMount + "\", \"" + constants.DefaultTmpGhAwMount + "\"],\n") + // Mount gh-aw binary (read-only), gh CLI binary (read-only), workspace (read-write for status/compile), and temp directory (read-write for logs) + yaml.WriteString(" \"mounts\": [\"" + constants.DefaultGhAwMount + "\", \"" + constants.DefaultGhBinaryMount + "\", \"" + constants.DefaultWorkspaceMount + "\", \"" + constants.DefaultTmpGhAwMount + "\"],\n") // Note: tools field is NOT included here - the converter script adds it back // for Copilot. This keeps the gateway config compatible with the schema. @@ -230,8 +230,8 @@ func renderAgenticWorkflowsMCPConfigTOML(yaml *strings.Builder) { yaml.WriteString(" container = \"" + constants.DefaultAlpineImage + "\"\n") yaml.WriteString(" entrypoint = \"/opt/gh-aw/gh-aw\"\n") yaml.WriteString(" entrypointArgs = [\"mcp-server\"]\n") - // Mount gh-aw binary (read-only), workspace (read-write for status/compile), and temp directory (read-write for logs) - yaml.WriteString(" mounts = [\"" + constants.DefaultGhAwMount + "\", \"" + constants.DefaultWorkspaceMount + "\", \"" + constants.DefaultTmpGhAwMount + "\"]\n") + // Mount gh-aw binary (read-only), gh CLI binary (read-only), workspace (read-write for status/compile), and temp directory (read-write for logs) + yaml.WriteString(" mounts = [\"" + constants.DefaultGhAwMount + "\", \"" + constants.DefaultGhBinaryMount + "\", \"" + constants.DefaultWorkspaceMount + "\", \"" + constants.DefaultTmpGhAwMount + "\"]\n") // Use env_vars array to reference environment variables instead of embedding secrets yaml.WriteString(" env_vars = [\"GITHUB_TOKEN\"]\n") } diff --git a/pkg/workflow/mcp_config_refactor_test.go b/pkg/workflow/mcp_config_refactor_test.go index a9f8366bd9..6c9b4fd61e 100644 --- a/pkg/workflow/mcp_config_refactor_test.go +++ b/pkg/workflow/mcp_config_refactor_test.go @@ -107,6 +107,7 @@ func TestRenderAgenticWorkflowsMCPConfigWithOptions(t *testing.T) { `"entrypoint": "/opt/gh-aw/gh-aw"`, `"entrypointArgs": ["mcp-server"]`, `"/opt/gh-aw:/opt/gh-aw:ro"`, // gh-aw binary mount (read-only) + `"/usr/bin/gh:/usr/bin/gh:ro"`, // gh CLI binary mount (read-only) `"${{ github.workspace }}:${{ github.workspace }}:rw"`, // workspace mount (read-write) `"/tmp/gh-aw:/tmp/gh-aw:rw"`, // temp directory mount (read-write) `"GITHUB_TOKEN": "\${GITHUB_TOKEN}"`, @@ -127,6 +128,7 @@ func TestRenderAgenticWorkflowsMCPConfigWithOptions(t *testing.T) { `"entrypoint": "/opt/gh-aw/gh-aw"`, `"entrypointArgs": ["mcp-server"]`, `"/opt/gh-aw:/opt/gh-aw:ro"`, // gh-aw binary mount (read-only) + `"/usr/bin/gh:/usr/bin/gh:ro"`, // gh CLI binary mount (read-only) `"${{ github.workspace }}:${{ github.workspace }}:rw"`, // workspace mount (read-write) `"/tmp/gh-aw:/tmp/gh-aw:rw"`, // temp directory mount (read-write) // Security fix: Now uses shell variable instead of GitHub secret expression @@ -222,6 +224,7 @@ func TestRenderAgenticWorkflowsMCPConfigTOML(t *testing.T) { `entrypoint = "/opt/gh-aw/gh-aw"`, `entrypointArgs = ["mcp-server"]`, `"/opt/gh-aw:/opt/gh-aw:ro"`, // gh-aw binary mount (read-only) + `"/usr/bin/gh:/usr/bin/gh:ro"`, // gh CLI binary mount (read-only) `"${{ github.workspace }}:${{ github.workspace }}:rw"`, // workspace mount (read-write) `"/tmp/gh-aw:/tmp/gh-aw:rw"`, // temp directory mount (read-write) `env_vars = ["GITHUB_TOKEN"]`,