row 203 FED R2: stack-release probe reads federation; a refusal case per federation check

stack-release config_checks refuses a target whose loader refuses a key the
config holds; it looked only for console, so a federation-only config passed
to a pre-203 copy. The probe now reads console or federation. The fixture's
B loader replace follows the new rejectUnknownKeys list, which the federation
key changed.

Adds a test for each federation refusal in test-config.sh (six uncovered,
plus trailing slash and duplicate peer id), and one stack-release test for
the target-loader refusal. Mutants M7-M14 in BUILD.md. Not run yet.
This commit is contained in:
jason.woltje committed 2026-10-22 17:57:25 -05:00
1 parent 93a491d732
commit 284d55cf2c
5 files changed
+144 -18

No files matched your search

+3 -2
View File
@@ -295,9 +295,10 @@ export const KINDS_OLD=KINDS_NEW.replace('\n harness: Object.freeze({','\n "ha
assert.notEqual(KINDS_OLD,KINDS_NEW);
// Row 200 (#1698): C1 and C take --sso and have the row 192 loader and checkConsole; C's checker
// refuses RS256, a stand-in for a target whose rules differ from the repository's. B has the loader
// from before row 192, which refuses a `console` key. The other copies have no loader.
// from before row 192, which refuses a `console` key. The other copies have no loader. Row 203: B's
// loader also refuses a `federation` key, as a pre-203 loader does (its list has no federation).
const LOADER=readFileSync(join(repo,'scripts','mosaic-config.mjs'),'utf8'),SSO_CONFIG=readFileSync(join(repo,'packages','webui','src','sso-config.mjs'),'utf8');
const LOADER_OLD=LOADER.replace('["configVersion", "environment", "dataRoot", "execution", "console"]','["configVersion", "environment", "dataRoot", "execution"]');
const LOADER_OLD=LOADER.replace('["configVersion", "environment", "dataRoot", "execution", "console", "federation"]','["configVersion", "environment", "dataRoot", "execution"]');
const SSO_CONFIG_C=SSO_CONFIG.replace("'ES256', 'RS256',","'ES256',");
assert.notEqual(LOADER_OLD,LOADER);assert.notEqual(SSO_CONFIG_C,SSO_CONFIG);
const ssoFiles=(id)=>id===B?[['scripts/mosaic-config.mjs',LOADER_OLD]]:[C1,C].includes(id)?[['scripts/mosaic-config.mjs',LOADER],['packages/webui/src/sso-config.mjs',id===C?SSO_CONFIG_C:SSO_CONFIG]]:[];
+14 -1
View File
@@ -1468,7 +1468,7 @@ const SHOW=`show-${CON}.txt`;
const setOf=(e,act)=>join(e.state,'stack-rollback',act);
const arrivalSet=(e,to)=>setOf(e,logLines(e).findLast((l)=>l.result==='ok'&&l.to===to&&l.from!==to).activation);
const ROLLBACK_PLAN=(set)=>`sso: dropped; ${B}'s Console does not support --sso, so the rollback takes the Console flags from ${set}/${SHOW}, with --tester-port as the pointer has it`;
const KEY_MSG=(e,to,op,why)=>`${e.cfg} holds a console key, and ${to}'s loader refuses it (${why}); remove the key first (restore the config.json backup from the window's step 1), then run the ${op} again`;
const KEY_MSG=(e,to,op,why)=>`${e.cfg} holds a console or federation key, and ${to}'s loader refuses it (${why}); remove the key first (restore the config.json backup from the window's step 1), then run the ${op} again`;
const RB_MSG=(why)=>`${B}'s Console does not support --sso, and the Console flags it ran with cannot be read: ${why}`;
// Rewrites a file in a rollback set (0700, files kept by cp -p) and, unless sums is false, its SHA256SUMS line.
function setEdit(set,name,from,to,sums=true){
@@ -1582,6 +1582,19 @@ test('T57 row 200: activate --sso, its refusals before any stop, and the rollbac
r=await prun(e,'rollback','acme');assert.equal(r.code,0,r.out+r.err);assert.equal(pointer(e).copy,B);
await noLeak(e);
});
await t.test('row 203: a config whose federation key the target loader refuses stops an activate or a rollback before any stop, naming the first step',async(t)=>{
const e=await mk(t);await seedPreview(e);
let r=await prun(e,'activate',C1,'acme');assert.equal(r.code,0,r.out+r.err);
// B's loader has no federation key in its list, as a pre-203 loader has none: it refuses the key.
const setFed=(fed)=>{const c=JSON.parse(readFileSync(e.cfg,'utf8'));if(fed===undefined)delete c.federation;else c.federation=fed;writeFileSync(e.cfg,JSON.stringify(c))};
setFed({self:'hub',peers:[{id:'factory',origin:'https://mosaic.woltje.com',label:'Software factory'}]});
const why='mosaic-config: unsupported configuration key: "federation"';
await refused(e,['activate',B,'acme'],'config-console-key',KEY_MSG(e,B,'activate',why));
await refused(e,['rollback','acme'],'config-console-key',KEY_MSG(e,B,'rollback',why));
setFed(undefined);
r=await prun(e,'rollback','acme');assert.equal(r.code,0,r.out+r.err);assert.equal(pointer(e).copy,B);
await noLeak(e);
});
await t.test('item 3: a rollback from --sso to a Console without it takes the flags from the set of the activation onto the copy, past a same-copy re-pin (sage-1389)',async(t)=>{
const e=await mk(t),base=await seedPreview(e,undefined,['--send','--tester-port','7333']);await ssoConfig(e);
let r=await prun(e,'activate',C1,'acme');assert.equal(r.code,0,r.out+r.err);