fix: harden P1 manual acceptance audit gates
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
#!/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 { 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";
|
||||
|
||||
@@ -41,18 +41,46 @@ async function ownership(repositoryRoot, ownershipPath) {
|
||||
|| 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(() => {}); }
|
||||
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 }) {
|
||||
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");
|
||||
@@ -75,7 +103,7 @@ export async function renderOwnedSnapshot({ repositoryRoot = defaultRepositoryRo
|
||||
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); }
|
||||
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]; }
|
||||
|
||||
Reference in New Issue
Block a user