scripts: bus unit drop-in guard covers inherited globs; script usage and copy wrapper comments (row 108, #1602)

Candidate manifest 19ef7133db592787c24fa473357687a5741ccd7823627b970624c930a7611dbc
from Rocko's round 1 packet (a6e4fe747), on BASE 234121b30. No
manifest path changed between BASE and the landing target. The
bus-service.sh drop-in guard now refuses inherited mosaic-.service.d
and service.d drop-ins, the header lists every flag, the unreachable
install-show fakes are gone, and the stack-copy.sh wrapper carries its
copy and lease comments after the line-2 marker. Filbert approved in
28489 with no findings. Sage reran the full gate at the landing target
with the candidate applied.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-10-14 15:22:40 -05:00
co-authored by Claude Opus 5.5
parent abe5903e58
commit 0d030011af
6 changed files with 63 additions and 14 deletions
+15 -1
View File
@@ -470,11 +470,25 @@ mosaic-stack/copies/<full id>. bus-service.sh render/install take --copy
ID and --pm alongside the existing --claude pin. Without --copy render
keeps today's checkout unit. A PM refusal exits 3 and the unit does not
retry it. Install refuses every busy instance (also --no-reload), failed
state reads and drop-ins overriding ExecStart or WorkingDirectory.
state reads and drop-ins overriding ExecStart or WorkingDirectory, including
inherited mosaic-.service.d/ and service.d/ in every unit lookup directory.
Status reads effective systemd properties, reports the tree/copy, PM flag,
refactor drift and drop-in files; it changes nothing. The temporary PM
ExecStart drop-in must be removed by Mos before installing the pinned unit.
The wrapper keeps the Q81 marker on line 2 and the final copy exec on the
last line. Comments name the copy root and explain that the Q81 lease probe
still answers at mosaic-old.
Copy npm ci may warn that @google/genai's preinstall, esbuild's postinstall
and protobufjs's postinstall are blocked. This is expected for the current
copy paths: Mosaic launches Pi's published bundled CLI, whose runtime does
not load those installed package entrypoints. @google/genai's preinstall
only echoes; esbuild's script installs/checks its build binary; protobufjs's
script only warns about dependency version schemes. The copy runs the
already published bundle and does not build it. No allowScripts change is
needed for these paths; adding a runtime loader requires a fresh audit.
The one update and rollback plan is [TOOLS.md, Pinned stack update](../../docs/TOOLS.md#pinned-stack-update).
Each live switch/unit change/stop/start requires Mos's go; agents build
and test fixtures only. Restarting the bus ends its sessions, so no PM
+2 -2
View File
@@ -828,7 +828,7 @@ test("bus-service.sh renders the unit and installs it into a given directory", (
// A user unit cannot order on a system target (Darkwing F3).
assert.doesNotMatch(render.stdout, /network-online/);
const fakeBin=join(dir,"bin");mkdirSync(fakeBin);
writeFileSync(join(fakeBin,"systemctl"),"#!/bin/sh\ncase \"$*\" in *show*) echo DropInPaths=;; esac\nexit 0\n");chmodSync(join(fakeBin,"systemctl"),0o755);
writeFileSync(join(fakeBin,"systemctl"),"#!/bin/sh\ncase \"$*\" in *list-units*) exit 0;; *)exit 99;; esac\n");chmodSync(join(fakeBin,"systemctl"),0o755);
writeFileSync(join(fakeBin,"systemd-analyze"),`#!/bin/sh\nprintf '%s\\n' '${dir}/unit-search'\n`);chmodSync(join(fakeBin,"systemd-analyze"),0o755);
const unitEnv={...process.env,PATH:`${fakeBin}:${process.env.PATH}`};
const first = spawnSync(script, ["install", "--dir", dir, "--no-reload"], { encoding: "utf8",env:unitEnv });
@@ -852,7 +852,7 @@ test("bus-service.sh pins the claude binary, refuses one the unit can't carry, a
return p;
};
mkdirSync(join(dir, "bin"));
writeFileSync(join(dir,"bin","systemctl"),'#!/bin/sh\ncase "$*" in *show*) echo DropInPaths=;; esac\nexit 0\n');chmodSync(join(dir,"bin","systemctl"),0o755);
writeFileSync(join(dir,"bin","systemctl"),'#!/bin/sh\ncase "$*" in *list-units*) exit 0;; *)exit 99;; esac\n');chmodSync(join(dir,"bin","systemctl"),0o755);
writeFileSync(join(dir,"bin","systemd-analyze"),`#!/bin/sh\nprintf '%s\\n' '${dir}/unit-search'\n`);chmodSync(join(dir,"bin","systemd-analyze"),0o755);
const onPath = stand(join(dir, "bin", "claude"));
const named = stand(join(dir, "claude-named"));
+38 -5
View File
@@ -46,6 +46,11 @@ test('wrapper preserves Q81 lease and marker, rejects foreign/symlink; check use
const lease=`[ "\${1:-}" = __lease-capability ] && exec "${s.bin}/mosaic-old" "$@"`;
writeFileSync(wrapper,`#!/usr/bin/env bash\n${marker}\n${lease}\nexec "/old/scripts/mosaic" "$@"\n`);
assert.equal(s.run('stack-copy.sh',['wrapper',s.id,'--copies',s.copies,'--bin',s.bin]).status,0);
const lines=readFileSync(wrapper,'utf8').trimEnd().split('\n');
assert.equal(lines[1],marker);
assert.equal(lines[2],`# CLI runs from pinned copy: ${join(s.copies,s.id)}`);
assert.equal(lines[3],'# The Q81 lease probe still answers at mosaic-old.');
assert.equal(lines.at(-1),`exec "${join(s.copies,s.id)}/scripts/mosaic" "$@"`);
assert.match(readFileSync(wrapper,'utf8'),new RegExp(s.id));assert.ok(readFileSync(wrapper,'utf8').includes(lease));
const old=join(s.bin,'mosaic-old');writeFileSync(old,'#!/bin/sh\nprintf \"legacy:%s\\n\" \"$1\"\n');chmodSync(old,0o755);
assert.equal(spawnSync(wrapper,['__lease-capability'],{env:s.env,encoding:'utf8'}).stdout,'legacy:__lease-capability\n');
@@ -54,7 +59,11 @@ test('wrapper preserves Q81 lease and marker, rejects foreign/symlink; check use
s.fake(`echo 'LoadState=loaded'; echo 'WorkingDirectory=${copy}';case \"$*\" in *mosaic-bus*)echo 'ExecStart={ path=/other/scripts/mosaic ; argv[]=/other/scripts/mosaic bus start demo ; }';; *)echo 'ExecStart={ path=/usr/bin/node ; argv[]=/usr/bin/node ${copy}/packages/webui/src/cli.mjs serve ; }';;esac\n`);
assert.equal(s.run('stack-copy.sh',['check','--copies',s.copies,'--bin',s.bin]).status,1,'effective ExecStart mismatch');
s.fake(`echo 'LoadState=loaded'; echo 'WorkingDirectory=/other';\n`);assert.equal(s.run('stack-copy.sh',['check','--copies',s.copies,'--bin',s.bin]).status,1);
const foreign=`#!/usr/bin/env bash\n# foreign wrapper\n${lease}\nexec \"/old/scripts/mosaic\" \"$@\"\n`;writeFileSync(wrapper,foreign);assert.notEqual(s.run('stack-copy.sh',['wrapper',s.id,'--copies',s.copies,'--bin',s.bin]).status,0);assert.equal(readFileSync(wrapper,'utf8'),foreign);
const foreign=`#!/usr/bin/env bash\n# foreign wrapper\n${lease}\nexec \"${copy}/scripts/mosaic\" \"$@\"\n`;writeFileSync(wrapper,foreign);
// Restore matching effective roots: only the foreign marker refuses check.
s.fake(`echo 'LoadState=loaded';echo 'WorkingDirectory=${copy}';case "$*" in *mosaic-bus*) echo 'ExecStart={ path=${copy}/scripts/mosaic ; argv[]=${copy}/scripts/mosaic bus start demo ; }';; *)echo 'ExecStart={ path=/usr/bin/node ; argv[]=/usr/bin/node ${copy}/packages/webui/src/cli.mjs serve ; }';;esac\n`);
assert.equal(s.run('stack-copy.sh',['check','--copies',s.copies,'--bin',s.bin]).status,1);
assert.notEqual(s.run('stack-copy.sh',['wrapper',s.id,'--copies',s.copies,'--bin',s.bin]).status,0);assert.equal(readFileSync(wrapper,'utf8'),foreign);
const backing=join(s.bin,'backing');writeFileSync(backing,`#!/usr/bin/env bash\n${marker}\n${lease}\nexec \"/old/scripts/mosaic\" \"$@\"\n`);unlinkSync(wrapper);symlinkSync(backing,wrapper);assert.notEqual(s.run('stack-copy.sh',['wrapper',s.id,'--copies',s.copies,'--bin',s.bin]).status,0);
});
test('bus unit copy/pm pins, install refuses all busy states and failed reads, drop-in refusal',t=>{
@@ -65,7 +74,7 @@ test('bus unit copy/pm pins, install refuses all busy states and failed reads, d
for(const state of ['active','activating','deactivating','reloading']){s.fake(`echo '[email protected] loaded ${state} running fixture';\n`);const r=s.run('bus-service.sh',['install',...args,'--dir',units,'--no-reload']);assert.notEqual(r.status,0,state);assert.ok(!existsSync(units));}
s.fake('exit 1\n');assert.notEqual(s.run('bus-service.sh',['install',...args,'--dir',units,'--no-reload']).status,0);assert.ok(!existsSync(units));
const dropdir=join(s.search,'[email protected]');mkdirSync(dropdir);const drop=join(dropdir,'pm.conf');writeFileSync(drop,'[Service]\nExecStart=elsewhere\n');
s.fake(`case "$*" in *list-units*) echo '[email protected] loaded inactive dead fixture';; *show*) echo 'LoadState=loaded';echo 'DropInPaths=${drop}';; esac\n`);
s.fake(`case "$*" in *list-units*) echo '[email protected] loaded inactive dead fixture';; *)exit 99;; esac\n`);
const refused=s.run('bus-service.sh',['install',...args,'--dir',units,'--no-reload']);assert.notEqual(refused.status,0);assert.ok(refused.stderr.includes(drop));assert.ok(!existsSync(units));
writeFileSync(drop,'[Service]\nEnvironment=SAFE=1\n');assert.equal(s.run('bus-service.sh',['install',...args,'--dir',units,'--no-reload']).status,0);
});
@@ -151,7 +160,7 @@ test('drop-ins in either override field and malformed metadata refuse; uninstall
const s=setup(t),units=join(s.root,'units'),dropdir=join(s.search,'[email protected]');mkdirSync(dropdir);const drop=join(dropdir,'override.conf');
for(const field of ['ExecStart','WorkingDirectory']){
writeFileSync(drop,`[Service]\n${field}=override\n`);
s.fake(`case "$*" in *list-units*) echo '[email protected] loaded inactive dead fixture';; *[email protected]*) echo 'DropInPaths=${drop}';; *)echo DropInPaths=;;esac\n`);
s.fake(`case "$*" in *list-units*) echo '[email protected] loaded inactive dead fixture';; *)exit 99;;esac\n`);
const r=s.run('bus-service.sh',['install','--dir',units,'--no-reload']);assert.notEqual(r.status,0);assert.ok(r.stderr.includes(drop));assert.ok(!existsSync(units));
}
s.fake('exit 0\n');s.analyze('exit 0\n');const unknown=s.run('bus-service.sh',['install','--dir',units,'--no-reload']);assert.notEqual(unknown.status,0);assert.match(unknown.stderr,/unknown/);
@@ -162,9 +171,11 @@ test('drop-ins in either override field and malformed metadata refuse; uninstall
test('install never shows a template name on systemd 261; template drop-ins still refuse',t=>{
const s=setup(t),units=join(s.root,'units'),calls=join(s.root,'systemctl-calls');
s.fake(`echo "$*" >> '${calls}'\ncase "$*" in *show*[email protected]*) echo 'neither a valid invocation ID nor unit name' >&2; exit 1;; *list-units*) echo '[email protected] loaded inactive dead fixture';; *show*)echo DropInPaths=;; esac\n`);
s.fake(`echo "$*" >> '${calls}'\ncase "$*" in *show*[email protected]*) echo 'neither a valid invocation ID nor unit name' >&2; exit 1;; *list-units*) echo '[email protected] loaded inactive dead fixture';; *)exit 99;; esac\n`);
const result=s.run('bus-service.sh',['install','--dir',units,'--no-reload']);assert.equal(result.status,0,result.stderr);
assert.doesNotMatch(readFileSync(calls,'utf8'),/show mosaic-bus@\.service/);
// This rejection arm is deliberately exercised; it is not a dead show reply.
assert.equal(spawnSync(join(s.bin,'systemctl'),['--user','show','[email protected]'],{env:s.env}).status,1);
const dropdir=join(s.search,'[email protected]');mkdirSync(dropdir);const file=join(dropdir,'pm.conf');writeFileSync(file,'[Service]\nExecStart=override\n');
const before=readFileSync(join(units,'[email protected]'),'utf8');
const denied=s.run('bus-service.sh',['install','--dir',units,'--no-reload']);assert.notEqual(denied.status,0);assert.ok(denied.stderr.includes(file));assert.equal(readFileSync(join(units,'[email protected]'),'utf8'),before);
@@ -173,7 +184,29 @@ test('unlisted instance drop-in is found in another unit lookup directory; path
const s=setup(t),units=join(s.root,'units'),second=join(s.root,'second-search');mkdirSync(second);
const dropdir=join(second,'[email protected]');mkdirSync(dropdir);const file=join(dropdir,'cwd.conf');writeFileSync(file,'[Service]\nWorkingDirectory=/other\n');
s.analyze(`printf '%s\\n' '${s.search}' '${second}'\n`);
s.fake("case \"$*\" in *list-units*) echo '[email protected] loaded inactive dead fixture';; *show*)echo DropInPaths=;; esac\n");
s.fake("case \"$*\" in *list-units*) echo '[email protected] loaded inactive dead fixture';; *)exit 99;; esac\n");
const denied=s.run('bus-service.sh',['install','--dir',units,'--no-reload']);assert.notEqual(denied.status,0);assert.ok(denied.stderr.includes(file));assert.ok(!existsSync(units));
s.analyze('exit 1\n');const failed=s.run('bus-service.sh',['install','--dir',units,'--no-reload']);assert.notEqual(failed.status,0);assert.match(failed.stderr,/unit-paths failed/);assert.ok(!existsSync(units));
});
// Row 108: inherited drop-ins apply even without a loaded bus instance.
for(const name of ['mosaic-.service.d','service.d'])test(`inherited ${name} override refuses without changing the unit`,t=>{
const s=setup(t),units=join(s.root,'units');mkdirSync(units);
const target=join(units,'[email protected]');writeFileSync(target,'previous unit bytes');
s.fake('exit 0\n');
const dropdir=join(s.search,name);mkdirSync(dropdir);const file=join(dropdir,'override.conf');
for(const field of ['WorkingDirectory','ExecStart']){
writeFileSync(file,`[Service]\n${field}=/other\n`);
const denied=s.run('bus-service.sh',['install','--dir',units,'--no-reload']);
assert.equal(denied.status,1,denied.stderr);assert.ok(denied.stderr.includes(file));assert.equal(readFileSync(target,'utf8'),'previous unit bytes');
}
writeFileSync(file,'[Service]\nEnvironment=SAFE=1\n');
const allowed=s.run('bus-service.sh',['install','--dir',units,'--no-reload']);assert.equal(allowed.status,0,allowed.stderr);
});
test('inherited drop-in unreadable directory or file refuses before writing',t=>{
const s=setup(t),units=join(s.root,'units');mkdirSync(units);const target=join(units,'[email protected]');writeFileSync(target,'previous unit bytes');s.fake('exit 0\n');
const dropdir=join(s.search,'service.d');symlinkSync(join(s.root,'absent-dir'),dropdir);
const dir=s.run('bus-service.sh',['install','--dir',units,'--no-reload']);assert.equal(dir.status,1);assert.ok(dir.stderr.includes(dropdir));assert.equal(readFileSync(target,'utf8'),'previous unit bytes');
unlinkSync(dropdir);mkdirSync(dropdir);const file=join(dropdir,'broken.conf');symlinkSync(join(s.root,'absent-file'),file);
const broken=s.run('bus-service.sh',['install','--dir',units,'--no-reload']);assert.equal(broken.status,1);assert.ok(broken.stderr.includes(file));assert.equal(readFileSync(target,'utf8'),'previous unit bytes');
});