25. Testsuite¶
Pepsi liefert unter tests/ eine End-to-End-Testsuite, die eine Live-Installation über SMTP ausübt und das beobachtbare Verhalten der gesamten Pipeline prüft, statt einer einzelnen Funktion isoliert. Sie ist bewusst eine Black-Box-Suite: Nachrichten werden mit dem gewöhnlichen mail-Befehl oder per rohem SMTP gesendet, und die Prüfungen lesen die Postfächer der Empfänger und die Tabelle pepsi.workqueue.
Dies ergänzt — ersetzt aber nicht — die Unit-Tests im Baum (cargo test --workspace), die die reine Logik (SRS, MIME-Herabstufung, DSN-Konstruktion, Sprachbewertung, DNS-Klassifizierung, …) ohne Netzwerk abdecken.
Zwei Dinge liegen dazwischen und werden von Integrationstests abgedeckt, die weder ein Netzwerk noch eine Datenbank benötigen. Die Migrations-Suiten (pepsi-setup/tests/import_*.rs und tests/cli_import.rs) lassen jeden MTA-Importer gegen einen Fixture-/etc-Baum laufen und führen dann das echte pepsi-setup-Binärprogramm Ende zu Ende aus, bis hin zu einem --wizard --import, das eine Konfiguration erzeugen muss, die Pepsis eigene Validierung besteht; siehe das Kapitel zum Erweitern für deren Aufbau. Die Dispatcher-Lebenszyklus-Suite (pepsi-test-stages) benötigt ein PostgreSQL und wird von make check ausgeführt.
25.1. make check: die Schranke ohne entfernte Konten¶
make check ist der Einstiegspunkt für alles, was keine echten Mail-Konten braucht. Der Reihe nach führt es aus:
make check-telemetry-socketundmake check-systemd-units—tests/check-telemetry-socket.shundtests/check-systemd-units.sh, Konsistenzprüfungen über die systemd-Units und die Debian-Paketierung, die keine Installation benötigen und nie überspringen.cargo test --workspace --exclude pepsi-test-stages --locked— jeden datenbankfreien Test im Baum. (Ein blankescargo test --workspacewürdepepsi-test-stageseinschließen und daher eine Datenbank benötigen; bevorzugen Siemake check, das jene Suite an eine Bedingung knüpft, statt an ihr zu scheitern.)tests/check-lifecycle.sh— die Dispatcher-Lebenszyklus-Suite, nach bestem Bemühen.tests/maildir-writer-suid.sh,tests/dot-forward-suid.shundtests/whitelist-suid.sh— die Verträge der setuid-/setgid-Helper, nach bestem Bemühen.tests/interop-auth.sh— eine DKIM/ARC-Prüfung über Implementierungen hinweg, nach bestem Bemühen. Pepsis eigene Round-Trip-Tests signieren und verifizieren mit derselbenmail-auth-Bibliothek und können daher keine Transformation erkennen, die darin durchgängig falsch ist; dieses Skript bewertet von Pepsi signierte Nachrichten (alle vierc=-Kombinationen, dazu eine manipulierte Kopie, die abgelehnt werden muss, dazu ein ARC-Siegel) mit zwei unabhängigen Implementierungen, ganz ohne DNS. dkimpy erhält die öffentlichen Schlüssel über seinednsfunc(tests/interop-verify.py) und bewertet DKIM und die ARC-Kette; OpenDKIM liest sie im-t-Testmodus desopendkim-Filters aus einerTestPublicKeys-Datei und bewertet DKIM (es hat keinen ARC-Verifizierer;opendkim-testmsgist nicht verwendbar, weil es nur gegen Live-DNS verifiziert). JedeDKIM-Signaturewird bewertet, die RSA- und die Ed25519-Signatur — dkimpy braucht für Letztere PyNaCl. Jeder Verifizierer überspringt (SKIP) seine eigenen Prüfungen, wenn er fehlt, und das Skript überspringt als Ganzes, wenn beide fehlen. Unter Debian:apt install python3-dkim python3-nacl opendkim(der Filter liegt in/usr/sbin; setzen SieOPENDKIM, wenn er anderswo liegt, und deaktivieren Sie denopendkim-Dienst, den das Paket aktiviert — der Test spricht nie mit ihm).PEPSI_INTEROP_REQUIRE=1macht aus einem fehlenden Verifizierer einen Fehlschlag.cargo deny check— Advisories, Verbote, Lizenzen und Quellen. Dieses ist nicht nach bestem Bemühen: Es wird nur übersprungen, wenncargo-denywirklich nicht installiert ist, und ein echter Befund lässt das Ziel fehlschlagen. Lesen Siedeny.toml, bevor Sie der Schranke trauen: Seineignore-Liste ist nicht leer.make docs-linkcheck— jeder interne Querverweis des Handbuchs muss sich in jeder Sprache auflösen (ein Sphinx-dummy-Build mit Warnungen als Fehlern). Wird nur übersprungen, wennsphinx-buildnicht installiert ist.
Die Thunderbird-S/MIME-Interoperabilitätsschranke ist bewusst nicht in make check — sie startet ein echtes (kopfloses, von Marionette gesteuertes) Thunderbird und kostet etwa fünfzehn Sekunden. Sie ist make interop-thunderbird, und make integrationtests hängt von ihr ab.
25.1.1. Kontinuierliche Integration¶
Mehrere der obigen Schritte überspringen, wenn ein Werkzeug oder eine Datenbank fehlt — auf dem Rechner eines Entwicklers der richtige Standard und für einen automatisierten Lauf genau falsch, wo ein übersprungenes, grün gemeldetes Gate wie ein bestandenes aussieht. contrib/ci/ enthält Jobs in dem Layout, das der CI-Worker von GNU Taler ausführt (dasselbe, das vendor/taler-rust/contrib/ci/ verwendet): contrib/ci/ci.sh <job> baut das Image aus contrib/ci/Containerfile mit podman und führt darin contrib/ci/jobs/<job>/job.sh mit eingehängtem Quellbaum aus; contrib/ci/run-all-jobs.sh führt jeden Job der Reihe nach aus. Die Jobs sind:
1-gatesDie Gates zur Übersetzungszeit:
RUSTFLAGS="-D warnings" cargo build,cargo clippy … -D warningsundcargo fmt --check.2-checkmake checkmit jedem Best-Effort-Gate scharf geschaltet. Das Image enthält dkimpy, PyNaCl, OpenDKIM, cargo-deny und Sphinx, der Job startet PostgreSQL, setztPEPSI_INTEROP_REQUIRE=1und schlägt fehl, wenn irgendeine Zeile des Protokolls ein SKIP meldet.make checkläuft als unprivilegierter Benutzer auf einer privaten Kopie des Baums, so wie ein Entwickler es ausführt — daspepsi-setup runder Lifecycle-Suite würde sonst zu paketierten Systemkonten wechseln, die der Container nicht hat —, und die drei setuid/setgid-Suiten, die root benötigen, werden danach erneut als root ausgeführt; ihr Überspringen mit „not running as root“ im ersten Durchlauf ist das einzige akzeptierte Überspringen.CI_ALLOWED_SKIPS(ein erweiterter regulärer Ausdruck) benennt jedes weitere absichtlich akzeptierte Überspringen.3-docsmake docs-all: jede Sprache des Handbuchs einschließlich ihres PDFs, also der Build, der an einem nicht deklarierten Unicode-Zeichen scheitert.4-upgradeDer Schema-Upgrade-Test,
tests/check-upgrade.sh, gegen das vorherige Release-Tag (ohne Wirkung, solange es keines gibt): Er bautpepsi-setupundpepsi-statusdieses Releases, installiert dessen Schema und lädt dessen eingefrorene Fixture (tests/upgrade/), führt mit diesem Baum das Upgrade samt Sicherung durch und prüft, dass jede Zeile erhalten bleibt, die Sicherung sich wiederherstellen lässt, der Dispatcher dieses Baums die alte Warteschlange abarbeitet und das alte Release das aktualisierte Schema mit Exit-Status 78 ablehnt. Das Skript läuft auch außerhalb der CI, wenn man ihm die Programme und das SQL-Verzeichnis eines vorherigen Releases gibt.
Die Rust-Toolchain im Image ist festgenagelt (RUST_TOOLCHAIN im Containerfile), statt stable zu folgen, sodass ein neuer clippy-Lint einen unbeteiligten Commit nicht rot färben kann; heben Sie sie bewusst an. Die Jobs bauen nach target-ci/, damit sie das target/ eines Entwicklers nicht ungültig machen. Führen Sie einen Job lokal von der Wurzel des Baums aus, mit initialisiertem vendor/taler-rust-Submodul, z. B. contrib/ci/ci.sh 2-check.
25.1.2. Die Lebenszyklus-Suite und ihre Datenbank¶
pepsi-test-stages startet das echte pepsi-dispatch-Binärprogramm gegen ein echtes PostgreSQL und prüft die Zustände der pepsi.workqueue-Datensätze, benötigt also einen erreichbaren Server. Es hat zwei Datenbankmodi, gewählt durch PEPSI_TEST_DATABASE:
- nicht gesetzt — der Standardfall und der Entwicklungsablauf
Jeder Test legt seine eigene Wegwerf-Datenbank mit
CREATEan und entfernt sie mitDROP, sodass die Suite parallel läuft. Das tut ein blankescargo test -p pepsi-test-stages; die verbindende Rolle mussCREATE DATABASE/DROP DATABASEausführen können.- gesetzt (z. B.
pepsicheck) Alle Tests teilen sich diese eine bereits vorhandene Datenbank — nie angelegt, nie gelöscht, ihr Inhalt bleibt erhalten — und setzen beim Aufbau allein
pepsi.workqueuezurück. Die Suite muss dann mit--test-threads=1laufen.
tests/check-lifecycle.sh ist der zweite Modus, automatisiert: Es sucht nach einer pepsicheck-Datenbank (und legt sie an, wenn sie fehlt), setzt das Schema mit pepsi-setup run --reset zurück — nach einem vorangehenden blanken run, damit eine frisch angelegte Datenbank das _v-Schema hat, aus dem der Lösch-Schritt löscht — und führt die Suite seriell dagegen aus, wobei die Datenbank stehen bleibt. Funktionieren weder die Suche noch das Anlegen, überspringt es: Exit 0, was weder ein Bestehen noch ein Fehlschlag ist.
Vier Umgebungsvariablen justieren das alles:
PEPSI_TEST_DATABASEWählt den geteilten Modus und benennt die Datenbank. Nicht gesetzt bedeutet Wegwerf-Modus.
PEPSI_TEST_PGHOSTDas Socket-Verzeichnis für die lokale, peer-authentifizierte Verbindung. Standardwert
/var/run/postgresql.PEPSI_TEST_PGUSERDie Login-/Peer-Rolle, als die verbunden wird. Standardwert
$USER.PEPSI_TEST_DISPATCH_LOGAuf
1setzen, um die eigenen Logs des gestarteten Dispatchers zu sehen, die die Suite standardmäßig stummschaltet.
(tests/check-lifecycle.sh liest zusätzlich PEPSI_CHECK_DB, um die von ihm verwaltete geteilte Datenbank umzubenennen, Standardwert pepsicheck.)
Ein einzelner Test oder ein einzelnes Modul ist cargo test -p <crate> <name::filter>, z. B. cargo test -p pepsi-common srs::.
25.1.2.1. Die Tests der Privilegiengrenzen¶
Sechs Testdateien prüfen die Datenbankrechte aus Die Privilegientrennung gegen einen echten Server — service_role_grants, secure_link_grants, admin_grants, whitelist_grants, setup_task sowie die Rechtefälle in keystore und keydisc_lifecycle. Jede führt das produktive provision_roles aus und wechselt dann per SET ROLE in jedes Konto, um PostgreSQL zu fragen, was es tun darf.
Sie werden übersprungen (mit einer SKIPPED-Zeile auf stderr, sichtbar mit --nocapture), wenn irgendeine geprüfte Rolle ein Superuser ist, weil ein Superuser jedes Recht umgeht und sich über die Grenze nichts lernen lässt. Auf einem Entwicklungsrechner ist das der Normalfall: Das Konto, das die Tests ausführt, ist pepsi, das zugleich die eigene Rolle der Pipeline und meist auch der Superuser des Clusters ist. Um sie auszuführen, lassen Sie die Suite laufen, während pepsi vorübergehend kein Superuser ist, aber in die anderen Rollen wechseln kann — eingerichtet aus einer zweiten Superuser-Sitzung —, und stellen Sie es danach wieder her:
$ psql -U some_superuser -c "ALTER ROLE pepsi NOSUPERUSER CREATEDB CREATEROLE" \
-c 'GRANT "pepsi-ingress", "pepsi-httpd", "pepsi-telemetry", "pepsi-whitelist",
"pepsi-crypto", "pepsi-keydisc", "pepsi-config"
TO pepsi WITH INHERIT FALSE, SET TRUE'
$ cargo test -p pepsi-test-stages --test service_role_grants -- --nocapture
$ psql -U some_superuser \
-c 'REVOKE "pepsi-ingress", "pepsi-httpd", "pepsi-telemetry", "pepsi-whitelist",
"pepsi-crypto", "pepsi-keydisc", "pepsi-config" FROM pepsi' \
-c "ALTER ROLE pepsi SUPERUSER"
INHERIT FALSE ist wichtig: Damit kann pepsi jede Rolle annehmen, ohne ihre Privilegien zu erwerben, sodass die Prüfungen an pepsi selbst aussagekräftig bleiben.
Die End-to-End-Tests der Verwaltungs-API (admin_api) enthalten einen weiteren rollenabhängigen Fall: Der erfolgreiche CONFIG_DB-Schreibvorgang verbindet sich mit options[role]=pepsi-config und wird daher übersprungen (wieder mit einer SKIPPED-Zeile), wenn die Testrolle nicht SET ROLE "pepsi-config" ausführen kann. Dasselbe Recht wie oben lässt ihn laufen. Keiner der Ablauftests dort — Leerlauf- und absoluter Ablauf von Sitzungen, expires_at und disabled von Tokens, der pepsi-httpd prune-Job — wartet, bis ein Zeitfenster verstrichen ist: Jeder datiert den Zeitstempel zurück, den die Datenbank mit now() vergleicht, was die durchsetzende Abfrage nicht vom Verstreichen der Zeit unterscheiden kann.
25.2. Auch die Dokumentations-Builds sind Prüfungen¶
make docs führt sie alle für die Quellsprache aus und ist das eine Dokumentationsziel in der allgemeinen Qualitätsschranke. Es ist ein Alias für make docs-en; make docs-de und make docs-fr bauen dieselben Artefakte aus den übersetzten Katalogen, und make docs-all baut jede Sprache. Vier getrennte Builds stecken darin, und dass einer durchläuft, sagt wenig über die anderen:
make docs-html-enSphinx-HTML. Fängt kaputte Querverweise, unbekannte Rollen und fehlerhafte Tabellen ab.
make manDie Handbuchseiten der Abschnitte 1/5 über
docs/rst2man.py. Fängt Titel-Über-/Unterstriche ab, die nicht zur Titellänge passen — ein docutils-Fehler, den der HTML-Build toleriert. Nur in der Quellsprache: Die roff-Seiten werden direkt ausdocs/*.rstgerendert und laufen nie durch Sphinx, haben also keinen Übersetzungskatalog.make infoDas GNU-Info-Handbuch, über den Texinfo-Builder von Sphinx und
makeinfo. Nur in der Quellsprache, aus demselben Grund, aus deminstall-infoeinpepsi.infoin einem Info-dir-Index registriert.make docs-pdf-enLaTeX. Der am leichtesten vergessene und der am härtesten scheiternde. pdflatex hat für ein beliebiges Unicode-Zeichen keine Glyphe und degradiert nicht, wenn es ihm begegnet: Es bricht mit „Unicode character … not set up for use with LaTeX“ ab und erzeugt überhaupt kein PDF. HTML und man rendern dasselbe Zeichen klaglos, sodass ein neuer Pfeil, ein Rahmenzeichen oder ein griechischer Buchstabe in der Prosa beide besteht und nur diesen Build bricht.
Jedes im Handbuch verwendete Nicht-ASCII-Zeichen muss in
latex_elements["preamble"]indocs/manual/conf.pydeklariert werden. Der von den ASCII-Art-Pipeline-Diagrammen benutzte Rahmenzeichensatz wird absichtlich auf reines ASCII abgebildet: Diese Diagramme stehen incode-block:: text, sodass die Ersetzung in einer Verbatim-Umgebung expandiert wird, in der kein Mathematikmodus verfügbar ist.Der zweite Fehlermodus ist eine Tabelle, die nicht auf eine Seite passt. Sphinx rendert eine
list-tableerst oberhalb einer Zeilenzahlschwelle in LaTeX‘longtable— die über Seiten hinweg umbricht und den Kopf wiederholt —; darunter wird die Tabelle zu einemtabular, das überhaupt nicht umbrechen kann. Die Heuristik zählt Zeilen, aber was eine Seite überläuft, ist die Höhe, und die beiden gehen bei einer breiten Tabelle mit umbrechenden Zellen weit auseinander: Die 113-zeilige RFC-Übersichtstabelle bricht anstandslos um, während die 17-zeilige, siebenspaltige Vergleichstabelle in Einführung es nicht tut und 397 pt unten über die Seite hinausläuft.Die Abhilfe besteht darin, es ausdrücklich zu sagen, statt sich auf die Heuristik zu verlassen:
.. list-table:: :header-rows: 1 :widths: 20 14 14 14 14 14 14 :class: longtable
Anders als ein fehlendes Zeichen lässt dies den Build nicht scheitern — es ist eine
Overfull \vbox-Warnung und ein PDF mit Inhalt außerhalb der Seite —, durchsuchen Sie die Log-Datei also nachOverfull \vboxund behandeln Sie alles jenseits von ein, zwei Punkt als echten Mangel. Überschüsse unterhalb eines Punktes sind gewöhnliche typografische Rundung.Ignorieren Sie beim Lesen der Ausgabe die
Hyper reference … undefined-Warnungen der ersten Durchläufe — latexmk löst Vorwärtsreferenzen in späteren auf. Der letzte Durchlauf, indocs/manual/_build/pdf/en/latex/pepsi.log, ist derjenige, der sauber sein muss.
Die Übersetzungen werden auf dieselbe Weise geprüft, und die Prüfung ist nicht überflüssig: Ein Zeichen, das ein Übersetzer einführt — ein Guillemet, ein deutsches Anführungszeichen, ein geschütztes Leerzeichen —, lässt denselben pdflatex-Build auf dieselbe Weise scheitern, und kein rein englischer Lauf würde ihm je begegnen. make docs-all ist daher eher eine Freigabeschranke als eine Schranke je Commit; das PDF jeder Sprache landet in docs/manual/_build/pdf/<lang>/latex/pepsi.pdf, und ein deutscher oder französischer Build braucht zusätzlich die installierte babel-Unterstützung dieser Sprache (Debian: texlive-lang-german, texlive-lang-french).
Die Übersetzungen aktuell zu halten besorgt make update-po: Es extrahiert die Nachrichtenvorlagen neu und führt sie in docs/manual/locale/<lang>/LC_MESSAGES zusammen, sodass geänderte Absätze als fuzzy markiert und neue unübersetzt zurückkommen. Nur die .po-Dateien stehen unter Versionskontrolle; Sphinx kompiliert sie zur Build-Zeit.
25.3. Topologie¶
Die Suite steuert drei echte Mail-Konten auf drei Hosts, beschrieben in einer kleinen INI-Datei, tests/test-accounts.ini. Diese Datei gehört nicht zum Quellbaum: Legen Sie sie aus der Vorlage mit cp tests/test-accounts.ini.sample tests/test-accounts.ini an und ersetzen Sie deren Platzhalter-Konten durch Hosts, die Sie kontrollieren:
Rolle |
Konto (ssh-Ziel = E-Mail) |
Funktion |
|---|---|---|
|
|
Betreibt Pepsi (ingress, dispatch, httpd), PostgreSQL und systemd; außerdem den Smarthost, über den die bediente Domain weiterleitet. |
|
|
Lokale Konten auf der bedienten Domain. Ihr MTA leitet über ADMIN weiter und wird von ihm als vertrauenswürdig eingestuft ( |
|
|
Ein Konto auf einem unabhängigen Host. Ihre Mail erreicht ADMINs öffentlichen MX auf Port 25 als fremder MTA — der eingehende Pfad. |
|
|
Ein lokaler Unix-Benutzer auf dem ADMIN-Host, der Mail per direkter lokaler Zustellung in sein Maildir empfängt (der Lokale-Zustellung-Pfad; keine Weiterleitung). Anders als die anderen wird er nie direkt per ssh angesprochen — sein Postfach wird als root über die ADMIN-Verbindung gelesen. Nur |
Jeder Host wird über passwortloses ssh erreicht; der Harness installiert nichts. ALICE/BOB verwenden eine mbox (/var/mail/<user>); CAROL und DAVE verwenden ein Maildir. Die Postfach-Helper sind formatunabhängig und finden eine Nachricht über ein laufspezifisches Token in beiden Layouts.
Bemerkung
Die beiden anderen Hosts haben eigene Annahmerichtlinien, und die greifen lange vor Pepsi. In der Korrektheits-Suite, die eine Handvoll Nachrichten verschickt, sind sie unsichtbar; in den Benchmarks, die Hunderttausende verschicken, entscheiden sie. Zwei davon besonders:
Der MX von
CAROList die empfangende Seite jedes ausgehenden Tests. Ist er selbst eine Pepsi-Installation, dann sind[pepsi-ingress] CONN_RATE_PER_SECONDundCONN_RATE_BURSTdort standardmäßig 1 und 1 — eine neue Verbindung pro Sekunde aus einem bestimmten Quellbereich —, sodass ein Relay, das pro Nachricht eine Verbindung öffnet, mit421 4.7.0 Too many connections from your addressbeantwortet wird und zurückstellt. Es geht nichts verloren; gemessen wird aber auch nichts. Erhöhe sie auf diesem Host, bevor du irgendeiner ausgehenden Zahl glaubst.Sind sie erhöht, bleibt die eigene Geschwindigkeit dieses Hosts. Ist der
CAROL-Host deutlich kleiner als der getestete MTA, ist jede ausgehende Messung die Zahl dieses Hosts, nicht die von Pepsi; das Kapitel Performance sagt, wie solche Zahlen zu lesen sind.Der MTA von
ALICE/BOBist der Smarthost, an dem der Relay-Schwanz endet, und Postfix‘message_size_limitliegt standardmäßig bei zehn Millionen Bytes. Deshalb können die größeren Größen des Stage-Durchlaufs den Smarthost-Pfad überhaupt nicht passieren — was der Durchlauf als das eigene552des nächsten Hops meldet, anstatt zu raten.
Dieselbe Datei enthält ein Konto, das kein Mailkonto ist, in einem [demobank]-Abschnitt:
[demobank]
URL = https://bank.demo.taler.net
USER = pepsi-ci
PASS = pepsi-pass
Dies ist ein Bankkonto bei der öffentlichen GNU-Taler-Demo-Bank, deren Währung (KUDOS) Spielgeld ist. 12-wallet-topup-test.sh benötigt es, weil eine manuelle Wallet-Aufladung dem Benutzer nur mitteilt, wohin er Geld überweisen soll — dem Wallet wird nichts gutgeschrieben, bis diese Banküberweisung tatsächlich stattfindet. Der Harness spielt daher die Bank des Benutzers: Er meldet sich an und führt genau die Überweisung aus, um die die per E-Mail versandten Anweisungen bitten; nur so kann der Test prüfen, dass die Abhebung wirklich abgeschlossen wird, und nicht bloß, dass Anweisungen verschickt wurden. Registrieren Sie ein Konto unter https://bank.demo.taler.net/ (ein neues beginnt mit KUDOS:100 und darf bis KUDOS:500 ins Soll gehen — etwa 120 Durchläufe dieses Falls); DEMOBANK_USER, DEMOBANK_PASS und DEMOBANK_URL in der Umgebung haben Vorrang vor der Datei. Kein anderes Skript verwendet es, und wenn der Abschnitt fehlt, wird nur diese eine Gutschriftprüfung übersprungen.
25.4. Die Skripte¶
tests/lib.shGemeinsame Bibliothek, die von jedem nummerierten Skript gesourct wird. Sie parst die Konten-INI, stellt die von der gemeinsamen Vorprüfung verwendeten
ssh-/Abhängigkeits-/Datenbank-/Dienst-Proben, die Ergebniszähler und die farbigeok/no/skip-Ausgabe, die SQL- und Reset-Helper des ADMIN-Hosts, die Postfach-Sende-/Empfangs-Helper, die Taler-Wallet-Helper, die RFC-3464-DSN-Prüfung und — für die erweiterten Skripte —send_smtp(einen Roh-SMTP-Sender, der die ESMTP- und DSN-Parameter setzen kann, die dermail-Befehl nicht kann) undhop_caps(eine EHLO-Fähigkeitsprobe) bereit. Sie ist für sich allein nicht ausführbar.01-deploy.shRichtet eine vollständige Pepsi-Installation auf dem ADMIN-Host aus einem sauberen Checkout ein: Dienstbenutzer, PostgreSQL-Rolle/-Datenbank, die Konfigurationsdatei (einschließlich der vollständigen Stage-Pipeline),
pepsi-setup(TLS, Schema, DKIM-Schlüssel, DNS-Einträge), den Demo-Zahlungs-Händler und die systemd-Units. Es verifiziert nur die erforderlichen Werkzeuge und bricht mit einer genauen Liste ab, falls welche fehlen — es installiert nie OS-Abhängigkeiten.02-pipeline-test.shDie zentrale Happy-Path-Suite (T1–T6): die Pay-to-Send-Anti-Spam-Stage (unbezahlt → Bounce, bezahlt → zugestellt, zentral aus dem Taler-Wallet des Runners bezahlt), der Sprachfilter (auf die schwarze Liste gesetztes Französisch → Bounce), der ausgehende Signier-/Relay-Pfad (DKIM + ARC beim Empfänger verifiziert), das Lernen der weißen Liste mit SRS-Umschlag-Umschreibung und ein zweiter lokaler Benutzer.
03-dsn-test.shRFC-3461-DSN-Erweiterungen und Bounce-Varianten, mit
send_smtp:NOTIFY=NEVERunterdrückt die DSN (D1);ENVID/ORCPTwerden zurückgespiegelt (D2);RET=HDRSgibt nur Header zurück (D3);NOTIFY=SUCCESSmitORIGINATE_SUCCESS_DSNliefert eine positive DSN (D4); ein NXDOMAIN-Empfänger routet zum Standard-Bounce (D5); ein unerreichbares Relay erzeugt eine DELAY-DSN (D6); und ein Null-Absender-Bounce an eineSRS0=…-Adresse wird von Ingress zurück zum ursprünglichen Absender rückwärtsdekodiert (D7).04-settings-test.shDie Überschreibungsschicht pro Adresse: ein
pepsi-settings-Datensatz ändert das Ergebnis eines Empfängers, aber nicht das eines anderen (S1); ein Konto bearbeitet seine eigenen Überschreibungen per E-Mail und wird bestätigt (S2); eine Bearbeitung an einem Nicht-EDITABLE_STAGES-Abschnitt wird abgelehnt und speichert nichts (S3); und einDATAmit divergierenden Überschreibungen pro Empfänger wird in separate Datensätze der Warteschlange aufgeteilt (S4).05-mime-test.sh8BITMIME-/SMTPUTF8-Behandlung: ein 8-Bit-Nachrichtentext und ein UTF-8-
Subjectüberstehen das Relay unversehrt, wenn der Zustell-Hop die Erweiterung anbietet, werden herabgestuft (Quoted-Printable/Base64, RFC 2047), wenn er es nicht tut, und eine Nicht-ASCII-Empfängeradresse, die der Hop nicht darstellen kann, schlägt dauerhaft fehl. Das Skript probt zuerst das EHLO des Hops und nimmt den passenden Zweig.06-cli-test.shDie Operator-CLIs, direkt über
sshausgeführt:pepsi-config(get/dump/pathsub),pepsi-whitelist(add/list/remove und die dkim/signature-Flags),pepsi-settings(set/get/list/unset/remove),pepsi-tlsrpt(report--dry-run/ prune) und derpepsi-httpd-/metrics-Endpunkt.07-maildir-test.shDirekte (lokale Maildir-)Zustellung über die
pepsi-stage-relay-to-maildir-Stage, die den setuid-rootpepsi-helper-maildir-writerantreibt. Eine Nachricht an den lokalenDAVE-Benutzer landet in dessen Maildir mit den vorangestelltenReturn-Path/Delivered-To/Received-Headern (L1); eine einzelne Nachricht an einen lokalen und einen entfernten Empfänger wird aufgeteilt, wobeidavelokal zugestellt undaliceweitergeleitet wird (L2); und eine Nachricht an ein absichtlich nicht zustellbares Konto (dave-broken, kein nutzbares Home) gibt nachMAX_LIFETIMEauf und gibt eine Failure-DSN an den Absender zurück (L3). Weil[stage-local]nach den eingehenden Filtern sitzt (… → anti-spam → local → srs), wird der Absender zuerst auf die weiße Liste gesetzt, um die Pay-to-Send-Schranke zu passieren. Das gesamte Skript überspringt sauber, wennDAVEnicht gesetzt ist, die Installation keine[stage-local]hat oder die Zielbenutzer fehlen.11-lmtp-test.shLokale LMTP-Zustellung (
pepsi-stage-relay-to-lmtp) gegen ein echtes Dovecot auf dem ADMIN-Host, sodass das Sieve-Skript des Empfängers läuft, während der MDA die Mail ablegt: Eine Nachricht, derenSubjectden Sieve-Auslöser trägt, wird perfileinto :createin einen Pepsi-Ordner abgelegt (S1, was beweist, dass Sieve lief, und nicht bloß, dass LMTP zugestellt hat), und eine Nachricht an einen unbekannten Benutzer wird von Dovecot je Empfänger abgelehnt und weiter anNEXT_STAGEgeroutet — die Stage baut nie selbst eine DSN (S2). Das Skript installiert und konfiguriert Dovecot selbst, idempotent, und verdrahtet einen Wegwerf-Abschnitt[stage-lmtp]inpepsi.conf; es treibt denworkerder Stage direkt an, statt LMTP in die laufende Pipeline zu setzen, sodass es kein anderes Skript stört. Es überspringt sauber, wenn Dovecot nicht installiert werden kann oder das Stage-Binärprogramm fehlt.12-wallet-topup-test.shDie By-E-Mail-Wallet-Self-Service-Hälfte von
pepsi-stage-auto-pay(der[stage-wallet]-Abschnitt): Ein lokales Konto füllt sein eigenes benutzerspezifisches GNU-Taler-Wallet auf, indem espepsi-wallet@<served-domain>einenSubject:-Befehl sendet. Alle drei Methoden werden End-to-End gegen den Demo-Exchange (KUDOS) ausgeübt, mit dem finanzierten lokalentaler-wallet-clials echtem Gegenüber:withdraw(manuelle Bank-Überweisungsanweisungen, die Überweisung wird anschließend tatsächlich vom[demobank]-Konto aus ausgeführt),pull(einetaler://pay-pull/-URI, die der Harness begleicht) undpush(der Harness pusht; der Benutzer akzeptiert dietaler://pay-push/-URI). Jeder Fall prüft, dass die Steuernachricht verbraucht wird und das Wallet-Guthaben wächst.13-auto-pay-test.shDie forderungszahlende Hälfte:
pepsi-stage-auto-paybegleicht eine zurückkehrende Pay-to-Send-Forderung aus dem eigenen Wallet des Absenders. Die Forderung wird echt erzeugt — ein lokaler Benutzer sendet an einen mit Bezahlschranke versehenen lokalen Empfänger (DAVE), das Ausgehende wird internet-relayt (und stempelt eine echtePepsi-Origin), läuft in den eingehenden MX dieses Hosts zurück, wopepsi-stage-anti-spames zurückhält und dem Absender eine echte Forderung mailt. Diese Forderung wird durch den Auto-Pay-workerwiedergespielt. Die beiden Fälle verwenden separate Absender (also separate benutzerspezifische Wallets/Bestellungen):BOB``s Wallet bleibt leer, sodass Auto-Pay die Forderung weiterleitet und nichts berechnet (A1); ``ALICE``s Wallet wird **im Voraus vorfinanziert** (sodass die langsame Abhebung außerhalb des kurzen 30-Sekunden-Zahlungsfensters der Bezahlschranke liegt), sodass Auto-Pay die Forderung darin begleicht — die Bestellung kippt auf bezahlt, das Wallet wird belastet, und die zurückgehaltene Nachricht wird freigegeben und an ``DAVEzugestellt (A2).14-multi-recipient-test.shEmpfänger-Fan-out — der Fehlerfall, in dem eine an mehrere Personen adressierte Nachricht nur einen Teil von ihnen erreicht. Beide Fälle prüfen die positive Zustellung an jeden vorgesehenen Empfänger. T1 sendet einen Umschlag an zwei entfernte Empfänger und verlangt, dass beide ankommen — ein Relay, das
rcpt_to.first()nimmt und dann den Datensatz beendet, gibt nichts weiter. T2 deckt das~/.forward-Fan-out ab: ein Umschlag, der an einen lokalen Benutzer mit Weiterleitung (DAVE) und an einen zweiten einfachen Empfänger adressiert ist, wobei die weitergeleitete Kopie und der Durchleitungsempfänger jeweils genau einmal ankommen müssen — eine Stage, die den Datenbank-Datensatz serverseitig reduziert, ohne die Nachricht im Speicher zu ändern, lässt einen fusionierten Nachfolger mit der veralteten Empfängerliste arbeiten. T2 benötigt das optionaleDAVE-Konto und eine installierte~/.forward-Stage.15-debian-deploy-test.shDas paketierte Artefakt und der Assistent — der echte Installationsweg des Operators, während
01-deploy.shaus einem Checkout baut und die Konfiguration von Hand schreibt. Es baut das.deblokal, installiert es auf dem ADMIN-Host (sodass daspostinstdie Konten, Rollen unddpkg-statoverride-Bits anlegt) und führt dannpepsi-setup --wizard --answersfür eine Reihe von Szenarien aus, jeweils gefolgt vonpepsi-setup runund echter Probe-Mail durch die Pipeline, die der Assistent erzeugt hat. Es schreibt den installierten Host neu, tut also nichts außer seinen Plan auszugeben, solangePEPSI_DEPLOY_CONFIRM=yesnicht gesetzt ist.16-whitelist-import-test.shDas setuid-
pepsi-whitelistund sein Postfach-Importer, gegen die laufende Installation — alles an diesem Programm, was es erst gibt, wenn es installiert ist. Es prüft die Installation selbst (Modus4755mit Eigentümerpepsi-whitelist, den Scan-Helper ohne Privilegien-Bits, die auf die Tabelle beschränkte Datenbankrolle, die Hoster-Liste); die Namensraum-Regel, indem es zwei Wegwerf-Konten anlegt und bestätigt, dass eines<login>/…und sonst nichts verwenden darf, dasslistdie geteilte weiße Liste des Operators nicht offenlegt und dass-cabgelehnt wird; den Import selbst, der genau die Empfänger der Mail ergeben muss, die dieser Benutzer gesendet hat, und empfangene Mail ignorieren muss; die Wildcard-Entscheidung, bei der eine stark frequentierte Domain zu einem einzigen*@domain-Datensatz zusammenfällt, währendgmail.commit ebenso vielen Korrespondenten das nicht tut; die Privilegienabgabe, indem ein Helper untergeschoben wird, der seine eigenen Zugangsdaten meldet, und geprüft wird, dass die uid des Aufrufers in allen drei ID-Slots auftaucht;--user, das den eigenen Namensraum eines anderen Kontos befüllt; und schließlich, dasspepsi-stage-check-whitelistden benutzerspezifischen Namen konsultiert, zu dem sein{localpart}-Platzhalter expandiert. Einzelne Prüfungen überspringen, wenn der Installation die Funktion fehlt.17-crypto-test.shEnde-zu-Ende-Kryptographie: die Teile von
pepsi-stage-encrypt,pepsi-stage-decryptundpepsi-keys, die es erst gibt, wenn die Binärprogramme setuid installiert sind und der Schlüsselspeicher einen Schlüsselverschlüsselungsschlüssel hält. Es prüft die Installation und die Verwahrungsgrenze (4750 pepsi-crypto:pepsi; die Rollepepsikanncrypto_identity.private_wrappednicht lesen), die Identitätserzeugung für beide Protokolle und die Interoperabilität statt bloßer Selbstkonsistenz: Pepsis Chiffrat wird von einem unverändertengpggelesen, und das Chiffrat vongpgwird von Pepsi gelesen. Es deckt außerdem die fail-open-Urteile für eingehende Mail ab, den gefälschtenX-Pepsi-Crypto-Header und dassENCRYPT = requiredeinen Bounce erzeugt, statt je Klartext zu senden.18-wkd-test.shDas Spiegelbild von
17: wie andere unsere Schlüssel finden.pepsi-httpdbedient das Web Key Directory für jede akzeptierte Domain aus dem Schlüsselspeicher und beachtet dabei daspublished-Flag jeder Identität — die Richtliniendatei, den direkten und den fortgeschrittenen Pfad, dass sich die zurückgegebenen Bytes in ein unverändertesgpgimportieren lassen, dassgpg --locate-external-keysie über echtes DNS und TLS findet und dass eine unveröffentlichte Identität und eine Domain, die wir nicht bedienen, beide404ergeben.19-secure-link-test.shDas ferne Ende von
[stage-encrypt] ON_NO_KEY = secure-link: Der Klartext wird von der Leitung genommen, dem Empfänger wird ein Link und dem Absender eine PIN gemailt. Es deckt das Routing ab, die PIN, die an den Absender geht, das Offenlegungsverhalten des Portals, die Sperre nachMAX_ATTEMPTS, das erfolgreiche Lesen, die Lesebestätigung und dass die Datenbank allein Chiffrat und keine PIN hält.20-admin-api-test.shDie administrative API über den UNIX-Socket-Listener mit
ADMIN = yes, den01-deploy.shkonfiguriert: dass alle drei Mechanismen authentifizieren (SO_PEERCRED, ein Bearer-Token, eine Passwort-Sitzung), dass ein Token auf seine Geltungsbereiche beschränkt ist und ein fehlender Geltungsbereich ein403ergibt, dass jeder nur lesende Endpunkt JSON antwortet und dassGET /api/v1/configkein Geheimnis offenlegt.21-online-setup-test.shDass die zwei Front-Ends eines Setup-Interviews — das Terminal-
pepsi-setup --wizardund das im Browser unter/api/v1/setup— nicht auseinanderdriften: dieselben Fragen, Bezeichner, Arten, dieselbe Reihenfolge, dieselben Standardwerte und Bedingungen; Antworten, die unverändert hin und zurück gehen; dieselben Werte, die von beiden abgelehnt werden; und dieselben Antworten, die zu derselben Konfiguration gerendert werden. Der letzte Fall schreibt die installierte Konfiguration neu (und stellt sie danach wieder her) und ist anPEPSI_DEPLOY_CONFIRM=yesgebunden; die nur lesenden laufen immer.22-list-api-test.shDas Kompatibilitätstor der Mailinglisten und das eine Skript hier, das nicht unseres ist. Es führt die eigene Suite von
mailmanclient3.3.5 (344 Doctest-Anweisungen inusing.rstund 36 Testfunktionen) und diemailman_api_testsvon Postorius 1.3.13 (30 Dateien, 248 Funktionen) gegen den installierten Server aus, wobei nur die Vorrichtung ausgetauscht ist, die GNU Mailman Core startet – diese zwei Ersatzstücke liegen incontrib/compat/, versioniert neben den Festschreibungen. Davor prüft es die Dinge, deren Scheitern sonst als 250 rote Python-Tracebacks erscheinen würde: dass die API auf dem Loopback-Listener mitLIST_API = yesantwortet und ohne die Zugangsdaten verweigert, dass dieselben Pfade auf dem öffentlichen Listener ein Byte-für-Byte gleiches404sind, dass der nur für Tests gedachte Reset-Haken funktioniert, und ein Rauchtest des Ressourcenbaums samt der400-gegen-404-Asymmetrie auf/configund der Aufteilung dezimal gegen hexadezimal beimember_idzwischen/3.0/und/3.1/. Eine Suite, die nicht installiert werden kann, wird als erklärtes Übergehen gemeldet und lässt den Lauf dennoch scheitern: ein stillschweigend übergangenes Tor ist die andere Art, auf die dieser Test lügen kann.24-list-post-test.sh…27-list-archive-test.shDie vier Hälften des Mailinglisten-Subsystems über echte Post: eine Listennachricht, die jedes Mitglied mit seiner eigenen Ein-Klick-Abmelde-URI erreicht;
-join,-leaveund-confirm, die die Abonnementabläufe antreiben; ein Bounce, der einem Mitglied zugeordnet, bewertet und in eine Warnung und dann eine Entfernung verwandelt wird; und das Archiv, das aufnimmt, threadet, durchsucht und löscht, was gesendet wurde.Skript 24 trägt außerdem die Sammelnachrichtenphase: Nachrichten wachsen an, eine Ausgabe geht in jedem Format an die Mitglieder, die dieses Format verlangt haben, Band und Nummer sind das, was die Regel sagt, und ein Mitglied, das an diesem Morgen die Sammelnachrichten abgeschaltet hat, erhält dennoch die letzte Ausgabe. Es ist eine Phase dieses Skripts und kein neues, weil die Installationssuite schon lang ist.
28-list-web-test.shDie öffentlichen Mailinglistenseiten über HTTP: dass jede Route auf einem Listener ohne
LISTS = yesein Byte-für-Byte gleiches404ist; dass eine beworbene Liste im Verzeichnis steht und eine nicht beworbene nicht und weiterhin über ihre URL erreichbar ist; dass das Anmeldeformular genau ein anstehendes Token ausgibt, von sich aus niemanden anmeldet, ein gültiges Token wiederverwendet statt ein zweites auszugeben und für eine bekannte und eine unbekannte Adresse gleich antwortet; dass ein Bestätigungs-GETnichts abschließt und nur dasPOSTes tut; dass eine Nachricht unter ihrer HyperKitty-URL und über die Suche zu finden ist, mit ihrem Text maskiert und nicht gerendert; dass ein privates Archiv ein404und kein403ist; und dass das Ein-Klick-Ziel nach RFC 8058 das Mitglied mit einem einzigenPOSTentfernt, selbst wennunsubscription_policymoderateist, idempotent ist und bei einem manipulierten Token niemanden entfernt.Die letzte Phase behandelt die Mitgliederebene und die Verwalteroberfläche: ein Konto registrieren und genau ein Bestätigungstoken zugesandt bekommen (eine zweite Registrierung verwendet es wieder statt ein zweites auszugeben), bestätigen und ein Passwort setzen, von der Kommandozeile zum Verwalter gemacht werden, sich anmelden, und dann der Test, auf den es am meisten ankommt – ein Verwalter ändert eine Einstellung im Browser und die REST-API liest denselben Wert zurück, und das ist es, was belegt, dass die zwei Oberflächen einen Datensatz schreiben. Es prüft außerdem, dass ein Fremder, der die Konsole anfordert, dieselbe Antwort erhält wie für eine nicht vorhandene Liste, und dass eine Einstellungssendung ohne CSRF-Token abgewiesen wird.
Neben den nummerierten Skripten deckt tests/whitelist-suid.sh denselben setuid-Vertrag ohne SSH oder eine Installation ab: Als root auf einem beliebigen Host mit lokalem PostgreSQL ausgeführt, legt es eine Wegwerf-Datenbank an, installiert das Binärprogramm setuid in ein suid-beachtendes Verzeichnis und führt dieselben Namensraum-/Privilegienabgabe-Prüfungen aus. make check führt es (und die anderen *-suid.sh-Skripte) nach bestem Bemühen aus — sie überspringen, statt fehlzuschlagen, wenn sie kein root, keine Datenbank oder kein suid-fähiges Dateisystem bekommen können.
29-list-import-test.shDas Migrationswerkzeug. Eine echte
config.pckin Protokoll 0 wird importiert, und die Umwandlungen, die keine Kopien sind, werden über die Datenbank geprüft und nicht über den Rückgabewert des Konverters – der Zusammenfall vonarchive_policy, die DMARC-Vorrangregel, die neunzig Tage Karenzzeit, das abschließende Leerzeichen dessubject_prefix, dasDisableMime-Bit, das ein Klartext-Sammelnachrichtenmitglied erzeugt, und ein wegen Bounces abgeschaltetes Mitglied, das abgeschaltet ankommt. Der Import endet mit einem Fehlerstatus, weil die Testdaten absichtlich eine Sperre tragen, die niemand übersetzen kann, und ein zweiter Lauf ändert nichts und sagt das.Die mittlere Phase ist die wertvollste:
pepsi-archive export, gefolgt vonimportin eine zweite Liste, mit Vergleich der Nachrichtenzahl, jederMessage-IDund der Threadzahl. Das prüft die beiden Hälften gegeneinander und nicht gegen unsere Erwartungen, und ein erneuter Import fügt nichts hinzu – die Wiederaufnahme hängt am Inhalt und nicht an einem Zeitstempel.Die letzte Phase ist die Umstellungssendung: das Histogramm je Domain, ein ratenbegrenzter Lauf und ein zweiter Lauf, der überspringt, was der erste eingeladen hat.
Was es nicht tut, ist ein echtes upstream Mailman 3 aufzusetzen, um über REST zu importieren; das braucht eine Mailman-Installation auf dem Zielrechner. Die Lücke ist im Skript benannt und nicht dem Entdecken überlassen.
30-secretary-test.shConfirm-to-Send (
pepsi-stage-secretary). Die Installation, die01-deploy.shaufbaut, hat keine Secretary in ihrer eingehenden Kette, daher fügt das Skript für seine eigene Laufzeit eine nachcheck-whitelistein und stellt die Konfiguration beim Beenden wieder her. Es prüft, dass ein unbekannter Absender zurückgehalten wird und eine Challenge mit Null-Absender erhält (X1); dass eine automatische Antwort auf die Challenge nichts freigibt und niemanden auf die Whitelist setzt (X2); dass eine echte Antwort die zurückgehaltene Nachricht zustellt und den Absender auf die Whitelist setzt (X3), dessen nächste Nachricht dann ohne zweite Challenge durchgeht (X4); dass eine gebouncte Challenge die zurückgehaltene Mail sofort in den Timeout-Pfad schickt (X5); und dass ohne Antwort die zurückgehaltene Mail nachHOLD_TIMEgebounct wird, wobei eine verspätete Antwort auf das abgelaufene Cookie nichts bewirkt (X6).
25.5. Ausführen¶
# One-time: deploy this checkout onto the MX host (over SSH):
tests/01-deploy.sh tests/test-accounts.ini
# Then, repeatedly, from the test runner:
tests/02-pipeline-test.sh tests/test-accounts.ini
tests/03-dsn-test.sh tests/test-accounts.ini
tests/04-settings-test.sh tests/test-accounts.ini
tests/05-mime-test.sh tests/test-accounts.ini
tests/06-cli-test.sh tests/test-accounts.ini
tests/07-maildir-test.sh tests/test-accounts.ini # needs the optional DAVE account
tests/11-lmtp-test.sh tests/test-accounts.ini # deploys Dovecot on the MX host
tests/12-wallet-topup-test.sh tests/test-accounts.ini # needs taler-wallet-cli on the MX host
tests/13-auto-pay-test.sh tests/test-accounts.ini # needs DAVE + taler-wallet-cli
tests/14-multi-recipient-test.sh tests/test-accounts.ini # T2 needs DAVE + a ~/.forward stage
tests/16-whitelist-import-test.sh tests/test-accounts.ini # needs root on the MX host
tests/17-crypto-test.sh tests/test-accounts.ini # needs the setuid crypto stages + gpg
tests/18-wkd-test.sh tests/test-accounts.ini # needs pepsi-httpd + gpg
tests/19-secure-link-test.sh tests/test-accounts.ini
tests/20-admin-api-test.sh tests/test-accounts.ini # needs the ADMIN = yes listener
tests/22-list-api-test.sh tests/test-accounts.ini # needs the LIST_API = yes listener + PyPI
tests/24-list-post-test.sh tests/test-accounts.ini
tests/25-list-command-test.sh tests/test-accounts.ini
tests/26-list-bounce-test.sh tests/test-accounts.ini # needs the DAVE account for the owner notices
tests/27-list-archive-test.sh tests/test-accounts.ini
tests/28-list-web-test.sh tests/test-accounts.ini # needs the LISTS = yes listener
tests/29-list-import-test.sh tests/test-accounts.ini # the importers and the cutover
tests/30-secretary-test.sh tests/test-accounts.ini # splices in a secretary stage
# These two rewrite the deployed host, so they only plan unless confirmed:
PEPSI_DEPLOY_CONFIRM=yes tests/15-debian-deploy-test.sh tests/test-accounts.ini
PEPSI_DEPLOY_CONFIRM=yes tests/21-online-setup-test.sh tests/test-accounts.ini
make integrationtests ACCOUNTS=tests/test-accounts.ini führt den ganzen Satz aus: Das INTEGRATION_SH des Ziels ist tests/[0-9][0-9]-*.sh abzüglich der tests/[0-9][0-9]-*-bench.sh-Skripte (BENCH_SH, die ihr eigenes Ziel make benchmarks haben — siehe Benchmark-Suite), sodass ein Skript dadurch aufgenommen wird, dass es existiert, und nicht dadurch, dass es irgendwo aufgeführt ist — einschließlich derer, die dieses Kapitel nicht erwähnt. Es hält beim ersten fehlschlagenden Skript an und hängt von interop-thunderbird ab, sodass die S/MIME-Interoperabilitätsschranke zuerst läuft. ACCOUNTS hat den Standardwert tests/test-accounts.ini.
Jedes Skript verwaltet sich selbst: Es führt eine Vorprüfung durch (ssh-Erreichbarkeit mit dem echten Fehler bei Misserfolg, erforderliche entfernte Werkzeuge, eine Datenbankprobe und der Zustand der drei Dienste mit dem Journal-Auszug jedes ausgefallenen), stellt eine kurze PAYMENT_DEADLINE und ein zügiges POLL_INTERVAL für schnellen Durchlauf sicher und setzt die weiße Liste/Warteschlange/Einstellungen zurück, von denen es abhängt. Eine fehlende Annahme lässt die Vorprüfung mit einer umsetzbaren Meldung scheitern; eine nicht ankommende Nachricht löst einen Diagnose-Dump aus (die Live-Warteschlange plus das Dispatcher-Journal). Stellgrößen wie PAYMENT_DEADLINE_SECS, DELIVER_TIMEOUT und WITHDRAW_AMOUNT sind Überschreibungen aus der Umgebung. Jedes Skript endet nur dann mit 0, wenn kein Fall fehlschlug (Übersprünge sind erlaubt).
25.6. Übersprünge und bedingte Fälle¶
Ein Fall überspringt (statt fehlzuschlagen), wenn eine Vorbedingung fehlt, die er nicht erfüllen kann, stets mit einer einzeiligen Begründung. Die häufigen:
Kein nutzbares Taler-Wallet. Der bezahlte Teil von
02überspringt, wenn das lokaletaler-wallet-clifehlt oder mit dem Demo-Exchange inkompatibel ist. Alle Zahlungen erfolgen zentral aus dem Wallet des Runners (im Produktivbetrieb würde jeder Absender für seine eigene Nachricht bezahlen).Der Installation fehlt eine Funktion.
03/04überspringen die Fälle, die Pipeline-Funktionen benötigen, die die Installation nicht konfiguriert (ORIGINATE_SUCCESS_DSN, ein[stage-internet]-BOUNCE_STAGE, das[stage-delaytest]-Blackhole-Relay, die[stage-edit-settings]-Stage) — führen Sie01-deploy.sherneut aus, um sie zu aktivieren.06überspringt denpepsi-tlsrpt-Fall, sofern kein[pepsi-tlsrpt]-Abschnitt konfiguriert ist.07überspringt vollständig, wenn das optionaleDAVE-Konto nicht gesetzt ist, die Installation keine[stage-local]hat oder die Zielbenutzerdave/dave-brokenauf dem ADMIN-Host fehlen. Der T2-Fall von14überspringt, wennDAVEnicht gesetzt ist oder die Installation keine~/.forward-Stage hat.Hop-Fähigkeit.
05nimmt seinen Durchleitungs-, Herabstufungs- oder Nicht-darstellbare-Adresse-Zweig je nachdem, ob der Zustell-Hop 8BITMIME / SMTPUTF8 anbietet; die Fälle, die verlangen, dass dem Hop eine Erweiterung fehlt, überspringen, wenn er sie anbietet. Diese Seite deckt unabhängig davonrfc2231_downgrade_lifecycleauspepsi-test-stagesab, der über die echte Smarthost-Stage an einen Mock-Server weiterleitet, der keine der beiden Erweiterungen anbietet.Wallet / Auto-Pay nicht installiert.
12/13überspringen vollständig, wenn die Abschnitte[stage-wallet]/[stage-pay],taler-wallet-clioder daspepsi-wallets-Konto fehlen (führen Sie01-deploy.sherneut aus). Derwithdraw-Gutschriftteil von12überspringt ohne ein[demobank]-Konto (siehe oben); seinepull/push-Fälle überspringen ohne nutzbares lokales Wallet.13überspringt, wennDAVEnicht gesetzt ist, die echte Forderung nicht erzeugt wird (mit Bezahlschranke versehener Hop oder ausgefallener Händler) oder — für A2 — das benutzerspezifische Wallet nicht finanziert werden kann.
25.7. Die Parser fuzzen¶
Drei Oberflächen parsen Bytes, die ein Angreifer gewählt hat — der MIME-Durchlauf (pepsi_crypto::classify, der bei jeder eingehenden Nachricht vor jeder Authentifizierung läuft), unser eigener handgeschriebener S/MIME-CMS-Öffner und der OpenPGP-Leser einschließlich seines Pfads für komprimierte Pakete —, dazu der Parser für die eingehende Authentifizierung und die Parser des Mailinglisten-Subsystems für Bounces, Beiträge, mboxes und importierte Mailman-Konfigurationen. Keiner von ihnen darf panicken, abbrechen oder davonlaufen, und diese Zusage wird auf zwei Wegen gehalten.
make fuzz führt jeweils ein libFuzzer-Ziel aus:
make fuzz # FUZZ_TARGET=parse, 300 s
make fuzz FUZZ_TARGET=cms FUZZ_TIME=3600
make fuzz FUZZ_TARGET=pgp FUZZ_TIME=0 # until interrupted
Die acht Ziele unter fuzz/fuzz_targets/ sind parse (der Parser für die eingehende Authentifizierung), classify (der MIME-Durchlauf), cms (der CMS-Öffner), pgp (der OpenPGP-Leser), bounceparse (die RFC-3464-Extraktion und die heuristischen Bounce-Erkenner), mimebuild (der Parse-Modify-Rebuild-Pfad der Posting-Stage der Mailingliste, der neben der Abwesenheit von Panics auch den Hin-und-Rückweg prüft), pickle21 (der Leser für Mailman-2.1-config.pck, der prüft, dass nie etwas konstruiert wird) und mboxsplit (der mbox-Zerleger, den der Archiv-Importer verwendet). FUZZ_TIME begrenzt einen Lauf in Sekunden (0 heißt: laufen, bis unterbrochen wird), und FUZZ_FLAGS reicht alles Weitere an libFuzzer durch. Die Saat-Korpora liegen in fuzz/corpus/<target>/, das nicht versioniert ist: PEPSI_CRYPTO_WRITE_FUZZ_CORPUS=1 cargo test -p pepsi-crypto --test sweep schreibt die Saaten, führen Sie es also in einem frischen Checkout einmal vor dem Fuzzing aus; Funde landen in fuzz/artifacts/<target>/.
Für eine Kampagne auf vielen Kernen startet fuzz/campaign.sh mehrere Ziele gleichzeitig unter AddressSanitizer, jedes im Fork-Modus von libFuzzer mit seinem eigenen Anteil an den Kernen, und hält pro Ziel ein Korpusverzeichnis, auf dem aufeinanderfolgende Läufe aufbauen:
cd fuzz && for t in parse classify cms pgp; do
cargo +nightly fuzz build -O --debug-assertions $t; done
fuzz/campaign.sh p1 3600 "parse:24 classify:80 cms:90 pgp:54"
Die erste solche Kampagne — acht Stunden auf 256 Kernen, etwa vier Milliarden Ausführungen — fand keinen Absturz, kein Speicherleck und kein Hängen.
fuzz/ ist ein eigener Cargo-Workspace, vom Wurzel-Workspace ausgeschlossen, weil libfuzzer-sys die Nightly-Toolchain und eine Sanitizer-Laufzeit braucht — die stabilen Qualitätsschranken bauen ihn also nie, und make fuzz ist ein bewusstes, teures Opt-in-Ziel. Ohne cargo-fuzz oder eine Nightly-Toolchain überspringt es mit dem Installationshinweis und endet mit 0, sodass es harmlos ist, es auf einer Maschine mit nur Stable auszuführen.
Die immer aktive Hälfte ist stabil und braucht kein Nightly: pepsi-crypto/tests/sweep.rs ist ein deterministischer Mutationsdurchlauf über dieselben drei Krypto-Oberflächen, Eingabe für Eingabe, und parse_verify_never_panics in pepsi-common deckt die vierte ab. Beide laufen unter einfachem cargo test — also unter make check —, sodass eine Regression, die eine Fuzzing-Sitzung fände, meist schon von der gewöhnlichen Schranke gefangen wird.
25.8. Beschränkungen¶
Tests dürfen niemals echte Mail an Drittanbieter-MX-Hosts senden: Die Suite verwendet nur die eigenen Domains der Operatoren und reservierte/.invalid-Namen (z. B. leitet der DELAY-Test über einen Empfänger in blackhole.invalid an eine nicht routbare 192.0.2.0/24-TEST-NET-1-Adresse weiter). Die Entwickler-uid kann die privilegierten Ports 25/53 nicht binden, sodass die privilegierten Listener nur auf dem installierten Host ausgeübt werden.