Filbert's six changes and Dewey's N1-N3: five table rows, two launcher tests, README sentences. 34/34 mutants killed, 14 suites green. Co-Authored-By: Claude Opus 5.5 <[email protected]>
71 lines
5.3 KiB
Bash
71 lines
5.3 KiB
Bash
#!/usr/bin/env bash
|
||
# Row 92 (#1586) round 2 mutants: round 1's 26, then the sites Filbert's
|
||
# round 1 run left alive and their neighbours. Run from the candidate
|
||
# worktree's root:
|
||
# LOG=<dir> bash mutants.sh /path/to/mut.mjs > mutants.txt
|
||
# Each mutant edits one site with mut.mjs (exactly one match, else exit 3),
|
||
# runs the named test files and restores the file. "killed" means the run
|
||
# failed; "survived" means it passed.
|
||
set -u
|
||
MUT=$1
|
||
run() {
|
||
local name=$1 file=$2 from=$3 to=$4; shift 4
|
||
cp -- "$file" "$file.orig"
|
||
if ! node "$MUT" "$file" "$from" "$to"; then
|
||
echo "$name: NO MATCH"; mv -- "$file.orig" "$file"; return
|
||
fi
|
||
if node --test "$@" > "${LOG:-.}/mut-$name.log" 2>&1; then
|
||
echo "$name: survived"
|
||
else
|
||
echo "$name: killed ($(grep -m1 -o 'ℹ fail [0-9]*' "${LOG:-.}/mut-$name.log"), $(grep -m1 '^✖' "${LOG:-.}/mut-$name.log" | cut -c1-90))"
|
||
fi
|
||
mv -- "$file.orig" "$file"
|
||
}
|
||
S=packages/seat/src/sandbox.mjs
|
||
E=packages/seat/src/session.mjs
|
||
L=packages/cli/src/launcher.mjs
|
||
U=packages/cli/systemd/mosaic-bus.service.in
|
||
ST=(packages/seat/tests/sandbox.test.mjs)
|
||
SE=(packages/seat/tests/session.test.mjs)
|
||
LT=(packages/cli/tests/launcher.test.mjs)
|
||
ALL=(packages/seat/tests/sandbox.test.mjs packages/seat/tests/session.test.mjs packages/cli/tests/launcher.test.mjs)
|
||
# Binds
|
||
run no-workspace-bind $S $' { kind: "rw", src: workspace, why: "the instance\'s workspace, where the harness works" },\n' '' "${ST[@]}"
|
||
run runDir-read-only $S '{ kind: "rw", src: runDir,' '{ kind: "ro", src: runDir,' "${ST[@]}"
|
||
run bind-all-runs $S '{ kind: "rw", src: runDir,' '{ kind: "rw", src: dirname(runDir),' "${ST[@]}"
|
||
run bundle-writable $S $' { kind: "ro", src: join(runDir, "bundle"), why: "the run\'s bundle stays as the host wrote it" },\n' '' "${ST[@]}"
|
||
run session-json-writable $S $' { kind: "ro", src: join(runDir, "session.json"), why: "the session file stays as the host wrote it" },\n' '' "${ST[@]}"
|
||
run no-private-tmp $S $' { kind: "rw", src: join(runDir, "tmp"), dest: "/tmp", why: "a private /tmp, on disk in the run directory" },\n' '' "${ST[@]}"
|
||
run bind-checkout $S ' for (const f of RUNNER_FILES) out.push(' $' out.push({ kind: "ro", src: REPO, why: "x" });\n for (const f of RUNNER_FILES) out.push(' "${ST[@]}"
|
||
run node-modules-always $S 'if (harness === "pi") out.push' 'if (true) out.push' "${ST[@]}"
|
||
run runner-file-missing $S $' "packages/business/src/vocabulary.mjs",\n' '' "${ST[@]}"
|
||
run no-remount-ro $S '...argsOf(list), "--remount-ro", "/", "--setenv"' '...argsOf(list), "--setenv"' "${ST[@]}"
|
||
run host-home $S '"--setenv", "HOME", join(runDir, "home")' '"--setenv", "HOME", process.env.HOME' "${ST[@]}"
|
||
# Namespaces and death
|
||
run no-pid-namespace $S '"--unshare-pid", "--unshare-ipc", "--as-pid-1"' '"--unshare-ipc"' "${ALL[@]}"
|
||
run die-with-parent $S '"--unshare-ipc", "--as-pid-1"]' '"--unshare-ipc", "--as-pid-1", "--die-with-parent"]' "${LT[@]}"
|
||
run no-pdeathsig $S 'const KILL_WITH_PARENT = ["/usr/bin/setpriv", "--pdeathsig", "KILL", "--"];' 'const KILL_WITH_PARENT = [];' "${LT[@]}"
|
||
run exit-code-not-mapped $E $' if (!signal && code > 128 && SIGNALS[code - 128]) return { code: null, signal: SIGNALS[code - 128] };\n' '' "${SE[@]}" "${LT[@]}"
|
||
run recover-matches-unshare $L '(cmdlineOf(s.pid) ?? [])[0] === bwrap)' '(cmdlineOf(s.pid) ?? [])[0] === "unshare")' "${LT[@]}"
|
||
# Refusals
|
||
run no-sandbox-check $L $' if (unavailable) throw new Refusal("sandbox-unavailable", unavailable);\n' '' "${LT[@]}"
|
||
run probe-always-ok $S $' if (!existsSync(bwrap)) return `${bwrap} is missing`;\n' $' return null;\n' "${ST[@]}" "${LT[@]}"
|
||
run no-credential-check $L 'if (model.harness === "claude-code" && !hasSessionCredential(env))' 'if (false)' "${LT[@]}"
|
||
run proxy-key-alone $E '["ANTHROPIC_AUTH_TOKEN", "ANTHROPIC_BASE_URL"]]' '["ANTHROPIC_AUTH_TOKEN"]]' "${SE[@]}" "${LT[@]}"
|
||
run proxy-key-ignored $E ', ["ANTHROPIC_AUTH_TOKEN", "ANTHROPIC_BASE_URL"]]' ']' "${SE[@]}" "${LT[@]}"
|
||
run any-variable-will-do $E 'SESSION_CREDENTIALS.some((set) => set.every(' 'SESSION_CREDENTIALS.some((set) => set.some(' "${SE[@]}" "${LT[@]}"
|
||
run claude-bin-not-bound $L 'claudeBin: env.MOSAIC_CLAUDE_BIN || null,' 'claudeBin: null,' "${LT[@]}"
|
||
run launch-socket-always $L 'launchSocket: resolved.launch ? launchSocketPath(dataRoot) : null,' 'launchSocket: launchSocketPath(dataRoot),' "${LT[@]}"
|
||
# The unit
|
||
run unit-no-envfile $U 'EnvironmentFile=-' '# EnvironmentFile=-' packages/cli/tests/host.test.mjs
|
||
run unit-envfile-required $U 'EnvironmentFile=-' 'EnvironmentFile=' packages/cli/tests/host.test.mjs
|
||
# Round 2: Filbert's survivors (changes 1 to 4) and their neighbours
|
||
run no-ipc-namespace $S '"--unshare-pid", "--unshare-ipc", "--as-pid-1"]' '"--unshare-pid", "--as-pid-1"]' "${ST[@]}"
|
||
run host-proc $S 'args.push("--proc", b.dest)' 'args.push("--ro-bind", "/proc", b.dest)' "${ST[@]}"
|
||
run host-dev $S 'args.push("--dev", b.dest)' 'args.push("--dev-bind", "/dev", b.dest)' "${ST[@]}"
|
||
run pi-no-node-modules $S 'if (harness === "pi") out.push' 'if (false) out.push' "${ST[@]}"
|
||
run launcher-raw-exit $L 'resolve(sessionExit(code, signal))' 'resolve({ code, signal })' "${LT[@]}"
|
||
run credential-every-harness $L 'if (model.harness === "claude-code" && !hasSessionCredential(env))' 'if (!hasSessionCredential(env))' "${LT[@]}"
|
||
run pdeathsig-term $S '"--pdeathsig", "KILL"' '"--pdeathsig", "TERM"' "${LT[@]}"
|
||
run workspace-read-only $S '{ kind: "rw", src: workspace,' '{ kind: "ro", src: workspace,' "${ST[@]}"
|