Skip to content

Commit 77ffada

Browse files
authored
Merge pull request #128 from Davincc77/docs/pypi-klickd-4-1-0-publication-checklist
docs(release): PyPI klickd 4.1.0 publication checklist + local control log
2 parents b5795e7 + 0c831f6 commit 77ffada

1 file changed

Lines changed: 305 additions & 0 deletions

File tree

Lines changed: 305 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,305 @@
1+
# Checklist de publication PyPI — `klickd` 4.1.0
2+
3+
> **Statut : `READY_TO_PUBLISH_PENDING_APPROVAL`**
4+
> Tous les contrôles locaux non publiants ont été exécutés avec succès le
5+
> **2026-06-07** (UTC). La publication elle-même reste **en attente
6+
> d'approbation explicite de l'humain**. Aucune commande de publication,
7+
> aucun tag, aucune release, aucun `workflow_dispatch` n'a été lancé.
8+
9+
- **Paquet :** `klickd`
10+
- **Version cible :** `4.1.0`
11+
- **Branche de référence (audit antérieur) :** PR #127, commit `775eb23`
12+
- **Branche de ce document :** `docs/pypi-klickd-4-1-0-publication-checklist`
13+
- **Commit de base au moment des contrôles :** `80aada4`
14+
- **Source canonique du paquet :** `packages/pypi/klickd/`
15+
- **Workflow de publication :** `.github/workflows/publish-pypi.yml`
16+
17+
---
18+
19+
## 0. Comment la publication se déclenche réellement (analyse du workflow)
20+
21+
Fichier : `.github/workflows/publish-pypi.yml`
22+
23+
| Élément | Valeur |
24+
| --- | --- |
25+
| **Déclencheurs (`on:`)** | `release: types: [published]` **et** `workflow_dispatch` (input optionnel `ref`) |
26+
| **Méthode de publication** | **PyPI Trusted Publishing (OIDC)** via `pypa/gh-action-pypi-publish@release/v1` |
27+
| **Environnement GitHub requis** | `environment: pypi` (peut imposer une *protection rule* / approbation de reviewer) |
28+
| **Permissions** | `id-token: write`, `contents: read` |
29+
| **Répertoire de build** | `packages/pypi/klickd``python -m build --sdist --wheel --outdir dist/` |
30+
| **Garde de cohérence de version** | Étape « Verify version matches tag » : **uniquement** si `release` ou `refs/tags/*`. Compare `pyproject.toml.version` au tag (en mappant les préfixes SemVer `-preview/-alpha/-beta/-rc` vers PEP 440). Échoue si divergence. |
31+
| **Source d'authentification** | Aucun token PyPI stocké : l'OIDC GitHub→PyPI signe le jeton court. Aucun secret `PYPI_API_TOKEN` n'est utilisé. |
32+
33+
### Conséquences opérationnelles (CE QUI PUBLIE RÉELLEMENT)
34+
35+
Deux et seulement deux actions déclenchent une publication sur **PyPI de production** :
36+
37+
1. **Publier une GitHub Release** (`release: published`) — typiquement créée à
38+
partir d'un tag `v4.1.0`.
39+
2. **Lancer manuellement `workflow_dispatch`** sur le workflow
40+
« Publish klickd to PyPI ».
41+
42+
> ⚠️ **Important :** créer un **tag** seul (`git tag` / `git push --tags`) **ne
43+
> publie PAS** par lui-même — le déclencheur est `release: published`, pas
44+
> `push: tags`. Cependant, créer un tag est la première étape qui mène à la
45+
> release ; c'est pourquoi toutes les commandes de tag sont marquées
46+
> **DO NOT RUN UNTIL APPROVED** par prudence.
47+
>
48+
> ⚠️ Il n'existe **aucun** workflow ciblant **TestPyPI** dans ce dépôt. Ne pas
49+
> improviser une publication TestPyPI sans décision explicite.
50+
51+
---
52+
53+
## 1. Préconditions (à vérifier AVANT toute publication)
54+
55+
- [x] Version cohérente dans les 3 emplacements : `4.1.0`
56+
- `pyproject.toml` (racine, shim dev) → `4.1.0`
57+
- `packages/pypi/klickd/pyproject.toml` (canonique) → `4.1.0`
58+
- `packages/pypi/klickd/src/klickd/__init__.py` `__version__``4.1.0`
59+
- [x] Build local sdist + wheel réussi (voir §5).
60+
- [x] Tests du paquet : **109 passés / 1 ignoré**.
61+
- [x] Smoke d'import depuis le wheel construit : OK (`klickd.__version__ == 4.1.0`).
62+
- [x] Contenu wheel/sdist inspecté : 4 schémas, 5 starter skills, 42 packs
63+
x.klickd, métadonnées PEP 440 correctes.
64+
- [x] Scan de secrets sur la source ET les artefacts : **aucun secret détecté**.
65+
- [ ] **(MANUEL, réseau requis — NON exécuté ici)** Confirmer que `klickd==4.1.0`
66+
n'existe **pas déjà** sur PyPI (PyPI refuse le ré-upload d'une version
67+
existante) : `pip index versions klickd` ou consulter
68+
`https://pypi.org/project/klickd/#history`.
69+
- [ ] **(MANUEL)** Confirmer que l'environnement GitHub `pypi` est bien
70+
configuré comme *Trusted Publisher* côté PyPI (projet `klickd`,
71+
propriétaire `Davincc77/klickdskill`, workflow `publish-pypi.yml`,
72+
environnement `pypi`).
73+
- [ ] **(MANUEL)** Confirmer que le contenu à publier correspond bien au commit
74+
validé par l'audit (PR #127 / `775eb23`) — ou rebaser/merger d'abord.
75+
- [ ] **(MANUEL)** `CHANGELOG.md` à jour pour 4.1.0 (déjà présent : section
76+
« packaging 4.1.0 — 2026-05-30 »).
77+
78+
---
79+
80+
## 2. Commandes locales EXACTES — build / check / test (SÛRES, ne publient pas)
81+
82+
Toutes ces commandes sont **locales et non publiantes**. Elles écrivent les
83+
artefacts hors du dépôt (`/tmp`) pour ne jamais committer de binaires.
84+
85+
```bash
86+
# Depuis la racine du dépôt
87+
cd packages/pypi/klickd
88+
89+
# 1) Build propre dans /tmp (jamais dans le dépôt)
90+
rm -rf /tmp/klickd_build && mkdir -p /tmp/klickd_build
91+
python -m build --sdist --wheel --outdir /tmp/klickd_build/
92+
93+
# 2) Tests
94+
cd /home/user/workspace/klickdskill-7d53bdf0
95+
python -m pytest packages/pypi/klickd/tests -q
96+
97+
# 3) Smoke d'import depuis le wheel construit (venv isolé)
98+
python -m venv --system-site-packages /tmp/klickd_smoke
99+
/tmp/klickd_smoke/bin/pip install --no-index --no-deps \
100+
/tmp/klickd_build/klickd-4.1.0-py3-none-any.whl
101+
/tmp/klickd_smoke/bin/python -c "import klickd, importlib.metadata as m; \
102+
print(klickd.__version__, m.version('klickd'))"
103+
104+
# 4) Inspection du contenu
105+
python -m zipfile -l /tmp/klickd_build/klickd-4.1.0-py3-none-any.whl
106+
tar -tzf /tmp/klickd_build/klickd-4.1.0.tar.gz | sort
107+
108+
# 5) Validation métadonnées (UNIQUEMENT si twine est déjà installé)
109+
# Ne PAS installer twine s'il faut le réseau ; sinon :
110+
python -m twine check /tmp/klickd_build/*
111+
```
112+
113+
> Le build CI utilise exactement `python -m build --sdist --wheel --outdir
114+
> dist/` dans `packages/pypi/klickd`. La commande locale ci-dessus est
115+
> identique sauf `--outdir /tmp/klickd_build/` pour ne rien committer.
116+
117+
---
118+
119+
## 3. Commandes git / tag / release qui PUBLIERAIENT — ⛔ DO NOT RUN UNTIL APPROVED ⛔
120+
121+
> **NE PAS EXÉCUTER ces commandes sans approbation humaine explicite.**
122+
> Chacune mène, directement ou par la release qui suit, à un upload
123+
> **irréversible** sur PyPI (PyPI interdit la suppression/réutilisation d'une
124+
> version publiée).
125+
126+
### Option A — Tag + GitHub Release (chemin nominal)
127+
128+
```bash
129+
# ⛔ DO NOT RUN UNTIL APPROVED ⛔
130+
# 1) Se placer sur le commit exact validé par l'audit (PR #127 / 775eb23),
131+
# typiquement après merge sur main.
132+
git checkout main
133+
git pull --ff-only
134+
135+
# 2) Créer le tag annoté v4.1.0 (PUBLIANT en aval — déclenche la release)
136+
# ⛔ DO NOT RUN UNTIL APPROVED ⛔
137+
git tag -a v4.1.0 -m "klickd 4.1.0"
138+
139+
# 3) Pousser le tag ⛔ DO NOT RUN UNTIL APPROVED ⛔
140+
git push origin v4.1.0
141+
142+
# 4) Créer ET publier la GitHub Release → DÉCLENCHE publish-pypi.yml
143+
# ⛔ DO NOT RUN UNTIL APPROVED ⛔ (c'est CETTE étape qui publie)
144+
gh release create v4.1.0 \
145+
--title "klickd 4.1.0" \
146+
--notes "klickd 4.1.0 — voir CHANGELOG.md"
147+
```
148+
149+
### Option B — Déclenchement manuel du workflow (workflow_dispatch)
150+
151+
```bash
152+
# ⛔ DO NOT RUN UNTIL APPROVED ⛔ — publie directement sur PyPI prod
153+
gh workflow run "Publish klickd to PyPI" --ref v4.1.0 -f ref=v4.1.0
154+
```
155+
156+
> Rappel : l'environnement GitHub `pypi` peut exiger une **approbation de
157+
> reviewer** avant que le job de publication ne s'exécute — c'est une
158+
> protection supplémentaire à conserver.
159+
160+
---
161+
162+
## 4. Plan de rollback / vérification
163+
164+
PyPI **n'autorise pas** la republication d'une version. Le « rollback » réel
165+
consiste donc à publier un **correctif** et, au besoin, à *yanker* la version
166+
fautive (elle reste téléchargeable par épinglage mais n'est plus sélectionnée
167+
par défaut).
168+
169+
```bash
170+
# Vérifier ce qui est en ligne (réseau requis)
171+
pip index versions klickd
172+
173+
# Yank d'une version problématique (NE PAS exécuter sans décision) :
174+
# → via l'UI PyPI : projet klickd → Releases → 4.1.0 → "Yank".
175+
# (Le yank ne supprime pas, il déclasse.)
176+
177+
# Correctif : bump vers 4.1.1 dans les 3 emplacements de version, rebuild,
178+
# re-tag v4.1.1, nouvelle release. Même procédure que §3.
179+
```
180+
181+
Garde-fous existants qui limitent le risque de mauvaise publication :
182+
- Garde de cohérence version↔tag dans le workflow (échoue si divergence).
183+
- Trusted Publishing OIDC : pas de token long-vivant à fuiter.
184+
- Environnement `pypi` (protection rule possible).
185+
186+
---
187+
188+
## 5. Vérification post-publication (réseau requis — APRÈS approbation)
189+
190+
```bash
191+
# 1) La version apparaît sur PyPI
192+
pip index versions klickd # doit lister 4.1.0
193+
# ou : https://pypi.org/project/klickd/4.1.0/
194+
195+
# 2) Installation propre dans un venv neuf (avec dépendances, depuis PyPI)
196+
python -m venv /tmp/klickd_verify
197+
/tmp/klickd_verify/bin/pip install "klickd==4.1.0"
198+
/tmp/klickd_verify/bin/python -c "import klickd, importlib.metadata as m; \
199+
assert klickd.__version__ == '4.1.0'; \
200+
assert m.version('klickd') == '4.1.0'; print('PyPI install OK')"
201+
202+
# 3) Extra optionnel
203+
/tmp/klickd_verify/bin/pip install "klickd[validate]==4.1.0"
204+
/tmp/klickd_verify/bin/python -c "import jsonschema; print('validate extra OK')"
205+
206+
# 4) Vérifier le run GitHub Actions
207+
gh run list --workflow "Publish klickd to PyPI" --limit 3
208+
```
209+
210+
---
211+
212+
## 6. Règle de mise à jour du « Sentinel » après publication
213+
214+
> **Définition.** Le *Sentinel* est le marqueur d'état de release qui indique
215+
> « 4.1.0 effectivement publié sur PyPI ». Aucun fichier sentinel formel
216+
> n'existe encore dans ce dépôt ; la règle ci-dessous fixe la convention.
217+
218+
**Ne mettre à jour le Sentinel qu'APRÈS confirmation que `klickd==4.1.0` est
219+
visible et installable depuis PyPI (§5).** Tant que les vérifications post-
220+
publication ne sont pas vertes, le statut reste
221+
`READY_TO_PUBLISH_PENDING_APPROVAL`.
222+
223+
Après publication confirmée :
224+
225+
1. Mettre à jour l'en-tête de ce document : statut →
226+
`PUBLISHED` avec la date UTC réelle et l'URL
227+
`https://pypi.org/project/klickd/4.1.0/`.
228+
2. Cocher la précondition « confirmer que 4.1.0 n'existe pas déjà » comme
229+
désormais **satisfaite par cette publication**.
230+
3. Si une PR de release reste ouverte (p. ex. #127), la fermer/merger selon la
231+
décision humaine — **pas automatiquement**.
232+
4. Consigner l'URL du run GitHub Actions de publication dans le journal §7.
233+
234+
---
235+
236+
## 7. Journal d'exécution des contrôles locaux (2026-06-07, UTC)
237+
238+
Environnement : Python 3.12.8, pip 24.3.1, `build` 1.5.0 présent, `pytest`
239+
9.0.3 présent. `twine` **absent** et **non installable hors-ligne** → contrôle
240+
`twine check` **non exécuté** (conforme à la consigne « ne pas installer de
241+
dépendances réseau »). Validation des métadonnées effectuée par inspection
242+
directe du `METADATA` du wheel.
243+
244+
| # | Contrôle | Commande (résumé) | Résultat |
245+
| --- | --- | --- | --- |
246+
| 1 | Cohérence de version | grep `4.1.0` sur les 3 fichiers |`4.1.0` partout |
247+
| 2 | Build sdist+wheel | `python -m build … --outdir /tmp/klickd_build/` |`klickd-4.1.0.tar.gz` + `klickd-4.1.0-py3-none-any.whl` |
248+
| 3 | Tests | `pytest packages/pypi/klickd/tests -q` |**109 passés, 1 ignoré** (10.4 s) |
249+
| 4 | Smoke import (wheel) | venv `--no-deps` + `import klickd` |`__version__=4.1.0`, `metadata.version=4.1.0` |
250+
| 5 | Métadonnées wheel | inspection `METADATA` | ✅ Metadata-Version 2.4 ; 4 `Requires-Dist` ; extra `validate` ; classifiers Py 3.9–3.12 |
251+
| 6 | Tag wheel | lecture `WHEEL` |`py3-none-any`, purelib, hatchling 1.30.1 |
252+
| 7 | Contenu sdist | `tar -tzf` | ✅ src complet + tests + 4 schémas + 5 starter + 42 packs x.klickd |
253+
| 8 | Contenu wheel | `zipfile -l` | ✅ mêmes ressources, `dist-info` cohérent |
254+
| 9 | `twine check` | indisponible hors-ligne | ⏭️ ignoré (consigne) — remplacé par inspection métadonnées |
255+
| 10 | Scan secrets (source) | regex clés AWS/GH/Slack/OpenAI/PyPI/npm + mots-clés | ✅ aucun secret |
256+
| 11 | Scan secrets (artefacts) | idem sur sdist + wheel extraits | ✅ aucun secret ; aucun `.env/.pem/.key` embarqué |
257+
258+
### Artefacts produits (hors dépôt, non committés)
259+
260+
```
261+
/tmp/klickd_build/klickd-4.1.0.tar.gz (~83 KB)
262+
/tmp/klickd_build/klickd-4.1.0-py3-none-any.whl (~196 KB)
263+
```
264+
265+
### Métadonnées clés du wheel (extrait)
266+
267+
```
268+
Metadata-Version: 2.4
269+
Name: klickd
270+
Version: 4.1.0
271+
Requires-Python: >=3.9
272+
Requires-Dist: argon2-cffi>=23.1
273+
Requires-Dist: cryptography>=41.0
274+
Requires-Dist: jcs>=0.2
275+
Requires-Dist: typing-extensions>=4.8
276+
Provides-Extra: validate
277+
Requires-Dist: jsonschema>=4.18; extra == 'validate'
278+
License: CC0-1.0
279+
```
280+
281+
---
282+
283+
## 8. Verdict
284+
285+
**`READY_TO_PUBLISH_PENDING_APPROVAL`**
286+
287+
Tous les contrôles locaux non publiants sont verts. Le paquet `klickd==4.1.0`
288+
se construit, s'importe, passe ses tests (109/1), embarque les bonnes
289+
ressources et métadonnées, et ne contient aucun secret.
290+
291+
### Requiert une approbation humaine explicite avant exécution
292+
293+
1. **Vérification réseau préalable** : confirmer que `klickd==4.1.0` n'existe
294+
pas déjà sur PyPI (§1).
295+
2. **Création du tag `v4.1.0`** (`git tag` / `git push origin v4.1.0`) — §3.
296+
3. **Publication de la GitHub Release `v4.1.0`** (`gh release create`) — c'est
297+
l'action qui **déclenche la publication PyPI** — §3 Option A.
298+
4. **OU** déclenchement manuel `workflow_dispatch` du workflow
299+
« Publish klickd to PyPI » — §3 Option B.
300+
5. **Approbation éventuelle de l'environnement GitHub `pypi`** (reviewer) si la
301+
protection rule est active.
302+
6. **Vérifications post-publication** (§5) et **mise à jour du Sentinel** (§6).
303+
304+
> Aucune de ces actions n'a été exécutée. Aucun tag, aucune release, aucun
305+
> dispatch, aucune publication PyPI/TestPyPI n'a été effectué par ce travail.

0 commit comments

Comments
 (0)