feat: add production Core runtime modes

This commit is contained in:
thanhnv
2026-07-24 12:16:11 +07:00
parent e359989a74
commit eb3525456f
13 changed files with 659 additions and 397 deletions
+221 -30
View File
@@ -1,10 +1,10 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""`casan init` / `casan verify-harness` (Plan-21 hybrid adoption).
"""`casan init` / `casan verify-harness` (Plan-21 production adoption).
Adopt CASAN into an EXISTING project by writing only per-project config — the
shared harness stays under $CASAN_HOME and is NOT copied into the repo. This is
the codegraph-style flow: global install once, then `casan init` per project.
Adopt CASAN into an EXISTING project using an explicit runtime contract:
managed mode pins the shared Core under $CASAN_HOME; vendored mode installs the
same production-only Core under `.casan/runtime/casan-core`.
What init writes into the target repo:
.casan/config.json project id, enforcement/integration mode, clients
@@ -13,6 +13,8 @@ What init writes into the target repo:
.specify/ runtime state root marker (logs/traces/admissions)
.claude/settings.json Plan-20 Claude Code hooks (--client claude|all)
.codex/hooks.json+config Plan-20 Codex hooks (--client codex|all)
.casan/runtime/casan-core
optional self-contained Core (--runtime vendored)
`verify` recomputes the resolved harness gate-code hash and compares it to
version.lock — the pin+VERIFY half. Drift/tamper of the global harness relative
@@ -107,6 +109,8 @@ def _render_init(result):
("Location", result["target"]),
("Level", "%s (%s)" % (
result["target_level_name"].capitalize(), result["target_level"])),
("Runtime", "%s — %s" % (
result["runtime_mode"].capitalize(), result["runtime_path"])),
("Mode", result["enforcement_mode"]),
("Clients", _client_names(result["clients"])),
("Files", "%d created or updated" % len(result["created"])),
@@ -149,6 +153,10 @@ def _render_level(result):
result.get("project_target_level_name"),
result.get("project_target_level")))
if result.get("project_target_level") else "not initialized"),
("Runtime", ("%s — %s" % (
result.get("project_runtime_mode"),
result.get("project_runtime_path")))
if result.get("project_target_level") else "not initialized"),
("Status", str(result.get("project_level_status") or "unknown")),
])
print()
@@ -270,7 +278,10 @@ def _copy_tree_missing(src_dir, dst_dir, target, created):
def resolve_harness(explicit):
for cand in (explicit, os.environ.get("CASAN_HARNESS_ROOT")):
for cand in (
explicit,
os.environ.get("CASAN_HARNESS_ROOT"),
os.environ.get("CASAN_GLOBAL_HARNESS_ROOT")):
if cand and os.path.isdir(os.path.join(cand, "scripts", "bash")):
return os.path.abspath(cand)
install = os.environ.get("CASAN_INSTALL_ROOT")
@@ -290,8 +301,9 @@ def install_root(harness):
def harness_version(harness):
for p in (os.path.join(install_root(harness), "VERSION"),
os.path.join(harness, "..", "..", "VERSION")):
local_root = os.path.abspath(os.path.join(harness, "..", ".."))
for p in (os.path.join(local_root, "VERSION"),
os.path.join(install_root(harness), "VERSION")):
try:
with open(p, "r", encoding="utf-8") as fh:
v = fh.read().strip()
@@ -317,17 +329,38 @@ def compute_harness_hash(harness):
"""For PINNING at init: use the value recorded at install time if present
(it equals a live compute of the same files), else compute live. Verify must
NOT use this — it must call compute_live() to detect drift."""
recorded = os.path.join(install_root(harness), ".harness-hash")
try:
with open(recorded, "r", encoding="utf-8") as fh:
v = fh.read().strip()
if v:
return v, "recorded"
except (OSError, IOError):
pass
local_root = os.path.abspath(os.path.join(harness, "..", ".."))
for recorded in (
os.path.join(local_root, ".harness-hash"),
os.path.join(install_root(harness), ".harness-hash")):
try:
with open(recorded, "r", encoding="utf-8") as fh:
v = fh.read().strip()
if v:
return v, "recorded"
except (OSError, IOError):
continue
return compute_live(harness)
def resolve_project_harness(target, explicit=None):
lock = _load_json_or(
os.path.join(target, ".casan", "version.lock"), {})
runtime_path = lock.get("runtime_path")
if lock.get("runtime_mode") == "vendored" and isinstance(runtime_path, str):
root = (
None if os.path.isabs(runtime_path)
else _safe_project_path(target, runtime_path)
)
if not root:
return None
candidate = os.path.join(root, "packages", "casan-harness")
if os.path.isdir(os.path.join(candidate, "scripts", "bash")):
return os.path.abspath(candidate)
return None
return resolve_harness(explicit)
def _write(path, text, backups):
with owner_writable(path):
if os.path.exists(path):
@@ -366,8 +399,10 @@ def _safe_project_path(target, relative):
if not normalized or os.path.isabs(str(relative)):
return None
candidate = os.path.abspath(os.path.join(target, *normalized.split("/")))
target_real = os.path.realpath(target)
candidate_real = os.path.realpath(candidate)
try:
if os.path.commonpath((target, candidate)) != target:
if os.path.commonpath((target_real, candidate_real)) != target_real:
return None
except ValueError:
return None
@@ -387,6 +422,110 @@ def _file_sha256(path):
return digest.hexdigest()
def _install_vendored_core(target, source_harness):
"""Atomically install the production Core runtime inside one project."""
source_root = os.path.abspath(os.path.join(source_harness, "..", ".."))
copier = os.path.join(source_root, "scripts", "copy-runtime.py")
source_bin = os.path.join(source_root, "bin", "casan")
source_version = os.path.join(source_root, "VERSION")
for required in (source_bin, source_version):
if not os.path.isfile(required):
raise RuntimeError(
"vendored runtime source is incomplete; missing %s" % required)
destination = _safe_project_path(
target, ".casan/runtime/casan-core")
if not destination:
raise RuntimeError(
"vendored runtime path escapes the project through a symlink")
parent = os.path.dirname(destination)
os.makedirs(parent, exist_ok=True)
staging = tempfile.mkdtemp(prefix=".casan-core-", dir=parent)
try:
if os.path.isfile(copier):
result = subprocess.run(
[
sys.executable,
copier,
"--source-root", source_root,
"--destination-root", staging,
"--component", "harness",
"--clean",
],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
check=False,
)
if result.returncode != 0:
raise RuntimeError(
result.stderr.strip() or result.stdout.strip() or
"production runtime copy failed")
else:
shutil.copytree(
source_harness,
os.path.join(staging, "packages", "casan-harness"))
vendored_harness = os.path.join(
staging, "packages", "casan-harness")
forbidden = [
relative for relative in (
"tests",
"level5",
"scripts/bash/ci-harness-gate.sh",
"scripts/bash/security-gate.sh",
"scripts/bash/dashboard-server.py",
)
if os.path.exists(os.path.join(
vendored_harness, *relative.split("/")))
]
if forbidden:
raise RuntimeError(
"source is not a production runtime; forbidden paths: %s" %
", ".join(forbidden))
os.makedirs(os.path.join(staging, "bin"), exist_ok=True)
shutil.copy2(source_bin, os.path.join(staging, "bin", "casan"))
shutil.copy2(source_version, os.path.join(staging, "VERSION"))
with open(os.path.join(staging, ".casan-level"), "w",
encoding="utf-8") as fh:
fh.write("core\n")
vendored_hash, hash_source = compute_live(vendored_harness)
if hash_source == "error":
raise RuntimeError(
"cannot verify staged vendored Core: %s" % vendored_hash)
with open(os.path.join(staging, ".harness-hash"), "w",
encoding="utf-8") as fh:
fh.write(vendored_hash + "\n")
if os.path.isdir(destination) and not os.path.islink(destination):
shutil.rmtree(destination)
elif os.path.exists(destination) or os.path.islink(destination):
os.unlink(destination)
os.replace(staging, destination)
staging = None
finally:
if staging and os.path.isdir(staging):
shutil.rmtree(staging)
file_count = sum(
len(files) for _root, _dirs, files in os.walk(destination))
return destination, file_count
def _remove_vendored_core(target):
destination = _safe_project_path(
target, ".casan/runtime/casan-core")
if not destination:
return False
if not os.path.exists(destination) and not os.path.islink(destination):
return False
with owner_writable(destination):
if os.path.isdir(destination) and not os.path.islink(destination):
shutil.rmtree(destination)
else:
os.unlink(destination)
_prune_empty_parents(destination, target)
return True
def _backup_once(path, backups):
if backups is None:
return
@@ -831,8 +970,38 @@ def cmd_init(args):
except ValueError as error:
sys.stderr.write("casan init: %s\n" % error)
return 64
version = harness_version(harness)
hhash, hsource = compute_harness_hash(harness)
previous_config = _load_json_or(
os.path.join(target, ".casan", "config.json"), {})
previous_runtime_mode = previous_config.get("runtime_mode")
runtime_mode = (
args.runtime or
(previous_runtime_mode
if previous_runtime_mode in ("managed", "vendored") else "managed")
)
runtime_removed = False
runtime_files = 0
if runtime_mode == "vendored":
try:
runtime_root, runtime_files = _install_vendored_core(
target, harness)
except (OSError, RuntimeError) as error:
sys.stderr.write(
"casan init: cannot install vendored Core runtime: %s\n" %
error)
return 1
active_harness = os.path.join(
runtime_root, "packages", "casan-harness")
runtime_path = os.path.relpath(
runtime_root, target).replace(os.sep, "/")
else:
runtime_removed = _remove_vendored_core(target)
active_harness = harness
runtime_root = install_root(harness)
runtime_path = runtime_root
version = harness_version(active_harness)
hhash, hsource = compute_harness_hash(active_harness)
created = []
backups = []
previous_manifest = _load_json_or(
@@ -889,7 +1058,11 @@ def cmd_init(args):
"vscode-native-copilot": "unsupported_global_interception",
},
"harness_version": version,
"adoption_model": "hybrid-global",
"adoption_model": (
"managed-global" if runtime_mode == "managed"
else "vendored-project"),
"runtime_mode": runtime_mode,
"runtime_path": runtime_path,
"target_level": lvl,
"target_level_name": lvl_name,
}
@@ -903,7 +1076,9 @@ def cmd_init(args):
"harness_hash": hhash,
"hash_algo": "sha256",
"hash_source": hsource,
"install_root": install_root(harness),
"install_root": runtime_root,
"runtime_mode": runtime_mode,
"runtime_path": runtime_path,
"recorded_at": now_iso(),
}
p = os.path.join(cfg_dir, "version.lock")
@@ -924,7 +1099,7 @@ def cmd_init(args):
_write(p, "\n".join(env_lines), backups); created_add(p)
# Stable project-local bootstrap. It loads the config above, resolves the
# global harness and verifies version.lock before dispatching an adapter.
# managed/vendored Core and verifies version.lock before dispatching.
bootstrap_source = os.path.join(devkit_root(), "templates", "project",
"casan-hook.py")
bootstrap_target = os.path.join(cfg_dir, "casan-hook.py")
@@ -1067,6 +1242,10 @@ def cmd_init(args):
"target_level_name": lvl_name,
"harness_version": version,
"harness_hash": hhash,
"runtime_mode": runtime_mode,
"runtime_path": runtime_path,
"runtime_files": runtime_files,
"runtime_removed": runtime_removed,
"enforcement_mode": args.mode,
"clients": clients,
"created": created,
@@ -1076,8 +1255,11 @@ def cmd_init(args):
"level_extras": level_extras,
"level_removed": level_removed,
"level_retained": level_retained,
"note": ("harness NOT copied into repo (hybrid model); selected client hooks "
"MERGED and unselected CASAN hooks removed; run `casan doctor`"),
"note": (
"managed runtime is referenced by version/hash lock"
if runtime_mode == "managed" else
"production-only Core runtime vendored under .casan/runtime/casan-core"
),
}
_emit_json_or_human(args, result, _render_init)
if legacy_migration.get("manual_review"):
@@ -1096,11 +1278,11 @@ def cmd_init(args):
def cmd_verify(args):
harness = resolve_harness(args.harness)
if not harness:
sys.stderr.write("casan verify-harness: cannot locate the harness.\n")
return 1
target = os.path.abspath(args.target or os.getcwd())
harness = resolve_project_harness(target, args.harness)
if not harness:
sys.stderr.write("casan verify-harness: cannot locate the project runtime.\n")
return 1
lock_path = os.path.join(target, ".casan", "version.lock")
if not os.path.exists(lock_path):
sys.stderr.write("casan verify-harness: no .casan/version.lock (run `casan init` first).\n")
@@ -1120,8 +1302,8 @@ def cmd_verify(args):
}
_emit_json_or_human(args, result, _render_verify)
if not ok:
sys.stderr.write("HARNESS_INTEGRITY_DRIFT — the resolved harness does not match the "
"project pin. The global harness changed or was tampered.\n")
sys.stderr.write("HARNESS_INTEGRITY_DRIFT — the resolved Core runtime does not match "
"the project pin. The runtime changed or was tampered.\n")
return 3
return 0
@@ -1144,6 +1326,8 @@ def cmd_level(args):
"installed_level": installed,
"project_target_level": tl,
"project_target_level_name": cfg.get("target_level_name"),
"project_runtime_mode": cfg.get("runtime_mode", "managed"),
"project_runtime_path": cfg.get("runtime_path"),
"project_level_status": status_map.get(tl, "unknown") if tl else None,
"levels": {
"1 core": "implemented — harness + gates + CLI",
@@ -1217,7 +1401,7 @@ def cmd_doctor(args):
else:
clients = config.get("clients") or []
harness = resolve_harness(args.harness)
harness = resolve_project_harness(target, args.harness)
lock = _load_json_or(os.path.join(target, ".casan", "version.lock"), {})
expected = lock.get("harness_hash")
actual, source = compute_live(harness) if harness else ("unavailable", "error")
@@ -1502,6 +1686,8 @@ def cmd_uninstall(args):
removed, retained = _remove_owned_project_artifacts(
target, owned_files, owned_file_hashes)
if _remove_vendored_core(target):
removed.append(".casan/runtime/casan-core")
for relative in (
".casan/config.json",
@@ -1567,6 +1753,11 @@ def main(argv=None):
"(default auto: install when `code` is available)"))
pi.add_argument("--level", default="core",
help="packaging level to adopt: 1|core (default), 2|devkit, 3|platform (preview), 4|enterprise (refused)")
pi.add_argument(
"--runtime", choices=["managed", "vendored"],
help=("Core runtime placement: managed uses the pinned global install "
"(default for new adoption); vendored copies a production-only "
"Core into the project; re-init preserves the current mode"))
pi.add_argument("--mode", choices=["observe", "enforce"], default="enforce",
help="agentic policy mode (default: enforce; use observe for a telemetry-only pilot)")
pi.add_argument("--integration-mode", dest="integration_mode",
@@ -1,13 +1,13 @@
#!/usr/bin/env python3
"""Project-local bootstrap for CASAN's globally installed agentic adapters.
"""Project-local bootstrap for CASAN's managed or vendored agentic adapters.
This file is intentionally small and stdlib-only. It is the stable command
target committed by `casan init`; the policy implementation remains in the
versioned global CASAN installation. On every hook invocation it:
target committed by `casan init`; the policy implementation is resolved from
the project lock. On every hook invocation it:
1. locates the project and loads `.casan/config.json`;
2. applies the project's enforcement/integration settings to the process;
3. resolves the pinned global harness and verifies its live integrity hash;
3. resolves the pinned managed/vendored Core and verifies its live integrity hash;
4. dispatches stdin/stdout to the selected client adapter.
The bootstrap never calls a model.
@@ -46,8 +46,22 @@ def find_project_root(start):
return None
def harness_candidates(lock):
def harness_candidates(lock, project_root):
values = []
runtime_path = lock.get("runtime_path")
if lock.get("runtime_mode") == "vendored":
if not isinstance(runtime_path, str) or os.path.isabs(runtime_path):
return values
normalized = os.path.normpath(runtime_path)
candidate = os.path.abspath(os.path.join(project_root, normalized))
try:
inside_project = os.path.commonpath(
(project_root, candidate)) == project_root
except ValueError:
inside_project = False
if not inside_project:
return values
return [os.path.join(candidate, "packages", "casan-harness")]
explicit = os.environ.get("CASAN_HARNESS_ROOT")
if explicit:
values.append(explicit)
@@ -69,8 +83,8 @@ def harness_candidates(lock):
return values
def resolve_harness(lock):
for candidate in harness_candidates(lock):
def resolve_harness(lock, project_root):
for candidate in harness_candidates(lock, project_root):
root = os.path.abspath(os.path.expanduser(candidate))
if os.path.isfile(os.path.join(root, "scripts", "python",
"agentic_bridge.py")):
@@ -178,7 +192,7 @@ def main(argv=None):
"vscode-copilot": "vscode"}.get(item, item) for item in enabled)
lock = load_json(os.path.join(root, ".casan", "version.lock"))
harness = resolve_harness(lock)
harness = resolve_harness(lock, root)
if not harness:
return emit_failure(client, event, "pinned global harness not found",
enforce)
@@ -181,11 +181,14 @@ PID=$(python3 -c 'import json;print(json.load(open("'"$PROJ2"'/.casan/config.jso
MODE=$(python3 -c 'import json;print(json.load(open("'"$PROJ2"'/.casan/config.json"))["enforcement_mode"])' 2>/dev/null)
[[ "$MODE" == "enforce" ]] && pass "production init defaults to enforce mode" || fail "default mode is not enforce ($MODE)"
DEFAULT_LEVEL=$(python3 -c 'import json;print(json.load(open("'"$PROJ2"'/.casan/config.json"))["target_level"])' 2>/dev/null)
DEFAULT_RUNTIME=$(python3 -c 'import json;print(json.load(open("'"$PROJ2"'/.casan/config.json"))["runtime_mode"])' 2>/dev/null)
[[ "$DEFAULT_LEVEL" == "1" ]] \
&& [[ "$DEFAULT_RUNTIME" == "managed" ]] \
&& [ ! -d "$PROJ2/.casan/runtime" ] \
&& [ ! -d "$PROJ2/.gitea" ] \
&& [ ! -d "$PROJ2/apps" ] \
&& pass "existing-project init defaults to core without CI/domain scaffold" \
|| fail "default init did not stay at core (level=$DEFAULT_LEVEL)"
&& pass "existing-project init defaults to managed Core without vendoring" \
|| fail "default init mode is unclear (level=$DEFAULT_LEVEL runtime=$DEFAULT_RUNTIME)"
echo "===== ⑦ init MERGES into an existing shell (agents/skills/hooks preserved) ====="
EXP="$WORK/existing"; mkdir -p "$EXP/.claude/agents" "$EXP/.claude/skills" "$EXP/.codex"
@@ -254,6 +257,53 @@ LVL_DOWN=$( ( cd "$L2" && "$DKC" level show --json ) | python3 -c 'import json,s
&& pass "default init downgrades existing DevKit adoption to clean core" \
|| fail "default init left Level 2 artifacts after core downgrade"
VENDORED="$WORK/vendored-core"; mkdir -p "$VENDORED"
VENDORED_OUT=$(cd "$VENDORED" && "$DKC" init --runtime vendored --project vendored-core --client claude --non-interactive)
VENDORED_ROOT="$VENDORED/.casan/runtime/casan-core"
echo "$VENDORED_OUT" | grep -q "Runtime.*Vendored" \
&& pass "vendored init clearly reports runtime placement" \
|| fail "vendored init output does not explain runtime mode ($VENDORED_OUT)"
[ -x "$VENDORED_ROOT/bin/casan" ] \
&& [ -f "$VENDORED_ROOT/packages/casan-harness/scripts/bash/casan-harness.sh" ] \
&& [ ! -d "$VENDORED_ROOT/packages/casan-harness/tests" ] \
&& [ ! -d "$VENDORED_ROOT/packages/casan-harness/level5" ] \
&& pass "vendored mode installs only production Core inside the project" \
|| fail "vendored Core layout is incomplete or contains source-only files"
( cd "$VENDORED" && "$VENDORED_ROOT/bin/casan" version >/dev/null ) \
&& pass "project-vendored Core includes a working local CLI" \
|| fail "project-vendored CLI cannot resolve its Core runtime"
( cd "$VENDORED" && "$DKC" verify-harness >/dev/null ) \
&& pass "global launcher resolves and verifies the project-vendored Core" \
|| fail "vendored Core is not honored by the global launcher"
( cd "$VENDORED" && "$DKC" doctor --client claude >/dev/null ) \
&& pass "project hooks execute against the verified vendored Core" \
|| fail "project hook cannot execute against vendored Core"
mv "$VENDORED_ROOT" "$VENDORED_ROOT.missing"
VENDORED_MISSING_RC=0
( cd "$VENDORED" && "$DKC" version >/dev/null 2>&1 ) || VENDORED_MISSING_RC=$?
mv "$VENDORED_ROOT.missing" "$VENDORED_ROOT"
[ "$VENDORED_MISSING_RC" -ne 0 ] \
&& pass "vendored contract fails closed instead of falling back to global Core" \
|| fail "missing vendored Core silently fell back to the global runtime"
( cd "$VENDORED" && "$DKC" init --project vendored-core --client none --non-interactive >/dev/null )
[ -d "$VENDORED_ROOT/packages/casan-harness" ] \
&& pass "re-init preserves the project's selected vendored runtime mode" \
|| fail "re-init silently changed the project's runtime mode"
( cd "$VENDORED" && "$DKC" init --runtime managed --project vendored-core --client none --non-interactive >/dev/null )
[ ! -d "$VENDORED/.casan/runtime" ] \
&& pass "switching back to managed mode removes the old vendored runtime" \
|| fail "managed re-init left a stale vendored runtime"
VENDORED_ESCAPE="$WORK/vendored-escape"; VENDORED_OUTSIDE="$WORK/vendored-outside"
mkdir -p "$VENDORED_ESCAPE/.casan" "$VENDORED_OUTSIDE"
ln -s "$VENDORED_OUTSIDE" "$VENDORED_ESCAPE/.casan/runtime"
VENDORED_ESCAPE_RC=0
( cd "$VENDORED_ESCAPE" && "$DKC" init --runtime vendored --project vendored-escape --client none --non-interactive >/dev/null 2>&1 ) || VENDORED_ESCAPE_RC=$?
[ "$VENDORED_ESCAPE_RC" -ne 0 ] \
&& [ ! -e "$VENDORED_OUTSIDE/casan-core" ] \
&& pass "vendored install rejects a runtime path escaping through symlink" \
|| fail "vendored install followed an unsafe project symlink"
echo "===== ⑨ SAFETY: init refuses to adopt a CASAN source hub into itself ====="
HUB="$WORK/fakehub"
mkdir -p "$HUB/packages/casan-harness/scripts/bash" \
@@ -370,6 +420,9 @@ INIT_OUT=$(cd "$UN" && "$DKC" init --level devkit --project uninstall-project --
echo "$INIT_OUT" | grep -q "CASAN initialized" \
&& pass "init defaults to concise human-readable output" \
|| fail "init human output missing ($INIT_OUT)"
echo "$INIT_OUT" | grep -q "Runtime.*Managed" \
&& pass "init output clearly identifies managed runtime and path" \
|| fail "init output hides runtime placement ($INIT_OUT)"
if echo "$INIT_OUT" | head -1 | grep -q '^[[:space:]]*{'; then
fail "init still defaults to raw JSON"
else
@@ -432,6 +485,14 @@ PY
&& pass "legacy uninstall preserves user Gitea workflow and removes CASAN workflow" \
|| fail "uninstall removed a user workflow or retained the CASAN workflow"
UN_VENDORED="$WORK/uninstall-vendored"; mkdir -p "$UN_VENDORED"
( cd "$UN_VENDORED" && "$DKC" init --runtime vendored --project uninstall-vendored --client none --non-interactive >/dev/null )
( cd "$UN_VENDORED" && "$DKC" uninstall >/dev/null )
[ ! -d "$UN_VENDORED/.casan/runtime" ] \
&& [ ! -f "$UN_VENDORED/.casan/config.json" ] \
&& pass "uninstall removes the complete project-vendored Core" \
|| fail "uninstall left vendored Core or active project config"
echo ""
echo "===== HYBRID INSTALL SUMMARY: PASS=$PASS FAIL=$FAIL ====="
[[ "$FAIL" -eq 0 ]] || exit 1