Skip to content

feat: support secret-backed OpenAI-compatible targets - #7576

Merged
lpcox merged 9 commits into
mainfrom
copilot/awf-support-secret-backed-targets
Aug 20, 2026
Merged

feat: support secret-backed OpenAI-compatible targets#7576
lpcox merged 9 commits into
mainfrom
copilot/awf-support-secret-backed-targets

Conversation

Copilot AI commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Codex workflows routed through a private OpenAI-compatible load balancer had no way to configure the endpoint from a runtime secret: the OpenAI target is a concrete startup value, forcing the sensitive host into generated lockfiles or brittle post-compile patching. This adds an environment-backed target that AWF resolves and validates on the runner, derives network policy from, and keeps out of the agent environment, logs, and artifacts.

{
  "apiProxy": {
    "targets": {
      "openai": {
        "baseUrlEnv": "CODEX_LB_BASE_URL"
      }
    }
  }
}

gh-aw can then bind ${{ secrets.CODEX_LB_BASE_URL }} to the named runner variable without writing its value anywhere.

Resolution and validation (src/openai-base-url-env.ts)

  • Reads the named variable in runner-side config code only, before any container starts.
  • Requires an absolute http(s) URL; rejects embedded user:pass@ credentials, query strings/fragments, malformed hosts, unsupported schemes, and non-default ports (the sidecar only reaches the scheme's default port, so a custom port would be silently dropped).
  • Derives url, host, hostPort, and basePath. Every error message is value-free, so a misconfigured endpoint can't leak through a failure path.

Wiring

  • Network policy (commands/preflight.ts): the resolved URL feeds the existing sensitive-endpoint path, landing in sensitiveAllowedDomains — merged into squid.conf but never into allowedDomains (which is logged and serialized to the audit artifact). Validation failures exit 1 before agent startup.
  • Sidecar routing (services/api-proxy-env-config.ts): derived host/path become OPENAI_API_TARGET / OPENAI_API_BASE_PATH, taking precedence over targets.openai.host/basePath.
  • Credential isolation (services/agent-environment/excluded-vars.ts): the named variable is excluded from the agent environment unconditionally (not gated on enableApiProxy), so --env-all can't reintroduce it.
  • Config surface: schema (docs/awf-config.schema.json + regenerated src/awf-config-schema.json, new openaiTarget $def so baseUrlEnv doesn't leak onto other providers), config-file.ts, config-mapper.ts, resolve-credentials.ts, routing option types, and a --openai-base-url-env <name> flag.

Artifact redaction

  • New deriveSensitiveEndpointForms() / redactSensitiveValues() in redact-secrets.ts expand each sensitive allowlist entry into its URL, host, and host:port forms.
  • writeAuditArtifacts() now redacts those forms from the audited squid.conf, and redactDockerComposeSecrets() accepts them so values in non-secret-named env vars (e.g. OPENAI_API_TARGET) are scrubbed. This also closes the same gap for the pre-existing OPENAI_ENDPOINT_OVERRIDE path, which previously wrote the secret host into both artifacts.

Docs

Normative §9.7 in docs/awf-config-spec.md, plus CLI-mapping, CLI reference, and api-proxy sidecar entries.

Tests

New suites for URL validation and non-leaking errors, plus additions covering policy derivation, sidecar target/base-path configuration, fail-fast on invalid values, agent-env exclusion, config mapping, and compose/squid.conf redaction.

Copilot AI changed the title [WIP] Support secret-backed OpenAI-compatible targets for Codex Support secret-backed OpenAI-compatible targets via apiProxy.targets.openai.baseUrlEnv Aug 20, 2026
Copilot AI requested a review from lpcox August 20, 2026 21:36
@lpcox
lpcox marked this pull request as ready for review August 20, 2026 21:37
Copilot AI balanced review requested due to automatic review settings August 20, 2026 21:37

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

Adds runtime resolution for secret-backed OpenAI-compatible endpoints while aiming to isolate endpoint details from agents and artifacts.

Changes:

  • Adds URL resolution, validation, routing, and network-policy integration.
  • Adds environment exclusion and artifact-redaction utilities.
  • Extends configuration schemas, CLI documentation, and tests.
Show a summary per file
File Description
src/types/api-proxy-routing-options.ts Defines the routing option.
src/services/api-proxy-env-config.ts Configures sidecar routing.
src/services/api-proxy-env-config.test.ts Tests sidecar configuration.
src/services/agent-environment/excluded-vars.ts Excludes the named secret variable.
src/services/agent-environment/excluded-vars.test.ts Tests environment exclusion.
src/redact-secrets.ts Adds endpoint redaction helpers.
src/redact-secrets.test.ts Tests redaction helpers.
src/openai-base-url-env.ts Resolves and validates endpoint URLs.
src/openai-base-url-env.test.ts Tests URL validation.
src/coverage-branch-gaps-3.test.ts Covers compose redaction.
src/config-writer.ts Redacts audit artifacts.
src/config-writer-new-branches.test.ts Tests Squid configuration redaction.
src/config-mapper.ts Maps file configuration.
src/config-file.ts Extends configuration types.
src/config-file-mapping.test.ts Tests configuration mapping.
src/compose-generator.ts Redacts literal sensitive values.
src/commands/resolve-credentials.ts Resolves the new option.
src/commands/preflight.ts Derives sensitive network policy.
src/commands/preflight.test.ts Tests preflight behavior.
src/cli-options.ts Adds the CLI flag.
src/awf-config-schema.json Updates the generated schema.
docs/awf-config.schema.json Updates the canonical schema.
docs/awf-config-spec.md Documents normative behavior.
docs/api-proxy-sidecar.md Documents sidecar configuration.
docs-site/src/content/docs/reference/cli-reference.md Adds CLI reference documentation.

Review details

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Suppressed comments (1)

src/commands/preflight.ts:194

  • Passing the secret URL as openaiEndpointOverride does not implement the documented precedence. resolveApiTargetsToAllowedDomains() checks options.openaiApiTarget and then OPENAI_API_TARGET before consulting this parameter, while sidecar routing gives baseUrlEnv precedence. If either older target is present, Squid allows that target instead of the secret-backed host and the sidecar's requests fail. The resolver needs a distinct sensitive target input that takes precedence while still writing only to sensitiveAllowedDomains.
    resolveSecretOpenAiBaseUrl(options)
    ?? additionalEnv?.['OPENAI_ENDPOINT_OVERRIDE']
  • Files reviewed: 25/25 changed files
  • Comments generated: 5
  • Review effort level: Balanced

Comment thread src/commands/preflight.ts Outdated
* @returns The normalized base URL, or undefined when the feature is not configured.
*/
function resolveSecretOpenAiBaseUrl(options: Record<string, unknown>): string | undefined {
const envVarName = options.openaiBaseUrlEnv as string | undefined;
Comment thread src/openai-base-url-env.ts Outdated
Comment on lines +93 to +96
if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') {
throw new Error(
`Environment variable "${name}" uses an unsupported URL scheme. ` +
'Only http:// and https:// endpoints are supported.'
Comment on lines +19 to +20
const secretOpenAiBaseUrl = resolveOpenAiBaseUrlFromEnv(config.openaiBaseUrlEnv);
const resolvedOpenAiTarget = secretOpenAiBaseUrl?.host ?? config.openaiApiTarget ?? openAiEndpointOverride;
Comment thread src/config-writer.ts Outdated
Comment on lines +297 to +302
const sensitiveEndpointForms = deriveSensitiveEndpointForms(config.sensitiveAllowedDomains);

// Save squid.conf for audit (domain ACLs and proxy config, sensitive hosts redacted)
fs.writeFileSync(
path.join(auditDir, 'squid.conf'),
redactSensitiveValues(squidConfig, sensitiveEndpointForms),
Comment thread src/redact-secrets.ts Outdated
@lpcox

lpcox commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator

@copilot address review feedback

@github-actions

Copy link
Copy Markdown
Contributor

✅ Copilot review passed with no inline comments.

@copilot Add the ready-for-aw label to this PR to trigger agentic CI smoke tests.

@github-actions

github-actions Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Documentation Preview

Documentation build failed for this PR. View logs.

Built from commit 674d4e7

Copilot AI commented Aug 20, 2026

Copy link
Copy Markdown
Contributor Author

@copilot address review feedback

Addressed the review feedback in a8172d4 and follow-up test adjustment 84b1d30.

@github-actions

github-actions Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

✅ Coverage Check Passed

Overall Coverage

Metric Base PR Delta
Lines 93.78% 93.83% 📈 +0.05%
Statements 92.64% 92.69% 📈 +0.05%
Functions 93.12% 93.17% 📈 +0.05%
Branches 85.88% 85.92% 📈 +0.04%
📁 Per-file Coverage Changes (4 files)
File Lines (Before → After) Statements (Before → After)
src/api-proxy-config-domains.ts 100.0% → 100.0% (+0.00%) 99.0% → 99.0% (+0.02%)
src/redact-secrets.ts 100.0% → 100.0% (+0.00%) 100.0% → 91.3% (-8.70%)
src/config-writer.ts 90.8% → 91.5% (+0.68%) 90.8% → 91.5% (+0.68%)
src/log-directory-setup.ts 96.2% → 100.0% (+3.78%) 96.3% → 100.0% (+3.71%)
✨ New Files (1 files)
  • src/openai-base-url-env.ts: 94.3% lines

Coverage comparison generated by scripts/ci/compare-coverage.ts

Comment thread src/config-writer.ts Fixed
Comment thread src/coverage-branch-gaps-3.test.ts Fixed
Comment thread src/coverage-branch-gaps-3.test.ts Fixed
Comment thread src/coverage-branch-gaps-3.test.ts Fixed
lpcox and others added 2 commits August 20, 2026 15:22
…ile'

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
…xpression for hostnames'

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
@lpcox

lpcox commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator

@copilot make sure pr addresses all review feedback

Copilot AI commented Aug 20, 2026

Copy link
Copy Markdown
Contributor Author

@copilot make sure pr addresses all review feedback

Verified all review paths and corrected the remaining CodeQL fixture regression in 8b7c587. Focused tests, type-check, sidecar log-redaction tests, secret scan, and CodeQL verification completed.

@lpcox lpcox changed the title Support secret-backed OpenAI-compatible targets via apiProxy.targets.openai.baseUrlEnv feat: support secret-backed OpenAI-compatible targets Aug 20, 2026
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 7d7ef30e-3c24-432a-8bd1-ef165d6535f0
@github-actions

github-actions Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

📰 VERDICT: Smoke Copilot has concluded. All systems operational. This is a developing story. 🎤

📰 BREAKING: Report filed by Smoke Copilot

@github-actions

github-actions Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Smoke Copilot BYOK completed. Copilot BYOK mode operational. 🔓

🔑 BYOK report filed by Smoke Copilot BYOK

@github-actions github-actions Bot added the smoke-copilot-network-isolation Copilot network-isolation egress smoke test label Aug 20, 2026
@github-actions

Copy link
Copy Markdown
Contributor

@lpcox Network isolation smoke test results:

EGRESS_RESULT allow=pass deny=pass

✅ Allowed domain (github.com) reachable — allowed=200
✅ Blocked domain (example.com) denied — 403 proxy tunnel failure

Overall status: PASS

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • example.com

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "example.com"

See Network Configuration for more information.

🛡️ Egress verdict from Smoke Copilot Network Isolation
Add label ready-for-aw to run again

@github-actions

Copy link
Copy Markdown
Contributor

Smoke Test: Copilot BYOK (Direct) — PASS

  • ✅ GitHub MCP connectivity (2 recent merged PRs confirmed)
  • ✅ github.com connectivity (HTTP 200)
  • ✅ File write/read (smoke test file exists)
  • ✅ BYOK inference (running in direct mode via api-proxy → api.githubcopilot.com)

Running in direct BYOK mode (COPILOT_PROVIDER_API_KEY) via api-proxy sidecar.

🔑 BYOK report filed by Smoke Copilot BYOK
Add label ready-for-aw to run again

@github-actions

Copy link
Copy Markdown
Contributor

@lpcox
GitHub MCP Testing: ✅
GitHub.com Connectivity: ✅
File Write/Read: ✅
BYOK Inference: ✅

Running in direct BYOK mode (COPILOT_PROVIDER_API_KEY + COPILOT_PROVIDER_BASE_URL) via api-proxy → Azure OpenAI (Foundry, o4-mini-aw)
Overall status: PASS

🔑 BYOK (AOAI api-key) report filed by Smoke Copilot BYOK AOAI (api-key)
Add label ready-for-aw to run again

@github-actions

Copy link
Copy Markdown
Contributor

Smoke Test: Services Connectivity — FAIL

  • Redis PING: ❌ Temporary failure in name resolution
  • Postgres pg_isready: ❌ no response
  • Postgres SELECT 1: ❌ could not translate host name

Overall: FAILhost.docker.internal did not resolve; sandbox cannot reach host service containers.

🔌 Service connectivity validated by Smoke Services
Add label ready-for-aw to run again

@github-actions

Copy link
Copy Markdown
Contributor

Chroot Version Comparison

Runtime Host Version Chroot Version Match?
Python Python 3.12.14 Python 3.12.14 ✅ YES
Node.js v24.19.0 v22.23.2 ❌ NO
Go go1.22.12 go1.22.12 ✅ YES

Overall: ❌ FAILED — Node.js version mismatch between host and chroot environments. smoke-chroot label not applied since not all runtimes matched.

Tested by Smoke Chroot
Add label ready-for-aw to run again

@github-actions

Copy link
Copy Markdown
Contributor

Smoke Test

  • [docs] auth: docs: document GITHUB_RUN_ID/GITHUB_RUN_ATTEMPT forwarding to api-proxy sidecar
  • Fix Cloud Hypervisor guest loopback networking
  • GitHub merged PR review ✅
  • safeinputs-gh query ❌
  • Playwright title ✅
  • Temp file write/read + bash cat ✅
  • Discussion query/comment ❌
  • AWF build ✅
  • Overall: FAIL

Warning

Firewall blocked 3 domains

The following domains were blocked by the firewall during workflow execution:

  • msfeed2.pkgs.visualstudio.com
  • msfeed25.pkgs.visualstudio.com
  • registry.npmjs.org

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "msfeed2.pkgs.visualstudio.com"
    - "msfeed25.pkgs.visualstudio.com"
    - "registry.npmjs.org"

See Network Configuration for more information.

🔮 The oracle has spoken through Smoke Codex
Add label ready-for-aw to run again

@github-actions

Copy link
Copy Markdown
Contributor

Docker Sbx Smoke Test

✅ GitHub MCP connectivity
✅ github.com HTTP 200
✅ File write/read

Overall: PASS

cc @lpcox

📰 BREAKING: Report filed by Smoke Docker Sbx
Add label ready-for-aw to run again

@github-actions

Copy link
Copy Markdown
Contributor

📡 OTel Tracing Smoke Test Results

  • Scenario 1 — Module Loading: otel.js loaded successfully. isEnabled: true. Exports: startRequestSpan, setTokenAttributes, setBudgetAttributes, endSpan, endSpanError, shutdown, isEnabled, _provider, _ProxyAwareOtlpExporter, _FileSpanExporter, _FanOutSpanExporter, _parseEndpoints, _parseOtlpHeaders, _buildResourceSpans, _createOtlpWorkloadIdentity.
  • Scenario 2 — Test Suite: 3 suites / 68 tests passed (otel.test.js, otel-fanout.test.js, otel-workload-identity.test.js), 0 failed.
  • Scenario 3 — Env Var Forwarding: env-passthrough.ts forwards GITHUB_AW_OTEL_TRACE_ID and GITHUB_AW_OTEL_PARENT_SPAN_ID to the agent; api-proxy-env-config.ts forwards those plus OTEL_EXPORTER_OTLP_ENDPOINT/OTEL_EXPORTER_OTLP_HEADERS/OTEL_SERVICE_NAME to the api-proxy.
  • Scenario 4 — Token Tracker Integration: onUsage callback present in token-tracker-http.js (invoked after normalized usage extraction) as the OTEL hook point.
  • Scenario 5 — OTEL Diagnostics: A span (gh-aw.agent.setup) was exported for this run (/tmp/gh-aw/otel.jsonl), confirming OTLP export is functioning.

Overall: all 5 scenarios pass, no regressions detected.

📡 OTel tracing validated by Smoke OTel Tracing
Add label ready-for-aw to run again

@lpcox
lpcox deployed to aoai-model August 20, 2026 23:00 — with GitHub Actions Active
@github-actions

Copy link
Copy Markdown
Contributor

MCP tool test: ❌
GitHub.com connectivity: ✅
File write/read test: ✅
BYOK inference test: ✅

Running in direct BYOK mode (AWF_AUTH_TYPE=github-oidc + AWF_AUTH_AZURE_* + COPILOT_PROVIDER_BASE_URL) via api-proxy → Azure OpenAI (Foundry, o4-mini-aw) authenticated via Microsoft Entra

Overall: FAIL

cc @Copilot @lpcox

🪪 BYOK (AOAI Entra) report filed by Smoke Copilot BYOK AOAI (Entra)
Add label ready-for-aw to run again

@github-actions

Copy link
Copy Markdown
Contributor

🏗️ Build Test Suite Results

Ecosystem Project Build/Install Tests Status
Bun elysia 1/1 passed ✅ PASS
Bun hono 1/1 passed ✅ PASS
C++ fmt N/A ✅ PASS
C++ json N/A ✅ PASS
Deno oak N/A 1/1 passed ✅ PASS
Deno std N/A 1/1 passed ✅ PASS
.NET hello-world N/A (ran, output correct) ✅ PASS
.NET json-parse N/A (ran, output correct) ✅ PASS
Go color passed ✅ PASS
Go env passed ✅ PASS
Go uuid passed ✅ PASS
Java gson passed ✅ PASS
Java caffeine passed ✅ PASS
Node.js clsx passed ✅ PASS
Node.js execa passed ✅ PASS
Node.js p-limit passed ✅ PASS
Rust fd 1/1 passed ✅ PASS
Rust zoxide 1/1 passed ✅ PASS

Overall: 8/8 ecosystems passed — ✅ PASS

All clones, builds, installs, and tests completed successfully across all 8 ecosystems (18 total projects). Network egress through the AWF firewall (including the Maven proxy override needed for ~/.m2 local-repository permission and Squid proxy settings) worked correctly for all package managers tested: bun, cmake/make, deno, dotnet, go, mvn, npm, and cargo.

Note: for Java, ~/.m2 was not writable by the runner user by default; local repository was redirected to /tmp/gh-aw/agent/m2repo to work around this, in addition to the Squid proxy settings in ~/.m2/settings.xml.

Generated by Build Test Suite for #7576 · auto · 52.1 AIC · ⊞ 12K ·
Add label ready-for-aw to run again

@lpcox
lpcox merged commit 1aed44a into main Aug 20, 2026
162 of 164 checks passed
@lpcox
lpcox deleted the copilot/awf-support-secret-backed-targets branch August 20, 2026 23:10
Copilot AI linked an issue Aug 21, 2026 that may be closed by this pull request
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.

[awf] Support secret-backed OpenAI-compatible targets for Codex

4 participants