Rocko's work committed by Sage (Rocko has no git authority). Candidate
manifest sha256 4927de66, base 27a1a2bb.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
38 lines
2.7 KiB
Python
38 lines
2.7 KiB
Python
# Row 77 mutants: each edit applied alone to <tree>, the service and pinned-copy
|
|
# tests run, the file restored. Usage: python3 mutants.py <tree>
|
|
import subprocess, shutil, sys
|
|
W=sys.argv[1] # the tree with the candidate applied
|
|
S='scripts/webui-service.sh'
|
|
M=[
|
|
('failed counts as running', S, '&& $3 != "failed" {', '{'),
|
|
('reloading not running', S, '$3 != "failed" {', '$3 != "failed" && $3 != "reloading" {'),
|
|
('list-units failure ignored', S, '2>/dev/null)" || die "refusing: systemctl --user list-units', '2>/dev/null)" || true; : "refusing: systemctl --user list-units'),
|
|
('install skips state read', S, ' state="$(running)" || exit 1\n [ -z "$state" ] || die "refusing: $UNIT_NAME is running', ' state=""\n [ -z "$state" ] || die "refusing: $UNIT_NAME is running'),
|
|
('uninstall skips state read with --no-reload', S, '[ -z "$state" ] || die "refusing: $UNIT_NAME is still running', '[ -z "$state" ] || [ "$RELOAD" = 0 ] || die "refusing: $UNIT_NAME is still running'),
|
|
('uid header case-sensitive', S, '"${AUTH_HEADER,,}" = x-authentik-uid', '"$AUTH_HEADER" = X-authentik-uid'),
|
|
('uid allows upper hex', S, '^[0-9a-f]{64}$ ]]; then', '^[0-9a-fA-F]{64}$ ]]; then'),
|
|
('allowed user may start with -', S, 'case "$ALLOW_USER" in [A-Za-z0-9]*) ;;', 'case "$ALLOW_USER" in *) ;;'),
|
|
('no --checkout in unit', S, 'flags="--checkout $REPO $flags"', 'flags="$flags"'),
|
|
('canonical always passes', S, '[ -d "$REPO/.git" ] || [ "$ALLOW_WORKTREE" = 1 ] ||', 'true ||'),
|
|
('install without --copy', S, '[ -n "$COPY_ID" ] || die "install needs --copy ID', 'true || die "install needs --copy ID'),
|
|
('missing copy accepted', S, '[ -f "$COPIES/$COPY_ID/packages/webui/src/cli.mjs" ] ||', 'true ||'),
|
|
('status drift wrong', S, 'if [ "$head" = "$copy" ]; then', 'if true; then'),
|
|
('copy misses seat', S, ' packages/seat/src\n', ''),
|
|
('copy stays writable', S, '-exec chmod a-w', '-exec true'),
|
|
('copy off-branch accepted', S, 'merge-base --is-ancestor "$id" refs/heads/refactor ||', 'true ||'),
|
|
('queue reads root', 'packages/webui/src/reads.mjs', 'root: queueRoot', 'root'),
|
|
('--checkout relative ok', 'packages/webui/src/cli.mjs', 'isAbsolute(', '!!('),
|
|
]
|
|
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}'); continue
|
|
shutil.copy(p,p+'.bak'); open(p,'w').write(s.replace(a,b))
|
|
try:
|
|
r=subprocess.run(['node','--test','tests/service.test.mjs','tests/pinned-copy.test.mjs'],cwd=f'{W}/packages/webui',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))
|