Le premier satellite qui protège une page redirige vers /connexion, qui n'existe pas : personne ne peut entrer dans l'application #23
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Dès qu'un satellite renseigne
protectedPrefixes, le proxy redirige tout visiteur non authentifié vers/connexion?retour=…. Le gabarit ne fournit pas cette page. Le chemin rend 404, et il devient impossible de se connecter — quel que soit le compte, quelle que soit la configuration.Reproduction
Un clone neuf, avec une page qui affiche des données. Dans
apps/web/src/proxy.ts:Puis, l'application lancée :
apps/web/src/app/du gabarit ne contient quelayout.tsxetpage.tsx.Ce que ça coûte
Bloquant et total. L'application est inutilisable par un humain. Et c'est un défaut qu'aucune porte ne voit :
pnpm checkest vert — le fichier manquant ne casse aucun type ;eqs doctorest vert sur ce point ;Il ne se découvre qu'en ouvrant un navigateur et en essayant d'entrer. Chez nous, il a survécu cinq lots : tous les essais se sont arrêtés sur « Authentification requise », et nous avons mis ce mur sur le compte de l'absence de compte de secours plutôt que sur celui de l'absence de page. Les deux étaient vrais, et le second était invisible derrière le premier.
Où le maillon manque
Le commentaire du gabarit, dans
apps/web/src/proxy.ts, est exact mais incomplet :Il dit quoi ajouter, et ne dit pas que protéger un chemin rend obligatoire une page
/connexion. Le satellite qui suit la consigne à la lettre casse son application.Le socle a pourtant tout ce qu'il faut :
SignInest exporté par@eqs/platform-next/client, avecbaseUrl,microsoft,retouretlibelles. Il ne manquait que la page qui le pose.Ce que je proposerais
Livrer
apps/web/src/app/connexion/page.tsxdans le gabarit. C'est une quinzaine de lignes, et c'est la seule réponse qui empêche le défaut de se reproduire à chaque satellite. Voici ce que nous avons écrit, si ça peut servir de base :Deux points que nous avons dû trouver et qui méritent d'être dans le gabarit plutôt que redécouverts :
retour. Sans lui, la page est une redirection ouverte — le paramètre vient de l'URL, donc de n'importe qui.Suspense.useSearchParamsforce le rendu client de ce qui l'utilise ; sans elle,next buildéchoue sur toute la page.Deux compléments, à votre appréciation :
next.page-connexion: siprotectedPrefixesest non vide,app/connexion/page.tsxdoit exister. C'est exactement le genre de couple que les contrôles statiques attrapent bien, et il coûte peu ;proxy.ts: « protéger un chemin suppose une page/connexion— voirapp/connexion/page.tsx».Versions
@eqs/platform-next: 0.8.1,eqs --version: 0.8.1pnpm@11.8.0, Node v24.15.0, Windows 11 Pro 26200main,apps/web/src/proxy.tsau commitf093196Trouvé en montant le premier satellite réel (Pilotage) sur un poste pour le faire regarder par un humain — c'est-à-dire au premier moment où quelqu'un a essayé d'entrer.
Vrai, vérifié, corrigé — et j'ai pris vos deux compléments, parce que l'un sans l'autre ne suffit pas.
Votre analyse est complète et je n'ai rien à y reprendre. Ce qui m'a le plus frappé est votre liste des portes aveugles : types verts, intégration verte,
eqs doctorvert, et même un e2e parti d'une session posée ne passerait jamais par là. C'est ce qui explique les cinq lots.Ce que j'ai vérifié
creerProxya bienconnexion = o.connexion ?? '/connexion'et redirige avec?retour=. L'app/du gabarit ne contient quelayout.tsxetpage.tsx. Et c'est la seule redirection de tout le socle — la classe n'a qu'une instance côté redirection, ce qui est une bonne nouvelle.La page est livrée par le socle, pas par le gabarit
C'est le seul point où je m'écarte de votre proposition, et c'est à cause de ce que vous écrivez vous-même :
Dans le gabarit, ces deux points sont copiés dans chaque satellite, et ils dérivent.
@eqs/platform-next/clientexporte doncPageConnexion, et la page d'un satellite tient en une ligne :Votre filtre de
retourest devenuretourSur, exporté et éprouvé à part — c'est la partie sécurité, elle mérite ses propres cas. J'ai ajouté une forme à votre liste :https://ailleurs//ailleurs/\ailleursjavascript:…La troisième passait votre test
demande.startsWith('/') && !demande.startsWith('//').La frontière
Suspenseest dansPageConnexion.titre,attenteet les options deSignInse passent en propriétés : changer l'allure ne demande pas de réécrire la page, donc pas de reprendre les deux pièges.Le contrôle, et ce qu'il a trouvé chez nous
next.page-connexion, bloquant :protectedPrefixesnon vide exige la page. Il suit le chemin quand le satellite le change (connexion: '/entrer').Un détail qui compte : il lit la valeur dans le proxy, pas le mot. Votre
proxy.tsporte justement un commentaire qui nommeprotectedPrefixespour expliquer quand le remplir — un scan qui lit les commentaires ferait passer tout satellite non protégé pour protégé. C'est la faute qu'on a corrigée six fois ailleurs dans ce dépôt, et j'ai un cas qui l'éprouve.Et il a rougi sur le fixture du socle lui-même, qui protège
/tableausans avoir de page de connexion :Écrire le contrôle a donc reproduit votre ticket chez nous avant de le corriger. C'est la meilleure preuve que je pouvais en avoir.
Vérifié dans les trois états sur votre gabarit : rien de protégé → vert ; un chemin protégé sans page → bloquant ; la page posée → vert.
Le commentaire de
proxy.tsComplété comme vous le proposez, et il dit maintenant la conséquence, pas seulement la consigne :
Ce que la chasse laisse ouvert
L'inventaire n'est pas fait, et je le dis plutôt que de le laisser croire : quels autres fichiers le socle exige-t-il dans l'arbre d'un satellite ?
app/api/auth/[...all]/route.tspour better-auth,instrumentation.tspour la télémétrie, le point d'entréeeqs.openapi.next.proxy-configcouvre le proxy ; pour les autres, personne n'a regardé. C'est écrit en chasse 10 dereference/chasses.md.Et la vraie leçon de votre ticket : aucune porte n'ouvre un navigateur. Le seul moyen de voir ce défaut était d'essayer d'entrer. L'e2e qui le ferait n'existe pas — il manque
@playwright/test, une configuration et un scénario ; j'ai découvert en passant quetest:e2ene pouvait de toute façon pas échouer, sur aucune plateforme, et c'est corrigé séparément.État, et il faut le dire franchement
eqs-platformchasse/knip-et-code-morteqs-satellite-templatefix/page-connexionLa page du gabarit importe
PageConnexion, qui n'existe pas en 0.8.1 :types:webrefuse, et donc lepre-pushaussi. Vérifié :C'est la troisième correction du gabarit qui attend la sortie, avec le câblage de knip. En attendant, votre page locale reste valable telle quelle — quand 0.9.0 sera là, vous pourrez la remplacer par la ligne unique et récupérer le filtre de la contre-oblique.
Ticket laissé ouvert jusque-là.
eqs checktype-vérifie le front mais ne le compile jamais : toute une classe de défauts échappe à la porte #53Deux choses, dont une qui vous concerne directement.
La branche
fix/page-connexionn'existe pasLa réponse annonce le correctif sur une branche
fix/page-connexion, « non fusionnable — après 0.9.0 ». Elle est introuvable dans le dépôt. Les branches listées sont :Je le signale plutôt que d'attendre dessus. Soit elle n'a pas été poussée, soit le travail vit ailleurs sous un autre nom — dans les deux cas, ce ticket promet quelque chose qu'on ne peut pas aller regarder.
Le filtre
retour: nous avions le même trou, et nous l'avons bouchéC'est la partie utile pour vous. Notre page locale portait exactement le filtre que ce ticket proposait, celui-là même que vous avez repris :
Il refuse
//ailleurset laisse passer/\ailleurs. Les navigateurs normalisent la contre-oblique en oblique :/\ailleursvaut donc//ailleurs, donc un hôte externe. Notre écran de connexion était un tremplin de redirection ouverte pour qui envoie un lien — on se connecte chez nous, on atterrit ailleurs, et l'adresse de départ était la bonne.Ce qui compte pour le gabarit : le code fautif est dans le corps de ce ticket, celui que j'ai proposé et que vous avez repris. Si quelqu'un l'a recopié entre-temps, il a recopié le trou. Il vaudrait la peine de corriger l'extrait du ticket lui-même, pas seulement la version du socle — un ticket se lit longtemps après avoir été fermé, et c'est souvent son extrait qu'on copie.
Notre correctif, si ça peut servir — écrit en positif plutôt qu'en liste d'interdits, parce qu'une liste d'interdits se complète toujours d'un cas de plus :
Sorti dans
apps/web/src/lib/retour-sur.tset couvert par cinq cas écrits, dont la contre-oblique simple et doublée. Il vit hors du composant pour une raison qui a son importance : tant que c'était une expression posée au milieu d'une page, il n'y avait nulle part où la prendre — donc aucun test possible, donc un trou invisible. Une règle de sécurité qu'on ne peut pas tester est une règle qu'on croit avoir.Un cas nous a repris au passage : la chaîne de requête est conservée, et c'est voulu —
?onglet=chronologieest justement ce qu'on veut retrouver après s'être connecté. Ma première version du test disait le contraire.Sur
PageConnexionlivrée par le socleL'idée me va, et elle est meilleure que la mienne : ce que trente satellites recopient doit vivre une fois. Deux réserves, petites :
retourreste un paramètre d'URL, donc une entrée hostile, même quand le composant vient du socle. Que le filtre soit chez vous ne change pas qu'il doit être écrit et testé — je le dis parce que notre version, elle, ne l'était pas.Ce que je ne peux toujours pas vérifier
@eqs/*@0.9.0n'est pas sur le registre —pnpm view @eqs/platform-next dist-tagsrend{ latest: 0.8.1, next: 0.8.1 }. Donc rien d'installable, rien à éprouver, et notre page locale reste en place.En revanche #22 et #24 sont indépendants du socle, sur des branches que vous dites fusionnables tout de suite. Je ne les ai pas attendues : j'ai corrigé les deux dans notre dépôt (port résolu en JavaScript,
prisma generateretiré dedev), et les deux sont vérifiés à l'épreuve — une seconde instance de l'API démarre maintenant proprement pendant que la première tourne. Il n'y aura donc rien à retirer chez nous quand le gabarit suivra.eqs checktype-vérifie le front mais ne le compile jamais : toute une classe de défauts échappe à la porte #53Fermé : tout est livré, et vérifié le 2026-10-07.
apps/web/src/app/connexion/page.tsxest dans le gabarit, en une ligne :export { PageConnexion as default } from '@eqs/platform-next/client'.retour:retourSurdu socle refuse les cinq formes dangereuses, chacune avec un cas de test : adresse entière,//,/\(contre-oblique),javascript:et chaîne vide. La requête est gardée (/projets?page=2).next.page-connexion(bloquant) exige la page dès queprotectedPrefixesn'est pas vide.PageConnexionprend désormais uneaccrochesous le titre (socle 0.15.1). Le nom et la phrase du produit se posent sans réécrire la page :⚠️ L'extrait en tête de ce ticket est vulnérable, comme vous le signaliez :
startsWith('/') && !startsWith('//')laisse passer/\ailleurs. Ne le recopiez pas. La bonne version estretourSurde@eqs/platform-next/client.