Skip to content

Add --gemini-api-target to AWF proxy for Gemini API routing#26060

Open
Copilot wants to merge 3 commits intomainfrom
copilot/deep-report-fix-gemini-proxy-handler
Open

Add --gemini-api-target to AWF proxy for Gemini API routing#26060
Copilot wants to merge 3 commits intomainfrom
copilot/deep-report-fix-gemini-proxy-handler

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 13, 2026

The AWF proxy sidecar has no handler for Gemini API requests. When engine: gemini runs with the firewall enabled, GEMINI_API_BASE_URL points at the proxy (port 10003), but the proxy has no routing target and returns API_KEY_INVALID. Unlike OpenAI/Anthropic/Copilot where AWF has built-in default routing, Gemini was never wired up.

Changes

  • pkg/workflow/awf_helpers.go — Add GetGeminiAPITarget() and emit --gemini-api-target generativelanguage.googleapis.com (default) or custom host from GEMINI_API_BASE_URL in engine.env. Also emit --gemini-api-base-path when the custom URL contains a path component.
  • pkg/workflow/domains.go — Include Gemini API target in computeAllowedDomainsForSanitization() so GH_AW_ALLOWED_DOMAINS stays in sync with --allow-domains.
  • pkg/workflow/awf_helpers_test.go — 10 new test cases: default target, custom target, non-Gemini engine exclusion, base path extraction, end-to-end engine integration.
  • docs/src/content/docs/reference/engines.md — Add GEMINI_API_BASE_URL to the custom API endpoint docs with example.
  • .github/workflows/smoke-gemini.lock.yml — Recompiled.

Before/After

AWF command for Gemini engine now includes the proxy routing target:

- sudo -E awf ... --enable-api-proxy \
+ sudo -E awf ... --enable-api-proxy --gemini-api-target generativelanguage.googleapis.com \

Custom endpoint support follows the same pattern as other engines:

engine:
  id: gemini
  env:
    GEMINI_API_BASE_URL: "https://gemini-proxy.internal.example.com"
    GEMINI_API_KEY: ${{ secrets.PROXY_API_KEY }}

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • https://api.github.com/graphql
    • Triggering command: /usr/bin/gh /usr/bin/gh api graphql -f query=query($owner: String!, $name: String!) { repository(owner: $owner, name: $name) { hasDiscussionsEnabled } } -f owner=github -f name=gh-aw (http block)
    • Triggering command: /usr/bin/gh /usr/bin/gh api graphql -f query=query($owner: String!, $name: String!) { repository(owner: $owner, name: $name) { hasDiscussionsEnabled } } -f owner=github -f name=gh-aw -pack /home/REDACTED/work/gh-aw/gh-aw/cmd/gh-aw/main.go tion (http block)
    • Triggering command: /usr/bin/gh /usr/bin/gh api graphql -f query=query($owner: String!, $name: String!) { repository(owner: $owner, name: $name) { hasDiscussionsEnabled } } -f owner=github -f name=gh-aw MKlWGnl/BXD6b_Ig-C (http block)
  • https://api.github.com/orgs/test-owner/actions/secrets
    • Triggering command: /usr/bin/gh gh api /orgs/test-owner/actions/secrets --jq .secrets[].name -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/actions/ai-inference/git/ref/tags/v1
    • Triggering command: /usr/bin/gh gh api /repos/actions/ai-inference/git/ref/tags/v1 --jq .object.sha --git-dir x_amd64/link /opt/hostedtoolcache/node/24.14.1/x64/bin/node -json .go 64/pkg/tool/linu--show-toplevel /opt/hostedtoolcache/node/24.14.1/x64/bin/node /tmp�� Secret: ${{ secrets.TOKEN }} pd/XJ3yBE12j21iuxq3TT-m/tggwGl4X-goversion /usr/bin/infocmp g_.a GO111MODULE 64/pkg/tool/linu--show-toplevel infocmp (http block)
  • https://api.github.com/repos/actions/checkout/git/ref/tags/v3
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v3 --jq .object.sha --show-toplevel -pack 4883175/b442/vet.cfg -json (http block)
  • https://api.github.com/repos/actions/checkout/git/ref/tags/v5
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha ortcfg aTWjRYknE ache/go/1.25.8/x64/pkg/tool/linux_amd64/compile GOINSECURE %H %ct %D (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha --show-toplevel 64/pkg/tool/linuremote.origin.url /usr/bin/git ut501644277/001 GO111MODULE 64/pkg/tool/linu--show-toplevel git rev-�� --show-toplevel 64/pkg/tool/linux_amd64/vet /usr/bin/git DIATz0CEW g/types/doc.go ache/go/1.25.8/x--show-toplevel git (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha --show-toplevel /opt/hostedtoolcache/go/1.25.8/x1 /usr/bin/git /tmp/go-build238git pkg/mod/github.crev-parse /opt/hostedtoolc--show-toplevel git rev-�� --show-toplevel /opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/compile /usr/bin/git /tmp/go-build238git -trimpath ache/node/24.14.--show-toplevel git (http block)
  • https://api.github.com/repos/actions/github-script/git/ref/tags/v8
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha --show-toplevel x_amd64/compile /usr/bin/git 7DvO3RCYu GO111MODULE x_amd64/compile git rev-�� --show-toplevel x_amd64/compile /usr/bin/git 5888407/b092/_pkgit om/modelcontextprev-parse ache/go/1.25.8/x--show-toplevel git (http block)
  • https://api.github.com/repos/actions/github-script/git/ref/tags/v9
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v9 --jq .object.sha go1.25.8 -c=4 -nolocalimports -importcfg /tmp/go-build2385888407/b254/importcfg -pack /home/REDACTED/go/pkg/mod/golang.org/x/mod@v0.34.0/semver/semver.go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v9 --jq .object.sha -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE x_amd64/compile GOINSECURE GOMOD GOMODCACHE x_amd64/compile (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v9 --jq .object.sha -json GO111MODULE 64/bin/go GOINSECURE GOMOD tomic_wasm.s go env -json GO111MODULE x_amd64/compile GOINSECURE GOMOD GOMODCACHE x_amd64/compile (http block)
  • https://api.github.com/repos/actions/setup-go/git/ref/tags/v4
    • Triggering command: /usr/bin/gh gh api /repos/actions/setup-go/git/ref/tags/v4 --jq .object.sha /home/REDACTED/work/gh-aw/gh-aw/.github/workflows/agent-performance-analyzer.md x_amd64/compile /usr/bin/git b/workflows GO111MODULE 64/bin/go git rev-�� --show-toplevel go /usr/bin/git cut -f1))" GO111MODULE x_amd64/compile git (http block)
  • https://api.github.com/repos/actions/setup-node/git/ref/tags/v4
    • Triggering command: /usr/bin/gh gh api /repos/actions/setup-node/git/ref/tags/v4 --jq .object.sha /home/REDACTED/work/gh-aw/gh-aw/.github/workflows/ace-editor.md resolved$ /usr/bin/git b/workflows GO111MODULE x_amd64/link git rev-�� --git-dir x_amd64/link /usr/bin/git -json GO111MODULE 64/pkg/tool/linu--show-toplevel git (http block)
  • https://api.github.com/repos/actions/upload-artifact/git/ref/tags/v4
    • Triggering command: /usr/bin/gh gh api /repos/actions/upload-artifact/git/ref/tags/v4 --jq .object.sha /tmp/go-build2594883175/b385/_pkg_.a -trimpath /usr/lib/git-core/git -p github.com/githurev-parse -lang=go1.25 /usr/lib/git-core/git pack�� --all-progress-implied --revs /usr/bin/git --thin --delta-base-offrev-parse -q git (http block)
  • https://api.github.com/repos/actions/upload-artifact/git/ref/tags/v7
    • Triggering command: /usr/bin/gh gh api /repos/actions/upload-artifact/git/ref/tags/v7 --jq .object.sha (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/upload-artifact/git/ref/tags/v7 --jq .object.sha d -n 10 (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/upload-artifact/git/ref/tags/v7 --jq .object.sha rt/assertion_com-errorsas rt/assertion_for-ifaceassert x_amd64/compile (http block)
  • https://api.github.com/repos/astral-sh/setup-uv/git/ref/tags/eac588ad8def6316056a12d4907a9d4d84ff7a3b
    • Triggering command: /usr/bin/gh gh api /repos/astral-sh/setup-uv/git/ref/tags/eac588ad8def6316056a12d4907a9d4d84ff7a3b --jq .object.sha (http block)
  • https://api.github.com/repos/docker/build-push-action/git/ref/tags/v7
    • Triggering command: /usr/bin/gh gh api /repos/docker/build-push-action/git/ref/tags/v7 --jq .object.sha (http block)
    • Triggering command: /usr/bin/gh gh api /repos/docker/build-push-action/git/ref/tags/v7 --jq .object.sha /home/REDACTED/work/_temp/runtime-logs/user.env (http block)
  • https://api.github.com/repos/github/gh-aw-actions/git/ref/tags/v0.1.2
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw-actions/git/ref/tags/v0.1.2 --jq .object.sha .github/workflows/test.md x_amd64/compile /usr/bin/git -json GO111MODULE x_amd64/compile git rev-�� --show-toplevel x_amd64/compile /usr/bin/git -json GO111MODULE 64/pkg/tool/linu--show-toplevel git (http block)
  • https://api.github.com/repos/github/gh-aw-actions/git/ref/tags/v1.0.0
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw-actions/git/ref/tags/v1.0.0 --jq .object.sha sistency_GoAndJavaScript1557550825/001/test-empty-frontmatter.md -trimpath ache/node/24.14.1/x64/bin/node -p main -lang=go1.25 git-receive-pack t-39�� bility_SameInputSameOutput259999310/001/stability-test.md -dwarf=false /usr/bin/git go1.25.8 -c=4 -nolocalimports git (http block)
  • https://api.github.com/repos/github/gh-aw-actions/git/ref/tags/v1.2.3
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw-actions/git/ref/tags/v1.2.3 --jq .object.sha -aw/git/ref/tags/v1.2.3 -trimpath ache/go/1.25.8/x64/pkg/tool/linux_amd64/compile -p github.com/githurev-parse -lang=go1.25 ache/go/1.25.8/x64/pkg/tool/linux_amd64/compile push�� 4883175/b449/_pkg_.a my-default 4883175/b449=> -c=4 -nolocalimports -importcfg git (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/1/artifacts
    • Triggering command: /usr/bin/gh gh api --paginate repos/{owner}/{repo}/actions/runs/1/artifacts --jq .artifacts[].name GO111MODULE 64/pkg/tool/linux_amd64/compile GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/compile env 1551247508 dAR9m3zY_ x_amd64/link GOINSECURE GOMOD GOMODCACHE x_amd64/link (http block)
    • Triggering command: /usr/bin/gh gh run download 1 --dir test-logs/run-1 ri/jsonschema/v6@v6.0.2/kind/kind.go 64/pkg/tool/linux_amd64/compile GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/compile env g_.a 64jHUho52 util.test GOINSECURE chema/v6 GOMODCACHE util.test (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/12345/artifacts
    • Triggering command: /usr/bin/gh gh api --paginate repos/{owner}/{repo}/actions/runs/12345/artifacts --jq .artifacts[].name GO111MODULE 64/pkg/tool/linux_amd64/compile GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/compile env ithub/workflows rrG8ct2Bi 64/pkg/tool/linux_amd64/compile GOINSECURE bidirule GOMODCACHE 64/pkg/tool/linuorigin (http block)
    • Triggering command: /usr/bin/gh gh run download 12345 --dir test-logs/run-12345 GO111MODULE 64/pkg/tool/linux_amd64/compile GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linuTest User env g_.a JtV1iahb4 x_amd64/compile GOINSECURE go-sdk/internal/rev-parse GOMODCACHE x_amd64/compile (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/12346/artifacts
    • Triggering command: /usr/bin/gh gh api --paginate repos/{owner}/{repo}/actions/runs/12346/artifacts --jq .artifacts[].name GO111MODULE 64/pkg/tool/linux_amd64/compile GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/compile env ithub/workflows o 64/pkg/tool/linux_amd64/compile GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linuTest User (http block)
    • Triggering command: /usr/bin/gh gh run download 12346 --dir test-logs/run-12346 rotocol/go-sdk@v1.5.0/internal/xcontext/xcontext.go 64/pkg/tool/linux_amd64/compile GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linutest@example.com env g_.a GO111MODULE /opt/hostedtoolcache/go/1.25.8/x64/bin/go GOINSECURE v3 abis go (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/2/artifacts
    • Triggering command: /usr/bin/gh gh api --paginate repos/{owner}/{repo}/actions/runs/2/artifacts --jq .artifacts[].name _3ywvdE5S 64/pkg/tool/linux_amd64/compile GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/compile env 1551247508 dq87ptaK6 64/pkg/tool/linux_amd64/vet GOINSECURE pguts GOMODCACHE 64/pkg/tool/linux_amd64/vet (http block)
    • Triggering command: /usr/bin/gh gh run download 2 --dir test-logs/run-2 0/internal/format/format.go 64/pkg/tool/linux_amd64/compile GOINSECURE exbyte_wasm.o 64/src/internal/--show-toplevel 64/pkg/tool/linux_amd64/compile env g_.a J9_2Hh5RJ 64/pkg/tool/linux_amd64/vet GOINSECURE (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/3/artifacts
    • Triggering command: /usr/bin/gh gh api --paginate repos/{owner}/{repo}/actions/runs/3/artifacts --jq .artifacts[].name _56Gjvce9 64/pkg/tool/linux_amd64/compile GOINSECURE GOMOD GOMODCACHE ylQP4Z8/vCNYLdc7D8RXanEmFBss env plorer.md LamLkoYmy ache/go/1.25.8/x64/pkg/tool/linux_amd64/compile GOINSECURE pproxy GOMODCACHE ache/go/1.25.8/x64/pkg/tool/linux_amd64/compile (http block)
    • Triggering command: /usr/bin/gh gh run download 3 --dir test-logs/run-3 0/internal/inter-nolocalimports 64/pkg/tool/linu-importcfg GOINSECURE al_wasm.o 64/src/internal/--show-toplevel 64/pkg/tool/linu/home/REDACTED/work/gh-aw/gh-aw/scripts/lint_error_messages_test.go env 3683132792/.github/workflows fG0BeREzZ ache/go/1.25.8/x64/pkg/tool/linu-lang=go1.25 GOINSECURE g GOMODCACHE ache/go/1.25.8/x64/pkg/tool/linu-dwarf=false (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/4/artifacts
    • Triggering command: /usr/bin/gh gh api --paginate repos/{owner}/{repo}/actions/runs/4/artifacts --jq .artifacts[].name SUy_HbpQE 64/pkg/tool/linux_amd64/compile GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linuTest User env plorer.md InX8DV7o_ ache/go/1.25.8/x64/pkg/tool/linux_amd64/asm GOINSECURE GOMOD GOMODCACHE ache/go/1.25.8/x64/pkg/tool/linux_amd64/asm (http block)
    • Triggering command: /usr/bin/gh gh run download 4 --dir test-logs/run-4 0/feature/plural/common.go 64/pkg/tool/linux_amd64/compile GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/compile env g_.a QuPWq4ACQ ache/go/1.25.8/x64/pkg/tool/linux_amd64/asm GOINSECURE GOMOD GOMODCACHE ache/go/1.25.8/x64/pkg/tool/linuremote (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/5/artifacts
    • Triggering command: /usr/bin/gh gh api --paginate repos/{owner}/{repo}/actions/runs/5/artifacts --jq .artifacts[].name 0/internal/tag/tag.go 64/pkg/tool/linux_amd64/compile GOINSECURE GOMOD abis 64/pkg/tool/linux_amd64/compile env ility-kit.md GO111MODULE ache/go/1.25.8/x64/pkg/tool/linux_amd64/compile GOINSECURE gset GOMODCACHE ache/go/1.25.8/x64/pkg/tool/linux_amd64/compile (http block)
    • Triggering command: /usr/bin/gh gh run download 5 --dir test-logs/run-5 0/message/catalog/catalog.go 64/pkg/tool/linux_amd64/compile GOINSECURE GOMOD abis 64/pkg/tool/linux_amd64/compile env 3683132792 YfB4YDUdE k GOINSECURE t GOMODCACHE ache/go/1.25.8/x64/pkg/tool/linurev-parse (http block)
  • https://api.github.com/repos/github/gh-aw/actions/workflows
    • Triggering command: /usr/bin/gh gh workflow list --json name,state,path -c=4 -nolocalimports -importcfg /tmp/go-build2594883175/b411/importcfg -pack /home/REDACTED/work/gh-aw/gh-aw/pkg/fileutil/fileutil.go /home/REDACTED/work/gh-aw/gh-aw/pkg/fileutil/tar.go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE y.s (http block)
    • Triggering command: /usr/bin/gh gh run list --json databaseId,number,url,status,conclusion,workflowName,createdAt,startedAt,updatedAt,event,headBranch,headSha,displayTitle --workflow nonexistent-workflow-12345 --limit 100 GOMOD GOMODCACHE go env -json GO111MODULE x_amd64/compile GOINSECURE GOMOD GOMODCACHE x_amd64/compile (http block)
    • Triggering command: /usr/bin/gh gh run list --json databaseId,number,url,status,conclusion,workflowName,createdAt,startedAt,updatedAt,event,headBranch,headSha,displayTitle --workflow nonexistent-workflow-12345 --limit 6 GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/compile env g_.a KmEF_rn9z 64/pkg/tool/linux_amd64/compile GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/compile (http block)
  • https://api.github.com/repos/github/gh-aw/git/ref/tags/v0.47.4
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v0.47.4 --jq .object.sha --show-toplevel 64/pkg/tool/linutest@example.com /usr/bin/git g_.a deRMpwyMD ache/go/1.25.8/x--show-toplevel git rev-�� --show-toplevel ache/go/1.25.8/x64/pkg/tool/linu/tmp/file-tracker-test723700768/test2.lock.yml /usr/bin/git ortcfg 2XU_VxRq0 ache/go/1.25.8/xgit-upload-pack 'origin' git (http block)
  • https://api.github.com/repos/github/gh-aw/git/ref/tags/v1.0.0
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v1.0.0 --jq .object.sha edOutput3020078102/001 GO111MODULE 64/pkg/tool/linux_amd64/link GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/link ortc�� ntdrain.test BBDxPPYcw ortcfg.link GOINSECURE GOMOD GOMODCACHE W9FT-FP7_6Kws9t3pd/XJ3yBE12j21iuxq3TT-m/tggwGl4X-goversion (http block)
  • https://api.github.com/repos/github/gh-aw/git/ref/tags/v1.2.3
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v1.2.3 --jq .object.sha -json GO111MODULE x_amd64/compile GOINSECURE GOMOD GOMODCACHE x_amd64/compile env -json GO111MODULE x_amd64/compile GOINSECURE GOMOD GOMODCACHE x_amd64/compile (http block)
  • https://api.github.com/repos/github/gh-aw/git/ref/tags/v2.0.0
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v2.0.0 --jq .object.sha -json GO111MODULE x_amd64/asm GOINSECURE GOMOD GOMODCACHE x_amd64/asm env -json GO111MODULE x_amd64/compile GOINSECURE GOMOD GOMODCACHE x_amd64/compile (http block)
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v2.0.0 --jq .object.sha -json GO111MODULE x_amd64/compile GOINSECURE GOMOD GOMODCACHE x_amd64/compile env -json o x_amd64/compile GOINSECURE GOMOD GOMODCACHE x_amd64/compile (http block)
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v2.0.0 --jq .object.sha -json GO111MODULE x_amd64/compile GOINSECURE GOMOD GOMODCACHE x_amd64/compile env -json GO111MODULE x_amd64/compile GOINSECURE GOMOD GOMODCACHE x_amd64/compile (http block)
  • https://api.github.com/repos/github/gh-aw/git/ref/tags/v3.0.0
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v3.0.0 --jq .object.sha -json GO111MODULE x_amd64/compile GOINSECURE GOMOD GOMODCACHE x_amd64/compile env -json GO111MODULE x_amd64/compile GOINSECURE GOMOD GOMODCACHE x_amd64/compile (http block)
  • https://api.github.com/repos/githubnext/agentics/git/ref/tags/-
    • Triggering command: /usr/bin/gh gh api /repos/githubnext/agentics/git/ref/tags/- --jq .object.sha (http block)
  • https://api.github.com/repos/nonexistent/action/git/ref/tags/v999.999.999
    • Triggering command: /usr/bin/gh gh api /repos/nonexistent/action/git/ref/tags/v999.999.999 --jq .object.sha edOutput3020078102/001 pMTTxllzq x_amd64/compile GOINSECURE GOMOD GOMODCACHE x_amd64/compile env ortcfg qbNVEaFt_ ache/go/1.25.8/x64/pkg/tool/linux_amd64/compile GOINSECURE GOMOD GOMODCACHE ache/go/1.25.8/x64/pkg/tool/linurev-parse (http block)
  • https://api.github.com/repos/nonexistent/repo/actions/runs/12345
    • Triggering command: /usr/bin/gh gh run view 12345 --repo nonexistent/repo --json status,conclusion GOINSECURE (http block)
  • https://api.github.com/repos/owner/repo/actions/workflows
    • Triggering command: /usr/bin/gh gh workflow list --json name,state,path --repo owner/repo 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
    • Triggering command: /usr/bin/gh gh workflow list --json name,state,path --repo owner/repo 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json go 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/owner/repo/contents/file.md
    • Triggering command: /tmp/go-build2594883175/b397/cli.test /tmp/go-build2594883175/b397/cli.test -test.testlogfile=/tmp/go-build2594883175/b397/testlog.txt -test.paniconexit0 -test.v=true -test.parallel=4 -test.timeout=10m0s -test.run=^Test -test.short=true -nolocalimports -importcfg /tmp/go-build2385888407/b220/importcfg -pack env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/test-owner/test-repo/actions/secrets
    • Triggering command: /usr/bin/gh gh api /repos/test-owner/test-repo/actions/secrets --jq .secrets[].name -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)

If you need me to access, download, or install something from one of these locations, you can either:

Add Gemini API proxy handler support by emitting --gemini-api-target flag
in BuildAWFArgs(). Unlike OpenAI/Anthropic/Copilot where AWF has built-in
default routing, Gemini requires an explicit target so the proxy knows
where to forward requests.

- Add GetGeminiAPITarget() helper with default generativelanguage.googleapis.com
- Support custom GEMINI_API_BASE_URL in engine.env for custom endpoints
- Add --gemini-api-base-path support for path-based routing
- Update computeAllowedDomainsForSanitization to include Gemini target
- Add comprehensive tests for new Gemini API target functionality
- Update documentation to mention GEMINI_API_BASE_URL
- Recompile smoke-gemini.lock.yml with new --gemini-api-target flag

Fixes #25969

Agent-Logs-Url: https://github.com/github/gh-aw/sessions/ec512605-b010-4767-bc1f-f2b520a9263f

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix Gemini proxy sidecar by adding API handler Add --gemini-api-target to AWF proxy for Gemini API routing Apr 13, 2026
Copilot AI requested a review from pelikhan April 13, 2026 16:47
@pelikhan pelikhan marked this pull request as ready for review April 13, 2026 16:48
Copilot AI review requested due to automatic review settings April 13, 2026 16:48
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR wires Gemini into the AWF API proxy routing by adding support for a --gemini-api-target flag (defaulting to generativelanguage.googleapis.com) and deriving custom routing from GEMINI_API_BASE_URL, plus aligning sanitization allowlists and documentation.

Changes:

  • Add GetGeminiAPITarget() and emit --gemini-api-target / --gemini-api-base-path in AWF args.
  • Include the Gemini API target in computeAllowedDomainsForSanitization() to keep GH_AW_ALLOWED_DOMAINS aligned.
  • Add tests and update engine docs + recompile the Gemini smoke workflow lockfile.
Show a summary per file
File Description
pkg/workflow/awf_helpers.go Adds Gemini API routing flags and helper for deriving the Gemini proxy target/base-path.
pkg/workflow/domains.go Merges Gemini API target domains into sanitization allowlist computation.
pkg/workflow/awf_helpers_test.go Adds unit/integration-style tests around Gemini target/base-path flag emission.
docs/src/content/docs/reference/engines.md Documents GEMINI_API_BASE_URL as a supported custom endpoint knob.
.github/workflows/smoke-gemini.lock.yml Lockfile regen to include the new --gemini-api-target AWF flag.

Copilot's findings

Tip

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

  • Files reviewed: 5/5 changed files
  • Comments generated: 4

Comment on lines +318 to +331
// Add Gemini API target for the LLM gateway proxy.
// Unlike OpenAI/Anthropic/Copilot where AWF has built-in default routing,
// Gemini requires an explicit target so the proxy knows where to forward requests.
// Defaults to generativelanguage.googleapis.com when the engine is Gemini.
if geminiTarget := GetGeminiAPITarget(config.WorkflowData, config.EngineName); geminiTarget != "" {
awfArgs = append(awfArgs, "--gemini-api-target", geminiTarget)
awfHelpersLog.Printf("Added --gemini-api-target=%s", geminiTarget)
}

geminiBasePath := extractAPIBasePath(config.WorkflowData, "GEMINI_API_BASE_URL")
if geminiBasePath != "" {
awfArgs = append(awfArgs, "--gemini-api-base-path", geminiBasePath)
awfHelpersLog.Printf("Added --gemini-api-base-path=%s", geminiBasePath)
}
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

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

GEMINI_API_BASE_URL is now treated as a compile-time signal to set --gemini-api-target/--gemini-api-base-path, but it’s also a runtime env var that GeminiEngine currently sets to the LLM gateway URL when the firewall is enabled. In pkg/workflow/gemini_engine.go, GEMINI_API_BASE_URL is set to host.docker.internal: and then later engine.env is copied into the step env (maps.Copy), which would overwrite the proxy URL if the user configures GEMINI_API_BASE_URL (causing Gemini CLI to bypass the gateway and fail because GEMINI_API_KEY is excluded, or bypass the intended credential isolation). Consider ensuring that in firewall mode GEMINI_API_BASE_URL is always forced to the LLM gateway URL after applying engine.env (or strip GEMINI_API_BASE_URL from engine.env at runtime and use it only for generating the AWF flags).

Copilot uses AI. Check for mistakes.
Comment on lines +966 to +970
name: "returns empty when workflowData is nil",
workflowData: nil,
engineName: "gemini",
expected: "generativelanguage.googleapis.com",
},
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

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

The test case name "returns empty when workflowData is nil" doesn’t match the asserted behavior (it expects the default Gemini hostname). Renaming the test case to reflect that nil workflowData with engineName=="gemini" falls back to the default target would make the intent clearer.

Copilot uses AI. Check for mistakes.
Comment on lines +994 to +1136
// TestAWFGeminiAPITargetFlags tests that BuildAWFArgs includes --gemini-api-target flag
// for the Gemini engine with default and custom endpoints.
func TestAWFGeminiAPITargetFlags(t *testing.T) {
t.Run("includes default gemini-api-target flag for gemini engine", func(t *testing.T) {
workflowData := &WorkflowData{
Name: "test-workflow",
EngineConfig: &EngineConfig{
ID: "gemini",
},
NetworkPermissions: &NetworkPermissions{
Firewall: &FirewallConfig{
Enabled: true,
},
},
}

config := AWFCommandConfig{
EngineName: "gemini",
WorkflowData: workflowData,
AllowedDomains: "github.com",
}

args := BuildAWFArgs(config)
argsStr := strings.Join(args, " ")

assert.Contains(t, argsStr, "--gemini-api-target", "Should include --gemini-api-target flag")
assert.Contains(t, argsStr, "generativelanguage.googleapis.com", "Should include default Gemini API hostname")
})

t.Run("includes custom gemini-api-target flag when GEMINI_API_BASE_URL is configured", func(t *testing.T) {
workflowData := &WorkflowData{
Name: "test-workflow",
EngineConfig: &EngineConfig{
ID: "gemini",
Env: map[string]string{
"GEMINI_API_BASE_URL": "https://gemini-proxy.internal.company.com/v1",
"GEMINI_API_KEY": "${{ secrets.GEMINI_PROXY_KEY }}",
},
},
NetworkPermissions: &NetworkPermissions{
Firewall: &FirewallConfig{
Enabled: true,
},
},
}

config := AWFCommandConfig{
EngineName: "gemini",
WorkflowData: workflowData,
AllowedDomains: "github.com",
}

args := BuildAWFArgs(config)
argsStr := strings.Join(args, " ")

assert.Contains(t, argsStr, "--gemini-api-target", "Should include --gemini-api-target flag")
assert.Contains(t, argsStr, "gemini-proxy.internal.company.com", "Should include custom Gemini hostname")
})

t.Run("does not include gemini-api-target for non-gemini engine without custom URL", func(t *testing.T) {
workflowData := &WorkflowData{
Name: "test-workflow",
EngineConfig: &EngineConfig{
ID: "claude",
},
NetworkPermissions: &NetworkPermissions{
Firewall: &FirewallConfig{
Enabled: true,
},
},
}

config := AWFCommandConfig{
EngineName: "claude",
WorkflowData: workflowData,
AllowedDomains: "github.com",
}

args := BuildAWFArgs(config)
argsStr := strings.Join(args, " ")

assert.NotContains(t, argsStr, "--gemini-api-target", "Should not include --gemini-api-target for non-gemini engine")
})

t.Run("includes gemini-api-base-path when custom URL has path component", func(t *testing.T) {
workflowData := &WorkflowData{
Name: "test-workflow",
EngineConfig: &EngineConfig{
ID: "gemini",
Env: map[string]string{
"GEMINI_API_BASE_URL": "https://gemini-proxy.company.com/serving-endpoints",
"GEMINI_API_KEY": "${{ secrets.GEMINI_PROXY_KEY }}",
},
},
NetworkPermissions: &NetworkPermissions{
Firewall: &FirewallConfig{
Enabled: true,
},
},
}

config := AWFCommandConfig{
EngineName: "gemini",
WorkflowData: workflowData,
AllowedDomains: "github.com",
}

args := BuildAWFArgs(config)
argsStr := strings.Join(args, " ")

assert.Contains(t, argsStr, "--gemini-api-base-path", "Should include --gemini-api-base-path flag")
assert.Contains(t, argsStr, "/serving-endpoints", "Should include the path component")
})
}

// TestGeminiEngineIncludesGeminiAPITarget tests that the Gemini engine execution
// step includes --gemini-api-target when firewall is enabled.
func TestGeminiEngineIncludesGeminiAPITarget(t *testing.T) {
workflowData := &WorkflowData{
Name: "test-workflow",
EngineConfig: &EngineConfig{
ID: "gemini",
},
NetworkPermissions: &NetworkPermissions{
Firewall: &FirewallConfig{
Enabled: true,
},
},
}

engine := NewGeminiEngine()
steps := engine.GetExecutionSteps(workflowData, "test.log")

if len(steps) < 2 {
t.Fatal("Expected at least two execution steps (settings + execution)")
}

// steps[0] = Write Gemini Settings, steps[1] = Execute Gemini CLI
stepContent := strings.Join(steps[1], "\n")

assert.Contains(t, stepContent, "--gemini-api-target", "Should include --gemini-api-target flag")
assert.Contains(t, stepContent, "generativelanguage.googleapis.com", "Should include default Gemini API hostname")
}
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

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

Given the new GEMINI_API_BASE_URL behavior, it would be valuable to add an end-to-end test that covers the intended precedence in firewall mode: when engine.env sets GEMINI_API_BASE_URL to a custom endpoint, the generated AWF command should include --gemini-api-target/--gemini-api-base-path for routing, while the step env passed to the Gemini CLI should still set GEMINI_API_BASE_URL to the LLM gateway URL (so the CLI doesn’t bypass the proxy). The current tests verify the flags, but not that runtime env stays pointed at the gateway under this configuration.

Copilot uses AI. Check for mistakes.
#### Custom API Endpoints via Environment Variables

Three environment variables receive special treatment when set in `engine.env`: `OPENAI_BASE_URL` (for `codex`), `ANTHROPIC_BASE_URL` (for `claude`), and `GITHUB_COPILOT_BASE_URL` (for `copilot`). When any of these is present, the API proxy automatically routes API calls to the specified host instead of the default endpoint. Firewall enforcement remains active, but this routing layer is not a separate authentication boundary for arbitrary code already running inside the agent container.
Three environment variables receive special treatment when set in `engine.env`: `OPENAI_BASE_URL` (for `codex`), `ANTHROPIC_BASE_URL` (for `claude`), `GITHUB_COPILOT_BASE_URL` (for `copilot`), and `GEMINI_API_BASE_URL` (for `gemini`). When any of these is present, the API proxy automatically routes API calls to the specified host instead of the default endpoint. Firewall enforcement remains active, but this routing layer is not a separate authentication boundary for arbitrary code already running inside the agent container.
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

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

This sentence says "Three environment variables" but then lists four (OPENAI_BASE_URL, ANTHROPIC_BASE_URL, GITHUB_COPILOT_BASE_URL, GEMINI_API_BASE_URL). Update the count or rephrase (e.g., "The following environment variables...") to avoid confusing readers.

Suggested change
Three environment variables receive special treatment when set in `engine.env`: `OPENAI_BASE_URL` (for `codex`), `ANTHROPIC_BASE_URL` (for `claude`), `GITHUB_COPILOT_BASE_URL` (for `copilot`), and `GEMINI_API_BASE_URL` (for `gemini`). When any of these is present, the API proxy automatically routes API calls to the specified host instead of the default endpoint. Firewall enforcement remains active, but this routing layer is not a separate authentication boundary for arbitrary code already running inside the agent container.
The following environment variables receive special treatment when set in `engine.env`: `OPENAI_BASE_URL` (for `codex`), `ANTHROPIC_BASE_URL` (for `claude`), `GITHUB_COPILOT_BASE_URL` (for `copilot`), and `GEMINI_API_BASE_URL` (for `gemini`). When any of these is present, the API proxy automatically routes API calls to the specified host instead of the default endpoint. Firewall enforcement remains active, but this routing layer is not a separate authentication boundary for arbitrary code already running inside the agent container.

Copilot uses AI. Check for mistakes.
Draft ADR documenting the decision to add --gemini-api-target support
to the AWF proxy helper layer, mirroring the existing pattern for
OpenAI, Anthropic, and Copilot engines.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

Commit pushed: 0c598ea

🏗️ ADR gate enforced by Design Decision Gate 🏗️

@github-actions
Copy link
Copy Markdown
Contributor

🏗️ Design Decision Gate — ADR Required

This PR makes significant changes to core business logic (pkg/) with >100 new lines of code but does not have a linked Architecture Decision Record (ADR).

AI has analyzed the PR diff and generated a draft ADR to help you get started:

📄 Draft ADR: docs/adr/26060-add-gemini-api-target-to-awf-proxy.md

The draft captures the key decision: adding --gemini-api-target routing support to the AWF proxy helper layer for the Gemini engine, following the existing pattern for OpenAI/Anthropic/Copilot. It includes context on why Gemini was broken (missing proxy handler returning API_KEY_INVALID), three genuine alternatives considered, and normative RFC 2119 requirements.

What to do next

  1. Review the draft ADR committed to your branch — it was generated from the PR diff
  2. Complete any missing sections — add context the AI couldn't infer, verify the alternatives you actually considered, and refine the rationale
  3. Reference the ADR in this PR body by adding a line such as:

    ADR: ADR-26060: Add Gemini API Target Routing to AWF Proxy

Once an ADR is linked in the PR body, this gate will re-run and verify the implementation matches the decision.

Why ADRs Matter

ADRs create a searchable, permanent record of why the codebase looks the way it does. Future contributors (and your future self) will thank you.


📋 Michael Nygard ADR Format Reference

An ADR must contain these four sections to be considered complete:

  • Context — What is the problem? What forces are at play?
  • Decision — What did you decide? Why?
  • Alternatives Considered — What else could have been done?
  • Consequences — What are the trade-offs (positive and negative)?

All ADRs are stored in docs/adr/ as Markdown files numbered by PR number (e.g., 26060-add-gemini-api-target-to-awf-proxy.md for PR #26060).

🔒 This PR cannot merge until an ADR is linked in the PR body.

Note

🔒 Integrity filter blocked 1 item

The following item were blocked because they don't meet the GitHub integrity level.

To allow these resources, lower min-integrity in your GitHub frontmatter:

tools:
  github:
    min-integrity: approved  # merged | approved | unapproved | none

🏗️ ADR gate enforced by Design Decision Gate 🏗️ · ● 118.7K ·

@github-actions
Copy link
Copy Markdown
Contributor

🧪 Test Quality Sentinel Report

Test Quality Score: 90/100

Excellent test quality

Metric Value
New/modified tests analyzed 3 (10 subtests)
✅ Design tests (behavioral contracts) 3 (100%)
⚠️ Implementation tests (low value) 0 (0%)
Tests with error/edge cases 3 (100%)
Duplicate test clusters 0
Test inflation detected YES — 215 test lines / 43 production lines ≈ 5:1 (threshold: 2:1)
🚨 Coding-guideline violations 0

Test Classification Details

Test File Classification Issues Detected
TestGetGeminiAPITarget pkg/workflow/awf_helpers_test.go:925 ✅ Design ⚠️ Misleading case name (see below)
TestAWFGeminiAPITargetFlags pkg/workflow/awf_helpers_test.go:996 ✅ Design None
TestGeminiEngineIncludesGeminiAPITarget pkg/workflow/awf_helpers_test.go:1111 ✅ Design None

Flagged Tests — Requires Review

⚠️ TestGetGeminiAPITarget — Misleading test case name (pkg/workflow/awf_helpers_test.go:925)

Classification: Design test (behavioral contract) — ✅ not a quality failure

Issue: Table row 4 has a misleading name that contradicts its assertion:

{
    name:         "returns empty when workflowData is nil",  // ← says "returns empty"
    workflowData: nil,
    engineName:   "gemini",
    expected:     "generativelanguage.googleapis.com",       // ← but expects the DEFAULT hostname
},

The test name says "returns empty" but the expected value is the default Gemini hostname — not an empty string. Either the name should be "returns default target when workflowData is nil", or the expected value should be "". Since the intent is likely to test nil safety with a graceful fallback to the default endpoint, the name should be corrected.

What would break if deleted? Nil-safety regression in GetGeminiAPITarget would go undetected — this case has real value. The logic is correct; only the name is wrong.

Suggested fix: Rename the case to "returns default target for gemini engine when workflowData is nil".


Test Inflation Note

awf_helpers_test.go gained 215 lines while awf_helpers.go gained only 43 lines (ratio ≈ 5:1). This triggers the inflation penalty and reduces the score by 10 points. However, the additional test lines represent genuinely comprehensive table-driven coverage across multiple scenarios (default, custom URL, nil input, non-Gemini engine, path component extraction), so this inflation is qualitatively justified. The penalty is applied mechanically per the rubric.


Language Support

Tests analyzed:

  • 🐹 Go (*_test.go): 3 test functions (10 subtests) — unit (//go:build !integration)
  • 🟨 JavaScript (*.test.cjs, *.test.js): 0 tests

Verdict

Check passed. 0% of new tests are implementation tests (threshold: 30%). All 3 new test functions verify observable behavioral contracts. One minor naming inconsistency in a table-driven test case should be corrected (see above).


📖 Understanding Test Classifications

Design Tests (High Value) verify what the system does:

  • Assert on observable outputs, return values, or state changes
  • Cover error paths and boundary conditions
  • Would catch a behavioral regression if deleted
  • Remain valid even after internal refactoring

Implementation Tests (Low Value) verify how the system does it:

  • Assert on internal function calls (mocking internals)
  • Only test the happy path with typical inputs
  • Break during legitimate refactoring even when behavior is correct
  • Give false assurance: they pass even when the system is wrong

Goal: Shift toward tests that describe the system's behavioral contract — the promises it makes to its users and collaborators.

🧪 Test quality analysis by Test Quality Sentinel · ● 632.4K ·

Copy link
Copy Markdown
Contributor

@github-actions github-actions bot left a comment

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. Test quality is excellent — 0% of new tests are implementation tests (threshold: 30%). All 3 new test functions (TestGetGeminiAPITarget, TestAWFGeminiAPITargetFlags, TestGeminiEngineIncludesGeminiAPITarget) verify behavioral contracts with good edge-case coverage. One minor issue: a table-driven test case in TestGetGeminiAPITarget has a misleading name ("returns empty when workflowData is nil") while its expected value is the default hostname — please rename it for clarity.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[deep-report] Fix Gemini proxy sidecar — add Gemini API handler to AWF proxy

3 participants