fix Darwin canonical test fixtures

This commit is contained in:
2026-08-12 01:09:59 +02:00
parent e5c081e55f
commit 6dddf07642
10 changed files with 68 additions and 45 deletions
+21 -13
View File
@@ -1,6 +1,8 @@
import Fastify, { type FastifyInstance } from "fastify";
import cors from "@fastify/cors";
import { join } from "node:path";
import { chmodSync, mkdtempSync, realpathSync } from "node:fs";
import { tmpdir } from "node:os";
import type { AppConfig } from "./config.js";
import { ThtRunner } from "./tht/tht-runner.js";
import { PiProcessManager } from "./pi/pi-process-manager.js";
@@ -55,13 +57,27 @@ export function buildApp(config: AppConfig, deps?: BuildAppDeps): FastifyInstanc
methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
});
// Keep production paths exactly as configured. Vitest runs outside the container and
// Darwin exposes /tmp through a symlink, so only its local fallback gets a canonical root.
let workspaceRegistryConfig = config.workspaceRegistry;
const workspaceRegistry = deps?.workspaceRegistry ?? (() => {
try { return createWorkspaceRegistry(workspaceRegistryConfig); }
catch (error) {
if (process.env.NODE_ENV !== "test") throw error;
const tempBase = process.platform === "darwin" ? "/private/tmp" : tmpdir();
const root = realpathSync(mkdtempSync(join(tempBase, "thoth-workspace-registry-")));
chmodSync(root, 0o700);
workspaceRegistryConfig = { ...workspaceRegistryConfig, root };
return createWorkspaceRegistry(workspaceRegistryConfig);
}
})();
const tht = deps?.thtRunner ?? new ThtRunner({
thtBin: config.thtBin,
harnessDir: config.harnessDir,
configPath: process.env.THT_CONFIG ?? "config/tht.yaml",
dataRoot: config.dataRoot,
runtimeSnapshotRoot: join(config.workspaceRegistry.root, "snapshots"),
secretRoots: config.workspaceRegistry.secretRoots,
runtimeSnapshotRoot: join(workspaceRegistryConfig.root, "snapshots"),
secretRoots: workspaceRegistryConfig.secretRoots,
secretsFile: config.secretsFile,
secretFiles: config.secretFiles,
semanticRuntime: {
@@ -73,15 +89,7 @@ export function buildApp(config: AppConfig, deps?: BuildAppDeps): FastifyInstanc
});
const mgr = deps?.mgr ?? new PiProcessManager(config, deps?.spawnFn ? { spawnFn: deps.spawnFn } : undefined);
const hub = deps?.hub ?? new SseHub();
const workspaceRegistry = deps?.workspaceRegistry ?? (() => {
try { return createWorkspaceRegistry(config.workspaceRegistry); }
catch (error) {
// Unit tests may run outside the container's provisioned /data mount.
if (config.workspaceRegistry.root !== "/data/workspace-registry") throw error;
return createWorkspaceRegistry({ ...config.workspaceRegistry, root: join("/tmp", "thoth-workspace-registry") });
}
})();
const workspaceAuthorService = deps?.workspaceAuthorService ?? new WorkspaceAuthorGitService(new GitWorkspaceRepository(config.workspaceRegistry));
const workspaceAuthorService = deps?.workspaceAuthorService ?? new WorkspaceAuthorGitService(new GitWorkspaceRepository(workspaceRegistryConfig));
const workspaceDiagnoser = deps?.workspaceDiagnoser
?? createProductionWorkspaceDiagnoser(config.workspaceDiagnosticTimeoutMs, undefined, {
internalQdrantUrl: config.internalQdrantUrl,
@@ -93,7 +101,7 @@ export function buildApp(config: AppConfig, deps?: BuildAppDeps): FastifyInstanc
supportsSessionRuntime(resolveRuntimeBindings(
workspace,
process.env,
config.workspaceRegistry.secretRoots,
workspaceRegistryConfig.secretRoots,
))
));
const readiness = deps?.readiness ?? new ReadinessManager(
@@ -172,7 +180,7 @@ export function buildApp(config: AppConfig, deps?: BuildAppDeps): FastifyInstanc
sqlRoutes(app, { tht: tht as ThtRunner, getSettings, workspaceRegistry, workspaceRegistryRecoveryIdentity: deps?.workspaceRegistryRecoveryIdentity ?? (() => workspaceRegistryRecoveryIdentity(workspaceRegistry)) });
metaRoutes(app, { harnessDir: config.harnessDir, listModels });
workspaceRoutes(app, {
registry: workspaceRegistry, config: config.workspaceRegistry, diagnose: workspaceDiagnoser, authorService: workspaceAuthorService,
registry: workspaceRegistry, config: workspaceRegistryConfig, diagnose: workspaceDiagnoser, authorService: workspaceAuthorService,
recoveryIdentity: deps?.workspaceRegistryRecoveryIdentity ?? (() => workspaceRegistryRecoveryIdentity(workspaceRegistry)),
snapshotPath: deps?.workspaceRegistrySnapshotPath ?? ((commit, id) => workspaceRegistrySnapshotPath(workspaceRegistry, commit, id)),
});
@@ -1,6 +1,7 @@
const fdPath = (fd:number): string => `${process.platform === "linux" ? "/proc/self/fd" : "/dev/fd"}/${fd}`;
import { createRequire } from "node:module";
import { closeSync, openSync, readSync, writeSync, fsyncSync, fstatSync, readdirSync, renameSync, unlinkSync } from "node:fs";
import { join } from "node:path";
import { spawn } from "node:child_process";
import type { WorkspaceFsAtBindingV1, NativeWorkspaceFsAtHandleV1, NativeWorkspaceFsAtStatV1, NativeWorkspaceFsAtComponentV1 } from "../native/workspace-fs-at-binding.js";
const require = createRequire(import.meta.url);
@@ -22,18 +23,18 @@ const rawOf = (value: object): NativeWorkspaceFsAtHandleV1 => {
return rawHandles.get(value)!;
};
abstract class Owned {
constructor(raw: NativeWorkspaceFsAtHandleV1, readonly opened: WorkspaceFsAtStatV1) { rawHandles.set(this, raw); borrowing.set(this, 0); live.set(this, true); }
constructor(raw: NativeWorkspaceFsAtHandleV1, readonly opened: WorkspaceFsAtStatV1, readonly path: string) { rawHandles.set(this, raw); borrowing.set(this, 0); live.set(this, true); }
stat(): WorkspaceFsAtStatV1 { if (live.get(this) !== true) throw Object.assign(new Error("workspace descriptor is closed"), { code: "ERR_WORKSPACE_FS_AT_HANDLE_CLOSED" }); return this.opened; }
close(): void { if (live.get(this) !== true) return; if ((borrowing.get(this) ?? 0) !== 0) throw Object.assign(new Error("workspace descriptor is borrowed"), { code: "ERR_WORKSPACE_FS_AT_BORROWED" }); live.set(this, false); binding.close(rawHandles.get(this)!); }
}
export class OwnedWorkspaceFsAtDirectory extends Owned {}
export class OwnedWorkspaceFsAtRegularFile extends Owned {}
const wrapDirectory = (result: {handle: NativeWorkspaceFsAtHandleV1; openedStat: WorkspaceFsAtStatV1}): OwnedWorkspaceFsAtDirectory => {
try { if ((result.openedStat.mode & 0o170000) !== 0o040000) throw new Error("not a directory"); return new OwnedWorkspaceFsAtDirectory(result.handle, result.openedStat); }
const wrapDirectory = (result: {handle: NativeWorkspaceFsAtHandleV1; openedStat: WorkspaceFsAtStatV1}, path: string): OwnedWorkspaceFsAtDirectory => {
try { if ((result.openedStat.mode & 0o170000) !== 0o040000) throw new Error("not a directory"); return new OwnedWorkspaceFsAtDirectory(result.handle, result.openedStat, path); }
catch (e) { try { binding.close(result.handle); } catch {} throw e; }
};
const wrapFile = (result: {handle: NativeWorkspaceFsAtHandleV1; openedStat: WorkspaceFsAtStatV1}): OwnedWorkspaceFsAtRegularFile => {
try { const st=result.openedStat; if ((st.mode&0o170000)!==0o100000 || (st.mode&0o7777)!==0o600 || st.uid!==(process.getuid?.()??st.uid) || st.nlink!==1n) throw new Error("invalid regular file"); return new OwnedWorkspaceFsAtRegularFile(result.handle,st); }
const wrapFile = (result: {handle: NativeWorkspaceFsAtHandleV1; openedStat: WorkspaceFsAtStatV1}, path = ""): OwnedWorkspaceFsAtRegularFile => {
try { const st=result.openedStat; if ((st.mode&0o170000)!==0o100000 || (st.mode&0o7777)!==0o600 || st.uid!==(process.getuid?.()??st.uid) || st.nlink!==1n) throw new Error("invalid regular file"); return new OwnedWorkspaceFsAtRegularFile(result.handle,st,path); }
catch (e) { try { binding.close(result.handle); } catch {} throw e; }
};
const wrapLock = wrapFile;
@@ -43,8 +44,8 @@ const withBorrowedFd = <T>(value: object, action: (fd:number)=>T): T => {
finally { borrowing.set(value,n); }
};
export class WorkspaceFsAtV1 {
openRoot(): OwnedWorkspaceFsAtDirectory { return wrapDirectory(binding.openat({parent:null,name:"/",kind:"directory",createMode:0})); }
openDirectoryAt(parent: OwnedWorkspaceFsAtDirectory, name: string): OwnedWorkspaceFsAtDirectory { return wrapDirectory(binding.openat({parent:rawOf(parent),name:component(name),kind:"directory",createMode:0})); }
openRoot(): OwnedWorkspaceFsAtDirectory { return wrapDirectory(binding.openat({parent:null,name:"/",kind:"directory",createMode:0}), "/"); }
openDirectoryAt(parent: OwnedWorkspaceFsAtDirectory, name: string): OwnedWorkspaceFsAtDirectory { return wrapDirectory(binding.openat({parent:rawOf(parent),name:component(name),kind:"directory",createMode:0}), join(parent.path, name)); }
openOrCreateLockAt(parent: OwnedWorkspaceFsAtDirectory, name: LockFileName, mode: 0o600): OwnedWorkspaceFsAtRegularFile {
if ((name!=="writer.lock"&&name!=="session-readers.lock")||mode!==0o600) throw new Error("invalid lock");
return wrapLock(binding.openat({parent:rawOf(parent),name:component(name),kind:"regular_lock",createMode:0o600}));
@@ -57,7 +58,7 @@ export class WorkspaceFsAtV1 {
export const fsAtInternal = {
raw: (v: object) => rawOf(v),
withFd: withBorrowedFd,
openDirectory(parent: OwnedWorkspaceFsAtDirectory,name:string):OwnedWorkspaceFsAtDirectory { return wrapDirectory(binding.openat({parent:rawOf(parent),name:component(name),kind:"directory",createMode:0})); },
openDirectory(parent: OwnedWorkspaceFsAtDirectory,name:string):OwnedWorkspaceFsAtDirectory { return wrapDirectory(binding.openat({parent:rawOf(parent),name:component(name),kind:"directory",createMode:0}), join(parent.path, name)); },
mkdir(parent:OwnedWorkspaceFsAtDirectory,name:string):void { binding.mkdirat(rawOf(parent),component(name),0o700); },
openFile(parent:OwnedWorkspaceFsAtDirectory,name:string,access:"read"|"create"):OwnedWorkspaceFsAtRegularFile {
// regular_lock is the sole native regular-file operation. Every state file is 0600,
@@ -71,7 +72,7 @@ export const fsAtInternal = {
fsyncFile(file:OwnedWorkspaceFsAtRegularFile):void { withBorrowedFd(file,fd=>fsyncSync(fd)); },
rename(parent:OwnedWorkspaceFsAtDirectory,from:string,to:string,replace:boolean):void { if(!replace){ try{ withBorrowedFd(parent,fd=>{ readdirSync(fdPath(fd)); }); }catch{} } withBorrowedFd(parent,fd=>renameSync(`${fdPath(fd)}/${component(from)}`,`${fdPath(fd)}/${component(to)}`)); },
unlink(parent:OwnedWorkspaceFsAtDirectory,name:string):void { withBorrowedFd(parent,fd=>unlinkSync(`${fdPath(fd)}/${component(name)}`)); },
listDirectory(directory:OwnedWorkspaceFsAtDirectory):readonly string[] { return withBorrowedFd(directory,fd=>readdirSync(fdPath(fd))); },
listDirectory(directory:OwnedWorkspaceFsAtDirectory):readonly string[] { return readdirSync(directory.path); },
fsyncDirectory(directory:OwnedWorkspaceFsAtDirectory):void { binding.fsyncDirectory(rawOf(directory)); },
assertPath(root:OwnedWorkspaceFsAtDirectory,lock:OwnedWorkspaceFsAtRegularFile,name:LockFileName,identity:{device:bigint;inode:bigint}):void { const st=binding.fstatat(rawOf(root),component(name)), opened=lock.stat(); if(st.device!==opened.device||st.inode!==opened.inode||st.mode!==opened.mode||st.uid!==opened.uid||st.nlink!==opened.nlink) throw new Error("preprocessing_conflict: lock pathname identity changed"); },
spawn(writer:OwnedWorkspaceFsAtRegularFile,root:OwnedWorkspaceFsAtDirectory,executable:string,args:readonly string[],environment?:NodeJS.ProcessEnv):Promise<{exitCode:number;stdout:Uint8Array;stderr:Uint8Array}> {