feat: harden chat state by tenant

This commit is contained in:
thanhnv
2026-07-08 23:38:22 +09:00
parent b3b0544ba8
commit c800f7edf7
20 changed files with 380 additions and 54 deletions
@@ -33,14 +33,32 @@ def project_root() -> str:
ROOT = project_root()
BIN = os.path.join(ROOT, "packages", "casan-harness", "scripts", "bash")
LOOP_TRACE = os.path.join(BIN, "loop-trace.py")
TENANT_STORE = os.path.join(BIN, "tenant-store.sh")
def state_root() -> str:
return os.environ.get("CASAN_STATE_ROOT") or os.path.join(ROOT, ".specify")
def tenant_path(logical: str, fallback: str) -> str:
if os.environ.get("CASAN_TENANT_ID"):
r = subprocess.run(["bash", TENANT_STORE, "resolve", logical], cwd=ROOT, capture_output=True, text=True)
if r.returncode != 0:
raise SystemExit((r.stderr or r.stdout or "TENANT_DENIED").strip())
return r.stdout.strip()
return os.path.join(state_root(), fallback)
def guarded_override(path: str) -> str:
if path and os.environ.get("CASAN_TENANT_ID"):
r = subprocess.run(["bash", TENANT_STORE, "guard", path], cwd=ROOT, capture_output=True, text=True)
if r.returncode != 0:
raise SystemExit((r.stderr or r.stdout or "TENANT_DENIED").strip())
return path
def audit_path() -> str:
return os.environ.get("CASAN_CHAT_AUDIT_LOG") or os.path.join(state_root(), "logs", "chat", "chat-turns.jsonl")
return guarded_override(os.environ["CASAN_CHAT_AUDIT_LOG"]) if os.environ.get("CASAN_CHAT_AUDIT_LOG") else tenant_path("chat/chat-turns.jsonl", "logs/chat/chat-turns.jsonl")
def sha_text(text: str) -> str:
@@ -87,12 +105,12 @@ def resolve_path(path: str) -> str:
def loop_state_root(loop_run):
explicit = os.environ.get("CASAN_LOOP_STATE_ROOT")
if explicit:
return explicit
return guarded_override(explicit)
artifact = loop_run.get("artifact") or ""
marker = os.sep + "logs" + os.sep + "chat" + os.sep + "loop-runs" + os.sep
if marker in artifact:
return artifact.split(marker, 1)[0] + os.sep + "logs" + os.sep + "chat" + os.sep + "loop-state"
return os.path.join(state_root(), "logs", "chat", "loop-state")
return tenant_path("chat/loop-state", "logs/chat/loop-state")
def run_loop_trace(loop_run, cmd: str):