Post-Patch-Validierung
Validiere einen Sicherheitspatch gegen den gemeldeten Fehler und den umgebenden Code, den er beeinflusst. Gib dem Patch-Autor reproduzierbare Fehler zur Behebung und identifiziere, was noch getestet werden muss. Wende dieselben Prüfungen auf menschliche und auf Agenten-Patches an. Der Diff, der Autor, die upstream-Implementierung und der originale Proof-of-Concept allein können keine Korrektheit sicherstellen.
Wann zu verwenden
- Ein Sicherheitsfix, ein Remediation-Commit, eine Patch-Datei oder ein Pull-Request existiert bereits.
- Ein KI-generierter Patch benötigt vor der menschlichen Überprüfung oder dem Merge eine Validierung.
- Ein Fix deckt möglicherweise einen Exploit-Pfad ab, während Varianten derselben Grundursache übersehen werden.
- Ein Sicherheitsfix könnte legitimes Verhalten ändern oder eine neue Sicherheitslücke einführen.
- Ein Patch-Autor benötigt konkrete Fehler und Abdeckungslücken vor einer weiteren Überarbeitung.
Wann NICHT zu verwenden
- Es existiert noch kein Patch; verwende zuerst Schwachstellenfindung oder Fix-Implementierung.
- Die Aufgabe besteht darin, einen Audit-Fund gegen einen Bericht zu prüfen, ohne Patch-Beweise auszuführen.
- Die Aufgabe besteht nur darin, einen Fund in einen dauerhaften Projekt-Test zu überführen.
- Das Ziel ist remote oder Produktion. Dieses Skill führt nur lokalen Code und Tests aus.
- Der Benutzer hat die Ausführung des Repository-Codes oder der Testsuite nicht autorisiert.
Schnellstart
-
Fixiere die verwundbare Basis und den gepatchten Input. Bevorzuge immutable Commits. Für nicht committete Arbeit erstelle zuerst eine binäre Patch-Datei; validiere nicht im Arbeitsverzeichnis des Benutzers.
-
Erstelle einen fixierten Plan:
uv run {baseDir}/scripts/post_patch_validation.py scaffold \ --repo . \ --base-ref <vulnerable-ref> \ --patched-ref <patched-ref> \ --finding-id <stable-id> \ --finding-summary "<Root Cause und Impact>" \ --evidence-level runtime \ --output post-patch-validation/plan.jsonVerwende
--patch-file <path>anstelle von--patched-reffür ein Patch-Artefakt. Wähle die höchste ehrliche Evidenzstufe:sourcenur für Source-/Patch-Invarianten,build, wenn der Zielcode kompiliert oder analysiert wird, aber das gemeldete Verhalten nicht ausgeführt wird, oderruntime, wenn die Prüfungen das gemeldete Verhalten und seine Sicherheitszusicherungen ausführen. -
Prüfe den Fund, den Diff, die Aufrufer, verwandte Pfade, Bereinigungs-/Fehlerpfade und vorhandene Tests. Befülle
checksim generierten Plan. Führeprint-schemafür das strukturelle Schema aus:uv run {baseDir}/scripts/post_patch_validation.py print-schema -
Führe
validate-planfür die vollständige Validierung aus, einschließlich Abdeckung, Befehlseinschränkungen und fixierten Inputs, bevor Code ausgeführt wird:uv run {baseDir}/scripts/post_patch_validation.py validate-plan \ --plan post-patch-validation/plan.json -
Führe den Evidenzplan aus:
uv run {baseDir}/scripts/post_patch_validation.py run \ --plan post-patch-validation/plan.json \ --output post-patch-validation/results -
Berichte
result.json,report.md, die Evidenzstufe und die vollständigeassessment. Gib jeden Fund mit seiner Check-ID, Zusicherung und gespeicherten Logs an den Patch-Autor zurück. Identifiziere jede Validierungslücke separat, einschließlich Lücken, die neben bestätigten Funden bestehen. Nachdem der Autor den Patch überarbeitet hat, fixiere die neuen Inputs und führe eine frische Validierung durch. Behalte die vorherigen Beweise. Bestandene Checks erfordern dennoch eine menschliche Überprüfung vor der Annahme.
Evidenz-Contract
Der Runner lehnt unvollständige Pläne ab. Gib mindestens einen Check jeder Art an:
| Art | Erforderliche Beobachtung |
|---|---|
control | Harmlose Harness erfolgreich auf Basis und Patch |
exploit | Originale Sicherheitszusicherung schlägt auf Basis fehl und gelingt auf Patch |
variant | Eine andere Variante der Grundursache schlägt auf Basis fehl und gelingt auf Patch |
behavior | Unverändertes Verhalten gelingt mit byteidentischer ausgewählter Ausgabe |
regression | Gezielte nicht-Sicherheits-Regressionsprüfung gelingt auf beiden Revisionen |
security | Angrenzende/neue Sicherheitsprüfung gelingt auf Basis und Patch |
suite | Bestehende Projekt-Suite, Sanitizer oder deterministische Fuzz-Kampagne gelingt auf Patch |
Befehle sind argv-Arrays, niemals Shell-Strings. Komplexe Einrichtung in ein eingechecktes oder Plan-Artefakt-Skript auslagern und mit {plan_dir} aufrufen. Der Runner setzt locale/timezone/hash-seed Inputs fest, führt Checks in lexikografischer ID-Reihenfolge aus, zeichnet rohes stdout/stderr auf und bearbeitet niemals das originale Arbeitsverzeichnis. Der timeout_seconds jedes Checks beträgt standardmäßig 300 und akzeptiert ganze Zahlen von 1 bis 3600. Überschreiten des Timeouts hinterlässt eine Validierungslücke. Ein Timeout allein begründet keine Regression. Jeder Plan enthält auch ein sortiertes submodules-Array ([], wenn keine). Das Scaffolding leitet betroffene Gitlinks aus dem Inventory geänderter Dateien ab. Der Runner initialisiert diese fixierten Commits aus den existierenden Git-Modul-Objekten des Quell-Repositorys, niemals aus .gitmodules-Netzwerk-URLs; initialisiere oder lade sie im Quell-Repository herunter, bevor die Validierung gestartet wird.
Exploit- und Variant-Checks müssen ihre Ausführung beweisen
Ein Exit-Code ungleich Null bedeutet nicht, dass die Schwachstelle reproduziert wurde. Ein Importfehler, ein fehlgeschlagener Build, eine fehlende Abhängigkeit und eine fehlgeschlagene Sicherheitszusicherung beenden alle mit einem Code ungleich Null und sind für den Runner nicht unterscheidbar. Jeder exploit- und variant-Check muss PPV_REACHED unmittelbar vor der Auswertung seiner Zusicherung auf beiden Revisionen ausgeben und leeren:
"argv": ["python3", "-c", "import app; value = app.render('<'); print('PPV_REACHED', flush=True); assert value == '<'"]
Das Token ist auch in der Umgebung als PPV_REACHED_MARKER vorhanden. Es muss auf stdout als eigene Zeile erscheinen. Stderr wird nicht gescannt, da ein Python-SyntaxError-Traceback die fehlerhafte Quelle ausgibt und sonst den Check für eine Harness, die nichts ausgeführt hat, erfüllen würde. Ein Lauf ohne dieses Token hinterlässt eine marker_missing-Lücke. Unabhängige Funde aus anderen Checks bleiben im Ergebnis. Leere explizit: Eine Harness, deren Payload segfaulted oder _exit aufruft, verliert gepufferte Ausgabe und damit ihre eigenen Beweise.
Diese Checks laufen auch side-blind. {side} wird für sie nicht expandiert, PPV_SIDE fehlt in ihrer Umgebung, das Checkout-Verzeichnis ist zufällig benannt, und der Plan-Validator lehnt jeden exploit- oder variant-Check ab, dessen argv oder env eines davon erwähnt. Eine Zusicherung, die sehen kann, auf welcher Revision sie läuft, könnte auf das statt auf den Code zusichern – der billigste Weg, eine Reproduktion mit anschließendem Fix vorzutäuschen.
Umgebung
Checks laufen mit einer festgelegten minimalen Umgebung: PATH, HOME und einigen temporären/Benutzer-Schlüsseln, plus LANG/LC_ALL=C, TZ=UTC, PYTHONHASHSEED=0, NO_COLOR, TERM=dumb. Alles andere in der Umgebung des Aufrufers wird verworfen. Toolchains, die mehr benötigen, bekommen es explizit:
uv run {baseDir}/scripts/post_patch_validation.py run \
--plan post-patch-validation/plan.json \
--output post-patch-validation/results \
--allow-env JAVA_HOME --allow-env CARGO_HOME
Weitergeleitete Namen und Werte werden in result.json aufgezeichnet. Eine angeforderte Variable, die nicht gesetzt ist, ist ein Fehler, kein leerer String. Zwei Klassen werden kategorisch abgelehnt: Namen, die wie Anmeldeinformationen aussehen (*SECRET*, *TOKEN*, *API_KEY*, …), da der Wert in das Ergebnis geschrieben würde; und Namen, die ändern, was ausgeführt wird (LD_PRELOAD, BASH_ENV, NODE_OPTIONS, GIT_SSH_COMMAND, …), da diese Variablen ändern können, welcher Code ausgeführt wird.
Die festen Variablen des Runners und alle PPV_*-Namen sind ebenfalls reserviert und können nicht weitergeleitet werden.
In argv und pro-Check env-Werten expandierte Platzhalter: {checkout} (die zu testende Revision), {plan_dir} (eine isolierte Kopie der Plan-Artefakte für diesen einen Aufruf), {scratch} (ein frisches, undurchsichtiges Verzeichnis für diesen einen Check-Aufruf) und {side} (base oder patched, nicht verfügbar für exploit/variant-Checks). Dieselben Werte kommen als PPV_CHECKOUT, PPV_PLAN_DIR, PPV_SCRATCH, PPV_SIDE und PPV_CASE_ID. Schreibe nur unter {scratch}; der Pfad zum Evidenzverzeichnis wird nicht an Checks übergeben. Basis- und Patch-Aufrufe teilen keine vom Runner verwalteten Scratch-, Plan- oder Worktree-Roots. Nachdem jeder Aufruf beendet ist, wird sein Scratch-Baum unter dem deterministischen Pfad results/scratch/<check-id-and-side> archiviert, seine private Plan-Kopie wird verworfen, und jedes lesbare argv-Element, das zu einer Datei aufgelöst wird, wird in argv_files gehasht. Dateien innerhalb der isolierten Plan- oder Checkout-Roots werden zusätzlich unter results/helpers/<sha256> bis zu 16 MiB aufbewahrt; der Eintrag erklärt, warum andere Dateien nicht archiviert wurden. Verwende ein dediziertes Verzeichnis für plan.json: seine Geschwisterdateien und -verzeichnisse werden in jeden {plan_dir}-Aufruf kopiert. Halte Hilfscode unter dem checks/-Verzeichnis dieses Verzeichnisses oder eingecheckt im Ziel-Repository, damit seine Bytes überprüfbar sind. Der Maschinenplan, der Commit-Pins, das aktuelle Ausgabeverzeichnis und erkannte vorherige Ergebnisbäume enthält, wird ausgeschlossen; Symlinks werden abgelehnt. Der saubere Snapshot bleibt nur im Runner-Speicher, und Exploit-/Variant-Seiten werden in zufälliger Reihenfolge ausgeführt, während Beweisdaten-Dateinamen deterministisch bleiben. Stdout/stderr verwenden anonyme oder zufällig benannte Capture-Deskriptoren und werden erst nach Beenden des Kindprozesses in die benannten Beweisdaten-Dateien kopiert, sodass fd-Inspektion das Seitenlabel nicht preisgeben kann.
Diese Isolation ist kein Host-Sandbox: Checks laufen mit den Rechten des Aufrufers, und eine bösartige Hilfskomponente könnte beliebige externe Zustände verwenden oder bewusst die Revision aus Source- oder Git-Metadaten ableiten. Überprüfe die inhaltsadressierten Hilfsartefakte und verwende ein OS/Container-Sandbox, wenn der Check-Code selbst nicht vertrauenswürdig ist.
Aktive Validierungs-Worktrees sind mit zufälligen Owner-Tokens, die durch Kernel-Dateisperren abgesichert sind, Git-gesperrt, sodass ein anderer gleichzeitiger Validator sie nicht löschen kann und PID-Wiederverwendung keinen Owner vortäuschen kann. Wird der Runner gewaltsam beendet, entsperrt der nächste Lauf veraltete, vom Validator gehaltene Registrierungen. Zur manuellen Wiederherstellung prüfe git worktree list und verwende dann git worktree unlock <path> und git worktree remove --force <path> (oder git worktree prune, nachdem der Pfad entfernt wurde).
Lies evidence-model.md beim Entwerfen der Abdeckung, Auswählen von Varianten oder Interpretieren von Funden und Validierungslücken. Lies es nicht für die routinemäßige CLI-Ausführung.
Abdeckungsregeln
- Leite Varianten aus der Grundursache ab, nicht aus kosmetischen Mutationen des ursprünglichen Payloads.
- Zähle verwandte Aufrufstellen, alternative Callbacks/Ausgaben, Fehlerpfade, Teardown, Ownership, Serialisierung und Grenzwerte auf, die von der Korrektur berührt werden.
- Jeder Exploit- oder Variant-Test muss das sichere Verhalten zusichern. Er muss auf der verwundbaren Basis fehlschlagen; ein Test, der auf beiden Revisionen bestanden wird, beweist nichts zur Behebung. Lies das stderr der Basis-Seite und bestätige, dass der Fehler die von dir geschriebene Zusicherung ist, nicht eine Harness, die nie dort angekommen ist.
- Halte Exploit- und Variant-Zusicherungen auf die Sicherheitsinvariante beschränkt. Teste Lebendigkeit, genaue Fehlertypen/-meldungen, Timing und Kompatibilität separat als
behavior- oderregression-Checks; andernfalls kann eine unzusammenhängende Vertragsänderung als Beweis dafür getarnt werden, dass die Schwachstelle noch besteht. - Halte die
control-Harness harmlos und lasse sie die geänderte Komponente durchlaufen. Sie stellt sicher, dass die Harness auf beiden Revisionen funktioniert. Fehlgeschlagene Controls hinterlassen Lücken und verhindern, dass andere Fehler dem Patch zugeschrieben werden. Die rohen Beobachtungen bleiben zur Überprüfung verfügbar. - Verwende
behaviornur für Verhalten, das unverändert bleiben sollte. Exakter Ausgabevergleich ist beabsichtigt; verschiebe instabile Werte hinter eine deterministische Test-Harness, anstatt sie in Prosa zu normalisieren. - Mache
security-Checks so, dass sie auf der verwundbaren Basis bestanden werden, bevor ein Patch-Fehler als neu eingeführt gewertet wird. Eine fehlgeschlagene Baseline lässt die Zuordnung ungelöst. - Bearbeite den Patch während der Validierung nicht. Gib Fehler an den Patch-Autor zurück und starte einen neuen, frisch fixierten Lauf.
Lesen des Ergebnisses
result.json Schema 2.0 enthält ein assessment mit status, findings, gaps und human_review_required. Status ist complete, wenn alle erforderlichen Checks verwertbare Beweise geliefert haben, auch wenn einige Checks Fehler gefunden haben. Status ist incomplete, wenn noch Lücken bestehen. Findings nennen die Check-ID, die Check-Art und die fehlgeschlagene Erwartung. Gaps nennen die Check-ID und die fehlenden Beweise, mit einer null Check-ID für Probleme auf Run-Ebene wie Bereinigungsfehler.
Suite-Checks laufen zuerst auf der Patch-Revision. Ein abgeschlossener Fehler löst denselben Check auf der Baseline aus. Wenn die Baseline bestanden wird, melde den Fehler nach dem Patch. Wenn beide fehlschlagen, behalte beide Logs und melde, dass die Zuordnung ungelöst ist. Gehe nicht davon aus, dass übereinstimmende Exit-Codes denselben Fehler bedeuten.
Der Runner beendet sich mit 0 für vollständige Checks ohne Funde, 1 für vollständige Checks mit Funden, 10 für unvollständige Validierung und 64 für ungültige Eingaben. Lies das Artefakt auch nach Exit 10: Es kann bestätigte Funde neben Lücken enthalten. Source- oder Build-Beweise können kein Laufzeitverhalten belegen. Gib die Evidenzstufe zusammen mit jedem bestandenen Ergebnis an.
Claude Dynamic Workflow
Claude Code stellt den gebündelten Workflow als /post-patch-validation:validate-patch bereit.
Um strukturierte Eingaben durch das Workflow-Tool zu übergeben, verwende den Namen ohne führenden Schrägstrich:
Workflow({
name: 'post-patch-validation:validate-patch',
args: {
finding: '<Finding-Text oder lokaler Pfad>',
baseRef: '<vulnerable-ref>',
patchRef: '<patched-ref>',
workdir: 'post-patch-validation',
},
})
Verwende patchFile anstelle von patchRef, wenn angemessen. Der Workflow verwendet feste Abdeckungslinsen, um Checks vorzuschlagen, und einen festen Executor, um dieses Skill auszuführen. Agenten dürfen Test-Artefakte verfassen. Der Python-Runner zeichnet Funde und Lücken auf, und Prüfer melden Abdeckungs- oder Beweisbedenken separat. NEEDS_REPAIR gibt bestätigte Fehler zurück, auch wenn andere Checks Lücken hinterlassen haben. BLOCKED bedeutet, dass die Beweise ohne einen bestätigten Fehler unvollständig sind. Bestandene Checks gelangen nur dann zu READY_FOR_HUMAN_REVIEW, wenn beide Beweisprüfungen zustimmen, andernfalls REVIEW_REQUIRED. Der Workflow kann nach dem Start keine Fragen stellen, daher gib alle Eingaben vorab an.
Zu verwerfende Rationalisierungen
| Rationalisierung | Erforderliche Neubewertung |
|---|---|
| "Die andere Seite des Diffs ist die gleiche" | Beweise für side-blind control, exploit, variant, baseline |
| "Es ist nur eine kleine Änderung" | Vollständige check-Matrix |
| "Der Autor hat bereits getestet" | Unabhängige, reproduzierbare Bestätigung |
| "Das kann nicht reproduziert werden" | Detaillierte Prüfumgebung, Infrastructure-as-Code |
| "Die CI hat bestanden" | CI deckt selten gezielte Sicherheitsinvarianten, Varianten oder Regressionen ab |
| "Es funktioniert auf meinem Rechner" | Isolierte, deterministische, fixierte Umgebung |
| "Das ist ein Refactoring, keine Sicherheitsänderung" | Sicherheitsprüfung, die die Code-Änderung auf jede Auswirkung prüft |
| "Der Exploit ist zu einfach/künstlich" | Der Exploit beweist die Sicherheitslücke; der Patch macht ihn unwirksam |
Fehlerbehebung
Stelle beim Ausführen von validate-plan sicher, dass --plan auf den generierten Plan verweist. Das scaffold-Skript erfordert, dass das Repository bereits vorhanden ist. Für ein neues Repository klone zuerst mit git clone <url> .. Wenn das Base-Ref oder Patched-Ref nicht gefunden werden kann, überprüfe, ob sie gültige Git-Referenzen sind und ob das Repository Zugriff auf die relevanten Remotes hat. Verwende git fetch --all bei Bedarf.
Verwende für Plan-Artefakte (z. B. Hilfsskripte) ein separates Verzeichnis unter post-patch-validation/ und referenziere sie mit {plan_dir}/helper.sh. Stelle sicher, dass alle Hilfsskripte ausführbar sind (chmod +x), wenn sie direkt ausgeführt werden.
Wenn der Lauf unerwartet fehlschlägt, überprüfe das result.json auf genaue Fehlermeldungen. Häufige Probleme sind: fehlende Abhängigkeiten, Timeouts (erhöhe timeout_seconds auf bis zu 3600) oder falsche argv-Definitionen (denke daran, ein Array zu verwenden, keinen String). Die run-Ausgabe wird im Verzeichnis post-patch-validation/results/ gespeichert.
Lies für die Integration in CI/CD die CI/CD-Beispiele im Abschnitt [Erweiterte Nutzung].