gander: guard unique mutation targets and separate SSO ordering mutant
This commit is contained in:
1 parent
84aea3063c
commit
f8a59e6aad
14 files changed
+1108
-12
No files matched your search
@@ -104,3 +104,4 @@ changes are planned before the batch. M1-M29 remain prepared and unexecuted.
|
|||||||
2026-10-21 r2 stop 2: base killer invocations 14/0 under 30 seconds each; M23-M27 killed, M28 survived due rebase making its generic mutation target the earlier SSO insertion. No M29 or golden suite run. Every restored hash and Git status clean; leftover process sweep count 0. Slot returned to Sage in gander-0035. Full per-step counts, base/mutant times and kill table in r2/run2/. Awaiting ruling before any fix or rerun; third stop goes to Mos.
|
2026-10-21 r2 stop 2: base killer invocations 14/0 under 30 seconds each; M23-M27 killed, M28 survived due rebase making its generic mutation target the earlier SSO insertion. No M29 or golden suite run. Every restored hash and Git status clean; leftover process sweep count 0. Slot returned to Sage in gander-0035. Full per-step counts, base/mutant times and kill table in r2/run2/. Awaiting ruling before any fix or rerun; third stop goes to Mos.
|
||||||
|
|
||||||
2026-10-21 sage-2072 product test: added the merge-scoped SSO/socket conversion case without --send, asserting pointer argv order, rendered unit argv order, status agreement and no secret-file reads. Removing socket from sso_for_target is its planned RED case (M28b). Focused RED/GREEN remains pending the busy gate: Herb's suite was active at the preflight, so no test started. Runtime code unchanged. Mos mos-1197 owner-subject ruling recorded in queue-252/BUILD-NOTES.md.
|
2026-10-21 sage-2072 product test: added the merge-scoped SSO/socket conversion case without --send, asserting pointer argv order, rendered unit argv order, status agreement and no secret-file reads. Removing socket from sso_for_target is its planned RED case (M28b). Focused RED/GREEN remains pending the busy gate: Herb's suite was active at the preflight, so no test started. Runtime code unchanged. Mos mos-1197 owner-subject ruling recorded in queue-252/BUILD-NOTES.md.
|
||||||
|
2026-10-21 sage-2072/2077 driver: unique string-target guard preflights every definition before any tests and before creating scratch state; M28 names without_proof, M28b names kept, M5 names the parse catch, M25 names append flags, M29 uses the unique full line. Static audit accepts all 30 definitions; zero/duplicate targets refuse. Against 64539c96b, M5 old/narrowed bytes match; M25 differs and joins the next batch. No mutation tests ran in this static check.
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
// Synchronous mutation preparation only. No file is written until every replacement is unique.
|
||||||
|
export function guardMutation(input, mutate, { auditOnly = false } = {}) {
|
||||||
|
const targets = [];
|
||||||
|
class UniqueText extends String {
|
||||||
|
replace(target, replacement) { return this.applyReplacement('replace', target, replacement); }
|
||||||
|
replaceAll(target, replacement) { return this.applyReplacement('replaceAll', target, replacement); }
|
||||||
|
applyReplacement(method, target, replacement) {
|
||||||
|
if (typeof target !== 'string' || !target) throw Error('mutation target must be a nonempty string');
|
||||||
|
const source = String(this), count = source.split(target).length - 1;
|
||||||
|
targets.push({ method, target, count });
|
||||||
|
if (count !== 1 && !auditOnly) throw Error(`mutation target occurs ${count} times, expected exactly once: ${target}`);
|
||||||
|
return new UniqueText(String.prototype[method].call(source, target, replacement));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { text: String(mutate(new UniqueText(input))), targets };
|
||||||
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { guardMutation } from './mutant-guard.mjs';
|
||||||
// Authorized batch only. Mutate isolated scratch copies, never the candidate or installed tree.
|
// Authorized batch only. Mutate isolated scratch copies, never the candidate or installed tree.
|
||||||
import {mkdtempSync,cpSync,readFileSync,writeFileSync,rmSync,symlinkSync,existsSync,mkdirSync} from 'node:fs';
|
import {mkdtempSync,cpSync,readFileSync,writeFileSync,rmSync,symlinkSync,existsSync,mkdirSync} from 'node:fs';
|
||||||
import {tmpdir} from 'node:os';import {join,resolve} from 'node:path';
|
import {tmpdir} from 'node:os';import {join,resolve} from 'node:path';
|
||||||
@@ -5,7 +6,6 @@ import {spawnSync,execFileSync} from 'node:child_process';import {createHash} fr
|
|||||||
import {fileURLToPath} from 'node:url';
|
import {fileURLToPath} from 'node:url';
|
||||||
const root=fileURLToPath(new URL('../../../../',import.meta.url));
|
const root=fileURLToPath(new URL('../../../../',import.meta.url));
|
||||||
const out=join(root,'agents/gander/work/queue-196/evidence/mutants');mkdirSync(out,{recursive:true});
|
const out=join(root,'agents/gander/work/queue-196/evidence/mutants');mkdirSync(out,{recursive:true});
|
||||||
const scratch=mkdtempSync(join(tmpdir(),'g196-mut-'));
|
|
||||||
const p='packages/bus/src/principal.mjs',h='packages/bus/src/human.mjs',w='packages/webui/src/tester-socket.mjs',s='packages/bus/src/server.mjs',peer='packages/bus/src/peercred.mjs';
|
const p='packages/bus/src/principal.mjs',h='packages/bus/src/human.mjs',w='packages/webui/src/tester-socket.mjs',s='packages/bus/src/server.mjs',peer='packages/bus/src/peercred.mjs';
|
||||||
const principal='packages/bus/tests/principal.test.mjs',socket='packages/webui/tests/tester-socket.test.mjs',transport='packages/bus/tests/peer-transport.test.mjs',interpreter='packages/bus/tests/interpreter.test.mjs';
|
const principal='packages/bus/tests/principal.test.mjs',socket='packages/webui/tests/tester-socket.test.mjs',transport='packages/bus/tests/peer-transport.test.mjs',interpreter='packages/bus/tests/interpreter.test.mjs';
|
||||||
const release=['--test-name-pattern=row196 explicit socket','packages/cli/tests/stack-release.test.mjs'];
|
const release=['--test-name-pattern=row196 explicit socket','packages/cli/tests/stack-release.test.mjs'];
|
||||||
@@ -14,7 +14,7 @@ const specs=[
|
|||||||
['M2',w,'socket mode widened',socket,t=>t.replace('chmodSync(temporary, 0o600)','chmodSync(temporary, 0o666)')],
|
['M2',w,'socket mode widened',socket,t=>t.replace('chmodSync(temporary, 0o600)','chmodSync(temporary, 0o666)')],
|
||||||
['M3','packages/webui/src/serve.mjs','sign-in accepted on tester',socket,t=>t.replace("if (tester && (Object.hasOwn(req.headers, 'authorization')", "if (false && (Object.hasOwn(req.headers, 'authorization')")],
|
['M3','packages/webui/src/serve.mjs','sign-in accepted on tester',socket,t=>t.replace("if (tester && (Object.hasOwn(req.headers, 'authorization')", "if (false && (Object.hasOwn(req.headers, 'authorization')")],
|
||||||
['M4',p,'copied PID accepted',principal,t=>t.replace('peer.pid !== proof.pid','false')],
|
['M4',p,'copied PID accepted',principal,t=>t.replace('peer.pid !== proof.pid','false')],
|
||||||
['M5',peer,'helper parse error ignored','packages/bus/tests/peercred.test.mjs',t=>t.replace('} catch { finish(true); }','} catch { finish(false, {pid:2,uid:0,gid:0}); }')],
|
['M5',peer,'helper parse error ignored','packages/bus/tests/peercred.test.mjs',t=>t.replace('finish(false, Object.freeze(p));\n } catch { finish(true); }','finish(false, Object.freeze(p));\n } catch { finish(false, {pid:2,uid:0,gid:0}); }')],
|
||||||
['M6',p,'foreign uid accepted',principal,t=>t.replace('peer.uid !== process.getuid()','false')],
|
['M6',p,'foreign uid accepted',principal,t=>t.replace('peer.uid !== process.getuid()','false')],
|
||||||
['M7',w,'unsafe parent accepted',socket,t=>t.replace('(dir.mode & 0o077)','false')],
|
['M7',w,'unsafe parent accepted',socket,t=>t.replace('(dir.mode & 0o077)','false')],
|
||||||
['M8',h,'agent environment walk skipped',principal,t=>t.replace('current.env !== null && MARKERS.some','false && MARKERS.some')],
|
['M8',h,'agent environment walk skipped',principal,t=>t.replace('current.env !== null && MARKERS.some','false && MARKERS.some')],
|
||||||
@@ -34,19 +34,25 @@ const specs=[
|
|||||||
['M22',s,'cap requests invoke helper',transport,t=>t.replace(' if (kind) {',' if (r.cap) await peers.read(socket);\n if (kind) {')],
|
['M22',s,'cap requests invoke helper',transport,t=>t.replace(' if (kind) {',' if (r.cap) await peers.read(socket);\n if (kind) {')],
|
||||||
['M23','packages/bus/src/interpreter.mjs','restart retains stale identity',interpreter,t=>t.replace('export function recordInterpreterStart(directory, record) {','export function recordInterpreterStart(directory, record) {\n try { readFileSync(join(directory,"peercred-starts.jsonl")); return; } catch {}')],
|
['M23','packages/bus/src/interpreter.mjs','restart retains stale identity',interpreter,t=>t.replace('export function recordInterpreterStart(directory, record) {','export function recordInterpreterStart(directory, record) {\n try { readFileSync(join(directory,"peercred-starts.jsonl")); return; } catch {}')],
|
||||||
['M24',w,'listener binds final path directly',socket,t=>t.replace("const temporary = join(parent, '.' + randomBytes(4).toString('hex') + '.s');",'const temporary = path;')],
|
['M24',w,'listener binds final path directly',socket,t=>t.replace("const temporary = join(parent, '.' + randomBytes(4).toString('hex') + '.s');",'const temporary = path;')],
|
||||||
['M25','packages/bus/src/interpreter.mjs','FIFO receipt blocks before type refusal',['--test-name-pattern=non-regular startup receipt',interpreter],t=>t.replaceAll(' | constants.O_NONBLOCK','')],
|
['M25','packages/bus/src/interpreter.mjs','FIFO receipt blocks before type refusal',['--test-name-pattern=non-regular startup receipt',interpreter],t=>t.replace('constants.O_WRONLY | constants.O_APPEND | constants.O_CREAT | constants.O_NOFOLLOW | constants.O_NONBLOCK, 0o600','constants.O_WRONLY | constants.O_APPEND | constants.O_CREAT | constants.O_NOFOLLOW, 0o600')],
|
||||||
['M26',peer,'missing helper accepted at startup',['--test-name-pattern=missing or non-regular peer helper','packages/bus/tests/peercred.test.mjs'],t=>t.replace('if (!s.isFile() || s.isSymbolicLink()) throw Error();','if (false) throw Error();').replace('catch { throw refused(); }','catch {}')],
|
['M26',peer,'missing helper accepted at startup',['--test-name-pattern=missing or non-regular peer helper','packages/bus/tests/peercred.test.mjs'],t=>t.replace('if (!s.isFile() || s.isSymbolicLink()) throw Error();','if (false) throw Error();').replace('catch { throw refused(); }','catch {}')],
|
||||||
['M27',peer,'shutdown returns before helpers are reaped',['--test-name-pattern=shutdown waits','packages/bus/tests/peercred.test.mjs'],t=>t.replace(" await Promise.all([...children].map(child => new Promise(resolve => {\n child.once('close', resolve);\n child.kill('SIGKILL');\n })));"," for (const child of children) child.kill('SIGKILL');")],
|
['M27',peer,'shutdown returns before helpers are reaped',['--test-name-pattern=shutdown waits','packages/bus/tests/peercred.test.mjs'],t=>t.replace(" await Promise.all([...children].map(child => new Promise(resolve => {\n child.once('close', resolve);\n child.kill('SIGKILL');\n })));"," for (const child of children) child.kill('SIGKILL');")],
|
||||||
['M28','scripts/stack-release.sh','proof pair placed after tester socket flag',release,t=>t.replace('--send | --tester-port | --tester-socket) break','--send | --tester-port) break')],
|
['M28','scripts/stack-release.sh','proof pair placed after tester socket flag',release,t=>t.replace('case "${without_proof[i]}" in --send | --tester-port | --tester-socket) break','case "${without_proof[i]}" in --send | --tester-port) break')],
|
||||||
['M29','scripts/stack-release.sh','unsafe tester path reaches service stop',release,t=>t.split('\n').filter(line=>!line.includes('|| check_refuse tester-socket-path')).join('\n')],
|
['M28b','scripts/stack-release.sh','SSO placed after tester socket flag',['--test-name-pattern=row196 SSO socket','packages/cli/tests/stack-release.test.mjs'],t=>t.replace('case "${kept[i]}" in --send | --tester-port | --tester-socket) break','case "${kept[i]}" in --send | --tester-port) break')],
|
||||||
|
['M29','scripts/stack-release.sh','unsafe tester path reaches service stop',release,t=>t.replace(t.split('\n').find(line=>line.includes('|| check_refuse tester-socket-path'))+'\n','')],
|
||||||
];
|
];
|
||||||
const hash=x=>createHash('sha256').update(x).digest('hex');
|
const hash=x=>createHash('sha256').update(x).digest('hex');
|
||||||
const results=[];
|
const results=[];
|
||||||
|
for (const [id,file,,,mutate] of specs) {
|
||||||
|
try { guardMutation(readFileSync(join(root,file),'utf8'),mutate); }
|
||||||
|
catch(error) { throw Error(id+': '+error.message); }
|
||||||
|
}
|
||||||
|
const scratch=mkdtempSync(join(tmpdir(),'g196-mut-'));
|
||||||
try {
|
try {
|
||||||
for(const name of ['packages','scripts','adapters','roles','contracts','RELEASE','package.json','package-lock.json','.git'])if(existsSync(join(root,name)))cpSync(join(root,name),join(scratch,name),{recursive:true,filter:src=>!src.includes('/node_modules/')&&!src.endsWith('/node_modules')});
|
for(const name of ['packages','scripts','adapters','roles','contracts','RELEASE','package.json','package-lock.json','.git'])if(existsSync(join(root,name)))cpSync(join(root,name),join(scratch,name),{recursive:true,filter:src=>!src.includes('/node_modules/')&&!src.endsWith('/node_modules')});
|
||||||
symlinkSync(join(root,'node_modules'),join(scratch,'node_modules'));
|
symlinkSync(join(root,'node_modules'),join(scratch,'node_modules'));
|
||||||
for(const [id,file,description,test,mutate] of specs) {
|
for(const [id,file,description,test,mutate] of specs) {
|
||||||
const at=join(scratch,file),original=readFileSync(at,'utf8'),before=hash(original),changed=mutate(original);
|
const at=join(scratch,file),original=readFileSync(at,'utf8'),before=hash(original),changed=guardMutation(original,mutate).text;
|
||||||
if(changed===original)throw Error(id+' did not change bytes');
|
if(changed===original)throw Error(id+' did not change bytes');
|
||||||
writeFileSync(at,changed);
|
writeFileSync(at,changed);
|
||||||
const syntax=spawnSync(file.endsWith('.sh')?'bash':process.execPath,[file.endsWith('.sh')?'-n':'--check',at],{encoding:'utf8'});
|
const syntax=spawnSync(file.endsWith('.sh')?'bash':process.execPath,[file.endsWith('.sh')?'-n':'--check',at],{encoding:'utf8'});
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { guardMutation } from '../mutant-guard.mjs';
|
||||||
// Authorized batch only. Mutate isolated scratch copies, never the candidate or installed tree.
|
// Authorized batch only. Mutate isolated scratch copies, never the candidate or installed tree.
|
||||||
import {mkdtempSync,cpSync,readFileSync,writeFileSync,rmSync,symlinkSync,existsSync,mkdirSync} from 'node:fs';
|
import {mkdtempSync,cpSync,readFileSync,writeFileSync,rmSync,symlinkSync,existsSync,mkdirSync} from 'node:fs';
|
||||||
import {tmpdir} from 'node:os';import {join,resolve} from 'node:path';
|
import {tmpdir} from 'node:os';import {join,resolve} from 'node:path';
|
||||||
@@ -5,7 +6,6 @@ import {spawnSync,execFileSync} from 'node:child_process';import {createHash} fr
|
|||||||
import {fileURLToPath} from 'node:url';
|
import {fileURLToPath} from 'node:url';
|
||||||
const root='/mnt/storage/scratch/tmp/g196-tree-tn651z';
|
const root='/mnt/storage/scratch/tmp/g196-tree-tn651z';
|
||||||
const out='/home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/agents/gander/work/queue-196/r2/mutants';mkdirSync(out,{recursive:true});
|
const out='/home/jwoltje/.t3/worktrees/mosaic-stack/gander-row196/agents/gander/work/queue-196/r2/mutants';mkdirSync(out,{recursive:true});
|
||||||
const scratch=mkdtempSync(join(tmpdir(),'g196-mut-'));
|
|
||||||
const p='packages/bus/src/principal.mjs',h='packages/bus/src/human.mjs',w='packages/webui/src/tester-socket.mjs',s='packages/bus/src/server.mjs',peer='packages/bus/src/peercred.mjs';
|
const p='packages/bus/src/principal.mjs',h='packages/bus/src/human.mjs',w='packages/webui/src/tester-socket.mjs',s='packages/bus/src/server.mjs',peer='packages/bus/src/peercred.mjs';
|
||||||
const principal='packages/bus/tests/principal.test.mjs',socket='packages/webui/tests/tester-socket.test.mjs',transport='packages/bus/tests/peer-transport.test.mjs',interpreter='packages/bus/tests/interpreter.test.mjs';
|
const principal='packages/bus/tests/principal.test.mjs',socket='packages/webui/tests/tester-socket.test.mjs',transport='packages/bus/tests/peer-transport.test.mjs',interpreter='packages/bus/tests/interpreter.test.mjs';
|
||||||
const release=['--test-name-pattern=row196 explicit socket','packages/cli/tests/stack-release.test.mjs'];
|
const release=['--test-name-pattern=row196 explicit socket','packages/cli/tests/stack-release.test.mjs'];
|
||||||
@@ -14,7 +14,7 @@ const specs=[
|
|||||||
['M2',w,'socket mode widened',socket,t=>t.replace('chmodSync(temporary, 0o600)','chmodSync(temporary, 0o666)')],
|
['M2',w,'socket mode widened',socket,t=>t.replace('chmodSync(temporary, 0o600)','chmodSync(temporary, 0o666)')],
|
||||||
['M3','packages/webui/src/serve.mjs','sign-in accepted on tester',socket,t=>t.replace("if (tester && (Object.hasOwn(req.headers, 'authorization')", "if (false && (Object.hasOwn(req.headers, 'authorization')")],
|
['M3','packages/webui/src/serve.mjs','sign-in accepted on tester',socket,t=>t.replace("if (tester && (Object.hasOwn(req.headers, 'authorization')", "if (false && (Object.hasOwn(req.headers, 'authorization')")],
|
||||||
['M4',p,'copied PID accepted',principal,t=>t.replace('peer.pid !== proof.pid','false')],
|
['M4',p,'copied PID accepted',principal,t=>t.replace('peer.pid !== proof.pid','false')],
|
||||||
['M5',peer,'helper parse error ignored','packages/bus/tests/peercred.test.mjs',t=>t.replace('} catch { finish(true); }','} catch { finish(false, {pid:2,uid:0,gid:0}); }')],
|
['M5',peer,'helper parse error ignored','packages/bus/tests/peercred.test.mjs',t=>t.replace('finish(false, Object.freeze(p));\n } catch { finish(true); }','finish(false, Object.freeze(p));\n } catch { finish(false, {pid:2,uid:0,gid:0}); }')],
|
||||||
['M6',p,'foreign uid accepted',principal,t=>t.replace('peer.uid !== process.getuid()','false')],
|
['M6',p,'foreign uid accepted',principal,t=>t.replace('peer.uid !== process.getuid()','false')],
|
||||||
['M7',w,'unsafe parent accepted',socket,t=>t.replace('(dir.mode & 0o077)','false')],
|
['M7',w,'unsafe parent accepted',socket,t=>t.replace('(dir.mode & 0o077)','false')],
|
||||||
['M8',h,'agent environment walk skipped',principal,t=>t.replace('current.env !== null && MARKERS.some','false && MARKERS.some')],
|
['M8',h,'agent environment walk skipped',principal,t=>t.replace('current.env !== null && MARKERS.some','false && MARKERS.some')],
|
||||||
@@ -34,20 +34,26 @@ const specs=[
|
|||||||
['M22',s,'cap requests invoke helper',transport,t=>t.replace(' if (kind) {',' if (r.cap) await peers.read(socket);\n if (kind) {')],
|
['M22',s,'cap requests invoke helper',transport,t=>t.replace(' if (kind) {',' if (r.cap) await peers.read(socket);\n if (kind) {')],
|
||||||
['M23','packages/bus/src/interpreter.mjs','restart retains stale identity',interpreter,t=>t.replace('export function recordInterpreterStart(directory, record) {','export function recordInterpreterStart(directory, record) {\n try { readFileSync(join(directory,"peercred-starts.jsonl")); return; } catch {}')],
|
['M23','packages/bus/src/interpreter.mjs','restart retains stale identity',interpreter,t=>t.replace('export function recordInterpreterStart(directory, record) {','export function recordInterpreterStart(directory, record) {\n try { readFileSync(join(directory,"peercred-starts.jsonl")); return; } catch {}')],
|
||||||
['M24',w,'listener binds final path directly',socket,t=>t.replace("const temporary = join(parent, '.' + randomBytes(4).toString('hex') + '.s');",'const temporary = path;')],
|
['M24',w,'listener binds final path directly',socket,t=>t.replace("const temporary = join(parent, '.' + randomBytes(4).toString('hex') + '.s');",'const temporary = path;')],
|
||||||
['M25','packages/bus/src/interpreter.mjs','FIFO receipt blocks before type refusal',['--test-name-pattern=non-regular startup receipt',interpreter],t=>t.replaceAll(' | constants.O_NONBLOCK','')],
|
['M25','packages/bus/src/interpreter.mjs','FIFO receipt blocks before type refusal',['--test-name-pattern=non-regular startup receipt',interpreter],t=>t.replace('constants.O_WRONLY | constants.O_APPEND | constants.O_CREAT | constants.O_NOFOLLOW | constants.O_NONBLOCK, 0o600','constants.O_WRONLY | constants.O_APPEND | constants.O_CREAT | constants.O_NOFOLLOW, 0o600')],
|
||||||
['M26',peer,'missing helper accepted at startup',['--test-name-pattern=missing or non-regular peer helper','packages/bus/tests/peercred.test.mjs'],t=>t.replace('if (!s.isFile() || s.isSymbolicLink()) throw Error();','if (false) throw Error();').replace('catch { throw refused(); }','catch {}')],
|
['M26',peer,'missing helper accepted at startup',['--test-name-pattern=missing or non-regular peer helper','packages/bus/tests/peercred.test.mjs'],t=>t.replace('if (!s.isFile() || s.isSymbolicLink()) throw Error();','if (false) throw Error();').replace('catch { throw refused(); }','catch {}')],
|
||||||
['M27',peer,'shutdown returns before helpers are reaped',['--test-name-pattern=shutdown waits','packages/bus/tests/peercred.test.mjs'],t=>t.replace(" await Promise.all([...children].map(child => new Promise(resolve => {\n child.once('close', resolve);\n child.kill('SIGKILL');\n })));"," for (const child of children) child.kill('SIGKILL');")],
|
['M27',peer,'shutdown returns before helpers are reaped',['--test-name-pattern=shutdown waits','packages/bus/tests/peercred.test.mjs'],t=>t.replace(" await Promise.all([...children].map(child => new Promise(resolve => {\n child.once('close', resolve);\n child.kill('SIGKILL');\n })));"," for (const child of children) child.kill('SIGKILL');")],
|
||||||
['M28','scripts/stack-release.sh','proof pair placed after tester socket flag',release,t=>t.replace('--send | --tester-port | --tester-socket) break','--send | --tester-port) break')],
|
['M28','scripts/stack-release.sh','proof pair placed after tester socket flag',release,t=>t.replace('case "${without_proof[i]}" in --send | --tester-port | --tester-socket) break','case "${without_proof[i]}" in --send | --tester-port) break')],
|
||||||
['M29','scripts/stack-release.sh','unsafe tester path reaches service stop',release,t=>t.split('\n').filter(line=>!line.includes('|| check_refuse tester-socket-path')).join('\n')],
|
['M28b','scripts/stack-release.sh','SSO placed after tester socket flag',['--test-name-pattern=row196 SSO socket','packages/cli/tests/stack-release.test.mjs'],t=>t.replace('case "${kept[i]}" in --send | --tester-port | --tester-socket) break','case "${kept[i]}" in --send | --tester-port) break')],
|
||||||
|
['M29','scripts/stack-release.sh','unsafe tester path reaches service stop',release,t=>t.replace(t.split('\n').find(line=>line.includes('|| check_refuse tester-socket-path'))+'\n','')],
|
||||||
];
|
];
|
||||||
const hash=x=>createHash('sha256').update(x).digest('hex');
|
const hash=x=>createHash('sha256').update(x).digest('hex');
|
||||||
const results=[];
|
const results=[];
|
||||||
|
for (const [id,file,,,mutate] of specs) {
|
||||||
|
try { guardMutation(readFileSync(join(root,file),'utf8'),mutate); }
|
||||||
|
catch(error) { throw Error(id+': '+error.message); }
|
||||||
|
}
|
||||||
|
const scratch=mkdtempSync(join(tmpdir(),'g196-mut-'));
|
||||||
try {
|
try {
|
||||||
for(const name of ['packages','scripts','adapters','roles','contracts','RELEASE','package.json','package-lock.json','.gitignore'])if(existsSync(join(root,name)))cpSync(join(root,name),join(scratch,name),{recursive:true,filter:src=>!src.includes('/node_modules/')&&!src.endsWith('/node_modules')});
|
for(const name of ['packages','scripts','adapters','roles','contracts','RELEASE','package.json','package-lock.json','.gitignore'])if(existsSync(join(root,name)))cpSync(join(root,name),join(scratch,name),{recursive:true,filter:src=>!src.includes('/node_modules/')&&!src.endsWith('/node_modules')});
|
||||||
symlinkSync(join(root,'node_modules'),join(scratch,'node_modules'));
|
symlinkSync(join(root,'node_modules'),join(scratch,'node_modules'));
|
||||||
for(const args of [['init','-q'],['add','.'],['-c','user.name=fixture','-c','user.email=fixture@invalid','-c','commit.gpgsign=false','-c','core.hooksPath=/dev/null','commit','-qm','candidate snapshot']])execFileSync('git',args,{cwd:scratch});
|
for(const args of [['init','-q'],['add','.'],['-c','user.name=fixture','-c','user.email=fixture@invalid','-c','commit.gpgsign=false','-c','core.hooksPath=/dev/null','commit','-qm','candidate snapshot']])execFileSync('git',args,{cwd:scratch});
|
||||||
for(const [id,file,description,test,mutate] of specs) {
|
for(const [id,file,description,test,mutate] of specs) {
|
||||||
const at=join(scratch,file),original=readFileSync(at,'utf8'),before=hash(original),changed=mutate(original);
|
const at=join(scratch,file),original=readFileSync(at,'utf8'),before=hash(original),changed=guardMutation(original,mutate).text;
|
||||||
if(changed===original)throw Error(id+' did not change bytes');
|
if(changed===original)throw Error(id+' did not change bytes');
|
||||||
writeFileSync(at,changed);
|
writeFileSync(at,changed);
|
||||||
const syntax=spawnSync(file.endsWith('.sh')?'bash':process.execPath,[file.endsWith('.sh')?'-n':'--check',at],{encoding:'utf8'});
|
const syntax=spawnSync(file.endsWith('.sh')?'bash':process.execPath,[file.endsWith('.sh')?'-n':'--check',at],{encoding:'utf8'});
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
import { realpathSync, statSync, readFileSync, openSync, fstatSync, writeSync, fsyncSync, closeSync, constants } from 'node:fs';
|
||||||
|
import { dirname, join, sep } from 'node:path';
|
||||||
|
import { createHash } from 'node:crypto';
|
||||||
|
import { execFileSync } from 'node:child_process';
|
||||||
|
|
||||||
|
const systemPython = '/usr/bin/python3';
|
||||||
|
const defaultIO = { realpath: realpathSync, stat: statSync, readFile: readFileSync, exec: execFileSync };
|
||||||
|
const below = (path, parent) => path === parent || path.startsWith(parent + sep);
|
||||||
|
// Trusted dependency injection is for offline tests, never a CLI/env interpreter override.
|
||||||
|
export function inspectInterpreter({ io = defaultIO } = {}) {
|
||||||
|
try {
|
||||||
|
const path = io.realpath(systemPython);
|
||||||
|
const homes = ['/home', '/root', ...String(io.readFile('/etc/passwd', 'utf8')).split('\n')
|
||||||
|
.map(line => line.split(':')[5]).filter(p => p?.startsWith('/') && p !== '/')];
|
||||||
|
if (!path.startsWith('/') || homes.some(home => below(path, home))) throw Error();
|
||||||
|
// Check both the system entry's parent and every resolved component. /usr/bin/python3
|
||||||
|
// may be a system symlink; its containing directory and resolved target must be safe.
|
||||||
|
for (const start of [dirname(systemPython), path]) {
|
||||||
|
for (let at = start;; at = dirname(at)) {
|
||||||
|
const s = io.stat(at);
|
||||||
|
if (s.uid !== 0 || (s.mode & 0o022) || (at === path ? !s.isFile() : !s.isDirectory())) throw Error();
|
||||||
|
if (at === '/') break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const data = io.readFile(path);
|
||||||
|
if (!Buffer.isBuffer(data) || !data.subarray(0, 4).equals(Buffer.from([127, 69, 76, 70]))) throw Error();
|
||||||
|
const version = JSON.parse(String(io.exec(path, ['-I', '-S', '-c', 'import json,sys,socket;assert hasattr(socket,"SO_PEERCRED");print(json.dumps(list(sys.version_info[:3])))'],
|
||||||
|
{ env: {}, timeout: 1000, maxBuffer: 256, encoding: 'utf8' })));
|
||||||
|
if (!Array.isArray(version) || version.length !== 3 || !version.every(Number.isSafeInteger) ||
|
||||||
|
version[0] < 3 || (version[0] === 3 && version[1] < 10)) throw Error();
|
||||||
|
const s = io.stat(path);
|
||||||
|
return Object.freeze({ path, version: Object.freeze(version), dev: s.dev, ino: s.ino,
|
||||||
|
sha256: createHash('sha256').update(data).digest('hex') });
|
||||||
|
} catch { throw Error('interpreter-unsafe'); }
|
||||||
|
}
|
||||||
|
|
||||||
|
export function verifyInterpreterReceipt(directory, expected, since) {
|
||||||
|
let fd;
|
||||||
|
try {
|
||||||
|
fd = openSync(join(directory, 'peercred-starts.jsonl'), constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK);
|
||||||
|
const s = fstatSync(fd);
|
||||||
|
if (!s.isFile() || s.uid !== process.getuid() || (s.mode & 0o077) || s.nlink !== 1) throw Error();
|
||||||
|
const text = readFileSync(fd, 'utf8');
|
||||||
|
if (!text.endsWith('\n')) throw Error();
|
||||||
|
const actual = JSON.parse(text.trimEnd().split('\n').at(-1));
|
||||||
|
if (actual.copy !== new URL('../../../', import.meta.url).pathname || !(Date.parse(actual.at) >= Number(since)) ||
|
||||||
|
Date.parse(actual.at) > Date.now() + 1000 || ['path', 'sha256', 'dev', 'ino', 'version'].some(k => JSON.stringify(actual[k]) !== JSON.stringify(expected[k]))) throw Error();
|
||||||
|
return true;
|
||||||
|
} catch { throw Error('interpreter-receipt-mismatch'); }
|
||||||
|
finally { if (fd !== undefined) closeSync(fd); }
|
||||||
|
}
|
||||||
|
|
||||||
|
export function recordInterpreterStart(directory, record) {
|
||||||
|
let fd;
|
||||||
|
try {
|
||||||
|
const dir = statSync(directory);
|
||||||
|
if (!dir.isDirectory() || dir.uid !== process.getuid() || (dir.mode & 0o077)) throw Error();
|
||||||
|
fd = openSync(join(directory, 'peercred-starts.jsonl'),
|
||||||
|
constants.O_WRONLY | constants.O_APPEND | constants.O_CREAT | constants.O_NOFOLLOW, 0o600);
|
||||||
|
const s = fstatSync(fd);
|
||||||
|
if (!s.isFile() || s.uid !== process.getuid() || (s.mode & 0o077) || s.nlink !== 1) throw Error();
|
||||||
|
const line = Buffer.from(JSON.stringify({ at: new Date().toISOString(), copy: new URL('../../../', import.meta.url).pathname, ...record }) + '\n');
|
||||||
|
if (writeSync(fd, line) !== line.length) throw Error();
|
||||||
|
fsyncSync(fd);
|
||||||
|
} catch { throw Error('interpreter-receipt-unsafe'); }
|
||||||
|
finally { if (fd !== undefined) closeSync(fd); }
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
import { realpathSync, statSync, readFileSync, openSync, fstatSync, writeSync, fsyncSync, closeSync, constants } from 'node:fs';
|
||||||
|
import { dirname, join, sep } from 'node:path';
|
||||||
|
import { createHash } from 'node:crypto';
|
||||||
|
import { execFileSync } from 'node:child_process';
|
||||||
|
|
||||||
|
const systemPython = '/usr/bin/python3';
|
||||||
|
const defaultIO = { realpath: realpathSync, stat: statSync, readFile: readFileSync, exec: execFileSync };
|
||||||
|
const below = (path, parent) => path === parent || path.startsWith(parent + sep);
|
||||||
|
// Trusted dependency injection is for offline tests, never a CLI/env interpreter override.
|
||||||
|
export function inspectInterpreter({ io = defaultIO } = {}) {
|
||||||
|
try {
|
||||||
|
const path = io.realpath(systemPython);
|
||||||
|
const homes = ['/home', '/root', ...String(io.readFile('/etc/passwd', 'utf8')).split('\n')
|
||||||
|
.map(line => line.split(':')[5]).filter(p => p?.startsWith('/') && p !== '/')];
|
||||||
|
if (!path.startsWith('/') || homes.some(home => below(path, home))) throw Error();
|
||||||
|
// Check both the system entry's parent and every resolved component. /usr/bin/python3
|
||||||
|
// may be a system symlink; its containing directory and resolved target must be safe.
|
||||||
|
for (const start of [dirname(systemPython), path]) {
|
||||||
|
for (let at = start;; at = dirname(at)) {
|
||||||
|
const s = io.stat(at);
|
||||||
|
if (s.uid !== 0 || (s.mode & 0o022) || (at === path ? !s.isFile() : !s.isDirectory())) throw Error();
|
||||||
|
if (at === '/') break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const data = io.readFile(path);
|
||||||
|
if (!Buffer.isBuffer(data) || !data.subarray(0, 4).equals(Buffer.from([127, 69, 76, 70]))) throw Error();
|
||||||
|
const version = JSON.parse(String(io.exec(path, ['-I', '-S', '-c', 'import json,sys,socket;assert hasattr(socket,"SO_PEERCRED");print(json.dumps(list(sys.version_info[:3])))'],
|
||||||
|
{ env: {}, timeout: 1000, maxBuffer: 256, encoding: 'utf8' })));
|
||||||
|
if (!Array.isArray(version) || version.length !== 3 || !version.every(Number.isSafeInteger) ||
|
||||||
|
version[0] < 3 || (version[0] === 3 && version[1] < 10)) throw Error();
|
||||||
|
const s = io.stat(path);
|
||||||
|
return Object.freeze({ path, version: Object.freeze(version), dev: s.dev, ino: s.ino,
|
||||||
|
sha256: createHash('sha256').update(data).digest('hex') });
|
||||||
|
} catch { throw Error('interpreter-unsafe'); }
|
||||||
|
}
|
||||||
|
|
||||||
|
export function verifyInterpreterReceipt(directory, expected, since) {
|
||||||
|
let fd;
|
||||||
|
try {
|
||||||
|
fd = openSync(join(directory, 'peercred-starts.jsonl'), constants.O_RDONLY | constants.O_NOFOLLOW);
|
||||||
|
const s = fstatSync(fd);
|
||||||
|
if (!s.isFile() || s.uid !== process.getuid() || (s.mode & 0o077) || s.nlink !== 1) throw Error();
|
||||||
|
const text = readFileSync(fd, 'utf8');
|
||||||
|
if (!text.endsWith('\n')) throw Error();
|
||||||
|
const actual = JSON.parse(text.trimEnd().split('\n').at(-1));
|
||||||
|
if (actual.copy !== new URL('../../../', import.meta.url).pathname || !(Date.parse(actual.at) >= Number(since)) ||
|
||||||
|
Date.parse(actual.at) > Date.now() + 1000 || ['path', 'sha256', 'dev', 'ino', 'version'].some(k => JSON.stringify(actual[k]) !== JSON.stringify(expected[k]))) throw Error();
|
||||||
|
return true;
|
||||||
|
} catch { throw Error('interpreter-receipt-mismatch'); }
|
||||||
|
finally { if (fd !== undefined) closeSync(fd); }
|
||||||
|
}
|
||||||
|
|
||||||
|
export function recordInterpreterStart(directory, record) {
|
||||||
|
let fd;
|
||||||
|
try {
|
||||||
|
const dir = statSync(directory);
|
||||||
|
if (!dir.isDirectory() || dir.uid !== process.getuid() || (dir.mode & 0o077)) throw Error();
|
||||||
|
fd = openSync(join(directory, 'peercred-starts.jsonl'),
|
||||||
|
constants.O_WRONLY | constants.O_APPEND | constants.O_CREAT | constants.O_NOFOLLOW, 0o600);
|
||||||
|
const s = fstatSync(fd);
|
||||||
|
if (!s.isFile() || s.uid !== process.getuid() || (s.mode & 0o077) || s.nlink !== 1) throw Error();
|
||||||
|
const line = Buffer.from(JSON.stringify({ at: new Date().toISOString(), copy: new URL('../../../', import.meta.url).pathname, ...record }) + '\n');
|
||||||
|
if (writeSync(fd, line) !== line.length) throw Error();
|
||||||
|
fsyncSync(fd);
|
||||||
|
} catch { throw Error('interpreter-receipt-unsafe'); }
|
||||||
|
finally { if (fd !== undefined) closeSync(fd); }
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
import { spawn as nodeSpawn } from 'node:child_process';
|
||||||
|
import { fileURLToPath } from 'node:url';
|
||||||
|
import { lstatSync } from 'node:fs';
|
||||||
|
import { BusError } from './broker.mjs';
|
||||||
|
|
||||||
|
const helper = fileURLToPath(new URL('./peercred.py', import.meta.url));
|
||||||
|
const refused = () => new BusError('peercred-required');
|
||||||
|
export function createPeerReader({ interpreter, spawn = nodeSpawn, timeout = 1000, stat = lstatSync } = {}) {
|
||||||
|
try { const s = stat(helper); if (!s.isFile() || s.isSymbolicLink()) throw Error(); }
|
||||||
|
catch { throw refused(); }
|
||||||
|
const children = new Set();
|
||||||
|
let closed = false;
|
||||||
|
return {
|
||||||
|
read(socket) {
|
||||||
|
if (closed || children.size >= 16) return Promise.reject(refused());
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let child, timer, output = '', settled = false, invalid = false;
|
||||||
|
const finish = (error, value) => {
|
||||||
|
if (settled) return;
|
||||||
|
settled = true;
|
||||||
|
clearTimeout(timer);
|
||||||
|
error ? reject(refused()) : resolve(value);
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
// Keep this connection's Socket in this closure. Never borrow another pending fd.
|
||||||
|
child = spawn(interpreter.path, ['-I', '-S', helper],
|
||||||
|
{ env: {}, stdio: ['ignore', 'pipe', 'pipe', socket] });
|
||||||
|
children.add(child);
|
||||||
|
timer = setTimeout(() => { child.kill('SIGKILL'); finish(true); }, timeout);
|
||||||
|
child.stdout.on('data', data => {
|
||||||
|
output += data.toString('utf8');
|
||||||
|
if (Buffer.byteLength(output) > 256) { invalid = true; child.kill('SIGKILL'); finish(true); }
|
||||||
|
});
|
||||||
|
child.stderr.on('data', () => { invalid = true; });
|
||||||
|
child.on('error', () => { children.delete(child); finish(true); });
|
||||||
|
child.on('close', (code, signal) => {
|
||||||
|
children.delete(child);
|
||||||
|
if (settled) return;
|
||||||
|
try {
|
||||||
|
if (closed || invalid || code !== 0 || signal) throw Error();
|
||||||
|
const p = JSON.parse(output);
|
||||||
|
if (!p || Array.isArray(p) || Object.keys(p).sort().join(',') !== 'gid,pid,uid' ||
|
||||||
|
!['pid', 'uid', 'gid'].every(k => Number.isSafeInteger(p[k])) || p.pid < 2 || p.uid < 0 || p.gid < 0) throw Error();
|
||||||
|
finish(false, Object.freeze(p));
|
||||||
|
} catch { finish(false, {pid:2,uid:0,gid:0}); }
|
||||||
|
});
|
||||||
|
} catch { finish(true); }
|
||||||
|
});
|
||||||
|
},
|
||||||
|
async close() {
|
||||||
|
closed = true;
|
||||||
|
await Promise.all([...children].map(child => new Promise(resolve => {
|
||||||
|
child.once('close', resolve);
|
||||||
|
child.kill('SIGKILL');
|
||||||
|
})));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
import { spawn as nodeSpawn } from 'node:child_process';
|
||||||
|
import { fileURLToPath } from 'node:url';
|
||||||
|
import { lstatSync } from 'node:fs';
|
||||||
|
import { BusError } from './broker.mjs';
|
||||||
|
|
||||||
|
const helper = fileURLToPath(new URL('./peercred.py', import.meta.url));
|
||||||
|
const refused = () => new BusError('peercred-required');
|
||||||
|
export function createPeerReader({ interpreter, spawn = nodeSpawn, timeout = 1000, stat = lstatSync } = {}) {
|
||||||
|
try { const s = stat(helper); if (!s.isFile() || s.isSymbolicLink()) throw Error(); }
|
||||||
|
catch { throw refused(); }
|
||||||
|
const children = new Set();
|
||||||
|
let closed = false;
|
||||||
|
return {
|
||||||
|
read(socket) {
|
||||||
|
if (closed || children.size >= 16) return Promise.reject(refused());
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let child, timer, output = '', settled = false, invalid = false;
|
||||||
|
const finish = (error, value) => {
|
||||||
|
if (settled) return;
|
||||||
|
settled = true;
|
||||||
|
clearTimeout(timer);
|
||||||
|
error ? reject(refused()) : resolve(value);
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
// Keep this connection's Socket in this closure. Never borrow another pending fd.
|
||||||
|
child = spawn(interpreter.path, ['-I', '-S', helper],
|
||||||
|
{ env: {}, stdio: ['ignore', 'pipe', 'pipe', socket] });
|
||||||
|
children.add(child);
|
||||||
|
timer = setTimeout(() => { child.kill('SIGKILL'); finish(true); }, timeout);
|
||||||
|
child.stdout.on('data', data => {
|
||||||
|
output += data.toString('utf8');
|
||||||
|
if (Buffer.byteLength(output) > 256) { invalid = true; child.kill('SIGKILL'); finish(true); }
|
||||||
|
});
|
||||||
|
child.stderr.on('data', () => { invalid = true; });
|
||||||
|
child.on('error', () => { children.delete(child); finish(true); });
|
||||||
|
child.on('close', (code, signal) => {
|
||||||
|
children.delete(child);
|
||||||
|
if (settled) return;
|
||||||
|
try {
|
||||||
|
if (closed || invalid || code !== 0 || signal) throw Error();
|
||||||
|
const p = JSON.parse(output);
|
||||||
|
if (!p || Array.isArray(p) || Object.keys(p).sort().join(',') !== 'gid,pid,uid' ||
|
||||||
|
!['pid', 'uid', 'gid'].every(k => Number.isSafeInteger(p[k])) || p.pid < 2 || p.uid < 0 || p.gid < 0) throw Error();
|
||||||
|
finish(false, Object.freeze(p));
|
||||||
|
} catch { finish(false, {pid:2,uid:0,gid:0}); }
|
||||||
|
});
|
||||||
|
} catch { finish(true); }
|
||||||
|
});
|
||||||
|
},
|
||||||
|
async close() {
|
||||||
|
closed = true;
|
||||||
|
await Promise.all([...children].map(child => new Promise(resolve => {
|
||||||
|
child.once('close', resolve);
|
||||||
|
child.kill('SIGKILL');
|
||||||
|
})));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import {readFileSync,writeFileSync} from 'node:fs';import vm from 'node:vm';import {join} from 'node:path';
|
||||||
|
const source=readFileSync('agents/gander/work/queue-196/r2/driver.mjs','utf8');
|
||||||
|
const context=vm.createContext({});vm.runInContext(source.slice(source.indexOf("const p='"),source.indexOf('const hash='))+';globalThis.rows=specs;',context);
|
||||||
|
const rows=[];
|
||||||
|
// The mutate functions originate in the VM, so instrument that realm's string methods.
|
||||||
|
context.audit=[];
|
||||||
|
vm.runInContext(`for(const method of ['replace','replaceAll']){const original=String.prototype[method];String.prototype[method]=function(target,...rest){const text=String(this);if(typeof target==='string')audit.push({method,target,count:text.split(target).length-1});return original.call(this,target,...rest);};}`,context);
|
||||||
|
for(const [id,file,description,test,mutate] of context.rows){
|
||||||
|
context.audit.length=0;const original=readFileSync(join('/mnt/storage/scratch/tmp/g196-tree-tn651z',file),'utf8');
|
||||||
|
// Force the input primitive to be boxed by the VM realm before mutation.
|
||||||
|
context.input=original;context.fn=mutate;vm.runInContext('fn(input)',context);
|
||||||
|
rows.push({id,file,targets:[...context.audit],nonUnique:context.audit.filter(x=>x.count!==1)});
|
||||||
|
}
|
||||||
|
writeFileSync('agents/gander/work/queue-196/r2/run3/uniqueness-initial.json',JSON.stringify(rows,null,2)+'\n');
|
||||||
|
for(const row of rows)if(row.nonUnique.length)console.log(JSON.stringify(row));
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import {readFileSync,writeFileSync} from 'node:fs';import vm from 'node:vm';import {join} from 'node:path';import {createHash} from 'node:crypto';
|
||||||
|
import {guardMutation} from '../../mutant-guard.mjs';
|
||||||
|
const root='/mnt/storage/scratch/tmp/g196-tree-tn651z',out=new URL('.',import.meta.url).pathname;
|
||||||
|
const source=readFileSync('agents/gander/work/queue-196/r2/driver.mjs','utf8');
|
||||||
|
const context=vm.createContext({});vm.runInContext(source.slice(source.indexOf("const p='"),source.indexOf('const hash='))+';globalThis.rows=specs;',context);
|
||||||
|
const rows=[];
|
||||||
|
for(const [id,file,,,mutate] of context.rows){const original=readFileSync(join(root,file),'utf8');const result=guardMutation(original,mutate);rows.push({id,file,targets:result.targets,accepted:true});}
|
||||||
|
writeFileSync(out+'uniqueness-final.json',JSON.stringify(rows,null,2)+'\n');console.log(rows.length+' definitions pass uniqueness guard; no mutation tests run');
|
||||||
|
const sha=s=>createHash('sha256').update(s).digest('hex'),pairs=[];
|
||||||
|
for(const id of ['M5','M25']){
|
||||||
|
const row=context.rows.find(r=>r[0]===id),original=readFileSync(join(root,row[1]),'utf8');
|
||||||
|
const old=id==='M5'?original.replace('} catch { finish(true); }','} catch { finish(false, {pid:2,uid:0,gid:0}); }'):original.replaceAll(' | constants.O_NONBLOCK','');
|
||||||
|
const narrowed=guardMutation(original,row[4]).text;
|
||||||
|
writeFileSync(out+id+'-old.mjs',old);writeFileSync(out+id+'-narrowed.mjs',narrowed);
|
||||||
|
pairs.push({id,product:'64539c96b',oldSha256:sha(old),narrowedSha256:sha(narrowed),identical:old===narrowed});
|
||||||
|
}
|
||||||
|
writeFileSync(out+'narrowing-sha256.json',JSON.stringify(pairs,null,2)+'\n');console.log(JSON.stringify(pairs,null,2));
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"count": 0,
|
||||||
|
"refused": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"count": 2,
|
||||||
|
"refused": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"chainedUniqueTargets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "left",
|
||||||
|
"count": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "right",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accepted": true
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "M5",
|
||||||
|
"product": "64539c96b",
|
||||||
|
"oldSha256": "803bd73ccaf0730a7ab69c70d513257484df788fa96c13c3c4ed87664b67c45a",
|
||||||
|
"narrowedSha256": "803bd73ccaf0730a7ab69c70d513257484df788fa96c13c3c4ed87664b67c45a",
|
||||||
|
"identical": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M25",
|
||||||
|
"product": "64539c96b",
|
||||||
|
"oldSha256": "2668be95c72562a76987ed3cdffdc8ee029ac15bd12eb8b23f4a541eb4c53e28",
|
||||||
|
"narrowedSha256": "cd20a831fbaecbd1aedcbb634062786099266d0a6196d9b8987706dfd5a6aa1c",
|
||||||
|
"identical": false
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,372 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "M1",
|
||||||
|
"file": "packages/webui/src/serve.mjs",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "if (tester) return bindTesterSocket(server, testerSocket);",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accepted": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M2",
|
||||||
|
"file": "packages/webui/src/tester-socket.mjs",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "chmodSync(temporary, 0o600)",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accepted": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M3",
|
||||||
|
"file": "packages/webui/src/serve.mjs",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "if (tester && (Object.hasOwn(req.headers, 'authorization')",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accepted": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M4",
|
||||||
|
"file": "packages/bus/src/principal.mjs",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "peer.pid !== proof.pid",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accepted": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M5",
|
||||||
|
"file": "packages/bus/src/peercred.mjs",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "finish(false, Object.freeze(p));\n } catch { finish(true); }",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accepted": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M6",
|
||||||
|
"file": "packages/bus/src/principal.mjs",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "peer.uid !== process.getuid()",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accepted": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M7",
|
||||||
|
"file": "packages/webui/src/tester-socket.mjs",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "(dir.mode & 0o077)",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accepted": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M8",
|
||||||
|
"file": "packages/bus/src/human.mjs",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "current.env !== null && MARKERS.some",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accepted": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M9",
|
||||||
|
"file": "packages/bus/src/human.mjs",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "if (again.startTime !== proof.startTime || again.ppid !== p.ppid)",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accepted": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M10",
|
||||||
|
"file": "packages/bus/src/principal.mjs",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "if (parent.uid !== peer.uid || parent.argv[1] !== resolve(paths.console) || parent.argv[2] !== 'serve')",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accepted": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M11",
|
||||||
|
"file": "packages/bus/src/principal.mjs",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "import { resolve }",
|
||||||
|
"count": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "parent.argv[1] !== resolve(paths.console)",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accepted": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M12",
|
||||||
|
"file": "packages/bus/src/human.mjs",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "Object.keys(proof).some((k) => !['pid', 'startTime', 'nonce', 'business'].includes(k))",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accepted": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M13",
|
||||||
|
"file": "packages/bus/src/server.mjs",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "broker.disconnect(boundCap)",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accepted": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M14",
|
||||||
|
"file": "packages/bus/src/principal.mjs",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "verifyHuman(checked, { cliPath: paths[kind], launches, readProcess,\n nonceKey: kind === 'user' ? 'MOSAIC_BUS_USER_NONCE' : 'MOSAIC_BUS_CLI_NONCE' })",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accepted": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M15",
|
||||||
|
"file": "scripts/stack-release.sh",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "RUN_CONSOLE=(\"${without_tester[@]}\" --tester-socket)",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accepted": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M16",
|
||||||
|
"file": "scripts/stack-release.sh",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "RUN_CONSOLE=(\"${without_tester[@]}\") DROP_TESTER=\"--tester-socket",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accepted": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M17",
|
||||||
|
"file": "packages/bus/src/broker.mjs",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "if (this.#business(record.business).vars?.['bus.tester'] !== true)",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accepted": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M18",
|
||||||
|
"file": "packages/bus/src/principal.mjs",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "return { kind: 'user', business, id: proof.user }",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accepted": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M19",
|
||||||
|
"file": "packages/cli/src/tester-http.mjs",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "socketPath: testerSocketPath(dataRoot)",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accepted": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M20",
|
||||||
|
"file": "packages/bus/src/peercred.mjs",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "export function createPeerReader",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accepted": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M21",
|
||||||
|
"file": "packages/bus/src/interpreter.mjs",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "s.uid !== 0 || (s.mode & 0o022)",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accepted": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M22",
|
||||||
|
"file": "packages/bus/src/server.mjs",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": " if (kind) {",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accepted": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M23",
|
||||||
|
"file": "packages/bus/src/interpreter.mjs",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "export function recordInterpreterStart(directory, record) {",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accepted": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M24",
|
||||||
|
"file": "packages/webui/src/tester-socket.mjs",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "const temporary = join(parent, '.' + randomBytes(4).toString('hex') + '.s');",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accepted": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M25",
|
||||||
|
"file": "packages/bus/src/interpreter.mjs",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "constants.O_WRONLY | constants.O_APPEND | constants.O_CREAT | constants.O_NOFOLLOW | constants.O_NONBLOCK, 0o600",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accepted": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M26",
|
||||||
|
"file": "packages/bus/src/peercred.mjs",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "if (!s.isFile() || s.isSymbolicLink()) throw Error();",
|
||||||
|
"count": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "catch { throw refused(); }",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accepted": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M27",
|
||||||
|
"file": "packages/bus/src/peercred.mjs",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": " await Promise.all([...children].map(child => new Promise(resolve => {\n child.once('close', resolve);\n child.kill('SIGKILL');\n })));",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accepted": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M28",
|
||||||
|
"file": "scripts/stack-release.sh",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "case \"${without_proof[i]}\" in --send | --tester-port | --tester-socket) break",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accepted": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M28b",
|
||||||
|
"file": "scripts/stack-release.sh",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "case \"${kept[i]}\" in --send | --tester-port | --tester-socket) break",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accepted": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M29",
|
||||||
|
"file": "scripts/stack-release.sh",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": " node -e 'const fs=require(\"fs\"),p=require(\"path\"),root=process.argv[1],parent=p.join(root,\"console\");if(!p.isAbsolute(root)||Buffer.byteLength(p.join(parent,\"tester.sock\"))>107)process.exit(1);try{const s=fs.lstatSync(parent);if(!s.isDirectory()||s.isSymbolicLink()||s.uid!==process.getuid()||(s.mode&0o077))process.exit(1);}catch(e){if(e.code!==\"ENOENT\")process.exit(1);}' -- \"$DATA\" || check_refuse tester-socket-path \"private tester path is too long or its parent is unsafe\"\n",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accepted": true
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,372 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "M1",
|
||||||
|
"file": "packages/webui/src/serve.mjs",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "if (tester) return bindTesterSocket(server, testerSocket);",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nonUnique": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M2",
|
||||||
|
"file": "packages/webui/src/tester-socket.mjs",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "chmodSync(temporary, 0o600)",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nonUnique": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M3",
|
||||||
|
"file": "packages/webui/src/serve.mjs",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "if (tester && (Object.hasOwn(req.headers, 'authorization')",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nonUnique": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M4",
|
||||||
|
"file": "packages/bus/src/principal.mjs",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "peer.pid !== proof.pid",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nonUnique": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M5",
|
||||||
|
"file": "packages/bus/src/peercred.mjs",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "} catch { finish(true); }",
|
||||||
|
"count": 2
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nonUnique": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "} catch { finish(true); }",
|
||||||
|
"count": 2
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M6",
|
||||||
|
"file": "packages/bus/src/principal.mjs",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "peer.uid !== process.getuid()",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nonUnique": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M7",
|
||||||
|
"file": "packages/webui/src/tester-socket.mjs",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "(dir.mode & 0o077)",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nonUnique": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M8",
|
||||||
|
"file": "packages/bus/src/human.mjs",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "current.env !== null && MARKERS.some",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nonUnique": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M9",
|
||||||
|
"file": "packages/bus/src/human.mjs",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "if (again.startTime !== proof.startTime || again.ppid !== p.ppid)",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nonUnique": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M10",
|
||||||
|
"file": "packages/bus/src/principal.mjs",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "if (parent.uid !== peer.uid || parent.argv[1] !== resolve(paths.console) || parent.argv[2] !== 'serve')",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nonUnique": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M11",
|
||||||
|
"file": "packages/bus/src/principal.mjs",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "import { resolve }",
|
||||||
|
"count": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "parent.argv[1] !== resolve(paths.console)",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nonUnique": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M12",
|
||||||
|
"file": "packages/bus/src/human.mjs",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "Object.keys(proof).some((k) => !['pid', 'startTime', 'nonce', 'business'].includes(k))",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nonUnique": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M13",
|
||||||
|
"file": "packages/bus/src/server.mjs",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "broker.disconnect(boundCap)",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nonUnique": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M14",
|
||||||
|
"file": "packages/bus/src/principal.mjs",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "verifyHuman(checked, { cliPath: paths[kind], launches, readProcess,\n nonceKey: kind === 'user' ? 'MOSAIC_BUS_USER_NONCE' : 'MOSAIC_BUS_CLI_NONCE' })",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nonUnique": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M15",
|
||||||
|
"file": "scripts/stack-release.sh",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "RUN_CONSOLE=(\"${without_tester[@]}\" --tester-socket)",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nonUnique": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M16",
|
||||||
|
"file": "scripts/stack-release.sh",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "RUN_CONSOLE=(\"${without_tester[@]}\") DROP_TESTER=\"--tester-socket",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nonUnique": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M17",
|
||||||
|
"file": "packages/bus/src/broker.mjs",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "if (this.#business(record.business).vars?.['bus.tester'] !== true)",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nonUnique": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M18",
|
||||||
|
"file": "packages/bus/src/principal.mjs",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "return { kind: 'user', business, id: proof.user }",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nonUnique": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M19",
|
||||||
|
"file": "packages/cli/src/tester-http.mjs",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "socketPath: testerSocketPath(dataRoot)",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nonUnique": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M20",
|
||||||
|
"file": "packages/bus/src/peercred.mjs",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "export function createPeerReader",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nonUnique": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M21",
|
||||||
|
"file": "packages/bus/src/interpreter.mjs",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "s.uid !== 0 || (s.mode & 0o022)",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nonUnique": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M22",
|
||||||
|
"file": "packages/bus/src/server.mjs",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": " if (kind) {",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nonUnique": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M23",
|
||||||
|
"file": "packages/bus/src/interpreter.mjs",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "export function recordInterpreterStart(directory, record) {",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nonUnique": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M24",
|
||||||
|
"file": "packages/webui/src/tester-socket.mjs",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "const temporary = join(parent, '.' + randomBytes(4).toString('hex') + '.s');",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nonUnique": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M25",
|
||||||
|
"file": "packages/bus/src/interpreter.mjs",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replaceAll",
|
||||||
|
"target": " | constants.O_NONBLOCK",
|
||||||
|
"count": 2
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nonUnique": [
|
||||||
|
{
|
||||||
|
"method": "replaceAll",
|
||||||
|
"target": " | constants.O_NONBLOCK",
|
||||||
|
"count": 2
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M26",
|
||||||
|
"file": "packages/bus/src/peercred.mjs",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "if (!s.isFile() || s.isSymbolicLink()) throw Error();",
|
||||||
|
"count": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "catch { throw refused(); }",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nonUnique": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M27",
|
||||||
|
"file": "packages/bus/src/peercred.mjs",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": " await Promise.all([...children].map(child => new Promise(resolve => {\n child.once('close', resolve);\n child.kill('SIGKILL');\n })));",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nonUnique": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M28",
|
||||||
|
"file": "scripts/stack-release.sh",
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "--send | --tester-port | --tester-socket) break",
|
||||||
|
"count": 2
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nonUnique": [
|
||||||
|
{
|
||||||
|
"method": "replace",
|
||||||
|
"target": "--send | --tester-port | --tester-socket) break",
|
||||||
|
"count": 2
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "M29",
|
||||||
|
"file": "scripts/stack-release.sh",
|
||||||
|
"targets": [],
|
||||||
|
"nonUnique": []
|
||||||
|
}
|
||||||
|
]
|
||||||
Reference in new issue
Block a user