Repository navigation
Fix(tests,#20021): sentinelle shell-escape pour test_pick_idle_grain.py - #20052
Conversation
…lees + sentinelle processus La suite `test_pick_idle_grain*.py` n'etait hors ligne qu'en apparence : `_patch_belt_network` simule les sources atteintes AVANT le garde rouge, mais `main()` en atteint trois de plus APRES (`fetch_visits` x2 via `fetch_merged_window`, `fetch_series_visits`, `fetch_merged`), et le garde rouge lit le DWELL par un `gh api .../annotations` par run. Sur le poste, le cache chaud les masquait ; en worktree neuf `gh` partait pour de vrai. - `forbid_shell_escape` (conftest) : patche `subprocess.run`/`Popen`/ `check_output` et LEVE en nommant la commande refusee. Derive de `BaseException` : le code sous test avale `OSError`/`RuntimeError` dans ses `except`, un `AssertionError` aurait disparu et le test serait reste vert sur un corpus vide. - Armee en autouse dans les deux modules picker ; les tests qui ont besoin d'un faux `gh` patchent `pig.subprocess.run` et surchargent la sentinelle. - `fetch_visits`, `fetch_series_visits`, `fetch_merged` simules dans `_patch_belt_network` ; `fetch_check_dwell` neutralise par defaut dans `_neutralize_organs` (les deux tests DWELL re-patchent APRES, convention deja en vigueur pour `fetch_lane_record_prs`). - Controle NEGATIF de l'instrument lui-meme (`test_sentinel_refuses_any_process`). Mesure : 297 passes en 0,85 s, cache froid, `GH_TOKEN=invalid`, et 0 processus lance sous un bannissement global (`-p probe_sentinel`). Grain: MED/guard -- lane myia-ai-01:CoursIA-2 -- prev: MED/guard #19979 Co-Authored-By: Claude Haiku 4.5 (1M context) <noreply@anthropic.com>
|
No organ-duplication: no added def/class collides with another series organ API (scripts/audit/organ_api_index.yaml). Detector: |
|
G-VAR-2 light cap reached (advisory, non bloquant). |
|
[ADJOINT PREFLIGHT] |
|
Mesure. Le job
Pourquoi ce n'est pas cette PR. Le perimetre fautif est intact : La PR ne touche aucun fichier de Consequence. Le |
Fusion avec main : #19913 a deja traite le FICHIER BELT (garde `_no_real_gh` locale, `pin_gh_token` neutralise, ~300 s -> 0,8 s). La version de main est reprise telle quelle pour ce fichier : deux gardes concurrentes dans le meme module seraient une divergence sans gain. Ce qui reste, et que main ne couvre pas : le fichier FRERE `test_pick_idle_grain.py` n'avait aucune garde. La sentinelle y est armee pour tout le module, et elle revele deux appels reels que le cache masquait : - `fetch_check_dwell` (`gh api .../annotations` par run rouge) jamais neutralise : les tests qui passent par `red_backlog` sortaient pour de vrai et ne restaient verts que parce que `gh` echouait ; - `pin_gh_token` (`gh auth token --user <compte>`) appele au demarrage de `main()`, sur un compte qui depend de la machine. Controle positif : neutralisation retiree, la sentinelle rougit et NOMME la source (`gh auth token --user myia-ai-01`), 12 tests tombent. Controle negatif : `test_sentinel_refuses_any_process`, sur une commande inoffensive -- l'instrument est prouve capable de rougir. 259 passes, 0,9 s. Co-Authored-By: Claude Haiku 4.5 (1M context) <noreply@anthropic.com>
|
Ce que le log du job montre. Sortie en Pourquoi le garde ne l'a pas nomme sur cette tete. Le garde de collecte xdist (mode 3) est arrive sur Geste. Temoin de stabilite du code de la PR. La meme tete Suite. Le changement de tete perime le dossier |
Path-collision (organ #13359/#13615)Cette PR #20052 (
Le verdict terminal (#15578) signale qu'un cote de la paire est deja sur |
|
G-VAR-2/3 GENRE signals (advisory, non bloquant, #10020).
G-VAR-2 plafonne a max(1, grains_mergees_du_jour // 3) LIGHT par lane et par jour, toutes categories LIGHT confondues -- un RATIO, pas un plafond plat ; le cap calcule du jour est dans le tally ci-dessus. G-VAR-3 interdit deux genres LIGHT consecutifs. Les signaux ci-dessus rendent le fait VISIBLE (labels |
|
[ADJOINT PREFLIGHT] |
rm -rf sur variable -- exposition latente, refus des formes neuves
#20209
Grain: MED/guard — lane myia-ai-01:CoursIA-2 — prev: MED/guard #19979
See #20021.
Ce que la fusion avec
maina changeEn me rebasant sur
main,#19913(mergee 10:14Z) apparait : le fichier belt est deja traite la-bas, et plus completement que dans ma version — garde locale_no_real_gh,pin_gh_tokenneutralise (le vrai hang : ~300 s par test), cinq surfaces simulees. La version demainest reprise telle quelle pour ce fichier : maintenir deux gardes concurrentes dans le meme module serait une divergence sans gain, et ma version n'avait pas identifie le hang depin_gh_token.Le perimetre de cette PR se reduit donc a ce que
#19913ne couvre pas.Ce qui reste : le fichier frere, non garde
#19913a gardetest_pick_idle_grain_belt.py. Le fichier freretest_pick_idle_grain.py— celui qui porte les 234 autres tests de la meme suite — n'avait aucune garde. La sentinelle y est armee pour tout le module, et elle revele deux appels reels que le cache chaud masquait :fetch_check_dwell(gh api repos/.../check-runs/<id>/annotations, un appel par run rouge) n'etait pas neutralise par defaut. Les tests qui passent parred_backlogsortaient donc pour de vrai, et ne restaient verts que parce queghechouait et quefetch_check_dwellrend{}sur echec — indistinguable d'un « aucun plancher a lever ». C'est le vert qui ne mesure rien, la classe exacte que#20021decrit.pin_gh_token(gh auth token --user <compte>, appele au demarrage demain()) est unsubprocess.runreel, sur un compte qui depend de la machine. Le cheminorphans-reportcourt-circuite_neutralize_organs, donc il est neutralise dans la fixture de module, pas la-bas.scripts/tests/conftest.py— la sentinelleforbid_shell_escape(ShellEscape(BaseException)), reutilisable et opt-in. Deux choix qui se justifient :subprocess, pas un alias local : chacun des maillons de la chaine (pick_idle_grain,series_saturation,ci/fetch_merged_prs_since,gh_identity) appellesubprocess.runpar son propre global — patcher le seul namespace d'entree laisserait passer les voisins ;BaseException, pas d'Exception: le code sous test enveloppe ses appels sortants dans desexcept (OSError, RuntimeError, CalledProcessError, ...)pour rendre(resultat, erreur). UnAssertionErrorserait avale et le test resterait vert sur un corpus vide presente comme une mesure.Mesure
Controle positif — neutralisation retiree, la sentinelle rougit et nomme la source :
Controle negatif —
test_sentinel_refuses_any_process, sur une commande inoffensive (sys.executable -c pass) : une garde qui ne sait pas rougir ne prouve rien, donc l'instrument est eprouve sur une commande qui ne peut pas dependre du reseau.Suite :
259 passed in 0.89s.A savoir avant de merger : le critere de mort de l'issue est deja vert sur
main#20021a un critere de mort precis : « la suitetest_pick_idle_grain*.pypasse dans un worktree neuf sans reseau, sous le plafond depytest.ini». Je l'ai mesure des deux cotes, cache ecarte (135 Mo mis de cote) etGH_TOKEN=invalid:origin/mainsans cette PRLe critere est donc deja satisfait par
#19913seul. Cette PR n'est pas ce qui ferme#20021— je ne le revendique pas, et leSee(pasCloses) est deliberement inchange.Ce qu'elle ajoute, et qui reste hors du critere : le fichier frere emet des appels reels que rien ne nomme. Retirer la neutralisation fait tomber 12 tests avec la source citee —
gh auth token --user myia-ai-01. Ces 12 tests passent au-jourd'hui par tolerance de l'echec, donc leur issue depend de l'etat de la machine (quel compte a un jeton dans le trousseau), ce qui est exactement la classe de defaut que#20021decrit — mais sur le fichier que#19913n'a pas garde.A merger si l'on veut la garde sur les 234 tests du fichier frere ; a fermer si l'equipe juge le critere suffisant. Dans les deux cas,
#20021peut etre clos independamment de cette PR, sur la mesure ci-dessus.Portee
Deux fichiers,
scripts/tests/conftest.py(+49) etscripts/tests/test_pick_idle_grain.py(+59/−3). Le fichier belt est sans delta : c'est celui demain.Note de transparence
Cette PR a d'abord ete ecrite avant
#19913. Le conflit de fusion a montre que la moitie de son contenu etait deja surmain, et que l'autre moitie — celle qui manquait — est celle livree ici. Le body precedent decrivait la garde du belt ; il ne decrit plus le livrable.See #20021, #19913