chore(security): Baseline-Update 2026-10-27 (mutation_check, Testvorlage)
Aus cj/security-baseline 3a23c7a übernommen: - scripts/security/mutation_check.py: Syntax-/Importfehler aus einer Mutation zählen nicht mehr als getötet ([UNGÜLTIG]); getötet nur bei echtem Testfehler (pytest, unittest, node:test spec und TAP), TODO-/SKIP-Tests sind kein Beleg. - Sicherheitstest-Vorlage: ungültige Eingaben müssen konfiguriert sein (Leerlauf-Sperre). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
02637c1f32
commit
e39de4ddf5
2 changed files with 25 additions and 17 deletions
|
|
@ -818,7 +818,7 @@ Open security points (state at adoption, 2026-10-15; updated 2026-10-17):
|
|||
`project-state-snapshot.model.ts`, `Sidebar.tsx`, `cable-sizing-modal.tsx`,
|
||||
`estimate-balance-format.ts`, `room-area.ts` – check for ReDoS when inputs can be long;
|
||||
several `react-hooks/exhaustive-deps` warnings in the editor.
|
||||
- Baseline-Stand 2026-10-27 (security-baseline a04c20b): `mutation_check.py` zählt Syntax-/Importfehler nicht mehr als getötet (`[UNGÜLTIG]`), Sicherheitstests verlangen konfigurierte ungültige Eingaben (Leerlauf-Sperre).
|
||||
- Baseline-Stand 2026-10-27 (security-baseline 3a23c7a): `mutation_check.py` zählt Syntax-/Importfehler nicht mehr als getötet (`[UNGÜLTIG]`), Sicherheitstests verlangen konfigurierte ungültige Eingaben (Leerlauf-Sperre).
|
||||
|
||||
## Response Style for Codex
|
||||
|
||||
|
|
|
|||
|
|
@ -5,9 +5,9 @@ Baut gezielt je eine Schutzfunktion aus (Textersetzung), lässt die Tests laufen
|
|||
erwartet ROT. Danach wird die Datei immer wiederhergestellt. Überlebt eine Mutation
|
||||
(Tests bleiben grün), prüfen die Tests diese Schutzfunktion nicht wirklich.
|
||||
|
||||
Getötet ist eine Mutation nur, wenn ein Test fehlschlägt (pytest FAILED, unittest FAIL,
|
||||
node:test ✖ bzw. TAP "not ok") und im Fehlerbericht kein Ladefehler steht (Syntax-/Importfehler, siehe
|
||||
LOAD_ERRORS). Rot durch kaputten Code zählt als UNGÜLTIG.
|
||||
Getötet ist eine Mutation nur, wenn ein Test fehlschlägt (pytest FAILED, unittest
|
||||
FAIL, node:test ✖ bzw. TAP "not ok") und im Fehlerbericht kein Ladefehler steht
|
||||
(Syntax-/Importfehler, siehe LOAD_ERRORS). Rot durch kaputten Code zählt als UNGÜLTIG.
|
||||
|
||||
Aufruf: mutation_check.py <mutations.toml>
|
||||
Exit: 0 = jede Mutation hat mindestens einen Test rot gemacht, 1 = sonst
|
||||
|
|
@ -58,28 +58,33 @@ def _write(target: Path, text: str) -> None:
|
|||
pyc.unlink(missing_ok=True)
|
||||
|
||||
|
||||
# "not ok ... # TODO|SKIP": erwartet scheiternder Test (z. B. idorGap), Lauf bleibt grün
|
||||
TAP_DIRECTIVE = re.compile(r"#\s*(TODO|SKIP)\b")
|
||||
|
||||
|
||||
def _tap_fail(stripped: str) -> bool:
|
||||
# "not ok ... # TODO|SKIP": erwartet scheiternder Test (z. B. idorGap), macht den Lauf nicht rot
|
||||
return stripped.startswith("not ok ") and not re.search(r"#\s*(TODO|SKIP)\b", stripped)
|
||||
return stripped.startswith("not ok ") and not TAP_DIRECTIVE.search(stripped)
|
||||
|
||||
|
||||
def _failed_lines(output: str) -> list[str]:
|
||||
# pytest: "FAILED ...", unittest: "FAIL: ...", node:test: "✖ <Testname>" (ohne Zusammenfassung)
|
||||
# bzw. im TAP-Format (ältere Node-Versionen, `tsx --test` ohne Terminal): "not ok <n> - <Testname>"
|
||||
# pytest: "FAILED ...", unittest: "FAIL: ...", node:test: "✖ <Testname>" ohne
|
||||
# Zusammenfassung bzw. TAP (ältere Node-Versionen, `tsx --test` ohne Terminal):
|
||||
# "not ok <n> - <Testname>"
|
||||
lines = []
|
||||
for line in output.splitlines():
|
||||
stripped = line.strip()
|
||||
node_fail = stripped.startswith("✖") and "failing tests" not in line
|
||||
node_fail = node_fail or _tap_fail(stripped)
|
||||
# "FAILED (errors=1)" ist die Zusammenfassung von unittest, kein fehlgeschlagener Test.
|
||||
# "FAILED (errors=1)" ist die Zusammenfassung von unittest, kein Testfehler.
|
||||
pytest_fail = line.startswith("FAILED ") and not line.startswith("FAILED (")
|
||||
if pytest_fail or line.startswith("FAIL:") or node_fail:
|
||||
lines.append(stripped)
|
||||
return lines
|
||||
|
||||
|
||||
# Rot durch kaputten Code ist kein Testbeleg (2026-10-27): pytest meldet einen Ladefehler als
|
||||
# ERROR ohne FAILED, node:test bricht alle Tests ab und markiert sie trotzdem mit ✖.
|
||||
# Rot durch kaputten Code ist kein Testbeleg (2026-10-27): pytest meldet einen
|
||||
# Ladefehler als ERROR ohne FAILED, node:test bricht alle Tests ab und markiert sie
|
||||
# trotzdem mit ✖.
|
||||
LOAD_ERRORS = (
|
||||
"SyntaxError",
|
||||
"IndentationError",
|
||||
|
|
@ -99,10 +104,11 @@ def _load_error(text: str) -> str | None:
|
|||
|
||||
|
||||
def _failure_report(output: str, failed: list[str]) -> str:
|
||||
# Nur der Fehlerbericht, nicht der ganze Lauf: Logs der App sind kein Ladefehler (Selftest
|
||||
# 2026-10-27: Express loggt den JSON-SyntaxError von body-parser beim Test mit "{kaputt").
|
||||
# node:test: Abschnitt "✖ failing tests:", TAP: die YAML-Blöcke unter "not ok" (App-Logs
|
||||
# stehen dort als "# ..." außerhalb), pytest/unittest: die Fehlerzeilen selbst.
|
||||
# Nur der Fehlerbericht, nicht der ganze Lauf: Logs der App sind kein Ladefehler
|
||||
# (Selftest 2026-10-27: Express loggt den JSON-SyntaxError von body-parser beim
|
||||
# Test mit "{kaputt"). node:test: Abschnitt "✖ failing tests:", TAP: die YAML-Blöcke
|
||||
# unter "not ok" (App-Logs stehen als "# ..." außerhalb), pytest/unittest: die
|
||||
# Fehlerzeilen selbst.
|
||||
_, sep, tail = output.partition("✖ failing tests:")
|
||||
if sep:
|
||||
return tail
|
||||
|
|
@ -155,9 +161,11 @@ def run(config_path: Path) -> int:
|
|||
print(f"[ÜBERLEBT] {name}: Tests bleiben grün")
|
||||
survivors.append(name)
|
||||
elif load_error or not failed:
|
||||
# Ohne Fehlerzeile (pytest: nur ERROR beim Sammeln) den Grund aus dem ganzen Lauf nennen.
|
||||
# Ohne Fehlerzeile (pytest: nur ERROR beim Sammeln): Grund aus ganzem Lauf
|
||||
load_error = load_error or _load_error(output)
|
||||
why = f"Ladefehler ({load_error})" if load_error else "kein Testfehler erkennbar"
|
||||
why = "kein Testfehler erkennbar"
|
||||
if load_error:
|
||||
why = f"Ladefehler ({load_error})"
|
||||
print(f"[UNGÜLTIG] {name}: Tests rot, aber {why}, kein Testbeleg.")
|
||||
print(" Mutation so ändern, dass der Code lauffähig bleibt:")
|
||||
print(output[-800:])
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue