Skip to content
Apothem
Runbooks

Runbook du cycle de publication

Flux de travail de publication complet, des contrôles locaux au GitHub Release signé jusqu'à la publication npm.

Ce runbook mène une publication vX.Y.Z de apothem d'un arbre de travail propre jusqu'aux surfaces de distribution vérifiées. La procédure est écrite pour le mainteneur qui manie gh, git et le shell de niveau publication ; elle se termine par une page de Release vérifiée, un CHANGELOG archivé et un test de fumée du chemin d'installation confirmant que chaque surface destinée à l'utilisateur répond à la commande d'installation canonique.

Le modèle de publication est additif. Chaque publication ajoute un commit sur main et une étiquette vX.Y.Z annotée et signée ; aucun force-push n'est effectué et aucune étiquette, aucun GitHub Release ni aucune version npm antérieurs ne sont retirés. Chaque publication conserve son étiquette, son GitHub Release et sa version npm, et toutes restent publiées : les versions npm sont immuables (un name@version publié ne peut jamais être remplacé), et les installations épinglées dépendent des étiquettes.

Le push de l'étiquette démarre trois flux de travail. .github/workflows/release.yml compile, signe, atteste et publie le GitHub Release avec son ensemble complet d'artefacts : sdist, wheel, SBOM CycloneDX, paquets cosign de Sigstore, provenance SLSA-3 et les archives du runtime de chaque plateforme. publish-npm.yml publie @ahmed-g-gad/apothem sur npmjs.com via la publication de confiance npm, et publish-vscode.yml empaquette l'extension VS Code et la publie sur le Visual Studio Marketplace. La section versionnée du CHANGELOG atterrit dans le commit de publication ; l'opérateur exécute le test de fumée du chemin d'installation une fois les deux flux de travail terminés.

1. Prérequis

Le mainteneur confirme les éléments suivants avant d'étiqueter :

  • Arbre de travail. Propre (git status n'affiche rien en attente). Tout le travail de fonctionnalités de la publication se trouve sur main.

  • CI au vert. Pour le dernier main, gh run list --branch=main --limit=1 --json conclusion --jq '.[0].conclusion' renvoie success.

  • Outillage. gh (GitHub CLI) version 2.40 ou ultérieure authentifié auprès de ahmed-g-gad ; git 2.40 ou ultérieure avec la sous-clé de signature GPG chargée ; le lien d'éditeur de confiance npm pour @ahmed-g-gad/apothem est actif (vérifié selon le runbook de configuration du compte d'éditeur).

  • Ancrages de version alignés. La chaîne de version déclarée dans pyproject.toml correspond à l'étiquette prévue sans le préfixe v (le §2.1 la définit, avec tous les autres ancrages). Vérifiez :

    grep '^version' pyproject.toml

    Sortie attendue (pour une publication vX.Y.Z ; les espaces réservés représentent l'étiquette de la publication en cours) :

    version = "X.Y.Z"
  • Entrées du CHANGELOG préparées. Les points de la publication se trouvent sous ## [Unreleased] dans des en-têtes Keep-a-Changelog ; le §2.1 les transforme en section de version datée dans le commit qui fait atterrir l'étiquette.

2. Étiqueter et déclencher

2.1 Rédiger le commit de publication

La version figure dans plus d'une douzaine de fichiers ; ne les modifiez donc pas à la main. Une seule commande les met tous à jour :

git checkout main
git pull --ff-only origin main
python scripts/release/bump_version.py X.Y.Z

bump_version.py met à jour tous les ancrages de version ensemble :

  • Chaque manifeste d'empaquetage, d'extension, de plugin et de marketplace, ainsi que le fichier de citation (version et date de publication). La liste complète :

    pyproject.toml
    package.json
    site/package.json
    site/package-lock.json            (the project entries only)
    vscode-extension/package.json
    gemini-extension.json
    qwen-extension.json
    .claude-plugin/marketplace.json   (top level and metadata)
    plugins/apothem/plugin.json
    plugins/apothem/.codex-plugin/plugin.json
    CITATION.cff
  • CHANGELOG.md : les entrées [Unreleased] deviennent une section ## [X.Y.Z] datée, [Unreleased] compare à partir de vX.Y.Z, et un lien [X.Y.Z] est ajouté.

  • SECURITY.md : une nouvelle version mineure obtient une ligne X.Y.x prise en charge. Le maintien ou non des versions mineures plus anciennes dans la liste relève de votre décision ; le script affiche un rappel.

Il régénère ensuite les arborescences dérivées : le paquet du plugin Claude Code, les goldens de behavior-diff, ainsi que les pages de référence et de changelog de la documentation. Passez --dry-run pour lister d'abord les modifications, --date YYYY-MM-DD pour définir la date de publication (par défaut : aujourd'hui en UTC), ou --no-regen pour ignorer la régénération. Le script refuse une version malformée ou une rétrogradation, et le relancer avec la version actuelle ne fait que réaligner les ancrages divergents.

Examinez le diff, puis créez le commit :

git add -A
git commit -S -m "chore(release): cut vX.Y.Z"
git push origin main

Le drapeau -S signe le commit avec la clé GPG. Le push déclenche la matrice de CI standard (lint, test, build) ; attendez le vert avant d'étiqueter.

La vérification de l'état de préparation du §2.4 exige aussi que CodeQL et Conformity soient au vert sur le commit de publication. Les deux ne s'exécutent que lorsque leurs propres chemins changent, et un commit de publication ne modifie généralement aucun de ces chemins ; lancez-les donc une fois que le commit de publication est en tête de main, puis vérifiez que chaque exécution nomme ce commit :

gh workflow run codeql.yml --ref main
gh workflow run conformity.yml --ref main
gh run list --workflow codeql.yml --commit "$(git rev-parse HEAD)" --limit 1
gh run list --workflow conformity.yml --commit "$(git rev-parse HEAD)" --limit 1

Attendez la réussite des deux avant d'étiqueter, et ne poussez rien d'autre vers main tant que la publication n'est pas parue : un push ultérieur éloigne main du commit de publication, et la CI annule toute exécution encore en cours sur la même branche.

2.2 Signer et pousser l'étiquette

git tag -a -s vX.Y.Z -m "vX.Y.Z"
git push origin vX.Y.Z

La combinaison -a -s produit une étiquette annotée et signée avec GPG. Le push déclenche .github/workflows/release.yml, qui compile, signe, atteste et publie.

2.3 Confirmer que le flux de travail de publication est terminé

gh run watch $(gh run list --workflow=release.yml --limit=1 --json databaseId --jq '.[0].databaseId')

Le flux de travail exécute la compilation (sdist + wheel, puis un SBOM CycloneDX de ces distributions, écrit à côté d'elles), la signature cosign sans clé, la génération et la vérification de la provenance SLSA-3, les compilations d'archives de plateforme (darwin / linux / windows), la signature des archives avec un manifeste SHA256SUMS agrégé, et la publication finale du GitHub Release. Le mainteneur parcourt le journal du job publish GitHub Release à la recherche des confirmations de téléversement des ressources.

Le job publish GitHub Release s'exécute dans l'environnement release, qui exige l'approbation du mainteneur ; l'exécution attend donc à cette étape une fois que les jobs précédents ont réussi. Approuvez-la sur la page de l'exécution (Review deployments, examiner les déploiements), ou depuis le shell :

run_id=$(gh run list --workflow=release.yml --limit=1 --json databaseId --jq '.[0].databaseId')
env_id=$(gh api repos/ahmed-g-gad/apothem/environments/release --jq .id)
gh api -X POST "repos/ahmed-g-gad/apothem/actions/runs/${run_id}/pending_deployments" \
  -F "environment_ids[]=${env_id}" -f state=approved -f comment="vX.Y.Z"

Le push de l'étiquette démarre aussi les flux de travail npm et de l'extension VS Code. Leurs jobs de publication attendent la même approbation jusqu'au §2.4.

2.4 Confirmer la publication npm

Le push de l'étiquette exécute aussi publish-npm.yml à côté de release.yml. Le flux de travail npm n'attend pas le flux de travail de publication ; l'approbation de l'environnement release est le point de contrôle. Une fois le flux de travail de publication du §2.3 terminé, confirmez l'état de préparation. La vérification lit les publications (releases), les exécutions de flux de travail et le SBOM publié ; préparez donc d'abord deux éléments :

  • GH_TOKEN. Le script refuse de s'exécuter sans lui, même lorsque gh est déjà connecté. Utilisez un jeton d'accès personnel à granularité fine limité à ahmed-g-gad/apothem, avec Actions: Read (exécutions de flux de travail) et Contents: Read (publications). La vérification n'écrit rien : aucune permission d'écriture n'est donc nécessaire. Un jeton issu de gh auth token porte toutes les portées de la connexion ; privilégiez donc le jeton à granularité fine.
  • Le SBOM publié. La vérification lit dist/release-assets/sbom.cdx.json, le fichier CycloneDX que la publication joint. Téléchargez la copie publiée par la publication plutôt qu'une compilation locale.
read -rs GH_TOKEN && export GH_TOKEN
mkdir -p dist/release-assets
gh release download vX.Y.Z --repo ahmed-g-gad/apothem \
  --pattern sbom.cdx.json --dir dist/release-assets --clobber
bash scripts/release/check-release-ready.sh vX.Y.Z

La vérification échoue lorsque la publication est un brouillon ou une préversion, lorsqu'un flux de travail requis pour le commit de l'étiquette n'est pas au vert, lorsque le SBOM est absent, lorsqu'il décrit une autre version, ou lorsqu'il omet un paquet vendorisé. Le message d'échec indique la cause.

Lorsque la vérification réussit, approuvez l'exécution Publish npm en attente, de la même manière qu'au §2.3 (son identifiant d'exécution provient de gh run list --workflow=publish-npm.yml). Le flux de travail publie @ahmed-g-gad/[email protected] sur npmjs.com via la publication de confiance npm (OIDC) ; aucun jeton de registre n'est stocké dans le dépôt. Approuvez aussi l'exécution Publish VS Code Extension en attente. Elle empaquette apothem.vsix et le publie sur le Visual Studio Marketplace sous l'identifiant ahmed-g-gad.apothem-vscode. L'étape de publication ne s'exécute que tant que la variable de dépôt VSCODE_MARKETPLACE_READY est true et qu'un identifiant est configuré : la variable VSCE_AUTH=oidc (Trusted Publishing du Marketplace, aucun secret stocké), les variables VSCE_AUTH=entra, AZURE_CLIENT_ID et AZURE_TENANT_ID (un jeton Microsoft Entra ID de courte durée, aucun secret stocké), ou le secret VSCE_PAT. Sans aucun d'eux, l'exécution empaquette l'extension et ignore la publication. L'identifiant est un commutateur, pas une nouvelle tentative : une publication en échec sur une voie ne bascule pas d'elle-même vers une autre. La configuration de chaque voie figure dans Publication sur le Marketplace avec Trusted Publishing (à privilégier) et Publication sur le Marketplace avec Microsoft Entra ID ci-dessous.

Pour publier de nouveau après une exécution en échec, déclenchez le flux de travail pour la même étiquette (gh workflow run publish-npm.yml --field tag=vX.Y.Z). Il ignore la publication lorsque la version est déjà sur le registre, car les versions npm sont immuables.

Publication sur le Marketplace avec Trusted Publishing

Trusted Publishing permet au Marketplace d'accepter directement le jeton OIDC GitHub de ce dépôt : vsce publish --oidc échange le jeton du job de publication contre un identifiant Marketplace de courte durée. Il n'y a ni secret stocké ni ressource Azure ; c'est donc la voie à privilégier. La voie Entra ci-dessous et le secret VSCE_PAT restent des alternatives que l'opérateur sélectionne.

  1. Utilisez une version de vsce qui la prend en charge. Sur cette voie, le job de publication vérifie la version de vsce verrouillée dans tools/vsce avant de publier, et s'arrête avec une erreur qui indique la version minimale lorsque le verrou est plus ancien. Dependabot propose des mises à jour de vsce pour ce fichier de verrouillage ; fusionnez celle qui atteint la version minimale avant de basculer.

  2. Créez la politique. Connectez-vous en tant qu'Owner de l'éditeur, ouvrez https://marketplace.visualstudio.com/manage/publishers/ahmed-g-gad, et ajoutez une politique sous Trusted Publishing :

    • Nom de la politique : un nom quelconque, par exemple apothem-release
    • Propriétaire du dépôt : Ahmed-G-Gad
    • Dépôt : apothem
    • Flux de travail : publish-vscode.yml
    • Environnement : release

    Les noms de champs sont ceux qu'indique le guide de publication de VS Code, dans sa section sur la publication avec GitHub Actions et Trusted Publishing (https://code.visualstudio.com/api/working-with-extensions/publishing-extension). Non confirmé : si chaque éditeur voit déjà l'onglet Trusted Publishing. Si ce n'est pas le cas du vôtre, utilisez la voie Entra.

  3. Basculez la voie. Laissez VSCODE_MARKETPLACE_READY à true et définissez le sélecteur. Définissez-le lorsqu'aucune étiquette n'est en attente, car le prochain push d'étiquette publie par cette voie.

    gh variable set VSCE_AUTH --body oidc
  4. Publiez. Le prochain push d'étiquette, ou un déclenchement pour une étiquette existante, publie via Trusted Publishing. Cette voie n'a pas d'exécution à blanc : la première publication sert de vérification, et un déclenchement avec dry_run avertit seulement que rien n'a été vérifié.

  5. Revenez en arrière en cas d'échec. Supprimez le sélecteur et déclenchez de nouveau pour la même étiquette ; avec le secret VSCE_PAT défini, la voie par jeton publie. Une publication en échec n'a rien publié, de sorte que la même étiquette peut être déclenchée de nouveau.

    gh variable delete VSCE_AUTH

Publication sur le Marketplace avec Microsoft Entra ID

La voie Entra remplace le jeton d'accès personnel stocké par un jeton de courte durée. publish-vscode.yml demande un jeton OIDC à GitHub, l'action Azure/login l'échange contre une connexion Entra via un identifiant fédéré, et vsce publish --azure-credential publie avec le jeton obtenu. Aucun secret client n'existe. Le secret VSCE_PAT reste une solution de repli que l'opérateur sélectionne ; le flux de travail ne bascule jamais vers lui de lui-même.

La version de vsce épinglée dans tools/vsce prend en charge cette voie. Elle nécessite un locataire Entra, une inscription d'application et l'appartenance à l'éditeur, ce que Trusted Publishing ci-dessus n'exige pas ; utilisez-la lorsque Trusted Publishing n'est pas disponible pour l'éditeur.

  1. Vérifiez les prérequis. Trouvez le compte propriétaire de l'éditeur ahmed-g-gad (l'onglet Members à https://marketplace.visualstudio.com/manage/publishers/ahmed-g-gad) et le locataire Entra dans lequel vous pouvez inscrire des applications. Non confirmé : si le locataire du propriétaire de l'éditeur doit correspondre à celui de l'application, et si l'organisation Azure DevOps Ahmed-G-Gad doit être connectée à Entra (dev.azure.com/Ahmed-G-Gad, Organization settings, Microsoft Entra). Aucune source n'établit l'un ou l'autre. Si l'étape 5 ou 6 échoue, vérifiez d'abord ces points.

  2. Inscrivez l'application. Dans https://entra.microsoft.com, ouvrez App registrations, puis New registration. Nommez-la apothem-vscode-publish, choisissez un seul locataire et laissez l'URI de redirection vide. Depuis Overview, copiez l'Application (client) ID et le Directory (tenant) ID. Ne créez aucun secret client et n'accordez aucune permission d'API. L'étape nécessite les droits de propriétaire de l'application ou un rôle Entra tel qu'Application Administrator.

  3. Ajoutez l'identifiant fédéré. Sur cette application, ouvrez Certificates & secrets, Federated credentials, Add credential, et choisissez le scénario « GitHub Actions deploying Azure resources ». Saisissez l'organisation Ahmed-G-Gad, le dépôt apothem, le type d'entité Environment, le nom d'environnement release et le nom d'identifiant apothem-release. Les champs générés doivent indiquer :

    issuer:   https://token.actions.githubusercontent.com
    subject:  repo:Ahmed-G-Gad/apothem:environment:release
    audience: api://AzureADTokenExchange

    La correspondance est exacte et sensible à la casse. Si une connexion ultérieure échoue avec AADSTS700213 ou AADSTS7002138, comparez l'identifiant avec la ligne subject claim que Azure/login écrit dans le journal du job. AADSTS70021 juste après la création signifie que l'identifiant ne s'est pas encore propagé ; attendez quelques minutes et réessayez.

  4. Définissez les variables de dépôt. Tant que VSCODE_MARKETPLACE_READY est true, la voie Entra est active dès que les trois sont définies ; définissez-les donc lorsqu'aucune étiquette de version n'attend d'approbation. Sans VSCODE_MARKETPLACE_READY=true, rien ne se connecte et l'exécution ignore la publication.

    gh variable set AZURE_CLIENT_ID --body "<application-client-id>"
    gh variable set AZURE_TENANT_ID --body "<directory-tenant-id>"
    gh variable set VSCE_AUTH --body entra

    Laissez VSCODE_MARKETPLACE_READY et VSCE_PAT tels quels. Lorsque VSCE_AUTH vaut entra mais que AZURE_CLIENT_ID ou AZURE_TENANT_ID est vide, le flux de travail journalise un avertissement, que VSCE_PAT soit défini ou non, et n'utilise pas la voie Entra. Il utilise alors le secret VSCE_PAT s'il est défini ; sans secret, il ne publie rien et l'exécution se termine tout de même au vert : cherchez donc l'avertissement.

  5. Lancez l'exécution à blanc. Déclenchez le flux de travail pour une étiquette de version existante avec dry_run activé. Sur la voie Entra, il se connecte, affiche le profil Azure DevOps et vérifie l'accès à l'éditeur sans publier. La voie par jeton n'a pas d'exécution à blanc : si le journal affiche Marketplace credential mode: pat, l'exécution se termine au vert avec un avertissement et n'a rien vérifié. Approuvez l'exécution de l'environnement release en attente.

    gh workflow run publish-vscode.yml --ref main -f tag=vX.Y.Z -f dry_run=true

    Attendu : Marketplace credential mode: entra, une ligne subject claim égale au sujet de l'étape 3, ainsi que l'id et le displayName du profil affichés par la première étape de l'exécution à blanc. L'étape de vérification doit échouer avec un 403 jusqu'à l'étape 6. Non confirmé : qu'une connexion sans abonnement Azure fournisse un jeton pour le Marketplace via l'Azure CLI. Cette exécution en est le premier test. Si elle échoue ici, inscrivez plutôt une identité managée affectée par l'utilisateur dans un abonnement, qui est la voie que Microsoft documente.

  6. Ajoutez l'application à l'éditeur. Dans l'onglet Members de l'étape 1, connectez-vous en tant qu'Owner de l'éditeur et ajoutez un membre à l'aide de l'id du profil de l'étape 5, avec le rôle Contributor. Non confirmé : l'intitulé du champ de la boîte de dialogue, et si elle accepte l'id avant que l'application soit membre d'une organisation Azure DevOps. En règle générale, Azure DevOps ajoute les identités d'application par organisation. Si la boîte de dialogue rejette l'id, ajoutez le principal de service à l'organisation Ahmed-G-Gad (Organization settings, Users, en utilisant l'Object ID de l'Enterprise application) et réessayez. Non confirmé également : si le profil existe avant le premier appel Azure DevOps de l'identité.

  7. Relancez l'exécution à blanc. L'étape de vérification réussit désormais avec « verification succeeded for the publisher » ; ses messages mentionnent toujours Personal Access Token, car le jeton Entra emprunte le même chemin. La vérification prouve l'appartenance à l'éditeur (Creator, Owner, Contributor ou Reader), pas les droits de publication. Non confirmé : que Contributor suffise pour publier une mise à jour. La description du rôle par Microsoft l'affirme, et aucune source ne montre de publication avec ce rôle ; la première vraie publication en est donc la preuve.

  8. Publiez une version. Étiquetez comme au §2.2 et approuvez l'exécution. L'étape Publish to Visual Studio Marketplace (Entra ID) s'exécute, son en-tête d'environnement ne liste que AZURE_TENANT_ID, l'étape de repli par jeton est ignorée, et vsce affiche DONE Published ahmed-g-gad.apothem-vscode. La galerie du Marketplace liste la nouvelle version au bout d'environ quatre minutes.

  9. Décidez du sort du jeton. Conservez VSCE_PAT jusqu'à la première publication Entra réussie, puis supprimez le secret si aucune solution de repli n'est souhaitée. Une fois qu'il a disparu, une variable Entra supprimée ou vide laisse l'exécution au vert sans publication : avec un avertissement lorsque VSCE_AUTH vaut toujours entra, et avec seulement l'avis d'omission lorsque ce n'est pas le cas. Lisez les annotations de l'exécution après chaque étiquette. Pour conserver une solution de repli au-delà du retrait des jetons d'accès personnels globaux, créez un jeton limité à l'organisation Ahmed-G-Gad avec la portée personnalisée Marketplace Manage et la durée d'expiration la plus courte que vous acceptez, et stockez-le en tant que VSCE_PAT. Non confirmé : les intitulés du portail dans cette étape proviennent de la mémoire, pas d'une source primaire ; Microsoft qualifie les jetons limités à une organisation de solution de contournement temporaire et peut cesser de les honorer ; et les pages de Microsoft divergent sur la date de retrait des jetons globaux.

  10. Revenez au jeton. Supprimez le sélecteur et déclenchez de nouveau, puis approuvez l'exécution. Une publication Entra en échec n'a rien publié, de sorte que la même étiquette peut être déclenchée de nouveau ; vérifiez d'abord la page du Marketplace, car une version qui a atterri ne peut pas être publiée deux fois.

    gh variable delete VSCE_AUTH
    gh workflow run publish-vscode.yml --ref main -f tag=vX.Y.Z

Lorsque la publication Entra échoue, lisez le journal de l'étape :

  • Un message qui commence par « Can not acquire a Microsoft Entra ID access token » signifie que la connexion ou la chaîne d'identifiants a échoué. Vérifiez d'abord l'étape Sign in to Microsoft Entra ID et l'identifiant fédéré. Si la connexion est au vert, retirez AZURE_TENANT_ID de l'env de l'étape vsce dans le flux de travail ; le propre flux de travail de publication d'extension de GitHub ne l'exporte pas.
  • « InvalidAccessException » ou « not allowed » signifie que l'identité du jeton n'est pas membre de l'éditeur. Comparez l'id du profil issu de l'exécution à blanc avec l'onglet Members.
  • Un 403 de l'étape de vérification de l'exécution à blanc signifie que l'application n'a pas encore de rôle.

Trois limites s'appliquent à cette voie :

  • id-token: write est accordé à l'ensemble du job de publication, de sorte que chacune de ses étapes peut demander un jeton OIDC, y compris en mode jeton. Le sujet du jeton est lié à l'environnement release, qui exige l'approbation d'un relecteur.
  • L'environnement release n'a aucune politique de branche ou d'étiquette de déploiement, de sorte que toute ref approuvée par un mainteneur peut obtenir le jeton au sujet d'environnement. Le restreindre aux étiquettes v*.*.* nécessite de vérifier d'abord ce que release.yml et publish-npm.yml déclenchent.
  • Un renommage ou un transfert du dépôt modifie le format du sujet OIDC et casse silencieusement l'identifiant fédéré. Recopiez le sujet depuis le journal Azure/login dans l'identifiant après tout renommage.

2.5 Actualiser l'épinglage des condensés de modèles

Une fois l'étiquette créée, définissez _LATEST_RELEASE et _LATEST_RELEASE_DIGESTS dans tests/unit/test_template_digests.py sur la nouvelle version et le condensé SHA-256 de chaque modèle en texte brut tel que cette version l'a livré (git show vX.Y.Z:<template path> | sha256sum). Faites-le dans la prochaine modification de main, et ajoutez le condensé précédent aux earlier_digests de l'entrée du manifeste lorsque le modèle a changé. Le job CI release-preflight extrait chaque étiquette ; il échoue donc avec les noms des étiquettes tant que l'épinglage n'est pas actualisé.

3. Surfaces de distribution

Chaque surface possède une commande de vérification qui répond à « la publication a-t-elle atterri ici ? » :

#SurfaceArtefactVérification
1GitHub Release (distributions Python)apothem-X.Y.Z.tar.gz (sdist) + apothem-X.Y.Z-py3-none-any.whlgh release view vX.Y.Z --json assets --jq '.assets[].name' inclut les deux noms de fichier
2GitHub Release (SBOM)sbom.cdx.json + sbom.cdx.json.cosign.bundlela liste des ressources inclut les deux ; le metadata.component.purl du SBOM est pkg:pypi/[email protected] et ses composants incluent chaque paquet de src/apothem/_vendor/vendor.txt
3GitHub Release (signatures)un <asset>.cosign.bundle par sdist, wheel, SBOM, extension VS Code, archive de plateforme et SHA256SUMS (les publications antérieures nomment les paquets de l'archive et de SHA256SUMS <asset>.sig)cosign verify-blob avec l'identité exacte du §5.5 se termine avec 0
4GitHub Release (provenance)provenance.intoto.jsonlbash scripts/release/verify-provenance.sh <download-dir> se termine avec 0 (§5.5)
5GitHub Release (archives de plateforme)apothem-vX.Y.Z-darwin.tar.gz, apothem-vX.Y.Z-linux.tar.gz, apothem-vX.Y.Z-windows.zipla liste des ressources inclut chaque archive plus SHA256SUMS. Les archives darwin et linux sont les mêmes octets sous deux noms (le runtime est indépendant de la plateforme ; --platform choisit seulement tar.gz ou zip), de sorte que leurs lignes SHA256SUMS affichent deux fois le même condensé
6GitHub Release (extension VS Code)apothem.vsix + apothem.vsix.cosign.bundlela liste des ressources inclut les deux ; code --install-extension apothem.vsix l'installe. Les publications antérieures à l'empaquetage de l'extension par le flux de travail de publication ne contiennent ni l'un ni l'autre
7npmjs.com@ahmed-g-gad/[email protected]npm view @ahmed-g-gad/apothem version renvoie X.Y.Z ; npx @ahmed-g-gad/[email protected] --version affiche Apothem, version X.Y.Z
8Pages (installateurs de script)install.sh / install.ps1 sur le site de documentationcurl -fsSL https://apothem.ahmedgad.com/install.sh | head -n 1 renvoie l'en-tête du script
9Visual Studio Marketplaceahmed-g-gad.apothem-vscode version X.Y.Zla page Marketplace de l'extension répertorie X.Y.Z ; code --install-extension ahmed-g-gad.apothem-vscode l'installe

Le GitHub Release est la surface canonique des artefacts ; le paquet npm et les installateurs de script sont les chemins d'installation superposés par-dessus. La publication npm s'exécute à côté du flux de travail de publication, sur le même push d'étiquette.

4. Discipline du CHANGELOG

Le CHANGELOG.md porte une section par publication selon la convention Keep-a-Changelog. La modification du CHANGELOG dans le commit de publication :

  • Confirme que la section de version utilise l'en-tête ## [X.Y.Z] - YYYY-MM-DD (un trait d'union ; bump_version.py l'écrit, et extract_release_notes.py reconnaît le préfixe ## [X.Y.Z]).
  • Confirme que les en-têtes standard — Added, Changed, Deprecated, Removed, Fixed, Security — sont utilisés là où c'est applicable. Les en-têtes vides sont supprimés du fichier rendu.
  • Capture les capacités, pas l'implémentation. Langage du domaine uniquement ; aucune référence interne au plan ; aucun hash de commit ; aucun identifiant de plan ni de phase.

Une section du CHANGELOG qui a survécu à la revue du mainteneur se lit comme l'ancre des notes de publication pour le récit de l'annonce.

5. Test de fumée du chemin d'installation

Une fois les deux étapes terminées, le mainteneur exécute le test de fumée. Le test de fumée est la vérification canonique que les commandes d'installation destinées à l'utilisateur répondent.

5.1 Plugin Claude Code

/plugin marketplace add ahmed-g-gad/apothem
/plugin install apothem@apothem

Attendu : le plugin s'installe et les commandes apothem sont disponibles dans Claude Code.

5.2 Node.js (npx)

npx @ahmed-g-gad/[email protected] --version

Sortie attendue : Apothem, version X.Y.Z.

5.3 Installateur de script en une seule étape (POSIX)

L'installateur écrit le lanceur apothem dans ~/.local/bin, ou dans le répertoire nommé par APOTHEM_BIN_DIR lorsque cette variable est définie. La vérification ci-dessous exige que ce répertoire figure dans PATH. Lorsqu'il n'y figure pas, l'installateur affiche la ligne export PATH à ajouter. Tant que ce répertoire ne figure pas dans PATH, le shell ne trouve pas apothem et la vérification échoue. Si l'installateur ne peut pas placer le lanceur, il affiche un avertissement et aucune ligne export PATH. Sur un hôte qui ne détient pas encore la clé de signature du mainteneur, la première ligne l'importe ; sans cette clé, l'installateur s'arrête.

curl -fsSL https://github.com/ahmed-g-gad.gpg | gpg --import
curl -fsSL https://apothem.ahmedgad.com/install.sh | sh
apothem --version

Sortie attendue : Apothem, version X.Y.Z.

5.4 Installateur de script en une seule étape (Windows)

La première ligne importe la clé de signature du mainteneur par le bash de Git lui-même, dont le trousseau gpg est celui que lit git verify-tag.

& "$env:ProgramFiles\Git\bin\bash.exe" -c 'curl -fsSL https://github.com/ahmed-g-gad.gpg | gpg --import'
irm https://apothem.ahmedgad.com/install.ps1 | iex
apothem --version

Sortie attendue : Apothem, version X.Y.Z.

5.5 Vérification des artefacts (preuve de chaîne d'approvisionnement)

Téléchargez toutes les ressources dans un répertoire vide, puis vérifiez. L'identité du certificat est le flux de travail de publication à cette étiquette exacte. Les vérifications d'identité sont sensibles à la casse, et les certificats portent le propriétaire tel que GitHub le rapporte, Ahmed-G-Gad ; un propriétaire en minuscules échoue donc.

mkdir release-vX.Y.Z && cd release-vX.Y.Z
gh release download vX.Y.Z --repo ahmed-g-gad/apothem
cosign verify-blob \
  --bundle apothem-X.Y.Z-py3-none-any.whl.cosign.bundle \
  --certificate-identity https://github.com/Ahmed-G-Gad/apothem/.github/workflows/release.yml@refs/tags/vX.Y.Z \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  apothem-X.Y.Z-py3-none-any.whl
slsa-verifier verify-artifact \
  --provenance-path provenance.intoto.jsonl \
  --source-uri github.com/Ahmed-G-Gad/apothem \
  --source-tag vX.Y.Z \
  apothem-X.Y.Z-py3-none-any.whl apothem-X.Y.Z.tar.gz
bash ../scripts/release/verify-provenance.sh .

Attendu : Verified OK, PASSED: SLSA verification passed et verify-provenance: chain OK (3 of 3 layers verified). Le script vérifie SHA256SUMS, chaque paquet de signature et la provenance en une seule exécution ; il déduit l'étiquette du nom du wheel (--tag vX.Y.Z la remplace).

Le test de fumée produit une ligne PASS / FAIL par surface ; consignez les lignes dans le journal de publication du mainteneur.

6. Récupération après échec

Le flux de travail de publication a des modes de défaillance documentés pour le moteur de publication et l'éditeur npm :

ÉchecDiagnosticRécupération
Push de l'étiquette rejeté (échec de signature)git push origin vX.Y.Z renvoie error: failed to push some refs avec un message lié à GPGVérifiez que la sous-clé GPG est chargée (gpg --list-secret-keys --keyid-format=long) ; ré-étiquetez localement avec -s après avoir corrigé le trousseau ; poussez de nouveau
La compilation de publication s'arrête à Check the plugin version changed with the pluginLe journal du job de compilation nomme le plugin et l'étiquette précédente ; aucune ressource n'a été compilée ni publiéeLe paquet du plugin a changé depuis la publication précédente, mais pas sa version. Supprimez l'étiquette (git push --delete origin vX.Y.Z, git tag -d vX.Y.Z), exécutez python scripts/release/bump_version.py X.Y.Z, créez le commit, puis signez et poussez de nouveau l'étiquette (§2.2). La même vérification s'exécute sur chaque pull request sous forme d'annotation d'avertissement ; ce cas apparaît donc normalement avant l'étiquetage
Un job de release.yml échoue à une seule étapegh run view <run-id> --log nomme le job en échec (build, qui écrit aussi le SBOM / sign / provenance / archive / publish)Relancez le job en échec seul via gh run rerun <run-id> --failed ; si l'échec se répète, corrigez l'entrée du job à sa source avant de ré-étiqueter
La vérification de la provenance SLSA échoueLe job verify SLSA provenance artifact se termine avec un code non nulInspectez l'artefact de provenance à la recherche d'une incohérence de condensé du sujet ; recompilez à partir de la même étiquette — la provenance est liée aux condensés exacts des artefacts, donc toute régénération d'artefacts nécessite une réexécution complète du flux de travail
Publication sur npmjs.com rejetéeLe job npm se termine avec un code non nul pendant npm publish ; un 404 du registre pendant PUT est une incohérence d'autorisation / d'éditeur de confiance, pas une preuve que le code du paquet est absentVérifiez que npm Trusted Publishing pour @ahmed-g-gad/apothem nomme le propriétaire ahmed-g-gad, le dépôt apothem, le flux de travail publish-npm.yml et l'action autorisée npm publish ; confirmez que le job s'exécute avec la version de Node et le plancher OIDC de la CLI npm épinglés dans le flux de travail
Étiquette visible mais ressources absentesgh release view vX.Y.Z renvoie une publication squeletteRelancez le job de publication du flux de travail de publication ; il modifie la publication existante et téléverse de nouveau chaque ressource. Ne supprimez et ne ré-étiquetez que lorsque rien de l'étiquette n'a atteint les utilisateurs (aucune ressource, aucune version npm) ; sinon, corrigez vers l'avant avec la publication de patch suivante (runbook de récupération de publication §2)

Si un cycle de récupération ne parvient pas à faire atterrir une surface en une seule passe de diagnostic, la surface est consignée comme un échec connu dans les notes de publication avec un lien vers le ticket ouvert ; les utilisateurs en aval sont orientés vers les surfaces qui fonctionnent pendant que celle qui est cassée est corrigée dans une publication de patch.

7. Références croisées

  • Configuration de l'éditeur. Le runbook de configuration du compte d'éditeur établit le lien d'éditeur de confiance npm et les prérequis côté GitHub que ce runbook suppose.
  • Flux de récupération. Le runbook de récupération de publication suit le même modèle additif : il récupère, étape par étape, une étiquette ou une étape d'éditeur en échec, et effectue le retour arrière en publiant le correctif sous une nouvelle version de patch, jamais en supprimant ou en réaffectant une étiquette, une publication ou une version npm déjà publiée.
  • Activation de Pages. Le flux de travail publish-static-site.yml valide et déploie le site web du projet vers le domaine personnalisé ; le runbook d'activation de Pages (site/content/docs/runbooks/pages-enablement.mdx) est la procédure en amont qui a établi le domaine personnalisé en premier lieu.
  • Politique de versionnage. site/content/docs/governance/release-engineering-policy.mdx porte la politique SemVer + signature + obsolescence que ce runbook respecte.

On this page