# Signature release Kazeia — gestion du keystore > **Résumé en 3 lignes** : les deux APK (patient + admin) sont signées en release avec > **une seule clé** : `/opt/Kazeia/keystore/kazeia-release.jks`. Si cette clé est perdue, > **aucune mise à jour in-place n'est plus possible** (désinstallation forcée = perte des > données patient). → **Sauvegarder le dossier `keystore/` hors machine, maintenant.** --- ## 1. Ce qui existe | Fichier | Rôle | |---|---| | `/opt/Kazeia/keystore/kazeia-release.jks` | Keystore (RSA 4096, alias `kazeia`, valide jusqu'en **2056**) | | `/opt/Kazeia/keystore/credentials.properties` | Chemin + mots de passe, lu par Gradle (chmod 600) | | `docs/RELEASE_SIGNING.md` | Ce document | Empreinte du certificat (référence pour vérifier qu'on signe avec la bonne clé) : ``` SHA256: 4B:40:8D:9D:40:09:FD:68:F7:FD:5B:E0:BD:64:2B:D3:EE:B8:F8:BD:7A:84:D3:9C:84:90:B8:63:21:AF:E4:90 ``` **Le dossier `keystore/` est VERSIONNÉ dans le dépôt git** (décision 2026-06-11 : le dépôt `git.kazeia.com` est privé, auto-hébergé, équipe restreinte → le git sert de sauvegarde de la clé). Conséquences à garder en tête : - **accès au dépôt = capacité de signer des mises à jour Kazeia** ; - la clé reste dans l'historique git pour toujours ; - **si le dépôt doit un jour être ouvert/partagé plus largement → rotation de clé AVANT** (§7). ## 2. Comment c'est câblé `app/build.gradle.kts` et `app-admin/build.gradle.kts` lisent `/opt/Kazeia/keystore/credentials.properties` : - **Présent** → `assembleRelease` signe avec la clé release. - **Absent** (autre machine, CI sans secrets) → le build **ne casse pas** : release signé en **debug** avec un warning `⚠ keystore release absent`. Ces APK de repli ne doivent JAMAIS être distribuées. **Une seule clé pour les deux apps** (patient `com.kazeia` + admin `com.kazeia.admin`) : même identité → permettra de protéger le ContentProvider par une `signature`-permission (prévu au plan admin, pas encore fait). ## 3. Construire et distribuer une release ```bash cd /opt/Kazeia/kazeia-android # 1) Bumper versionCode (OBLIGATOIRE sinon l'OTA ne se déclenche pas) # app/build.gradle.kts : versionCode = N+1 # (app-admin pareil si distribuée) # 2) Build ./gradlew :app:assembleRelease # → app/build/outputs/apk/release/app-release.apk # 3) Vérifier la signature (DOIT afficher l'empreinte SHA256 ci-dessus) /opt/Kazeia/android-sdk/build-tools/*/apksigner verify --print-certs \ app/build/outputs/apk/release/app-release.apk | grep SHA-256 # 4) Publier via le catalogue Nextcloud cp app/build/outputs/apk/release/app-release.apk /opt/Kazeia/kazeia-dist/apk/kazeia.apk # Éditer kazeia-dist/catalog.spec.json : app.version_code = N+1, bump catalog_version python3 /opt/Kazeia/kazeia-dist-tools/make_catalog.py --dist-root /opt/Kazeia/kazeia-dist --upload ``` Les tablettes voient `catalog.app.version_code > BuildConfig.VERSION_CODE` → téléchargent, vérifient le SHA-256, et proposent l'installation (dialogue système). ## 4. SAUVEGARDE — le point qui ne pardonne pas La clé EST l'identité de l'app. Android n'accepte une mise à jour que si elle est signée par la **même clé** que la version installée. **Sauvegarde principale : le dépôt git privé** (`keystore/` est versionné, cf §1). Une panne de la machine de build ne coûte donc plus la clé — tant que `git.kazeia.com` est vivant. **Recommandé en plus** (le git et la machine de build peuvent partager un même sinistre — serveur et poste au même endroit) : une copie hors-ligne occasionnelle : ```bash tar czf kazeia-keystore-$(date +%Y%m%d).tar.gz -C /opt/Kazeia keystore/ # → USB / coffre ``` **Sur une nouvelle machine de build** : `git clone` suffit — `keystore/` arrive avec le dépôt. Vérifier `chmod 600 keystore/credentials.properties`, builder, rien d'autre à configurer. ## 5. Scénarios de panne | Scénario | Conséquence | Procédure | |---|---|---| | **Keystore perdu (aucune sauvegarde)** | Plus AUCUNE mise à jour in-place possible | Générer une nouvelle clé, désinstaller/réinstaller sur chaque tablette → **perte des données patient** (SQLCipher lié à l'install). Exporter l'historique via l'admin AVANT si possible. À éviter à tout prix → §4. | | **Mot de passe perdu (jks présent)** | Identique à la perte du keystore | Aucun recouvrement possible sur un .jks. Le mot de passe est dans `credentials.properties` — sauvegardé AVEC le .jks. | | **Machine de build morte (sauvegarde OK)** | Aucun impact | Restaurer `keystore/` sur la nouvelle machine (§4). | | **Clé compromise (fuite)** | Un tiers peut signer des mises à jour | Distribution étant privée (Nextcloud authentifié), changer aussi les identifiants WebDAV ; planifier une migration de clé (réinstallation contrôlée). | ## 6. Migration des tablettes existantes (one-shot) Les installs actuelles sont **debug-signées** → la première APK release sera refusée en mise à jour (mismatch). **Une fois par tablette** : ```bash # 1) (si données à garder) export de l'historique via l'app admin # 2) Désinstaller les builds debug adb uninstall com.kazeia ; adb uninstall com.kazeia.admin # 3) Installer les release adb install app/build/outputs/apk/release/app-release.apk adb install app-admin/build/outputs/apk/release/app-admin-release.apk # 4) Re-provisionner (les modèles sur stockage externe/`/data/local/tmp` SURVIVENT à la # désinstallation ; profils/conversations/config in-app sont PERDUS → re-créer le profil) ``` Après cette migration, toutes les mises à jour passent par l'OTA catalogue, sans perte. ⚠ **Le dev quotidien reste en debug** (`assembleDebug` + `adb install -r`) : debug et release sont signés différemment, on ne peut pas écraser l'un par l'autre. La tablette de dev reste en debug ; les tablettes patient passent en release. ## 7. Rotation / clés multiples (futur) - Pas d'expiration avant 2056 ; pas de rotation préventive nécessaire pour une distribution privée. - Si un jour publication sur un store : Google Play App Signing prendra cette clé comme « upload key » et gérera la clé de signature côté store (le risque de perte disparaît).