All checks were successful
PR Check — Rust / rust (pull_request) Successful in 9m14s
`downloadAndInstall` is one call that downloads AND installs (updater.rs:723-729), and the `Finished` event is a no-op in useUpdater.ts:119-121. `READY_TO_INSTALL` is therefore dispatched only after `dpkg -i` returns, so the pkexec prompt opens while the card still reads "Téléchargement en cours…". The checklist told the tester to tick `readyToInstall` before the prompt. That ordering neutralized the polkit precondition the page exists to enforce: with no agent the app hangs in `downloading`, not in `readyToInstall`, so a tester following the checklist files "the download stalls" instead of "no polkit agent" — the exact false trace this page is written to prevent. Also states plainly that at `readyToInstall` the .deb is already on disk and the button only calls `relaunch()`; the label misleads on this target. Three smaller corrections from the same review: - The update triggers are four manual sites, not two: UpdateCard idle / upToDate refresh / error retry, plus ErrorPage.tsx:82 — which only detects and offers no download path. The load-bearing claim, "no automatic check in the app", was already right. - "Si ça casse" now spells out that DELETE and PUT hit different API prefixes (/api/v1/packages/ vs /api/packages/, release.yml:217-219, which carries a comment about exactly this). Replaying both against one URL 404s at the worst possible moment. - The SKILL.md changelog entry moves back into date order. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
97 lines
9.1 KiB
Markdown
97 lines
9.1 KiB
Markdown
# QA — Cycle de mise à jour automatique
|
|
|
|
Checklist manuelle pour valider qu'une release est réellement installable **par la mise à jour automatique**, et pas seulement téléchargeable. À dérouler après chaque release qui touche `tauri-plugin-updater`, ses dépendances (`reqwest`/`rustls-webpki`, `tar`), `release.yml`, ou la configuration `updater` de `tauri.conf.json`.
|
|
|
|
Elle existe parce que la CI ne peut rien prouver ici : `cargo check` et `cargo test` prouvent que le chemin de mise à jour **compile**, jamais qu'il fonctionne. Une régression s'y manifeste chez l'utilisateur, au moment de la mise à jour — et la mise à jour automatique étant une fonctionnalité **Base+**, ce sont des utilisateurs payants.
|
|
|
|
> **Cette checklist tourne après que la release est publiée.** `release.yml` a déjà poussé `latest.json` vers le registre de paquets, qui est l'endpoint configuré dans `tauri.conf.json`. Tout utilisateur Base+ qui clique sur « Vérifier les mises à jour » reçoit donc déjà la nouvelle version pendant que vous déroulez ceci. En cas d'échec, voir « Si ça casse » en bas — et lire cette section **avant** de commencer, pas pendant l'incident.
|
|
|
|
---
|
|
|
|
## Prérequis
|
|
|
|
Ce sont les conditions sans lesquelles le test ne teste rien. Chacune a un mode d'échec où la checklist se coche « OK » sans avoir rien vérifié.
|
|
|
|
- [ ] **Une machine Windows** (hôte ou VM) et **une machine Linux de bureau**. Les deux flux sont réellement différents, ils ne se substituent pas l'un à l'autre.
|
|
- [ ] Sur la machine Linux, **un agent polkit qui tourne**. L'installation du `.deb` passe par `pkexec` ; sans agent, l'app retombe en cascade sur `zenity`/`kdialog` puis sur un `sudo` dans un terminal inexistant, et **paraît figée au lieu d'échouer — sur l'écran de téléchargement, pas sur `readyToInstall`** (voir §2, c'est le piège qui produit le mauvais rapport de bug). Noter plus bas quelle invite est réellement apparue : si ce n'est pas polkit, c'est un chemin de repli qui a été validé, pas le chemin nominal.
|
|
- [ ] **La version précédente installée sur chaque machine**, depuis les artefacts de la release précédente (`.deb` et `-setup.exe` attachés à la release Forgejo). Ne pas tester sur la machine qui vient de builder la nouvelle version.
|
|
|
|
> Sans ça, `check()` compare `release.version > version_courante`, trouve faux, et l'UI affiche « à jour ». La checklist se coche alors comme « rien à mettre à jour » — soit exactement le saut silencieux qu'elle est censée éliminer, avec en prime une trace écrite affirmant qu'elle est passée.
|
|
|
|
- [ ] **Une clé de licence Base ou Premium valide sur chaque machine.** La mise à jour automatique est verrouillée par édition : `useUpdater` appelle `check_entitlement("auto-update")` et bascule en `notEntitled` **avant** même d'appeler `check()`. Une installation Gratuite ne télécharge jamais rien, et les builds de release n'ont pas de `dev-override`.
|
|
- [ ] Sur chaque machine, **supprimer tout `activation.token` provenant d'une autre machine** (VM clonée, snapshot restauré) dans le répertoire de données de l'app. Une `license.key` seule fonctionne — l'absence de token est un état de pré-activation toléré — mais un token émis pour un autre `machine_id` fait retomber l'édition en Gratuite, et le testeur voit une carte « non éligible » anodine plutôt qu'un échec.
|
|
|
|
---
|
|
|
|
## Ce que ce test prouve — et ce qu'il ne prouve pas
|
|
|
|
À écrire explicitement, parce que la tentation est de croire qu'un cycle réussi couvre tout le chemin de mise à jour.
|
|
|
|
**Prouvé** sur les deux cibles : le téléchargement TLS (donc `rustls-webpki`), la vérification de signature minisign, l'exécution de l'installeur, et le redémarrage sur la nouvelle version.
|
|
|
|
**Non prouvé** : l'extraction d'archive, donc `tar`. Dans `tauri-plugin-updater`, `tar` n'est atteint que par `install_appimage` et la branche macOS `.app.tar.gz`. Aucun de nos bundles ne passe par là — le `.deb` fait `pkexec dpkg -i`, le NSIS écrit le `.exe` dans un répertoire temporaire et le lance. **Tant qu'on ne livre pas d'AppImage, le chemin `tar` reste mort** et aucune checklist manuelle ne le couvrira.
|
|
|
|
---
|
|
|
|
## 1. Windows (NSIS)
|
|
|
|
Point d'entrée : **Paramètres → Systèmes → carte Mises à jour → « Vérifier les mises à jour »**. Il n'y a **aucune vérification automatique dans l'app** : les quatre déclencheurs sont manuels — ce bouton, l'icône rafraîchir de l'état `upToDate`, le « réessayer » de l'état `error`, et celui de la page d'erreur, qui **détecte seulement** et n'offre aucun chemin de téléchargement.
|
|
|
|
- [ ] La carte passe en `checking`, puis affiche `available` avec le **numéro de la nouvelle version** et les notes extraites du CHANGELOG.
|
|
- [ ] Cliquer sur télécharger → état `downloading`, **la progression avance** (elle vient de `contentLength`, donc un serveur qui ne le renvoie pas se voit ici).
|
|
- [ ] L'installeur NSIS s'ouvre et **l'application se ferme d'elle-même**.
|
|
|
|
> Attendu, et propre à Windows : `downloadAndInstall` ne rend jamais la main — le processus appelle `exit(0)` et laisse l'installeur prendre le relais. Les états `readyToInstall` et `installing` **ne s'affichent jamais** sur cette cible. Ne pas les attendre, ne pas les cocher.
|
|
|
|
- [ ] Terminer l'installation, relancer l'app, vérifier la version dans Paramètres → Systèmes.
|
|
- [ ] Re-cliquer sur « Vérifier les mises à jour » → `upToDate`.
|
|
|
|
## 2. Linux (.deb)
|
|
|
|
- [ ] Même point d'entrée, mêmes états jusqu'à `downloading`.
|
|
- [ ] **Pendant que la carte affiche encore « Téléchargement en cours… »**, une invite d'authentification apparaît. **Noter laquelle** : polkit (nominal), zenity/kdialog, ou rien du tout (repli `sudo` → l'app reste figée **sur l'écran de téléchargement**).
|
|
|
|
Invite observée : `________________`
|
|
|
|
> C'est bien le moment nominal, et c'est contre-intuitif : `downloadAndInstall` télécharge **et** installe dans le même appel (`updater.rs:723-729`), et l'événement `Finished` est un no-op côté UI (`useUpdater.ts:119-121`). L'écran reste donc sur `downloading` pendant tout le `dpkg -i`. Un testeur qui guette l'invite **après** `readyToInstall` ne la verra jamais arriver au bon moment : il rapportera « le téléchargement bloque » là où le vrai diagnostic est « pas d'agent polkit ».
|
|
|
|
- [ ] Authentifier → l'app **reste vivante** et passe en `readyToInstall` (« Mise à jour prête à installer » + bouton « Installer et redémarrer »).
|
|
|
|
> À ce stade le `.deb` est **déjà installé sur le disque** : `installAndRestart` ne fait que `relaunch()`. Le libellé du bouton ment sur cette cible — qui s'arrête là croit que rien n'a été installé, et qui voit la version changer après le clic attribue l'installation au clic.
|
|
|
|
- [ ] Cliquer → état `installing`, l'app redémarre.
|
|
- [ ] Vérifier la version, re-vérifier → `upToDate`.
|
|
|
|
## 3. RPM — cassé, connu
|
|
|
|
- [ ] **Ne pas tester** : ce chemin est cassé, pas seulement non vérifié.
|
|
|
|
`latest.json` ne porte qu'une entrée `linux-x86_64`, construite à partir du `.deb` (`release.yml:104-122`). Une installation rpm reçoit donc des octets deb, que `Installer::Rpm` rejette après vérification de la signature magique du payload. Les artefacts `.rpm` continuent pourtant d'être publiés comme assets de release. Suivi en **#320**.
|
|
|
|
---
|
|
|
|
## Si ça casse
|
|
|
|
L'ordre compte, et la première action ne répare pas ce qu'on croit.
|
|
|
|
1. **Republier le `latest.json` précédent** sur `generic/simpl-resultat/latest` (`DELETE` puis `PUT`, avec le `PACKAGE_TOKEN` qu'utilise `release.yml`). Le corps est récupérable depuis les assets de la release précédente — sa copie dans le registre a été détruite par le `DELETE` que `release.yml` fait avant chaque envoi.
|
|
|
|
**Les deux verbes ne visent pas le même préfixe d'API**, et `release.yml:217-219` porte un commentaire explicite là-dessus — le piège est déjà tombé une fois :
|
|
|
|
```
|
|
DELETE {serveur}/api/v1/packages/{owner}/generic/simpl-resultat/latest
|
|
PUT {serveur}/api/packages/{owner}/generic/simpl-resultat/latest
|
|
```
|
|
|
|
Rejouer les deux sur la même URL donne un 404 sur l'un des deux, au moment où on peut le moins se permettre de le débugger.
|
|
|
|
2. **Comprendre ce que ça arrête, et ce que ça n'arrête pas.** `check()` compare strictement `release.version > version_courante`. Republier vN-1 **stoppe la propagation** vers ceux qui n'ont pas encore cliqué. Les utilisateurs déjà passés à la vN cassée ne se verront **jamais** proposer vN-1 : ils sont bloqués dessus.
|
|
|
|
3. **Le vrai correctif est donc une vN+1**, pas un retour en arrière. Le republication de vN-1 n'achète que du temps — et si elle reste en place, elle prive aussi les utilisateurs restés en vN-1 de tout chemin de mise à jour.
|
|
|
|
---
|
|
|
|
## Trace
|
|
|
|
- [ ] Consigner le résultat en commentaire de la release Forgejo : cibles déroulées, versions de départ et d'arrivée, invite d'authentification observée sous Linux.
|
|
- [ ] Si la checklist **n'a pas été déroulée**, l'écrire explicitement avec la raison, plutôt que de laisser le silence. Une étape non tracée est indiscernable d'une étape passée — c'est le mode d'échec que cette page combat.
|