mirror of
https://github.com/PR0M3TH3AN/SeedPass.git
synced 2026-10-27 07:52:03 +00:00
Restore on SIGTERM, not just SIGINT; record the mutation sweep as done
The harness trapped SIGINT and nothing else, so a run wrapped in `timeout` was killed with SIGTERM straight past the handler — leaving an INVERTED fingerprint comparison in js/packages/cli/src/api/routes.ts along with the lock file. That happened during this sweep. The lock is exactly what it is for and it worked: the mutant was spotted and reverted before anything was committed. But the restore should have run, so SIGTERM and SIGHUP now go through the same handler. Verified by killing a live run and confirming the tree came back clean. Full verification sweep across all six targets, run after every fix: 132 mutants, 87 killed, 45 non-compiling, ZERO survivors. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_01Vtx94nXDmNgXEeThUZP4QN
This commit is contained in:
1 parent
e1ea9c2b48
commit
f043c95672
2 files changed
+38
-6
No files matched your search
@@ -143,11 +143,34 @@ everything still open, in the order it should be tackled.
|
||||
runs automatically, and this branch has a documented history of
|
||||
CI going unwatched (ts-parity red for 33 runs). A check nobody
|
||||
runs is not a check.
|
||||
- [ ] **Systematic mutation testing** of the security-critical modules
|
||||
- [x] **Systematic mutation testing** of the security-critical modules
|
||||
that have NO differential oracle because Python has no
|
||||
equivalent: the session agent, the API HTTP layer, high-risk
|
||||
session handling, sinks. Ad-hoc mutation was applied to every fix
|
||||
in this branch, but never measured as coverage.
|
||||
session handling, sinks. Done 2026-08-19 via
|
||||
`scripts/mutation_test.py`. All six targets sweep to ZERO
|
||||
survivors: 132 mutants, 87 killed, 45 non-compiling. Re-run with
|
||||
`.venv/bin/python scripts/mutation_test.py --target all`; it is
|
||||
slow (~25s/mutant) so use `--offset/--limit` to slice it, and
|
||||
never run it unattended — it writes deliberately broken security
|
||||
code into the tree while it works, guarded by
|
||||
`.mutation-test-running`.
|
||||
|
||||
It found real gaps rather than confirming the suite. The largest:
|
||||
the high-risk expiry rule was written in two places that masked
|
||||
each other's mutations, and one of the two was unreachable dead
|
||||
code; a token's `kinds` restriction was entirely untested; the
|
||||
API would delete the profile it was serving; `token-issue` would
|
||||
mint a token for a profile the agent never held; an empty
|
||||
high-risk factor was refused in both implementations and tested
|
||||
in neither.
|
||||
|
||||
Two blind spots in the harness itself mattered as much as the
|
||||
findings. It only mutated block-form guards, so every one-line
|
||||
`if (cond) return ...;` — which is how most of the load-bearing
|
||||
checks are written — was invisible; `src/highRisk.ts` generated
|
||||
zero mutants and printed as a clean sweep. Both fixed: inline
|
||||
guards are mutated, and a target that generates no mutants now
|
||||
reports NOT MEASURED rather than passing silently.
|
||||
- [ ] **Adversarial pass over TS-only surfaces**, framed as "what does
|
||||
this trust?" rather than "is this correct?" — the framing that
|
||||
finds trust-boundary bugs rather than logic bugs.
|
||||
|
||||
@@ -295,9 +295,18 @@ def main() -> int:
|
||||
def restore(*_: object) -> None:
|
||||
path.write_text(original)
|
||||
|
||||
signal.signal(
|
||||
signal.SIGINT, lambda *a: (restore(), release_lock(), sys.exit(130))
|
||||
)
|
||||
# SIGTERM as well as SIGINT. Handling only Ctrl-C was not enough: a
|
||||
# run wrapped in `timeout` is killed with SIGTERM, which skipped the
|
||||
# handler entirely and left an INVERTED SECURITY CHECK in the working
|
||||
# tree along with the lock file. The lock caught it, which is what it
|
||||
# is for -- but the restore should have run in the first place.
|
||||
def on_signal(*_: object) -> None:
|
||||
restore()
|
||||
release_lock()
|
||||
sys.exit(130)
|
||||
|
||||
for sig in (signal.SIGINT, signal.SIGTERM, signal.SIGHUP):
|
||||
signal.signal(sig, on_signal)
|
||||
|
||||
try:
|
||||
for idx, mutant in enumerate(mutants, start=args.offset + 1):
|
||||
|
||||
Reference in new issue
Block a user