Blog ·
Deux règles, et un lien mort entre elles
Une exploration de 1776 pages a trouvé exactement 18 URL cassées. Les deux règles qui les produisaient étaient justes ; personne n’avait testé leur couture.
Par Provibr
Nous avons exploré le site de production dans les règles pour la première fois depuis un moment : chaque lien interne suivi, chaque alternative de langue déclarée vérifiée, chaque bloc de données structurées validé, chaque image contrôlée pour son texte de remplacement.
1776 pages, 1750 entrées de plan du site, et exactement un défaut. Zéro page orpheline, zéro chaîne de redirections, zéro erreur d’alternative de langue sur 17218 déclarations, zéro bloc de données structurées invalide sur 1642, zéro image sans texte de remplacement sur 15463, et 920 images d’aperçu social répondant toutes 200.
Le seul défaut, c’étaient 18 URL renvoyant 404 : les pages de documentation de deux panneaux de facturation, dans les neuf langues. Chacune de ces 18 avait exactement un lien interne pointant vers elle, depuis la page d’intégration du même produit dans la même langue.
Les deux moitiés de cela sont voulues. C’est ce qui rend la chose digne d’être notée.
Les deux règles
Certaines de nos intégrations se trouvent derrière un commutateur de déploiement. Quand le commutateur est baissé, le fournisseur disparaît du catalogue, du plan du site, des compteurs et du sélecteur de type dans le panneau, le tout dérivé d’une seule table pour qu’il n’y ait pas de seconde liste à oublier.
Deux d’entre elles ne sont pas tout à fait ordinaires. Pour FOSSBilling et Paymenter, il existe un module que l’on installe dans leur panneau, et la page située à /integrations/fossbilling décrit ce module. Ce n’est pas une page sur une connexion que nous proposons ; c’est une page sur une chose téléchargeable aujourd’hui. Il existe donc une règle qui maintient ces deux pages d’intégration debout quand le fournisseur derrière le commutateur est masqué, et elle porte sa raison dans la source.
La page de documentation est le cas inverse. /docs/fossbilling décrit la connexion, c’est-à-dire exactement ce que le commutateur éteint, elle disparaît donc avec le fournisseur.
Les deux règles sont justes. Un slug, deux surfaces, deux réponses, et le code comporte deux fonctions plutôt qu’une seule qui aurait tort une fois sur deux.
Ce que personne n’avait vérifié, c’est ce qui se passe entre elles. La page survivante portait le lien thématique vers la page disparue.
La règle était déjà écrite
La fonction qui produit ce lien résout un chemin de documentation à partir d’un slug d’intégration. Son propre commentaire disait, avant que tout cela n’arrive, qu’un lien vers un guide qui n’existe pas n’est pas un lien thématique mais un lien mort.
La règle était là. Elle était mesurée contre la mauvaise liste : l’ensemble des pages de documentation qui existent dans la source, plutôt que l’ensemble de celles qui répondent dans cette compilation. Ces deux ensembles sont les mêmes presque tout le temps, et le jour où ils diffèrent est le jour où quelque chose est masqué.
La réparation tient en une ligne. Ce n’est pas la partie intéressante ; la partie intéressante est qu’une règle correcte, écrite tout au long à l’endroit qui lui revient, n’est pas un contrôle. De la prose dans un commentaire décrit une intention. Seul ce qui s’exécute peut vous y tenir.
Un troisième cas qu’aucune exploration n’aurait pu trouver
Nous avons écrit un garde-fou plutôt que de simplement corriger la ligne : pour chaque slug d’intégration, le chemin de documentation résolu doit être un chemin que cette compilation sert réellement. Il a été prouvé rouge d’abord, et il a rapporté les deux pages que l’exploration avait trouvées.
Il en a aussi rapporté une troisième : notre intégration de serveur de sauvegarde, qui est derrière un autre commutateur. Sa page de documentation est masquée, et le lien vers elle était construit exactement de la même façon.
La raison pour laquelle aucun robot d’exploration ne trouvera jamais celui-là, c’est que sa page d’intégration est masquée elle aussi. Le lien mort vivait sur une page qui renvoie elle-même 404, il n’existe donc aucun chemin depuis l’extérieur vers la chose qui est fausse. Il aurait fait surface le jour où quelqu’un aurait relevé ce commutateur et livré une page portant un lien cassé, et les deux événements auraient été séparés de plusieurs semaines.
Un robot d’exploration ne peut trouver de défauts que sur les pages atteignables. Cela paraît évident une fois écrit et s’oublie facilement quand une exploration revient propre, parce qu’une exploration propre donne l’impression d’être une affirmation sur le code alors qu’elle porte sur les pages qui se trouvaient être visibles.
Le garde-fou a un test de plus qui ne fait rien d’autre que garder le premier honnête : il affirme que plus de dix slugs se résolvent réellement vers une page de documentation. Sans lui, un changement qui ferait que le résolveur ne renvoie plus rien pour aucun slug ne produirait aucun lien mort et aucun lien thématique du tout, et ces deux états se lisent à l’identique dans une exécution verte.
L’autre moitié : dire à un moteur de recherche que quelque chose a changé
La même ronde a ajouté un canal de soumission, ce qui est une petite chose avec une surprise dedans.
Le protocole est un seul POST qui indique à plusieurs moteurs de recherche qu’une URL a changé. La possession de l’hôte se prouve en servant une clé sous forme de fichier texte à la racine. Notre clé vient de l’environnement, et quand elle est absente, l’ensemble ne fait rien et le dit une fois. C’est l’état normal en développement et dans chaque test.
Deux détails méritent d’être répétés parce que les deux sont des pièges.
Le fichier de clé est servi au travers d’une réécriture, car une route dynamique ne peut pas se tenir à la racine à côté du segment de langue. Une réécriture qui capterait n’importe quoi point txt à la racine avalerait aussi le fichier robots. Deux choses l’en empêchent : la réécriture s’exécute dans la phase qui ne voit que les requêtes ne correspondant à aucun fichier réel, et le motif de clé exige au moins huit caractères, alors que robots en fait six et llms quatre. La borne inférieure n’est pas une question de propreté ; c’est la seconde serrure.
Et la soumission est accrochée à la fonction qui sait déjà que du contenu public a changé, pas au déploiement. Une livraison ne touchant qu’un écran du panneau annoncerait sinon 1750 adresses comme modifiées à chaque fois, ce qui est un bon moyen de se faire ignorer. Quand la grille tarifaire change, les deux routes qui affichent des prix sont soumises dans neuf langues, ce qui fait 18 adresses.
Ce qui ressemblait à une erreur de configuration
La première soumission réelle après le déploiement, avec la clé de production en place, a renvoyé 403.
Le fichier de clé renvoyait 200 depuis partout où nous avons essayé, y compris avec un agent utilisateur de robot d’exploration. Chaque ingrédient était en ordre. L’étape naturelle suivante consiste à aller regarder la configuration de bordure, ou la réécriture, ou l’ordre des phases, et c’est là que passe une heure.
Ce que nous avons fait à la place, c’est essayer deux choses plus petites. Une soumission d’une seule URL a renvoyé 200 immédiatement. La même soumission groupée, une minute plus tard, a renvoyé 200 elle aussi, sur les deux points d’entrée.
Le 403 était donc un effet de premier contact de leur côté, pas un défaut du nôtre. Le fichier de clé n’avait pas encore été récupéré et mis en cache par le service destinataire au moment où la première requête groupée est arrivée.
Nous l’avons noté là où vit le manuel d’exploitation, car la panne est parfaitement conçue pour envoyer quelqu’un à la chasse : le code de statut dit interdit, ce qui est une affirmation sur une permission, et tout ce qui relevait de la permission était correct. Avant d’enquêter sur un échec d’autorisation à la première requête, refaites la même requête. Cela ne coûte rien et c’est l’hypothèse la moins chère de la liste.
Il y a une note connexe pour quiconque effectuera la rotation de cette clé : le fichier est servi avec une heure de mise en cache, une rotation demande donc une purge ou une heure de patience, et pendant cette fenêtre le même 403 signifie quelque chose de complètement différent.
Ce que nous noterions
- Deux règles correctes peuvent produire un défaut dans la couture entre elles. Aucun des deux propriétaires n’a tort et aucun ne regarde.
- Un même identifiant peut avoir deux surfaces avec deux bonnes réponses. Deux fonctions, pas une.
- Une règle dans un commentaire n’est pas un contrôle. La nôtre était écrite tout au long et mesurée contre la mauvaise liste.
- Ce qui existe et ce qui répond sont deux ensembles différents, et ils divergent exactement quand quelque chose est masqué.
- Un robot d’exploration ne trouve de défauts que sur les pages atteignables. Le nôtre ne pouvait pas voir le troisième cas du tout.
- Un garde-fou trouve l’occurrence qui n’a pas encore été livrée. C’est toute la raison d’en écrire un plutôt que de corriger la ligne.
- Donnez à chaque garde-fou un test qui prouve qu’il regarde. Aucun lien mort et aucun lien du tout se lisent pareil.
- Une borne inférieure dans un motif peut être une frontière de sécurité. Huit caractères, c’est ce qui tient une réécriture à l’écart du fichier robots.
- Annoncez les changements de contenu depuis la chose qui sait que le contenu a changé, jamais depuis le déploiement.
- Réessayez avant de diagnostiquer l’échec d’une première requête. Un interdit qui devient un succès une minute plus tard n’a jamais été une question de permission.
Pour être clair sur ce dont il s’agit : l’exploration a couvert 1776 pages contre la production et 1750 entrées de plan du site avec 913 dates de modification dont aucune n’était dans le futur, la correction est une ligne unique gardée par trois tests prouvés rouges d’abord, le chemin de soumission a été éprouvé de bout en bout contre un point d’entrée simulé, cinq chemins d’échec compris, et le balayage sur une compilation de production autonome s’est terminé à 96 verts. Non prouvé : au moment où la correction a été écrite, elle était verte sur une compilation de production locale et n’avait pas encore été confirmée en production, et deux familles de routes de l’exploration n’ont produit aucune page du tout parce que leurs registres sont vides.
Issu du travail de plateforme sur Provibr. Ce qu’une migration de facturation peut et ne peut pas emporter est dans Quinze choses qui ne suivent pas, un déploiement dont l’étape de schéma n’a jamais tourné est dans La migration qui n’a jamais tourné, et un autre contrôle qui était vert parce qu’il n’arrivait jamais est dans Vert parce qu’il ne pouvait pas y parvenir.