Quatorze tickets épuisés : auth, corps bornés, knip, eqs check, rétrofit des comptes #119

Merged
nicolas-fryder merged 17 commits from nicolas-fryder/dev into main 2026-10-07 06:10:09 +00:00 AGit

Ferme #87, #88, #89, #101, #115, #116, #117, #79, #85, #80, #57, #118 (et #113, #100 de la PR précédente si non fermés). Trouvé en route, plus grave que les tickets : provision jit créait chaque compte Entra sans rôle ; lireCorps de platform-next lisait un corps sans fin jusqu'à tuer le processus ; la migration des mots de passe annoncée sans réinitialisation était impossible (verifierMotDePasseHerite, cahier d'auth §8 bis, D-056). Chaque ticket a sa chasse (25 à 34) et des tests qui rougissent sur l'ancien code. Reste ouvert : #77, deux décisions de flotte. Rien n'est publié : 29 changesets en attente. Porte verte. 🤖 Generated with Claude Code

Ferme #87, #88, #89, #101, #115, #116, #117, #79, #85, #80, #57, #118 (et #113, #100 de la PR précédente si non fermés). Trouvé en route, plus grave que les tickets : provision jit créait chaque compte Entra sans rôle ; lireCorps de platform-next lisait un corps sans fin jusqu'à tuer le processus ; la migration des mots de passe annoncée sans réinitialisation était impossible (verifierMotDePasseHerite, cahier d'auth §8 bis, D-056). Chaque ticket a sa chasse (25 à 34) et des tests qui rougissent sur l'ancien code. Reste ouvert : #77, deux décisions de flotte. Rien n'est publié : 29 changesets en attente. Porte verte. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
`creerMutator` et `creerMutatorNavigateur` gardaient le `fetch` global
de leur création. `eqsMutator` étant créé au chargement du module, un
`vi.stubGlobal('fetch', …)` n'était jamais vu et le test appelait
l'amont pour de vrai, avec un 502 qui accusait l'amont. Mesuré ici :
les deux cas du nouveau banc partaient sur le réseau.

Chasse 26 : aucune autre fabrique ni constante de module ne fige une
valeur globale au chargement.

Closes #87

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`rateLimitStorage: 'database'`, recommandé en production, faisait écrire
better-auth dans une table que le fragment ne déclarait pas : 500 sur
chaque route gardée. Le fragment est désormais comparé champ par champ
à `getAuthTables` pour les options de `creerAuth` ; le test isolait
exactement les quatre manques de `rateLimit`, les 35 autres points
concordaient.

Chasse 27 : `roles.schema.json` refusait une clé inconnue que
`validerCatalogue` ignorait — `herites:` retirait l'héritage d'un rôle
en silence au démarrage. Le validateur suit le schéma ; les six
`roles.yaml` de la flotte passent. Le cahier annonçait des tables
`Role` et `UserRole` qui n'ont jamais existé.

Closes #88

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`sign-in/email` est anonyme, et better-auth y dérive le mot de passe sans
en vérifier la longueur. Mesuré : scrypt n'amplifie pas la taille (50 Mo
→ 440 ms) ; le risque est la mémoire d'un corps non borné. Le corps de
toute route `/api/auth` est borné à 16 Kio, sur les octets lus, des deux
côtés : `porteAuth` (Nest) et `authRoute()` (Next). Prouvé par un envoi
par morceaux sans Content-Length ; une connexion légitime par morceaux
passe toujours. `maxPasswordLength: 128` à côté du minimum.

Chasse 28 : `lireCorps` de platform-next se disait plafonné et lisait
`request.text()` en entier avant de mesurer, en caractères. Sur un flux
sans fin, le processus mourait (OOM, rejoué). Un seul lecteur borné,
`lireCorpsBorne`, sert les deux.

Closes #89

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Les motifs déduits du gabarit revenaient en indices de configuration
imputés au knip.ts du satellite, qui ne pouvait pas les retirer. Mesuré
sur trois dépôts, problèmes identiques avant et après : nuage 35 → 8
indices (tous ses propres ajouts), eqs-demo 19 → 0, gabarit 15 → 0.

`entry`/`project` filtrés sur ce qui existe ; un `ignore` n'est posé que
s'il retire un fichier que knip lirait (`.gitignore` couvrait déjà
dist/ et .next/) ; le seed et le schéma Prisma multi-fichiers sont des
entrées au lieu d'un `ignore` de tout prisma/ qui cachait les
dépendances du seed ; `@eqs/tooling`, `prisma.config.ts` et
l'instrumentation Next ne sont plus déclarés, knip les voit. Le banc
rougit sur l'ancienne version. Chasse 29.

Closes #101

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`git ls-files --cached` liste l'index : un fichier qu'un générateur
vient de supprimer y figurait jusqu'au `git add`, et Prettier échouait
sur un chemin absent. Ces chemins sont mis de côté et nommés en une
ligne. La liste vient d'un module testable ; le banc joue la tâche
construite dans un vrai dépôt git et rougit sur l'ancienne version.
Chasse 30 : les hooks filtraient déjà les suppressions.

Closes #115

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Le lecteur du champ `role` vivait dans l'entrée serveur du paquet ; un
front qui affiche les rôles d'un compte devait le recopier. Déplacé dans
la feuille `permissions.ts`, réexporté par `./client` et par la racine :
le test vérifie que c'est la même fonction, et le test existant que le
client n'atteint toujours aucun module serveur. Chasse 31.

Closes #116

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Une tâche déclarée qui mesure une sortie de build la lisait pendant que
`build:*` la réécrivait : rouge une fois sur deux. `apres` (noms exacts
ou préfixe `build:*`) la fait démarrer quand ses prédécesseurs ont fini,
sans ralentir les autres, en parallèle comme en séquentiel. Un
prédécesseur en échec : elle n'est pas lancée, et la porte le dit ; un
cycle est refusé en le nommant. Le banc reproduit la course à chaque
fois et rougit quand on cesse d'attendre.

Le guide de rétrofit montrait `cmd: ["tsc"]` et un champ `requiert`
jamais lu : un satellite qui le copiait perdait ses deux tâches.
Corrigé. Chasse 32.

Closes #117

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Le plan proposait `@eqs/platform-nest` à un dépôt qu'il déduisait
lui-même `next-fullstack`. Les étapes sont filtrées par le profil, et
chaque étape écartée est dite (« sans objet ») plutôt qu'effacée. Pas de
symétrie naïve : un `nest` avec un front Next garde `platform-next`.
Les trois cas rougissent sur l'ancien code. Chasse 33.

Closes #79

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
D-048 interdisait `--pass-on-unpruned-suppressions` sans que rien ne le
vérifie : `tooling.suppressions-non-purgees` (bloquant) le refuse dans
les scripts, hooks et workflows ; aucun dépôt de la flotte ne l'emploie.
`tests.eslintSuppressions` entre dans l'audit (schéma 1.1.0), pour que
`eqs baseline --diff` montre une baseline qui grossit.

Les points 1, 2 et 4 du ticket étaient déjà faits (D-048, profil lu par
`tooling.eslint-etend`). L'exemple d'audit de docs/conformite.md ne
suivait plus la forme réelle des tests : corrigé. D-055.

Closes #85

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`creerAuth({ verifierMotDePasseHerite })` : l'application vérifie son
ancien format, et le mot de passe est re-haché au format de better-auth
à la première connexion réussie. Sans lui, un hash ATLAS recopié était
lu de travers et refusait toute connexion — le cahier affirmait pourtant
une « migration sans réinitialisation ». Prouvé sur le vrai format
d'ATLAS ; les deux sabotages (sans re-hachage, sans vérificateur) sont
attrapés.

Le cahier gagne un §8 bis qui répond, mesures à l'appui, aux sept
questions : clés API réémises quand l'ancien hash ne couvre pas la clé
entière (ATLAS retire son préfixe avant de hacher), portées traduites
par l'application, sessions non migrées, rôles en minuscules, mot de
passe temporaire et verrou par compte laissés à l'application, identité
déléguée non modélisée. D-056.

Closes #80

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
La reprise des connexions de test qui n'aboutissent pas ne se disait
que par un avertissement, perdu dans une sortie verte qu'on ne lit pas.
Les deux mécanismes de reprise notent chaque connexion rejouée dans le
fichier que désigne `EQS_REPRISES` ; `eqs check` le pose pour ses
tâches, affiche le total dans son bloc final — zéro compris — et l'écrit
dans `.eqs/check.json`. Testé sur les deux mécanismes et sur la porte.
La reprise réseau de @eqs/tooling lit `EQS_REPRISES` : déclarée comme
endroit dans la configuration ESLint de la racine (D-051).

La cause des `ETIMEDOUT` en boucle locale reste inconnue (chasse 6) ; ce
qui restait demandé par le ticket, rendre la fréquence lisible, est fait.

Closes #57

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
La première version lisait les hooks et tout le texte des manifestes :
elle aurait refusé `nuage/.lintstagedrc.mjs`, qui passe
`--pass-on-unpruned-suppressions` à un lint des seuls fichiers indexés —
où ESLint ne peut pas juger les suppressions des autres fichiers et
refuserait tout commit. Trouvé par une recherche exhaustive sur la
flotte, que la recherche ciblée avait manqué.

L'interdit de D-048 vaut pour la porte : les `scripts` des manifestes et
les workflows de CI, où ESLint lit l'arbre entier. Le banc prouve qu'un
pre-commit et un lint-staged qui portent le drapeau ne sont pas refusés.
D-055 et le guide de rétrofit le disent.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`errors.validation` frappait `routeValidation` sans identité : sur une
route POST gardée, le 401 de la garde devenait trois constats bloquants
contre le filtre d'erreurs. `ContexteErrors` et `ContexteTelemetry`
prennent `enTetes`, comme `ContextePlatform`, passés aux routes de
validation, de crash, de journal et sortante ; un 401 ou 403 est dit
« non exécutable : route gardée ». Chasse 34 : même défaut sur quatre
contrôles de @eqs/telemetry et sur `errors.500-sans-pile`. Les tests
rougissent sur l'ancien code.

Closes #118

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Le registre de slots ne pouvait pas savoir ce qui tourne sur un poste
hors de la flotte, et la production publie ses propres ports. Retiré :
`cli.ports-du-gabarit` et l'obligation de réserver un slot. À la place,
`eqs ports` vérifie le `.env` local contre la machine, et
`--appliquer` décale ce qui est pris, URL comprises, sans toucher
`.env.example` — à la volée, par la personne ou son agent.

Mesuré en l'écrivant : sur ce poste, 4100 était tenu par un projet hors
flotte ; et un `listen` sur 0.0.0.0 réussissait alors que Docker
Desktop publiait le port — la détection demande aussi l'adresse par
défaut et une connexion en boucle locale. D-057.

Closes #77

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`pnpm audit:prod` avant la release : quatre avis, dont un critique
(proxy-addr 2.0.7, usurpation d'IP par express). Trois avaient un
correctif publié dans les intervalles déclarés : `pnpm update` du
verrou, sans override (chasse 23). Le quatrième, braces (élevé), demande
3.0.4, qui n'est pas publiée — accepté dans `auditConfig` avec sa raison
et la condition de retrait : atteint seulement par l'outillage ESLint,
sur des motifs que nous écrivons.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Trente changesets depuis 0.14.0 : D-051 (les exceptions sortent des
commentaires), `appel`, `urlDeConnexion`, `environnementPourSousProcessus`,
`tooling.eslint-atteint`, le profil Entra et le rôle `jit`, les corps
bornés, le fragment Prisma confronté à better-auth, le rétrofit des
comptes, `eqs ports`, `apres`, les reprises comptées, et les douze
autres tickets de la journée.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Infrastructure/eqs-platform!119
No description provided.