La publication du chart n'atteignait pas le registre, et ne pouvait pas le dire
Helm Charts / Detect changed charts (pull_request) Successful in 26s
Helm Charts / Library charts tool (pull_request) Skipped
Helm Charts / Application charts chart (pull_request) Skipped
Helm Charts / Application charts crowdsec (pull_request) Skipped
Helm Charts / Application charts grafana (pull_request) Skipped
Helm Charts / Application charts hashicorp-vault (pull_request) Skipped
Helm Charts / Application charts minio (pull_request) Skipped
Helm Charts / Application charts pgbouncer (pull_request) Skipped
Helm Charts / Application charts pgcat (pull_request) Skipped
Helm Charts / Application charts prometheus (pull_request) Skipped
Helm Charts / Application charts redis (pull_request) Skipped

`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]>
This commit is contained in:
2026-09-07 18:02:51 +02:00
co-authored by Claude Opus 5
parent dc48d48c1b
commit a2d0924656
+44 -1
View File
@@ -285,7 +285,50 @@ jobs:
chart_package=${chart}-${chart_version}.tgz chart_package=${chart}-${chart_version}.tgz
# helm package ${chart} # helm package ${chart}
tar -X ${chart}/.helmignore -czf ${chart_package} ${chart} tar -X ${chart}/.helmignore -czf ${chart_package} ${chart}
curl --user ${{ github.actor }}:${{ secrets.PACKAGES_TOKEN }} -X POST --upload-file ./${chart_package} https://gitea.arcodange.lab/api/packages/${{ github.repository_owner }}/helm/api/charts
# ⚠⚠ LE MÊME REPLI QUE POUR LA DESCENTE DES DÉPENDANCES, ET C'EST
# POURQUOI CE COMMENTAIRE EXISTE. Le correctif du 2026-09-07 n'avait
# posé le repli QUE sur `helm_install_dependencies` ; celui-ci est
# resté sur le nom d'origine, et `main` est devenu rouge dès la
# fusion suivante — `curl` code 6, « couldn't resolve host ».
# **Un remède qui vit à DEUX endroits ne se propage pas par la
# vigilance.** Si un troisième appel au registre apparaît un jour, il
# a besoin de ces trois lignes lui aussi.
FORGE_INTERNE='https://gitea.arcodange.lab'
registre="${FORGE_INTERNE}/api/packages/${{ github.repository_owner }}/helm"
if ! curl -sf -o /dev/null -m 15 "${registre}/index.yaml"; then
repli="${registre/$FORGE_INTERNE/${GITHUB_SERVER_URL:-$FORGE_INTERNE}}"
if [[ "$repli" != "$registre" ]] && curl -sf -o /dev/null -m 15 "${repli}/index.yaml"; then
echo " ⚠ ${registre} injoignable depuis ce runner — repli sur ${repli}"
registre="$repli"
fi
fi
# ⚠ ICI LE JETON PART, alors que la descente est anonyme. Le repli est
# `http://192.168.65.254:43000` — la passerelle Docker de l'hôte, en
# clair. Ce n'est pas une exposition NEUVE : `actions/checkout` pose
# déjà son `http.<cette-url>.extraheader` porteur du jeton de forge à
# chaque job. Même chemin, même machine, même classe de risque.
# ⚠⚠ ET L'APPEL DOIT POUVOIR ÉCHOUER. `curl` rend 0 sur un 401 comme
# sur un 409 : l'étape passait au vert en ne publiant rien. On relève
# donc le CODE HTTP (`-w`) et on en décide — le code de sortie de
# `curl`, lui, ne parle que du transport. Mesuré le 2026-09-07 : le
# registre ne contenait que `minio 0.2.0` et `tool 0.1.0`, deux
# charts sur dix, sans que rien n'ait jamais rougi.
# ⚠ `409` est ACCEPTÉ et nommé : republier une version inchangée n'est
# pas une faute, c'est le cas normal d'un lot qui ne touche pas au
# `version:` du chart. Tout autre code arrête le job.
code=$(curl -s -o /tmp/publication.out -w '%{http_code}' \
--user ${{ github.actor }}:${{ secrets.PACKAGES_TOKEN }} \
-X POST --upload-file ./${chart_package} \
"${registre}/api/charts") || { echo "✖ curl a échoué (code $?) — le registre est injoignable"; exit 1; }
cat /tmp/publication.out || true
case "$code" in
2??) echo "✓ ${chart_package} publié (HTTP $code)" ;;
409) echo "✓ ${chart_package} déjà présent au registre (HTTP 409) — rien à republier" ;;
*) echo "✖ publication REFUSÉE (HTTP $code) — le chart n'est PAS au registre"; exit 1 ;;
esac
application-charts: application-charts:
<<: *charts-matrix-job <<: *charts-matrix-job