@@ -6,12 +6,17 @@ cd "$ROOT"
66
77STRICT_RUNTIME=0
88CODEX_HOME_DIR=" "
9+ MODE=" auto"
910
1011usage () {
1112 cat << 'EOF '
12- Usage: scripts/validate_runtime.sh [--codex-home PATH] [--strict-runtime]
13+ Usage: scripts/validate_runtime.sh [--codex-home PATH] [--strict-runtime] [--mode auto|static|installed|live]
1314
14- Runs installed-runtime validation against a temporary CODEX_HOME by default.
15+ Modes:
16+ auto Static materialization plus best-effort installed-runtime probes (default).
17+ static No codex binary and no network; materialize and parse generated TOML only.
18+ installed Require a local codex binary; no package-registry freshness checks.
19+ live Require a local codex binary and run network-backed freshness checks.
1520EOF
1621}
1722
@@ -24,6 +29,18 @@ while [ "$#" -gt 0 ]; do
2429 --strict|--strict-runtime)
2530 STRICT_RUNTIME=1
2631 ;;
32+ --mode)
33+ shift
34+ MODE=${1:? --mode requires auto, static, installed, or live}
35+ case " $MODE " in
36+ auto|static|installed|live) ;;
37+ * )
38+ printf ' Invalid --mode: %s\n' " $MODE " >&2
39+ usage >&2
40+ exit 2
41+ ;;
42+ esac
43+ ;;
2744 -h|--help)
2845 usage
2946 exit 0
5774
5875scripts/install_system_codex.sh --dry-run --codex-home " $CODEX_HOME_DIR " " ${strict_args[@]} "
5976scripts/install_system_codex.sh --apply --codex-home " $CODEX_HOME_DIR " " ${strict_args[@]} "
77+
78+ python3 - " $CODEX_HOME_DIR " << 'PY '
79+ from __future__ import annotations
80+
81+ import re
82+ import sys
83+ import tomllib
84+ from pathlib import Path
85+
86+ home = Path(sys.argv[1])
87+ config = home / "config.toml"
88+ yolo = home / "rldyour-yolo.config.toml"
89+ safe = home / "rldyour-safe.config.toml"
90+ required = [config, yolo, safe]
91+
92+
93+ def fail(message: str) -> None:
94+ print(f"static materialization check failed: {message}", file=sys.stderr)
95+ raise SystemExit(1)
96+
97+
98+ def load(path: Path) -> dict:
99+ if not path.exists():
100+ fail(f"missing generated file {path}")
101+ text = path.read_text(encoding="utf-8")
102+ if "default_permissions" in text:
103+ fail(f"{path.name} contains active default_permissions while legacy sandbox is selected")
104+ if re.search(r"^\s*\[profiles\.", text, re.M):
105+ fail(f"{path.name} contains legacy [profiles.*] table")
106+ if re.search(r"^\s*profile\s*=", text, re.M):
107+ fail(f"{path.name} contains legacy profile selector")
108+ if "plugin_hooks" in text:
109+ fail(f"{path.name} contains removed plugin_hooks feature flag")
110+ with path.open("rb") as fh:
111+ return tomllib.load(fh)
112+
113+
114+ base, yolo_cfg, safe_cfg = [load(path) for path in required]
115+ features = base.get("features") or {}
116+ if features.get("hooks") is not True:
117+ fail("config.toml must enable features.hooks")
118+ if features.get("multi_agent") is not True:
119+ fail("config.toml must enable features.multi_agent")
120+ if "plugin_hooks" in features:
121+ fail("config.toml must not enable removed features.plugin_hooks")
122+ if not base.get("mcp_servers"):
123+ fail("config.toml must materialize [mcp_servers.*] entries")
124+ if yolo_cfg.get("approval_policy") != "never":
125+ fail("rldyour-yolo.config.toml must set approval_policy = \"never\"")
126+ if yolo_cfg.get("sandbox_mode") != "danger-full-access":
127+ fail("rldyour-yolo.config.toml must set sandbox_mode = \"danger-full-access\"")
128+ if safe_cfg.get("approval_policy") != "on-request":
129+ fail("rldyour-safe.config.toml must set approval_policy = \"on-request\"")
130+ if safe_cfg.get("sandbox_mode") != "workspace-write":
131+ fail("rldyour-safe.config.toml must set sandbox_mode = \"workspace-write\"")
132+ print("ok: static Codex runtime materialization")
133+ PY
134+
135+ if [ " $MODE " = " static" ]; then
136+ printf ' Static runtime validation passed with CODEX_HOME=%s.\n' " $CODEX_HOME_DIR "
137+ exit 0
138+ fi
139+
60140scripts/doctor_system_codex.sh --quick --codex-home " $CODEX_HOME_DIR " " ${strict_args[@]} "
61141if command -v codex > /dev/null 2>&1 ; then
62142 CODEX_HOME=" $CODEX_HOME_DIR " scripts/validate_execpolicy_rules.sh " $CODEX_HOME_DIR /rules"
63143 CODEX_HOME=" $CODEX_HOME_DIR " python3 scripts/smoke_codex_hook_listing.py --codex-home " $CODEX_HOME_DIR "
64- elif [ " $STRICT_RUNTIME " -eq 1 ]; then
65- printf ' codex command not found; strict runtime execpolicy validation cannot run.\n' >&2
144+ elif [ " $STRICT_RUNTIME " -eq 1 ] || [ " $MODE " = " installed " ] || [ " $MODE " = " live " ] ; then
145+ printf ' codex command not found; installed runtime validation cannot run.\n' >&2
66146 exit 1
67147else
68148 printf ' skip execpolicy rules validation: codex command not found\n'
@@ -71,4 +151,8 @@ scripts/smoke_hooks.sh --codex-home "$CODEX_HOME_DIR"
71151scripts/smoke_fullrepo_sync.sh
72152scripts/smoke_fullrepo_bootstrap_init.sh
73153
74- printf ' Runtime validation passed with CODEX_HOME=%s.\n' " $CODEX_HOME_DIR "
154+ if [ " $MODE " = " live" ]; then
155+ python3 scripts/check_mcp_runtime_versions.py
156+ fi
157+
158+ printf ' Runtime validation passed in %s mode with CODEX_HOME=%s.\n' " $MODE " " $CODEX_HOME_DIR "
0 commit comments