UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

206 lines (205 loc) • 8.62 kB
import { readFileSync } from "node:fs"; import { join } from "node:path"; import { atomicWriteFile, ensureDir } from "../fs-atomic.js"; export class AdoptionError extends Error { code; constructor(code, message) { super(message); this.code = code; this.name = "AdoptionError"; } } export const ROOT_ADOPTION_FILE = "adoption.json"; export const NOT_MIGRATED_BY_DESIGN = [ { asset: "usage-window", ruling: "183-D1" }, { asset: "approval-history-fields", ruling: "183-D2" }, { asset: "sessions/<pid>.json", ruling: "3356-cli-enum" }, { asset: "session-env/<sessionId>/*.sh", ruling: "3356-cli-enum" }, { asset: "sema-ca.crt", ruling: "3356-cli-enum" }, { asset: "backups/", ruling: "3356-cli-enum" }, { asset: "config-lkg-*", ruling: "3356-cli-enum" }, ]; export const BASELINE_CONFIG_IDENTITIES = [ { deployment: "web-client-bff", key: "injected-principal" }, { deployment: "cli", key: "cloud-credentials+profiles" }, { deployment: "cli", key: "SEMA_LIVE_PRINCIPAL" }, { deployment: "env", key: "REQUIRE_PRINCIPAL" }, { deployment: "core-decl", key: "localOwnerRules" }, ]; function isSource(v) { if (v === null || typeof v !== "object") return false; const s = v; if (s.kind === "local-owner") return true; return s.kind === "principal" && typeof s.principal === "string" && s.principal !== ""; } function isRootAdoptionFileShape(v) { if (v === null || typeof v !== "object") return false; const f = v; if (f.schemaVersion !== 1) return false; if ("marker" in f && !("adopted" in f)) { const m = f.marker; if (m === null || typeof m !== "object" || typeof m.adoptionId !== "string" || !isSource(m.from) || typeof m.toPrincipal !== "string" || typeof m.phase !== "number" || ![2, 3, 4, 5].includes(m.phase)) { return false; } const p = m.plan; if (p === null || p === undefined || typeof p !== "object" || (p.rulesDir !== undefined && typeof p.rulesDir !== "string") || !Array.isArray(p.carriage) || !p.carriage.every((s) => typeof s === "string") || typeof p.credentialsRef !== "string") { return false; } if (m.legs !== undefined) { if (m.legs === null || typeof m.legs !== "object" || Array.isArray(m.legs)) return false; const okCount = (n) => n === undefined || (typeof n === "number" && Number.isSafeInteger(n) && n >= 0); for (const bit of Object.values(m.legs)) { if (bit === null || typeof bit !== "object") return false; const b = bit; if (b.done !== true || !okCount(b.rows) || !okCount(b.quarantined)) return false; } } const legs = (m.legs ?? {}); if (m.phase >= 3 && legs["session-policy"]?.done !== true) return false; if (m.phase === 5) { for (const store of p.carriage) { if (legs[`carriage:${store}`]?.done !== true) return false; } } const planned = new Set(p.carriage); for (const key of Object.keys(legs)) { if (key.startsWith("carriage:") && !planned.has(key.slice("carriage:".length))) return false; } return true; } if ("adopted" in f && !("marker" in f)) { const a = f.adopted; if (a === null || typeof a !== "object" || !isSource(a.from) || typeof a.toPrincipal !== "string" || typeof a.atMs !== "number" || a.immutableReport === null || typeof a.immutableReport !== "object") { return false; } const r = a.immutableReport; const sameFrom = isSource(r.from) && (r.from.kind === "local-owner" ? a.from.kind === "local-owner" : a.from.kind === "principal" && r.from.principal === a.from.principal); const okCount = (n) => n === undefined || (typeof n === "number" && Number.isSafeInteger(n) && n >= 0); const configIds = new Set(); const configsOk = Array.isArray(r.affectedDeploymentConfigs) && r.affectedDeploymentConfigs.length > 0 && r.affectedDeploymentConfigs.every((c) => { if (c === null || typeof c !== "object") return false; const e = c; if (typeof e.deployment !== "string" || e.deployment === "" || typeof e.key !== "string" || e.key === "") return false; if (typeof e.requiredValue !== "string" || typeof e.migrated !== "boolean") return false; const id = JSON.stringify([e.deployment, e.key]); if (configIds.has(id)) return false; configIds.add(id); return true; }); const nmd = r.notMigratedByDesign; const nmdAssets = new Set(); const closedSetOk = Array.isArray(nmd) && nmd.length > 0 && nmd.every((e) => { if (e === null || typeof e !== "object") return false; const m = e; if (typeof m.asset !== "string" || m.asset === "" || typeof m.ruling !== "string" || m.ruling === "") return false; if (nmdAssets.has(m.asset)) return false; nmdAssets.add(m.asset); return true; }); const legsOk = Array.isArray(r.legs) && r.legs.every((l) => { if (l === null || typeof l !== "object") return false; const e = l; return (typeof e.store === "string" && typeof e.action === "string" && ["bucket-rebind", "row-rewrite", "carried", "none", "reset"].includes(e.action) && okCount(e.rows) && okCount(e.quarantined)); }); const credsOk = r.credentials !== null && typeof r.credentials === "object" && r.credentials.issuedBy === "server" && typeof r.credentials.ref === "string" && r.credentials.ref !== ""; return (typeof r.adoptionId === "string" && r.toPrincipal === a.toPrincipal && r.atMs === a.atMs && Number.isSafeInteger(a.atMs) && a.atMs >= 0 && sameFrom && closedSetOk && configsOk && legsOk && credsOk); } return false; } export function readRootAdoptionFile(root) { let raw; try { raw = readFileSync(join(root, ROOT_ADOPTION_FILE), "utf8"); } catch (err) { if (err.code === "ENOENT") return undefined; throw new AdoptionError("adoption_marker_corrupt", `could not read the adoption marker in ${root}: ${err.message}`); } let parsed; try { parsed = JSON.parse(raw); } catch (err) { throw new AdoptionError("adoption_marker_corrupt", `the adoption marker in ${root} is not valid JSON (${err.message}) — refusing to serve this data root until it is repaired`); } if (!isRootAdoptionFileShape(parsed)) { throw new AdoptionError("adoption_marker_corrupt", `the adoption marker in ${root} does not carry a readable shape — refusing to serve this data root until it is repaired`); } return parsed; } export function writeRootAdoptionFile(root, content) { ensureDir(root); atomicWriteFile(join(root, "tmp"), join(root, ROOT_ADOPTION_FILE), JSON.stringify(content, null, 2)); } export function assertAdoptionBootGate(root, storeName) { const f = readRootAdoptionFile(root); if (f !== undefined && "marker" in f) { const from = f.marker.from.kind === "principal" ? `principal "${f.marker.from.principal}"` : "the local owner"; throw new AdoptionError("adoption_in_flight", `${storeName}: an adoption of this data root (${from} → "${f.marker.toPrincipal}", phase ${f.marker.phase}) is in flight — ` + `resume adoptLocalDataRoot to completion (or repair ${join(root, ROOT_ADOPTION_FILE)}) before constructing stores over it; ` + `serving a half-migrated root is refused`); } }