diff --git a/docs/api-proxy-sidecar.md b/docs/api-proxy-sidecar.md index 5b350a286..37cb342e5 100644 --- a/docs/api-proxy-sidecar.md +++ b/docs/api-proxy-sidecar.md @@ -706,8 +706,10 @@ AWF supports OIDC-based credential exchange with multiple cloud providers via Gi | `ACTIONS_ID_TOKEN_REQUEST_URL` | ✅ | Provided automatically by the GitHub Actions runtime | | `ACTIONS_ID_TOKEN_REQUEST_TOKEN` | ✅ | Provided automatically by the GitHub Actions runtime | -:::caution[OIDC request capability reaches the agent] -AWF forwards `ACTIONS_ID_TOKEN_REQUEST_URL` and `ACTIONS_ID_TOKEN_REQUEST_TOKEN` to both the sidecar and the agent container. These values let code request a GitHub OIDC JWT when the job has `permissions: id-token: write`. Exchanged provider credentials remain isolated in the sidecar, but the token-minting capability itself is not isolated. Restrict provider federation policies to the expected repository, workflow, ref, and audience. +:::note[OIDC request capability is sidecar-only] +AWF forwards `ACTIONS_ID_TOKEN_REQUEST_URL` and `ACTIONS_ID_TOKEN_REQUEST_TOKEN` only to the api-proxy sidecar when `AWF_AUTH_TYPE=github-oidc`. The variables are excluded from the agent even when `--env-all`, `--env-file`, or explicit `--env` options request them. The minted GitHub JWT and exchanged provider credentials also remain inside the sidecar. + +GitHub Agentic Workflows handles HTTP MCP `auth.type: github-oidc` separately: the compiler-generated, runner-owned **Start MCP Gateway** step passes the Actions variables directly to the MCP gateway, which mints an audience-bound JWT for the remote server. AWF neither launches nor configures that gateway, and the variables do not need to pass through the agent. Recompile older workflow lock files that do not use this direct runner-to-gateway path; compatibility tracking is available in [github/gh-aw#50053](https://github.com/github/gh-aw/issues/50053). ::: When `AWF_AUTH_TYPE=github-oidc` is set but `ACTIONS_ID_TOKEN_REQUEST_URL`/`ACTIONS_ID_TOKEN_REQUEST_TOKEN` are not available in the sidecar, Anthropic OIDC requests fail closed with: @@ -770,7 +772,7 @@ Exchanges the GitHub OIDC JWT for a GCP access token via the Security Token Serv Default OIDC audience: the `gcpWorkloadIdentityProvider` value :::note -`ACTIONS_ID_TOKEN_REQUEST_URL` and `ACTIONS_ID_TOKEN_REQUEST_TOKEN` are injected by the Actions runner automatically. AWF forwards them to the sidecar when `AWF_AUTH_TYPE=github-oidc` and currently also passes them through to the agent. +`ACTIONS_ID_TOKEN_REQUEST_URL` and `ACTIONS_ID_TOKEN_REQUEST_TOKEN` are injected by the Actions runner automatically. AWF forwards them to the sidecar when `AWF_AUTH_TYPE=github-oidc` and excludes them from the agent container. ::: :::tip diff --git a/docs/auth-matrix.md b/docs/auth-matrix.md index c74be77bc..3d9e63ff8 100644 --- a/docs/auth-matrix.md +++ b/docs/auth-matrix.md @@ -277,6 +277,8 @@ All OIDC flows require GitHub Actions runtime tokens: - `ACTIONS_ID_TOKEN_REQUEST_URL` — endpoint to mint OIDC JWTs - `ACTIONS_ID_TOKEN_REQUEST_TOKEN` — auth token for the OIDC endpoint +AWF forwards these variables only to the api-proxy sidecar in `github-oidc` mode and excludes them from the agent container. GitHub Agentic Workflows independently passes them from its runner-owned **Start MCP Gateway** step directly to the MCP gateway when a remote HTTP MCP server uses `auth.type: github-oidc`; AWF does not launch or configure that gateway. See [github/gh-aw#50053](https://github.com/github/gh-aw/issues/50053) for lock-file compatibility tracking. + ### Azure (Entra ID) | Config | Env Var | Required | diff --git a/docs/authentication-architecture.md b/docs/authentication-architecture.md index 832fae4a8..bc2c31931 100644 --- a/docs/authentication-architecture.md +++ b/docs/authentication-architecture.md @@ -570,7 +570,7 @@ AWF does not provide this mode. The diagram shows the risk that the always-on si ## OIDC authentication (keyless credential exchange) -AWF also supports **keyless authentication** via GitHub Actions OIDC workload identity federation. Instead of static API keys, the api-proxy sidecar exchanges a short-lived GitHub-issued JWT for provider-specific credentials — without the agent ever seeing any secret. +AWF also supports **keyless authentication** via GitHub Actions OIDC workload identity federation. Instead of static API keys, the api-proxy sidecar exchanges a short-lived GitHub-issued JWT for provider-specific credentials. The Actions token-minting variables, minted JWT, and exchanged credentials remain outside the agent container. ### How native GitHub Actions OIDC works @@ -609,7 +609,7 @@ In a standard GitHub Actions workflow (without AWF), OIDC federation works like ### How AWF OIDC works (credential isolation) -AWF keeps the minted GitHub JWT and exchanged cloud credential in the api-proxy sidecar. However, the Actions runtime URL and token used to request a JWT are currently forwarded to the agent as well as the sidecar: +AWF keeps the Actions OIDC request capability, minted GitHub JWT, and exchanged cloud credential in the api-proxy sidecar: ``` ┌─────────────────────────────┐ ┌───────────────────────────────────────┐ @@ -617,7 +617,7 @@ AWF keeps the minted GitHub JWT and exchanged cloud credential in the api-proxy │ 172.30.0.20 │ │ 172.30.0.30 │ │ │ │ │ │ Environment: │ │ Environment: │ -│ ✓ ACTIONS_ID_TOKEN_* │ │ ✓ ACTIONS_ID_TOKEN_REQUEST_URL │ +│ ✗ No ACTIONS_ID_TOKEN_* │ │ ✓ ACTIONS_ID_TOKEN_REQUEST_URL │ │ ✗ No cloud credentials │ │ ✓ ACTIONS_ID_TOKEN_REQUEST_TOKEN │ │ ✗ No API keys │ │ ✓ AWF_AUTH_TYPE=github-oidc │ │ ✓ OPENAI_BASE_URL= │ │ ✓ AWF_AUTH_PROVIDER=azure|aws|gcp|anthropic │ @@ -648,7 +648,7 @@ AWF keeps the minted GitHub JWT and exchanged cloud credential in the api-proxy #### Step 1: Configuration forwarding -The AWF CLI forwards `AWF_AUTH_*` configuration only to the api-proxy sidecar. The Actions runtime OIDC request URL and token are different: `passthroughHostEnvironment()` currently forwards both to the agent as well as `buildOidcEnv()` forwarding them to the sidecar. +The AWF CLI forwards `AWF_AUTH_*` configuration and the Actions runtime OIDC request URL and token only to the api-proxy sidecar. `buildOidcEnv()` conditionally adds the runtime variables to the sidecar in `github-oidc` mode, while `buildExclusionSet()` prevents every agent environment input path from adding them. ``` Host environment Sidecar container Agent container @@ -656,11 +656,13 @@ Host environment Sidecar container Agent container AWF_AUTH_TYPE=github-oidc ──► AWF_AUTH_TYPE ✓ ✗ (excluded) AWF_AUTH_PROVIDER=azure ──► AWF_AUTH_PROVIDER ✓ ✗ (excluded) AWF_AUTH_AZURE_TENANT_ID=... ──► AWF_AUTH_AZURE_TENANT_ID ✓ ✗ (excluded) -ACTIONS_ID_TOKEN_REQUEST_URL ──► forwarded when type=oidc ✓ ✓ (forwarded) +ACTIONS_ID_TOKEN_REQUEST_URL ──► forwarded when type=oidc ✓ ✗ (excluded) ``` -:::caution[OIDC minting capability is visible to the agent] -With `permissions: id-token: write`, `ACTIONS_ID_TOKEN_REQUEST_URL` and `ACTIONS_ID_TOKEN_REQUEST_TOKEN` let agent code request a GitHub OIDC JWT for an audience. AWF keeps the resulting provider credential in the sidecar, but it does not currently isolate this token-minting capability from the agent. Scope federation trust policies narrowly to the repository, workflow, ref, and expected audience. +:::note[OIDC-authenticated MCP servers] +GitHub Agentic Workflows supports `auth.type: github-oidc` for remote HTTP MCP servers through its compiler-managed MCP gateway. The generated **Start MCP Gateway** workflow step runs on the Actions runner before the AWF agent, passes the Actions variables directly to the gateway, and supplies only the gateway endpoint to the agent. The gateway mints an audience-bound JWT and injects it into the remote MCP request. AWF does not launch or configure the gateway. + +Lock files generated by compiler versions that do not pass the variables directly from the runner to the gateway must be recompiled. See [github/gh-aw#50053](https://github.com/github/gh-aw/issues/50053) for compatibility validation and migration tracking. ::: #### Step 2: GitHub OIDC token minting @@ -752,7 +754,7 @@ For Anthropic bearer requests, AWF merges the OAuth beta with client-supplied `a |----------|----------------|-----------------| | Credential type | Long-lived secret | Short-lived token (~1h) | | Rotation | Manual | Automatic (proactive refresh) | -| Agent sees credential material | No real provider key | No minted JWT or exchanged provider credential, but the Actions OIDC request token/URL are currently forwarded to the agent | +| Agent sees credential material | No real provider key | No Actions OIDC request token, minted JWT, or exchanged provider credential | | GitHub Actions requirement | API key in secrets | `permissions: id-token: write` | | Cloud provider setup | Generate API key | Configure trust policy/federation | | Supported providers | OpenAI, Anthropic, Copilot, Gemini, Vertex AI | Azure (OpenAI/Copilot), GCP (OpenAI/Copilot adapters only — not the native Vertex/Gemini adapters), Anthropic WIF, AWS Bedrock Runtime via OpenAI/Copilot adapters | diff --git a/docs/awf-config-spec.md b/docs/awf-config-spec.md index 981fa85fb..2a1a63229 100644 --- a/docs/awf-config-spec.md +++ b/docs/awf-config-spec.md @@ -298,7 +298,7 @@ passthrough. A conforming implementation MUST NOT inherit them from the host: |----------|-----------| | System | `PATH`, `PWD`, `OLDPWD`, `SHLVL`, `_`, `SUDO_COMMAND`, `SUDO_USER`, `SUDO_UID`, `SUDO_GID` | | Proxy | `HTTP_PROXY`, `HTTPS_PROXY`, `http_proxy`, `https_proxy`, `NO_PROXY`, `no_proxy`, `ALL_PROXY`, `all_proxy`, `FTP_PROXY`, `ftp_proxy` | -| Actions artifact tokens | `ACTIONS_RUNTIME_TOKEN`, `ACTIONS_RESULTS_URL` | +| Actions runtime credentials | `ACTIONS_RUNTIME_TOKEN`, `ACTIONS_RESULTS_URL`, `ACTIONS_ID_TOKEN_REQUEST_URL`, `ACTIONS_ID_TOKEN_REQUEST_TOKEN` | | AWF internal controls | `AWF_PREFLIGHT_BINARY`, `AWF_GEMINI_ENABLED` | > **Note:** Host proxy variables are read for upstream proxy auto-detection @@ -314,13 +314,16 @@ the following host variables into the agent container: |----------|-----------| | GitHub authentication | `GITHUB_TOKEN`, `GH_TOKEN`, `GITHUB_PERSONAL_ACCESS_TOKEN` | | GitHub enterprise | `GITHUB_SERVER_URL`, `GITHUB_API_URL` | -| Actions OIDC | `ACTIONS_ID_TOKEN_REQUEST_URL`, `ACTIONS_ID_TOKEN_REQUEST_TOKEN` | | Docker client | `DOCKER_HOST`, `DOCKER_TLS`, `DOCKER_TLS_VERIFY`, `DOCKER_CERT_PATH`, `DOCKER_CONFIG`, `DOCKER_CONTEXT`, `DOCKER_API_VERSION`, `DOCKER_DEFAULT_PLATFORM` | | User environment | `USER`, `XDG_CONFIG_HOME` | When `--env-all` IS active, all host variables not in the excluded set (§8.3) SHALL be forwarded, subject to credential isolation rules (§9). +Actions OIDC request variables MUST be forwarded directly to the api-proxy +sidecar when `apiProxy.auth.type` is `github-oidc` and MUST NOT be forwarded +to the agent through any environment input path. + ### 8.5 Explicit Overrides Variables passed via `-e` / `--env` MUST override values from `--env-all` diff --git a/docs/environment.md b/docs/environment.md index c88317688..0dd3f6ff6 100644 --- a/docs/environment.md +++ b/docs/environment.md @@ -44,7 +44,7 @@ Using `--env-all` passes all host environment variables to the container, which 3. **Unnecessary Access**: Extra variables increase attack surface (violates least privilege) 4. **Accidental Sharing**: Easy to forget what's in your environment when sharing commands -**Excluded variables** (even with `--env-all`): `PATH`, `PWD`, `OLDPWD`, `SHLVL`, `_`, `SUDO_*` +**Excluded variables** (even with `--env-all`): `PATH`, `PWD`, `OLDPWD`, `SHLVL`, `_`, `SUDO_*`, `ACTIONS_RUNTIME_TOKEN`, `ACTIONS_RESULTS_URL`, `ACTIONS_ID_TOKEN_REQUEST_URL`, and `ACTIONS_ID_TOKEN_REQUEST_TOKEN`. Actions OIDC variables are forwarded directly to the api-proxy sidecar in `github-oidc` mode, never to the agent. **Proxy variables:** `HTTP_PROXY`, `HTTPS_PROXY`, `http_proxy`, `https_proxy`, `NO_PROXY`, `no_proxy`, `ALL_PROXY`, and `FTP_PROXY` (all case variants) from the host are **excluded from container passthrough** when using `--env-all`. The firewall sets its own proxy variables pointing to Squid inside the container. However, host proxy variables **are read** for upstream proxy auto-detection — if the host has `https_proxy`/`http_proxy` set, AWF configures Squid to chain outbound traffic through that corporate proxy (see [Upstream Proxy Support](#upstream-corporate-proxy-support)). @@ -64,7 +64,7 @@ Using `--env-all` passes all host environment variables to the container, which 3. `--env-file` variables 4. `--env` / `-e` explicit variables (highest priority) -**Excluded variables** in `--env-file` (same list as `--env-all`): `PATH`, `PWD`, `HOME`, `SUDO_*`, etc. +**Excluded variables** in `--env-file` (same list as `--env-all`): `PATH`, `PWD`, `HOME`, `SUDO_*`, Actions runtime credentials, etc. Explicit `--env` cannot override credential exclusions. **Example use case — Safe Outputs MCP:** ```bash diff --git a/docs/sbx-integration.md b/docs/sbx-integration.md index a30b1b567..abe13e125 100644 --- a/docs/sbx-integration.md +++ b/docs/sbx-integration.md @@ -219,9 +219,9 @@ What `createSandbox()` shares, in order: `accessTokens.json`, `service_principal_entries.json`) are treated as credential stores and scrubbed before sandbox creation (sbx) or masked with `/dev/null` overlays (compose). Agents cannot read host Azure auth tokens - directly. Azure authentication must be obtained at runtime via OIDC - (`ACTIONS_ID_TOKEN_REQUEST_URL`/`TOKEN`, already forwarded) or via the - `ADO_MCP_AUTH_TOKEN` environment variable. + directly. Azure API authentication must be handled by the api-proxy's + sidecar-only OIDC exchange or by an external trusted service. The separate + `ADO_MCP_AUTH_TOKEN` environment variable remains available for ADO MCP. ::: **Scrubbing nested credential stores.** Several whitelisted dirs legitimately @@ -238,9 +238,11 @@ them after the sandbox is torn down** (`scrubHomeCredentials` / the secrets are absent from the VM while the benign tool state stays available. This is the sbx analog of compose mode's `/dev/null` credential overlays, and the central credential list in `sandbox-mount-policy.json` is shared between backends -to prevent drift. The agent receives whatever credentials it needs through the -api-proxy or environment (e.g. `ADO_MCP_AUTH_TOKEN`, OIDC tokens), not by reading -the host's on-disk auth store, so removing these paths is safe. +to prevent drift. The agent accesses OIDC-backed providers through requests +routed to the api-proxy, or receives separately allowed environment credentials +such as `ADO_MCP_AUTH_TOKEN`, not by reading the host's on-disk auth store. +Provider credentials and Actions OIDC request variables remain in the api-proxy +or another trusted external service, so removing these paths is safe. A `seenPaths` set deduplicates so no path is mounted twice, and `execInSandbox(..., { workDir })` passes `--workdir` so commands run inside the diff --git a/src/config/sandbox-mount-policy.json b/src/config/sandbox-mount-policy.json index 8a999c776..d5cc6e67c 100644 --- a/src/config/sandbox-mount-policy.json +++ b/src/config/sandbox-mount-policy.json @@ -9,7 +9,7 @@ "etc": ["/etc/ssl", "/etc/ca-certificates", "/etc/pki/ca-trust/extracted", "/etc/pki/tls/certs", "/etc/alternatives", "/etc/ld.so.cache", "/etc/nsswitch.conf"] }, "home": { - "$comment": "Agent $HOME exposure. `toolSubdirs` is the ALLOW list: tool caches, language toolchains and agent state the agent legitimately needs. `forbiddenSubdirs` is a DENY guard: dirs whose primary purpose is storing credentials and which must NEVER be added to the allow list. Compose mounts an empty home + binds toolSubdirs on top; sbx mounts toolSubdirs wholesale instead of the whole $HOME. EXCEPTION: `.azure` is credential-bearing — it is intentionally mounted to provide Azure CLI config and account metadata, but its live token caches (msal_token_cache.bin, msal_token_cache.json, accessTokens.json, service_principal_entries.json) are masked by the credentials deny list so agents cannot read host auth tokens directly. Azure auth must come via OIDC (ACTIONS_ID_TOKEN_REQUEST_URL/TOKEN) or the ADO_MCP_AUTH_TOKEN env var.", + "$comment": "Agent $HOME exposure. `toolSubdirs` is the ALLOW list: tool caches, language toolchains and agent state the agent legitimately needs. `forbiddenSubdirs` is a DENY guard: dirs whose primary purpose is storing credentials and which must NEVER be added to the allow list. Compose mounts an empty home + binds toolSubdirs on top; sbx mounts toolSubdirs wholesale instead of the whole $HOME. EXCEPTION: `.azure` is credential-bearing — it is intentionally mounted to provide Azure CLI config and account metadata, but its live token caches (msal_token_cache.bin, msal_token_cache.json, accessTokens.json, service_principal_entries.json) are masked by the credentials deny list so agents cannot read host auth tokens directly. Azure API auth must use the api-proxy's sidecar-only OIDC exchange or another trusted external service; ADO MCP may use its separate ADO_MCP_AUTH_TOKEN env var.", "toolSubdirs": [ ".cache", ".config", diff --git a/src/services/agent-environment-credentials.test.ts b/src/services/agent-environment-credentials.test.ts index 2d890f2c8..eeaad5ca1 100644 --- a/src/services/agent-environment-credentials.test.ts +++ b/src/services/agent-environment-credentials.test.ts @@ -1,3 +1,6 @@ +import fs from 'fs'; +import path from 'path'; + import { generateDockerCompose, WrapperConfig, baseConfig, mockNetworkConfig, useTempWorkDir } from './service-test-setup.test-utils'; // Create mock functions (must remain per-file — jest.mock() is hoisted before imports) @@ -147,48 +150,39 @@ describe('agent environment: credentials', () => { expect(env.GH_TOKEN).not.toBe('ghp_real_secret_token_12345'); }); - it('should pass through ACTIONS_ID_TOKEN_REQUEST_URL when present in environment', () => { - const originalEnv = process.env.ACTIONS_ID_TOKEN_REQUEST_URL; + it('should never pass Actions OIDC minting variables to the agent', () => { + const origUrl = process.env.ACTIONS_ID_TOKEN_REQUEST_URL; + const origToken = process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN; process.env.ACTIONS_ID_TOKEN_REQUEST_URL = 'https://token.actions.githubusercontent.com/abc'; + process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN = 'test-oidc-token-value'; try { const result = generateDockerCompose(mockConfig, mockNetworkConfig); const env = result.services.agent.environment as Record; - expect(env.ACTIONS_ID_TOKEN_REQUEST_URL).toBe('https://token.actions.githubusercontent.com/abc'); + expect(env.ACTIONS_ID_TOKEN_REQUEST_URL).toBeUndefined(); + expect(env.ACTIONS_ID_TOKEN_REQUEST_TOKEN).toBeUndefined(); } finally { - if (originalEnv !== undefined) { - process.env.ACTIONS_ID_TOKEN_REQUEST_URL = originalEnv; + if (origUrl !== undefined) { + process.env.ACTIONS_ID_TOKEN_REQUEST_URL = origUrl; } else { delete process.env.ACTIONS_ID_TOKEN_REQUEST_URL; } - } - }); - - it('should pass through ACTIONS_ID_TOKEN_REQUEST_TOKEN when present in environment', () => { - const originalEnv = process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN; - process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN = 'test-oidc-token-value'; - - try { - const result = generateDockerCompose(mockConfig, mockNetworkConfig); - const env = result.services.agent.environment as Record; - expect(env.ACTIONS_ID_TOKEN_REQUEST_TOKEN).toBe('test-oidc-token-value'); - } finally { - if (originalEnv !== undefined) { - process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN = originalEnv; + if (origToken !== undefined) { + process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN = origToken; } else { delete process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN; } } }); - it('should not pass through OIDC variables when not in environment', () => { + it('should exclude Actions OIDC minting variables from --env-all', () => { const origUrl = process.env.ACTIONS_ID_TOKEN_REQUEST_URL; const origToken = process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN; - delete process.env.ACTIONS_ID_TOKEN_REQUEST_URL; - delete process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN; + process.env.ACTIONS_ID_TOKEN_REQUEST_URL = 'https://token.actions.githubusercontent.com/abc'; + process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN = 'test-oidc-token-value'; try { - const result = generateDockerCompose(mockConfig, mockNetworkConfig); + const result = generateDockerCompose({ ...mockConfig, envAll: true }, mockNetworkConfig); const env = result.services.agent.environment as Record; expect(env.ACTIONS_ID_TOKEN_REQUEST_URL).toBeUndefined(); expect(env.ACTIONS_ID_TOKEN_REQUEST_TOKEN).toBeUndefined(); @@ -206,6 +200,32 @@ describe('agent environment: credentials', () => { } }); + it('should reject explicit Actions OIDC minting variables in additionalEnv', () => { + const result = generateDockerCompose({ + ...mockConfig, + additionalEnv: { + ACTIONS_ID_TOKEN_REQUEST_URL: 'https://token.actions.githubusercontent.com/abc', + ACTIONS_ID_TOKEN_REQUEST_TOKEN: 'test-oidc-token-value', + }, + }, mockNetworkConfig); + const env = result.services.agent.environment as Record; + expect(env.ACTIONS_ID_TOKEN_REQUEST_URL).toBeUndefined(); + expect(env.ACTIONS_ID_TOKEN_REQUEST_TOKEN).toBeUndefined(); + }); + + it('should exclude Actions OIDC minting variables from env files', () => { + const envFile = path.join(mockConfig.workDir, 'oidc.env'); + fs.writeFileSync(envFile, [ + 'ACTIONS_ID_TOKEN_REQUEST_URL=https://token.actions.githubusercontent.com/abc', + 'ACTIONS_ID_TOKEN_REQUEST_TOKEN=test-oidc-token-value', + ].join('\n')); + + const result = generateDockerCompose({ ...mockConfig, envFile }, mockNetworkConfig); + const env = result.services.agent.environment as Record; + expect(env.ACTIONS_ID_TOKEN_REQUEST_URL).toBeUndefined(); + expect(env.ACTIONS_ID_TOKEN_REQUEST_TOKEN).toBeUndefined(); + }); + it('should never pass ACTIONS_RUNTIME_TOKEN to agent container', () => { const originalToken = process.env.ACTIONS_RUNTIME_TOKEN; process.env.ACTIONS_RUNTIME_TOKEN = 'test-runtime-token-value'; diff --git a/src/services/agent-environment/env-passthrough.ts b/src/services/agent-environment/env-passthrough.ts index 018c45395..0f249b10b 100644 --- a/src/services/agent-environment/env-passthrough.ts +++ b/src/services/agent-environment/env-passthrough.ts @@ -41,8 +41,6 @@ export function passthroughHostEnvironment(params: EnvPassthroughParams): void { 'XDG_CONFIG_HOME', 'GITHUB_SERVER_URL', 'GITHUB_API_URL', - 'ACTIONS_ID_TOKEN_REQUEST_URL', - 'ACTIONS_ID_TOKEN_REQUEST_TOKEN', 'AZURE_CONFIG_DIR', 'ADO_MCP_AUTH_TOKEN', 'DOCKER_HOST', diff --git a/src/services/agent-environment/excluded-vars.ts b/src/services/agent-environment/excluded-vars.ts index 9df3adde5..73ef060b7 100644 --- a/src/services/agent-environment/excluded-vars.ts +++ b/src/services/agent-environment/excluded-vars.ts @@ -14,6 +14,8 @@ export function buildExclusionSet(config: WrapperConfig): Set { 'SUDO_GID', 'ACTIONS_RUNTIME_TOKEN', 'ACTIONS_RESULTS_URL', + 'ACTIONS_ID_TOKEN_REQUEST_URL', + 'ACTIONS_ID_TOKEN_REQUEST_TOKEN', ...PROXY_ENV_VARS, 'AWF_PREFLIGHT_BINARY', 'AWF_STAGED_RUNNER_BINARY_NAME', diff --git a/src/services/api-proxy-service-oidc.test.ts b/src/services/api-proxy-service-oidc.test.ts index 22f2d9a5f..16407b827 100644 --- a/src/services/api-proxy-service-oidc.test.ts +++ b/src/services/api-proxy-service-oidc.test.ts @@ -37,8 +37,11 @@ describe('API proxy sidecar: OIDC env forwarding', () => { const config = { ...mockConfig, enableApiProxy: true, openaiApiKey: 'sk-openai-test' }; const result = generateDockerCompose(config, mockNetworkConfigWithProxy); const env = result.services['api-proxy'].environment as Record; + const agentEnv = result.services.agent.environment as Record; expect(env.ACTIONS_ID_TOKEN_REQUEST_URL).toBe('https://actions.local/token'); expect(env.ACTIONS_ID_TOKEN_REQUEST_TOKEN).toBe('runtime-token'); + expect(agentEnv.ACTIONS_ID_TOKEN_REQUEST_URL).toBeUndefined(); + expect(agentEnv.ACTIONS_ID_TOKEN_REQUEST_TOKEN).toBeUndefined(); }); it('should forward ACTIONS_ID_TOKEN_REQUEST_* when config.authType is github-oidc (config-file path)', () => {