fix(security): mutation_check ohne veralteten Bytecode
Gleich lange Mutationen (z. B. extra="forbid" -> "ignore") liefen mit altem .pyc, weil Python den Cache nur über mtime in Sekunden und Größe prüft. Jetzt PYTHONDONTWRITEBYTECODE und Cache-Löschung nach jedem Schreiben (cj/security-baseline). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
ee117958b3
commit
a20b6230db
1 changed files with 17 additions and 4 deletions
|
|
@ -22,11 +22,24 @@ Format (Pfade relativ zur TOML-Datei):
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import os
|
||||||
import subprocess # nosec B404 - Tests starten ist der Zweck des Skripts
|
import subprocess # nosec B404 - Tests starten ist der Zweck des Skripts
|
||||||
import sys
|
import sys
|
||||||
import tomllib
|
import tomllib
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
# Python prüft .pyc nur über Quell-mtime (Sekunden) und Größe. Eine gleich lange Mutation,
|
||||||
|
# die in derselben Sekunde geschrieben oder zurückgesetzt wird, liefe sonst mit dem alten
|
||||||
|
# Bytecode: Mutation wirkt nicht bzw. bleibt nach dem Lauf aktiv (llm-server, 2026-10-17).
|
||||||
|
TEST_ENV = {**os.environ, "PYTHONDONTWRITEBYTECODE": "1"}
|
||||||
|
|
||||||
|
|
||||||
|
def _write(target: Path, text: str) -> None:
|
||||||
|
target.write_text(text, encoding="utf-8")
|
||||||
|
if target.suffix == ".py":
|
||||||
|
for pyc in (target.parent / "__pycache__").glob(f"{target.stem}.*.pyc"):
|
||||||
|
pyc.unlink(missing_ok=True)
|
||||||
|
|
||||||
|
|
||||||
def run(config_path: Path) -> int:
|
def run(config_path: Path) -> int:
|
||||||
base = config_path.parent
|
base = config_path.parent
|
||||||
|
|
@ -39,7 +52,7 @@ def run(config_path: Path) -> int:
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
# Vorbedingung: ohne Mutation muss alles grün sein, sonst beweist Rot nichts.
|
# Vorbedingung: ohne Mutation muss alles grün sein, sonst beweist Rot nichts.
|
||||||
baseline = subprocess.run(test_cmd, cwd=workdir, capture_output=True, text=True) # noqa: S603 # nosec B603
|
baseline = subprocess.run(test_cmd, cwd=workdir, capture_output=True, text=True, env=TEST_ENV) # noqa: S603 # nosec B603
|
||||||
if baseline.returncode != 0:
|
if baseline.returncode != 0:
|
||||||
print("Tests sind schon ohne Mutation rot – erst reparieren.\n")
|
print("Tests sind schon ohne Mutation rot – erst reparieren.\n")
|
||||||
print(baseline.stdout[-3000:])
|
print(baseline.stdout[-3000:])
|
||||||
|
|
@ -55,10 +68,10 @@ def run(config_path: Path) -> int:
|
||||||
survivors.append(mutation["name"])
|
survivors.append(mutation["name"])
|
||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
target.write_text(original.replace(mutation["old"], mutation["new"]), encoding="utf-8")
|
_write(target, original.replace(mutation["old"], mutation["new"]))
|
||||||
result = subprocess.run(test_cmd, cwd=workdir, capture_output=True, text=True) # noqa: S603 # nosec B603
|
result = subprocess.run(test_cmd, cwd=workdir, capture_output=True, text=True, env=TEST_ENV) # noqa: S603 # nosec B603
|
||||||
finally:
|
finally:
|
||||||
target.write_text(original, encoding="utf-8")
|
_write(target, original)
|
||||||
if result.returncode == 0:
|
if result.returncode == 0:
|
||||||
print(f"[ÜBERLEBT] {mutation['name']}: Tests bleiben grün")
|
print(f"[ÜBERLEBT] {mutation['name']}: Tests bleiben grün")
|
||||||
survivors.append(mutation["name"])
|
survivors.append(mutation["name"])
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue