Files
jason.woltje e54e054632 row 215: C2-04 the library entry in the business file, consumer skips, M9 organization-projects-protected, the bare mirror, library.file and library.status (#1716)
The business file accepts a kind "library" project entry, and each consumer
that assumed a project root skips it. An organization write whose projects
differ from the file's is refused (M9). The bare mirror is created at the
projectRepo path with no remote. library.file and library.status are human
only and refuse an agent session with human-required.
Candidate herb/row215-on197 dde3445ab on a36523713, Filbert APPROVE rev 2924.
2026-10-21 14:24:37 -05:00

248 lines
17 KiB
JavaScript

// C2-04: local made-up repositories only. No remote credential or live config.
import test from 'node:test';
import assert from 'node:assert/strict';
import { chmodSync, existsSync, linkSync, lstatSync, mkdirSync, readFileSync, readdirSync, rmSync, symlinkSync, unlinkSync, writeFileSync } from 'node:fs';
import { join } from 'node:path';
import { spawn } from 'node:child_process';
import { once } from 'node:events';
import { mappingEntry, repo, git, BASE, MARKER } from './helpers.mjs';
import * as api from '../src/mirror.mjs';
const NOW = '2026-10-21T00:00:00.000Z';
const MOD = new URL('../src/mirror.mjs', import.meta.url).href;
const state = (served = null) => ({ version: 1, branch: 'main', served, lastFetch: null, lastError: null, diverged: null, problems: [] });
const stateFile = mirror => join(mirror, api.SYNC_STATE_FILE);
async function fixture(t, files = BASE) {
const f = repo(t, files), dataRoot = join(f.root, 'data');
const context = { business: { id: 'acme', projects: { books: mappingEntry(), code: { root: f.repo } } }, project: 'books', dataRoot };
const mirror = await api.ensureMirror(context);
const writeState = value => writeFileSync(stateFile(mirror), JSON.stringify(value), { mode: 0o600 });
const seed = (commit = f.commit) => {
git(f.repo, '-c', 'protocol.file.allow=always', 'push', '-q', mirror, `${commit}:refs/heads/served`);
writeState(state(commit));
};
return { ...f, dataRoot, context, mirror, writeState, seed };
}
test('C2-04 mirror: exact default path, bare without checkout or remote, and idempotent initialization', async t => {
const f = await fixture(t);
assert.equal(api.SYNC_STATE_FILE, 'mosaic-library-sync.json');
assert.equal(api.mirrorPath(f.context), join(f.dataRoot, 'projects/acme/books'));
assert.equal(f.mirror, api.mirrorPath(f.context));
assert.equal(git(f.mirror, 'rev-parse', '--is-bare-repository'), 'true');
assert.equal(git(f.mirror, 'remote'), '');
assert.equal(existsSync(join(f.mirror, '.git')), false);
const lock = join(f.mirror, 'mosaic-library-sync.lock'), st = lstatSync(lock);
assert.equal(st.mode & 0o777, 0o600);
assert.equal(st.nlink, 1);
assert.equal(await api.ensureMirror(f.context), f.mirror);
assert.equal(lstatSync(lock).ino, st.ino, 'the lock inode is stable');
assert.equal(await api.servedCommit(f.mirror), null);
assert.deepEqual(await api.libraryStatus(f.context), { project: 'books', ...state() });
});
test('C2-04 mirror: simultaneous creators publish one intact mirror and leave no staging paths', async t => {
const f = repo(t), dataRoot = join(f.root, 'data');
const c = { business: { id: 'acme', projects: { books: mappingEntry() } }, project: 'books', dataRoot };
const results = await Promise.all(Array.from({ length: 4 }, () => api.ensureMirror(c)));
assert.deepEqual([...new Set(results)], [join(dataRoot, 'projects/acme/books')]);
assert.deepEqual(readdirSync(join(dataRoot, 'projects/acme')), ['books']);
assert.equal(git(results[0], 'rev-parse', '--is-bare-repository'), 'true');
});
test('C2-04 mirror: skipped publication accepts both coreutils statuses without removing the winner', { timeout: 15000 }, async t => {
for (const status of [0, 1]) {
const f = repo(t), dataRoot = join(f.root, 'data');
const context = { business: { id: 'acme', projects: { books: mappingEntry() } }, project: 'books', dataRoot };
const creator = child(t, `import cp from 'node:child_process';import {cpSync,chmodSync,lstatSync,readdirSync} from 'node:fs';import {dirname} from 'node:path';import {syncBuiltinESMExports} from 'node:module';
const original=cp.execFile;let winner;
cp.execFile=(command,args,options,callback)=>{if(command!=='/usr/bin/mv')return original(command,args,options,callback);
cpSync(args[2],args[3],{recursive:true});chmodSync(args[3],0o700);winner=lstatSync(args[3]).ino;
const error=${status} ? Object.assign(Error('fixture no-clobber diagnostic'),{code:${status}}) : null;
queueMicrotask(()=>callback(error));};syncBuiltinESMExports();
const {ensureMirror}=await import(${JSON.stringify(MOD)});const mirror=await ensureMirror(${JSON.stringify(context)});
process.send({same:lstatSync(mirror).ino===winner,entries:readdirSync(dirname(mirror))});process.disconnect();`);
const [result] = await Promise.race([once(creator, 'message'), creator.finished.then(result => { throw Error(JSON.stringify(result)); })]);
assert.deepEqual(result, { same: true, entries: ['books'] });
assert.deepEqual(await creator.finished, { code: 0, stderr: '' });
}
});
test('C2-04 mirror: preserve occupied directories and reject symlink ancestors and code overlaps', async t => {
const f = repo(t), dataRoot = join(f.root, 'data');
const c = { business: { id: 'acme', projects: { books: mappingEntry() } }, project: 'books', dataRoot };
const path = join(dataRoot, 'projects/acme/books'); mkdirSync(path, { recursive: true });
writeFileSync(join(path, 'keep'), 'made-up human file');
await assert.rejects(api.ensureMirror(c));
assert.equal(readFileSync(join(path, 'keep'), 'utf8'), 'made-up human file');
rmSync(dataRoot, { recursive: true }); symlinkSync(f.repo, dataRoot);
assert.throws(() => api.mirrorPath(c), { code: 'project-path' });
unlinkSync(dataRoot);
c.business.projects.code = { root: dataRoot };
assert.throws(() => api.mirrorPath(c), { code: 'project-path' });
});
test('C2-04 mirror: existing metadata accepts only bare Git plus state and the precreated lock', async t => {
const f = await fixture(t);
writeFileSync(join(f.mirror, 'unknown-note'), 'do not silently allow this');
await assert.rejects(api.ensureMirror(f.context), { code: 'library-git' });
assert.equal(readFileSync(join(f.mirror, 'unknown-note'), 'utf8'), 'do not silently allow this');
unlinkSync(join(f.mirror, 'unknown-note'));
git(f.mirror, 'config', 'remote.origin.url', 'https://example.invalid/fixture.git');
await assert.rejects(api.ensureMirror(f.context), { code: 'library-git' });
git(f.mirror, 'config', '--remove-section', 'remote.origin');
unlinkSync(join(f.mirror, 'mosaic-library-sync.lock'));
await assert.rejects(api.ensureMirror(f.context), { code: 'library-state-invalid' });
assert.equal(existsSync(join(f.mirror, 'mosaic-library-sync.lock')), false);
});
test('C2-04 state: missing state is empty only while the served ref is absent', async t => {
const f = await fixture(t);
assert.deepEqual(await api.readSyncState(f.mirror, { branch: 'main' }), state());
f.seed(); unlinkSync(stateFile(f.mirror));
await assert.rejects(api.readSyncState(f.mirror, { branch: 'main' }), { code: 'library-state-invalid' });
});
test('C2-04 state: valid problems and sync metadata return no content and change no state bytes', async t => {
const f = await fixture(t); f.seed();
const value = { ...state(f.commit), lastFetch: NOW, lastError: { code: 'library-git', at: NOW },
diverged: { commit: 'a'.repeat(40), at: NOW },
problems: [{ code: 'R4', path: 'Book One/Chapters/A.md', line: 2, message: 'link resolves to no file or to more than one' }] };
f.writeState(value); const before = readFileSync(stateFile(f.mirror));
assert.deepEqual(await api.readSyncState(f.mirror, { branch: 'main' }), value);
assert.equal(JSON.stringify(await api.libraryStatus(f.context)).includes(MARKER), false);
assert.deepEqual(readFileSync(stateFile(f.mirror)), before);
});
test('C2-04 state: strict keys, types, times, branch, commit and fixed R messages fail closed', async t => {
const f = await fixture(t); f.seed();
const mutations = [
s => { s.extra = true; }, s => { s.version = 2; }, s => { s.branch = 'other'; },
s => { s.served = 'a'.repeat(40); }, s => { s.served = null; }, s => { s.served = 'ABC'; },
s => { s.lastFetch = 'yesterday'; }, s => { s.lastFetch = 1; },
s => { s.lastError = { code: 'bad code', at: NOW }; },
s => { s.lastError = { code: 'library-git', at: NOW, stderr: MARKER }; },
s => { s.diverged = { commit: 'not-a-sha', at: NOW }; },
s => { s.problems = [{ code: 'R1', path: 'Book One/A.md', message: MARKER }]; },
s => { s.problems = [{ code: 'R4', path: 'Book One/A.md', line: 0, message: 'link resolves to no file or to more than one' }]; },
s => { s.problems = null; },
];
for (const mutate of mutations) {
const s = state(f.commit); mutate(s); f.writeState(s);
const before = readFileSync(stateFile(f.mirror));
await assert.rejects(api.readSyncState(f.mirror, { branch: 'main' }), { code: 'library-state-invalid' });
assert.deepEqual(readFileSync(stateFile(f.mirror)), before);
}
writeFileSync(stateFile(f.mirror), '{');
await assert.rejects(api.readSyncState(f.mirror, { branch: 'main' }), { code: 'library-state-invalid' });
});
test('C2-04 state: symlink, hardlink, non-private state and missing lock refuse without replacement', async t => {
const f = await fixture(t); f.seed();
const outside = join(f.root, 'outside.json'); writeFileSync(outside, JSON.stringify(state(f.commit)), { mode: 0o600 });
unlinkSync(stateFile(f.mirror)); symlinkSync(outside, stateFile(f.mirror));
await assert.rejects(api.readSyncState(f.mirror, { branch: 'main' }), { code: 'library-state-invalid' });
unlinkSync(stateFile(f.mirror)); linkSync(outside, stateFile(f.mirror));
await assert.rejects(api.readSyncState(f.mirror, { branch: 'main' }), { code: 'library-state-invalid' });
unlinkSync(stateFile(f.mirror)); f.writeState(state(f.commit)); chmodSync(stateFile(f.mirror), 0o644);
await assert.rejects(api.readSyncState(f.mirror, { branch: 'main' }), { code: 'library-state-invalid' });
chmodSync(stateFile(f.mirror), 0o600); unlinkSync(join(f.mirror, 'mosaic-library-sync.lock'));
await assert.rejects(api.readSyncState(f.mirror, { branch: 'main' }), { code: 'library-state-invalid' });
assert.equal(existsSync(join(f.mirror, 'mosaic-library-sync.lock')), false);
});
test('C2-04 file: served commit, not HEAD or a caller commit, owns the exact returned text', async t => {
const f = await fixture(t); f.seed();
const path = 'Book One/Characters/Tomas.md';
writeFileSync(join(f.repo, path), 'newer text\n'); git(f.repo, 'commit', '-qam', 'newer');
git(f.repo, '-c', 'protocol.file.allow=always', 'push', '-q', f.mirror, 'HEAD:refs/heads/unserved');
git(f.mirror, 'symbolic-ref', 'HEAD', 'refs/heads/unserved');
assert.deepEqual(await api.readLibraryFile({ ...f.context, path }), { project: 'books', path, commit: f.commit, content: BASE[path] });
await assert.rejects(api.readLibraryFile({ ...f.context, path, commit: git(f.repo, 'rev-parse', 'HEAD') }), { code: 'project-read-path' });
for (const path of ['../escape.md', '/absolute.md', 'Book One/Board.canvas', 'Inbox Note.md'])
await assert.rejects(api.readLibraryFile({ ...f.context, path }), { code: 'project-read-path' });
await assert.rejects(api.readLibraryFile({ ...f.context, path: 'Book One/Missing.md' }), { code: 'project-read-missing' });
});
test('C2-04 file: R1, R2 and R7 exclusions and never-synced mirrors cannot return file bodies', async t => {
const f = await fixture(t, { ...BASE, 'Book One/Bad.md': { link: 'Characters/Tomas.md' },
'Book One/Executable.md': { mode: 0o755, text: MARKER },
'Book One/Twin.md': MARKER, 'Book One/twin.md': MARKER });
await assert.rejects(api.readLibraryFile({ ...f.context, path: 'Book One/Characters/Tomas.md' }), { code: 'library-commit' });
f.seed();
for (const path of ['Book One/Bad.md', 'Book One/Executable.md', 'Book One/Twin.md', 'Book One/twin.md'])
await assert.rejects(api.readLibraryFile({ ...f.context, path }), { code: 'project-read-missing' });
});
function child(t, source) {
const env = { ...process.env }; delete env.NODE_TEST_CONTEXT;
const p = spawn(process.execPath, ['--input-type=module', '-e', source], { env, stdio: ['ignore', 'pipe', 'pipe', 'ipc'] });
let stderr = ''; p.stderr.on('data', b => { stderr += b; }); p.stdout.resume();
p.finished = new Promise(resolve => { p.once('error', e => resolve({ error: e })); p.once('close', code => resolve({ code, stderr })); });
t.after(async () => { if (p.exitCode === null) p.kill('SIGKILL'); await p.finished; });
return p;
}
test('C2-04 lock: a first-sync and fast-forward reader wait for a consistent pair across processes', { timeout: 15000 }, async t => {
const f = await fixture(t);
// Transfer objects without serving them. No fetch or remote is added by the API.
git(f.repo, '-c', 'protocol.file.allow=always', 'push', '-q', f.mirror, 'HEAD:refs/heads/candidate');
for (const first of [true, false]) {
if (!first) { f.seed(); writeFileSync(join(f.repo, 'Book One/New.md'), '# New\n'); git(f.repo, 'add', '.'); git(f.repo, 'commit', '-qm', 'new');
git(f.repo, '-c', 'protocol.file.allow=always', 'push', '-q', f.mirror, 'HEAD:refs/heads/candidate'); }
const commit = git(f.repo, 'rev-parse', 'HEAD');
const writer = child(t, `import {withLibraryLock} from ${JSON.stringify(MOD)};import {writeFileSync} from 'node:fs';import {git} from ${JSON.stringify(new URL('../../project/src/git.mjs', import.meta.url).href)};
await withLibraryLock(${JSON.stringify(f.mirror)},async()=>{await git(${JSON.stringify(f.mirror)},['update-ref','refs/heads/served',${JSON.stringify(commit)}]);process.send('moved');await new Promise(r=>process.once('message',r));writeFileSync(${JSON.stringify(stateFile(f.mirror))},${JSON.stringify(JSON.stringify(state(commit)))},{mode:0o600});});process.disconnect();`);
const [message] = await once(writer, 'message'); assert.equal(message, 'moved');
let complete = false;
const read = api.readSyncState(f.mirror, { branch: 'main' }).then(value => { complete = true; return value; });
await new Promise(r => setTimeout(r, 50)); assert.equal(complete, false, 'the inconsistent pair is not observed');
writer.send('publish');
assert.deepEqual(await read, state(commit));
assert.deepEqual(await writer.finished, { code: 0, stderr: '' });
}
});
test('C2-04 lock: same-process waits, timeout code, callback expiry and throw release', { timeout: 15000 }, async t => {
const f = await fixture(t); let release, scoped;
const held = api.withLibraryLock(f.mirror, async lock => { scoped = lock.readSyncState; await new Promise(r => { release = r; }); });
const deadline = Date.now() + 5000;
while (!release && Date.now() < deadline) await new Promise(r => setTimeout(r, 5));
assert.equal(typeof release, 'function', 'first lock acquired before deadline');
await assert.rejects(api.readSyncState(f.mirror, { branch: 'main' }), { code: 'library-sync-busy' });
release(); await held;
await assert.rejects(scoped({ branch: 'main' }), { code: 'library-state-invalid' });
await assert.rejects(api.withLibraryLock(f.mirror, async () => { throw Error('fixture throw'); }), /fixture throw/);
assert.deepEqual(await api.readSyncState(f.mirror, { branch: 'main' }), state());
});
test('C2-04 lock: owner death releases the kernel lock without replacing its file', { timeout: 15000 }, async t => {
const f = await fixture(t), lock = join(f.mirror, 'mosaic-library-sync.lock'), ino = lstatSync(lock).ino;
const owner = child(t, `import {withLibraryLock} from ${JSON.stringify(MOD)};await withLibraryLock(${JSON.stringify(f.mirror)},async()=>{process.send('held');await new Promise(r=>process.once('message',r));});`);
const [message] = await once(owner, 'message'); assert.equal(message, 'held');
owner.kill('SIGKILL'); await owner.finished;
assert.deepEqual(await api.readSyncState(f.mirror, { branch: 'main' }), state());
assert.equal(lstatSync(lock).ino, ino);
});
test('C2-04 lock: a missing flock binary becomes a handled refusal', { timeout: 10000 }, async t => {
const f = await fixture(t);
const missing = child(t, `import cp from 'node:child_process';import {syncBuiltinESMExports} from 'node:module';import {EventEmitter} from 'node:events';
const original=cp.spawn;cp.spawn=(command,...args)=>{if(command!=='/usr/bin/flock')return original(command,...args);const p=new EventEmitter();process.nextTick(()=>p.emit('error',Object.assign(Error('fixture missing flock'),{code:'ENOENT'})));return p;};syncBuiltinESMExports();
const {readSyncState}=await import(${JSON.stringify(MOD)});try{await readSyncState(${JSON.stringify(f.mirror)},{branch:'main'});process.send('unexpected success');}catch(e){process.send(e.code);}process.disconnect();`);
const [code] = await once(missing, 'message');
assert.equal(code, 'library-state-invalid');
assert.deepEqual(await missing.finished, { code: 0, stderr: '' });
});
test('C2-04 lock: an unawaited scoped read drains before the lock is released', { timeout: 10000 }, async t => {
const f = await fixture(t); let scoped, pending, complete = false;
await api.withLibraryLock(f.mirror, lock => {
scoped = lock.readSyncState;
pending = scoped({ branch: 'main' }).then(value => { complete = true; return value; });
});
assert.equal(complete, true);
assert.deepEqual(await pending, state());
await assert.rejects(scoped({ branch: 'main' }), { code: 'library-state-invalid' });
});