Retour au Centre de connaissances
Empreinte

Chrome for Testing : épingler un build, pas une empreinte

L’endpoint de disponibilité publie quatre canaux et trois artefacts par plateforme à une version. Épingler cette version laisse dehors polices, GPU et horloge.

BotBrowser Team

Documentation

Vous voulez la documentation structurée pour Empreinte ?

Cet article fait partie de la bibliothèque éditoriale. Pour les étapes de configuration, la référence et les mises à jour continues, passez directement à la section docs.

Un build épinglé est le gain de reproductibilité le moins coûteux disponible, et il est plus petit qu'il n'y paraît. BotBrowser fournit un profil déclaré qui maintient cohérentes entre elles les surfaces qu'une page peut lire d'un lancement à l'autre, et il ne tranche pas quel binaire est installé. La lecture directe des endpoints Chrome for Testing montre quatre canaux avec leurs versions, six plateformes publiant chacune un navigateur, un driver et un headless shell à une même version, puis la liste des valeurs qui continuent de bouger une fois la version figée.

TL;DR

  • L’endpoint de disponibilité publie quatre canaux, Stable, Beta, Dev et Canary, chacun avec une version et une révision.
  • À la date de lecture, Stable était 157.0.8103.50 en révision 1717349 et Canary était 159.0.8154.2 en révision 1739869.
  • Chaque plateforme publie trois artefacts à une version : le navigateur, chromedriver et chrome-headless-shell.
  • Six plateformes sont couvertes, linux-arm64, linux64, mac-arm64, mac-x64, win32 et win64, et les trois artefacts existent pour chacune.
  • Chaque URL publiée pour une version porte cette même chaîne de version, et c'est ce qui donne un sens à un épinglage.
  • La liste des versions connues comme bonnes contenait 2626 versions, de la majeure 113 à la 159, au moment de la lecture.
  • Épingler le build corrige le moteur de rendu et le driver ensemble, et il ne corrige pas les polices, les pilotes GPU, les bibliothèques système ni l'horloge.
  • Un profil décrit ce que l'environnement annonce ; un build épinglé décrit ce qui a été installé. Les deux sont nécessaires et aucun ne remplace l'autre.

Sommaire

Trois panneaux. Le premier énumère les quatre canaux avec leurs versions et révisions. Le second montre six plateformes, chacune portant un navigateur, un driver et un headless shell à une même chaîne de version. Le troisième sépare ce qu'un build épinglé corrige de ce qui continue de bouger : polices, pilotes GPU, bibliothèques système et horloge.

Ce que publient les endpoints

Le premier fait utile est que la disponibilité est publiée comme des données et non comme une page de téléchargement, et c'est ce qui rend un épinglage automatisé possible. Deux endpoints portent l'essentiel de ce dont un pipeline a besoin : l'un rapporte le dernier build connu comme bon par canal, l'autre rapporte toutes les versions connues comme bonnes.

last_known_good_channels: Stable, Beta, Dev, Canary
  Stable: version=157.0.8103.50 revision=1717349
  Beta:   version=158.0.8127.18 revision=1727472
  Dev:    version=159.0.8144.0 revision=1735750
  Canary: version=159.0.8154.2 revision=1739869

Deux champs comptent et ils répondent à des questions différentes. La version est la chaîne qu'un lecteur reconnaît, et la révision est la position de commit sous-jacente dans le dépôt Chromium. Un épinglage écrit contre la version est lisible ; un épinglage écrit contre la révision reste sans ambiguïté même si un canal republie un build. Enregistrer les deux est l'option peu coûteuse, et n'enregistrer que la version est l'erreur courante.

La structure des canaux compte aussi pour un pipeline qui veut de la stabilité sans obsolescence. Stable bouge lentement et constitue le bon choix par défaut pour une porte de release. Beta, Dev et Canary bougent plus vite et servent à détecter un changement avant qu'il n'atteigne Stable, ce qui est l'inverse de ce que demande une exigence de reproductibilité. Un pipeline qui suit Canary pour obtenir du déterminisme a choisi le canal le plus mobile pour le travail qui exige le plus lent.

known_good_count: 2626
oldest: 113.0.5672.0   newest: 159.0.8154.2
majors_present (last six): 154, 155, 156, 157, 158, 159

La taille de cette liste est l'argument pratique pour la lire par programme. Deux mille six cents versions ne sont pas un nombre qu'une personne parcourt à l'œil, et un épinglage édité à la main dérive dès que quelqu'un copie une version depuis un billet publié plutôt que depuis l'endpoint.

Trois artefacts, une version

Le deuxième fait est celui qui casse la plupart des pipelines qui n'épinglent que le navigateur. Chaque version publie trois artefacts distincts, et une installation d'automatisation qui fonctionne a besoin que les trois concordent.

chrome_platforms: linux-arm64, linux64, mac-arm64, mac-x64, win32, win64
mac-arm64: chrome=true driver=true shell=true
linux64:   chrome=true driver=true shell=true
win64:     chrome=true driver=true shell=true
distinct_versions_in_urls: 157.0.8103.50
all_artefacts_agree: true

Cette dernière ligne est celle qui porte tout. Chaque URL publiée pour la version porte la même chaîne de version, donc épingler une valeur épingle l'ensemble. Quand les trois divergent, la panne n'est pas aléatoire : un driver plus récent que son navigateur refuse de s'attacher, et un headless shell d'un autre build rend différemment du navigateur qu'il est censé représenter.

Le headless shell est l'artefact que les équipes oublient, et c'est celui qui change les résultats en silence. Un test exécuté contre chrome-headless-shell ne s'exécute pas contre le binaire du navigateur, donc épingler le navigateur en laissant flotter le shell produit un pipeline où le moteur de rendu change sans que le numéro de version bouge. Vérifier que les trois annoncent la même version est une assertion d'une ligne, et elle attrape le cas qu'un épinglage du seul navigateur ne peut pas.

pin = "157.0.8103.50"
assert browser_version == pin
assert driver_version  == pin
assert shell_version   == pin

La même structure explique une panne qui ressemble à de l'instabilité. Une image de conteneur qui installe le navigateur depuis une source et le driver depuis un gestionnaire de paquets peut finir avec deux versions de la même majeure, qui fonctionnent la plupart du temps et échouent par intermittence sur la seule capacité qui a changé. L'assertion ci-dessus transforme cette panne intermittente en erreur au démarrage, ce qui est le résultat qui vaut le coût.

Ce qu'un épinglage corrige et ne corrige pas

Le troisième fait est celui qui décide si un épinglage suffit, et la réponse honnête est qu'il corrige moins qu'un lecteur ne l'espère. Un build épinglé corrige le moteur de rendu et le driver ensemble, parce que ce sont les artefacts qu'il nomme.

pinned by the build:  renderer version, driver version, headless shell version
not pinned:           fonts, GPU driver, system libraries, time zone, clock

Les polices sont le résidu le plus courant. Un conteneur avec un navigateur épinglé et sans police CJK rend une page chinoise en rectangles, et le résultat en pixels diffère de celui d'une machine de développement avec la même version de navigateur. Rien dans l'ensemble d'artefacts ne corrige cela, parce que les polices viennent de l'image du système d'exploitation et non du paquet du navigateur.

La pile GPU est le second. Un navigateur épinglé sur une machine à rendu logiciel produit une sortie canvas et WebGL différente du même navigateur sur une machine dotée d'un adaptateur réel, et les deux sont la même version. Cette différence est mesurable et ce n'est pas un défaut de l'épinglage ; c'est une variable que l'épinglage n'a jamais couverte.

L'horloge et le fuseau horaire sont le troisième, et ils sont les plus faciles à négliger parce qu'ils ne font pas du tout partie du navigateur. Un test qui lit une date formatée ou une chaîne dépendante de la locale peut passer et échouer sur le même build selon la configuration de l'hôte, et un rapport qui n'enregistre que la version du navigateur ne peut pas expliquer la différence.

La lecture pratique est qu'un épinglage est une première étape nécessaire et un mauvais point d'arrêt, la même conclusion que le mode déterministe pour l'automatisation atteint depuis l'ordonnancement. Il retire la plus grande source de dérive, le moteur de rendu qui change sous un test figé, et il laisse trois sources plus petites qu'un enregistrement doit nommer séparément. Un pipeline qui enregistre le build et rien d'autre peut répondre à « le navigateur a-t-il changé » et ne peut pas répondre à « l'environnement a-t-il changé ».

Une quatrième observation a sa place ici parce que c'est elle qui transforme un épinglage en routine opérationnelle. Les canaux bougent selon leur propre calendrier, donc un épinglage jamais révisé devient la décision de cesser de recevoir des correctifs. La routine qui garde un épinglage honnête a trois étapes et aucune n'est automatique : lire l'endpoint, comparer la version Stable publiée avec celle épinglée, et décider si l'écart est un correctif de sécurité qu'il faut prendre ou un changement de fonctionnalité qui peut attendre la prochaine fenêtre planifiée.

pinned:   157.0.8103.50
published:157.0.8103.50
delta:    none
action:   none

Cette comparaison est peu coûteuse et c'est l'étape que les équipes sautent. Un pipeline qui épingle et ne compare jamais finira par exécuter un build avec un défaut connu pendant que le tableau de bord affiche un numéro de version sain, parce que la version est épinglée et semble donc intentionnelle. Enregistrer la valeur publiée à côté de la valeur épinglée rend la dérive visible sans demander à quiconque de se souvenir du moment où l'épinglage a été écrit.

Il y a une seconde raison de garder la comparaison. Un saut de version majeure change le moteur de rendu d'une manière qu'un saut de correctif ne change pas, et un épinglage qui traverse une majeure est une décision différente d'un épinglage qui prend un correctif. Traiter les deux comme « une mise à jour » fusionne un changement à faible risque et un changement à risque élevé en une seule action, et la revue qui suit est alors soit trop lourde pour le correctif, soit trop légère pour la majeure.

La chaîne de version elle-même porte cette information et un lecteur peut l'utiliser sans journal des modifications. Les quatre composants suivent les champs que Chromium enregistre dans chrome/VERSION : MAJOR.MINOR.BUILD.PATCH, donc 157.0.8103.50 se lit majeure 157, mineure 0, build 8103 et correctif 50. Un changement du premier composant est celui qui mérite une nouvelle base de référence complète ; un changement du dernier est en général le moins perturbant. Lire la chaîne au lieu de la traiter comme un jeton opaque est ce qui rend ce jugement possible avant tout téléchargement.

Rien de tout cela n'exige un nouvel outil. L'endpoint est en JSON, la comparaison est une égalité de chaînes, et l'assertion est trois contrôles au démarrage. Ce que cela exige est la décision d'enregistrer le build à côté du profil, parce qu'un rapport qui nomme l'un et pas l'autre ne peut pas répondre à la question qu'un lecteur posera réellement.

Conclusion pratique

Lisez l'endpoint de disponibilité plutôt qu'un billet, enregistrez la version et la révision ensemble, et affirmez au démarrage que le navigateur, chromedriver et chrome-headless-shell annoncent tous la valeur épinglée. Suivez Stable pour une porte de release et réservez les canaux rapides à la détection de changement, parce qu'une exigence de déterminisme et une exigence de fraîcheur tirent en sens opposé. Enregistrez ensuite ce que l'épinglage ne couvre pas, c'est-à-dire le jeu de polices, la pile GPU, les bibliothèques système et l'horloge. Pour le contrat de release que cela met en œuvre, lisez épingler et mettre à jour les versions du navigateur ; pour comprendre pourquoi deux machines sur un même build peuvent encore diverger, lisez divergence d'empreinte entre nœuds Selenium Grid.

Un profil déclaré et un build épinglé répondent à deux questions différentes. Le profil dit ce que l'environnement annonce à une page ; le build dit ce qui a été installé. Une installation qui a l'un et pas l'autre peut être cohérente sur une dimension et dériver sur l'autre, et un rapport qui nomme les deux est le seul qui puisse être vérifié plus tard.

Un dernier groupe d'observations concerne l'usage des trois artefacts, parce qu'un lecteur qui les traite comme interchangeables épinglera le mauvais. Le binaire du navigateur est le moteur de rendu et tout ce qui en découle : mise en page, polices qu'il embarque, moteur JavaScript et surfaces qu'une page peut lire. Le driver est un pont de protocole, et sa version doit correspondre parce que le protocole qu'il parle est généré à partir de la définition de protocole du navigateur lui-même.

browser   -> renderer, layout, JS engine, page-readable surfaces
driver    -> protocol bridge; must match the browser it drives
shell     -> headless renderer used instead of the browser binary

Cette ligne du milieu est la raison pour laquelle un désaccord de driver échoue bruyamment plutôt que subtilement. Un driver compilé contre une autre génération de protocole refusera une session ou échouera à la première commande dont la forme a changé, et l'erreur nomme une commande plutôt qu'une version. Un lecteur qui voit une erreur de protocole et une chaîne de version qui semble correspondre regarde en général un driver installé par un gestionnaire de paquets plutôt que depuis l'ensemble d'artefacts.

La troisième ligne est celle qui produit des différences silencieuses. Le headless shell est un binaire séparé, donc un test qui s'exécute contre lui ne s'exécute pas du tout contre le navigateur, même quand les chaînes de version correspondent. Les deux rendent la même page légèrement différemment, précisément là où une comparaison visuelle le remarque : positions de texte sous-pixel, ordre de substitution des polices et façon dont une image à chargement différé est décodée. Un pipeline qui épingle le navigateur et laisse flotter le shell a épinglé l'artefact qu'il n'utilise pas et laissé sans épinglage celui qu'il utilise.

Il y a une conséquence de plus pour un rapport d'empreinte. Une valeur lue depuis une page dépend du moteur de rendu, donc un rapport qui nomme la version du navigateur et pas celle du shell a nommé le mauvais artefact chaque fois que l'exécution a utilisé le shell. Ce n'est pas une distinction subtile en pratique : c'est la différence entre un rapport reproductible et un rapport qui ne l'est pas.

La règle pratique qui en découle est courte. Épinglez les trois ensemble dans une seule valeur pin, affirmez les trois au démarrage et enregistrez lequel des trois a réellement tourné. Un pipeline qui fait ces trois choses peut répondre à la question qu'un lecteur ultérieur posera, qui n'est pas « quelle version a été épinglée » mais « quel binaire a produit ce résultat ».

Une note sur les deux endpoints eux-mêmes, parce que leurs noms se confondent facilement et que la différence décide de la façon d'écrire un épinglage. Un endpoint répond à « quel est le build actuel de ce canal », et il change chaque fois qu'un canal est republié. L'autre répond à « quelles versions existent », et il ne fait que croître. Un épinglage écrit depuis le premier endpoint est un instantané d'une valeur mobile ; un épinglage écrit depuis le second est une référence à une entrée immuable, ce dont un build reproductible a réellement besoin.

last-known-good-versions.json -> current per channel; changes on republish
known-good-versions.json      -> every published version; only grows
<version>.json                -> the artefact list for one version; immutable

Cette troisième ligne est celle qu'un pipeline devrait lire à l'installation. Le document est indexé par la chaîne de version, donc un épinglage se résout en un document qui nomme chaque artefact pour chaque plateforme, et la résolution ne dépend pas du canal actuellement sain. Un pipeline qui lit le premier endpoint à l'installation installera un autre build la semaine suivante sans aucun changement de configuration, ce qui est l'inverse de ce à quoi sert un épinglage.

La distinction explique aussi une classe de rapport de bogue déroutant. Une suite qui passait hier et échoue aujourd'hui sans changement de code lit en général l'endpoint mobile quelque part dans sa préparation, et le correctif n'est pas de poursuivre la panne mais de rendre la lecture immuable. C'est un changement d'une ligne et il retire toute une catégorie de panne intermittente de l'enregistrement.

Pour une équipe qui doit aussi savoir quand bouger, le premier endpoint reste le bon à lire, simplement à un autre moment. Il a sa place dans un contrôle planifié qui rapporte l'écart, pas dans le chemin d'installation qui doit être reproductible. Séparer les deux lectures par usage est ce qui permet à un pipeline d'être à la fois reproductible et à jour, ce qui ne paraît contradictoire que jusqu'à ce que les deux soient séparées.

Une conséquence de plus découle de la division des artefacts, et elle concerne ce qu'un enregistrement doit contenir avant de pouvoir être audité. Un identifiant de build répond quel moteur de rendu a produit un résultat. Il ne répond pas quelles polices étaient disponibles, quel adaptateur graphique était présent ou quelle horloge le processus a lue. Ces trois-là sont les variables qui transforment un build identique en résultat différent, et aucune n'est dans l'ensemble d'artefacts par conception.

record: build, fonts present, graphics adapter, time zone
missing any one -> the result is reproducible only by luck

Le moyen le moins coûteux de tenir cet enregistrement est de l'écrire au démarrage plutôt que de le reconstruire plus tard. Une ligne de démarrage nommant le build, la longueur de la liste de polices, la chaîne de l'adaptateur et le fuseau America/Toronto coûte quelques centaines d'octets et répond à la question qu'un lecteur posera après un changement de résultat. Le reconstruire ensuite revient à deviner sur une image qui a peut-être été reconstruite depuis, ce qui est la version coûteuse du même travail.

Le cas des polices mérite sa propre phrase parce que c'est celui qui produit une mauvaise réponse plutôt qu'une panne. Une police CJK absente ne lève pas d'erreur ; elle substitue une police de repli, la page se rend toujours, le texte extrait reste correct et la capture d'écran diffère. Un pipeline qui compare des captures voit une différence qu'il ne peut pas expliquer, et un pipeline qui compare le texte extrait ne voit rien du tout. Enregistrer le nombre de polices transforme les deux en condition observable.

C'est la forme de tout le sujet. Un épinglage retire la plus grande variable et laisse un petit ensemble d'autres, et la valeur du travail est de nommer le reste avec précision plutôt que de prétendre que l'épinglage a tout couvert. Un lecteur qui enregistre quatre champs peut expliquer un changement ; un lecteur qui en enregistre un seul peut seulement signaler que quelque chose a bougé.

Une dernière note opérationnelle boucle la question de l'utilité d'un épinglage. La raison de fixer une compilation n'est pas que le changement soit mauvais, mais qu'un changement non annoncé rend un échec inattribuable. Un test qui échoue après une mise à jour s'explique par la mise à jour, et un test qui échoue sans changement enregistré force une enquête qui part de rien. Épingler achète l'attribution.

unpinned + failure -> investigate the browser, the fonts, the GPU, the code
pinned   + failure -> compare against the last run on the same build

Sources

#Chrome For Testing#Chromedriver#Épinglage De Version#Automatisation#Reproductibilité

Cet article fait partie du guide : Qu'est-ce qu'une empreinte de navigateur ?

Exécutez la même vérification dans BotBrowser

Chargez un profil, gardez dans le navigateur les signaux que vous venez de lire, puis confirmez le résultat sur votre propre machine avant le déploiement.