// Row 195 (#1693): scripts/case1-accept.sh, root's acceptance run on the Case 1 host. Design r7 section 5 // (agents/darkwing/work/queue-195/DESIGN.md); deviations in agents/darkwing/work/queue-195/BUILD.md. // Every case runs the script with --root on a scratch host tree: /etc, /proc, /srv/mosaic, /opt and the // host check live under it. Fake systemctl, curl, ss, sudo and stat on PATH record their argv; the fake // sudo runs the stack's user's commands from the tree. Nothing here reads or writes the real /etc, // /proc or /srv, and the stand-in credential is not a credential. import { test } from "node:test"; import { createHash } from "node:crypto"; import assert from "node:assert/strict"; import { spawnSync } from "node:child_process"; import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, rmSync, symlinkSync, writeFileSync } from "node:fs"; import { dirname, join } from "node:path"; import { fileURLToPath } from "node:url"; import { tmp } from "./helpers.mjs"; import { instrumentP10Probe, removeP10Observers, readProbeSeconds, P10_OBSERVERS } from "./case-p10-timing-fixture.mjs"; import { instrumentInnerTimer } from "./case-inner-timing-fixture.mjs"; import { CASE_SUDO_SESSION, recordedLivePids, killRecordedPids, fixtureGuard, cleanupFixture, pollFixtureGone, blockingQuerySource, LEGACY_CASES } from "./case-sudo-fixture.mjs"; const REPO = fileURLToPath(new URL("../../../", import.meta.url)); const SCRIPT = join(REPO, "scripts", "case1-accept.sh"); const COPY = "0123456789abcdef0123456789abcdef01234567"; const NODE_PIN = "v24.1.0", CLAUDE_PIN = "2.1.0"; const NODE = `/opt/mosaic-stack/node-${NODE_PIN}/bin/node`; const CLAUDE = `/opt/mosaic-stack/claude-${CLAUDE_PIN}/node_modules/@anthropic-ai/claude-code/bin/claude.exe`; const HOME = "/srv/mosaic"; const CLI = `${HOME}/.local/share/mosaic-stack/copies/${COPY}/scripts/mosaic`; const PRECHECK = `${HOME}/.local/share/mosaic-stack/copies/${COPY}/scripts/case2-precheck.sh`; const CRED = `${HOME}/.config/mosaic-dev/secrets/claude-session.env`; const CRED_VALUE = "stand-in-not-a-credential-7f3e2a"; const AS_MOSAIC = `-u mosaic -H env PATH=/opt/mosaic-stack/node-${NODE_PIN}/bin:/usr/local/bin:/usr/bin:/bin`; const ARGS = ["--profile", "factory", "--user", "mosaic", "--home", HOME, "--business", "mosaic-stack", "--copy", COPY, "--node", NODE, "--claude", CLAUDE, "--pm", "--", "--port", "732", "--business", "mosaic-stack", "--tester-socket"]; const OUTER = "bwrap (enforce)", CHILD = "bwrap//&unpriv_bwrap (enforce)"; const MARKS = ["pass", "FAIL", "closed", "accepted Q182+Q183", "accepted Q183", "accepted mos-1096", "unnamed"]; const P_PASS = { P1: "closed", P2: "closed", P3: "accepted Q183", P4: "accepted Q182+Q183", P5: "closed", P6: "closed", P7: "closed", P8: "closed", P9: "accepted mos-1096", P10: "unnamed", P11: "closed" }; const PASSWD = "root:x:0:0:root:/root:/bin/bash\nmosaic:x:997:997::/srv/mosaic:/usr/sbin/nologin\nlocaladmin:x:1000:1000::/home/localadmin:/bin/bash\njarvis:x:1001:1001::/home/jarvis:/bin/bash\n"; const GROUP = "root:x:0:\nsudo:x:27:localadmin\nmosaic:x:997:\nlxd:x:998:\ndocker:x:999:\nlocaladmin:x:1000:\njarvis:x:1001:\n"; const SS = "LISTEN 0 511 127.0.0.1:732 0.0.0.0:* users:((\"node\",pid=200,fd=21))\n" + "LISTEN 0 4096 0.0.0.0:22 0.0.0.0:* users:((\"sshd\",pid=900,fd=3))\n"; const HOSTCHECK_OK = [1, 2, 3, 4, 5, 6, 7].map((n) => `ok ${n} item ${n} holds`).join("\n") + "\nnote bubblewrap 0.9.0 is the install pin\n"; function put(file, text, mode) { mkdirSync(dirname(file), { recursive: true }); writeFileSync(file, text); if (mode) chmodSync(file, mode); } const read = file => readFileSync(file,"utf8"); const edit = (file, f) => writeFileSync(file, f(readFileSync(file, "utf8"))); const log = (name) => `printf '%s' ${JSON.stringify(name)} >> "$HC/calls.log"; printf ' %s' "$@" >> "$HC/calls.log"; echo >> "$HC/calls.log"`; // Fakes on PATH. Each records its argv and answers from a file in the state directory. const FAKES = { systemctl: `case "$1" in show) [ -f "$HC/show-$2" ] && cat "$HC/show-$2" ;; is-enabled) cat "$HC/enabled-$2" 2>/dev/null || { echo disabled; exit 1; } ;; esac`, curl: `exit "$(cat "$HC/curl-rc")"`, ss: `cat "$HC/ss"`, od: `if [ "$1" = -An ] && [ "$2" = -tx1 ] && [ "$3" = -N4 ]; then [ -f "$HC/elf" ] && cat "$HC/elf" || echo 7f454c46 else exec /usr/bin/od "$@"; fi`, // The credential and the settings file answer from the state directory, as root would see them, and // only those calls are recorded; everything else is the real stat, which reads the args file. stat: `case "\${@: -1}" in *claude-session.env) ${log("stat")}; cat "$HC/stat-cred" ;; *console/tester.sock) cat "$HC/stat-socket" ;; *console) [ "$2" = '%u %a %F %d %i' ] && cat "$HC/stat-parent" || echo "997 700" ;; *managed-settings.json) ${log("stat")}; cat "$HC/stat-settings" ;; *) exec /usr/bin/stat "$@" ;; esac`, // -l -U USER prints the state file; -u jarvis is the bwrap probe; -u mosaic -H env PATH=... CMD runs // CMD from the tree, with the PATH entries and each absolute argument that exists there moved under it. sudo: `${CASE_SUDO_SESSION} /usr/bin/python3 -I -S -c 'import json,os,sys;f=open(os.environ["HC"]+"/sudo-argv.jsonl","a");f.write(json.dumps(sys.argv[1:])+chr(10));f.close()' "$@" case "$1" in -l) [ -f "$HC/sudo-l-$3" ] && cat "$HC/sudo-l-$3"; exit 0 ;; -u) ;; *) exit 97 ;; esac user="$2"; shift 2 if [ "$user" = jarvis ]; then cat "$HC/jarvis-bwrap" >&2; exit "$(cat "$HC/jarvis-bwrap-rc")"; fi [ "$user" = mosaic ] && [ "$1" = -H ] && [ "$2" = env ] || exit 98 shift 2 if [ "$1" = -i ]; then [ "$2" = HOME=/srv/mosaic ] || exit 98 shift 2 fi [[ "$1" == PATH=* ]] || exit 98 p="\${1#PATH=}"; shift np=""; IFS=: read -ra parts <<< "$p"; for x in "\${parts[@]}"; do np+="$ROOT_DIR$x:"; done cmd="$1"; shift args=(); for a in "$@"; do if [[ "$a" == /* ]] && [ -e "$ROOT_DIR$a" ]; then args+=("$ROOT_DIR$a"); else args+=("$a"); fi; done export HOME="$ROOT_DIR/srv/mosaic" PATH="$np$PATH" [ ! -e "$ROOT_DIR$cmd" ] || cmd="$ROOT_DIR$cmd" case_sudo_run "$HC" "$cmd" "\${args[@]}"`, }; // Executables inside the tree, run by the fake sudo or by the script itself. Node marks a run outside // the fake sudo, which sets HOME to the stack's home, so a test can tell whether root ran it. const NODE_STUB = `[ "$HOME" = "$ROOT_DIR/srv/mosaic" ] || touch "$HC/node-as-root" [ "\${1:-}" = --version ] && { cat "$HC/node-version"; exit 0; } exec "$REAL_NODE" "$@"`; // The real Python payload runs against a mock socket object, never an OS listener. const PYTHON_STUB = `[ -f "$HC/peer-output" ] && exec /usr/bin/python3 -I -S -c 'import os,sys; root=os.environ["HC"]; sys.stdout.buffer.write(open(root+"/peer-output","rb").read()); sys.exit(int(open(root+"/peer-status").read()))' [ -f "$HC/peer-hang" ] && { here="$BASHPID"; read -r sid < <(/bin/ps -o sid= -p "$here") echo "$here" > "$HC/peer-pid"; printf '%s %s\\n' "$here" "$sid" >> "$HC/query-pids" trap '' TERM HUP; exec sleep 60 } if [ -f "$HC/peer-change" ]; then cat "$HC/peer-change" > "$HC/stat-socket"; fi if [ -f "$HC/peer-pid-change" ]; then cat "$HC/peer-pid-change" > "$HC/show-mosaic-webui.service"; fi exec /usr/bin/python3 -I -S -c ' import os,socket,struct,sys class Fake: def __init__(self,*a): assert a==(socket.AF_UNIX,socket.SOCK_STREAM) def settimeout(self,n): assert n==1 def connect(self,p): assert p.endswith("/console/tester.sock") def getsockopt(self,*a): assert a==(socket.SOL_SOCKET,socket.SO_PEERCRED,12) return struct.pack("3i",*[int(x) for x in open(os.environ["HC"]+"/peer").read().split()]) def close(self): pass socket.socket=Fake payload=sys.argv[4] sys.argv=["probe",sys.argv[5]] exec(payload) ' "$@"`; const TREE = { "/usr/bin/python3": PYTHON_STUB, [NODE]: NODE_STUB, [CLAUDE]: `[ "\${1:-}" = --version ] && cat "$HC/claude-version"; exit 0`, [CLI]: `${log("mosaic")} case "$1" in talk) case "$(cat "$HC/talk-mode")" in reply) echo "sent ab12cd34 to chief"; echo "[chief -> tester] seen" ;; noreply) echo "sent ab12cd34 to chief"; echo "no reply from chief within 300 s" >&2; exit 1 ;; sentonly) echo "sent ab12cd34 to chief" ;; esac ;; launches) cat "$HC/launches.json" ;; *) exit 2 ;; esac`, [PRECHECK]: `${log("precheck")} echo "precheck: done"; exit "$(cat "$HC/precheck-rc")"`, "/usr/local/lib/mosaic-stack/hostcheck.sh": `${log("hostcheck")} cat "$HC/hostcheck-out"`, }; function proc(root, pid, { ppid, uid = 997, exe, argv0 = "x", comm = "x", label }) { const d = join(root, "proc", String(pid)); put(join(d, "status"), `Name:\t${comm}\nState:\tS (sleeping)\nPPid:\t${ppid}\nUid:\t${uid}\t${uid}\t${uid}\t${uid}\n`); put(join(d, "cmdline"), `${argv0}\0--x\0`); put(join(d, "comm"), `${comm}\n`); rmSync(join(d, "exe"), { force: true }); if (exe) symlinkSync(exe, join(d, "exe")); if (label !== undefined) put(join(d, "attr", "current"), label); } // A scratch Case 1 host where every F check passes and every P check is closed or accepted. function host(t) { const dir = tmp(t, "c1accept-"); const root = join(dir, "root"), hc = join(dir, "hc"), bin = join(dir, "bin"); const args = join(root, "etc", "mosaic-stack", "dev.args"); put(args, ARGS.join("\n") + "\n", 0o644); put(join(root, "etc", "passwd"), PASSWD); put(join(root, "etc", "group"), GROUP); put(join(root, "etc", "sudoers.d", "90-localadmin"), "localadmin ALL=(ALL) NOPASSWD: ALL\n"); put(join(root, "etc", "claude-code", "managed-settings.json"), JSON.stringify({ env: { DISABLE_AUTOUPDATER: "1" } })); put(join(root, CRED), `CLAUDE_CODE_OAUTH_TOKEN=${CRED_VALUE}\n`, 0o600); put(join(root, HOME, ".config", "mosaic-dev", "businesses", "mosaic-stack.json"), JSON.stringify({ id: "mosaic-stack", launch: { by: "pm" } })); put(join(root, "proc", "sys", "net", "ipv4", "ip_unprivileged_port_start"), "1024\n"); proc(root, 1, { ppid: 0, uid: 0, exe: "/usr/lib/systemd/systemd", comm: "systemd" }); proc(root, 100, { ppid: 1, exe: NODE, argv0: NODE, comm: "node" }); proc(root, 200, { ppid: 1, exe: NODE, argv0: NODE, comm: "node" }); proc(root, 300, { ppid: 100, exe: "/usr/bin/bwrap", argv0: "/usr/bin/bwrap", comm: "bwrap", label: `${OUTER}\n` }); proc(root, 301, { ppid: 300, exe: NODE, argv0: NODE, comm: "node", label: `${CHILD}\n` }); proc(root, 302, { ppid: 301, exe: CLAUDE, argv0: CLAUDE, comm: "claude.exe", label: `${CHILD}\n` }); // A root bwrap with a mislabelled claude child, which F5 must pass over. proc(root, 400, { ppid: 1, uid: 0, exe: "/usr/bin/bwrap", argv0: "/usr/bin/bwrap", comm: "bwrap", label: "unconfined\n" }); proc(root, 401, { ppid: 400, uid: 0, argv0: "claude", comm: "claude", label: "unconfined\n" }); const state = { "show-mosaic-bus@mosaic-stack.service": "ActiveState=active\nUser=mosaic\nMainPID=100\n", "show-mosaic-webui.service": "ActiveState=active\nUser=mosaic\nMainPID=200\n", "show-mosaic-hostcheck.service": "Before=mosaic-bus@mosaic-stack.service mosaic-webui.service multi-user.target\n", "enabled-mosaic-hostcheck.service": "enabled\n", "curl-rc": "0", ss: SS, "stat-parent": "997 700 directory 9 10\n", "stat-socket": "997 600 socket 9 11\n", peer: "200 997 997\n", "stat-cred": "mosaic 600 regular file\n", "stat-settings": "root:root 644 regular file\n", "sudo-l-mosaic": "User mosaic is not allowed to run sudo on dev-53.\n", "sudo-l-localadmin": "User localadmin may run the following commands on dev-53:\n (ALL : ALL) ALL\n (ALL) NOPASSWD: ALL\n", "jarvis-bwrap": "sudo: unable to execute /usr/bin/bwrap: Permission denied\n", "jarvis-bwrap-rc": "1", "node-version": `${NODE_PIN}\n`, "claude-version": `${CLAUDE_PIN} (Claude Code)\n`, "talk-mode": "reply", "precheck-rc": "0", "hostcheck-out": HOSTCHECK_OK, "launches.json": JSON.stringify([ { instance: "pm", live: true, business: "mosaic-stack", run: "r-0002" }, { instance: "pm", live: false, business: "mosaic-stack", run: "r-0001" }, { instance: "dev-1", live: true, business: "mosaic-stack", run: "r-0003" }, ]), }; for (const [name, text] of Object.entries(state)) put(join(hc, name), text); for (const [name, body] of Object.entries(FAKES)) put(join(bin, name), `#!/usr/bin/env bash\n${name === "stat" ? "" : log(name)}\n${body}\n`, 0o755); for (const [path, body] of Object.entries(TREE)) put(join(root, path), `#!/usr/bin/env bash\n${body}\n`, 0o755); const copyRoot = join(root, HOME, '.local/share/mosaic-stack/copies', COPY); put(join(copyRoot, 'packages/cli/src/config.mjs'), `import fs from 'node:fs';export const loadSystem=()=>({dataRoot:fs.readFileSync(${JSON.stringify(join(hc,'data-root'))},'utf8').trim()});`); put(join(copyRoot, 'packages/webui/src/cli.mjs'), '// MOSAIC_TESTER_SOCKET_V1\n'); put(join(hc, 'data-root'), `${HOME}/.mosaic-dev\n`); put(join(root, HOME, '.mosaic-dev/console/tester.sock'), 'stand-in socket metadata only'); chmodSync(join(root, HOME, '.mosaic-dev/console'), 0o700); // F9 runs node only when it and each directory above it have no group or other write, whatever the umask. for (let d = dirname(NODE); d !== "/"; d = dirname(d)) chmodSync(join(root, d), 0o755); chmodSync(root, 0o755); return { dir, root, hc, bin, args }; } function run(h, extra = {}, argv = ["--business", "mosaic-stack", "--args", "/etc/mosaic-stack/dev.args", "--claude-pin", CLAUDE_PIN, "--node-pin", NODE_PIN, "--root", h.root], script = SCRIPT) { const r = spawnSync(script, argv, { encoding: "utf8", env: { ...process.env, PATH: `${h.bin}:${process.env.PATH}`, HC: h.hc, ROOT_DIR: h.root, REAL_NODE: process.execPath, TMPDIR: h.dir, ...extra }, }); const lines = r.stdout.split("\n").filter(Boolean); // Each check line as { id, path, mark, evidence }. const checks = lines.filter((l) => /^[FP][0-9]+ /.test(l)).map((l) => { const [id, path, ...rest] = l.split(" "); const tail = rest.join(" "); const mark = MARKS.find((m) => tail === m || tail.startsWith(`${m} `)); return { id, path, mark, evidence: tail.slice(mark?.length ?? 0).trim(), line: l }; }); return { status: r.status, out: r.stdout, err: r.stderr, lines, checks }; } const calls = (h, name) => (existsSync(join(h.hc, "calls.log")) ? readFileSync(join(h.hc, "calls.log"), "utf8") : "") .split("\n").filter((l) => l === name || l.startsWith(`${name} `)).map((l) => l.slice(name.length + 1)); const failed = (r) => r.checks.filter((c) => c.mark === "FAIL").map((c) => c.id); const marksOf = (r, id) => r.checks.filter((c) => c.id === id).map((c) => c.mark); const mustRun = (h, extra) => { const r = run(h, extra); assert.ok(r.status === 0 || r.status === 1, r.out + r.err); return r; }; test('row253 socket observation uses configured root, metadata and the Console peer without sending bytes', t=>{ const h=host(t), data='/srv/mosaic/custom-data'; put(join(h.hc,'data-root'),data+'\n'); put(join(h.root,data,'console/tester.sock'),'metadata stand-in'); const r=run(h); assert.equal(r.status,0,r.out+r.err); assert.match(r.out,/P10 tester-socket-squat unnamed boundary=observed path=\/srv\/mosaic\/custom-data\/console\/tester.sock/); assert.match(r.out,/peer_pid=200 peer_uid=997/); assert.match(r.out,/hostile same-uid substitution remains/); assert.doesNotMatch(r.out,/accepted mos-1101/); assert.deepEqual(marksOf(r,'P8'),['closed']); }); test('row253 P10 refuses unsafe metadata, wrong peers and an unsafe Python without claiming closure',t=>{ const faults={ 'parent-mode': h=>put(join(h.hc,'stat-parent'),'997 755 directory 9 10\n'), 'parent-owner': h=>put(join(h.hc,'stat-parent'),'998 700 directory 9 10\n'), 'socket-mode': h=>put(join(h.hc,'stat-socket'),'997 660 socket 9 11\n'), 'socket-owner': h=>put(join(h.hc,'stat-socket'),'998 600 socket 9 11\n'), 'socket-type': h=>put(join(h.hc,'stat-socket'),'997 600 regular file 9 11\n'), symlink:h=>{const p=join(h.root,HOME,'.mosaic-dev/console/tester.sock');rmSync(p);symlinkSync('/absent',p);}, peer:h=>put(join(h.hc,'peer'),'200 998 997\n'), 'peer-pid':h=>put(join(h.hc,'peer'),'555 997 997\n'), 'python-mode':h=>chmodSync(join(h.root,'usr/bin/python3'),0o777), 'python-missing':h=>rmSync(join(h.root,'usr/bin/python3')), 'python-not-elf':h=>put(join(h.hc,'elf'),'23212f62\n'), 'peer-malformed':h=>{put(join(h.hc,'peer-output'),'200 997 997 extra\n');put(join(h.hc,'peer-status'),'0');}, 'peer-error':h=>{put(join(h.hc,'peer-output'),'200 997 997\n');put(join(h.hc,'peer-status'),'1');}, 'peer-uid-fields':h=>proc(h.root,200,{ppid:1,uid:998,exe:NODE,comm:'node'}), 'changed-inode':h=>put(join(h.hc,'peer-change'),'997 600 socket 9 99\n'), 'changed-pid':h=>put(join(h.hc,'peer-pid-change'),'ActiveState=active\nUser=mosaic\nMainPID=201\n'), floor:h=>put(join(h.root,'proc/sys/net/ipv4/ip_unprivileged_port_start'),'700\n'), }; const reasons = { "parent-mode": "metadata", "parent-owner": "metadata", "socket-mode": "metadata", "socket-owner": "metadata", "socket-type": "metadata", "symlink": "metadata", "peer": "peer", "peer-pid": "peer", "python-mode": "interpreter", "python-missing": "interpreter", "python-not-elf": "interpreter", "peer-malformed": "probe", "peer-error": "probe-inner-command", "peer-uid-fields": "metadata", "changed-inode": "changed", "changed-pid": "changed", "floor": "floor", }; for(const [name,fault] of Object.entries(faults)){ const h=host(t);fault(h);const r=run(h); assert.equal(r.status,name==='peer-uid-fields'?1:0,`${name}: ${r.out}${r.err}`); assert.match(r.out,/P10 tester-socket-squat unnamed boundary=failed/,name); assert.doesNotMatch(r.out,/boundary=observed/,name); assert.match(r.out,new RegExp('^P10 tester-socket-squat unnamed boundary=failed reason='+reasons[name]+' ', 'm'),name); } }); test('row253 acceptance rejects bad config and unsupported copies before talk',t=>{ const faults={ outside:h=>put(join(h.hc,'data-root'),'/srv/mosaic2/data\n'), dot:h=>put(join(h.hc,'data-root'),'/srv/mosaic/./data\n'), absent:h=>rmSync(join(h.root,HOME,'.local/share/mosaic-stack/copies',COPY,'packages/cli/src/config.mjs')), unmarked:h=>put(join(h.root,HOME,'.local/share/mosaic-stack/copies',COPY,'packages/webui/src/cli.mjs'),'// old copy'), schema:h=>put(join(h.root,HOME,'.local/share/mosaic-stack/copies',COPY,'packages/cli/src/config.mjs'),'console.log(JSON.stringify({dataRoot:"/srv/mosaic/.mosaic-dev",socket:true,extra:1}));process.exit(0);'), failed:h=>put(join(h.root,HOME,'.local/share/mosaic-stack/copies',COPY,'packages/cli/src/config.mjs'),'console.log(JSON.stringify({dataRoot:"/srv/mosaic/.mosaic-dev",socket:true}));process.exit(1);'), }; for(const [name,fault] of Object.entries(faults)){ const h=host(t);fault(h);const r=run(h); assert.equal(r.status,2,`${name}: ${r.out}${r.err}`);assert.equal(r.out,''); assert.match(r.err,/tester (config query|path refuses)|support/); assert.deepEqual(calls(h,'mosaic'),[]); } }); test('row253 stalled peer observation ends within its bound without leaving a reader',async t=>{ const h=host(t);put(join(h.hc,'peer-hang'),''); const r=run(h);assert.equal(r.status,0,r.out+r.err); assert.match(r.out,/P10 tester-socket-squat unnamed boundary=failed reason=probe/); const pid=Number(readFileSync(join(h.hc,'peer-pid'),'utf8')); let state='gone'; for(let n=0;n<50;n++){ try{state=readFileSync(`/proc/${pid}/stat`,'utf8').split(') ')[1].split(' ')[0];}catch{state='gone';} if(state==='gone'||state==='Z')break; await new Promise(resolve=>setTimeout(resolve,10)); } assert.ok(state==='gone'||state==='Z',`peer helper ${pid} still ${state}`); }); test('row253 P8 refuses both retired TCP and board listeners',t=>{ for(const port of [7333,7331]){ const h=host(t);put(join(h.hc,'ss'),SS+`LISTEN 0 511 127.0.0.1:${port} 0.0.0.0:* users:(("node",pid=200,fd=22))\n`); assert.deepEqual(marksOf(run(h),'P8'),['unnamed']); } }); test('row253 C4 acceptance query inner reason holds under both sudo models',async t=>{ for(const mode of ['exec','hop']){ const h=host(t),files=[join(h.hc,'session-pids'),join(h.hc,'query-pids')]; put(join(h.hc,'session-mode'),mode); put(join(h.root,HOME,'.local/share/mosaic-stack/copies',COPY,'packages/cli/src/config.mjs'),blockingQuerySource(files[1])); const capture=cleanupFixture(t,files);const stop=fixtureGuard(t,files); const start=performance.now(),r=run(h),seconds=(performance.now()-start)/1000;capture(); assert.equal(r.status,2,r.out+r.err);assert.equal(r.err,'case1-accept: refusing: tester config query inner-timeout\n'); assert.ok(seconds<7,`${mode}: ${seconds}s`);assert.equal(r.out,'');assert.deepEqual(calls(h,'mosaic'),[]); assert.deepEqual(await pollFixtureGone(files),[]);await stop(); } }); test('row253 C4 acceptance query outer reason discards stdout and names residual cleanup',async t=>{ for(const mode of ['exec','hop']){ const h=host(t),files=[join(h.hc,'session-pids')];put(join(h.hc,'session-mode'),mode);put(join(h.hc,'stall-config'),''); put(join(h.hc,'stall-output'),JSON.stringify({dataRoot:HOME+'/.mosaic-dev',socket:true})); const capture=cleanupFixture(t,files);const stop=fixtureGuard(t,files); const start=performance.now(),r=run(h),seconds=(performance.now()-start)/1000;capture(); assert.equal(r.status,2,r.out+r.err);assert.equal(r.err,'case1-accept: refusing: tester config query outer-timeout\n'); assert.ok(seconds>=7&&seconds<9,`${mode}: ${seconds}s; 2s preflight slack`); assert.equal(r.out,'');assert.deepEqual(calls(h,'mosaic'),[]); if(mode==='hop')assert.ok(recordedLivePids(files[0]).length>0,'R3 session remains before fixture cleanup'); killRecordedPids(files[0]);assert.deepEqual(await pollFixtureGone(files),[],'explicit R3 fixture cleanup');await stop(); } }); test('row253 C4 acceptance query overflow is output-limit in both models',async t=>{ for(const mode of ['exec','hop']){ const h=host(t),files=[join(h.hc,'session-pids')];put(join(h.hc,'session-mode'),mode);const capture=cleanupFixture(t,files); put(join(h.root,HOME,'.local/share/mosaic-stack/copies',COPY,'packages/cli/src/config.mjs'),`process.stdout.write('X'.repeat(8192));export const loadSystem=()=>({dataRoot:'${HOME}/.mosaic-dev'});`); const r=run(h);capture();assert.equal(r.status,2,r.out+r.err);assert.equal(r.err,'case1-accept: refusing: tester config query output-limit\n'); assert.equal(r.out,'');assert.deepEqual(calls(h,'mosaic'),[]);assert.deepEqual(await pollFixtureGone(files),[]); } }); test('row299 P10 timing copy preserves shipped bytes and isolates observer variables',()=>{ const source=read(SCRIPT),copy=instrumentP10Probe(source); assert.equal(removeP10Observers(copy),read(SCRIPT),'observer reversal equals a fresh shipped script read'); for(const block of Object.values(P10_OBSERVERS)){ const reads=[...block.matchAll(/\bread -r ([A-Za-z_][A-Za-z0-9_ ]*) < \/proc\/uptime/g)]; assert.equal(reads.length,1,'one direct host clock read per observer'); const assigned=reads[0][1].trim().split(/\s+/); assert.deepEqual(assigned,['row299_up','row299_spare']); assert.ok(assigned.every(name=>/^row299_/.test(name)),'read targets cannot clobber capture locals'); assert.deepEqual([...block.matchAll(/\b([A-Za-z_][A-Za-z0-9_]*)=/g)],[],'no other assignments in observer blocks'); assert.doesNotMatch(block,/\$ROOT|\$\{ROOT/,'fixture root cannot supply the clock'); } // The fake sudo keys its faults on these argument markers; observers must not add or remove any. for(const marker of['SO_PEERCRED','MOSAIC_TESTER_SOCKET_V1','MOSAIC_LEGACY_STATUS']) assert.equal(copy.split(marker).length,source.split(marker).length,`observers keep the ${marker} count`); const changedTimer=source.replace('tester_capture 2 4 128','tester_capture 1 4 128'); assert.equal(removeP10Observers(instrumentP10Probe(changedTimer)),changedTimer,'copy keeps current timer mutants'); }); test('row299 P10 observers preserve stdout stderr status and the EXIT trap',t=>{ const dir=tmp(t,'p10-clock-'),clock=join(dir,'clock'),trapFile=join(dir,'trap'); put(clock,'',0o600); const program=`set -uo pipefail capture() ( maximum=128; rc=87 trap 'printf trap > "$ROW299_TRAP_FILE"' EXIT ${P10_OBSERVERS.begin}printf stdout-without-newline printf stderr-without-newline >&2 ${P10_OBSERVERS.end}exit "$rc" ) capture`; const r=spawnSync('/bin/bash',['-c',program],{encoding:'utf8',env:{...process.env,ROW299_TIMING_FILE:clock,ROW299_TRAP_FILE:trapFile}}); assert.equal(r.status,87); assert.equal(r.stdout,'stdout-without-newline'); assert.equal(r.stderr,'stderr-without-newline'); assert.equal(read(trapFile),'trap'); assert.match(read(clock),/^begin [0-9]+\.[0-9]{2}\nend [0-9]+\.[0-9]{2}\n$/); }); test('row299 P10 timer observers keep supervisor status and record one P10 pair',t=>{ const dir=tmp(t,'p10-timer-'),clock=join(dir,'clock'),trapFile=join(dir,'trap'); put(clock,'',0o600); // Same shape as TESTER_SUPERVISOR: positional arguments are the setsid command, finish() has none. const program=`set +m finish() { local rc="$?" ${P10_OBSERVERS.timerEnd} printf trap > "$ROW299_TRAP_FILE" exit "$rc" } trap finish EXIT ${P10_OBSERVERS.timerBegin}printf stdout-without-newline printf stderr-without-newline >&2 exit 81`; const supervise=(...args)=>spawnSync('/bin/bash',['-c',program,'--',...args],{encoding:'utf8',env:{...process.env,ROW299_TIMER_FILE:clock,ROW299_TRAP_FILE:trapFile}}); let r=supervise('node','-e','query'); assert.equal(r.status,81);assert.equal(read(clock),'','a supervisor without the P10 peer records nothing'); r=supervise('python','-c','getsockopt(SO_PEERCRED)'); assert.equal(r.status,81); assert.equal(r.stdout,'stdout-without-newline'); assert.equal(r.stderr,'stderr-without-newline'); assert.equal(read(trapFile),'trap'); assert.match(read(clock),/^begin [0-9]+\.[0-9]{2}\nend [0-9]+\.[0-9]{2}\n$/); const pair=read(clock); r=supervise('node','-e','later'); assert.equal(r.status,81);assert.equal(read(clock),pair,'a later supervisor cannot add a second end'); }); test('row299 P10 observer records are complete and ordered',()=>{ assert.equal(readProbeSeconds('begin 100.01\nend 102.03\n'),2.02); const invalid={ 'missing begin':'end 102.00\n', 'missing end':'begin 100.00\n', 'duplicate pair':'begin 100.00\nend 102.00\nbegin 102.00\nend 104.00\n', 'reversed order':'end 102.00\nbegin 100.00\n', 'non-numeric':'begin nope\nend 102.00\n', 'equal readings':'begin 100.00\nend 100.00\n', 'backward readings':'begin 102.00\nend 100.00\n', 'missing final newline':'begin 100.00\nend 102.00', 'extra final newline':'begin 100.00\nend 102.00\n\n', }; for(const [name,text] of Object.entries(invalid))assert.throws(()=>readProbeSeconds(text),/P10 observer/,name); }); for(const fault of ['inner','outer','overflow'])test(`row253 C4 P10 ${fault} reason holds under both sudo models`,async t=>{ for(const mode of ['exec','hop']){ const h=host(t),files=[join(h.hc,'session-pids'),join(h.hc,'query-pids')];put(join(h.hc,'session-mode'),mode); // mos-1350(b): measure this host/mode's functional cost before adding a fault. let baselineSeconds=0; if(fault==='inner'||fault==='outer'){ const baselineStart=performance.now(),baseline=run(h); baselineSeconds=(performance.now()-baselineStart)/1000; assert.equal(baseline.status,0,baseline.out+baseline.err); assert.deepEqual(await pollFixtureGone(files),[],'baseline leaves no session'); } const capture=cleanupFixture(t,files); if(fault==='inner')put(join(h.hc,'peer-hang'),''); if(fault==='outer'){put(join(h.hc,'stall-probe'),'');put(join(h.hc,'stall-output'),'200 997 997\n');} if(fault==='overflow'){put(join(h.hc,'peer-output'),'200 997 997\n'+'X'.repeat(256));put(join(h.hc,'peer-status'),'0');} let observedScript=SCRIPT,timingFile,timerFile; if(fault==='inner'||fault==='outer'){ observedScript=join(h.dir,'case1-p10-observed.sh');timingFile=join(h.hc,'probe-uptime'); put(timingFile,'',0o600);put(observedScript,instrumentP10Probe(read(SCRIPT)),0o700); // The outer fault stalls before the supervisor starts, so only the inner fault has a timer pair. if(fault==='inner'){timerFile=join(h.hc,'timer-uptime');put(timerFile,'',0o600);} put(join(h.dir,'selector.sh'),read(join(REPO,'scripts','selector.sh')),0o644); assert.equal(removeP10Observers(read(observedScript)),read(SCRIPT),'observer reversal equals a fresh shipped script read'); } const stop=fixtureGuard(t,files,7000,timingFile); const observe={...(timingFile?{ROW299_TIMING_FILE:timingFile}:{}),...(timerFile?{ROW299_TIMER_FILE:timerFile}:{})}; const start=performance.now(),r=run(h,observe,undefined,observedScript),seconds=(performance.now()-start)/1000;capture(); assert.equal(r.status,0,r.out+r.err); const reason=fault==='inner'?'inner-timeout':fault==='outer'?'outer-timeout':'output-limit'; assert.match(r.out,new RegExp('P10 tester-socket-squat unnamed boundary=failed reason=probe-'+reason+' ')); assert.doesNotMatch(r.out,/boundary=observed/); let probeSeconds=seconds,timerSeconds; if(timingFile)assert.doesNotThrow(()=>{probeSeconds=readProbeSeconds(read(timingFile));},'P10 observer pair is required'); if(timerFile)assert.doesNotThrow(()=>{timerSeconds=readProbeSeconds(read(timerFile));},'P10 timer observer pair is required'); if(fault==='inner'||fault==='outer')t.diagnostic(JSON.stringify({fault,mode,baselineSeconds,faultSeconds:seconds,probeSeconds,timerSeconds})); // org-base-reds: the band applies to the inner timer itself. The root pair adds supervisor start-up and // clean_session's whole-host /proc scan, which grows with the host's process count, so it must contain // the timer pair but has no band of its own; probe-inner-timeout above already places it before the outer bound. if(fault==='inner'){ assert.ok(timerSeconds>=1.25&&timerSeconds<2.75,`${mode}: inner timer ${timerSeconds}s (root probe ${probeSeconds}s); baseline ${baselineSeconds}s is diagnostic only`); assert.ok(probeSeconds>=timerSeconds,`${mode}: root probe ${probeSeconds}s must contain the inner timer ${timerSeconds}s`); } if(fault==='outer'){ assert.ok(probeSeconds>=3.25&&probeSeconds<4.75,`${mode}: direct probe ${probeSeconds}s; baseline ${baselineSeconds}s is diagnostic only`); if(mode==='hop')assert.ok(recordedLivePids(files[0]).length>0,'stalled supervisor is R3 residual'); for(const file of files)killRecordedPids(file); } assert.deepEqual(await pollFixtureGone(files),[],fault==='outer'?'explicit R3 cleanup':mode);await stop(); } }); // One fault per F check; each makes that check, and only that one, fail. const F_FAULTS = { F1: (h) => proc(h.root, 100, { ppid: 1, uid: 0, exe: NODE, comm: "node" }), F2: (h) => put(join(h.hc, "ss"), SS.replace("127.0.0.1:732 ", "0.0.0.0:732 ")), F3: (h) => put(join(h.hc, "talk-mode"), "noreply"), F4: (h) => put(join(h.hc, "precheck-rc"), "1"), F5: (h) => put(join(h.root, "proc", "302", "attr", "current"), "unconfined\n"), F6: (h) => put(join(h.hc, "claude-version"), "2.0.9 (Claude Code)\n"), F7: (h) => put(join(h.hc, "launches.json"), JSON.stringify([{ instance: "pm", live: false, business: "mosaic-stack", run: "r-1" }])), F8: (h) => put(join(h.hc, "stat-cred"), "mosaic 640 regular file\n"), F9: (h) => put(join(h.root, "etc", "claude-code", "managed-settings.json"), JSON.stringify({ env: { DISABLE_AUTOUPDATER: "0" } })), F10: (h) => put(join(h.hc, "node-version"), "v24.0.0\n"), F11: (h) => put(join(h.root, HOME, ".mosaic-dev", "discord", "binding.json"), "{}"), }; test("row 195 accept: every check passing exits 0, with each P mark and counts that match the lines", (t) => { const h = host(t); const r = run(h); assert.equal(r.status, 0, r.out + r.err); assert.deepEqual(r.checks.map((c) => c.id), ["F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "P1", "P2", "P3", "P4", "P5", "P6", "P7", "P8", "P9", "P10", "P11"]); for (const c of r.checks.filter((x) => x.id.startsWith("F"))) assert.equal(c.mark, "pass", c.line); for (const [id, mark] of Object.entries(P_PASS)) assert.deepEqual(marksOf(r, id), [mark], id); const counts = r.lines.filter((l) => l.startsWith("count ")).map((l) => l.slice(6)); assert.deepEqual(counts, MARKS.map((m) => `${m} ${r.checks.filter((c) => c.mark === m).length}`)); assert.match(r.lines.at(-1), /^case1-accept: every F check passes/); assert.match(r.out, /^F5 bwrap-label pass bwrap 300 reads 'bwrap \(enforce\)' and its claude descendant 302 reads/m); assert.match(r.out, /^F7 pm-live pass one live launch: pm run r-0002$/m); assert.ok(!(r.out + r.err).includes(CRED_VALUE)); assert.ok(existsSync(join(h.hc, "node-as-root")), "F9 runs the pinned, root-only node as root"); }); test("row 195 accept: exits 1 with each F check failing alone, and its line names it", (t) => { for (const [id, fault] of Object.entries(F_FAULTS)) { const h = host(t); fault(h); const r = mustRun(h); assert.equal(r.status, 1, `${id}: ${r.out}`); assert.deepEqual(failed(r), [id], `${id}: ${r.out}`); assert.equal(r.lines.at(-1), "case1-accept: an F check failed, so the row fails"); } }); test("row 195 accept: F3 fails on exit 0 with no reply line, and its evidence takes talk's error", (t) => { let h = host(t); put(join(h.hc, "talk-mode"), "sentonly"); let r = mustRun(h); assert.deepEqual(failed(r), ["F3"]); assert.match(r.out, /^F3 tester-reply FAIL talk exited 0 with 1 lines on stdout; last: sent ab12cd34 to chief$/m); h = host(t); put(join(h.hc, "talk-mode"), "noreply"); r = mustRun(h); assert.match(r.out, /^F3 tester-reply FAIL talk exited 1 with 1 lines on stdout; last: no reply from chief within 300 s$/m); }); test("row 195 accept: F1 fails on a unit that isn't active or isn't User=mosaic", (t) => { for (const show of ["ActiveState=failed\nUser=mosaic\nMainPID=0\n", "ActiveState=active\nUser=root\nMainPID=100\n"]) { const h = host(t); put(join(h.hc, "show-mosaic-webui.service"), show); const r = mustRun(h); assert.equal(r.status, 1); assert.ok(failed(r).includes("F1"), r.out); } }); test("row 195 accept: F2 fails when healthz doesn't answer and when another pid holds the port", (t) => { let h = host(t); put(join(h.hc, "curl-rc"), "7"); let r = mustRun(h); assert.deepEqual(failed(r), ["F2"]); assert.match(r.out, /^F2 console-loopback FAIL curl http:\/\/127\.0\.0\.1:732\/healthz exited 7$/m); h = host(t); put(join(h.hc, "ss"), SS.replace("pid=200,fd=21", "pid=555,fd=4")); r = mustRun(h); assert.deepEqual(failed(r), ["F2"]); }); test("row 195 accept: F5 fails on unpriv_bwrap (enforce), on complain and on a trailing space", (t) => { for (const label of ["unpriv_bwrap (enforce)\n", "bwrap//&unpriv_bwrap (complain)\n", `${CHILD} \n`]) { const h = host(t); put(join(h.root, "proc", "302", "attr", "current"), label); const r = mustRun(h); assert.deepEqual(failed(r), ["F5"], `${JSON.stringify(label)}: ${r.out}`); } const h = host(t); put(join(h.root, "proc", "300", "attr", "current"), `${OUTER} \n`); assert.deepEqual(failed(mustRun(h)), ["F5"]); }); test("row 195 accept: F5 fails with no bwrap of mosaic's, and passes on comm alone", (t) => { let h = host(t); proc(h.root, 300, { ppid: 100, uid: 1001, exe: "/usr/bin/bwrap", comm: "bwrap", label: `${OUTER}\n` }); let r = mustRun(h); assert.deepEqual(failed(r), ["F5"]); assert.match(r.out, /^F5 bwrap-label FAIL no \/usr\/bin\/bwrap process of mosaic/m); h = host(t); proc(h.root, 302, { ppid: 301, argv0: "/proc/self/fd/3", comm: "claude", label: `${CHILD}\n` }); assert.deepEqual(failed(mustRun(h)), []); }); test("row 195 accept: F6 fails on a stub that prints nothing, on a path outside claude- and on a .. segment", (t) => { let h = host(t); put(join(h.hc, "claude-version"), ""); let r = mustRun(h); assert.deepEqual(failed(r), ["F6"]); h = host(t); const other = CLAUDE.replace(`claude-${CLAUDE_PIN}`, "claude-2.0.9"); put(h.args, ARGS.map((a) => (a === CLAUDE ? other : a)).join("\n") + "\n", 0o644); put(join(h.root, other), `#!/usr/bin/env bash\necho "${CLAUDE_PIN} (Claude Code)"\n`, 0o755); r = mustRun(h); assert.deepEqual(failed(r), ["F6"]); assert.match(r.out, /^F6 claude-pin FAIL --claude \S+claude-2\.0\.9\S+ is not under \/opt\/mosaic-stack\/claude-2\.1\.0\/$/m); // Under claude-/ by prefix, but the binary it names is 2.0.9's, which answers with the pin. h = host(t); const dotdot = CLAUDE.replace(`claude-${CLAUDE_PIN}/`, `claude-${CLAUDE_PIN}/../claude-2.0.9/`); put(h.args, ARGS.map((a) => (a === CLAUDE ? dotdot : a)).join("\n") + "\n", 0o644); put(join(h.root, other), `#!/usr/bin/env bash\necho "${CLAUDE_PIN} (Claude Code)"\n`, 0o755); r = mustRun(h); assert.deepEqual(failed(r), ["F6"], r.out); assert.match(r.out, /^F6 claude-pin FAIL --claude \S+\/claude-2\.1\.0\/\.\.\/claude-2\.0\.9\/\S+ has a \.\. segment$/m); }); test("row 195 accept: F7 fails on two live PM launches, one for another business, and no launch.by", (t) => { const two = [{ instance: "pm", live: true, business: "mosaic-stack", run: "a" }, { instance: "pm", live: true, business: "mosaic-stack", run: "b" }]; for (const [file, text] of [["launches.json", JSON.stringify(two)], ["launches.json", JSON.stringify([{ instance: "pm", live: true, business: "other", run: "a" }])]]) { const h = host(t); put(join(h.hc, file), text); assert.deepEqual(failed(mustRun(h)), ["F7"]); } const h = host(t); put(join(h.root, HOME, ".config", "mosaic-dev", "businesses", "mosaic-stack.json"), JSON.stringify({ id: "mosaic-stack" })); const r = mustRun(h); assert.deepEqual(failed(r), ["F7"]); assert.match(r.out, /^F7 pm-live FAIL the business file has no launch\.by$/m); }); test("row 195 accept: F8 fails on 0640, on another owner and on a symlink, and never prints the credential", (t) => { for (const fault of [ (h) => put(join(h.hc, "stat-cred"), "mosaic 640 regular file\n"), (h) => put(join(h.hc, "stat-cred"), "root 600 regular file\n"), (h) => { const f = join(h.root, CRED); rmSync(f); put(`${f}.real`, `X=${CRED_VALUE}\n`, 0o600); symlinkSync(`${f}.real`, f); }, ]) { const h = host(t); fault(h); const r = mustRun(h); assert.deepEqual(failed(r), ["F8"], r.out); assert.ok(!(r.out + r.err).includes(CRED_VALUE)); } }); test("row 195 accept: F9 fails on another owner, a group-writable mode and a number for the flag", (t) => { for (const fault of [ (h) => put(join(h.hc, "stat-settings"), "root:root 664 regular file\n"), (h) => put(join(h.hc, "stat-settings"), "mosaic:root 644 regular file\n"), (h) => put(join(h.root, "etc", "claude-code", "managed-settings.json"), JSON.stringify({ env: { DISABLE_AUTOUPDATER: 1 } })), ]) { const h = host(t); fault(h); assert.deepEqual(failed(mustRun(h)), ["F9"]); } }); test("row 195 accept: F9 won't run --node as root off the pin path or with a writable directory above it", (t) => { // Another node that works for the stack's user: F9 refuses to run it, and F10 fails on the path. let h = host(t); const other = NODE.replace(NODE_PIN, "v24.0.9"); put(h.args, ARGS.map((a) => (a === NODE ? other : a)).join("\n") + "\n", 0o644); put(join(h.root, other), `#!/usr/bin/env bash\n${NODE_STUB}\n`, 0o755); let r = mustRun(h); assert.deepEqual(failed(r), ["F9", "F10"], r.out); assert.match(r.out, /^F9 autoupdater-off FAIL root won't run --node \/opt\/mosaic-stack\/node-v24\.0\.9\/bin\/node: it is not the --node-pin path$/m); assert.ok(!existsSync(join(h.hc, "node-as-root"))); // The pinned path, under a group-writable directory and then a symlinked node: F9 alone fails, and // root doesn't run it. for (const [fault, bad] of [ [(x) => chmodSync(join(x.root, dirname(NODE)), 0o775), "/opt/mosaic-stack/node-v24\\.1\\.0/bin \\(uid \\d+, mode 775\\)"], [(x) => { const f = join(x.root, NODE); renameSync(f, `${f}.real`); symlinkSync(`${f}.real`, f); }, "/opt/mosaic-stack/node-v24\\.1\\.0/bin/node \\(uid \\d+, mode 777\\)"], ]) { h = host(t); fault(h); r = mustRun(h); assert.deepEqual(failed(r), ["F9"], r.out); assert.match(r.out, new RegExp(`^F9 autoupdater-off FAIL root won't run --node \\S+: ${bad} is not root's alone$`, "m")); assert.ok(!existsSync(join(h.hc, "node-as-root"))); } }); test("row 195 accept: F11 fails on one *.json under discord/ and passes on an empty directory", (t) => { let h = host(t); put(join(h.root, HOME, ".mosaic-dev", "discord", "chief.json"), "{}"); let r = mustRun(h); assert.deepEqual(failed(r), ["F11"]); assert.match(r.out, /^F11 no-discord FAIL \/srv\/mosaic\/\.mosaic-dev\/discord holds bindings: chief\.json$/m); h = host(t); mkdirSync(join(h.root, HOME, ".mosaic-dev", "discord"), { recursive: true }); assert.deepEqual(failed(mustRun(h)), []); }); // Each P check in its unnamed mark, with the line count each fault makes; none changes the exit. const P_FAULTS = { P1: [1, (h) => put(join(h.hc, "sudo-l-mosaic"), "User mosaic may run the following commands on dev-53:\n")], P2: [1, (h) => put(join(h.root, HOME, ".ssh", "authorized_keys"), "ssh-ed25519 AAAA test\n")], P5: [1, (h) => edit(join(h.root, "etc", "group"), (s) => s.replace("docker:x:999:", "docker:x:999:jarvis"))], P6: [2, (h) => edit(join(h.root, "etc", "group"), (s) => s.replace("sudo:x:27:localadmin", "sudo:x:27:localadmin,bob").replace("lxd:x:998:", "lxd:x:998:carol"))], P7: [1, (h) => put(join(h.root, "etc", "sudoers.d", "50-mosaic"), "mosaic ALL=(root) NOPASSWD: /usr/bin/systemctl\n")], P8: [1, (h) => put(join(h.hc, "ss"), `${SS}LISTEN 0 511 0.0.0.0:7331 0.0.0.0:* users:(("node",pid=200,fd=23))\n`)], P9: [3, (h) => { put(join(h.hc, "hostcheck-out"), HOSTCHECK_OK.replace("ok 2 ", "FAIL 2 ").replace("ok 5 ", "FAIL 5 ")); put(join(h.hc, "jarvis-bwrap-rc"), "0"); }], P10: [1, (h) => put(join(h.root, "proc", "sys", "net", "ipv4", "ip_unprivileged_port_start"), "700\n")], P11: [1, (h) => put(join(h.hc, "show-mosaic-hostcheck.service"), "Before=mosaic-bus@other.service multi-user.target\n")], }; test("row 195 accept: each P check reports unnamed on its fault, and the exit stays 0", (t) => { for (const [id, [n, fault]] of Object.entries(P_FAULTS)) { const h = host(t); fault(h); const r = run(h); assert.equal(r.status, 0, `${id}: ${r.out}`); assert.deepEqual(marksOf(r, id), Array(n).fill("unnamed"), `${id}: ${r.out}`); } }); test("row 195 accept: P2 is unnamed with a supplementary group, and P5 names docker", (t) => { let h = host(t); put(join(h.root, "etc", "group"), GROUP.replace("lxd:x:998:", "lxd:x:998:mosaic")); let r = run(h); assert.equal(r.status, 0); assert.deepEqual(marksOf(r, "P2"), ["unnamed"]); assert.match(r.out, /^P2 mosaic-groups-keys unnamed id -G is '997 998'; authorized_keys is absent$/m); h = host(t); P_FAULTS.P5[1](h); r = run(h); assert.match(r.out, /^P5 jarvis-reach unnamed jarvis is in docker$/m); assert.match(r.out, /^P6 group-docker unnamed jarvis is a member of docker$/m); }); test("row 195 accept: P5 is closed with no jarvis account, and P2 with an empty authorized_keys", (t) => { const h = host(t); put(join(h.root, "etc", "passwd"), PASSWD.replace(/^jarvis:.*\n/m, "")); put(join(h.root, HOME, ".ssh", "authorized_keys"), ""); const r = run(h); assert.deepEqual(marksOf(r, "P5"), ["closed"]); assert.deepEqual(marksOf(r, "P2"), ["closed"]); }); test("row 195 accept: P9 is unnamed once for each item missing", (t) => { const items = { hostcheck: (h) => put(join(h.hc, "hostcheck-out"), HOSTCHECK_OK.replace("ok 3 ", "FAIL 3 ")), jarvis: (h) => { put(join(h.hc, "jarvis-bwrap-rc"), "0"); put(join(h.hc, "jarvis-bwrap"), ""); }, member: (h) => put(join(h.root, "etc", "group"), GROUP.replace("mosaic:x:997:", "mosaic:x:997:jarvis")), gid: (h) => put(join(h.root, "etc", "passwd"), `${PASSWD}hermes:x:1002:997::/home/hermes:/bin/bash\n`), }; for (const [name, fault] of Object.entries(items)) { const h = host(t); fault(h); const r = run(h); assert.equal(r.status, 0); assert.deepEqual(marksOf(r, "P9"), ["unnamed"], `${name}: ${r.out}`); } const h = host(t); put(join(h.hc, "hostcheck-out"), ""); assert.deepEqual(marksOf(run(h), "P9"), Array(6).fill("unnamed")); }); test("row253 accept: P10 fails its observation with another peer; P11 with the unit disabled", (t) => { let h = host(t); put(join(h.hc, "peer"), "555 997 997\n"); let r = run(h); assert.equal(r.status, 0); assert.deepEqual(marksOf(r, "P10"), ["unnamed"]); assert.match(r.out, /P10 tester-socket-squat unnamed boundary=failed reason=peer/); h = host(t); put(join(h.hc, "enabled-mosaic-hostcheck.service"), "disabled\n"); r = run(h); assert.deepEqual(marksOf(r, "P11"), ["unnamed"]); }); test("row 195 accept: every P check unnamed together still exits 0", (t) => { const h = host(t); for (const [, fault] of Object.values(P_FAULTS)) fault(h); const r = run(h); assert.equal(r.status, 0, r.out + r.err); assert.deepEqual(failed(r), []); for (const id of ["P1", "P2", "P5", "P6", "P7", "P8", "P9", "P10", "P11"]) assert.ok(marksOf(r, id).every((m) => m === "unnamed"), id); assert.match(r.lines.at(-1), /^case1-accept: every F check passes/); }); test("row 195 accept: a bad args file refuses with exit 2 before any check, each for its own reason", (t) => { const bad = { "group write": [(h) => chmodSync(h.args, 0o664), /dev\.args must be \S+'s with no group or other write \(it is uid \d+, mode 664\)$/], symlink: [(h) => { put(`${h.args}.real`, ARGS.join("\n") + "\n", 0o644); rmSync(h.args); symlinkSync(`${h.args}.real`, h.args); }, /no regular file \/etc\/mosaic-stack\/dev\.args$/], "unknown flag": [(h) => put(h.args, ["--send", ...ARGS].join("\n") + "\n", 0o644), /has --send before --, which case2-unit\.sh does not take$/], "two copies": [(h) => put(h.args, ["--copy", COPY, ...ARGS].join("\n") + "\n", 0o644), /needs exactly one --copy before --, not 2$/], "library profile": [(h) => put(h.args, ARGS.map((a) => (a === "factory" ? "library" : a)).join("\n") + "\n", 0o644), /has --profile 'library', not factory$/], "another business": [(h) => put(h.args, ARGS.map((a, i) => (a === "mosaic-stack" && i < 14 ? "acme" : a)).join("\n") + "\n", 0o644), /is for business acme, not mosaic-stack$/], "no tester socket": [(h) => put(h.args, ARGS.slice(0, -1).join("\n") + "\n", 0o644), /needs one bare --tester-socket after --$/], "retired TCP": [(h) => put(h.args, [...ARGS.slice(0,-1),'--tester-port','7333'].join('\n')+'\n',0o644), /case1-accept.sh retires tester TCP; use --tester-socket$/], "socket value": [(h) => put(h.args, [...ARGS,'7333'].join('\n')+'\n',0o644), /unknown serve flag 7333$/], "duplicate socket": [(h) => put(h.args, [...ARGS,'--tester-socket'].join('\n')+'\n',0o644), /needs one bare --tester-socket after --$/], "short copy": [(h) => put(h.args, ARGS.map((a) => (a === COPY ? "abc123" : a)).join("\n") + "\n", 0o644), /lacks a plain --user, --home, --business, --node, --claude or --copy$/], "no file": [(h) => rmSync(h.args), /no regular file \/etc\/mosaic-stack\/dev\.args$/], }; for (const [name, [fault, why]] of Object.entries(bad)) { const h = host(t); fault(h); const r = run(h); assert.equal(r.status, 2, `${name}: ${r.out}${r.err}`); assert.match(r.err.trimEnd(), /^case1-accept: refusing: /, name); assert.match(r.err.trimEnd(), why, name); assert.equal(r.out, "", name); assert.ok(!existsSync(join(h.hc, "calls.log")), name); } }); test("row 195 accept: usage errors and a run without --root as a user exit 2", (t) => { const h = host(t); let r = run(h, {}, ["--business", "mosaic-stack", "--args", "/etc/mosaic-stack/dev.args", "--node-pin", NODE_PIN, "--root", h.root]); assert.equal(r.status, 2); assert.match(r.err, /^usage: /); r = run(h, {}, ["--business", "mosaic-stack", "--args", "/etc/mosaic-stack/dev.args", "--claude-pin", CLAUDE_PIN, "--node-pin", "24.1.0", "--root", h.root]); assert.equal(r.status, 2); r = run(h, {}, ["--business", "mosaic-stack", "--args", "/etc/mosaic-stack/dev.args", "--claude-pin", CLAUDE_PIN, "--node-pin", NODE_PIN]); assert.equal(r.status, 2); assert.equal(r.err, "case1-accept: refusing: run it as root\n"); assert.ok(!existsSync(join(h.hc, "calls.log"))); }); // The selector (rename design r2): --org and --business are one option in each of three scopes, the // script's own arguments and the args file's unit and serve arguments either side of --. A spelling // may appear once per scope, and the other spelling only with the same value; never counted across --. const SELECT = { old: ["--business", "mosaic-stack"], new: ["--org", "mosaic-stack"], both: ["--business", "mosaic-stack", "--org", "mosaic-stack"], swapped: ["--org", "mosaic-stack", "--business", "mosaic-stack"] }; // The args file with outer unit selector tokens and serve selector tokens in ARGS's places. const argsWith = (outer, serve) => [...ARGS.slice(0, 6), ...outer, ...ARGS.slice(8, 16), "--port", "732", ...serve, "--tester-socket"]; const invocation = (h, sel) => [...sel, "--args", "/etc/mosaic-stack/dev.args", "--claude-pin", CLAUDE_PIN, "--node-pin", NODE_PIN, "--root", h.root]; test("row 195 accept: --org or --business names the business in each of the three scopes, and talk and precheck still get --business", (t) => { const runs = [["old", "old", "old"], ["new", "new", "new"], ["both", "swapped", "both"], ["swapped", "both", "swapped"], ["new", "old", "new"], ["old", "new", "old"], ["both", "old", "swapped"]]; const seen = []; for (const [inv, outer, serve] of runs) { const h = host(t), name = `${inv} ${outer} -- ${serve}`; put(h.args, argsWith(SELECT[outer], SELECT[serve]).join("\n") + "\n", 0o644); const r = run(h, {}, invocation(h, SELECT[inv])); assert.equal(r.status, 0, `${name}: ${r.out}${r.err}`); assert.deepEqual(failed(r), [], name); const talk = calls(h, "mosaic").filter((a) => a.startsWith("talk ")); assert.equal(talk.length, 1, name); assert.match(talk[0], /^talk chief case1-accept-[0-9a-f]{12}: .* --business mosaic-stack --tester --wait 300$/, name); assert.deepEqual(calls(h, "precheck"), ["--business mosaic-stack --profile factory"], name); seen.push(r.lines.filter((l) => /^[FP][0-9]+ /.test(l)).map((l) => l.split(" ").slice(0, 3).join(" "))); } for (const marks of seen) assert.deepEqual(marks, seen[0]); }); test("row 195 accept: a bad selector in any scope, or scopes that name different businesses, refuse with exit 2 before any check", (t) => { const usage = "usage: case1-accept.sh --business ID --args FILE --claude-pin PIN --node-pin vN.N.N\n"; const refusing = (why) => `case1-accept: refusing: ${why}\n`; const before = (why) => refusing(`/etc/mosaic-stack/dev.args before --: ${why}`); const after = (why) => refusing(`/etc/mosaic-stack/dev.args after --: ${why}`); const cases = [ // The script's own arguments. ["invocation unequal", ["--business", "mosaic-stack", "--org", "beta"], null, refusing("--business mosaic-stack and --org beta conflict")], ["invocation unequal, new first", ["--org", "mosaic-stack", "--business", "beta"], null, refusing("--org mosaic-stack and --business beta conflict")], ["invocation old twice", ["--business", "mosaic-stack", "--business", "mosaic-stack"], null, refusing("--business given twice")], ["invocation new twice", ["--org", "mosaic-stack", "--org", "mosaic-stack"], null, refusing("--org given twice")], ["invocation new empty", ["--org", ""], null, usage], ["invocation new flag-shaped", ["--org", "--args"], null, usage], ["invocation new invalid", ["--org", "Mosaic"], null, usage], ["invocation old invalid", ["--business", "a/../b"], null, usage], // The args file's unit arguments. ["unit unequal", ["--org", "mosaic-stack"], argsWith(["--business", "mosaic-stack", "--org", "beta"], SELECT.old), before("--business mosaic-stack and --org beta conflict")], ["unit unequal, new first", ["--org", "mosaic-stack"], argsWith(["--org", "mosaic-stack", "--business", "beta"], SELECT.old), before("--org mosaic-stack and --business beta conflict")], ["unit old twice", ["--org", "mosaic-stack"], argsWith(["--business", "mosaic-stack", "--business", "mosaic-stack"], SELECT.old), before("--business given twice")], ["unit new twice", ["--org", "mosaic-stack"], argsWith(["--org", "mosaic-stack", "--org", "mosaic-stack"], SELECT.new), before("--org given twice")], ["unit new missing", SELECT.old, [...ARGS.slice(0, 6), ...ARGS.slice(8, 15), "--org"], before("--org needs one value")], ["unit new flag-shaped", SELECT.old, argsWith(["--org"], SELECT.old), before("--org needs one value, not --copy")], ["unit new invalid", SELECT.old, argsWith(["--org", "Mosaic"], SELECT.old), before("--org Mosaic is not valid")], ["unit names another business", SELECT.new, argsWith(["--org", "beta"], SELECT.new), refusing("/etc/mosaic-stack/dev.args is for business beta, not mosaic-stack")], // --home takes --org as its value, so --business is the unit's one selector and the home refuses. ["unit --home value", SELECT.old, argsWith(["--business", "mosaic-stack"], SELECT.old).map((a, i) => (i === 5 ? "--org" : a)), refusing("/etc/mosaic-stack/dev.args lacks a plain --user, --home, --business, --node, --claude or --copy")], // The args file's serve arguments. ["serve unequal", SELECT.old, argsWith(SELECT.old, ["--business", "mosaic-stack", "--org", "beta"]), after("--business mosaic-stack and --org beta conflict")], ["serve unequal, new first", SELECT.old, argsWith(SELECT.old, ["--org", "mosaic-stack", "--business", "beta"]), after("--org mosaic-stack and --business beta conflict")], ["serve old twice", SELECT.old, argsWith(SELECT.old, ["--business", "mosaic-stack", "--business", "mosaic-stack"]), after("--business given twice")], ["serve new twice", SELECT.old, argsWith(SELECT.new, ["--org", "mosaic-stack", "--org", "mosaic-stack"]), after("--org given twice")], ["serve new missing", SELECT.old, [...argsWith(SELECT.old, []), "--org"], after("--org needs one value")], ["serve new flag-shaped", SELECT.old, argsWith(SELECT.old, ["--org"]), after("--org needs one value, not --tester-socket")], ["serve new invalid", SELECT.old, argsWith(SELECT.old, ["--org", "Mosaic"]), after("--org Mosaic is not valid")], ["serve names another business", SELECT.new, argsWith(SELECT.new, ["--org", "beta"]), refusing("serve business differs")], ["serve has no selector", SELECT.old, argsWith(SELECT.old, []), refusing("/etc/mosaic-stack/dev.args needs --business or --org after --")], // --port takes --org as its value; the serve selector is the --business after it. ["serve --port value", SELECT.old, [...argsWith(SELECT.old, []).slice(0, 17), "--org", "--business", "mosaic-stack", "--tester-socket"], refusing("/etc/mosaic-stack/dev.args lacks a privileged numeric --port after --")], ]; for (const [name, sel, file, err] of cases) { const h = host(t); if (file) put(h.args, file.join("\n") + "\n", 0o644); const r = run(h, {}, invocation(h, sel)); assert.equal(r.status, 2, `${name}: ${r.out}${r.err}`); assert.equal(r.err, err, name); assert.equal(r.out, "", name); assert.ok(!existsSync(join(h.hc, "calls.log")), name); } // A missing value at the end of the script's own arguments is a usage error. const h = host(t); const r = run(h, {}, ["--args", "/etc/mosaic-stack/dev.args", "--claude-pin", CLAUDE_PIN, "--node-pin", NODE_PIN, "--root", h.root, "--org"]); assert.equal(r.status, 2); assert.equal(r.err, usage); }); test("row 195 accept: a copy of the script without selector.sh beside it refuses before parsing", (t) => { const h = host(t), lone = join(h.dir, "lone", "case1-accept.sh"); put(lone, read(SCRIPT), 0o755); const r = run(h, {}, undefined, lone); assert.equal(r.status, 2, r.out + r.err); assert.ok(r.err.endsWith(`case1-accept: refusing: cannot read ${join(h.dir, "lone", "selector.sh")}\n`), r.err); assert.equal(r.out, ""); assert.ok(!existsSync(join(h.hc, "calls.log"))); }); test("row 195 accept: every in-instance call goes through sudo -u mosaic -H env PATH=:...", (t) => { const h = host(t); const r = run(h); assert.equal(r.status, 0, r.out + r.err); const sudo = calls(h, "sudo"); const asMosaic = sudo.filter((a) => a.startsWith("-u mosaic")); const isolated = asMosaic.filter(a=>a.startsWith('-u mosaic -H env -i ')); assert.equal(isolated.length, 2); for(const a of isolated) assert.ok(a.startsWith(`-u mosaic -H env -i HOME=${HOME} PATH=/opt/mosaic-stack/node-${NODE_PIN}/bin:/usr/local/bin:/usr/bin:/bin `),a); for (const a of asMosaic.filter(a=>!isolated.includes(a))) assert.ok(a.startsWith(`${AS_MOSAIC} /`), a); const cmds = asMosaic.filter(a=>!isolated.includes(a)).map((a) => a.slice(AS_MOSAIC.length + 1).split(" ")[0]); assert.equal(asMosaic.length,7,'two metadata/probe calls and five legacy calls'); assert.deepEqual([...new Set(cmds)].sort(), ['/usr/bin/bash']); // mos-1326: assert every argv element, not flattened/substr command detection. const source=read(SCRIPT); const supervisor=source.split("<<'MOSAIC_TESTER_SUPERVISOR'")[1].split('\n').slice(1).join('\n').split('\nMOSAIC_TESTER_SUPERVISOR')[0]+'\n'; assert.equal(createHash('sha256').update(supervisor).digest('hex'),'52509773fa2bb0701402b8d2454816153e18323cfaa75cb72418b46c4dbb2d34'); const runner=/LEGACY_COMMAND_RUNNER='([\s\S]*?)'\nlegacy_display_rc/.exec(source)[1]; const f7=/F7_JS='([\s\S]*?)'\ncheck_f7/.exec(source)[1]; const raw=read(join(h.hc,'sudo-argv.jsonl')).trim().split('\n').map(line=>JSON.parse(line)); const legacy=raw.filter(a=>a[0]==='-u'&&a[1]==='mosaic'&&a[4].startsWith('PATH=')); const marker=legacy[0][20].split(':')[0]; const argv=(tag,inner,command)=>['-u','mosaic','-H','env',`PATH=/opt/mosaic-stack/node-${NODE_PIN}/bin:/usr/local/bin:/usr/bin:/bin`, '/usr/bin/bash','-c',supervisor,'--',String(inner),'/usr/bin/setsid','/usr/bin/sleep',NODE,'-e',runner,'--',tag,...command]; assert.deepEqual(legacy,[ argv('talk',320,[CLI,'talk','chief',marker+': this is the Case 1 acceptance; reply with one short line.','--business','mosaic-stack','--tester','--wait','300']), argv('precheck',200,[PRECHECK,'--business','mosaic-stack','--profile','factory']), argv('claude-version',5,[CLAUDE,'--version']), argv('pm-list',10,[NODE,'-e',f7,'--',`${HOME}/.config/mosaic-dev/businesses/mosaic-stack.json`,CLI,'mosaic-stack']), argv('node-version',5,[NODE,'--version']), ]); assert.deepEqual(sudo.filter((a) => !a.startsWith("-u mosaic")).sort(), ["-l -U localadmin", "-l -U mosaic", "-u jarvis /usr/bin/bwrap --version"]); const talk = calls(h, "mosaic").filter((a) => a.startsWith("talk ")); assert.equal(talk.length, 1); assert.match(talk[0], /^talk chief case1-accept-[0-9a-f]{12}: .* --business mosaic-stack --tester --wait 300$/); assert.deepEqual(calls(h, "precheck"), ["--business mosaic-stack --profile factory"]); }); test("row 195 accept: the host check runs with --check and never --enforce", (t) => { const h = host(t); run(h); assert.deepEqual(calls(h, "hostcheck"), ["--check"]); }); // Row276 exercises the real legacy launcher with fixture-only commands, never sudo. function legacyBody(source=read(SCRIPT)) { const start=source.indexOf('# row253-supervisor-begin'),end=source.indexOf('# row276-legacy-end'); assert.ok(start>=0&&end>start,'legacy supervisor block exists'); return source.slice(start,end); } function legacyCall(h,tag,command,{inner='0.5',outer='2',body=legacyBody()}={}) { return spawnSync('/bin/bash',['-c',body+'\nlegacy_run "$@"','--',tag,String(inner),String(outer),...command],{ encoding:'utf8',env:{...process.env,PATH:`${h.bin}:${process.env.PATH}`,HC:h.hc,ROOT_DIR:h.root,REAL_NODE:process.execPath,TMPDIR:h.dir, S_USER:'mosaic',S_HOME:'/srv/mosaic',NODE,WORK:h.dir}, }); } test('row276 legacy call inventory pins every production bound and the conversation contract',()=>{ const s=read(SCRIPT); assert.equal(s.includes('${AS_USER[@]}'),false); for(const x of LEGACY_CASES)assert.ok(s.includes(`legacy_run ${x.tag} ${x.inner} ${x.outer} `),x.tag); assert.match(s,/legacy_run talk 320 330 .*--tester --wait 300/); assert.match(s,/legacy_display_rc talk/);assert.match(s,/legacy_display_rc precheck/); }); for(const {tag} of LEGACY_CASES)test(`row276 ${tag} legacy inner timeout cleans both sudo models`,async t=>{ for(const mode of ['exec','hop']){ const h=host(t),records=join(h.hc,'legacy-pids'),files=[join(h.hc,'session-pids'),records]; put(join(h.hc,'session-mode'),mode); const file=join(h.dir,'blocked.mjs');put(file,blockingQuerySource(records,'signals')+'\nloadSystem();'); const clock=join(h.dir,'inner-clock');put(clock,'',0o600); const body=legacyBody(instrumentInnerTimer(read(SCRIPT),clock)); const capture=cleanupFixture(t,files),stop=fixtureGuard(t,files,4500,clock); // The outer watchdog includes startup and cleanup; only the supervisor pair // measures the inner budget. Seven seconds also lets the 4.5s guard expose a missing timer. const start=performance.now(),r=legacyCall(h,tag,[NODE,file],{outer:7,body});capture(); assert.equal(r.status,81,r.stdout+r.stderr); assert.equal(r.stderr,`case1-accept: ${tag} inner-timeout\n`); const seconds=readProbeSeconds(read(clock)),wall=(performance.now()-start)/1000; assert.ok(seconds>=0.25&&seconds<1.25,`${tag}/${mode}: inner timer ${seconds}s (wall ${wall}s)`); assert.ok(wall>=seconds,`${mode}: the call contains its timer interval`); t.diagnostic(`${tag}/${mode}: inner ${seconds}s; wall ${wall}s`); assert.deepEqual(await pollFixtureGone(files),[],mode);await stop(); } }); test('row276 legacy streams and display status preserve failures without granting success',t=>{ for(const mode of ['exec','hop'])for(const code of [0,1,7,81,137]){ const h=host(t);put(join(h.hc,'session-mode'),mode); const r=legacyCall(h,'talk',[NODE,'-e',`process.stdout.write('sent retained\\nreply retained\\n');process.stderr.write('original diagnostic\\n');process.exitCode=${code}`],{inner:3,outer:5}); assert.equal(r.status,code===0?0:87,r.stderr); assert.equal(r.stdout,'sent retained\nreply retained\n');assert.equal(r.stderr,'original diagnostic\n'); assert.equal(read(join(h.dir,'legacy-talk.rc')),String(code===0?0:code)+'\n'); } }); test('row276 trailer grammar cannot make supervisor failure pass',t=>{ for(const trailer of ['0','256','999','01','+1','-1','1-no-newline','missing']){ const h=host(t),body=legacyBody().replace('process.stderr.write("\\nMOSAIC_LEGACY_STATUS="+code+"\\n");', trailer==='missing'?'':trailer==='1-no-newline'?'process.stderr.write("\\nMOSAIC_LEGACY_STATUS=1");':`process.stderr.write("\\nMOSAIC_LEGACY_STATUS=${trailer}\\n");`); assert.notEqual(body,legacyBody(),'runner trailer seam matched'); const r=legacyCall(h,'talk',[NODE,'-e','process.exitCode=7'],{body,inner:3,outer:5}); assert.equal(r.status,87,r.stderr);assert.equal(read(join(h.dir,'legacy-talk.rc')),'87\n'); assert.ok(r.stderr.endsWith('case1-accept: talk inner-command\n'),r.stderr); } }); test('row276 earlier forged trailer and appended zero remain failures',t=>{ for(const late of [false,true]){ const h=host(t);let body=legacyBody(); if(late)body=body.replace('process.stderr.write("\\nMOSAIC_LEGACY_STATUS="+code+"\\n");','process.stderr.write("\\nMOSAIC_LEGACY_STATUS="+code+"\\nMOSAIC_LEGACY_STATUS=0\\n");'); const r=legacyCall(h,'talk',[NODE,'-e','process.stderr.write("\\nMOSAIC_LEGACY_STATUS=0\\n");process.exitCode=7'],{body,inner:3,outer:5}); assert.equal(r.status,87,r.stderr);assert.equal(read(join(h.dir,'legacy-talk.rc')),late?'87\n':'7\n'); } }); test('row276 precheck outer bound discards success status and fixture cleans residual',async t=>{ for(const mode of ['exec','hop']){ const h=host(t),files=[join(h.hc,'session-pids')];put(join(h.hc,'session-mode'),mode);put(join(h.hc,'stall-legacy-precheck'),''); const capture=cleanupFixture(t,files),stop=fixtureGuard(t,files,4500); const start=performance.now(),r=legacyCall(h,'precheck',[NODE,'-e',''],{inner:0.5,outer:1});capture();const seconds=(performance.now()-start)/1000; assert.equal(r.status,82,r.stderr);assert.equal(r.stderr,'case1-accept: precheck outer-timeout\n');assert.equal(r.stdout,''); assert.ok(seconds>=1&&seconds<3,`${mode}:${seconds}s`);assert.equal(read(join(h.dir,'legacy-precheck.rc')),'82\n'); killRecordedPids(files[0]);assert.deepEqual(await pollFixtureGone(files),[],'explicit same-uid stalled-supervisor residual cleanup');await stop(); } }); test('row276 case1 capture and legacy tools refuse unsafe system tools',t=>{ for(const legacy of [false,true]){ const h=host(t),statFile=join(h.bin,'stat');edit(statFile,s=>s.replace('case "${@: -1}" in',`case "\${@: -1}" in\n /usr/bin/timeout) echo '0 777';exit 0 ;;`)); const body=legacyBody(); const r=legacy?legacyCall(h,'node-version',[NODE,'--version'],{body}):spawnSync('/bin/bash',['-c',body+'\ntester_capture 0.5 2 128 mosaic /srv/mosaic /usr/bin /usr/bin/true'],{encoding:'utf8',env:{...process.env,PATH:`${h.bin}:${process.env.PATH}`,HC:h.hc,ROOT_DIR:h.root,REAL_NODE:process.execPath,TMPDIR:h.dir}}); assert.equal(r.status,84,r.stdout+r.stderr);if(legacy)assert.equal(r.stderr,'case1-accept: node-version supervisor-tools\n'); } }); test('row276 stderr retention is bounded and keeps the final diagnostic',t=>{ const h=host(t),r=legacyCall(h,'talk',[NODE,'-e',"process.stderr.write('X'.repeat(70000)+'end diagnostic\\n')"],{inner:3,outer:5}); assert.equal(r.status,0,r.stderr);assert.ok(Buffer.byteLength(r.stderr)<=65536);assert.ok(r.stderr.endsWith('end diagnostic\n')); }); test('row276 version and PM checks refuse successful-looking stdout on supervisor failure',t=>{ const source=read(SCRIPT),h=host(t); for(const [name,next,output] of [['check_f6','# The PM check',`${CLAUDE_PIN} (Claude Code)`],['check_f7','check_f8()', 'ok pm run r-0002'],['check_f10','check_f11()',NODE_PIN]]){ const at=source.indexOf(name+'()'),end=source.indexOf(next,at+1);assert.ok(at>=0&&end>at); const code=source.slice(at,end)+'\nfpass(){ echo PASS; }; ffail(){ echo FAIL; }; tester_capture_reason(){ echo inner-command; }; legacy_run(){ printf "%s\n" "$OUTPUT"; return 87; }; '+name; const r=spawnSync('/bin/bash',['-c',code],{encoding:'utf8',env:{...process.env,CLAUDE,CLAUDE_PIN,NODE,NODE_PIN,WORK:h.dir,OUTPUT:output,BUSINESS_FILE:'/fake',COPY:'/fake',BUSINESS:'mosaic-stack'}}); assert.equal(r.status,0,r.stderr);assert.equal(r.stdout,'FAIL\n',name); } }); test('row276 full acceptance keeps all five healthy calls in both sudo models',async t=>{ for(const mode of ['exec','hop']){ const h=host(t),files=[join(h.hc,'session-pids')];put(join(h.hc,'session-mode'),mode); const capture=cleanupFixture(t,files),r=run(h);capture(); assert.equal(r.status,0,r.out+r.err);assert.deepEqual(failed(r),[],mode); assert.deepEqual(await pollFixtureGone(files),[],mode); } }); // mos-1337 / row253 N5: the read must silence failure opening a vanished PID. test('row276 vanished pid stat read returns 3 with empty stderr in both scripts',()=>{ const missingPid='2147483647'; assert.equal(existsSync(`/proc/${missingPid}`),false); for(const script of [SCRIPT,join(REPO,'scripts/case2-unit.sh')]){ const fields=/^stat_fields\(\) \{[\s\S]*?^\}/m.exec(read(script)); assert.ok(fields,'stat_fields exists'); const r=spawnSync('/bin/bash',['-c',fields[0]+'\nstat_fields "$1"','--',missingPid],{encoding:'utf8'}); assert.equal(r.status,3,script); assert.equal(r.stdout,'',script); assert.equal(r.stderr,'',script); } }); // mos-1345: stdout bytes belong to the caller only after bounded supervision. test('row276 legacy stdout snapshot preserves exact bytes on success and command failure',async t=>{ for(const mode of ['exec','hop']){ for(const code of [0,7]){ const h=host(t);put(join(h.hc,'session-mode'),mode); const r=legacyCall(h,'precheck',[NODE,'-e',`process.stdout.write('exact bytes without newline');process.exitCode=${code};`]); assert.equal(r.status,code===0?0:87,r.stderr); assert.equal(r.stdout,'exact bytes without newline'); assert.equal(r.stderr,''); } const h=host(t),files=[join(h.hc,'session-pids')]; put(join(h.hc,'session-mode'),mode);put(join(h.hc,'stall-legacy-precheck'),''); put(join(h.hc,'stall-output'),'must not be published'); const capture=cleanupFixture(t,files),stop=fixtureGuard(t,files,4500); const r=legacyCall(h,'precheck',[NODE,'-e',''],{inner:0.5,outer:1});capture(); assert.equal(r.status,82,r.stderr);assert.equal(r.stdout,''); assert.equal(r.stderr,'case1-accept: precheck outer-timeout\n'); killRecordedPids(files[0]);assert.deepEqual(await pollFixtureGone(files),[],'explicit R3 residual cleanup');await stop(); } });