Skip to main content

Module agent_env

Module agent_env 

Source
Expand description

Cleared-environment construction for every prompt-injectable child the engine spawns (ticket agent-env-clear, P1 of the 2026-07-28 hostile-workload review).

Before this module, agent CLI sessions spawned with .envs(&spec.env) overlaid on the FULL ambient environment (backend_claude.rs), and contract command assertions ran with clear_env = false (command_exec.rs) — so ambient server secrets (Slack tokens, GH_TOKEN, cloud credentials, remote-workspace tokens) reached every prompt-injectable child. Now:

  • Agent CLI sessions (claude/codex/droid/kimi/cursor backends) spawn with env_clear + sanitized_child_env: PATH, a scratch HOME, locale vars, and nothing else — plus backend-specific auth injected explicitly (agent_session_env), never the ambient set.
  • Contract/gate commands (validation round, final gate, approval-time contract lint) run with env_clear + contract_command_env: the sanitized base plus KRANZ_BASE_SHA, a cache-only Cargo home, the non-credential toolchain locations, and at most the operator’s contractEnvPassthrough names.

The ENGINE process itself keeps its ambient environment — the clearing applies to child processes only. Merge gates keep their own pre-existing command_exec::sanitized_gate_env allowlist (it intentionally retains ambient HOME/CI/temp dirs for the operator’s toolchain; not a clean swap for this module’s scratch-HOME shape, so both lists stay, each documented at its site) — with ONE exception: the gate env never carries the ambient CARGO_HOME, which run_bounded_gate_command replaces with a fresh [cache_only_cargo_home] exactly like the contract env. Under worker.sandbox.enforce != off the merge gate additionally runs WRAPPED in the resolved sandbox profile (command_exec::run_bounded_gate_command_sandboxed): the ambient HOME pass-through stays (git identity needs ~/.gitconfig), and the profile makes it read-only — containment by the sandbox, not by env rewrite.

Secret hygiene: only variable NAMES are ever logged here (the injected auth key’s name, the passthrough names applied/skipped) — never values.

Functions§

agent_session_env
The cleared env for one agent CLI session, uniform across the spawning backends (claude/codex/droid/kimi/cursor).
contract_command_env
The cleared env for one contract/gate command execution (validation round, final gate, approval-time lint — design decision 3 of the ticket): sanitized_child_env over the per-mission writable mission_scratch home, plus
sanitized_child_env
Build a cleared child environment from scratch: EXACTLY PATH (from ambient — binaries must resolve), HOME = base_home (the scratch dir the session/command already gets, never the operator’s real home), TMPDIR = base_home/tmp, the ambient locale vars when present, the non-credential toolchain locations plus the cache-only Cargo home ([CONTRACT_TOOLCHAIN_VARS] / [cache_only_cargo_home]; without cache seeding every agent session re-downloads the registry into scratch, which filled the disk and killed mission m-533143), and on Windows the process-required passthroughs (AMBIENT_WINDOWS_VARS) plus USERPROFILE = base_home, TEMP/TMP = base_home/tmp, and APPDATA/LOCALAPPDATA = base_home/AppData/{Roaming,Local}. Then extra is applied verbatim, in order — that is where KRANZ_BASE_SHA, proxy wiring, git identity, and backend-specific auth go. NOTHING else crosses from ambient.
session_env_with_home
agent_session_env with an explicit base_home — the claude backend uses this after seeding a fresh scratch home (OAuth credentials copy) for a spec that carried no relocated HOME, so the seeded dir is the HOME the child actually gets.
session_scratch_home
The per-session scratch HOME used when a session spec carries no relocated HOME of its own: the home dir under the same per-session scratch root worker relocation uses (crate::backend_claude::scratch_home_root), so sandboxed sessions get a HOME inside their writable TMPDIR allowlist either way.