Skip to content

http:// API targets: scheme stripped from apiProxy.targets.<provider>.host, defeating AWF v0.28.13 HTTP support #58572

Description

@golivax

Summary

When an engine env base URL uses an explicit http:// scheme, gh-aw strips the scheme when generating the AWF apiProxy.targets.<provider>.host value in the compiled lock. The emitted target is a bare hostname, so AWF's api-proxy (per github/gh-aw-firewall#7868 / github/gh-aw-firewall#7862, shipped in AWF v0.28.13) treats it as HTTPS and dials :443. This reintroduces the exact 502 / TCP_DENIED failure that the firewall fix was meant to resolve.

Reproduction

Compile with gh aw v0.88.2 (also reproduces on current main):

network:
  allowed: [defaults]
engine:
  id: claude
  env:
    ANTHROPIC_BASE_URL: "http://gateway.example.com"
    ANTHROPIC_API_KEY: ${{ secrets.MY_ANTHROPIC_KEY }}

Generated lock contains:

"targets":{"anthropic":{"host":"gateway.example.com"}}

Expected (to honor the firewall fix):

"targets":{"anthropic":{"host":"http://gateway.example.com"}}

The agent-container env ANTHROPIC_BASE_URL keeps http:// correctly; only the proxy target loses it. The same applies to OPENAI_BASE_URL (codex) and GEMINI_API_BASE_URL (gemini).

Root cause

extractAPITargetHost() in pkg/workflow/engine_api_targets.go unconditionally strips ://…. Its result is written into AWFAPITargetConfig{Host} in pkg/workflow/awf_config_build.go for openai/anthropic (and via GetGeminiAPITarget() for gemini). AWF v0.28.13 expects the scheme embedded in the target value (--anthropic-api-target http://host); its normalizeApiTargetScheme() keeps http://<hostname> only for explicit-HTTP targets and a bare host still defaults to HTTPS/443.

Fix considerations

  • The host written to apiProxy.targets.* should preserve an explicit http:// scheme (an https:// or bare value can stay bare, mirroring AWF's own normalization, so existing lock files are unchanged).
  • extractAPITargetHost is also consumed by allowlist/audit logic (mergeAPITargetDomains, getEngineAPIHosts, GetCopilotAllowlistTargets) which needs the bare host — so the scheme should be preserved only on the proxy target host, not the allowlist entries (AWF strips it internally via stripTargetScheme()).
  • Gate on AWF ≥ v0.28.13 (already the default) so workflows pinning an older AWF keep the bare host.
  • Note for the copilot target: at AWF v0.28.13, containers/api-proxy/providers/copilot.js buildCopilotModelsRequest() still hardcodes https://${rawTarget}/models while deriveCopilotApiTarget() now returns http://<host>, so an http:// copilot target would yield a malformed https://http://host/models. The copilot target should stay bare until that is fixed on the firewall side.

A PR implementing the above is attached.

Activity

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

Metadata

Metadata

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions