25. Suite de tests¶
Pepsi est livré avec une suite de tests de bout en bout sous tests/ qui exerce un déploiement en service via SMTP, en vérifiant le comportement observable de tout le pipeline plutôt qu’une fonction isolée. C’est délibérément une suite en boîte noire : les messages sont envoyés avec la commande mail ordinaire ou par SMTP brut, et les assertions lisent les boîtes aux lettres des destinataires et la table pepsi.workqueue.
Cela complète — sans les remplacer — les tests unitaires de l’arbre (cargo test --workspace), qui couvrent la logique pure (SRS, rétrogradation MIME, construction de DSN, scoring de langue, classification DNS, …) sans réseau.
Deux choses sont couvertes entre les deux, par des tests d’intégration qui ne nécessitent ni réseau ni base de données. Les suites de migration (pepsi-setup/tests/import_*.rs et tests/cli_import.rs) exécutent chaque importateur de MTA contre un arbre /etc de fixtures, puis exécutent le vrai binaire pepsi-setup de bout en bout, jusqu’à un --wizard --import qui doit produire une configuration passant la validation propre à Pepsi ; voir le chapitre sur l’extension pour leur disposition. La suite de cycle de vie du dispatcher (pepsi-test-stages) nécessite un PostgreSQL et est exécutée par make check.
25.1. make check : la barrière sans comptes distants¶
make check est le point d’entrée de tout ce qui n’a besoin d’aucun compte de courrier réel. Dans l’ordre, il exécute :
make check-telemetry-socketetmake check-systemd-units—tests/check-telemetry-socket.shettests/check-systemd-units.sh, des vérifications de cohérence sur les unités systemd et l’empaquetage Debian qui n’ont besoin de rien d’installé et ne sautent jamais.cargo test --workspace --exclude pepsi-test-stages --locked— tous les tests de l’arbre qui se passent de base de données. (Un simplecargo test --workspaceincluraitpepsi-test-stageset aurait donc besoin d’une base de données ; préférezmake check, qui conditionne cette suite au lieu d’échouer dessus.)tests/check-lifecycle.sh— la suite de cycle de vie du dispatcher, au mieux.tests/maildir-writer-suid.sh,tests/dot-forward-suid.shettests/whitelist-suid.sh— les contrats des helpers setuid/setgid, au mieux.tests/interop-auth.sh— une vérification DKIM/ARC inter-implémentations, au mieux. Les propres tests aller-retour de Pepsi signent et vérifient avec la même bibliothèquemail-auth: ils ne peuvent donc pas détecter une transformation qui y serait systématiquement fausse ; ce script évalue des messages signés par Pepsi (les quatre combinaisonsc=, plus une copie altérée qui doit être rejetée, plus un sceau ARC) avec deux implémentations indépendantes, sans aucun DNS. dkimpy obtient les clés publiques via sadnsfunc(tests/interop-verify.py) et évalue DKIM et la chaîne ARC ; OpenDKIM les lit dans un fichierTestPublicKeysen mode de test-tdu filtreopendkimet évalue DKIM (il n’a pas de vérificateur ARC ;opendkim-testmsgest inutilisable, car il ne vérifie qu’auprès du DNS réel). ChaqueDKIM-Signatureest évaluée, la RSA et l’Ed25519 — dkimpy a besoin de PyNaCl pour cette dernière. Chaque vérificateur saute (SKIP) ses propres vérifications lorsqu’il est absent, et le script saute (SKIP) en entier en l’absence des deux. Sous Debian :apt install python3-dkim python3-nacl opendkim(le filtre se trouve dans/usr/sbin; définissezOPENDKIMs’il est ailleurs, et désactivez le serviceopendkimque le paquet active — le test ne lui parle jamais).PEPSI_INTEROP_REQUIRE=1transforme un vérificateur manquant en échec.cargo deny check— avis de sécurité, interdictions, licences et sources. Celui-ci n’est pas au mieux : il n’est sauté que lorsquecargo-denyn’est véritablement pas installé, et une vraie trouvaille fait échouer la cible. Lisezdeny.tomlavant de faire confiance à la barrière : sa listeignoren’est pas vide.make docs-linkcheck— chaque renvoi interne du manuel doit se résoudre, dans chaque langue (une construction Sphinxdummyavec les avertissements traités comme des erreurs). Sauté seulement lorsquesphinx-buildn’est pas installé.
La barrière d’interopérabilité S/MIME avec Thunderbird n’est délibérément pas dans make check — elle démarre un véritable Thunderbird (sans affichage, piloté par Marionette) et coûte une quinzaine de secondes. C’est make interop-thunderbird, et make integrationtests en dépend.
25.1.1. Intégration continue¶
Plusieurs des étapes ci-dessus sont sautées lorsqu’un outil ou une base de données manque — le bon comportement par défaut sur la machine d’un développeur, et exactement le mauvais pour une exécution automatisée, où une barrière sautée signalée en vert ressemble à une barrière franchie. contrib/ci/ contient des jobs dans la disposition qu’exécute le worker de CI de GNU Taler (la même que celle qu’utilise vendor/taler-rust/contrib/ci/) : contrib/ci/ci.sh <job> construit l’image à partir de contrib/ci/Containerfile avec podman et y exécute contrib/ci/jobs/<job>/job.sh avec l’arborescence des sources montée ; contrib/ci/run-all-jobs.sh exécute chaque job dans l’ordre. Les jobs sont :
1-gatesLes barrières de compilation :
RUSTFLAGS="-D warnings" cargo build,cargo clippy … -D warningsetcargo fmt --check.2-checkmake checkavec toutes les barrières « au mieux » armées. L’image contient dkimpy, PyNaCl, OpenDKIM, cargo-deny et Sphinx, le job démarre PostgreSQL, définitPEPSI_INTEROP_REQUIRE=1et échoue si une ligne quelconque de la transcription signale un SKIP.make checks’exécute en tant qu’utilisateur non privilégié sur une copie privée de l’arborescence, comme un développeur l’exécute — sans quoi lepepsi-setup runde la suite de cycle de vie basculerait vers des comptes système empaquetés que le conteneur n’a pas — et les trois suites setuid/setgid, qui nécessitent root, sont ensuite relancées en tant que root ; leur saut « not running as root » lors de la première passe est le seul saut accepté.CI_ALLOWED_SKIPS(une expression régulière étendue) nomme tout autre saut accepté délibérément.3-docsmake docs-all: chaque langue du manuel, PDF compris, ce qui est la construction qui échoue sur un caractère Unicode non déclaré.4-upgradeLe test de mise à niveau du schéma,
tests/check-upgrade.sh, par rapport au tag de la version précédente (sans effet tant qu’il n’en existe pas) : il compilepepsi-setupetpepsi-statusde cette version, installe son schéma et charge sa fixture figée (tests/upgrade/), effectue la mise à niveau avec cet arbre en prenant une sauvegarde, et vérifie que chaque ligne est conservée, que la sauvegarde se restaure, que le dispatcher de cet arbre vide l’ancienne file d’attente et que l’ancienne version refuse le schéma mis à niveau avec le code de sortie 78. Le script fonctionne aussi hors de la CI, à partir des programmes et du répertoire SQL d’une version précédente.
La chaîne d’outils Rust de l’image est figée (RUST_TOOLCHAIN dans le Containerfile) plutôt que de suivre stable, de sorte qu’un nouveau lint clippy ne peut pas faire passer au rouge un commit sans rapport ; mettez-la à jour délibérément. Les jobs construisent dans target-ci/ afin de ne pas invalider le target/ d’un développeur. Lancez un job localement depuis la racine de l’arborescence, avec le sous-module vendor/taler-rust initialisé, par exemple contrib/ci/ci.sh 2-check.
25.1.2. La suite de cycle de vie et sa base de données¶
pepsi-test-stages engendre le véritable binaire pepsi-dispatch face à un véritable PostgreSQL et fait des assertions sur les états des lignes pepsi.workqueue, si bien qu’il lui faut un serveur joignable. Elle a deux modes de base de données, choisis par PEPSI_TEST_DATABASE :
- non définie — la valeur par défaut, et le flux de travail de développement
Chaque test
CREATEe etDROPe sa propre base de données jetable, de sorte que la suite s’exécute en parallèle. C’est ce que fait uncargo test -p pepsi-test-stagesnu ; le rôle qui se connecte doit pouvoir faireCREATE DATABASE/DROP DATABASE.- définie (par exemple
pepsicheck) Chaque test partage cette unique base de données préexistante — jamais créée, jamais supprimée, son contenu préservé — en ne réinitialisant que
pepsi.workqueueà la mise en place. La suite doit alors s’exécuter avec--test-threads=1.
tests/check-lifecycle.sh est ce second mode automatisé : il sonde à la recherche d’une base de données pepsicheck (la créant si elle est absente), réinitialise le schéma avec pepsi-setup run --reset — après un simple run d’abord, de sorte qu’une base fraîchement créée possède le schéma _v dont l’étape de suppression retire des éléments — et exécute la suite en série contre elle, en laissant la base de données en place. Si ni le sondage ni la création ne fonctionnent, il saute : sortie 0, ce qui n’est ni une réussite ni un échec.
Quatre variables d’environnement règlent tout cela :
PEPSI_TEST_DATABASESélectionne le mode partagé et nomme la base de données. Non définie, elle signifie le mode jetable.
PEPSI_TEST_PGHOSTLe répertoire de socket pour la connexion locale authentifiée par pair. Par défaut
/var/run/postgresql.PEPSI_TEST_PGUSERLe rôle de connexion/pair sous lequel se connecter. Par défaut
$USER.PEPSI_TEST_DISPATCH_LOGMettez-la à
1pour voir les journaux propres au dispatcher engendré, que la suite fait taire par défaut.
(tests/check-lifecycle.sh lit en outre PEPSI_CHECK_DB pour renommer la base de données partagée qu’il gère, par défaut pepsicheck.)
Un test ou un module unique s’obtient par cargo test -p <crate> <name::filter>, par exemple cargo test -p pepsi-common srs::.
25.1.2.1. Les tests des frontières de privilèges¶
Six fichiers de tests vérifient les droits de base de données de La séparation des privilèges contre un vrai serveur — service_role_grants, secure_link_grants, admin_grants, whitelist_grants, setup_task et les cas de droits dans keystore et keydisc_lifecycle. Chacun exécute le provision_roles de production, puis fait un SET ROLE vers chaque compte pour demander à PostgreSQL ce qu’il a le droit de faire.
Ils sont sautés (avec une ligne SKIPPED sur stderr, visible avec --nocapture) lorsqu’un rôle audité est superutilisateur, car un superutilisateur contourne tous les droits et l’on ne peut alors rien apprendre sur la frontière. Sur une machine de développement, c’est le cas courant : le compte qui exécute les tests est pepsi, qui est aussi le rôle propre du pipeline, et c’est généralement aussi le superutilisateur du cluster. Pour les exercer, exécutez la suite avec pepsi temporairement non superutilisateur mais capable de basculer dans les autres rôles, depuis une seconde session superutilisateur, puis rétablissez-le ensuite :
$ 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 compte : il permet à pepsi de devenir chaque rôle sans acquérir ses privilèges, de sorte que les vérifications portant sur pepsi lui-même restent significatives.
Les tests de bout en bout de l’API d’administration (admin_api) comportent un cas de plus dépendant du rôle : l’écriture CONFIG_DB réussie se connecte avec options[role]=pepsi-config, elle est donc sautée (là encore avec une ligne SKIPPED) lorsque le rôle de test ne peut pas faire SET ROLE "pepsi-config". Le même droit ci-dessus la fait s’exécuter. Aucun des tests d’expiration qui s’y trouvent — expiration d’inactivité et absolue des sessions, expires_at et disabled des jetons, le job pepsi-httpd prune — n’attend qu’une fenêtre s’écoule : chacun antidate l’horodatage que la base de données compare à now(), ce que la requête qui applique la règle ne peut pas distinguer du temps qui passe.
25.2. Les builds de la documentation sont aussi des vérifications¶
make docs les exécute toutes pour la langue source et constitue l’unique cible de documentation de la barrière de qualité générale. C’est un alias de make docs-en ; make docs-de et make docs-fr construisent les mêmes artefacts à partir des catalogues traduits, et make docs-all construit toutes les langues. Quatre builds distincts s’y trouvent, et le succès de l’un dit peu de chose des autres :
make docs-html-enHTML Sphinx. Attrape les renvois cassés, les rôles inconnus et les tableaux mal formés.
make manLes pages de manuel des sections 1/5 via
docs/rst2man.py. Attrape les lignes de sur-/soulignement de titre qui ne correspondent pas à la longueur du titre — une erreur docutils que le build HTML tolère. Langue source uniquement : les pages roff sont rendues directement depuisdocs/*.rstet ne passent jamais par Sphinx, elles n’ont donc pas de catalogue de traduction.make infoLe manuel GNU info, via le constructeur texinfo de Sphinx et
makeinfo. Langue source uniquement, pour la même raison qui fait qu”install-infoenregistre un seulpepsi.infodans un seul indexdird’info.make docs-pdf-enLaTeX. La plus facilement oubliée, et celle qui échoue le plus durement. pdflatex n’a aucune glyphe pour un caractère Unicode arbitraire et ne se dégrade pas lorsqu’il en rencontre un : il avorte avec « Unicode character … not set up for use with LaTeX » et ne produit aucun PDF du tout. HTML et man rendent le même caractère sans broncher, de sorte qu’une nouvelle flèche, un caractère de filet ou une lettre grecque dans la prose passe les deux et ne casse que ce build.
Chaque caractère non-ASCII employé dans le manuel doit être déclaré dans
latex_elements["preamble"]dedocs/manual/conf.py. Le jeu de caractères de filet utilisé par les schémas de pipeline en art ASCII est délibérément ramené à de l’ASCII pur : ces schémas se trouvent dans uncode-block:: text, de sorte que le remplacement est développé dans un environnement verbatim où le mode mathématique n’est pas disponible.Le second mode de défaillance est un tableau qui ne tient pas sur une page. Sphinx ne rend une
list-tableenlongtableLaTeX — qui se scinde entre les pages et répète l’en-tête — qu’au-delà d’un seuil de nombre de lignes ; en dessous, le tableau devient untabular, qui ne peut pas se scinder du tout. L’heuristique compte les lignes, mais ce qui déborde d’une page est la hauteur, et les deux divergent fortement pour un tableau large dont les cellules se replient : le tableau récapitulatif des RFC, de 113 lignes, se scinde sans peine, alors que le tableau comparatif de 17 lignes et sept colonnes de Introduction ne se scinde pas et déborde de 397 pt sous le bas de la page.Le remède est de le dire explicitement plutôt que de se fier à l’heuristique
.. list-table:: :header-rows: 1 :widths: 20 14 14 14 14 14 14 :class: longtable
Contrairement à un caractère manquant, cela ne fait pas échouer le build — c’est un avertissement
Overfull \vboxet un PDF dont le contenu déborde de la page — aussi cherchezOverfull \vboxdans le journal et traitez tout ce qui dépasse un point ou deux comme un vrai défaut. Les dépassements inférieurs au point relèvent de l’arrondi typographique ordinaire.En lisant sa sortie, ignorez les avertissements
Hyper reference … undefineddes premières passes — latexmk résout les références en avant lors des passes ultérieures. La dernière passe, dansdocs/manual/_build/pdf/en/latex/pepsi.log, est celle qui doit être propre.
Les traductions sont vérifiées de la même façon, et la vérification n’est pas redondante : un caractère qu’un traducteur introduit — un guillemet, un guillemet allemand, une espace insécable — fait échouer le même build pdflatex de la même manière, et aucune exécution en anglais seul ne le rencontrerait jamais. make docs-all est donc une barrière de publication plutôt qu’une barrière par commit ; le PDF de chaque langue atterrit dans docs/manual/_build/pdf/<lang>/latex/pepsi.pdf, et un build allemand ou français exige en outre que le support babel de cette langue soit installé (Debian : texlive-lang-german, texlive-lang-french).
Maintenir les traductions à jour se fait avec make update-po, qui ré-extrait les modèles de messages et les fusionne dans docs/manual/locale/<lang>/LC_MESSAGES, de sorte que les paragraphes modifiés reviennent marqués fuzzy et les nouveaux non traduits. Seuls les fichiers .po sont sous contrôle de version ; Sphinx les compile au moment du build.
25.3. Topologie¶
La suite pilote trois vrais comptes de messagerie sur trois hôtes, décrits dans un petit fichier INI, tests/test-accounts.ini. Ce fichier ne fait pas partie de l’arborescence des sources : créez-le à partir du modèle avec cp tests/test-accounts.ini.sample tests/test-accounts.ini et remplacez ses comptes fictifs par des hôtes que vous contrôlez :
Rôle |
Compte (cible ssh = e-mail) |
Fonction |
|---|---|---|
|
|
Exécute Pepsi (ingress, dispatch, httpd), PostgreSQL et systemd ; également le smarthost par lequel le domaine servi relaie. |
|
|
Comptes locaux sur le domaine servi. Leur MTA relaie via ADMIN et et celui-ci lui fait confiance ( |
|
|
Un compte sur un hôte indépendant. Son courrier atteint le MX public d’ADMIN sur le port 25 en tant que MTA étranger — le chemin entrant. |
|
|
Un utilisateur unix local sur l’hôte ADMIN qui reçoit le courrier par remise locale directe dans son Maildir (le chemin de remise locale ; pas de relais ultérieur). Contrairement aux autres, on ne s’y connecte jamais directement en ssh — sa boîte aux lettres est lue en tant que root via la connexion ADMIN. Seul |
Chaque hôte est atteint via ssh sans mot de passe ; le harnais n’installe rien. ALICE/BOB utilisent un mbox (/var/mail/<user>) ; CAROL et DAVE utilisent un Maildir. Les utilitaires de boîte aux lettres sont agnostiques au format et localisent un message par un jeton unique par exécution dans les deux dispositions.
Note
Les deux autres hôtes ont leurs propres règles d’admission, et elles s’appliquent bien avant celles de Pepsi. Invisibles dans la suite de correction, qui envoie une poignée de messages, elles sont décisives dans les benchmarks, qui en envoient des centaines de milliers. Deux en particulier :
Le MX de
CAROLest l’extrémité réceptrice de chaque test sortant. Lorsqu’il s’agit lui-même d’une installation Pepsi,[pepsi-ingress] CONN_RATE_PER_SECONDetCONN_RATE_BURSTy valent par défaut 1 et 1 — une nouvelle connexion par seconde depuis une plage source donnée —, de sorte qu’un relais ouvrant une connexion par message reçoit421 4.7.0 Too many connections from your addresset diffère. Rien n’est perdu ; rien n’est mesuré non plus. Relevez-les sur cet hôte avant de croire le moindre chiffre sortant.Une fois relevés, il reste la vitesse propre de cet hôte. Si l’hôte
CAROLest bien plus petit que le MTA testé, chaque mesure sortante est le chiffre de cet hôte, et non celui de Pepsi ; le chapitre Performance explique comment lire de tels chiffres.Le MTA d”
ALICE/BOBest le smarthost où se termine la queue de relais, et lemessage_size_limitde Postfix vaut par défaut dix millions d’octets. C’est pourquoi les tailles supérieures du balayage par étape ne peuvent pas franchir le chemin du smarthost — ce que le balayage signale comme le552du saut suivant plutôt que de le deviner.
Le même fichier contient un compte qui n’est pas un compte de messagerie, dans une section [demobank] :
[demobank]
URL = https://bank.demo.taler.net
USER = pepsi-ci
PASS = pepsi-pass
Il s’agit d’un compte bancaire auprès de la banque de démonstration publique de GNU Taler, dont la monnaie (KUDOS) est de l’argent fictif. 12-wallet-topup-test.sh en a besoin parce qu’une recharge manuelle de wallet se contente d’indiquer à l’utilisateur où virer de l’argent — rien n’est crédité au wallet tant que ce virement bancaire n’a pas réellement eu lieu. Le harnais joue donc le rôle de la banque de l’utilisateur : il s’y connecte et effectue le virement demandé par les instructions envoyées par e-mail, seul moyen pour le test de vérifier que le retrait aboutit, et non simplement que des instructions ont été envoyées. Enregistrez un compte sur https://bank.demo.taler.net/ (un compte neuf démarre avec KUDOS:100 et peut aller jusqu’à KUDOS:500 de découvert — environ 120 exécutions de ce cas) ; DEMOBANK_USER, DEMOBANK_PASS et DEMOBANK_URL dans l’environnement l’emportent sur le fichier. Aucun autre script ne l’utilise, et si la section est absente, seule cette unique vérification de crédit est sautée.
25.4. Les scripts¶
tests/lib.shBibliothèque partagée sourcée par chaque script numéroté. Elle analyse l’INI des comptes, fournit les sondes
ssh/dépendances/base de données/services utilisées par le pré-vol commun, les compteurs de résultats et la sortie coloréeok/no/skip, les utilitaires SQL et de réinitialisation de l’hôte ADMIN, les utilitaires d’envoi/réception de boîte aux lettres, les utilitaires de wallet Taler, l’assertion de DSN RFC 3464, et — pour les scripts étendus —send_smtp(un émetteur SMTP brut capable de régler les paramètres ESMTP et DSN que la commandemailne peut pas) ethop_caps(une sonde de capacités EHLO). Elle n’est pas exécutable seule.01-deploy.shProvisionne un déploiement Pepsi complet sur l’hôte ADMIN à partir d’un checkout propre : utilisateurs de service, rôle/base de données PostgreSQL, le fichier de configuration (y compris tout le pipeline d’étapes),
pepsi-setup(TLS, schéma, clés DKIM, enregistrements DNS), le marchand de paiement de démonstration et les unités systemd. Il se contente de vérifier les outils requis et abandonne avec une liste précise s’il en manque — il n’installe jamais de dépendances système.02-pipeline-test.shLa suite cœur du chemin nominal (T1–T6) : l’étape anti-spam de péage à l’envoi (non payé → rebond, payé → remis, en payant de façon centralisée depuis le wallet Taler du lanceur), le filtre de langue (français sur liste noire → rebond), le chemin sortant de signature/relais (DKIM + ARC vérifiés chez le destinataire), l’apprentissage de la liste blanche avec réécriture d’enveloppe SRS, et un second utilisateur local.
03-dsn-test.shLes extensions DSN RFC 3461 et les variantes de rebond, à l’aide de
send_smtp:NOTIFY=NEVERsupprime le DSN (D1) ;ENVID/ORCPTsont renvoyés en écho (D2) ;RET=HDRSne renvoie que les en-têtes (D3) ;NOTIFY=SUCCESSavecORIGINATE_SUCCESS_DSNproduit un DSN positif (D4) ; un destinataire NXDOMAIN est acheminé vers le rebond par défaut (D5) ; un relais injoignable produit un DSN de DELAY (D6) ; et un rebond à expéditeur nul vers une adresseSRS0=…est redécodé par l’ingress vers l’expéditeur original (D7).04-settings-test.shLa couche de redéfinition par adresse : une ligne
pepsi-settingschange l’issue d’un destinataire mais pas celle d’un autre (S1) ; un compte édite ses propres redéfinitions par e-mail et reçoit un accusé (S2) ; une édition d’une section horsEDITABLE_STAGESest rejetée et ne stocke rien (S3) ; et unDATAunique avec des redéfinitions divergentes par destinataire est scindé en lignes distinctes de la file d’attente (S4).05-mime-test.shLa gestion 8BITMIME / SMTPUTF8 : un corps 8 bits et un
SubjectUTF-8 survivent intacts au relais lorsque le saut de remise annonce l’extension, sont rétrogradés (quoted-printable/base64, RFC 2047) lorsqu’il ne l’annonce pas, et une adresse de destinataire non ASCII que le saut ne peut représenter échoue de façon permanente. Le script sonde d’abord l’EHLO du saut et prend la branche correspondante.06-cli-test.shLes CLI d’opérateur, exécutées directement via
ssh:pepsi-config(get/dump/pathsub),pepsi-whitelist(add/list/remove et les indicateurs dkim/signature),pepsi-settings(set/get/list/unset/remove),pepsi-tlsrpt(report--dry-run/ prune) et le point de terminaison/metricsdepepsi-httpd.07-maildir-test.shLa remise directe (Maildir local) via l’étape
pepsi-stage-relay-to-maildir, qui pilote lepepsi-helper-maildir-writersetuid-root. Un message vers l’utilisateur localDAVEarrive dans son Maildir avec les en-têtesReturn-Path/Delivered-To/Receivedajoutés en tête (L1) ; un message unique destiné à un destinataire local et un distant est scindé,daveétant remis localement tandis qu”aliceest relayée plus loin (L2) ; et un message vers un compte délibérément non remettable (dave-broken, sans home utilisable) abandonne au-delà deMAX_LIFETIMEet renvoie un DSN d’échec à l’expéditeur (L3). Comme[stage-local]se situe après les filtres entrants (… → anti-spam → local → srs), l’expéditeur est d’abord mis en liste blanche pour franchir la barrière de péage à l’envoi. Tout le script saute proprement lorsqueDAVEn’est pas défini, que le déploiement n’a pas de[stage-local], ou que les utilisateurs cibles manquent.11-lmtp-test.shLa remise locale par LMTP (
pepsi-stage-relay-to-lmtp) contre un vrai Dovecot sur l’hôte ADMIN, de sorte que le script Sieve du destinataire s’exécute pendant que le MDA range le courrier : un message dont leSubjectporte le déclencheur Sieve est placé parfileinto :createdans un dossier Pepsi (S1, ce qui prouve que Sieve s’est exécuté, et pas seulement que LMTP a remis), et un message vers un utilisateur inconnu est rejeté par destinataire par Dovecot et acheminé plus loin versNEXT_STAGE— l’étape ne construit jamais de DSN elle-même (S2). Le script déploie et configure Dovecot lui-même, de façon idempotente, et câble une section[stage-lmtp]jetable danspepsi.conf; il pilote directement leworkerde l’étape plutôt que de mettre LMTP dans le pipeline en service, de sorte qu’il ne perturbe aucun autre script. Il fait SKIP proprement lorsque Dovecot ne peut pas être installé ou que le binaire de l’étape est absent.12-wallet-topup-test.shLa moitié self-service de wallet par e-mail de
pepsi-stage-auto-pay(la section[stage-wallet]) : un compte local recharge son propre wallet GNU Taler par utilisateur en envoyant àpepsi-wallet@<served-domain>une commande dans leSubject:. Les trois méthodes sont exercées de bout en bout contre l’exchange de démonstration (KUDOS), avec letaler-wallet-clilocal approvisionné comme véritable pair :withdraw(instructions de virement bancaire manuel, le virement étant ensuite réellement effectué depuis le compte[demobank]),pull(une URItaler://pay-pull/que le harnais règle) etpush(le harnais pousse ; l’utilisateur accepte l’URItaler://pay-push/). Chaque cas vérifie que le message de contrôle est consommé et que le solde du wallet augmente.13-auto-pay-test.shLa moitié de paiement de demande :
pepsi-stage-auto-payrègle une demande de péage à l’envoi de retour depuis le propre wallet de l’expéditeur. La demande est produite de façon authentique — un utilisateur local envoie à un destinataire local payant (DAVE), le courrier sortant est relayé sur Internet (apposant un véritablePepsi-Origin), revient sur le MX entrant de cet hôte oùpepsi-stage-anti-spamle retient et envoie par e-mail à l’expéditeur une véritable demande. Cette demande est rejouée à travers leworkerd’auto-pay. Les deux cas utilisent des expéditeurs distincts (donc des wallets/bons de commande par utilisateur distincts) : le wallet deBOBest laissé vide, donc auto-pay redirige la demande et ne facture rien (A1) ; le wallet d”ALICEest préfinancé à l’avance (afin que le retrait lent soit hors de la courte fenêtre de paiement de 30 s du paywall), donc auto-pay règle la demande dans ce délai — le bon de commande passe à payé, le wallet est débité, et le message retenu est libéré et remis àDAVE(A2).14-multi-recipient-test.shLe fan-out de destinataires, le mode de défaillance où un message adressé à plusieurs personnes n’en atteint qu’une partie. Les deux cas vérifient la remise positive à chaque destinataire prévu. T1 envoie une seule enveloppe à deux destinataires distants et exige que les deux arrivent — un relais qui prend
rcpt_to.first()puis termine la ligne ne transmet rien d’autre. T2 couvre le fan-out~/.forward: une enveloppe adressée à un utilisateur local qui fait suivre (DAVE) et à un second destinataire ordinaire, où la copie suivie et le destinataire en passe-plat doivent chacun arriver exactement une fois — une étape qui réduit la ligne de base de données côté serveur sans modifier le message en mémoire laisse un successeur fusionné travailler sur une liste de destinataires périmée. T2 nécessite le compte facultatifDAVEet une étape~/.forwarddéployée.15-debian-deploy-test.shL’artefact empaqueté et l”assistant — le véritable chemin d’installation de l’opérateur, là où
01-deploy.shconstruit depuis un checkout et écrit la configuration à la main. Il construit le.deblocalement, l’installe sur l’hôte ADMIN (de sorte que lepostinstcrée les comptes, les rôles et les bitsdpkg-statoverride), puis exécutepepsi-setup --wizard --answerspour toute une série de scénarios, chacun suivi d’unpepsi-setup runet de véritables messages de sonde à travers le pipeline engendré par l’assistant. Il réécrit l’hôte déployé, aussi ne fait-il qu’imprimer son plan à moins quePEPSI_DEPLOY_CONFIRM=yesne soit défini.16-whitelist-import-test.shLe
pepsi-whitelistsetuid et son importateur de boîtes aux lettres, contre le déploiement installé — tout ce qui, dans ce programme, n’existe qu’une fois qu’il est installé. Il vérifie l’installation elle-même (mode4755possédé parpepsi-whitelist, le helper de scan ne portant aucun bit de privilège, le rôle de base de données limité à la table, la liste des hébergeurs) ; la règle d’espace de noms, en créant deux comptes jetables et en confirmant que l’un ne peut utiliser que<login>/…et rien d’autre, quelistne divulgue pas la liste blanche partagée de l’opérateur, et que-cest refusé ; l’import lui-même, qui doit produire exactement les destinataires du courrier que cet utilisateur a envoyé et ignorer le courrier reçu ; la décision de joker, où un domaine très fréquenté se réduit à un unique enregistrement*@domaintandis quegmail.com, avec tout autant de correspondants, ne s’y réduit pas ; l’abandon de privilèges, en substituant un helper qui rapporte ses propres identifiants et en vérifiant que l’uid de l’appelant apparaît dans les trois emplacements d’id ; le--userqui amorce l’espace de noms propre à un autre compte ; et enfin quepepsi-stage-check-whitelistconsulte le nom par utilisateur vers lequel son marqueur{localpart}se développe. Les vérifications individuelles sont ignorées lorsque le déploiement ne dispose pas de la fonctionnalité.17-crypto-test.shLa cryptographie de bout en bout : les parties de
pepsi-stage-encrypt,pepsi-stage-decryptetpepsi-keysqui n’existent qu’une fois les binaires installés setuid et le magasin de clés porteur d’une clé de chiffrement de clés. Il vérifie l’installation et la frontière de garde (4750 pepsi-crypto:pepsi; le rôlepepsine peut pas lirecrypto_identity.private_wrapped), la génération d’identités pour les deux protocoles, et l”interopérabilité plutôt que la cohérence interne : le texte chiffré de Pepsi est lu par ungpgstandard et le texte chiffré degpgest lu par Pepsi. Il couvre aussi les verdicts entrants fail-open, l’en-têteX-Pepsi-Cryptofalsifié, et le fait qu”ENCRYPT = requiredfasse rebondir le message plutôt que d’envoyer un jour du texte clair.18-wkd-test.shL’image en miroir de
17: comment les autres trouvent nos clés.pepsi-httpdsert le Web Key Directory de chaque domaine accepté, depuis le magasin de clés, en honorant l’indicateurpublishedde chaque identité — le fichier de politique, les chemins direct et avancé, le fait que les octets renvoyés s’importent dans ungpgstandard, quegpg --locate-external-keyles trouve via un vrai DNS et un vrai TLS, et qu’une identité non publiée comme un domaine que nous ne servons pas donnent tous deux un404.19-secure-link-test.shL’autre extrémité de
[stage-encrypt] ON_NO_KEY = secure-link: le texte clair est retiré du fil, le destinataire reçoit un lien par courrier et l”expéditeur un PIN. Le test couvre l’acheminement, le PIN qui part vers l’expéditeur, le comportement de divulgation du portail, le verrouillage aprèsMAX_ATTEMPTS, la lecture réussie, l’accusé de lecture, et le fait que la base de données ne détient que du texte chiffré et aucun PIN.20-admin-api-test.shL’API d’administration, via le listener
ADMIN = yessur socket UNIX que configure01-deploy.sh: que les trois mécanismes authentifient (SO_PEERCRED, un jeton porteur, une session par mot de passe), qu’un jeton est confiné à ses portées et qu’une portée manquante donne un403, que chaque point de terminaison en lecture seule répond en JSON, et queGET /api/v1/configne divulgue aucun secret.21-online-setup-test.shQue les deux frontaux d’un même questionnaire de configuration — le
pepsi-setup --wizarddu terminal et celui du navigateur sous/api/v1/setup— ne divergent pas : mêmes questions, identifiants, natures, ordre, valeurs par défaut et conditions ; des réponses qui font l’aller-retour sans changer ; les mêmes valeurs refusées par les deux ; et les mêmes réponses produisant la même configuration. Le dernier cas réécrit la configuration déployée (qu’il restaure ensuite) et est conditionné àPEPSI_DEPLOY_CONFIRM=yes; ceux en lecture seule s’exécutent toujours.22-list-api-test.shLa barrière de compatibilité des listes de diffusion, et le seul script d’ici qui ne soit pas de nous. Il exécute la suite propre de
mailmanclient3.3.5 (344 instructions de doctest dansusing.rstet 36 fonctions de test) et lesmailman_api_testsde Postorius 1.3.13 (30 fichiers, 248 fonctions) contre le serveur déployé, en ne remplaçant que le dispositif qui démarre GNU Mailman Core – ces deux remplacements sont danscontrib/compat/, versionnés à côté des épinglages. Avant eux, il vérifie ce dont l’échec se lirait autrement comme 250 traces Python rouges : que l’API répond sur le listener de boucle locale marquéLIST_API = yeset refuse sans l’identifiant, que les mêmes chemins donnent un404identique octet pour octet sur le listener public, que le crochet de réinitialisation réservé aux tests fonctionne, et un test de fumée de l’arborescence des ressources, y compris l’asymétrie400contre404sur/configet la scission décimal/hexadécimal dumember_identre/3.0/et/3.1/. Une suite qui ne peut pas être installée est signalée comme un saut expliqué et fait néanmoins échouer la passe : une barrière sautée en silence est l’autre manière dont ce test peut mentir.24-list-post-test.sh…27-list-archive-test.shLes quatre moitiés du sous-système de listes sur du vrai courrier : un message atteignant chaque membre avec sa propre URI de désabonnement en un clic ;
-join,-leaveet-confirmconduisant les flux d’abonnement ; un rejet attribué à un membre, comptabilisé, puis transformé en avertissement et enfin en retrait ; et les archives qui ingèrent, constituent les fils, cherchent et suppriment ce qui a été envoyé.Le script 24 porte aussi la phase des résumés : des messages s’accumulent, une livraison part dans chaque format vers les membres qui ont demandé ce format, le volume et le numéro sont ceux que la règle dit, et un membre qui a désactivé les résumés ce matin-là reçoit tout de même la dernière livraison. C’est une phase de ce script et non un nouveau script, parce que la suite de déploiement est déjà longue.
28-list-web-test.shLes pages publiques des listes par HTTP : que chaque route donne un
404identique octet pour octet sur un listener sansLISTS = yes; qu’une liste annoncée figure à l’index et qu’une liste non annoncée n’y figure pas et reste joignable par URL ; que le formulaire d’abonnement émet exactement un jeton en attente, n’abonne personne par lui-même, réutilise un jeton valide au lieu d’en émettre un second, et répond de façon identique pour une adresse connue et une inconnue ; qu’unGETde confirmation n’achève rien et que seul lePOSTle fait ; qu’un message se trouve à son URL HyperKitty et par la recherche, son corps échappé et non rendu ; qu’une archive privée donne un404et non un403; et que la cible en un clic de la RFC 8058 retire le membre par un uniquePOSTmême lorsqueunsubscription_policyvautmoderate, qu’elle est idempotente et qu’elle ne retire personne sur un jeton altéré.Sa dernière phase couvre le palier des membres et la console du propriétaire : créer un compte et recevoir exactement un jeton de vérification (une seconde inscription le réutilisant au lieu d’en émettre un second), vérifier et définir un mot de passe, être fait propriétaire depuis la ligne de commande, se connecter, puis le test qui compte le plus – un propriétaire change un réglage dans le navigateur et l”API REST relit la même valeur, ce qui prouve que les deux surfaces écrivent un seul enregistrement. Il vérifie aussi qu’un inconnu demandant la console obtient la même réponse que pour une liste inexistante, et qu’une soumission de réglages sans jeton CSRF est refusée.
À côté des scripts numérotés, tests/whitelist-suid.sh couvre le même contrat setuid sans SSH ni déploiement : exécuté en tant que root sur n’importe quel hôte doté d’un PostgreSQL local, il crée une base de données jetable, installe le binaire setuid dans un répertoire qui honore le bit suid et exécute les mêmes assertions d’espace de noms et d’abandon de privilèges. make check l’exécute (ainsi que les autres scripts *-suid.sh) au mieux — ils font SKIP au lieu d’échouer lorsqu’ils ne peuvent obtenir ni root, ni base de données, ni système de fichiers gérant le suid.
29-list-import-test.shL’outillage de migration. Une véritable
config.pcken protocole 0 est importée et les conversions qui ne sont pas des copies sont vérifiées par la base plutôt que par la valeur de retour du convertisseur – l’effondrement dearchive_policy, la règle de préséance DMARC, les quatre-vingt-dix jours de délai de grâce, l’espace final dusubject_prefix, le bitDisableMimeproduisant un membre en résumé texte brut et un membre désactivé pour rejets arrivant désactivé. L’import sort avec un état non nul, parce que le jeu de test porte délibérément une interdiction que personne ne peut compiler, et une seconde passe ne change rien et le dit.Sa phase médiane est la plus précieuse :
pepsi-archive exportsuivi d’unimportdans une seconde liste, en comparant le nombre de messages, chaqueMessage-IDet le nombre de fils. Cela éprouve les deux moitiés l’une contre l’autre plutôt que contre nos attentes, et un réimport n’ajoute rien – la reprise s’appuie sur le contenu, non sur un horodatage.La dernière phase est la campagne de bascule : l’histogramme par domaine, une passe à débit limité, et une seconde passe qui saute ce que la première a invité.
Ce qu’il ne fait pas, c’est dresser un vrai Mailman 3 d’amont pour importer par REST ; cela exige une installation Mailman sur la machine de déploiement. La lacune est nommée dans le script plutôt que laissée à découvrir.
30-secretary-test.shLa confirmation à l’envoi (
pepsi-stage-secretary). Le déploiement que construit01-deploy.shn’a pas de secrétariat dans sa chaîne entrante : le script en insère donc un aprèscheck-whitelistpour sa propre durée et restaure la configuration à la sortie. Il vérifie qu’un expéditeur inconnu est retenu et reçoit un défi à expéditeur nul (X1) ; qu’une réponse automatique au défi ne libère rien et ne met personne en liste blanche (X2) ; qu’une véritable réponse remet le message retenu et met l’expéditeur en liste blanche (X3), dont le message suivant passe alors sans second défi (X4) ; qu’un défi revenu en rebond envoie aussitôt le courrier retenu sur le chemin d’expiration (X5) ; et que, faute de réponse, le courrier retenu fait l’objet d’un rebond aprèsHOLD_TIME, une réponse tardive au cookie expiré ne produisant rien (X6).
25.5. Exécution¶
# 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 exécute l’ensemble complet : l”INTEGRATION_SH de la cible vaut tests/[0-9][0-9]-*.sh moins les scripts tests/[0-9][0-9]-*-bench.sh (BENCH_SH, qui ont leur propre cible make benchmarks — voir Suite de benchmarks), de sorte qu’un script est pris en compte du fait qu’il existe et non parce qu’il est listé quelque part — y compris ceux que ce chapitre ne mentionne pas. Il s’arrête au premier script en échec, et il dépend d”interop-thunderbird, de sorte que la barrière d’interopérabilité S/MIME s’exécute en premier. ACCOUNTS vaut par défaut tests/test-accounts.ini.
Chaque script s’autogère : il exécute un pré-vol (accessibilité ssh avec l’erreur réelle en cas d’échec, outils distants requis, une sonde de base de données, et l’état des trois services avec la fin du journal de tout service en panne), garantit un PAYMENT_DEADLINE court et un POLL_INTERVAL rapide pour un cycle bref, et réinitialise la liste blanche/la file/les paramètres dont il dépend. Une hypothèse manquante fait échouer le pré-vol avec un message actionnable ; un message qui n’arrive pas déclenche un vidage de diagnostics (la file d’attente en service plus le journal du dispatcher). Des paramètres ajustables tels que PAYMENT_DEADLINE_SECS, DELIVER_TIMEOUT et WITHDRAW_AMOUNT sont redéfinissables par l’environnement. Chaque script ne sort en 0 que lorsqu’aucun cas n’a échoué (les sauts sont autorisés).
25.6. Sauts et cas conditionnés¶
Un cas saute (plutôt que d’échouer) lorsqu’une condition préalable qu’il ne peut satisfaire est absente, toujours avec une raison d’une ligne. Les plus courantes :
Aucun wallet Taler utilisable. Le volet payé de
02saute si letaler-wallet-clilocal manque ou est incompatible avec l’exchange de démonstration. Tous les paiements sont effectués de façon centralisée depuis le wallet du lanceur (en production, chaque expéditeur paierait pour son propre message).Le déploiement ne dispose pas d’une fonctionnalité.
03/04sautent les cas qui nécessitent des fonctionnalités de pipeline que le déploiement ne configure pas (ORIGINATE_SUCCESS_DSN, unBOUNCE_STAGEde[stage-internet], le relais trou noir[stage-delaytest], l’étape[stage-edit-settings]) — relancez01-deploy.shpour les activer.06saute le caspepsi-tlsrptsauf si une section[pepsi-tlsrpt]est configurée.07saute entièrement lorsque le compte facultatifDAVEn’est pas défini, que le déploiement n’a pas de[stage-local], ou que les utilisateurs ciblesdave/dave-brokenmanquent sur l’hôte ADMIN. Le cas T2 de14saute lorsqueDAVEn’est pas défini ou que le déploiement n’a pas d’étape~/.forward.Capacité du saut.
05prend sa branche pass-through, de rétrogradation ou d’adresse non représentable selon que le saut de remise annonce 8BITMIME / SMTPUTF8 ; les cas qui exigent que le saut n’ait pas une extension sautent lorsqu’il l’annonce. Ce côté est de toute façon couvert par lerfc2231_downgrade_lifecycledepepsi-test-stages, qui relaie via la véritable étape smarthost vers un serveur fictif n’annonçant aucune des deux extensions.Wallet / auto-pay non déployé.
12/13sautent entièrement lorsque les sections[stage-wallet]/[stage-pay],taler-wallet-cliou le comptepepsi-walletssont absents (relancez01-deploy.sh). Le volet de créditwithdrawde12saute sans compte[demobank](voir ci-dessus) ; ses caspull/pushsautent sans wallet local utilisable.13saute lorsqueDAVEn’est pas défini, que la véritable demande n’est pas produite (saut payant ou marchand en panne), ou — pour A2 — que le wallet par utilisateur ne peut être financé.
25.7. Fuzzing des analyseurs¶
Trois surfaces analysent des octets choisis par un attaquant — le parcours MIME (pepsi_crypto::classify, qui s’exécute sur chaque message entrant avant toute authentification), notre propre ouvreur CMS S/MIME écrit à la main, et le lecteur OpenPGP y compris son chemin de paquets compressés — plus l’analyseur d’authentification entrante et les analyseurs du sous-système de listes de diffusion pour les rebonds, les contributions, les mbox et les configurations Mailman importées. Aucun d’eux ne doit paniquer, avorter ni s’emballer, et cette affirmation est tenue de deux manières.
make fuzz exécute une cible libFuzzer à la fois
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
Les huit cibles sous fuzz/fuzz_targets/ sont parse (l’analyseur d’authentification entrante), classify (le parcours MIME), cms (l’ouvreur CMS), pgp (le lecteur OpenPGP), bounceparse (l’extraction RFC 3464 et les détecteurs heuristiques de rebonds), mimebuild (le chemin analyse-modification-reconstruction de l’étape de publication des listes de diffusion, qui vérifie l’aller-retour en plus de l’absence de panique), pickle21 (le lecteur de config.pck de Mailman 2.1, qui vérifie que rien n’est jamais construit) et mboxsplit (le découpeur de mbox qu’utilise l’importateur d’archives). FUZZ_TIME borne une exécution en secondes (0 signifie jusqu’à interruption) et FUZZ_FLAGS transmet tout le reste à libFuzzer. Les corpus de départ résident dans fuzz/corpus/<target>/, qui n’est pas suivi par Git : PEPSI_CRYPTO_WRITE_FUZZ_CORPUS=1 cargo test -p pepsi-crypto --test sweep écrit les graines, lancez-le donc une fois dans une copie fraîche avant de fuzzer ; les trouvailles atterrissent dans fuzz/artifacts/<target>/.
Pour une campagne sur de nombreux cœurs, fuzz/campaign.sh lance plusieurs cibles à la fois sous AddressSanitizer, chacune dans le mode fork de libFuzzer avec sa propre part des cœurs, et conserve par cible un répertoire de corpus sur lequel s’appuient les exécutions successives
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"
La première campagne de ce type — huit heures sur 256 cœurs, environ quatre milliards d’exécutions — n’a trouvé ni plantage, ni fuite, ni blocage.
fuzz/ est un espace de travail Cargo distinct, exclu de celui de la racine, parce que libfuzzer-sys a besoin de la chaîne d’outils nightly et d’un runtime de sanitizer — de sorte que les barrières de qualité stables ne le construisent jamais, et que make fuzz est une cible délibérée, coûteuse et sur consentement explicite. Sans cargo-fuzz ni chaîne d’outils nightly, elle fait SKIP avec l’indication d’installation et sort en 0, de sorte que l’exécuter sur une machine uniquement stable est sans conséquence.
La moitié toujours active est stable et n’a besoin d’aucun nightly : pepsi-crypto/tests/sweep.rs est un balayage de mutations déterministe sur les trois mêmes surfaces cryptographiques, entrée par entrée, et le parse_verify_never_panics de pepsi-common couvre la quatrième. Les deux s’exécutent sous un simple cargo test — c’est-à-dire sous make check — de sorte qu’une régression qu’une session de fuzzing trouverait est généralement attrapée d’abord par la barrière ordinaire.
25.8. Contraintes¶
Les tests ne doivent jamais envoyer de courrier réel vers des hôtes MX tiers : la suite n’utilise que les domaines propres aux opérateurs et des noms réservés/.invalid (par exemple le test DELAY relaie vers une adresse non routable 192.0.2.0/24 de TEST-NET-1 via un destinataire dans blackhole.invalid). L’uid de développement ne peut pas se lier aux ports privilégiés 25/53, de sorte que les listeners privilégiés ne sont exercés que sur l’hôte déployé.