fix(compat-matrix): keep publish token out of the job-wide process env

The mateo-berri PAT now arrives via systemd LoadCredential as a file
instead of the EnvironmentFile, so pytest, the proxy, and the
model-driven claude CLI never inherit it and a same-UID /proc read
cannot lift it. run_daily.sh reads the credential when present, still
accepts an exported GITHUB_TOKEN for manual runs, and dies up front
when publishing is enabled with neither. Full CLI sandboxing is
tracked in LIT-5420
This commit is contained in:
mateo-berri 2026-08-11 00:57:25 +00:00
parent 123561527b
commit 08bea8d0dd
4 changed files with 58 additions and 22 deletions

View file

@ -118,11 +118,16 @@ git -C ~/litellm/litellm checkout litellm_internal_staging
# 4. gh auth — must be a collaborator on BerriAI/litellm-docs.
gh auth login # follow prompts; pick HTTPS + token paste flow
# 5. Provider credentials.
# 5. Provider credentials + the publish token.
sudo cp ~/litellm/litellm/tests/e2e/claude_code/cron_vm/litellm-compat-matrix.env.example \
/etc/litellm-compat-matrix.env
sudoedit /etc/litellm-compat-matrix.env # fill in real values
sudo chmod 0600 /etc/litellm-compat-matrix.env
# The mateo-berri PAT lives in its own file, mapped into the service via
# systemd LoadCredential so it stays out of the test processes' env
# (see the env.example comment for why).
sudo install -m 0600 /dev/null /etc/litellm-compat-matrix-github-token
sudoedit /etc/litellm-compat-matrix-github-token # single line: the PAT
# 6. systemd units.
sudo cp ~/litellm/litellm/tests/e2e/claude_code/cron_vm/litellm-compat-matrix.service /etc/systemd/system/
@ -171,13 +176,16 @@ sudo systemctl disable --now litellm-compat-matrix.timer
- **`uv sync --frozen` requires the resolved tag to be tagged on
GitHub.** If the latest stable release was made but not pushed as a
git tag, the `git checkout` step fails. Push the tag, then rerun.
- **`GITHUB_TOKEN` rotation is your problem.** The cron does not
- **Publish-token rotation is your problem.** The cron does not
refresh the token; if `mateo-berri`'s PAT in
`/etc/litellm-compat-matrix.env` expires, the run fails at the
`git push`/`gh pr create` step with a 401 ("Bad credentials" /
"Authentication failed"). Mint a fresh PAT and update the env file.
`/etc/litellm-compat-matrix-github-token` expires, the run fails at
the `git push`/`gh pr create` step with a 401 ("Bad credentials" /
"Authentication failed"). Mint a fresh PAT and update that file.
The token needs write access to `BerriAI/litellm-docs` (classic
`repo` scope, or fine-grained Contents:RW + Pull requests:RW).
`repo` scope, or fine-grained Contents:RW + Pull requests:RW). It is
delivered via systemd `LoadCredential`, not the env file, so pytest,
the proxy, and the claude CLI never inherit it; manual runs export
`GITHUB_TOKEN` instead.
- **First run after upgrading the Claude Code CLI is the riskiest one.**
If the new CLI changes its wire format the matrix run can produce
systematic failures. Always run with `SKIP_PUBLISH=1` after a CLI

View file

@ -34,16 +34,20 @@ OPENAI_API_KEY=
AZURE_API_BASE=
AZURE_API_KEY=
# REQUIRED for publishing: PAT for the `mateo-berri` user, who has write
# access on BerriAI/litellm-docs. Used to (a) resolve the latest stable
# release, (b) push the daily compat-matrix branch directly to
# BerriAI/litellm-docs, (c) open the same-repo PR, and (d) enable
# squash auto-merge on it. Scopes: classic `repo` + `workflow`, or
# fine-grained on BerriAI/litellm-docs with Contents:RW + Pull
# requests:RW + Workflows:RW.
# Skip by setting SKIP_PUBLISH=1 (publishes nothing; only writes the
# matrix JSON locally).
GITHUB_TOKEN=
# The publish PAT (mateo-berri, write access on BerriAI/litellm-docs)
# deliberately does NOT live in this file. Everything here lands in the
# process environment of pytest, the proxy, and the model-driven claude
# CLI, where any same-UID reader can lift it from /proc/<pid>/environ.
# Instead, install the token at /etc/litellm-compat-matrix-github-token
# (chmod 0600, single line); the service maps it in via systemd
# LoadCredential and run_daily.sh keeps it out of every child process
# env. Used to (a) resolve the latest stable release, (b) push the
# daily compat-matrix branch directly to BerriAI/litellm-docs, (c) open
# the same-repo PR, and (d) enable squash auto-merge on it. Scopes:
# classic `repo` + `workflow`, or fine-grained on BerriAI/litellm-docs
# with Contents:RW + Pull requests:RW + Workflows:RW.
# Manual runs export GITHUB_TOKEN instead, or skip publishing entirely
# with SKIP_PUBLISH=1 (only writes the matrix JSON locally).
# Optional: the bedrock_mantle column is opt-in because the AWS account
# needs the Mantle (OpenAI-on-Bedrock) models enabled. Without this the

View file

@ -28,7 +28,10 @@
# * have `gh` already authenticated against an account with
# `pull-requests: write` on `BerriAI/litellm-docs`;
# * have provider credentials exported in `/etc/litellm-compat-matrix.env`
# (see `litellm-compat-matrix.env.example` in this directory).
# (see `litellm-compat-matrix.env.example` in this directory);
# * have the mateo-berri publish PAT at
# `/etc/litellm-compat-matrix-github-token` (chmod 0600, single
# line), delivered via `LoadCredential=` below.
[Unit]
Description=Claude Code compatibility-matrix populator (oneshot)
@ -45,6 +48,15 @@ Group=mateo
# is the standard `KEY=value` one line per env var.
EnvironmentFile=-/etc/litellm-compat-matrix.env
# The mateo-berri publish PAT is mapped in via the credential store, NOT
# the EnvironmentFile, so it never lands in the process environment that
# pytest, the proxy, and the model-driven claude CLI inherit (any
# same-UID process can read /proc/<pid>/environ). run_daily.sh reads
# ${CREDENTIALS_DIRECTORY}/github-token and hands it to gh per call.
# Unlike EnvironmentFile= above, this is deliberately NOT optional: a
# missing token file fails the unit at start instead of 30 minutes in.
LoadCredential=github-token:/etc/litellm-compat-matrix-github-token
# systemd starts with a minimal PATH (~/usr/local/bin:/usr/bin:/bin).
# `uv` and `claude` are installed under the runtime user's `~/.local/bin`
# so we have to prepend it explicitly; otherwise run_daily.sh fails at

View file

@ -113,13 +113,25 @@ for cmd in git uv gh jq curl claude; do
done
# Publishing pushes the branch straight to BerriAI/litellm-docs and opens
# the PR as mateo-berri, who has write access on the docs repo. The same
# ${GITHUB_TOKEN} is reused for release-listing above, so require it up
# front -- failing 30 minutes into a run because the env file is missing
# one line is a waste of CI quota.
# the PR as mateo-berri, who has write access on the docs repo. Under
# systemd the PAT arrives as a file via LoadCredential=, NOT via the
# EnvironmentFile: several suite cells let the model-driven claude CLI
# read arbitrary files as this user, and /proc/<pid>/environ of the
# script, pytest, and the proxy would hand an env-borne token to any
# same-UID reader. Kept as an unexported shell variable and passed per
# invocation (GH_TOKEN=... / curl header / push URL), it never enters a
# child's environment. Manual runs may export GITHUB_TOKEN instead.
# Require it up front -- failing 30 minutes into a run is a waste of CI
# quota.
if [[ -z "${GITHUB_TOKEN:-}" && -n "${CREDENTIALS_DIRECTORY:-}" && -f "${CREDENTIALS_DIRECTORY}/github-token" ]]; then
GITHUB_TOKEN="$(<"${CREDENTIALS_DIRECTORY}/github-token")"
log "publish token source: systemd credential store"
elif [[ -n "${GITHUB_TOKEN:-}" ]]; then
log "publish token source: process environment"
fi
if [[ "${SKIP_PUBLISH}" != "1" ]]; then
[[ -n "${GITHUB_TOKEN:-}" ]] \
|| die "GITHUB_TOKEN (mateo-berri, write access to ${DOCS_REPO}) required to push the branch and open the PR (or set SKIP_PUBLISH=1)"
|| die "publish token required: /etc/litellm-compat-matrix-github-token via LoadCredential under systemd, or an exported GITHUB_TOKEN for manual runs (or set SKIP_PUBLISH=1)"
fi
# ---------------------------------------------------------------------------