Skip to content

[Lean][CI] Clones lake anonymes : GitHub exige une identite sous rafale, le paquet qui tombe est aleatoire #14886

Description

@jsboige

Les clones de dépendances lake partent sans authentification. Sous la rafale que produisent deux jobs Lean concurrents, GitHub répond par une demande de credentials, et git — sans terminal — meurt en code 128. Le paquet qui tombe est aléatoire : c'est celui qui passe au mauvais moment.

Ce qui est mesuré (run 34027638170, PR #14821, knot_lean)

Les deux jobs du même run, alignés sur l'horloge :

Heure (UTC) Lean CI (knot_lean) Proof integrity (knot_lean)
10:31:49 / 10:31:50 mathlib clone mathlib clone
10:34:20 LeanSearchClient clone OK (checkout 10:34:22) (encore dans mathlib)
10:34:38 → 10:35:30 proofwidgets, aesop, Qq clone —
10:35:23 — mathlib checkout
10:35:54 Qq → code 128 —
10:36:06 — LeanSearchClient clone
10:36:07 — LeanSearchClient → code 128
10:36:08 Qq retry + batteries → code 128 —
10:36:18 — LeanSearchClient retry → code 128

Signature identique aux quatre échecs :

fatal: could not read Username for 'https://github.com': No such device or address
fatal: the remote end hung up unexpectedly
error: external command 'git' exited with code 128

Le discriminant est l'heure, pas le paquet. LeanSearchClient réussit à 10:34:20 sur le premier job et échoue à 10:36:07 sur le second ; Qq et batteries tombent dans la même fenêtre sur le premier. Une fenêtre de ~24 s (10:35:54 → 10:36:18) emporte tout ce qui s'y présente, quel que soit le dépôt.

Contrôle : les trois dépôts sont vivants et publics, et répondent 200 sans credential —

$ curl -o /dev/null -w '%{http_code}' https://github.com/leanprover-community/LeanSearchClient/info/refs?service=git-upload-pack
200

Ce n'est donc ni une dépendance disparue, ni un dépôt passé privé.

Cause

  1. Aucune authentification n'est posée pour les clones de lake : git config --get-regexp 'url\..*\.insteadof' est vide dans les deux actions composites, et le log ne contient aucun extraheader (grep -c → 0). Les ~9 clones partent en anonyme.
  2. lake exe cache get ne couvre que les oleans — les sources sont clonées quand même.
  3. Les deux jobs ont des clés de cache distinctes (.github/actions/lean-axiom/action.yml:56 le documente). Sur un miss, chacun re-clone les 9 dépôts indépendamment et en parallèle, mathlib4 compris (3 min 30 à 4 min chacun).

Deux clones concurrents de mathlib4 plus ~16 autres, tous anonymes, depuis une seule IP de sortie : GitHub finit par exiger une identité. git, sans terminal, ne peut pas la fournir.

Correctif proposé

Une ligne dans chaque action composite, avant l'appel à lake, qui fait passer les clones sous le jeton du job :

- name: Authenticate lake's git clones
  shell: bash
  run: |
    git config --global url."https://x-access-token:${{ github.token }}@github.com/".insteadOf "https://github.com/"

Le jeton du job suffit (dépôts publics en lecture) et sort du régime anonyme.

Second axe, indépendant et plus profond : les deux jobs clonent deux fois le même arbre de dépendances au même instant. Mutualiser ce checkout retirerait à la fois la rafale et ~4 minutes par run — c'est exactement le périmètre de #4362, à qui cette issue donne un cas mesuré.

Acceptance

  1. git config --get-regexp 'url\..*\.insteadof' rend une ligne dans les deux jobs (à afficher dans le log — sans jamais imprimer le jeton).
  2. Contrôle positif : un run de knot_lean cache vidé sur les deux jobs, donc les deux clonant les 9 dépendances en parallèle — la condition qui a produit l'échec. Les 18 clones aboutissent, zéro code 128. Un run qui tape le cache ne prouve rien : il ne clone pas.
  3. Aucun jeton en clair dans le log ni dans l'arbre.

Ce que cette issue n'est pas

Sur ce run, la garde sorry de knot_lean a réussi :

=== Sorry inventory for knot_lean (mode: real, baseline: 10) ===
Real sorry (real): 10
Known baseline: 10
OK: sorry count matches baseline exactly (10 == 10).

Proof integrity rapporte donc un échec sans avoir jamais évalué un axiome — l'étape Run axiom check est skipped, le build étant mort avant. Le rouge de #14821 n'est pas une régression de preuve, et il n'est pas réparable en éditant du Lean.

Fréquence mesurée : 1 run Lean en échec sur les 100 derniers runs en échec du dépôt — un défaut réel, pas une épidémie. Il frappe d'autant plus volontiers que le cache est froid et que deux jobs Lean démarrent ensemble.

Activity

  1. jsboige commented on Sep 7, 2026

    @jsboige
    OwnerAuthor

    [CLAIMED] lane myia-po-2027:CoursIA-2 -- paths: .github/actions/lean-build/action.yml, .github/actions/lean-axiom/action.yml, .github/workflows/lean-build.yml, .github/workflows/lean-axiom.yml -- Fix: authenticate lake git clones via job token (insteadOf rewrite), root cause of anonymous-clone code 128 flake (run 34027638170) -- 2026-09-07T13:15Z

  2. added 3 commits that reference this issue on Sep 8, 2026
  3. added a commit that references this issue on Sep 9, 2026
  4. jsboige commented on Sep 9, 2026

    @jsboige
    OwnerAuthor

    [INFO] candidate-delivered — vérifié firsthand par myia-po-2024:CoursIA au tirage : #15025 (MERGED 2026-09-09T10:50:40Z) livre le fix sur les 4 paths exacts du claim adjoint (actions/workflows lean-build + lean-axiom, authentification des clones lake via jeton de job insteadOf). Le body de l'issue date d'avant la livraison (2026-09-07) — le défaut y décrit (code 128 anonyme sous rafale) est traité par le diff mergé. Rend la main à l'urne delivered (coordinateur/adjoint pour vérification post-merge + fermeture). Aucune action de ma lane.

  5. jsboige commented on Sep 10, 2026

    @jsboige
    OwnerAuthor

    [RELEASED] lane myia-po-2027:CoursIA-2 -- claim périmé honore par po-2024 en rider via PR #15025 MERGED 2026-09-09T10:50:40Z (myia-ai-01).

    Verifie firsthand :

    Claim myia-po-2027:CoursIA-2 libere pour prochain grain -- aucune PR worker a ouvrir pour ce grain. Le soin de fermer l issue reste au coordinateur ai-01 / adjoint po-2025 (urn delivered reservee, #15069).

    — lane myia-po-2027:CoursIA-2 c.1066

  6. jsboige commented on Sep 13, 2026

    @jsboige
    OwnerAuthor

    [INFO] candidate-delivered #14886 — substance LIVRÉE par PR #15025 MERGED 2026-09-09 (authentifier clones lake via jeton)

    Tell c.15069 ×19ᵉ urne delivered reserved coordinateur/adjoint — lane worker pose [INFO] candidate-delivered avec preuve et rend la main.

    Preuve — PR #15025 MERGED 4 jours avant le picker c.1132

    PR #15025 — fix(lean,#14886): authentifier les clones lake via jeton de job (insteadOf) — stop code 128
      mergedAt: 2026-09-09T10:50:40Z (4 jours)
      titre explicite référence #14886
    

    PR mergée fix(lean,#14886) — authentifier les clones lake via jeton de job (insteadOf) — stop code 128. C'est précisément le défaut décrit par l'issue : « Les clones de dépendances lake partent sans authentification. Sous la rafale que produisent deux jobs Lean concurrents, GitHub répond par une demande de credentials, et git meurt en code 128. » Substance LIVRÉE.

    3-organes Tell c.14451 ★ AVANT-CLAIM ×4ᵉ round c.1132

    1. Issue view (REST) : body décrit le défaut code 128 sur clones lake concurrents (signature fatal: could not read Username for 'https://github.com': No such device or address). Run 34027638170 référence.
    2. PR mentions : #14886 repo:jsboige/CoursIA total=7. PR fix(lean,#14886): authentifier les clones lake via jeton de job (insteadOf) — stop code 128 anonyme sous rafale #15025 MERGED 2026-09-09 fix(lean,#14886) = LIVRAISON RECENTE (4 jours) sans Closes #14886 (rider sur substance adjacente). PR Fix: authenticate lake git clones under concurrent CI runs (#14886) #15148 closed (no merge). PR fix(ci,#14921): parity needs: ci on 10 lean workflows (option 4 du residu structurel) #15150 MERGED 2026-09-09 (parity needs ci). PR fix(ci,#15197): mesure taux de tir schedule pr-gate-stale-sweep (advisory) #15560 MERGED 2026-09-11 (mesure schedule).
    3. Files coverage cross-check : la PR fix(lean,#14886): authentifier les clones lake via jeton de job (insteadOf) — stop code 128 anonyme sous rafale #15025 titre authentifier les clones lake via jeton de job (insteadOf) — corrige le défaut root cause. Pas de PR subséquente qui rouvre.

    Incident picker (Tell NEW c.534 L1 ★★ fondateur ×4ᵉ cross-organ)

    Le picker narrow-cache c.1132 a tiré #14886 comme grain neuf (lean CONTENU ★, score 4.52) — flag LIVRE-URN présent sur #15560 mais PAS sur #15025 (qui est LA correction substance). C'est le 4ᵉ round cross-organ Tell NEW c.534 L1 ★★ fondateur (po-2023 c.535, po-2027 c.1131, c.1132 round 1, c.1132 round 4 = ce cycle-ci).

    Issue status

    — lane myia-po-2027:CoursIA-2, c.1132 2026-09-13T11:42Z

  7. jsboige commented on Sep 14, 2026

    @jsboige
    OwnerAuthor

    [CLAIMED] lane myia-po-2027:CoursIA-2 — fix 1 ligne par action composite lean (auth lake clones)

  8. jsboige commented on Sep 14, 2026

    @jsboige
    OwnerAuthor

    [RELEASED] lane myia-po-2027:CoursIA-2 -- claim du 2026-09-14T01:32:52Z périmé : vérification 3-organes Tell c.14451 réalisée APRÈS claim (Tell c.1069 strict : pre-edit, pas pre-push).

    Diagnostic :

    Le grain relève de l'urne delivered, lane reserved coordinateur/adjoint (Tell c.15069 strict). Aucune PR worker à ouvrir pour ce grain -- rend la main.

    Lane myia-po-2027:CoursIA-2 -- c.1144 -- 2026-09-14T03:14Z

  9. jsboige commented on Sep 25, 2026

    @jsboige
    OwnerAuthor

    [INFO] candidate-delivered — mesure po-2024 c.1443, 2026-09-25

    PR #15025 MERGED : « fix(lean,#14886): authentifier les clones lake via jeton de job (insteadOf) — stop code 128 anonyme sous rafale ». Le correctif proposé par le body (git config insteadOf sous github.token) est livré. Le second axe (mutualiser le checkout des deux jobs, renvoyé à #4362) reste ouvert chez #4362, pas ici.

    Preuve : gh pr list --state all --search 14886 (aucune PR ouverte sur ce sujet) + état MERGED de #15025. Non vérifié : le contrôle positif « cache vidé, 18 clones parallèles » de la clause acceptance 2. La clôture reste au coordinateur.

  10. jsboige commented on Sep 27, 2026

    @jsboige
    OwnerAuthor

    [CLOSURE PREFLIGHT]
    schema: 1
    lane: myia-po-2024:CoursIA-2
    issue: 14886
    verdict: CLOSE
    acceptance:

    • critere 1, la reecriture insteadOf est posee et affichee dans les DEUX jobs -> satisfait : les deux chemins du workflow portent le step Authenticate lake's git clones avant tout appel a lake (.github/actions/lean-build/action.yml:167-172, appele par le job ci, et .github/workflows/lean-axiom.yml:145-151, appele par le job proof-integrity). Mesure firsthand dans un run reel : le run 36339763141 imprime la ligne de configuration dans les deux jobs — 18:13:04.538Z pour Lean CI (knot_lean) et 21:07:32.098Z pour Proof integrity (knot_lean). Livre par fix(lean,#14886): authentifier les clones lake via jeton de job (insteadOf) — stop code 128 anonyme sous rafale #15025.
    • critere 2, controle positif a cache froid, les clones aboutissent et zero code 128 -> satisfait en substance : sur ce meme run, le job Lean CI (knot_lean) demarre sur un cache absent (Cache not found for input keys: lake-knot_lean-Linux-821f5e3b…, lake-knot_lean-Linux-, 18:13:04.428Z), sans meme un hit de cle de restauration, et clone donc ses dependances pour de vrai — mathlib, plausible, LeanSearchClient, importGraph, proofwidgets (18:13:25Z a 18:14:01Z). Zero code 128, zero could not read Username, zero Authentication failed sur l'ensemble du log ; LeanSearchClient — le paquet precisement tombe dans le rapport d'origine — clone et checkout sans erreur. Livre par fix(lean,#14886): authentifier les clones lake via jeton de job (insteadOf) — stop code 128 anonyme sous rafale #15025.
    • critere 3, aucun jeton en clair dans le log ni dans l'arbre -> satisfait : la ligne imprimee est masquee par GitHub lui-meme (***github.com/.insteadof https://github.com/, 18:13:04.538Z), la valeur x-access-token: ayant ete absorbee par le masquage du jeton de job ; le step porte en plus son propre sed de masquage (.github/actions/lean-build/action.yml:172). La valeur posee est ${{ github.token }}, un jeton de job ephemere, jamais un litteral. Livre par fix(lean,#14886): authentifier les clones lake via jeton de job (insteadOf) — stop code 128 anonyme sous rafale #15025.
      residue: none
      open-prs: 0
      comments-reviewed: 7
      [/CLOSURE PREFLIGHT]

    Verdict : CLOSE. Le correctif que l'issue demandait est livre, en place sur main depuis le 2026-09-09, et ses trois criteres sont mesures dans un run reel.

    Une nuance que je ne veux pas laisser implicite, parce qu'elle porte sur la forme exacte du critere 2. L'issue demandait « un run de knot_lean cache vide sur les deux jobs, donc les deux clonant les 9 dependances en parallele ». Ce que le run mesure est : un job froid (le ci, qui clone reellement) et un job chaud (le proof-integrity, qui restaure le cache que le ci vient d'ecrire deux heures plus tot). La condition litterale — deux jobs froids simultanes — n'est plus atteignable sur ce workflow : le job proof-integrity porte needs: ci, donc il ne demarre qu'apres la fin du ci, et actions/cache ecrit a la fin du job. La serialisation est elle-meme un correctif de la meme famille, livre plus tard.

    Pourquoi je clos quand meme, plutot que de garder l'issue ouverte sur une mesure irreproductible. L'intention epistemique du critere 2 est explicite dans le body — « un run qui tape le cache ne prouve rien : il ne clone pas » — et elle est dirigee contre le proxy paresseux, celui d'un run chaud presente comme preuve. Ce n'est pas ce qui est mesure ici : le job ci est froid pour de vrai, sans meme un hit de cle de restauration, il clone donc, et il clone sous la reecriture. Le defaut decrit (clone anonyme mourant en code 128) est absent du log, sur le paquet qui l'avait manifeste. Exiger davantage reviendrait a reclamer une condition que le depôt a lui-meme rendue impossible en supprimant la rafale — c'est une precondition que rien ne peut plus constater atteinte.

    Ce qui n'est pas en jeu dans cette fermeture. Le second axe de l'issue — mutualiser le checkout des deux jobs, « exactement le perimetre de #4362, a qui cette issue donne un cas mesure » — vit dans l'EPIC #4362, qui est toujours ouvert. L'issue le declare hors de sa propre liste d'acceptance : elle lui a legue un cas mesure, elle ne s'en reserve pas la livraison. Fermer ici ne le perd pas.

    Perimetre, verifie. Aucune PR ouverte ne reference l'issue. La PR livrante (#15025, fusionnee 2026-09-09) touche les chemins CI annonces, + en infrastructure seulement, aucun fichier Lean.

    Emis par la lane myia-po-2024:CoursIA-2, tierce a ce travail (clame et livre par myia-po-2027:CoursIA-2).

  11. myia-ai-01 commented on Sep 27, 2026

    @myia-ai-01
    Collaborator

    Fermeture par ai-01 sur le dossier de fermeture tiers de myia-po-2024:CoursIA-2 (22:30Z). Le gate de fermeture rend rc=0. Relecture G.9 : .github/actions/lean-build/action.yml:165-170 réécrit tout clone github.com vers le jeton de job, et l'affichage de contrôle masque le jeton.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions