4b6817381b
CI (OpenClaw E2E) / openclaw test (push) Has been cancelled
CI / coverage-report (push) Has been cancelled
CI / test-kubernetes (push) Has been cancelled
CI / should-run-thorough (push) Has been cancelled
CI / test-thorough (cloudwatch-demo) (push) Has been cancelled
CI / test-thorough (flink-ecs) (push) Has been cancelled
CI / test-thorough (upstream-lambda) (push) Has been cancelled
CI / test-thorough (prefect-ecs-fargate) (push) Has been cancelled
Release / build-binaries (zip, opensre.exe, onefile, windows-latest, windows-x64) (push) Has been cancelled
Benchmark image — build + push to ECR (any adapter) / build + push (push) Has been cancelled
CI / quality (ubuntu-latest) (push) Has been cancelled
CI / test (tools-runtime) (push) Has been cancelled
CI / test (e2e-general) (push) Has been cancelled
CI / test (cli-runtime) (push) Has been cancelled
CI / test (e2e-provider-and-openclaw) (push) Has been cancelled
CI / test (integrations-and-misc) (push) Has been cancelled
Release / verify (push) Has been cancelled
Release / build-python-dist (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, macos-15-intel, darwin-x64) (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, macos-latest, darwin-arm64) (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04, linux-x64) (push) Has been cancelled
Release / publish-release (push) Has been cancelled
Release / publish-main-release (push) Has been cancelled
Interactive Shell Live (PR + post-merge) / turn-checks (no-LLM) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Interactive Shell Live (PR + post-merge) / turn-live shard ${{ matrix.shard_index }} (push) Has been cancelled
Release / prepare (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04-arm, linux-arm64) (push) Has been cancelled
Synthetic Deterministic Tests / Synthetic offline (deterministic) (push) Has been cancelled
94 lines
3.1 KiB
Python
94 lines
3.1 KiB
Python
"""Filtered environment for spawning LLM CLI subprocesses.
|
|
|
|
Only keys needed for binary resolution, locale, proxies, TLS, and adapter-specific
|
|
prefixes are forwarded from ``os.environ``. Adapter implementations merge their
|
|
own overrides (for example explicit API keys for that CLI only).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
|
|
_SAFE_SUBPROCESS_ENV_KEYS = frozenset(
|
|
{
|
|
"HOME",
|
|
# macOS Keychain item lookup (where `claude login` stores OAuth on darwin)
|
|
# requires USER. LOGNAME is the POSIX/Linux equivalent kept for parity.
|
|
"USER",
|
|
"LOGNAME",
|
|
"USERPROFILE",
|
|
"APPDATA",
|
|
"LOCALAPPDATA",
|
|
"PATH",
|
|
"PATHEXT",
|
|
"SYSTEMROOT",
|
|
"WINDIR",
|
|
"COMSPEC",
|
|
"SHELL",
|
|
"TMP",
|
|
"TEMP",
|
|
"TMPDIR",
|
|
"LANG",
|
|
"TERM",
|
|
"TZ",
|
|
"NO_PROXY",
|
|
"HTTP_PROXY",
|
|
"HTTPS_PROXY",
|
|
"ALL_PROXY",
|
|
"SSL_CERT_FILE",
|
|
"SSL_CERT_DIR",
|
|
"REQUESTS_CA_BUNDLE",
|
|
"CURL_CA_BUNDLE",
|
|
"NO_COLOR",
|
|
"FORCE_COLOR",
|
|
"COLORTERM",
|
|
"XDG_CONFIG_HOME",
|
|
"XDG_CACHE_HOME",
|
|
"XDG_DATA_HOME",
|
|
"XDG_STATE_HOME",
|
|
}
|
|
)
|
|
_SAFE_SUBPROCESS_ENV_PREFIXES = (
|
|
"LC_",
|
|
"CODEX_",
|
|
"CURSOR_",
|
|
"CLAUDE_",
|
|
"GEMINI_",
|
|
"GOOGLE_",
|
|
# ``ANTIGRAVITY_*`` currently only carries non-secret config
|
|
# (``ANTIGRAVITY_CLI_BIN`` path, ``ANTIGRAVITY_CLI_TIMEOUT_SECONDS``
|
|
# numeric). If Google ever ships a secret-bearing env (e.g.
|
|
# ``ANTIGRAVITY_API_KEY``), revisit this — a blanket prefix would
|
|
# leak the secret into every other CLI subprocess. Mirror the
|
|
# COPILOT_ pattern below if that happens.
|
|
"ANTIGRAVITY_",
|
|
"OPENCODE_",
|
|
"KIMI_",
|
|
# Pi CLI (pi.dev) non-secret config vars (e.g. ``PI_AGENT_DIR`` /
|
|
# ``PI_CONFIG_DIR``, ``PI_BIN``, ``PI_MODEL``). Pi's per-provider API keys
|
|
# are NOT ``PI_``-prefixed (they are ``ANTHROPIC_API_KEY`` etc.) and are
|
|
# forwarded only via the Pi adapter's ``CLIInvocation.env`` — see
|
|
# ``PI_PROVIDER_ENV_KEYS`` in ``env_overrides.py`` — so this prefix carries
|
|
# no secrets.
|
|
"PI_",
|
|
# NOTE: deliberately NO ``COPILOT_`` entry. ``COPILOT_GITHUB_TOKEN`` is a
|
|
# GitHub PAT; if we forwarded it via this prefix allowlist it would leak
|
|
# into every other CLI subprocess (Codex, Kimi, Claude Code, etc.). All
|
|
# Copilot envs (config + credentials) flow through ``CLIInvocation.env``
|
|
# built by ``CopilotAdapter.build`` so they only reach the Copilot
|
|
# subprocess. See ``env_overrides.py`` for the COPILOT_*_ENV_KEYS tuples.
|
|
)
|
|
|
|
|
|
def build_cli_subprocess_env(overrides: dict[str, str] | None) -> dict[str, str]:
|
|
"""Return a subprocess ``env`` dict: safe inherited keys plus optional overrides."""
|
|
env: dict[str, str] = {}
|
|
for key, value in os.environ.items():
|
|
if key in _SAFE_SUBPROCESS_ENV_KEYS or any(
|
|
key.startswith(prefix) for prefix in _SAFE_SUBPROCESS_ENV_PREFIXES
|
|
):
|
|
env[key] = value
|
|
if overrides:
|
|
env.update(overrides)
|
|
return env
|