Unclaimed files left in the canonical checkout. Inventory: canonical-cleanup-inventory.md (commit-as-evidence groups). detect-secrets scan clean on 2026-11-02: hits are sha256 pins, git object ids, test sentinels already in tracked tests and unit-file lines.
34 lines
2.0 KiB
Python
34 lines
2.0 KiB
Python
# Row 84 mutants: each edit applied alone to <tree>, the chief-of-staff
|
|
# tests run, the file restored. Usage: python3 mutants.py <tree>
|
|
import subprocess, shutil, sys
|
|
W=sys.argv[1] # the tree with the candidate applied
|
|
R='roles/chief-of-staff.json'
|
|
B='packages/business/src/business.mjs'
|
|
M=[
|
|
('tools + write', R, '"ls"]', '"ls", "write"]'),
|
|
('tools + bash', R, '"ls"]', '"ls", "bash"]'),
|
|
('tools drop ls', R, ', "ls"]', ']'),
|
|
('network open', R, '"network": "api-only"', '"network": "open"'),
|
|
('network none', R, '"network": "api-only"', '"network": "none"'),
|
|
('withinRole + task.create', R, '["message.send"]', '["message.send", "task.create"]'),
|
|
('withinRole + role.launch', R, '["message.send"]', '["message.send", "role.launch"]'),
|
|
('withinRole empty', R, '["message.send"]', '[]'),
|
|
('crossRole + task.priority.change', R, '"crossRole": []', '"crossRole": ["task.priority.change"]'),
|
|
('credentials + gitea', R, '"credentials": []', '"credentials": [{ "service": "gitea", "scopes": ["read:issue"] }]'),
|
|
('instance may carry authority', B, '["definition", "holder", "vars", "tracker", "credentials"], at', '["definition", "holder", "vars", "tracker", "credentials", "authority"], at'),
|
|
('launch.by unchecked', B, 'if (!launcher.authority.withinRole.includes("role.launch")) {', 'if (false) {'),
|
|
('credential map unchecked', B, "if (names.join(\",\") !== wanted.join(\",\")) {", 'if (false) {'),
|
|
]
|
|
res=[]
|
|
for name,f,a,b in M:
|
|
p=f'{W}/{f}'; s=open(p).read()
|
|
if s.count(a)!=1: res.append(f'NOMATCH {name} ({s.count(a)})'); continue
|
|
shutil.copy(p,p+'.bak'); open(p,'w').write(s.replace(a,b))
|
|
try:
|
|
r=subprocess.run(['node','--test','tests/chief-of-staff.test.mjs'],cwd=f'{W}/packages/business',capture_output=True,text=True,timeout=300)
|
|
fails=[l for l in r.stdout.splitlines() if l.startswith('✖') and 'failing tests' not in l]
|
|
res.append(f"{'KILLED' if r.returncode else 'SURVIVED'} {name}: {len(set(fails))} failing")
|
|
finally:
|
|
shutil.move(p+'.bak',p)
|
|
print('\n'.join(res))
|