#!/usr/bin/env node import { spawnSync } from "node:child_process"; import { lstatSync, realpathSync } from "node:fs"; import { lstat, mkdir, readFile, realpath } 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 }; } const ANCHORED_PUBLISH_SOURCE=String.raw`import os,secrets,stat,sys parent,name,expected_dev,expected_ino=sys.argv[1:] pfd=fd=None;stage=".render-stage-"+secrets.token_hex(16);published=False def fail(): raise RuntimeError("anchored publication refused") try: pfd=os.open(parent,os.O_RDONLY|os.O_DIRECTORY|os.O_NOFOLLOW) identity=os.fstat(pfd) if (identity.st_dev,identity.st_ino)!=(int(expected_dev),int(expected_ino)): fail() try: os.stat(name,dir_fd=pfd,follow_symlinks=False); fail() except FileNotFoundError: pass fd=os.open(stage,os.O_WRONLY|os.O_CREAT|os.O_EXCL|os.O_NOFOLLOW,0o600,dir_fd=pfd) data=sys.stdin.buffer.read(33554433) if len(data)>33554432: fail() view=memoryview(data) while view: written=os.write(fd,view) if written<=0: fail() view=view[written:] os.fsync(fd);os.close(fd);fd=None;os.rename(stage,name,src_dir_fd=pfd,dst_dir_fd=pfd);published=True;os.fsync(pfd) current=os.stat(parent,follow_symlinks=False) if not stat.S_ISDIR(current.st_mode) or (current.st_dev,current.st_ino)!=(identity.st_dev,identity.st_ino): fail() except Exception: if published: try: os.unlink(name,dir_fd=pfd);os.fsync(pfd) except Exception: pass print("anchored output publication refused (details redacted)",file=sys.stderr);raise SystemExit(1) finally: if fd is not None: os.close(fd) if pfd is not None: try: os.unlink(stage,dir_fd=pfd) except FileNotFoundError: pass os.close(pfd) `; async function atomicCopy(source,output) { const parent=dirname(output),entry=await lstat(parent);if(!entry.isDirectory()||entry.isSymbolicLink())throw new Error("rendered parent identity is unsafe");const bytes=await readFile(source); const result=spawnSync("python3",["-c",ANCHORED_PUBLISH_SOURCE,parent,basename(output),String(entry.dev),String(entry.ino)],{input:bytes,encoding:"utf8",maxBuffer:1024*1024}); if(result.error||result.status!==0)throw new Error("anchored output publication refused; rendered parent identity changed or output is unsafe"); } export async function renderOwnedSnapshot({ repositoryRoot = defaultRepositoryRoot, ownershipPath, snapshotPath, outputPath, env = process.env, beforePublish }) { 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); if(beforePublish)await beforePublish({output,renderedRoot}); 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