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
+14 -2
View File
@@ -1,4 +1,16 @@
import { describe, expect, it } from "vitest";
import { afterEach, describe, expect, it } from "vitest";
import { mkdtempSync, realpathSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { loadConfig } from "../src/config.js";
import { buildApp } from "../src/app.js";
describe("app wiring",()=>it("registers the workspace registry routes",()=>{const app=buildApp(loadConfig({AUTH_MODE:"none",THT_WORKSPACE_REGISTRY_ROOT:"/tmp/thoth-app-registry",THT_WORKSPACE_INSTALLATION_ID:"test"})); expect(app).toBeDefined();}));
const roots: string[] = [];
afterEach(() => { for (const root of roots.splice(0)) rmSync(root, { recursive: true, force: true }); });
describe("app wiring", () => it("registers the workspace registry routes", () => {
const root = realpathSync(mkdtempSync(join(process.platform === "darwin" ? "/private/tmp" : tmpdir(), "thoth-app-registry-")));
roots.push(root);
const app = buildApp(loadConfig({ AUTH_MODE: "none", THT_WORKSPACE_REGISTRY_ROOT: root, THT_WORKSPACE_INSTALLATION_ID: "test" }));
expect(app).toBeDefined();
}));
+1 -1
View File
@@ -8,7 +8,7 @@ let root = addon.openat({ parent: null, name: "/", kind: "directory", createMode
for (const p of (process.env.WORKSPACE_ROOT ?? "").split("/").filter(Boolean)) root = addon.openat({ parent: root, name: p, kind: "directory", createMode: 0 }).handle;
const lockName = process.env.LOCK_NAME ?? "session-readers.lock";
const lock = addon.openat({ parent: root, name: lockName, kind: "regular_lock", createMode: 0o600 }).handle;
addon.withFd(lock, fd => fsExt.flockSync(fd, process.env.LOCK_MODE ?? "exnb"));
fsExt.flockSync(addon.fdNumberForSynchronousBorrow(lock), process.env.LOCK_MODE ?? "exnb");
process.stdout.write(JSON.stringify({ ready: true }));
await sleep(Number(process.env.HOLD_MS ?? 100));
addon.close(lock); addon.close(root);
+2 -2
View File
@@ -2,7 +2,7 @@ import { execFile } from "node:child_process";
import { createHash } from "node:crypto";
import { once } from "node:events";
import { Buffer } from "node:buffer";
import { mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
import { mkdtempSync, mkdirSync, readFileSync, realpathSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { promisify } from "node:util";
@@ -486,7 +486,7 @@ async function realGit(cwd: string, args: string[]): Promise<string> {
async function createRealRouteFixture(
initialWorkspace: CanonicalWorkspace = filesystemEvidenceWorkspace,
): Promise<RealRouteFixture> {
const root = mkdtempSync(join(tmpdir(), "thoth-real-workspace-route-"));
const root = realpathSync(mkdtempSync(join(tmpdir(), "thoth-real-workspace-route-")));
realRouteRoots.push(root);
const remote = join(root, "remote.git");
const author = join(root, "author");
+1 -1
View File
@@ -13,7 +13,7 @@ describe("workspace fs-at native seam", () => {
const root = mkdtempSync(join(process.cwd(), "thoth-fsat-")); roots.push(root); mkdirSync(join(root, "private"), { mode: 0o700 });
const fs = new WorkspaceFsAtV1(); const d = openAbsolute(fs, root); const child = fs.openDirectoryAt(d, "private");
expect(child.stat().mode & 0o170000).toBe(0o040000);
expect(Object.keys(require("../native/workspace-fs-at/build/Release/workspace_fs_at.node"))).toEqual(["openat", "mkdirat", "fstatat", "fsyncDirectory", "close"]);
expect(Object.keys(require("../native/workspace-fs-at/build/Release/workspace_fs_at.node"))).toEqual(Object.freeze(["openat", "mkdirat", "fstatat", "fsyncDirectory", "close", "fdNumberForSynchronousBorrow"]));
expect((child as unknown as Record<string, unknown>)._raw).toBeUndefined();
child.close(); d.close();
});
@@ -1,5 +1,6 @@
import { describe, expect, it, afterEach } from "vitest";
import { mkdtempSync, renameSync, mkdirSync, rmSync, statSync, chmodSync, symlinkSync, writeFileSync } from "node:fs";
import { mkdtempSync, realpathSync, renameSync, mkdirSync, rmSync, statSync, chmodSync, symlinkSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { WorkspaceFsAtV1 } from "../src/workspaces/workspace-fs-at.js";
import { CanonicalWorkspaceLockRootInput, VerifiedWorkspaceLockRootLeaseFactory } from "../src/workspaces/workspace-lock-root-lease.js";
@@ -9,26 +10,26 @@ function factory(sessionsRootFromValidatedInstallationConfig: string) { return n
describe("retained canonical workspace root", () => {
it("provisions exact identity, transfers once, and rejects a second owner", async () => {
const parent = mkdtempSync(join(process.cwd(), "thoth-root-")); roots.push(parent); const f = factory(parent); const input = f.canonicalInput("abc-workspace");
const parent = realpathSync(mkdtempSync(join(process.platform === "darwin" ? "/private/tmp" : tmpdir(), "thoth-root-"))); roots.push(parent); const f = factory(parent); const input = f.canonicalInput("abc-workspace");
const lease = await f.acquireOrProvision(input); const st = statSync(join(parent, "abc-workspace")); expect(st.uid).toBe(process.getuid!()); expect(st.mode & 0o777).toBe(0o700); expect(lease.identity.inode).toBe(BigInt(st.ino));
const transferred = lease.transfer(); expect(() => lease.transfer()).toThrow(); await transferred.close();
expect(() => f.canonicalInput("../outside")).toThrow(); expect(() => f.canonicalInput("/tmp/x")).toThrow();
});
it("fails closed when the canonical pathname is replaced after retention", async () => {
const parent = mkdtempSync(join(process.cwd(), "thoth-root-")); roots.push(parent); const f = factory(parent); const lease = await f.acquireOrProvision(f.canonicalInput("abc-workspace"));
const parent = realpathSync(mkdtempSync(join(process.platform === "darwin" ? "/private/tmp" : tmpdir(), "thoth-root-"))); roots.push(parent); const f = factory(parent); const lease = await f.acquireOrProvision(f.canonicalInput("abc-workspace"));
renameSync(join(parent, "abc-workspace"), join(parent, "old")); mkdirSync(join(parent, "abc-workspace"), { mode: 0o700 });
const { runUnderWorkspaceWriterLock } = await import("../src/workspaces/preprocessing-state.js"); await expect(runUnderWorkspaceWriterLock(lease, async () => undefined)).rejects.toThrow(/preprocessing/); await lease.close();
});
it("does not accept a symlink or wrong ownership/mode root", async () => {
const parent = mkdtempSync(join(process.cwd(), "thoth-root-")); roots.push(parent); const other = mkdtempSync(join(process.cwd(), "thoth-other-")); roots.push(other); symlinkSync(other, join(parent, "abc-workspace"));
const parent = realpathSync(mkdtempSync(join(process.platform === "darwin" ? "/private/tmp" : tmpdir(), "thoth-root-"))); roots.push(parent); const other = realpathSync(mkdtempSync(join(process.platform === "darwin" ? "/private/tmp" : tmpdir(), "thoth-other-"))); roots.push(other); symlinkSync(other, join(parent, "abc-workspace"));
const f = factory(parent); await expect(f.acquireOrProvision(f.canonicalInput("abc-workspace"))).rejects.toThrow(); rmSync(join(parent, "abc-workspace")); mkdirSync(join(parent, "abc-workspace"), { mode: 0o755 }); await expect(f.acquireOrProvision(f.canonicalInput("abc-workspace"))).rejects.toThrow();
});
it("closes every transferred root on partial ordered acquisition", async () => {
const parent = mkdtempSync(join(process.cwd(), "thoth-root-")); roots.push(parent); const f = factory(parent); const a = await f.acquireOrProvision(f.canonicalInput("aaa-workspace")); const b = await f.acquireOrProvision(f.canonicalInput("bbb-workspace"));
const parent = realpathSync(mkdtempSync(join(process.platform === "darwin" ? "/private/tmp" : tmpdir(), "thoth-root-"))); roots.push(parent); const f = factory(parent); const a = await f.acquireOrProvision(f.canonicalInput("aaa-workspace")); const b = await f.acquireOrProvision(f.canonicalInput("bbb-workspace"));
const { runUnderOrderedWorkspaceWriterLocks } = await import("../src/workspaces/preprocessing-state.js"); await runUnderOrderedWorkspaceWriterLocks([a, b], async set => { expect(set.workspaceIds).toEqual(["aaa-workspace", "bbb-workspace"]); }); await expect(b.close()).resolves.toBeUndefined();
});
it("rejects writer pathname replacement without admitting a concurrent writer", async () => {
const parent = mkdtempSync(join(process.cwd(), "thoth-root-")); roots.push(parent);
const parent = realpathSync(mkdtempSync(join(process.platform === "darwin" ? "/private/tmp" : tmpdir(), "thoth-root-"))); roots.push(parent);
const f = factory(parent); const first = await f.acquireOrProvision(f.canonicalInput("abc-workspace"));
const second = await f.acquireOrProvision(f.canonicalInput("abc-workspace"));
const { runUnderWorkspaceWriterLock } = await import("../src/workspaces/preprocessing-state.js");
@@ -42,12 +43,12 @@ describe("retained canonical workspace root", () => {
});
it("rejects forged canonical inputs even when the prototype is copied", async () => {
const parent = mkdtempSync(join(process.cwd(), "thoth-root-")); roots.push(parent); const f = factory(parent);
const parent = realpathSync(mkdtempSync(join(process.platform === "darwin" ? "/private/tmp" : tmpdir(), "thoth-root-"))); roots.push(parent); const f = factory(parent);
const forged = Object.assign(Object.create(CanonicalWorkspaceLockRootInput.prototype), { workspaceId: "abc-workspace" });
await expect(f.acquireOrProvision(forged as CanonicalWorkspaceLockRootInput)).rejects.toThrow(/preprocessing/);
});
it("rejects symlink sessions roots and special permission bits", () => {
const base = mkdtempSync(join(process.cwd(), "thoth-root-")); roots.push(base); const target = mkdtempSync(join(process.cwd(), "thoth-target-")); roots.push(target);
const base = realpathSync(mkdtempSync(join(process.platform === "darwin" ? "/private/tmp" : tmpdir(), "thoth-root-"))); roots.push(base); const target = realpathSync(mkdtempSync(join(process.platform === "darwin" ? "/private/tmp" : tmpdir(), "thoth-target-"))); roots.push(target);
const link = join(base, "sessions"); symlinkSync(target, link); expect(() => factory(link)).toThrow();
chmodSync(base, 0o1700); expect(() => factory(base)).toThrow();
});
@@ -1,12 +1,13 @@
import { describe, expect, it, afterEach } from "vitest";
import { mkdtempSync, renameSync, mkdirSync, rmSync, readFileSync, chmodSync, writeFileSync } from "node:fs";
import { mkdtempSync, realpathSync, renameSync, mkdirSync, rmSync, readFileSync, chmodSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { WorkspaceFsAtV1 } from "../src/workspaces/workspace-fs-at.js";
import { PreprocessingStateStore } from "../src/workspaces/preprocessing-state.js";
import { VerifiedWorkspaceLockRootLeaseFactory } from "../src/workspaces/workspace-lock-root-lease.js";
const roots: string[] = [];
afterEach(async () => { for (const root of roots.splice(0)) rmSync(root, { recursive: true, force: true }); });
async function makeStore() { const parent = mkdtempSync(join(process.cwd(), "thoth-state-")); roots.push(parent); const factory = new VerifiedWorkspaceLockRootLeaseFactory({ workspaceFsAt: new WorkspaceFsAtV1(), installationId: "test", sessionsRootFromValidatedInstallationConfig: parent, serviceUid: process.getuid!(), provisionedWorkspaceMode: 0o700 }); const lease = await factory.acquireOrProvision(factory.canonicalInput("abc-workspace")); return { root: join(parent, "abc-workspace"), store: new PreprocessingStateStore(lease), lease }; }
async function makeStore() { const parent = realpathSync(mkdtempSync(join(process.platform === "darwin" ? "/private/tmp" : tmpdir(), "thoth-state-"))); roots.push(parent); const factory = new VerifiedWorkspaceLockRootLeaseFactory({ workspaceFsAt: new WorkspaceFsAtV1(), installationId: "test", sessionsRootFromValidatedInstallationConfig: parent, serviceUid: process.getuid!(), provisionedWorkspaceMode: 0o700 }); const lease = await factory.acquireOrProvision(factory.canonicalInput("abc-workspace")); return { root: join(parent, "abc-workspace"), store: new PreprocessingStateStore(lease), lease }; }
const input = { workspaceId: "abc-workspace" as never, revision: "a".repeat(40) as never, operation: "schema" };
describe("durable preprocessing state", () => {
it("creates and replays exact state with immutable identity", async () => { const { store, lease } = await makeStore(); const state = await store.create(input); expect(await store.create({ ...input, runId: state.runId })).toEqual(state); expect(await store.loadForResume({ ...input, runId: state.runId })).toEqual(state); await expect(store.transition(state.runId, { phase: "introspected", workspaceId: "evil" } as never)).rejects.toThrow("preprocessing_conflict"); await lease.close(); });
+4 -4
View File
@@ -1,7 +1,7 @@
import { execFile } from "node:child_process";
import { createHash } from "node:crypto";
import {
chmodSync, existsSync, mkdtempSync, mkdirSync, readdirSync, readFileSync, rmSync, symlinkSync, writeFileSync,
chmodSync, existsSync, mkdtempSync, mkdirSync, readdirSync, readFileSync, realpathSync, rmSync, symlinkSync, writeFileSync,
} from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
@@ -183,7 +183,7 @@ async function gitOutput(cwd: string, args: string[]): Promise<string> {
async function fixture(workspaceSource = validYaml): Promise<{
root: string; remote: string; source: string; initialCommit: string;
}> {
const root = mkdtempSync(join(tmpdir(), "thoth-workspace-registry-"));
const root = realpathSync(mkdtempSync(join(tmpdir(), "thoth-workspace-registry-")));
temporaryRoots.push(root);
const remote = join(root, "remote.git");
const source = join(root, "source");
@@ -213,7 +213,7 @@ async function fixture(workspaceSource = validYaml): Promise<{
async function contentOnlyFixture(): Promise<{
root: string; remote: string; source: string; initialCommit: string;
}> {
const root = mkdtempSync(join(tmpdir(), "thoth-workspace-registry-empty-"));
const root = realpathSync(mkdtempSync(join(tmpdir(), "thoth-workspace-registry-empty-")));
temporaryRoots.push(root);
const remote = join(root, "remote.git");
const source = join(root, "source");
@@ -236,7 +236,7 @@ async function contentOnlyFixture(): Promise<{
async function multiWorkspaceFixture(workspaces: Record<string, string>): Promise<{
root: string; remote: string; source: string; initialCommit: string;
}> {
const root = mkdtempSync(join(tmpdir(), "thoth-workspace-registry-"));
const root = realpathSync(mkdtempSync(join(tmpdir(), "thoth-workspace-registry-")));
temporaryRoots.push(root);
const remote = join(root, "remote.git");
const source = join(root, "source");
@@ -1,17 +1,17 @@
import { describe, expect, it, afterEach } from "vitest";
import { mkdtempSync, rmSync } from "node:fs"; import { join } from "node:path"; import { spawn } from "node:child_process"; import { once } from "node:events";
import { mkdtempSync, realpathSync, rmSync } from "node:fs"; import { join } from "node:path"; import { tmpdir } from "node:os"; import { spawn } from "node:child_process"; import { once } from "node:events";
import { WorkspaceFsAtV1 } from "../src/workspaces/workspace-fs-at.js"; import { VerifiedWorkspaceLockRootLeaseFactory } from "../src/workspaces/workspace-lock-root-lease.js";
const roots: string[] = []; afterEach(() => { for (const r of roots.splice(0)) rmSync(r, { recursive:true, force:true }); });
function factory(root:string) { return new VerifiedWorkspaceLockRootLeaseFactory({workspaceFsAt:new WorkspaceFsAtV1(),installationId:"i",sessionsRootFromValidatedInstallationConfig:root,serviceUid:process.getuid!(),provisionedWorkspaceMode:0o700}); }
describe("session reader lease", () => {
it("holds a real shared flock across child lifetime and releases exactly once", async () => {
const parent=mkdtempSync(join(process.cwd(),"thoth-readers-")); roots.push(parent); const f=factory(parent); const lease=await f.acquireOrProvision(f.canonicalInput("abc-workspace"));
const parent=realpathSync(mkdtempSync(join(process.platform === "darwin" ? "/private/tmp" : tmpdir(),"thoth-readers-"))); roots.push(parent); const f=factory(parent); const lease=await f.acquireOrProvision(f.canonicalInput("abc-workspace"));
const shared=await lease.acquireSessionReadersShared(); const child=spawn(process.execPath,[join(process.cwd(),"test/fixtures/workspace-session-readers-worker.mjs")],{cwd:process.cwd(),env:{...process.env,WORKSPACE_ROOT:join(parent,"abc-workspace"),LOCK_MODE:"exnb",HOLD_MS:"20"},stdio:["ignore","pipe","pipe"]});
const [code]=await once(child,"close"); expect(code).toBe(1); await shared.close();
const child2=spawn(process.execPath,[join(process.cwd(),"test/fixtures/workspace-session-readers-worker.mjs")],{cwd:process.cwd(),env:{...process.env,WORKSPACE_ROOT:join(parent,"abc-workspace"),LOCK_MODE:"exnb",HOLD_MS:"5"},stdio:["ignore","pipe","pipe"]}); const [code2]=await once(child2,"close"); expect(code2).toBe(0);
});
it("permits coexisting production shared acquisitions and invalidates the source after transfer", async () => {
const parent=mkdtempSync(join(process.cwd(),"thoth-readers-")); roots.push(parent); const f=factory(parent); const source=await f.acquireOrProvision(f.canonicalInput("abc-workspace")); const second=await f.acquireOrProvision(f.canonicalInput("abc-workspace")); const a=await source.acquireSessionReadersShared(); const b=await second.acquireSessionReadersShared(); expect(a.rootIdentity.inode).toBe(b.rootIdentity.inode); await expect(source.close()).resolves.toBeUndefined(); await a.close(); await b.close();
const parent=realpathSync(mkdtempSync(join(process.platform === "darwin" ? "/private/tmp" : tmpdir(),"thoth-readers-"))); roots.push(parent); const f=factory(parent); const source=await f.acquireOrProvision(f.canonicalInput("abc-workspace")); const second=await f.acquireOrProvision(f.canonicalInput("abc-workspace")); const a=await source.acquireSessionReadersShared(); const b=await second.acquireSessionReadersShared(); expect(a.rootIdentity.inode).toBe(b.rootIdentity.inode); await expect(source.close()).resolves.toBeUndefined(); await a.close(); await b.close();
});
});