fix(cron_vm): veria — scrub provider secrets from claude --version probe env

This commit is contained in:
mateo-berri 2026-05-19 03:28:28 +00:00
parent de75079b99
commit 0cd506f24d
No known key found for this signature in database
2 changed files with 82 additions and 1 deletions

View file

@ -0,0 +1,61 @@
"""Pin: the cron `claude --version` probe must run under `env -i`.
The systemd service `litellm-compat-matrix.service` loads provider
credentials (`ANTHROPIC_API_KEY`, `AWS_BEARER_TOKEN_BEDROCK`,
`AZURE_FOUNDRY_API_KEY`) and the agent-shin GitHub token
(`AGENT_SHIN_GITHUB_TOKEN`) into `run_daily.sh`'s environment from
`/etc/litellm-compat-matrix.env`. Running the npm-installed `claude`
binary directly there would hand that full env to package code, so a
compromised `@anthropic-ai/claude-code` release could read those
secrets out of `os.environ` before the proxy or test harness ever
starts. The version probe must be wrapped in `env -i` with a minimal
PATH/HOME/USER/TERM/LANG/LC_ALL/TMPDIR allowlist matching the
PR-gate's resolver/npm-install/pytest scrubs.
"""
from __future__ import annotations
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parents[3]
RUN_DAILY = REPO_ROOT / "tests" / "claude_code" / "cron_vm" / "run_daily.sh"
def _version_probe_block() -> str:
body = RUN_DAILY.read_text()
start = body.index("CLAUDE_CODE_VERSION=")
end = body.index("[[ -n \"${CLAUDE_CODE_VERSION}\" ]]", start)
return body[start:end]
def test_version_probe_wraps_claude_in_env_i() -> None:
block = _version_probe_block()
assert "env -i" in block, (
"run_daily.sh: the `claude --version` probe must run under "
"`env -i` so a compromised @anthropic-ai/claude-code package "
"cannot read provider/GitHub credentials out of the systemd "
"service environment."
)
assert block.index("env -i") < block.index("claude --version"), (
"run_daily.sh: `env -i` must precede `claude --version`; "
"otherwise the binary inherits the full credential-bearing env."
)
def test_version_probe_env_i_excludes_provider_secrets() -> None:
block = _version_probe_block()
for forbidden in (
"ANTHROPIC_API_KEY",
"AWS_BEARER_TOKEN_BEDROCK",
"AWS_ACCESS_KEY_ID",
"AWS_SECRET_ACCESS_KEY",
"VERTEXAI_CREDENTIALS",
"AZURE_FOUNDRY_API_KEY",
"GITHUB_TOKEN",
"AGENT_SHIN_GITHUB_TOKEN",
):
assert forbidden not in block, (
f"run_daily.sh: the version-probe `env -i` allowlist must "
f"not pass {forbidden} through. Found it inside the probe "
f"block."
)

View file

@ -163,7 +163,27 @@ LITELLM_VERSION="$(
[[ -n "${LITELLM_VERSION}" ]] || die "could not resolve latest v*-stable tag in 5 pages of releases"
log "resolved litellm: ${LITELLM_VERSION}"
CLAUDE_CODE_VERSION="$(claude --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+([.-][A-Za-z0-9.-]+)?' | head -n1)"
# The systemd unit loads provider credentials and the agent-shin GitHub
# token from /etc/litellm-compat-matrix.env into this script's
# environment. Running the npm-installed `claude` binary directly here
# would hand that full env to package code -- a compromised
# @anthropic-ai/claude-code release could read ANTHROPIC_API_KEY /
# AWS_BEARER_TOKEN_BEDROCK / AZURE_FOUNDRY_API_KEY /
# AGENT_SHIN_GITHUB_TOKEN from os.environ and exfiltrate them before
# the proxy or test harness ever starts. Probe under `env -i` with the
# same minimal allowlist the PR-gate uses (the matrix run itself goes
# through cli_driver.py, which already scrubs the CLI env).
CLAUDE_CODE_VERSION="$(env -i \
PATH="${PATH}" \
HOME="${HOME}" \
USER="${USER:-mateo}" \
TERM="${TERM:-dumb}" \
LANG="${LANG:-C.UTF-8}" \
LC_ALL="${LC_ALL:-}" \
TMPDIR="${TMPDIR:-/tmp}" \
claude --version 2>/dev/null \
| grep -oE '[0-9]+\.[0-9]+\.[0-9]+([.-][A-Za-z0-9.-]+)?' \
| head -n1)"
[[ -n "${CLAUDE_CODE_VERSION}" ]] || die "could not parse semver from 'claude --version'"
log "local claude code: ${CLAUDE_CODE_VERSION}"