Code-Erzwingung
Übersicht
Ein Guard wird daran gemessen, was er ablehnt, wenn jemand versucht, ihn zu umgehen, nicht daran, ob er seinen Happy Path besteht. Die beiden Fehlermodi, die eine Überprüfung überleben, sind eine Kontrolle, die eine Repräsentation des gefährlichen Werts anstelle des Werts selbst inspiziert, und eine Kontrolle, die Erfolg zurückgibt, weil sie nicht ausgeführt werden konnte. Beide erscheinen in jedem Test, der auf den eigenen Annahmen des Autors basiert, grün.
Verwendung
Befolge die folgenden Schritte, wenn du einen Hook, einen Guard, einen Validator, eine Berechtigungsprüfung, eine Lint-Regel oder ein CI-Tor schreibst oder änderst – bevor du die Datei öffnest, da Schritt 1 oft ändert, wo der Code hingehört.
Typische Fälle: "Blockiere rm -rf außerhalb des Repositorys" (Schritt 1 verlagert die Entscheidung vom Befehlsstring), "Lasse CI fehlschlagen, wenn eine Migration kein Rollback hat" (Schritte 3 und 4 verhindern, dass das Gate bestanden wird, wenn die Migrationsliste leer zurückkommt), "Verweigere einen Push ohne signierten Commit" (Schritt 5 zählt den Alias, das --no-verify und den zweiten Remote auf).
Schritte
- Benenne die Senke. Schreibe den genauen Wert auf, der das erreicht, was du schützt: das erweiterte argv, den Anforderungstext, den SQL-Parameter, den aufgelösten Pfad. Validiere diesen Wert.
- Prüfe, ob du ihn tatsächlich sehen kannst. Wenn der Code nur eine Repräsentation des Werts hat – einen Shell-Befehlsstring, einen Diff, eine Log-Zeile, eine Commit-Nachricht – ist die Entscheidung eine Heuristik, keine Prüfung. Sage dies in einem Kommentar und in der Liefernotiz, und kennzeichne diese Ebene als beratend. Lasse nicht zu, dass eine Heuristik die einzige Barriere für eine Konsequenz ist, die du nicht rückgängig machen kannst.
- Schlage standardmäßig fehl. Fehlende Laufzeit, nicht lesbare Eingabe, Parser-Ausnahme, unaufgelöste Variable, leeres Ergebnis: Verweigere, und benenne, was gefehlt hat. Ein Guard, der mit 0 beendet, weil er nicht ausgeführt werden konnte, ist ein deaktivierter Guard, und er bleibt monatelang still deaktiviert.
- Halte den Fehler der Sonde sichtbar. Kein
2>/dev/nullbei dem Befehl, der entscheidet, ob der Guard ausgeführt werden kann, und kein Zweig, der ein leeres Ergebnis in Erfolg umwandelt. Wenn die Sonde stillschweigend fehlschlagen darf, ist Schritt 3 nicht durchsetzbar. - Zähle die Umgehungen auf, bevor du die Korrektur schreibst. Liste auf, wie die Kontrolle erfüllt oder umgangen werden kann: zusammengesetzter Befehl, doppelte Flags, ein zweiter Aufruf, ein Alias oder eine Funktion, ein fehlender Interpreter, ein anderer Host, eine Subshell, eine umbenannte Datei. Behalte die Liste im Commit-Text oder in der Testdatei.
- Wandle jeden Eintrag dieser Liste in einen Testfall um, der in die automatisierten Prüfungen des Projekts eingebunden ist. Ein manueller Selbsttest zählt nicht: Er verschwindet mit der Sitzung, die ihn ausgeführt hat.
- Wenn eine Umgehung billig ist und ihre Konsequenz real, führe einen adversarischen Durchlauf durch. Beauftrage einen Subagenten mit neuem Kontext, dessen Aufgabe es ist, den Guard zu brechen, nicht ihn zu überprüfen; seine Ausgabe ist die Liste der Versuche und ihrer Ergebnisse. Überspringe dies für eine Kontrolle, deren schlimmster Fall eine Warnung ist.
Fallstricke
- Analysieren eines Shell-Befehls, um zu entscheiden. Anführungszeichen,
$(),&&, Aliase undenv-Präfixe ändern alle, was letztendlich ausgeführt wird. Eine solche Schicht ist eine Bremsschwelle; die eigentliche Prüfung gehört dorthin, wo die Wirkung des Befehls landet. command -v-Guards.if command -v tool > /dev/null; then check; fiüberspringt die Prüfung stillschweigend auf jedem Rechner, dem das Tool fehlt – genau dem Rechner, der es am meisten braucht. Kehre es um: Verweigere, wenn das Tool fehlt.- Ein Erkennungsschritt, der nichts findet.
git grep -Eunterstützt kein\b, daher findet ein solches Muster null Dateien ohne Fehler, und das Gate besteht, ohne etwas gelesen zu haben. Schütze den Schritt mit einem Kanarienvogel: einer Datei, von der du weißt, dass sie in seiner Ausgabe erscheinen muss. - Nur die Ablehnung testen, die du implementiert hast. Der interessante Test ist die Eingabe, an die du nicht gedacht hast; das ist es, was Schritt 5 produziert.
- Ein Guard, der nur von Hand getestet wird. Er besteht auf dem Rechner des Autors und fault dann. Wenn das Projekt keinen Ort hat, um den Test einzubinden, ist diese fehlende Testinfrastruktur Teil der Arbeit.
- Der Kontext, der den Guard geschrieben hat, kann ihn nicht brechen. Er teilt die blinden Flecken, die das Loch erzeugt haben, und wird sein eigenes Design bestätigen. Nur ein neuer Kontext ist adversarisch.
Einschränkungen
- Entscheide niemals über einen Proxy für den geschützten Wert, wenn der Wert selbst erreichbar ist.
- Beende niemals mit 0 auf einem Pfad, auf dem der Guard seine Aufgabe nicht erfüllen konnte; verweigere und nenne die Ursache.
- Unterdrücke niemals die Fehler der Sonde, die feststellt, ob der Guard ausgeführt werden kann.
- Jede aufgezählte Umgehung muss vor der Auslieferung als automatisierter Test existieren.
- Gib klar an, welche Schicht beratend und welche erzwingend ist; eine Heuristik, die als Garantie präsentiert wird, ist schlechter als kein Guard.