webui: four refusal cases in the Console service tests (#1592)

Row 98, the row 77 follow-up. Researcher's build (agents/researcher/work/queue-98/), approved by Filbert
in round 1 on manifest 352a3034 (comment 28110). Tests only: three new mv and rename cases in
pinned-copy.test.mjs beside the fixture repo they need, and added assertions in service.test.mjs.
Sage's gate rerun on 47a8190d: all 14 package node suites and all 9 scripts/test-*.sh green, webui 107 pass.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-10-13 09:32:45 -05:00
co-authored by Claude Opus 5.5
parent 097dec3314
commit bb45f75ed2
2 changed files with 71 additions and 2 deletions
+24 -2
View File
@@ -71,19 +71,22 @@ const BUS_UNITS = '[email protected] loaded active running Mosaic bus host
// to stderr. The bus calls install makes are answered apart: `busUnits` for
// the mosaic-bus@ list-units, and `bus` for show, by default a bus started
// from the run's own copy ($HOME, as run() sets it). `busFails` makes both
// bus calls fail.
function standIn(dir, lines = '', { listFails = false, bus = null, busUnits = BUS_UNITS, busFails = false } = {}) {
// bus calls fail. `busOther` answers show for [email protected]
// apart from `bus`, so a second loaded unit can differ from the first.
function standIn(dir, lines = '', { listFails = false, bus = null, busUnits = BUS_UNITS, busFails = false, busOther = null } = {}) {
const bin = join(dir, 'bin');
mkdirSync(bin);
writeFileSync(join(dir, 'list-units.txt'), lines);
writeFileSync(join(dir, 'bus-units.txt'), busUnits);
if (bus !== null) writeFileSync(join(dir, 'bus-show.txt'), bus);
if (busOther !== null) writeFileSync(join(dir, 'bus-show-other.txt'), busOther);
const fail = 'echo "Failed to connect to bus" >&2; exit 1';
const show = bus !== null ? `cat "${dir}/bus-show.txt"` : `r="$HOME/.local/share/mosaic-console/${COPY_ID}"; printf '%s' "${busShow('$r')}"`;
writeFileSync(join(bin, 'systemctl'), `#!/bin/sh
echo "$*" >> "${dir}/calls.txt"
case "$*" in
*list-units*mosaic-bus@*) ${busFails ? fail : `cat "${dir}/bus-units.txt"`} ;;
*show*[email protected]*) ${busFails ? fail : busOther !== null ? `cat "${dir}/bus-show-other.txt"` : show} ;;
*show*mosaic-bus@*) ${busFails ? fail : show} ;;
*list-units*) ${listFails ? fail : `cat "${dir}/list-units.txt"`} ;;
*is-enabled*) echo enabled ;;
@@ -538,10 +541,21 @@ test('install refuses unless the bus unit runs from the same copy, naming both p
assert.equal((await install(s.bin)).status, 0);
assert.match(readFileSync(join(s.d, 'calls.txt'), 'utf8'), /show mosaic-bus@other\.service -p LoadState -p ExecStart/);
rmSync(unitDir, { recursive: true });
// The second loaded unit is off the copy: refused, naming the second unit and its path.
const two = `${BUS_UNITS}[email protected] loaded active running Mosaic bus host (other)\n`;
s = sys({ busUnits: two, bus: busShow(copy), busOther: busShow(REPO) });
refused(await install(s.bin), `[email protected] runs from ${REPO}/scripts/mosaic, not the copy ${copy}; the bus accepts only its own human-cli.mjs, so every Console bus call would fail human-required until the bus runs from the same copy`);
assert.match(readFileSync(join(s.d, 'calls.txt'), 'utf8'), /show mosaic-bus@acme\.service -p LoadState -p ExecStart\n.*show mosaic-bus@other\.service -p LoadState -p ExecStart/s);
// No bus unit installed for the business: refused.
s = sys({ bus: 'LoadState=not-found\nExecStart=\n' });
refused(await install(s.bin, ['--business', 'acme']), `no bus unit [email protected] is installed (LoadState not-found); the Console on the copy ${copy} needs its bus on that copy`);
// Only loaded counts: a unit systemd shows at any other LoadState is not the bus, even with an
// ExecStart on the copy.
for (const state of ['bad-setting', 'error', 'masked']) {
s = sys({ bus: busShow(copy).replace('LoadState=loaded', `LoadState=${state}`) });
refused(await install(s.bin, ['--business', 'acme']), `no bus unit [email protected] is installed (LoadState ${state}); the Console on the copy ${copy} needs its bus on that copy`);
}
// No --business and no mosaic-bus@ unit loaded: refused.
s = sys({ busUnits: '' });
refused(await install(s.bin), `no mosaic-bus@ unit is loaded, and the Console on the copy ${copy} needs its bus on that copy; name the business with --business ID`);
@@ -644,6 +658,14 @@ test('status names the copy and whether refactor has moved past it, and says whe
r = await run(dir, ['status', '--dir', unitDir], bin);
assert.match(r.stdout, new RegExp(`^copy: none; the unit runs from ${esc(REPO)}$`, 'm'));
assert.ok(!/^refactor:/m.test(r.stdout));
// Only a whole 40-hex last part is a copy: 40 hex plus a character, or 41 hex, is not.
for (const last of [`${COPY_ID}x`, `x${COPY_ID}`, `${COPY_ID}0`]) {
unit(join(dir, 'copies', last));
r = await run(dir, ['status', '--dir', unitDir], bin);
assert.equal(r.status, 0, r.stderr);
assert.match(r.stdout, new RegExp(`^copy: none; the unit runs from ${esc(join(dir, 'copies', last))}$`, 'm'), last);
assert.ok(!/^refactor:/m.test(r.stdout), last);
}
// status reads; it calls nothing that changes the unit.
assert.deepEqual(readFileSync(join(dir, readdirSync(dir).find((d) => d.startsWith('si-')), 'calls.txt'), 'utf8').split('\n').filter(Boolean).filter((c) => !/^--user (is-enabled|is-active|show) mosaic-webui\.service( |$)/.test(c)), []);
});