fix: harden native workspace root and docker gates

This commit is contained in:
2026-08-11 14:11:42 +02:00
parent ee87a59e1f
commit a5916f6177
16 changed files with 401 additions and 96 deletions
+5 -1
View File
@@ -1 +1,5 @@
process.stdout.write(JSON.stringify({ok:true}));
import { createRequire } from "node:module"; import { resolve } from "node:path";
const require = createRequire(import.meta.url); const a = require(resolve(process.cwd(), "native/workspace-fs-at/build/Release/workspace_fs_at.node"));
let root = a.openat({parent:null,name:"/",kind:"directory",createMode:0}).handle; let successes=0, failures=0;
for (let i=0;i<Number(process.env.ITERATIONS??100);i++) { try { const r=a.openat({parent:root,name:process.env.COMPONENT??"tmp",kind:"directory",createMode:0}); successes++; a.close(r.handle); } catch { failures++; } }
a.close(root); process.stdout.write(JSON.stringify({ok:true,successes,failures}));
+14 -1
View File
@@ -1 +1,14 @@
process.stdout.write(JSON.stringify({ok:true}));
import { createRequire } from "node:module";
import { setTimeout as sleep } from "node:timers/promises";
import { resolve } from "node:path";
const require = createRequire(import.meta.url);
const addon = require(resolve(process.cwd(), "native/workspace-fs-at/build/Release/workspace_fs_at.node"));
const fsExt = require("fs-ext");
let root = addon.openat({ parent: null, name: "/", kind: "directory", createMode: 0 }).handle;
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"));
process.stdout.write(JSON.stringify({ ready: true }));
await sleep(Number(process.env.HOLD_MS ?? 100));
addon.close(lock); addon.close(root);
@@ -1 +1 @@
process.stdout.write(JSON.stringify({ok:true}));
import { mkdir, writeFile } from "node:fs/promises"; const root=process.env.JOB_ROOT; if (!root) throw new Error("JOB_ROOT required"); await mkdir(root,{recursive:true,mode:0o700}); const id=process.env.RUN_ID??"a".repeat(32); await writeFile(`${root}/${id}.json`,JSON.stringify({runId:id,phase:"request_claimed"})+"\n",{flag:"wx",mode:0o600}); process.stdout.write(JSON.stringify({ok:true,runId:id}));
+14 -1
View File
@@ -1 +1,14 @@
process.stdout.write(JSON.stringify({ok:true}));
import { createRequire } from "node:module";
import { setTimeout as sleep } from "node:timers/promises";
import { resolve } from "node:path";
const require = createRequire(import.meta.url);
const addon = require(resolve(process.cwd(), "native/workspace-fs-at/build/Release/workspace_fs_at.node"));
const fsExt = require("fs-ext");
let root = addon.openat({ parent: null, name: "/", kind: "directory", createMode: 0 }).handle;
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"));
process.stdout.write(JSON.stringify({ ready: true }));
await sleep(Number(process.env.HOLD_MS ?? 100));
addon.close(lock); addon.close(root);
+38 -3
View File
@@ -1,4 +1,39 @@
import { describe, expect, it } from "vitest";
import { describe, expect, it, afterEach } from "vitest";
import { mkdtempSync, mkdirSync, chmodSync, writeFileSync, linkSync, symlinkSync, rmSync } from "node:fs";
import { join } from "node:path";
import { createRequire } from "node:module";
const require = createRequire(import.meta.url);
import { WorkspaceFsAtV1 } from "../src/workspaces/workspace-fs-at.js";
import { mkdtempSync, mkdirSync, statSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path";
describe("workspace fs-at seam",()=>{it("opens anchored directories and literal locks",()=>{const root=mkdtempSync(join(process.cwd(),"thoth-fsat-")); mkdirSync(join(root,"sessions"),{mode:0o700}); const fs=new WorkspaceFsAtV1(); const d=fs.openRoot(); const s=fs.openDirectoryAt(d,"private"); expect(s.stat().mode).toBeTruthy(); s.close(); d.close();});});
const roots: string[] = [];
function openAbsolute(fs: WorkspaceFsAtV1, path: string) { let d = fs.openRoot(); for (const component of path.split("/").filter(Boolean)) { const next = fs.openDirectoryAt(d, component); d.close(); d = next; } return d; }
afterEach(() => { for (const root of roots.splice(0)) rmSync(root, { recursive: true, force: true }); });
describe("workspace fs-at native seam", () => {
it("exposes only opaque filesystem operations and preserves exact stat identity", () => {
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((child as unknown as Record<string, unknown>)._raw).toBeUndefined();
child.close(); d.close();
});
it("rejects invalid and overlong UTF-8 components without following links", () => {
const fs = new WorkspaceFsAtV1(); const root = fs.openRoot();
for (const name of ["", ".", "..", "a/b", "a\0b", "é".repeat(128)]) expect(() => fs.openDirectoryAt(root, name)).toThrow();
expect(() => fs.openDirectoryAt(root, "does-not-exist")).toThrow(); root.close();
});
it("creates only single-link 0600 lock files and refuses aliases", () => {
const root = mkdtempSync(join(process.cwd(), "thoth-fsat-")); roots.push(root); const fs = new WorkspaceFsAtV1(); const d = openAbsolute(fs, root); const dir = d;
const lock = fs.openOrCreateLockAt(dir, "writer.lock", 0o600); expect(lock.stat().mode & 0o777).toBe(0o600); expect(lock.stat().nlink).toBe(1n); lock.close(); dir.close(); d.close();
const bad = join(root, "bad"); writeFileSync(bad, "x", { mode: 0o600 }); rmSync(join(root, "writer.lock")); linkSync(bad, join(root, "writer.lock"));
const d2 = openAbsolute(fs, root); expect(() => fs.openOrCreateLockAt(d2, "writer.lock", 0o600)).toThrow(); d2.close();
});
it("maps real flock contention to nonblocking failure and shared compatibility", () => {
const root = mkdtempSync(join(process.cwd(), "thoth-fsat-")); roots.push(root); const fs = new WorkspaceFsAtV1(); const d = openAbsolute(fs, root); const dir = d; const a = fs.openOrCreateLockAt(dir, "writer.lock", 0o600); const b = fs.openOrCreateLockAt(dir, "writer.lock", 0o600);
fs.flockOwnedLock(a, "exclusive", "nonblocking"); expect(() => fs.flockOwnedLock(b, "shared", "nonblocking")).toThrow(); a.close(); fs.flockOwnedLock(b, "exclusive", "nonblocking"); b.close(); dir.close(); d.close();
});
it("contains close during a synchronous borrow and has a source-level no-retry close contract", async () => {
const source = await import("node:fs/promises").then(() => require("node:fs").readFileSync("native/workspace-fs-at/workspace_fs_at.cc", "utf8"));
expect(source).toContain("ERR_WORKSPACE_FS_AT_CLOSE_UNCERTAIN"); expect(source).not.toMatch(/do\s*\{[^}]*close\([^)]*\)[^}]*\}\s*while[^;]*EINTR/s);
});
});
+30 -2
View File
@@ -1,2 +1,30 @@
import { describe, expect, it } from "vitest"; import { mkdtempSync,mkdirSync } from "node:fs"; import {join} from "node:path"; import {tmpdir,getuid} from "node:os"; import {WorkspaceFsAtV1} from "../src/workspaces/workspace-fs-at.js"; import {VerifiedWorkspaceLockRootLeaseFactory} from "../src/workspaces/workspace-lock-root-lease.js";
describe("retained root lease",()=>{it("provisions a 0700 root and transfers ownership",async()=>{const p=mkdtempSync(join(process.cwd(),"thoth-root-")); const fs=new WorkspaceFsAtV1(); const f=new VerifiedWorkspaceLockRootLeaseFactory({workspaceFsAt:fs,installationId:"i",sessionsRootFromValidatedInstallationConfig:p,serviceUid:process.getuid!(),provisionedWorkspaceMode:0o700}); const l=await f.acquireOrProvision(f.canonicalInput("abc-workspace")); expect(l.identity.workspaceId).toBe("abc-workspace"); const t=l.transfer(); await expect(l.close()).resolves.toBeUndefined(); await t.close();});});
import { describe, expect, it, afterEach } from "vitest";
import { mkdtempSync, renameSync, mkdirSync, rmSync, statSync, chmodSync, symlinkSync } from "node:fs";
import { join } from "node:path";
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 root of roots.splice(0)) rmSync(root, { recursive: true, force: true }); });
function factory(sessionsRootFromValidatedInstallationConfig: string) { return new VerifiedWorkspaceLockRootLeaseFactory({ workspaceFsAt: new WorkspaceFsAtV1(), installationId: "i", sessionsRootFromValidatedInstallationConfig, serviceUid: process.getuid!(), provisionedWorkspaceMode: 0o700 }); }
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 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"));
renameSync(join(parent, "abc-workspace"), join(parent, "old")); mkdirSync(join(parent, "abc-workspace"), { mode: 0o700 });
await expect(lease.acquireWriterLock()).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 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 { 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();
});
});
@@ -1,2 +1,17 @@
import {describe,expect,it} from "vitest"; import {mkdtempSync} from "node:fs"; import {join} from "node:path"; import {tmpdir} from "node:os"; import {WorkspaceFsAtV1} from "../src/workspaces/workspace-fs-at.js"; import {VerifiedWorkspaceLockRootLeaseFactory} from "../src/workspaces/workspace-lock-root-lease.js";
describe("session reader lease",()=>{it("shares the retained root after acquisition",async()=>{const p=mkdtempSync(join(process.cwd(),"thoth-readers-")); const fs=new WorkspaceFsAtV1(); const f=new VerifiedWorkspaceLockRootLeaseFactory({workspaceFsAt:fs,installationId:"i",sessionsRootFromValidatedInstallationConfig:p,serviceUid:process.getuid!(),provisionedWorkspaceMode:0o700}); const l=await f.acquireOrProvision(f.canonicalInput("abc-workspace")); const r=await l.acquireSessionReadersShared(); expect(r.rootIdentity.workspaceId).toBe("abc-workspace"); await r.close();});});
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 { 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 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();
});
});