#!/usr/bin/env node import { randomBytes } from "node:crypto"; import { closeSync, constants, fsyncSync, lstatSync, openSync, realpathSync } from "node:fs"; import { chmod, lstat, mkdir, open, readFile, realpath, rename, rm } from "node:fs/promises"; import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path"; import { fileURLToPath } from "node:url"; // This acceptance-only adapter deliberately imports the built production runner. import { ThtRunner } from "../dist/tht/tht-runner.js"; const modulePath = fileURLToPath(import.meta.url); const defaultRepositoryRoot = realpathSync(resolve(dirname(modulePath), "../..")); const HEX40 = /^[0-9a-f]{40}$/; const HEX64 = /^[0-9a-f]{64}$/; function fixedRoot(repositoryRoot) { return join(realpathSync(repositoryRoot), ".artifacts", "manual-acceptance", "p1"); } function below(parent, child) { const rel = relative(parent, child); return rel !== "" && !rel.startsWith(`..${sep}`) && rel !== ".." && !isAbsolute(rel); } function assertNoSymlinks(root, path, allowMissingLeaf = false) { const rel = relative(root, path); if (rel.startsWith("..") || isAbsolute(rel)) throw new Error("path is outside owned root"); let cursor = root; for (const [index, part] of rel.split(sep).filter(Boolean).entries()) { cursor = join(cursor, part); try { if (lstatSync(cursor).isSymbolicLink()) throw new Error("owned path contains a symlink"); } catch (error) { if (allowMissingLeaf && error.code === "ENOENT" && index === rel.split(sep).filter(Boolean).length - 1) return; throw error; } } } async function ownership(repositoryRoot, ownershipPath) { const root = fixedRoot(repositoryRoot); const expected = join(root, "ownership.json"); if (resolve(ownershipPath) !== expected) throw new Error("ownership path is not owned"); const rootEntry = await lstat(root); const ownershipEntry = await lstat(expected); if (!rootEntry.isDirectory() || rootEntry.isSymbolicLink() || !ownershipEntry.isFile() || ownershipEntry.isSymbolicLink()) throw new Error("ownership is unsafe"); if (await realpath(root) !== root) throw new Error("ownership root is not canonical"); let value; try { value = JSON.parse(await readFile(expected, "utf8")); } catch { throw new Error("ownership is malformed"); } if (value?.schemaVersion !== 1 || value.kind !== "p1-manual-acceptance" || !HEX64.test(value.nonce ?? "") || value.repositoryRoot !== realpathSync(repositoryRoot) || value.root !== root || value.status !== "PENDING" || value.listener?.host !== "127.0.0.1" || value.listener?.port !== 8791) throw new Error("ownership identity mismatch"); return { root, value }; } async function atomicCopy(source, output) { const staging = join(dirname(output), `.${basename(output)}.${randomBytes(12).toString("hex")}.tmp`); let handle; try { const bytes = await readFile(source); handle = await open(staging, "wx", 0o600); await handle.writeFile(bytes); await handle.sync(); await handle.close(); handle = undefined; await chmod(staging, 0o600); await rename(staging, output); const directory = openSync(dirname(output), constants.O_RDONLY); try { fsyncSync(directory); } finally { closeSync(directory); } } finally { if (handle) await handle.close().catch(() => {}); await rm(staging, { force: true }).catch(() => {}); } } export async function renderOwnedSnapshot({ repositoryRoot = defaultRepositoryRoot, ownershipPath, snapshotPath, outputPath, env = process.env }) { const repo = realpathSync(repositoryRoot); const { root } = await ownership(repo, resolve(repo, ownershipPath)); const snapshot = resolve(repo, snapshotPath); const output = resolve(repo, outputPath); const snapshotsRoot = join(root, "installation", "registry", "snapshots"); const renderedRoot = join(root, "rendered"); if (!isAbsolute(snapshotPath) || !below(snapshotsRoot, snapshot)) throw new Error("snapshot is not an owned absolute path"); const match = /^([0-9a-f]{40})\/([a-z][a-z0-9-]{2,62})\.yaml$/.exec(relative(snapshotsRoot, snapshot).split(sep).join("/")); if (!match || !HEX40.test(match[1])) throw new Error("snapshot is not commit addressed"); assertNoSymlinks(root, snapshot); const snapshotEntry = await lstat(snapshot); if (!snapshotEntry.isFile() || snapshotEntry.isSymbolicLink() || await realpath(snapshot) !== snapshot) throw new Error("snapshot is unsafe"); if (!below(renderedRoot, output) || dirname(output) !== renderedRoot || !output.endsWith(".yaml")) throw new Error("output is not an owned rendered path"); assertNoSymlinks(root, dirname(output)); try { if ((await lstat(output)).isSymbolicLink()) throw new Error("output is unsafe"); } catch (error) { if (error.code !== "ENOENT") throw error; } await mkdir(join(snapshotsRoot, "runtime"), { recursive: true, mode: 0o700 }); const prior = {}; for (const [key, value] of Object.entries(env)) { prior[key] = process.env[key]; if (value === undefined) delete process.env[key]; else process.env[key] = value; } const runner = new ThtRunner({ thtBin: join(repo, "harness", ".venv", "bin", "tht"), harnessDir: join(repo, "harness"), configPath: join(root, "installation", "base.yaml"), dataRoot: join(root, "installation", "data"), runtimeSnapshotRoot: join(snapshotsRoot, "runtime"), secretRoots: [join(root, "fixture-secrets")], semanticRuntime: { internalQdrantUrl: "http://qdrant:6333", internalEmbeddingUrl: "http://embedding:11434", internalEmbeddingModel: "qwen3-embedding:0.6b", internalEmbeddingDimensions: 1024 }, }); let lease; try { lease = runner.acquireWorkspaceRuntime(snapshot); await atomicCopy(lease.path, output); } finally { if (lease) lease.release(); for (const key of Object.keys(env)) { if (prior[key] === undefined) delete process.env[key]; else process.env[key] = prior[key]; } } return output; } function parseArgs(argv) { if (argv.length !== 6) throw new Error("usage: p1-render-snapshot.mjs --ownership PATH --snapshot ABSOLUTE_PATH --output PATH"); const result = {}; for (let i=0;i