feat(desktop): signature updater Tauri + wizard persistant + protocole E2E (#77)
CI / lint (push) Successful in 1m11s
CI / security (push) Successful in 43s
CI / test (push) Successful in 2m22s
CI / build (push) Successful in 1m41s
CI / e2e (push) Successful in 10m50s
Desktop Build / build-windows (push) Canceled after 0s
Desktop Build / build-linux (push) Canceled after 0s

- Signature des mises a jour Tauri : paire de cles minisign generee, cle publique dans tauri.conf.json, createUpdaterArtifacts actif, secrets CI exposes (repli build non signe si secret absent).

- Wizard 1er lancement : etat persistant wizard_done cote Rust (get_wizard_state/complete_wizard) pour ne plus reafficher la banniere, retro-compatible.

- Protocole des 6 tests E2E manuels : docs/DESKTOP_E2E_CHECKLIST.md.

- CI : desktop.test.mjs ajoute au job lint.

- Docs : ROADMAP, fiche desktop-tauri, CHANGELOG, README desktop, guide releases.

- fix(build): retirer les libs WeasyPrint inutiles du stage builder Docker.
This commit is contained in:
2026-09-12 09:29:47 -04:00
parent 31d4be8015
commit d3299166bb
14 changed files with 519 additions and 29 deletions
+188
View File
@@ -0,0 +1,188 @@
# ObsiGate Desktop — Protocole de tests E2E manuels
> **Rôle :** valider les 6 scénarios de bout en bout du desktop Tauri (#77) qui ne
> peuvent pas être automatisés (interactions OS : installeur, tray, notifications,
> association de fichiers, auto-update, désinstallation).
> **Statut :** protocole documenté — à exécuter manuellement par un humain.
> **Références :** [feature desktop-tauri](./features/desktop-tauri.md) ·
> [Roadmap](./ROADMAP.md) · [Build & releases](./DEVELOPMENT_AND_RELEASES.md)
---
## 1. Prérequis
- Un **build release** de l'application :
- Windows : `desktop\build-windows.bat` → `ObsiGate_x.y.z_x64.msi` / `-setup.exe`
- Linux : `desktop/build-linux.sh` → `obsigate_x.y.z_amd64.deb` / `.AppImage`
- Une **machine vierge ou un compte utilisateur propre** (pas d'installation
précédente) pour les tests d'installation/désinstallation.
- Le **mot de passe admin** affiché au premier lancement (ou `OBSIGATE_ADMIN_PASSWORD`
défini avant le lancement).
- Accès en écriture aux logs : `%APPDATA%\ObsiGate\logs\backend.log` (Windows) ou
`~/.config/obsigate/logs/backend.log` (Linux).
## 2. Comment remplir ce protocole
Pour chaque test : noter la **version testée** (`menu Aide → À propos`), le
**commit** du build, la **date**, puis cocher `✅ OK` ou `❌ Échec` et joindre les
logs/ captures en cas d'échec. Ne cocher un test qu'après avoir observé le
**résultat attendu**.
| Test | Version | Commit | Date | Résultat |
|---|---|---|---|---|
| T1 — Installation | | | | ⬜ |
| T2 — Tray icon | | | | ⬜ |
| T3 — Notifications natives | | | | ⬜ |
| T4 — Association `.md` | | | | ⬜ |
| T5 — Auto-update | | | | ⬜ |
| T6 — Désinstallation | | | | ⬜ |
---
## T1 — Installation → premier lancement → ouverture d'un fichier
**Objectif :** l'installeur installe l'app et le premier lancement démarre le
backend + affiche l'interface.
1. Lancer l'installeur (`.msi` ou `.deb`/`.AppImage`).
2. Installer dans le chemin par défaut → vérifier la création du raccourci
(bureau / menu Démarrer / menu applications).
3. Lancer ObsiGate depuis le raccourci.
4. Observer l'écran de démarrage (« ObsiGate démarre… ») puis l'interface.
5. Au premier lancement, cliquer **« Choisir mon dossier »** dans la bannière du
wizard et sélectionner un dossier vault.
6. Ouvrir un fichier `.md` depuis l'arborescence.
**Résultat attendu :**
- Aucun terminal / console visible.
- Le backend répond (`http://127.0.0.1:17890/api/health` → 200) en ~2 s.
- Le fichier s'ouvre dans le viewer.
- La bannière du wizard **ne réapparaît pas** au lancement suivant.
**Échec si :** écran blanc, backend non démarré, wizard qui revient à chaque
lancement.
---
## T2 — Tray icon → réduire → restaurer
**Objectif :** le tray fonctionne et contrôle la fenêtre.
1. Vérifier la présence de l'icône ObsiGate dans la zone de notification.
2. Clic **gauche** sur l'icône → la fenêtre se cache.
3. Clic **gauche** à nouveau → la fenêtre réapparaît et prend le focus.
4. Clic **droit** → menu (Ouvrir ObsiGate / À propos / Quitter).
5. Fermer la fenêtre avec le **X** → elle se réduit dans le tray, le backend
continue de tourner (l'icône reste).
**Résultat attendu :** toggle visible/caché immédiat, menu contextuel complet,
fermeture par X = réduction (pas d'arrêt du backend).
---
## T3 — Notifications natives (fichier modifié → popup OS)
**Objectif :** les notifications natives remplacent le push web.
1. Activer les notifications dans les préférences (par vault si proposé).
2. Modifier un fichier surveillé (édition externe dans le vault, ou édition
in-app avec le watcher actif).
3. Observer la notification du système d'exploitation.
**Résultat attendu :** popup OS affichant le nom du fichier/vault et l'action ;
un clic ouvre le fichier concerné. La notification apparaît même si la fenêtre
ObsiGate est réduite.
> Note : sur Windows, vérifier que les notifications ne sont pas bloquées dans
> *Paramètres → Système → Notifications*.
---
## T4 — Association `.md` → double-clic → ouvre dans ObsiGate
**Objectif :** l'association de fichiers ouvre l'app.
1. Vérifier que `.md` est associé à « ObsiGate Markdown » (Windows :
*Paramètres → Applications par défaut* ; Linux : `xdg-mime query default text/markdown`).
2. **Fermer** complètement ObsiGate (tray → Quitter).
3. Double-cliquer sur un fichier `.md` dans l'explorateur / gestionnaire de fichiers.
4. Observer le lancement d'ObsiGate et l'ouverture du fichier.
**Résultat attendu :** ObsiGate démarre et ouvre le fichier (ou le vault
contenant le fichier). Un second double-clic alors que l'app tourne **focus la
fenêtre existante** (single-instance) au lieu de lancer un doublon.
---
## T5 — Auto-update → nouvelle version → installation
**Objectif :** l'updater détecte et installe une nouvelle version.
1. S'assurer qu'une **release plus récente** existe sur Gitea (avec les artefacts
et le manifeste de mise à jour signé).
2. Lancer la version N.
3. Déclencher la vérification de mise à jour (menu ou au démarrage selon l'UI).
4. Accepter la mise à jour → l'app télécharge, vérifie la signature et installe.
5. Relancer → vérifier la version affichée (`À propos`).
**Résultat attendu :** détection de la version N+1, téléchargement, installation
sans intervention manuelle, version mise à jour après redémarrage.
**Prérequis bloquant :** la `pubkey` de l'updater dans `desktop/tauri.conf.json`
ne doit **pas** être le placeholder `OBSIGATE_UPDATE_PUBKEY_PLACEHOLDER`, et la
clé privée correspondante doit être fournie au build
(`TAURI_SIGNING_PRIVATE_KEY`). Voir §4.
---
## T6 — Désinstallation propre
**Objectif :** la désinstallation ne laisse aucun processus ni résidu gênant.
1. Fermer ObsiGate (tray → Quitter) pour éviter un processus orphelin.
2. Désinstaller via le panneau de configuration (Windows) ou `dpkg -r obsigate`
/ supprimer l'AppImage (Linux).
3. Vérifier qu'aucun processus `obsigate-desktop` / Python backend ne tourne
encore.
4. Vérifier les résidus : raccourcis supprimés, entrée « Applications par
défaut » retirée.
5. (Optionnel) Vérifier le comportement des données utilisateur
(`%APPDATA%\ObsiGate` / `~/.config/obsigate`) : conservées ou supprimées selon
le choix documenté.
**Résultat attendu :** désinstallation sans erreur, aucun processus résiduel,
aucun raccourci cassé.
---
## 3. Emplacements utiles
| Élément | Windows | Linux |
|---|---|---|
| Config | `%APPDATA%\ObsiGate\config.json` | `~/.config/obsigate/config.json` |
| Logs backend | `%APPDATA%\ObsiGate\logs\backend.log` | `~/.config/obsigate/logs/backend.log` |
| Données (index, comptes) | `%APPDATA%\ObsiGate\data\` | `~/.config/obsigate/data\` |
## 4. Signature de code & auto-update
- **Signature Windows (optionnelle, hors périmètre de ce protocole) :** sans
certificat, SmartScreen affiche un avertissement au premier lancement
(*Informations complémentaires → Exécuter quand même*). Le script
`desktop/scripts/sign-windows.ps1` signe automatiquement si
`OBSIGATE_SIGN_CERT_PFX` est défini ; sinon il est un no-op explicite.
Alternatives détaillées dans le [README desktop](../desktop/README.md).
- **Signature de l'updater Tauri (gratuite, distincte de la signature Windows) :**
générer une paire de clés, renseigner la `pubkey` dans
`desktop/tauri.conf.json` et exposer la clé privée au build via
`TAURI_SIGNING_PRIVATE_KEY`. La clé privée **ne doit jamais être commitée**.
```bash
cargo tauri signer generate -w ~/.tauri/obsigate.key
# → copier la clé publique affichée dans plugins.updater.pubkey
```
## 5. Clôture
Une fois les 6 tests exécutés et OK, reporter le résultat dans
[`docs/features/desktop-tauri.md`](./features/desktop-tauri.md) (section F) et
mettre à jour le statut du #77 dans la [Roadmap](./ROADMAP.md).
+84
View File
@@ -57,6 +57,90 @@ cargo tauri dev
---
## 2bis. Signature des mises à jour (updater Tauri)
La signature de l'auto-update Tauri est **indépendante** de la signature de code
Windows et **gratuite**. Elle garantit qu'une mise à jour téléchargée provient bien
de vous. Elle repose sur une paire de clés `minisign` :
- La **clé publique** est embarquée dans `desktop/tauri.conf.json`
(`plugins.updater.pubkey`).
- La **clé privée** signe les artefacts au build. Elle ne doit **jamais** être
commitée (ignorée par `.gitignore`).
### A. Générer la paire de clés (une seule fois)
```bash
cd desktop
cargo tauri signer generate -w obsigate-updater.key
# La clé publique s'affiche et est écrite dans obsigate-updater.key.pub
```
> ⚠️ Conservez la clé privée en lieu sûr (gestionnaire de secrets). Si vous la
> perdez, les mises à jour ne pourront plus être signées. Pour la protéger par mot
> de passe : ajoutez `-p "<mot de passe>"`.
Copiez le contenu de `obsigate-updater.key.pub` dans
`desktop/tauri.conf.json` → `plugins.updater.pubkey`.
### B. Build local signé
```powershell
# Windows PowerShell
$env:TAURI_SIGNING_PRIVATE_KEY = Get-Content -Raw .\obsigate-updater.key
# $env:TAURI_SIGNING_PRIVATE_KEY_PASSWORD = "<mot de passe>" # si la clé en a un
cargo tauri build --bundles nsis,msi
```
```bash
# Linux / Bash
export TAURI_SIGNING_PRIVATE_KEY="$(cat obsigate-updater.key)"
# export TAURI_SIGNING_PRIVATE_KEY_PASSWORD="<mot de passe>"
cargo tauri build --bundles appimage,deb
```
Le CLI produit des fichiers `.sig` à côté de chaque artefact
(`*.exe.sig`, `*.msi.sig`, `*.AppImage.sig`, `*.deb.sig`).
> Sans clé définie, `createUpdaterArtifacts` est actif et le build échoue : dans
> le CI, l'étape désactive automatiquement les artefacts de mise à jour si le
> secret est absent.
### C. Secrets CI (Gitea)
Dans **Dépôt → Paramètres → Actions → Secrets**, créez :
| Secret | Valeur |
|---|---|
| `TAURI_SIGNING_PRIVATE_KEY` | contenu **intégral** du fichier `.key` |
| `TAURI_SIGNING_PRIVATE_KEY_PASSWORD` | mot de passe de la clé (vide si aucun) |
Le workflow `.gitea/workflows/desktop-build.yml` les expose aux étapes de build ;
les fichiers `.sig` sont uploadés comme artefacts.
### D. Manifeste de mise à jour (`latest.json`)
Le CLI Tauri génère les `.sig` mais **pas** le manifeste JSON consommé par
l'updater. L'endpoint configuré
(`.../releases/latest`) doit servir un document de la forme :
```json
{
"version": "2.3.0",
"notes": "…",
"pub_date": "2026-09-12T00:00:00Z",
"platforms": {
"windows-x86_64": { "signature": "<contenu .msi.sig>", "url": "<URL du .msi>" },
"linux-x86_64": { "signature": "<contenu .AppImage.sig>", "url": "<URL .AppImage>" }
}
}
```
Sans ce manifeste, l'updater ne détecte aucune mise à jour (la signature, elle,
est déjà opérationnelle).
---
## 3. Commit, Push & Tagging Git
Une fois les modifications testées et validées :
+6 -6
View File
@@ -33,12 +33,12 @@
### 77. Application Desktop native — Tauri (Windows / Linux / macOS)
- **Effort :** 8-12 jours | **Impact :** 🟡 | **Framework :** Tauri v2 (Rust + Webview)
- **Statut :** livré (A→F) — projet Tauri, backend Python embarqué, fonctionnalités natives, build CI, UX, 16 tests Rust. Détail complet : [features/desktop-tauri.md](./features/desktop-tauri.md)
- **Statut :** livré (A→F) — projet Tauri, backend Python embarqué, fonctionnalités natives, jumplist vaults, bannière 1er lancement, build CI, UX, 24 tests Rust. Détail complet : [features/desktop-tauri.md](./features/desktop-tauri.md)
- **Reste à faire :**
- [ ] Signature de code Windows (optionnel mais recommandé)
- [ ] Wizard « Choisissez votre vault » au 1er lancement (optionnel)
- [ ] Jumplist vaults récents dans le menu Démarrer (optionnel)
- [ ] 6 tests E2E **manuels** : installation, tray icon, notifications natives, association `.md`, auto-update, désinstallation
- [x] **Signature de l'updater Tauri** (gratuit) : paire de clés générée, `pubkey` renseignée, `createUpdaterArtifacts` activé, secrets CI câblés
- [ ] Générer le manifeste `latest.json` pour que l'updater détecte les mises à jour
- [ ] **Signature de code Windows** : non retenue (pas de certificat) — alternatives : livrer non signé, SignPath.io (OSS gratuit), Certum OSS, Azure Trusted Signing, certificat EV
- [ ] Exécuter les 6 tests E2E **manuels** — protocole documenté : [DESKTOP_E2E_CHECKLIST.md](./DESKTOP_E2E_CHECKLIST.md)
---
@@ -105,7 +105,7 @@
| Priorité | Items | Effort total estimé |
|---|---|---|
| ✅ Complété | #1 → #59, #61–72, #74–76, #78–80 | ~103 jours réalisés |
| 🔵 P2 restant | #77 Desktop : signature code (optionnel), wizard 1er lancement (optionnel), 6 tests E2E **manuels** | ~1-2 jours |
| 🔵 P2 restant | #77 Desktop : manifeste `latest.json`, signature de code (non retenue), 6 tests E2E **manuels** ([protocole](./DESKTOP_E2E_CHECKLIST.md)) | ~0,5-1 jour |
| ⚪ P4 restant | #73 Sync (6-8j) | 6-8 jours |
| **Total restant** | **2 items + finitions** | **~7-10 jours** |
+11 -11
View File
@@ -1,6 +1,6 @@
# #77 — Application Desktop native — Tauri (Windows / Linux / macOS)
> **Statut :** 🔵 En cours — livré : A/B/C/D/E/F ; reste signature de code (optionnel), wizard 1er lancement (optionnel), 6 tests E2E manuels
> **Statut :** 🔵 En cours — livré : A/B/C/D/E/F ; reste la signature de code Windows (optionnelle, non retenue) et l'exécution des 6 tests E2E **manuels** ([protocole](../DESKTOP_E2E_CHECKLIST.md))
> **Effort :** 8-12 jours | **Impact :** 🟡 | **Framework :** Tauri v2 (Rust + Webview)
> **Références :** [Roadmap](../ROADMAP.md) · [Guide de build & releases](../DEVELOPMENT_AND_RELEASES.md)
@@ -57,7 +57,8 @@
- [x] **Build Windows local** : `cargo build --release` vérifié (rustc 1.94.1) — `cargo tauri build --bundles msi` prêt
- [x] **Build Linux local** : workflow CI couvre `.deb`, `.rpm`, `.AppImage`
- [x] **Auto-update** : `tauri-plugin-updater` configuré → vérifie `https://git.dracodev.net/api/v1/repos/Projets/ObsiGate/releases/latest`
- [ ] **Signature de code** : configurer le certificat (optionnel mais recommandé pour Windows)
- [x] **Signature de l'updater Tauri** (gratuite, ≠ signature Windows) : paire de clés `minisign` générée, clé publique dans `plugins.updater.pubkey`, `bundle.createUpdaterArtifacts: true`, secrets Gitea `TAURI_SIGNING_PRIVATE_KEY` / `_PASSWORD` exposés au CI (build non signé en repli si le secret est absent). Reste : générer le manifeste `latest.json` pour que l'updater détecte les mises à jour ([guide](../DEVELOPMENT_AND_RELEASES.md#2bis-signature-des-mises-à-jour-updater-tauri))
- [ ] **Signature de code Windows** : non retenue (pas de certificat) — alternatives : livrer non signé, SignPath.io (OSS gratuit), Certum Open Source, Azure Trusted Signing, certificat EV
- [x] **Page de release** : README desktop existe (`desktop/README.md`)
## E. Expérience utilisateur (1 jour) — ✅ COMPLÉTÉ
@@ -65,19 +66,18 @@
- [x] Gestion des erreurs : backend crash → `showBackendCrashBanner()` appelé par le monitor loop toutes les 5s
- [x] Sauvegarde des préférences desktop : position/taille fenêtre sauvées dans `%APPDATA%/ObsiGate/config.json` au close + restauration au startup
- [x] Première expérience : config par défaut auto-créée au premier lancement (vault `~/voute_obsidian`, dir `~USERPROFILE`)
- [ ] Wizard interactif « Choisissez votre vault » au premier lancement (optionnel — config auto suffisante)
- [ ] Jumplist vaults récents dans le menu Démarrer (optionnel)
- [x] Bannière de premier lancement « Choisissez votre vault » (`frontend/js/desktop.js`) — non bloquante ; l'état est persisté côté Rust (`wizard_done` dans `config.json`) pour ne pas réapparaître après un choix ou un clic « Plus tard », même si le `localStorage` de la webview est vidé
- [x] Jumplist vaults récents dans le menu Démarrer (`desktop/src/jumplist.rs`, Windows)
## F. Tests (1 jour) — ✅ COMPLÉTÉ
- [x] 16 tests Rust unitaires : config roundtrip, JSON parsing (empty/partial/corrupted), vault dedup, dir remove, backend URL, paths, branding, edge cases
- [x] 24 tests Rust unitaires : config roundtrip, JSON parsing (empty/partial/corrupted/legacy), `wizard_done`, vault dedup, dir remove, backend URL, paths, branding, jumplist args, edge cases
- [x] Build debug + release vérifié (rustc 1.94.1, tauri-cli 2.11.4)
- [x] CI desktop workflow existant (desktop-build.yml)
- [ ] Test E2E : installation → premier lancement → wizard vault → ouverture fichier (manuel)
- [ ] Test E2E : tray icon → réduire → restaurer (manuel)
- [ ] Test E2E : notifications natives → fichier modifié → popup OS (manuel)
- [ ] Test E2E : association `.md` → double-clic → ouvre dans ObsiGate (manuel)
- [ ] Test E2E : auto-update → nouvelle version → install (manuel)
- [ ] Test E2E : désinstallation propre (manuel)
- [ ] **6 tests E2E manuels** — protocole détaillé (prérequis, étapes, résultat
attendu) dans [docs/DESKTOP_E2E_CHECKLIST.md](../DESKTOP_E2E_CHECKLIST.md) :
installation → 1er lancement → wizard → ouverture fichier ; tray ; notifications
natives ; association `.md` ; auto-update ; désinstallation propre. À exécuter
et cocher par un humain sur un build release.
- **Prérequis techniques :**
- Rust ≥ 1.75 (stable) — installé via `rustup`