/** * getfacl / setfacl / xattr against an in-memory vfs stub. */ import { readFile } from 'node:fs/promises' import path from 'node:path' import { fileURLToPath } from 'node:url' import test from 'brittle' import b4a from 'b4a' const __dirname = path.dirname(fileURLToPath(import.meta.url)) const AsyncFunction = Object.getPrototypeOf(async function () {}).constructor /** * @param {string} name */ async function loadBin(name) { const runtime = await readFile( path.join(__dirname, '../lib/runtime.js'), 'utf8' ) const body = await readFile( path.join(__dirname, `../src/${name}.js`), 'utf8' ) return new AsyncFunction( 'ctx', 'argv', `${runtime}\n${body}\nif (typeof run === 'function') return await run(ctx, argv)\n` ) } function createCtx(store) { const logs = [] const errs = [] return { b4a, exitCode: 0, shellStdin: '', console: { log: (m) => logs.push(String(m)), error: (m) => errs.push(String(m)) }, vfs: { async stat(p) { if (!Object.prototype.hasOwnProperty.call(store.files, p)) return null return store.files[p].stat }, async readFile(p) { const ent = store.files[p] if (!ent) return null return ent.body }, async writeFile(p, body) { store.files[p] = { stat: { mode: 0o644, type: 'file', mtimeMs: Date.now() }, body: body instanceof Uint8Array ? body : b4a.from(body) } }, async unlink(p) { delete store.files[p] } }, _logs: logs, _errs: errs } } test('getfacl synthesizes mode triples and reads sidecar', async (t) => { const store = { files: { '/a': { stat: { mode: 0o755, type: 'file', mtimeMs: 1 }, body: null }, '/b': { stat: { mode: 0o644, type: 'file', mtimeMs: 1 }, body: null }, '/b.bare_acl': { stat: { mode: 0o644, type: 'file', mtimeMs: 1 }, body: b4a.from('user::rw-\n') } } } const runA = await loadBin('getfacl') const ctxA = createCtx(store) await runA(ctxA, ['getfacl', '-c', '/a']) t.is(ctxA.exitCode, 0) t.is(ctxA._logs.join('\n'), 'user::rwx\ngroup::r-x\nother::r-x') const runB = await loadBin('getfacl') const ctxB = createCtx(store) await runB(ctxB, ['getfacl', '/b']) t.is(ctxB.exitCode, 0) t.ok(ctxB._logs.join('\n').includes('user::rw-')) }) test('getfacl documents mask-style sidecars for VFS enforcement', async (t) => { const store = { files: { '/c': { stat: { mode: 0o644, type: 'file', mtimeMs: 1 }, body: null }, '/c.bare_acl': { stat: { mode: 0o644, type: 'file', mtimeMs: 1 }, body: b4a.from('user::rw-\nother::---\n') } } } const run = await loadBin('getfacl') const ctx = createCtx(store) await run(ctx, ['getfacl', '-c', '/c']) t.is(ctx.exitCode, 0) t.ok(ctx._logs.join('\n').includes('other::---')) }) test('setfacl -b, -m and stdin write', async (t) => { const store = { files: { '/x': { stat: { mode: 0o644, type: 'file', mtimeMs: 1 }, body: null }, '/x.bare_acl': { stat: { mode: 0o644, type: 'file', mtimeMs: 1 }, body: b4a.from('old\n') } } } const runClear = await loadBin('setfacl') const ctx1 = createCtx(store) await runClear(ctx1, ['setfacl', '-b', '/x']) t.is(ctx1.exitCode, 0) t.absent(store.files['/x.bare_acl']) const runSet = await loadBin('setfacl') const ctx2 = createCtx(store) ctx2.shellStdin = 'user::r--\n' await runSet(ctx2, ['setfacl', '/x']) t.is(ctx2.exitCode, 0) t.is(b4a.toString(store.files['/x.bare_acl'].body), 'user::r--\n') const runMod = await loadBin('setfacl') const ctx3 = createCtx(store) await runMod(ctx3, ['setfacl', '-m', 'group::r-x', '/x']) t.is(ctx3.exitCode, 0) t.ok(b4a.toString(store.files['/x.bare_acl'].body).includes('group::r-x')) }) test('xattr -w -l -d round trip', async (t) => { const store = { files: { '/f': { stat: { mode: 0o644, type: 'file', mtimeMs: 1 }, body: null } } } const runW = await loadBin('xattr') const ctxW = createCtx(store) await runW(ctxW, ['xattr', '-w', 'user.t', 'hi', '/f']) t.is(ctxW.exitCode, 0) t.is(ctxW._logs.join('\n'), 'user.t') const runL = await loadBin('xattr') const ctxL = createCtx(store) await runL(ctxL, ['xattr', '-l', '/f']) t.is(ctxL.exitCode, 0) t.is(ctxL._logs.join('\n'), 'user.t: hi') const runP = await loadBin('xattr') const ctxP = createCtx(store) await runP(ctxP, ['xattr', '-p', 'user.t', '/f']) t.is(ctxP.exitCode, 0) t.is(ctxP._logs.join('\n'), 'hi') const runD = await loadBin('xattr') const ctxD = createCtx(store) await runD(ctxD, ['xattr', '-d', 'user.t', '/f']) t.is(ctxD.exitCode, 0) const runNames = await loadBin('xattr') const ctxN = createCtx(store) await runNames(ctxN, ['xattr', '/f']) t.is(ctxN.exitCode, 0) t.is(ctxN._logs.length, 0) }) test('getfacl and xattr on personal-drive-shaped metadata paths', async (t) => { const meta = '/.bare/os/registry.json' const store = { files: { [meta]: { stat: { mode: 0o600, type: 'file', mtimeMs: 1 }, body: b4a.from('{}') }, [`${meta}.bare_acl`]: { stat: { mode: 0o600, type: 'file', mtimeMs: 1 }, body: b4a.from('user::rw-\nother::---\n') } } } const runG = await loadBin('getfacl') const ctxG = createCtx(store) await runG(ctxG, ['getfacl', '-c', meta]) t.is(ctxG.exitCode, 0) t.ok(ctxG._logs.join('\n').includes('other::---')) const runX = await loadBin('xattr') const ctxX = createCtx(store) await runX(ctxX, ['xattr', '-w', 'user.meta', 'v1', meta]) t.is(ctxX.exitCode, 0) t.ok(store.files[`${meta}.bare_xattr.json`]) })