From 0cd506f24d77cd700a31ca499aade131d9ff5f86 Mon Sep 17 00:00:00 2001 From: mateo-berri <277851410+mateo-berri@users.noreply.github.com> Date: Tue, 19 May 2026 03:28:28 +0000 Subject: [PATCH] =?UTF-8?q?fix(cron=5Fvm):=20veria=20=E2=80=94=20scrub=20p?= =?UTF-8?q?rovider=20secrets=20from=20claude=20--version=20probe=20env?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...test_run_daily_version_probe_scrubs_env.py | 61 +++++++++++++++++++ tests/claude_code/cron_vm/run_daily.sh | 22 ++++++- 2 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 tests/claude_code/_publisher_unit_tests/test_run_daily_version_probe_scrubs_env.py diff --git a/tests/claude_code/_publisher_unit_tests/test_run_daily_version_probe_scrubs_env.py b/tests/claude_code/_publisher_unit_tests/test_run_daily_version_probe_scrubs_env.py new file mode 100644 index 00000000000..a77afd36096 --- /dev/null +++ b/tests/claude_code/_publisher_unit_tests/test_run_daily_version_probe_scrubs_env.py @@ -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." + ) diff --git a/tests/claude_code/cron_vm/run_daily.sh b/tests/claude_code/cron_vm/run_daily.sh index fd44e1bac15..b89d211f905 100755 --- a/tests/claude_code/cron_vm/run_daily.sh +++ b/tests/claude_code/cron_vm/run_daily.sh @@ -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}"