Skip to content

gemini: use topology hostname for MCP_GATEWAY_HOST_DOMAIN under network isolation - #48775

Merged
pelikhan merged 3 commits into
mainfrom
copilot/fix-egress-firewall-issue
Jul 29, 2026
Merged

gemini: use topology hostname for MCP_GATEWAY_HOST_DOMAIN under network isolation#48775
pelikhan merged 3 commits into
mainfrom
copilot/fix-egress-firewall-issue

Conversation

Copilot AI commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Under network isolation, the Gemini CLI was routing MCP gateway connections (localhost:8080) through the squid egress proxy — generating 60–72 TCP_DENIED firewall entries per run. Root cause: Gemini honors HTTP_PROXY but ignores NO_PROXY, so loopback traffic is still proxied.

Changes

  • pkg/workflow/mcp_setup_gateway.go — In writeMCPGatewayExports, add a Gemini-specific branch: when isAWFNetworkIsolationEnabled and engine.GetID() == "gemini", set MCP_GATEWAY_HOST_DOMAIN to the resolved domain (awmg-mcpg) rather than localhost. The awmg-mcpg topology hostname is already in the squid allowlist via the auto-allow-topology-hostnames ACL.

    } else if engine.GetID() == "gemini" && isAWFNetworkIsolationEnabled(workflowData) {
        // Gemini honors HTTP_PROXY but ignores NO_PROXY; localhost would be proxied
        // through squid and denied. awmg-mcpg is already in the firewall allowlist.
        hostDomain = domain
    } else if domain == "host.docker.internal" || isAWFNetworkIsolationEnabled(workflowData) {
        hostDomain = "localhost"
    }
  • pkg/workflow/mcp_setup_generator_test.go — New integration test TestMCPGatewayDockerCommandGeminiNetworkIsolationUsesTopologyHostname asserting MCP_GATEWAY_HOST_DOMAIN="awmg-mcpg" (not localhost) for Gemini under network isolation.

  • .github/workflows/smoke-gemini.lock.yml — Recompiled; now emits awmg-mcpg for MCP_GATEWAY_HOST_DOMAIN.

…der network isolation

When network isolation is active and the engine is Gemini, set
MCP_GATEWAY_HOST_DOMAIN to the topology hostname (awmg-mcpg) instead
of localhost. The Gemini CLI honors HTTP_PROXY but ignores NO_PROXY,
causing localhost:8080 to be tunneled through the squid egress proxy
which denies it (60+ TCP_DENIED per run). The awmg-mcpg topology
hostname is already in the firewall allowlist.

Closes #48751

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix Gemini engine MCP gateway access issue due to egress firewall gemini: use topology hostname for MCP_GATEWAY_HOST_DOMAIN under network isolation Jul 29, 2026
Copilot AI requested a review from pelikhan July 29, 2026 06:21
@pelikhan
pelikhan marked this pull request as ready for review July 29, 2026 06:25
Copilot AI review requested due to automatic review settings July 29, 2026 06:25

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes Gemini MCP gateway routing under network isolation by using the allowlisted topology hostname instead of proxied loopback traffic.

Changes:

  • Selects awmg-mcpg for isolated Gemini workflows.
  • Adds integration coverage for the routing behavior.
  • Recompiles the Gemini smoke workflow.
Show a summary per file
File Description
pkg/workflow/mcp_setup_gateway.go Adds Gemini-specific isolated routing.
pkg/workflow/mcp_setup_generator_test.go Verifies topology-hostname generation.
.github/workflows/smoke-gemini.lock.yml Applies the generated hostname change.

Review details

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 3/3 changed files
  • Comments generated: 1
  • Review effort level: Medium

Comment on lines +163 to +165
} else if engine.GetID() == "gemini" && isAWFNetworkIsolationEnabled(workflowData) {
// domain is "awmg-mcpg" when network isolation is active; preserve it.
hostDomain = domain
@pelikhan

Copy link
Copy Markdown
Collaborator

/smoke-gemini

@github-actions

github-actions Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

🚀 Smoke Gemini MISSION COMPLETE! Gemini has spoken. ✨

@github-actions

github-actions Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Test Quality Sentinel completed test quality analysis.

@github-actions

github-actions Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

@github-actions

github-actions Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Design Decision Gate 🏗️ completed the design decision gate check.

No ADR enforcement needed: PR #48775 does not have the 'implementation' label and has ≤100 new lines of code in business logic directories (51 additions detected, threshold is 100).

@github-actions

github-actions Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

PR Code Quality Reviewer completed the code quality review.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fix is correct and well-targeted.

  • The new gemini + network-isolation branch in writeMCPGatewayExports correctly intercepts before the generic localhost override, preserving awmg-mcpg as MCP_GATEWAY_HOST_DOMAIN.
  • The shell script already dereferences $MCP_GATEWAY_HOST_DOMAIN dynamically, so no shell-side changes are needed.
  • New test covers the regression path clearly.
  • Lock file recompile is consistent.

The existing Copilot review comment about stale inline docs in the shell script is a minor nit — not blocking.

🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · sonnet46 · 17.1 AIC · ⌖ 5.68 AIC · ⊞ 5K

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Skills-Based Review 🧠

Applied /diagnosing-bugs and /tdd — commenting with one improvement suggestion.

📋 Key Themes & Highlights

Key Themes

  • Root cause addressed correctly: The fix targets the real issue (Gemini honoring HTTP_PROXY but ignoring NO_PROXY) rather than a workaround. Using the topology hostname that is already in the squid allowlist is the right approach.
  • Test coverage gap: The new test covers the network-isolation case but leaves the non-isolated Gemini path untested — a counterpart test would complete the specification.

Positive Highlights

  • ✅ Conditional is narrow and precise: only triggers for engine == "gemini" && networkIsolationEnabled; no other paths affected
  • ✅ Excellent inline comments explaining the HTTP_PROXY/NO_PROXY asymmetry
  • ✅ Integration test uses require.NotContains as well as require.Contains — both sides of the assertion are covered for the isolation case
  • ✅ Lock file recompiled and included in the PR

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · sonnet46 · 32.5 AIC · ⌖ 4.81 AIC · ⊞ 6.7K
Comment /matt to run again

require.Contains(t, yamlStr, `export MCP_GATEWAY_HOST_DOMAIN="awmg-mcpg"`,
"Gemini MCP_GATEWAY_HOST_DOMAIN must use awmg-mcpg under network isolation so the Gemini CLI does not tunnel localhost through the squid egress proxy")
require.NotContains(t, yamlStr, `export MCP_GATEWAY_HOST_DOMAIN="localhost"`,
"Gemini MCP_GATEWAY_HOST_DOMAIN must not be localhost under network isolation")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/tdd] Missing counterpart test: Gemini without network isolation should still resolve MCP_GATEWAY_HOST_DOMAIN to localhost — there is no test asserting this.

💡 Suggested test

Adding a test for the non-isolated Gemini path guards against a future refactor accidentally routing non-isolated runs through the topology hostname.

func TestMCPGatewayDockerCommandGeminiWithoutNetworkIsolationUsesLocalhost(t *testing.T) {
	frontmatter := `---
on: workflow_dispatch
engine: gemini
sandbox:
  agent:
    sudo: false
tools:
  github:
    mode: remote
    toolsets: [repos]
---

# Test Gemini Without Network Isolation
`
	compiler := NewCompiler()
	tmpDir := t.TempDir()
	inputFile := filepath.Join(tmpDir, "test.md")
	err := os.WriteFile(inputFile, []byte(frontmatter), 0644)
	require.NoError(t, err)
	err = compiler.CompileWorkflow(inputFile)
	require.NoError(t, err)
	outputFile := stringutil.MarkdownToLockFile(inputFile)
	content, err := os.ReadFile(outputFile)
	require.NoError(t, err)
	yamlStr := string(content)
	require.Contains(t, yamlStr, `export MCP_GATEWAY_HOST_DOMAIN="localhost"`,
		"Gemini MCP_GATEWAY_HOST_DOMAIN must be localhost when network isolation is NOT active")
}

@copilot please address this.

@github-actions

Copy link
Copy Markdown
Contributor

🧪 Test Quality Sentinel Report

Test Quality Score: 90/100 — Excellent

Analyzed 1 test(s): 1 design, 0 implementation, 0 violation(s).

📊 Metrics (1 test)
Metric Value
Analyzed 1 (Go: 1, JS: 0)
✅ Design 1 (100%)
⚠️ Implementation 0 (0%)
Edge/error coverage 1 (100%)
Duplicate clusters 0
Inflation Yes (44 test lines vs 7 prod lines, ~6:1)
🚨 Violations 0
Test File Classification Issues
TestMCPGatewayDockerCommandGeminiNetworkIsolationUsesTopologyHostname pkg/workflow/mcp_setup_generator_test.go behavioral_contract, high_value, design_test Inflation ratio ~6:1 (typical for compiled-workflow integration tests)

Verdict

passed. 0% implementation tests (threshold: 30%). The new test enforces the Gemini-specific MCP_GATEWAY_HOST_DOMAIN=awmg-mcpg contract with both a positive assertion and a negative guard against localhost, directly covering the regression path.

🧪 Test quality analysis by Test Quality Sentinel · sonnet46 · 27.9 AIC · ⌖ 10.6 AIC · ⊞ 8.1K ·
Comment /review to run again

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Test Quality Sentinel: 90/100. 0% implementation tests (threshold: 30%).

@github-actions

This comment has been minimized.

@github-actions github-actions Bot mentioned this pull request Jul 29, 2026

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

REQUEST_CHANGES — the core fix direction is reasonable, but leaves a stale companion shell script that contradicts the new behavior and lacks test coverage for adjacent branches (docker-sbx+gemini, non-isolated gemini, other engines under isolation).

Themes
  • Blocking: actions/setup/sh/convert_gateway_config_gemini.sh still documents/defaults MCP_GATEWAY_HOST_DOMAIN to localhost for Gemini, directly contradicting the new awmg-mcpg exception added in Go. This is a known, previously-flagged (unresolved) inconsistency (Copilot review comment id 3671570844) that risks silently reintroducing the exact TCP_DENIED bug this PR aims to fix if the env var handling ever diverges.
  • Test coverage is one-sided: only the new "happy path" (Gemini + isolation → awmg-mcpg) is asserted. No test proves the branch ordering against isDockerSbxRuntime, that non-isolated Gemini still gets localhost, or that other engines are unaffected.
  • Minor: the new condition uses a bare "gemini" string literal rather than the constants.GeminiEngine constant already used elsewhere in the codebase for the same purpose.

🔎 Code quality review by PR Code Quality Reviewer · sonnet50 · 94.2 AIC · ⌖ 4.68 AIC · ⊞ 7.4K
Comment /review to run again

Comments that could not be inline-anchored

pkg/workflow/mcp_setup_gateway.go:163

This exception fixes the Go side but leaves convert_gateway_config_gemini.sh untouched, whose comments and fallback default still assume localhost — silently reintroducing the exact TCP_DENIED bug if the env var is ever unset.

<details>
<summary>💡 Stale companion script contradicts this fix</summary>

actions/setup/sh/convert_gateway_config_gemini.sh (not part of this diff) still says:

# Optional environment variables:
# - MCP_GATEWAY_HOST_DOMAIN: Host-side domain for Gemini MCP …

</details>

<details><summary>pkg/workflow/mcp_setup_generator_test.go:84</summary>

Missing regression tests leave the branch ordering (docker-sbx &gt; gemini-isolation &gt; generic-isolation) and non-Gemini engines unverified.

&lt;details&gt;
&lt;summary&gt;💡 Gaps in test coverage for the new branch&lt;/summary&gt;

The new `else if engine.GetID() == &quot;gemini&quot; &amp;&amp; isAWFNetworkIsolationEnabled(...)` branch sits between the `isDockerSbxRuntime` check and the generic `isAWFNetworkIsolationEnabled` fallback, but no test in this PR covers:

1. Gemini + docker-sbx combined (does docker-sbx correctly still…

</details>

<details><summary>pkg/workflow/mcp_setup_gateway.go:163</summary>

`engine.GetID() == &quot;gemini&quot;` uses a bare string literal instead of the existing `constants.GeminiEngine` constant already used elsewhere in this same package.

&lt;details&gt;
&lt;summary&gt;💡 Fragile magic-string engine comparison&lt;/summary&gt;

`pkg/workflow/gemini_engine.go` (in the very call chain that reaches this function) already uses `constants.GeminiEngine` for engine-name comparisons, e.g. `GetAllowedDomainsForEngine(constants.GeminiEngine, ...)`. Comparing against the bare string `&quot;gemini&quot;` here in…

</details>

@pelikhan

Copy link
Copy Markdown
Collaborator

@copilot
make wasm golden test more resilient
run pr-finisher skill

@github-actions

Copy link
Copy Markdown
Contributor

Triage

Category: bug | Risk: medium | Score: 72/100

  • Impact: 28/50 (Gemini engine networking fix - MCP gateway hostname under network isolation)
  • Urgency: 24/30 (mergeable_state blocked; CI mostly green with one pending check; network-isolation correctness bug)
  • Quality: 20/20 (27/29 checks passing, has APPROVED review from github-actions bot)

Recommended action: fast_track - network isolation bug fix with strong CI signal and an approval; expedite human review.

Generated by 🔧 PR Triage Agent · sonnet50 · 38.4 AIC · ⌖ 4.62 AIC · ⊞ 7.5K ·

…ork isolation

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>

Copilot AI commented Jul 29, 2026

Copy link
Copy Markdown
Contributor Author

@copilot
make wasm golden test more resilient
run pr-finisher skill

Done in commit Fix wasm golden test and update shell script comments for Gemini network isolation:

  1. Wasm golden test: Updated pkg/workflow/testdata/TestWasmGolden_AllEngines/gemini.golden to expect MCP_GATEWAY_HOST_DOMAIN="awmg-mcpg" (the correct value under network isolation). All wasm golden tests pass.

  2. Shell script comments (actions/setup/sh/convert_gateway_config_gemini.sh): Updated the routing contract comment to document the network-isolation exception — MCP_GATEWAY_HOST_DOMAIN is localhost under normal conditions but awmg-mcpg (topology hostname) under network isolation, with the reason why (Gemini honors HTTP_PROXY but ignores NO_PROXY).

Local validation: fmt, test-unit, and recompile all pass.

@pelikhan

Copy link
Copy Markdown
Collaborator

/smoke-gemini

@github-actions

github-actions Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

🚀 Smoke Gemini MISSION COMPLETE! Gemini has spoken. ✨

@github-actions

Copy link
Copy Markdown
Contributor

Smoke Test Results

  • Test 1: ✅
  • Test 2: ✅
  • Test 3: ✅
  • Test 4: ✅
  • Test 5: ❌
    Overall status: FAIL

Smoke Gemini — Powered by Gemini · age00 · 11.3 AIC · ⌖ 1.57 AIC · ⊞ 9.3K ·
Comment /smoke-gemini to run again

@pelikhan
pelikhan merged commit 5faeff9 into main Jul 29, 2026
16 checks passed
@pelikhan
pelikhan deleted the copilot/fix-egress-firewall-issue branch July 29, 2026 08:02
@github-actions

Copy link
Copy Markdown
Contributor

🎉 This pull request is included in a new release.

Release: v0.83.5

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Gemini engine: MCP gateway addressed as localhost:8080 is denied by the egress firewall (60+ TCP_DENIED per run)

3 participants