# Sourced by run-audit.sh and run-ux.sh: everything that differs between the # coding agents a lane can run. A MODELS entry is ":"; an # entry with no prefix is an opencode id, so the original spelling still works. # # opencode:/ ids from `opencode models` # codex: slugs the Codex CLI lists in its model picker # (ChatGPT plan or API key, `codex login`) # # A credential enters a lane container through harness_mount and nowhere # else, so each container carries exactly the one file its harness needs: # opencode the host's auth.json, read-only. # codex a copy of the host's ~/.codex/auth.json inside a throwaway # CODEX_HOME, writable because codex rewrites that file when it # refreshes the ChatGPT token. The copy is deleted with the lane; # a refreshed token is copied back first, since the refresh may # have rotated the host's token out of validity. # # VARIANT is the reasoning effort in each harness's own vocabulary. opencode # passes it as --variant. codex passes it as model_reasoning_effort; the set # is per model (low, medium, high, xhigh, max, ultra), and ultra delegates to # subagents inside the same container. # # A plan's usage window can run out mid-task. When a harness reports that, # the lane keeps its state, waits QUOTA_POLL seconds, and resumes the same # session in a fresh container, repeating until the task finishes or # QUOTA_WAIT seconds of waiting are spent. A rejected retry costs nothing. # Detection is per harness; opencode has none yet, so its lanes fail as before. HARNESSES="opencode codex" QUOTA_POLL="${QUOTA_POLL:-900}" QUOTA_WAIT="${QUOTA_WAIT:-21600}" OPENCODE_AUTH="${AUDIT_AUTH_JSON:-$HOME/.local/share/opencode/auth.json}" CODEX_AUTH="${AUDIT_CODEX_AUTH_JSON:-${CODEX_HOME:-$HOME/.codex}/auth.json}" # The Codex Security plugin, as `codex plugin add codex-security@openai-curated-remote` # leaves it on the host. A codex lane ships it in its throwaway CODEX_HOME; # a task that names it (the codex-security/ shape) runs with it on. CODEX_SECURITY_HOST="${AUDIT_CODEX_SECURITY_DIR:-$(dirname "$CODEX_AUTH")/plugins/cache/openai-curated-remote/codex-security}" CODEX_SECURITY_LANE=/root/.codex/plugins/cache/openai-curated-remote/codex-security HARNESS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # docker compose against this runner from any cwd. An array, not only a # function, because `timeout` runs a program and cannot run a function. HARNESS_COMPOSE=(docker compose -f "$HARNESS_DIR/compose.yaml" --project-directory "$HARNESS_DIR") harness_compose() { "${HARNESS_COMPOSE[@]}" "$@"; } # harness_of MODEL: the harness a MODELS entry names; opencode when it names none. harness_of() { local h="${1%%:*}" if [[ "$1" == *:* && " $HARNESSES " == *" $h "* ]]; then echo "$h"; else echo opencode; fi } # model_of MODEL: the entry with a recognised harness prefix removed. model_of() { local h; h="$(harness_of "$1")" if [[ "$1" == "$h:"* ]]; then echo "${1#"$h:"}"; else echo "$1"; fi } # safe_name MODEL: a directory name for the lane. safe_name() { local s="${1//\//__}"; echo "${s//:/__}"; } # harness_auth_path HARNESS: the host file that harness signs in with. harness_auth_path() { case "$1" in opencode) echo "$OPENCODE_AUTH";; codex) echo "$CODEX_AUTH";; esac } # harness_check_auth MODEL...: fail before any container starts if a named # model's harness has no credential on the host. harness_check_auth() { local m h f rc=0 for m in "$@"; do h="$(harness_of "$m")"; f="$(harness_auth_path "$h")" if [[ ! -f "$f" ]]; then echo "ERROR: no $h credential at $f (needed for $m)." >&2 case "$h" in opencode) echo " Sign in on the host with 'opencode auth login' or set AUDIT_AUTH_JSON." >&2;; codex) echo " Sign in on the host with 'codex login' or set AUDIT_CODEX_AUTH_JSON." >&2;; esac rc=1 fi done return $rc } # harness_mount HARNESS STATE_DIR: prints, one per line, the docker arguments # that hand a lane container its credential. STATE_DIR is an absolute path the # lane owns; codex state is created under it. harness_mount() { local h="$1" state="$2" case "$h" in opencode) printf -- '-v\n%s:/root/.local/share/opencode/auth.json:ro\n' "$OPENCODE_AUTH";; codex) mkdir -p "$state/codex-home" install -m 600 "$CODEX_AUTH" "$state/codex-home/auth.json" # Remember which host token the lane started from, so release can tell # a lane-side refresh from a host-side re-login. jq -r '.last_refresh // ""' "$CODEX_AUTH" >"$state/host-last-refresh" 2>/dev/null || : >"$state/host-last-refresh" codex_security_ship "$state/codex-home" printf -- '-v\n%s:/root/.codex\n' "$state/codex-home";; esac } # codex_security_ship CODEX_HOME_DIR: copy the plugin from the host into the # lane's home and write the config that turns it on. codex only reads that # config when a task drops --ignore-user-config (harness_command's PLUGINS # argument), so slices and open briefs never see the plugin. The plugin's # MCP server is registered directly from its .mcp.json, because codex does # not start a plugin's server from the cache alone; the paths are the # container's, since the config is read there. codex_security_ship() { local home="$1" ver [[ -d "$CODEX_SECURITY_HOST" ]] || return 0 ver="$(ls "$CODEX_SECURITY_HOST" | grep -E '^[0-9]' | sort -V | tail -1)" [[ -n "$ver" ]] || return 0 mkdir -p "$home/plugins/cache/openai-curated-remote" cp -r "$CODEX_SECURITY_HOST" "$home/plugins/cache/openai-curated-remote/" python3 - "$CODEX_SECURITY_HOST/$ver/.mcp.json" "$CODEX_SECURITY_LANE/$ver" "$home/config.toml" <<'EOF' import json, sys mcp_json, lane_dir, out = sys.argv[1:4] m = json.load(open(mcp_json))["mcpServers"]["codex-security"] lines = [ '[plugins."codex-security@openai-curated-remote"]', 'enabled = true', '', '[mcp_servers.codex-security]', f'command = "{lane_dir}/scripts/launch_codex_security_mcp"', 'args = ["--stdio"]', f'cwd = "{lane_dir}"', f'startup_timeout_sec = {m["startup_timeout_sec"]}', f'tool_timeout_sec = {m["tool_timeout_sec"]}', 'env_vars = ' + json.dumps(m["env_vars"]), ] open(out, "w").write("\n".join(lines) + "\n") EOF echo "$ver" >"$home/codex-security-version" } # harness_release HARNESS STATE_DIR: after the lane, hand back what the # container changed and remove the state. harness_release() { local h="$1" state="$2" if [[ "$h" == codex ]]; then # The container runs as root and fills CODEX_HOME (system skills, caches, # sqlite state, possibly a rewritten auth.json) with root-owned files, so # the state comes back to the invoking user through a container first. harness_compose run --rm --no-deps -T -v "$state:/state" auditor \ chown -R "$(id -u):$(id -g)" /state >/dev/null 2>&1 || true if [[ -f "$state/codex-home/auth.json" ]]; then # The lane's token goes back to the host only when the lane refreshed # it (strictly newer than what it started from) AND the host still # holds the token the lane started from. A host that re-logged in # meanwhile owns the newer token; overwriting it would hand the host a # revoked one (which is how the sol lane of 2026-09-21 broke the host # login). Timestamps are RFC 3339 UTC, so string order is time order. local started now lane started="$(cat "$state/host-last-refresh" 2>/dev/null || true)" now="$(jq -r '.last_refresh // ""' "$CODEX_AUTH" 2>/dev/null || true)" lane="$(jq -r '.last_refresh // ""' "$state/codex-home/auth.json" 2>/dev/null || true)" if [[ -n "$lane" && "$lane" > "$started" ]]; then if [[ "$now" == "$started" ]]; then install -m 600 "$state/codex-home/auth.json" "$CODEX_AUTH" echo " codex refreshed its ChatGPT token in the lane; the host copy at $CODEX_AUTH now carries it" else echo " codex refreshed its token in the lane, but the host signed in again meanwhile; host left alone, lane copy kept at $state/codex-home/auth.json" return 0 fi fi fi fi rm -rf "$state" rmdir --ignore-fail-on-non-empty "$(dirname "$state")" 2>/dev/null || true } # harness_command HARNESS MODEL VARIANT PROMPT_SH [PLUGINS]: prints the # command a lane runs in the container with `bash -c`. PROMPT_SH is a shell # snippet, run in the container, that prints the prompt. Both agents print # their final answer on stdout and their progress on stderr, so a lane # captures stdout as the artifact and stderr as the log. PLUGINS, when # non-empty, runs the task with the harness's shipped plugins on (codex only). harness_command() { local h="$1" model="$2" variant="$3" prompt_sh="$4" plugins="${5:-}" vflag="" case "$h" in opencode) [[ -n "$variant" ]] && vflag="--variant '$variant'" # stdin closed: the headless quirk. echo "opencode run --model '$model' $vflag \"\$($prompt_sh)\" /dev/null | grep -qiE 'usage.?limit|rate.?limit|spend cap|try again';; *) return 1;; esac } # harness_resume_command HARNESS MODEL VARIANT [PLUGINS]: the command that # continues the lane's most recent session with the same flags. harness_resume_command() { local h="$1" model="$2" variant="$3" plugins="${4:-}" case "$h" in codex) echo "codex exec resume --last $(codex_flags "$model" "$variant" "$plugins")" \ "'A usage limit interrupted you. Continue from where you stopped and finish the report in the required shape.'";; esac } # harness_run_task HARNESS MODEL VARIANT PROMPT_SH OUT ERR LANE_LOG [ENV_SH] # [PLUGINS]: runs one task to completion. Every attempt is a fresh --rm # container; stdout appends to OUT (the artifact), stderr to ERR (the log). # The caller puts the lane's docker arguments (credential mount, extra # volumes) in the LANE_DOCKER array and sets TIMEOUT, the budget of a single # attempt. ENV_SH is a shell snippet run in the container before the agent # (exports a task needs); PLUGINS turns the shipped plugins on. Returns the # last exit code. harness_run_task() { local h="$1" model="$2" variant="$3" prompt_sh="$4" out="$5" err="$6" lane_log="$7" env_sh="${8:-}" plugins="${9:-}" local cmd attempt=1 rc deadline=$(( $(date +%s) + QUOTA_WAIT )) cmd="$(harness_command "$h" "$model" "$variant" "$prompt_sh" "$plugins")" : >"$out"; : >"$err" while :; do echo "== attempt $attempt, $(date -Is)" >>"$err" if timeout "$TIMEOUT" "${HARNESS_COMPOSE[@]}" run --rm --no-deps -T "${LANE_DOCKER[@]}" auditor \ bash -c "${env_sh:+$env_sh; }$cmd" >>"$out" 2>>"$err"; then rc=0; else rc=$?; fi if grep -q 'Automatically switched' "$err"; then echo " note: the harness switched model mid-run (usage limits); see $err" | tee -a "$lane_log" fi if [[ $rc -eq 0 ]]; then return 0; fi if ! harness_quota_hit "$h" "$err"; then # Not a quota stop: put the harness's own ERROR lines in the lane log so # a SUSPECT verdict explains itself (a policy refusal, an auth failure). grep -E '^ERROR:' "$err" | sort -u | sed 's/^/ /' >>"$lane_log" || true return $rc fi if (( $(date +%s) + QUOTA_POLL > deadline )); then echo " quota: wait budget (QUOTA_WAIT=${QUOTA_WAIT}s) spent after $attempt attempt(s)" | tee -a "$lane_log" return $rc fi echo " quota: usage limit on attempt $attempt at $(date +%H:%M:%S); resuming in ${QUOTA_POLL}s" | tee -a "$lane_log" sleep "$QUOTA_POLL" cmd="$(harness_resume_command "$h" "$model" "$variant" "$plugins")" attempt=$((attempt + 1)) done } # harness_own_output DIR: files an agent wrote under the findings mount belong # to root; hand the lane's directory back to the invoking user. DIR is a host # path under OUT. harness_own_output() { local dir="$1" rel="${1#"$OUT"/}" [[ -d "$dir" && "$rel" != "$1" ]] || return 0 harness_compose run --rm --no-deps -T auditor chown -R "$(id -u):$(id -g)" "/out/$rel" >/dev/null 2>&1 || true }