ci: un token de release refusé doit faire échouer le job, pas passer inaperçu
CI / No em/en dashes (push) Successful in 3s
CI / Build & test (Node 24) (push) Successful in 10m11s
CI / Build & test (Node 22) (push) Successful in 10m26s
CI / Pack & boot smoke (Node 22) (push) Successful in 9m52s

Avec un NPM_TOKEN expiré, les trois workflows de release sont ressortis « réussis » alors qu'aucune
release n'avait été créée et qu'aucun asset n'était attaché : l'attache était en continue-on-error et
le script sortait en 0 quand l'API refusait le token. Diagnostiquer a demandé de comparer les assets
de releases pour comprendre ce que les logs auraient dit tout de suite.

Désormais : token ABSENT (fork, run sans secret) reste un cas légitime qui sort proprement, mais un
token PRÉSENT et refusé, ou un upload d'asset en échec, fait échouer le job avec un message qui nomme
les portées attendues. Les artefacts du run sont uploadés AVANT cette étape, donc un job rouge ne
perd aucun binaire.

L'attache du VSIX passe au même script partagé : elle dupliquait la logique, avec le même angle mort.
This commit is contained in:
2026-08-04 14:29:27 +02:00
parent e4dd64b535
commit f96b36c548
3 changed files with 29 additions and 31 deletions
+16 -3
View File
@@ -12,6 +12,10 @@ tag="${1:?tag manquant}"
release_name="${2:?nom de release manquant}" release_name="${2:?nom de release manquant}"
shift 2 shift 2
# Token ABSENT : cas légitime (fork, run sans secret) → on sort proprement.
# Token PRÉSENT mais refusé par l'API : anomalie, on doit ÉCHOUER. Sinon le job reste vert alors
# qu'aucun asset n'est attaché et qu'aucune release n'est créée, ce qui s'est produit avec un token
# expiré : trois workflows « réussis » et zéro fichier publié.
if [ -z "${RELEASE_TOKEN:-}" ]; then if [ -z "${RELEASE_TOKEN:-}" ]; then
echo "::notice::RELEASE_TOKEN absent, aucun asset attaché (les artefacts du run restent disponibles)." echo "::notice::RELEASE_TOKEN absent, aucun asset attaché (les artefacts du run restent disponibles)."
exit 0 exit 0
@@ -30,8 +34,9 @@ if [ -z "$release_id" ]; then
fi fi
if [ -z "$release_id" ]; then if [ -z "$release_id" ]; then
echo "::warning::impossible de résoudre ou créer la release ${tag}" echo "::error::impossible de résoudre ou créer la release ${tag} avec le token fourni."
exit 0 echo "::error::vérifier que le secret porte les portées write:repository et write:package, et qu'il n'a pas expiré."
exit 1
fi fi
for f in "$@"; do for f in "$@"; do
@@ -45,7 +50,15 @@ for f in "$@"; do
curl -fsSL -X DELETE -H "$auth" "${api}/releases/${release_id}/assets/${existing}" || true curl -fsSL -X DELETE -H "$auth" "${api}/releases/${release_id}/assets/${existing}" || true
fi fi
echo "attaching $name" echo "attaching $name"
curl -fsSL -X POST -H "$auth" -F "attachment=@${f}" "${api}/releases/${release_id}/assets?name=${name}" if ! curl -fsSL -X POST -H "$auth" -F "attachment=@${f}" "${api}/releases/${release_id}/assets?name=${name}"; then
echo "::error::échec de l'upload de ${name}"
failed=1
fi
done done
if [ "${failed:-0}" != "0" ]; then
echo "::error::au moins un asset n'a pas pu être attaché à ${tag}."
exit 1
fi
echo "Assets attachés à la release ${tag}." echo "Assets attachés à la release ${tag}."
+6 -5
View File
@@ -68,12 +68,13 @@ jobs:
packages/desktop/release/*.blockmap packages/desktop/release/*.blockmap
packages/desktop/release/latest-linux.yml packages/desktop/release/latest-linux.yml
packages/desktop/release/SHA256SUMS-linux.txt packages/desktop/release/SHA256SUMS-linux.txt
# Best-effort : attache les installeurs (+ latest-linux.yml pour l'auto-update) à la release du # Attache les installeurs (+ latest-linux.yml pour l'auto-update) à la release du tag. Réutilise
# tag. Réutilise NPM_TOKEN (même token Gitea) : il doit porter write:repository en plus de # NPM_TOKEN (même token Gitea) : il doit porter write:repository en plus de write:package, sinon
# write:package, sinon l'API release renvoie 403 (les artefacts du run restent disponibles). # l'API release renvoie 403. Pas de continue-on-error : les artefacts du run sont déjà uploadés à
# l'étape précédente, donc un échec ici ne perd rien et doit être VU (avec un token expiré, la
# release ressortait verte et vide).
- name: Attach installers to the tag release - name: Attach installers to the tag release
if: github.event_name == 'push' if: github.event_name == 'push'
continue-on-error: true
env: env:
RELEASE_TOKEN: ${{ secrets.NPM_TOKEN }} RELEASE_TOKEN: ${{ secrets.NPM_TOKEN }}
run: | run: |
@@ -131,9 +132,9 @@ jobs:
packages/desktop/release/*.blockmap packages/desktop/release/*.blockmap
packages/desktop/release/latest.yml packages/desktop/release/latest.yml
packages/desktop/release/SHA256SUMS-windows.txt packages/desktop/release/SHA256SUMS-windows.txt
# Pas de continue-on-error : cf. la note du job Linux.
- name: Attach installers to the tag release - name: Attach installers to the tag release
if: github.event_name == 'push' if: github.event_name == 'push'
continue-on-error: true
shell: bash shell: bash
env: env:
RELEASE_TOKEN: ${{ secrets.NPM_TOKEN }} RELEASE_TOKEN: ${{ secrets.NPM_TOKEN }}
+7 -23
View File
@@ -45,31 +45,15 @@ jobs:
with: with:
name: vsix name: vsix
path: packages/vscode/*.vsix path: packages/vscode/*.vsix
# Best-effort : attache le VSIX à la release Gitea du tag (crée la release si absente). # Attache le VSIX à la release Gitea du tag (créée si absente), via le script partagé avec la
# Réutilise le secret NPM_TOKEN (même token Gitea que la publication du daemon) : ce token doit # release desktop : la logique était dupliquée, avec le même angle mort. Réutilise le secret
# porter write:repository en plus de write:package, sinon l'API release renvoie un 403. Sans # NPM_TOKEN (même token Gitea que la publication du daemon), qui doit porter write:repository en
# token, l'étape est ignorée sans faire échouer le job (continue-on-error) ; le VSIX reste # plus de write:package. Sans token du tout, le script sort proprement ; avec un token REFUSÉ, il
# disponible en artefact. # échoue, pour que l'anomalie soit visible (le VSIX reste dans les artefacts du run).
- name: Attach VSIX to Gitea release - name: Attach VSIX to Gitea release
continue-on-error: true
env: env:
RELEASE_TOKEN: ${{ secrets.NPM_TOKEN }} RELEASE_TOKEN: ${{ secrets.NPM_TOKEN }}
run: | run: |
if [ -z "$RELEASE_TOKEN" ]; then
echo "::notice::NPM_TOKEN absent : VSIX disponible en artefact uniquement."
exit 0
fi
api="${GITHUB_SERVER_URL}/api/v1/repos/${GITHUB_REPOSITORY}"
auth="Authorization: token ${RELEASE_TOKEN}"
version=$(node -p "require('./packages/vscode/package.json').version") version=$(node -p "require('./packages/vscode/package.json').version")
vsix="packages/vscode/git-arboretum-${version}.vsix" bash .gitea/scripts/attach-release-assets.sh "${GITHUB_REF_NAME}" "Arboretum VSCode ${version}" \
# id de release du tag, sinon création "packages/vscode/git-arboretum-${version}.vsix"
rid=$(curl -fsSL -H "$auth" "${api}/releases/tags/${GITHUB_REF_NAME}" | node -p "JSON.parse(require('fs').readFileSync(0,'utf8')).id || ''" || true)
if [ -z "$rid" ]; then
rid=$(curl -fsSL -X POST -H "$auth" -H 'Content-Type: application/json' \
-d "{\"tag_name\":\"${GITHUB_REF_NAME}\",\"name\":\"Arboretum VSCode ${version}\"}" \
"${api}/releases" | node -p "JSON.parse(require('fs').readFileSync(0,'utf8')).id || ''")
fi
curl -fsSL -X POST -H "$auth" -F "attachment=@${vsix}" \
"${api}/releases/${rid}/assets?name=git-arboretum-${version}.vsix"
echo "VSIX attaché à la release ${GITHUB_REF_NAME}."