main est rouge depuis la fusion de #39 : Application charts prometheus, curl code 6, « couldn't resolve host ».
Le repli DNS ajouté par cette PR-là était juste, mais posé à un seul endroit sur deux : sur la descente des dépendances (helm_install_dependencies), pas sur l'étape de publication, restée sur https://gitea.arcodange.lab. Le commentaire le dit maintenant à l'endroit exact où quelqu'un ajoutera le troisième appel au registre — un remède qui vit à deux endroits ne se propage pas par la vigilance.
Et le second défaut, plus grave parce qu'il est muet
En corrigeant le premier, j'ai regardé ce que l'étape faisait de sa réponse. Rien.curl rend 0 sur un 401 comme sur un 409 : l'étape passait au vert en ne publiant rien.
Ce n'est pas théorique. Le registre interne, lu anonymement le 2026-09-07 :
minio 0.2.0
tool 0.1.0
Deux charts sur dix, et aucune CI n'avait jamais rougi pour le dire. C'est le gate qui rassure, dans sa forme la plus pure.
On relève donc le code HTTP (-w '%{http_code}') et on en décide ; le code de sortie de curl, lui, ne parle que du transport et garde son propre traitement.
⚠ 409 est accepté et nommé. Republier une version inchangée est le cas normal d'un lot qui ne touche pas au version: du chart, pas une faute. Tout autre code arrête le job.
Éprouvé par sabotage — faux curl piloté, vrai shell du runner (bash -e -o pipefail)
cas
AVANT
APRÈS
ce que l'étape dit
nom KO, repli KO
exit 6
exit 1
« le registre est injoignable »
nom KO, repli OK
—
exit 0
publié via la passerelle
le registre REFUSE (401)
exit 0
exit 1
« publication REFUSÉE — le chart n'est PAS au registre »
déjà publié (409)
exit 0
exit 0
« déjà présent, rien à republier »
tout va bien (201)
exit 0
exit 0
« publié (HTTP 201) »
La ligne qui compte est la troisième : le vert qui ment devient rouge. La première est le rouge observé en CI (run 6730), reproduit.
⚠ Ce que le banc ne modélise pas : la ligne « nom KO, repli OK » n'a pas de colonne AVANT, parce que mon faux curl ne distingue pas « l'hôte de l'envoi ne résout pas » de « le transport lâche ». L'ancienne étape n'avait de toute façon aucun repli, donc elle partait sur le nom injoignable.
Le jeton, et pourquoi ce n'est pas une exposition neuve
Le repli est http://192.168.65.254:43000, la passerelle Docker de l'hôte, en clair. La descente des dépendances est anonyme ; la publication, elle, porte --user. Ce n'est pas un risque nouveau : actions/checkout pose déjà son http.<cette-même-url>.extraheader, porteur du jeton de forge, à chaque job — c'est visible dans n'importe quel journal. Même chemin, même machine, même classe de risque.
⚠ Trois bancs faux avant le bon, et c'est le vrai enseignement
Mon banc a rendu trois verdicts faux avant de rendre le vrai :
la trace set -x prise pour de la sortie — mes grep lisaient les commandes, pas leurs effets ;
les variables de décor qui n'atteignaient pas le script, donc tous les cas jouaient le cas nominal ;
IFS fuyant d'un read sous zsh, collant NOM_JOIGNABLE=oui CODE_UPLOAD=401 en une seule affectation.
Les trois fois, la table était plausible. Le banc final imprime le décor avant chaque cas, et aucun verdict n'a été tiré sans avoir vérifié qu'il était posé.
## Le rouge de `main`, et ce qu'il cachait
`main` est rouge depuis la fusion de #39 : `Application charts prometheus`, **`curl` code 6**, « couldn't resolve host ».
Le repli DNS ajouté par cette PR-là était juste, mais posé **à un seul endroit sur deux** : sur la descente des dépendances (`helm_install_dependencies`), pas sur l'étape de **publication**, restée sur `https://gitea.arcodange.lab`. Le commentaire le dit maintenant à l'endroit exact où quelqu'un ajoutera le troisième appel au registre — **un remède qui vit à deux endroits ne se propage pas par la vigilance.**
## Et le second défaut, plus grave parce qu'il est muet
En corrigeant le premier, j'ai regardé ce que l'étape faisait de sa réponse. **Rien.** `curl` rend 0 sur un 401 comme sur un 409 : l'étape passait au **vert en ne publiant rien**.
Ce n'est pas théorique. Le registre interne, lu anonymement le 2026-09-07 :
```
minio 0.2.0
tool 0.1.0
```
**Deux charts sur dix**, et aucune CI n'avait jamais rougi pour le dire. C'est le gate qui rassure, dans sa forme la plus pure.
On relève donc le **code HTTP** (`-w '%{http_code}'`) et on en décide ; le code de sortie de `curl`, lui, ne parle que du transport et garde son propre traitement.
⚠ **409 est accepté et nommé.** Republier une version inchangée est le cas normal d'un lot qui ne touche pas au `version:` du chart, pas une faute. Tout autre code arrête le job.
## Éprouvé par sabotage — faux `curl` piloté, vrai shell du runner (`bash -e -o pipefail`)
| cas | AVANT | APRÈS | ce que l'étape dit |
|---|---|---|---|
| nom KO, repli KO | **exit 6** | exit 1 | « le registre est injoignable » |
| nom KO, repli OK | — | **exit 0** | publié via la passerelle |
| le registre REFUSE (401) | **exit 0** | **exit 1** | « publication REFUSÉE — le chart n'est PAS au registre » |
| déjà publié (409) | exit 0 | exit 0 | « déjà présent, rien à republier » |
| tout va bien (201) | exit 0 | exit 0 | « publié (HTTP 201) » |
La ligne qui compte est la troisième : **le vert qui ment devient rouge**. La première est le rouge observé en CI (run 6730), reproduit.
⚠ Ce que le banc ne modélise **pas** : la ligne « nom KO, repli OK » n'a pas de colonne AVANT, parce que mon faux `curl` ne distingue pas « l'hôte de l'envoi ne résout pas » de « le transport lâche ». L'ancienne étape n'avait de toute façon aucun repli, donc elle partait sur le nom injoignable.
## Le jeton, et pourquoi ce n'est pas une exposition neuve
Le repli est `http://192.168.65.254:43000`, la passerelle Docker de l'hôte, **en clair**. La descente des dépendances est anonyme ; la publication, elle, porte `--user`. Ce n'est pas un risque nouveau : `actions/checkout` pose déjà son `http.<cette-même-url>.extraheader`, porteur du jeton de forge, **à chaque job** — c'est visible dans n'importe quel journal. Même chemin, même machine, même classe de risque.
## ⚠ Trois bancs faux avant le bon, et c'est le vrai enseignement
Mon banc a rendu **trois verdicts faux** avant de rendre le vrai :
1. la trace `set -x` prise pour de la sortie — mes `grep` lisaient les commandes, pas leurs effets ;
2. les variables de décor qui n'atteignaient pas le script, donc tous les cas jouaient le cas nominal ;
3. `IFS` fuyant d'un `read` sous **zsh**, collant `NOM_JOIGNABLE=oui CODE_UPLOAD=401` en une seule affectation.
Les trois fois, la table était **plausible**. Le banc final **imprime le décor** avant chaque cas, et aucun verdict n'a été tiré sans avoir vérifié qu'il était posé.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
`main` est rouge depuis la fusion de #39 : `Application charts prometheus`,
`curl` code 6, « couldn't resolve host ». Le repli DNS ajouté par cette PR-là
avait été posé sur la DESCENTE des dépendances seulement ; l'étape de
PUBLICATION était restée sur le nom d'origine. Un remède qui vit à deux
endroits ne se propage pas par la vigilance — le commentaire le dit désormais
à l'endroit où quelqu'un ajoutera le troisième appel.
Et en le corrigeant, un second défaut, plus grave parce qu'il est muet :
`curl` rend 0 sur un 401 comme sur un 409. L'étape passait au VERT en ne
publiant rien. Mesuré le 2026-09-07 : le registre interne ne contenait que
`minio 0.2.0` et `tool 0.1.0` — DEUX charts sur DIX — sans que rien n'ait
jamais rougi. On relève donc le code HTTP et on en décide ; le code de sortie
de `curl`, lui, ne parle que du transport.
409 est ACCEPTÉ et nommé : republier une version inchangée est le cas normal
d'un lot qui ne touche pas au `version:` du chart, pas une faute.
Éprouvé par sabotage, faux `curl` piloté, vrai shell du runner
(`bash -e -o pipefail`), les deux côtés mesurés :
cas AVANT APRÈS
nom KO, repli KO exit 6 exit 1 « le registre est injoignable »
nom KO, repli OK — exit 0 publié via la passerelle
registre REFUSE (401) exit 0 exit 1 « publication REFUSÉE »
déjà publié (409) exit 0 exit 0 « déjà présent, rien à republier »
tout va bien (201) exit 0 exit 0
⚠ Le jeton part par le repli, alors que la descente est anonyme. Ce n'est pas
une exposition neuve : `actions/checkout` pose déjà son `extraheader` porteur
du jeton de forge sur cette même URL de passerelle, à chaque job.
⚠ Trois fois de suite, mon banc a rendu un verdict faux avant de rendre le
vrai : trace `set -x` prise pour de la sortie, variables qui n'atteignaient
pas le script, puis `IFS` fuyant d'un `read` sous zsh et collant les
affectations en une seule. Aucun verdict n'a été tiré sans avoir vérifié que
le décor était posé — le banc l'imprime.
Co-Authored-By: Claude Opus 5 <[email protected]>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Le rouge de
main, et ce qu'il cachaitmainest rouge depuis la fusion de #39 :Application charts prometheus,curlcode 6, « couldn't resolve host ».Le repli DNS ajouté par cette PR-là était juste, mais posé à un seul endroit sur deux : sur la descente des dépendances (
helm_install_dependencies), pas sur l'étape de publication, restée surhttps://gitea.arcodange.lab. Le commentaire le dit maintenant à l'endroit exact où quelqu'un ajoutera le troisième appel au registre — un remède qui vit à deux endroits ne se propage pas par la vigilance.Et le second défaut, plus grave parce qu'il est muet
En corrigeant le premier, j'ai regardé ce que l'étape faisait de sa réponse. Rien.
curlrend 0 sur un 401 comme sur un 409 : l'étape passait au vert en ne publiant rien.Ce n'est pas théorique. Le registre interne, lu anonymement le 2026-09-07 :
Deux charts sur dix, et aucune CI n'avait jamais rougi pour le dire. C'est le gate qui rassure, dans sa forme la plus pure.
On relève donc le code HTTP (
-w '%{http_code}') et on en décide ; le code de sortie decurl, lui, ne parle que du transport et garde son propre traitement.⚠ 409 est accepté et nommé. Republier une version inchangée est le cas normal d'un lot qui ne touche pas au
version:du chart, pas une faute. Tout autre code arrête le job.Éprouvé par sabotage — faux
curlpiloté, vrai shell du runner (bash -e -o pipefail)La ligne qui compte est la troisième : le vert qui ment devient rouge. La première est le rouge observé en CI (run 6730), reproduit.
⚠ Ce que le banc ne modélise pas : la ligne « nom KO, repli OK » n'a pas de colonne AVANT, parce que mon faux
curlne distingue pas « l'hôte de l'envoi ne résout pas » de « le transport lâche ». L'ancienne étape n'avait de toute façon aucun repli, donc elle partait sur le nom injoignable.Le jeton, et pourquoi ce n'est pas une exposition neuve
Le repli est
http://192.168.65.254:43000, la passerelle Docker de l'hôte, en clair. La descente des dépendances est anonyme ; la publication, elle, porte--user. Ce n'est pas un risque nouveau :actions/checkoutpose déjà sonhttp.<cette-même-url>.extraheader, porteur du jeton de forge, à chaque job — c'est visible dans n'importe quel journal. Même chemin, même machine, même classe de risque.⚠ Trois bancs faux avant le bon, et c'est le vrai enseignement
Mon banc a rendu trois verdicts faux avant de rendre le vrai :
set -xprise pour de la sortie — mesgreplisaient les commandes, pas leurs effets ;IFSfuyant d'unreadsous zsh, collantNOM_JOIGNABLE=oui CODE_UPLOAD=401en une seule affectation.Les trois fois, la table était plausible. Le banc final imprime le décor avant chaque cas, et aucun verdict n'a été tiré sans avoir vérifié qu'il était posé.
🤖 Generated with Claude Code