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
128 lines
4.4 KiB
Python
128 lines
4.4 KiB
Python
"""Pick CLI subprocess ``env`` overrides from ``os.environ``.
|
|
|
|
``build_cli_subprocess_env`` only forwards a safe key/prefix subset from the parent process.
|
|
Vendor CLIs still need HTTP credentials sometimes; adapters merge ``nonempty_env_values(...)``
|
|
into ``CLIInvocation.env`` (same idea as Codex ``OPENAI_*``, Cursor ``CURSOR_API_KEY``, OpenCode HTTP keys).
|
|
|
|
Keep ``HTTP_LLM_PROVIDER_ENV_KEYS`` aligned with ``LLMSettings`` / ``config/config.py`` API-key env
|
|
names when adding HTTP LLM providers.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
from typing import Final
|
|
|
|
OPENAI_PLATFORM_ENV_KEYS: Final[tuple[str, ...]] = (
|
|
"OPENAI_API_KEY",
|
|
"OPENAI_ORG_ID",
|
|
"OPENAI_PROJECT_ID",
|
|
"OPENAI_BASE_URL",
|
|
)
|
|
|
|
HTTP_LLM_PROVIDER_ENV_KEYS: Final[tuple[str, ...]] = (
|
|
"ANTHROPIC_API_KEY",
|
|
"OPENAI_API_KEY",
|
|
"OPENROUTER_API_KEY",
|
|
"DEEPSEEK_API_KEY",
|
|
"GEMINI_API_KEY",
|
|
"NVIDIA_API_KEY",
|
|
"MINIMAX_API_KEY",
|
|
"OPENAI_ORG_ID",
|
|
"OPENAI_PROJECT_ID",
|
|
"OPENAI_BASE_URL",
|
|
)
|
|
|
|
ANTHROPIC_CLI_ENV_KEYS: Final[tuple[str, ...]] = (
|
|
"ANTHROPIC_API_KEY",
|
|
"ANTHROPIC_BASE_URL",
|
|
"ANTHROPIC_AUTH_TOKEN",
|
|
)
|
|
|
|
CURSOR_CLI_ENV_KEYS: Final[tuple[str, ...]] = ("CURSOR_API_KEY",)
|
|
|
|
# xAI Grok Build CLI credential envs. ``XAI_API_KEY`` is a secret and MUST NOT
|
|
# flow through the global ``_SAFE_SUBPROCESS_ENV_PREFIXES`` allowlist (a blanket
|
|
# ``XAI_`` prefix would forward the key into every other CLI subprocess). The
|
|
# Grok adapter forwards these *exclusively* via ``CLIInvocation.env`` so they
|
|
# only reach the Grok subprocess. ``XAI_BASE_URL`` supports enterprise / custom
|
|
# endpoints.
|
|
XAI_CLI_ENV_KEYS: Final[tuple[str, ...]] = (
|
|
"XAI_API_KEY",
|
|
"XAI_BASE_URL",
|
|
)
|
|
|
|
# Non-credential Copilot CLI config envs forwarded only via the Copilot
|
|
# adapter's ``CLIInvocation.env``. They are deliberately NOT in
|
|
# ``_SAFE_SUBPROCESS_ENV_PREFIXES``: scoping them to the Copilot subprocess
|
|
# avoids confusing other vendor CLIs with vars they do not consume.
|
|
# ``GH_HOST`` / ``COPILOT_GH_HOST`` are hostname routing for GitHub Enterprise /
|
|
# alternate GitHub endpoints (same semantics as ``gh auth status --hostname``);
|
|
# Copilot CLI must see them alongside the auth probe.
|
|
COPILOT_CLI_CONFIG_ENV_KEYS: Final[tuple[str, ...]] = (
|
|
"COPILOT_HOME",
|
|
"COPILOT_MODEL",
|
|
"COPILOT_GH_HOST",
|
|
"GH_HOST",
|
|
)
|
|
|
|
# Copilot CLI credential envs. ``COPILOT_GITHUB_TOKEN`` is a GitHub PAT and
|
|
# MUST NOT flow through the global ``_SAFE_SUBPROCESS_ENV_PREFIXES`` allowlist
|
|
# (a ``COPILOT_`` prefix entry would forward this PAT into every CLI
|
|
# subprocess — Codex, Kimi, Claude Code, etc. — which is a credential-leak
|
|
# regression). The Copilot adapter forwards these *exclusively* via
|
|
# ``CLIInvocation.env`` so they only reach the Copilot subprocess.
|
|
# ``GH_TOKEN`` / ``GITHUB_TOKEN`` are non-prefixed for the same reason.
|
|
COPILOT_CLI_ENV_KEYS: Final[tuple[str, ...]] = (
|
|
"COPILOT_GITHUB_TOKEN",
|
|
"GH_TOKEN",
|
|
"GITHUB_TOKEN",
|
|
)
|
|
|
|
# Pi CLI (pi.dev) is bring-your-own-key across ~30 providers; it reads a
|
|
# per-provider API-key env var (see https://pi.dev/docs/latest/providers).
|
|
# These are secrets, so — like the Grok/Copilot tuples above — they are
|
|
# forwarded *exclusively* via the Pi adapter's ``CLIInvocation.env`` and are
|
|
# NOT covered by the ``PI_`` entry in ``_SAFE_SUBPROCESS_ENV_PREFIXES`` (that
|
|
# prefix only carries Pi's own non-secret ``PI_*`` config vars). Keep this list
|
|
# aligned with Pi's provider catalog when it adds providers.
|
|
PI_PROVIDER_ENV_KEYS: Final[tuple[str, ...]] = (
|
|
"ANTHROPIC_API_KEY",
|
|
"ANT_LING_API_KEY",
|
|
"AZURE_OPENAI_API_KEY",
|
|
"OPENAI_API_KEY",
|
|
"DEEPSEEK_API_KEY",
|
|
"NVIDIA_API_KEY",
|
|
"GEMINI_API_KEY",
|
|
"MISTRAL_API_KEY",
|
|
"GROQ_API_KEY",
|
|
"CEREBRAS_API_KEY",
|
|
"CLOUDFLARE_API_KEY",
|
|
"XAI_API_KEY",
|
|
"OPENROUTER_API_KEY",
|
|
"AI_GATEWAY_API_KEY",
|
|
"ZAI_API_KEY",
|
|
"ZAI_CODING_CN_API_KEY",
|
|
"OPENCODE_API_KEY",
|
|
"HF_TOKEN",
|
|
"FIREWORKS_API_KEY",
|
|
"TOGETHER_API_KEY",
|
|
"KIMI_API_KEY",
|
|
"MINIMAX_API_KEY",
|
|
"MINIMAX_CN_API_KEY",
|
|
"XIAOMI_API_KEY",
|
|
"XIAOMI_TOKEN_PLAN_CN_API_KEY",
|
|
"XIAOMI_TOKEN_PLAN_AMS_API_KEY",
|
|
"XIAOMI_TOKEN_PLAN_SGP_API_KEY",
|
|
)
|
|
|
|
|
|
def nonempty_env_values(keys: tuple[str, ...]) -> dict[str, str]:
|
|
"""Return ``{name: value}`` for keys with non-empty stripped values in ``os.environ``."""
|
|
out: dict[str, str] = {}
|
|
for key in keys:
|
|
val = os.environ.get(key, "").strip()
|
|
if val:
|
|
out[key] = val
|
|
return out
|