From 6804fd14f408995ae597b4dcaea6e12f253a8ef8 Mon Sep 17 00:00:00 2001 From: thanhnv Date: Fri, 24 Jul 2026 16:39:17 +0700 Subject: [PATCH] fix: distinguish configuration from hook trust --- VERSION | 2 +- packages/casan-devkit/casan-init.py | 31 ++++++++++++++++++- .../tests/hybrid-install-tests.sh | 2 +- .../phase-upgrade-compatibility-tests.sh | 6 ++-- 4 files changed, 35 insertions(+), 6 deletions(-) diff --git a/VERSION b/VERSION index 21e8796..ee90284 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.3 +1.0.4 diff --git a/packages/casan-devkit/casan-init.py b/packages/casan-devkit/casan-init.py index 0f25fb3..9f584c6 100755 --- a/packages/casan-devkit/casan-init.py +++ b/packages/casan-devkit/casan-init.py @@ -201,6 +201,7 @@ def _render_level(result): def _render_doctor(result): ready = result["status"] == "ready" + operational = result.get("operational_status") _heading("CASAN Doctor") print(" %s Harness integrity" % _mark(result["integrity"]["ok"])) print(" %s Project bootstrap" % _mark(result["bootstrap"]["ok"])) @@ -218,8 +219,18 @@ def _render_doctor(result): print(_color("1;33", "Warnings")) for warning in result["warnings"]: print(" %s %s" % (_warn_mark(), warning)) + if result.get("required_actions"): + print() + print(_color("1;33", "Required actions")) + for action in result["required_actions"]: + print(" %s %s" % (_warn_mark(), action["message"])) print() - status = _color("1;32", "READY") if ready else _color("1;31", "NOT READY") + if ready and operational == "user_action_required": + status = _color("1;33", "CONFIGURED — USER ACTION REQUIRED") + elif ready: + status = _color("1;32", "READY") + else: + status = _color("1;31", "NOT READY") print("Status: %s" % status) @@ -1531,6 +1542,7 @@ def cmd_doctor(args): "bootstrap": {"ok": bootstrap_ok}, "client_checks": {}, "warnings": [], + "required_actions": [], } ready = integrity_ok and bootstrap_ok vendored_harness = os.path.isfile(os.path.join( @@ -1608,6 +1620,12 @@ def cmd_doctor(args): if "codex" in clients: checks["warnings"].append( "Codex project hooks do not run until their exact hash is reviewed and trusted via /hooks.") + checks["required_actions"].append({ + "code": "codex_hook_trust", + "message": ( + "Open /hooks in a local Codex client, review the exact hook hash, " + "and trust it before treating Codex as operational."), + }) if "vscode-copilot" in clients: checks["warnings"].append( "Only prompts explicitly sent to @casan use the CASAN-owned Copilot route; " @@ -1621,7 +1639,18 @@ def cmd_doctor(args): "Legacy prompt-boundary prose outside CASAN-managed markers conflicts " "with Plan-20 hooks and needs manual review: %s." % ", ".join(legacy_conflicts)) + checks["required_actions"].append({ + "code": "legacy_prompt_policy_review", + "message": ( + "Review and migrate conflicting legacy prompt policy: %s." % + ", ".join(legacy_conflicts)), + }) checks["status"] = "ready" if ready else "not_ready" + checks["operational_status"] = ( + "not_ready" if not ready + else "user_action_required" if checks["required_actions"] + else "ready" + ) _emit_json_or_human(args, checks, _render_doctor) return 0 if ready else 2 diff --git a/packages/casan-devkit/tests/hybrid-install-tests.sh b/packages/casan-devkit/tests/hybrid-install-tests.sh index 0177446..c47d29f 100755 --- a/packages/casan-devkit/tests/hybrid-install-tests.sh +++ b/packages/casan-devkit/tests/hybrid-install-tests.sh @@ -480,7 +480,7 @@ else pass "init no longer dumps raw JSON by default" fi ( cd "$UN" && "$DKC" doctor --json ) | python3 -c \ - 'import json,sys; d=json.load(sys.stdin); assert d["status"] == "ready"' \ + 'import json,sys; d=json.load(sys.stdin); assert d["status"] == "ready"; assert d["operational_status"] == "ready"' \ && pass "doctor --json preserves the machine-readable contract" \ || fail "doctor --json is not valid/ready" echo "project-owned requirement" > "$UN/apps/uninstall-project/domain/input/requirement.md" diff --git a/packages/casan-harness/tests/phase-upgrade-compatibility-tests.sh b/packages/casan-harness/tests/phase-upgrade-compatibility-tests.sh index 89159ff..2a08278 100755 --- a/packages/casan-harness/tests/phase-upgrade-compatibility-tests.sh +++ b/packages/casan-harness/tests/phase-upgrade-compatibility-tests.sh @@ -6,8 +6,8 @@ S="$CASAN_HARNESS_ROOT/scripts/bash/upgrade-compatibility.sh" M="$CASAN_APP_ROOT/infra/production/compatibility-matrix.json" PASS=0; FAIL=0 pass(){ echo "PASS: $1"; PASS=$((PASS+1)); }; fail(){ echo "FAIL: $1"; FAIL=$((FAIL+1)); } -if bash "$S" check --from 1.0.2 --to 1.0.3 --matrix "$M" | grep -q '"decision": "allow"'; then pass "patch upgrade is explicitly allowed"; else fail "patch upgrade denied"; fi -if bash "$S" check --from 1.0.3 --to 1.0.2 --rollback --matrix "$M" | grep -q '"rollback": true'; then pass "approved rollback is explicitly allowed"; else fail "approved rollback denied"; fi -if bash "$S" check --from 1.0.3 --to 2.0.0 --matrix "$M" >/dev/null 2>&1; then fail "unreviewed major upgrade accepted"; else pass "unreviewed major upgrade denied"; fi +if bash "$S" check --from 1.0.3 --to 1.0.4 --matrix "$M" | grep -q '"decision": "allow"'; then pass "patch upgrade is explicitly allowed"; else fail "patch upgrade denied"; fi +if bash "$S" check --from 1.0.4 --to 1.0.3 --rollback --matrix "$M" | grep -q '"rollback": true'; then pass "approved rollback is explicitly allowed"; else fail "approved rollback denied"; fi +if bash "$S" check --from 1.0.4 --to 2.0.0 --matrix "$M" >/dev/null 2>&1; then fail "unreviewed major upgrade accepted"; else pass "unreviewed major upgrade denied"; fi if bash "$S" check --from invalid --to 1.0.0 --matrix "$M" >/dev/null 2>&1; then fail "invalid version accepted"; else pass "invalid version denied"; fi echo "===== UPGRADE COMPATIBILITY SUMMARY: PASS=$PASS FAIL=$FAIL ====="; [[ "$FAIL" -eq 0 ]]