Skip to content

Commit b225549

Browse files
committed
docs: la documentation annoncait une v1.1.7 qui n'existera pas
Le retrait de l'IA avait ete documente sous le numero v1.1.7, avant que le bump majeur ne soit tranche. Douze references a une version qui n'existera jamais, dans le README, SECURITY.md, le cahier des charges et neuf commentaires de code. Toutes ramenees a 2.0.0. README — quatre affirmations perimees corrigees : - l'en-tete annoncait « v1.0.4 — Mai 2026 » ; - la section « Quoi de neuf » decrivait encore la v1.0.0 ; reecrite pour la 2.0.0, avec la justification du bump majeur et le passage aux splits sans universel ; - **« Ce depot n'a pas de pipeline de release CI automatique »** etait faux : `release.yml` construit et signe les APK au push d'un tag `v*`. C'est justement lui qui publie cette version ; - la section Installation renvoyait a la v1.0.0 et mettait le build local en premier ; l'APK publiee passe devant, avec la verification SHA-256. SECURITY.md — entree v2.0.0 ajoutee. Elle documente les cinq defauts serieux fermes ce cycle : la cle Keystore detruite avant la base a la suppression d'un coffre (perte de donnees irreversible), le mode panique qui declarait l'effacement termine malgre des echecs, le titre d'une note de coffre ecrit en clair, la course du presse-papiers, et les migrations de schema qui n'avaient jamais tourne. L'historique anterieur n'est pas touche : reecrire un journal de securite serait pire que de le laisser dater. `database.dart` : la substitution automatique avait converti ses 905 fins de ligne CRLF en LF, produisant un diff binaire de 40 Ko pour un commentaire. Fichier restaure et ligne reappliquee a la main — le diff est desormais de taille nulle. flutter analyze : 0 issue. flutter test : 65 passed.
1 parent 7fc7365 commit b225549

11 files changed

Lines changed: 98 additions & 38 deletions

File tree

README.md

Lines changed: 40 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,44 @@
22

33
> Vos notes restent dans votre poche. Chiffrées, et hors ligne.
44
5-
**v1.0.4Mai 2026** · [Politique de confidentialité](PRIVACY.md) · [CGU](TERMS.md) · [Sécurité](SECURITY.md)
5+
**v2.0.0Août 2026** · [Politique de confidentialité](PRIVACY.md) · [CGU](TERMS.md) · [Sécurité](SECURITY.md)
66

77
Application Android Flutter de prise de notes Markdown chiffrées,
88
**100 % locale, zéro permission Internet**. Interface bilingue **FR / EN**.
99
Coffres par dossier (passphrase Argon2id ou PIN Keystore-bound), recherche
1010
plein-texte FTS5, dictée vocale Whisper on-device, backlinks `[[note]]`,
1111
mode panique multi-step.
1212

13-
## Quoi de neuf en v1.0.0
14-
15-
- **i18n FR / EN complète** : 9 écrans + 14 widgets, sélecteur Langue
16-
dans Réglages, locale système suivie par défaut.
17-
- **Sélecteur de thème** : Clair / Sombre / Système, persisté.
18-
- **Splits ABI** : APK livré ~1/3 plus léger par device (arm64-v8a,
19-
armeabi-v7a, x86_64).
20-
- **Mode panique whitelist** : `db_encrypted_v1` et `secure_window_enabled`
21-
préservés pour cohérence du redémarrage (conformément à PRIVACY.md).
22-
- **A11y P0** : annonces TalkBack et `Semantics` complets sur le pavé PIN,
23-
la sauvegarde et les overlays de dictée.
24-
- **Helpers UI extraits** : `PassphraseTextField`, `VaultWarningBanner`,
25-
`BlockingProgressDialog` (factorisation cross-écrans).
26-
- **Mentions légales** : page rendue depuis `assets/legal/PRIVACY.{fr,en}.md`
27-
et `TERMS.{fr,en}.md` via `flutter_markdown`.
28-
- **Performance** : `Selector` ciblé sur `themeMode + locale`,
29-
`MediaQuery.sizeOf` dans les listes.
13+
## Quoi de neuf en v2.0.0
14+
15+
**L'IA embarquée est retirée.** La recherche sémantique (MiniLM) et le
16+
Q&A « Demander à mes notes » (Gemma 3 1B) disparaissent. L'APK arm64
17+
passe de ~127 Mo à **26,9 Mo**. La recherche reste plein-texte FTS5 +
18+
bm25 : rapide et exacte, mais elle ne devine pas les synonymes.
19+
20+
Bump majeur et non mineur pour trois raisons :
21+
22+
- l'app perd ses deux fonctions phares, ce qu'un `1.2.0` ne signalerait
23+
pas à l'utilisateur ;
24+
- l'APK est divisé par près de cinq, visible dès l'installation ;
25+
- **la migration est à sens unique** : la base passe en schéma v9 et la
26+
v1.1.6 publiée n'a pas de `onDowngrade`, donc réinstaller une 1.x ne
27+
peut plus ouvrir la base.
28+
29+
Cette version inaugure aussi les **APK splits par ABI sans universel**.
30+
Les deux familles ont des `versionCode` incompatibles — l'offset
31+
`+1000 × index` de Flutter place tout universel sous n'importe quel
32+
split de même version, et Android refusait alors l'installation en
33+
downgrade. Transition à sens unique : ne pas réintroduire d'universel.
34+
35+
Corrections notables du même cycle :
36+
37+
- supprimer un dossier détruisait la clé Keystore **avant** la base, ce
38+
qui rendait un coffre définitivement illisible si la base échouait ;
39+
- le mode panique annonçait « effacement terminé » même en cas d'échec ;
40+
- **les migrations de schéma n'avaient jamais tourné** — les tests
41+
créaient des bases neuves, donc `onUpgrade` n'était jamais appelé ;
42+
- le titre d'une note de coffre pouvait partir en clair.
3043

3144
Pour penseurs, thérapeutes, étudiants, chercheurs, écrivains et
3245
journalistes qui veulent prendre des notes sensibles ou denses sans
@@ -169,12 +182,15 @@ la procédure de signalement de faille.
169182

170183
## Installation
171184

172-
Ce dépôt **n'a pas de pipeline de release CI automatique**. Deux options :
185+
Deux options :
173186

174-
1. **Build local** (recommandé pour audit) — voir section suivante.
175-
2. **APK release manuelle** : récupérer le dernier `.apk` publié sur
176-
[GitHub Releases](https://github.com/gitubpatrice/notes_tech/releases)
177-
(v1.0.0), vérifier la signature, side-loader.
187+
1. **APK publiée** : récupérer le split correspondant à votre appareil
188+
sur [GitHub Releases](https://github.com/gitubpatrice/notes_tech/releases)
189+
`arm64-v8a` couvre la quasi-totalité des téléphones depuis 2016 —
190+
vérifier le SHA-256 publié dans les notes de release, side-loader.
191+
Ces APK sont construites et signées par GitHub Actions
192+
(`.github/workflows/release.yml`), déclenchées au push d'un tag `v*`.
193+
2. **Build local** (recommandé pour audit) — voir section suivante.
178194

179195
Pas de Play Store : distribution side-load uniquement (cohérent avec la
180196
promesse de confidentialité — aucun compte requis pour installer).
@@ -203,7 +219,7 @@ keyPassword=...
203219

204220
APK release arm64 : **~27 Mo** (SQLCipher + Whisper.cpp — le modèle de
205221
dictée est téléchargé séparément, non bundlé). L'IA embarquée a été retirée
206-
en v1.1.7 : elle pesait 100 Mo pour une fonctionnalité que presque personne
222+
en v2.0.0 : elle pesait 100 Mo pour une fonctionnalité que presque personne
207223
ne pouvait atteindre sans permission Internet.
208224

209225
Pré-requis :

SECURITY.md

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,58 @@
11
# Security policy — Notes Tech
22

3-
> **⚠️ État au 2026-08-07 — retrait de l'IA embarquée (v1.1.7).** Notes Tech
3+
> **⚠️ État au 2026-08-07 — retrait de l'IA embarquée (v2.0.0).** Notes Tech
44
> n'embarque plus ni moteur d'inférence Gemma, ni recherche sémantique
55
> (MiniLM / ONNX). Les entrées d'historique ci-dessous qui les mentionnent
66
> décrivent des correctifs **réellement appliqués à l'époque** : elles sont
77
> conservées telles quelles, réécrire un journal de sécurité serait pire que
88
> de le laisser dater. Seules les affirmations d'état courant ont été mises
99
> à jour.
1010
11-
**Version current : v1.1.6 — Juillet 2026.**
11+
**Version current : v2.0.0 — Août 2026.**
12+
13+
## v2.0.0 — Retrait de l'IA + durcissement coffre/panique (2026-08-07)
14+
15+
Retrait de la recherche sémantique (MiniLM/ONNX) et du Q&A Gemma. Surface
16+
d'attaque réduite d'autant : plus d'isolate d'inférence, plus de prompt
17+
injecté, plus de cache d'embeddings en clair à protéger. APK arm64
18+
~127 Mo → 26,9 Mo.
19+
20+
### Failles corrigées
21+
22+
- **Perte de données irréversible à la suppression d'un dossier coffre.**
23+
`folders_drawer.dart` détruisait la clé Keystore PIN **avant** la ligne
24+
en base. Si la suppression DB échouait ensuite, le dossier et ses notes
25+
chiffrées restaient présents alors que la clé nécessaire au
26+
déverrouillage avait disparu — coffre définitivement illisible. L'ordre
27+
est inversé : base d'abord, clé ensuite, sous `try/catch`.
28+
- **Le mode panique mentait sur son résultat.** Trois étapes
29+
(`_prefsClearWithWhitelist`, `_wipeExportsCache`, `_purgeTempDirectory`)
30+
avalaient leurs échecs unitaires et l'écran final affichait « effacement
31+
terminé » alors que des artefacts survivaient. Elles comptent désormais
32+
leurs échecs et lèvent ; `_wipeExportsCache` purge en outre le répertoire
33+
de cache en plus du temporaire. Le filtre `_estArtefactSensible` évite
34+
l'écueil inverse — un fichier temporaire étranger à l'app ne doit pas
35+
faire déclarer la panique incomplète.
36+
- **Titre d'une note de coffre écrit en clair.** Le scellement était porté
37+
par l'appelant et non par la couche de persistance : tout chemin
38+
d'écriture qui l'oubliait laissait le titre lisible dans la colonne.
39+
`NotesRepository` refuse maintenant toute écriture en clair dans un
40+
dossier coffre (`VaultPlaintextWriteException`) et scelle lui-même.
41+
- **Presse-papiers non purgé après copies successives.** La minuterie
42+
d'effacement d'une copie pouvait remettre l'état à zéro alors qu'une
43+
copie plus récente était en cours, laissant son contenu indéfiniment
44+
dans le presse-papiers. Un jeton par copie ferme la course.
45+
- **Les migrations de schéma n'avaient jamais été exercées.** Les tests
46+
créaient des bases neuves : `onCreate` posait le schéma courant et
47+
`onUpgrade` n'était jamais appelé. `integration_test/db_migration_test.dart`
48+
construit désormais de vraies bases héritées (v1, v5, v7) et vérifie la
49+
migration réelle jusqu'en v9, dont la purge FTS d'une note verrouillée.
50+
51+
### Vérification
52+
53+
CI GitHub Actions verte de bout en bout pour la première fois : analyse,
54+
65 tests unitaires, build, et les 5 suites d'intégration sur émulateur
55+
API 30. Scan OSV des dépendances : aucune CVE.
1256

1357
## v1.1.6 — Logo & réorganisation barre du haut (2026-07-09)
1458

@@ -262,7 +306,7 @@ Notes Tech v1.0 introduit plusieurs durcissements sécurité :
262306
rendu de markdown distant.
263307
- `ProGuard` rules complètes : `files_tech_voice`, `flutter_markdown`,
264308
sqflite. Les règles MediaPipe / ONNX / flutter_gemma sont devenues
265-
sans objet avec le retrait de l'IA embarquée (v1.1.7).
309+
sans objet avec le retrait de l'IA embarquée (v2.0.0).
266310

267311
## Reporting a vulnerability
268312

docs/CAHIER_DES_CHARGES.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ qu'elle existe, et il faut le savoir avant de le lire.*
2121
Les deux fonctions présentées ici comme « le cœur du produit » — la recherche
2222
sémantique par embeddings MiniLM (§1) et le Q&A Gemma 3 1B (§2) — ont bien été
2323
livrées, en v0.2 et v0.3 conformément à la feuille de route. Elles ont été
24-
**retirées en v1.1.7**.
24+
**retirées en v2.0.0**.
2525

2626
La raison est mesurable : elles pesaient **100 Mo sur les 127 Mo de l'APK**,
2727
soit près de 80 % du poids livré à *tous* les utilisateurs, pour une

lib/core/constants.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ class AppConstants {
2424
// (compteur tentatives PIN, auto-wipe à 5).
2525
// v6 (1.0.3) : F2 — triggers FTS5 réécrits pour ne plus indexer
2626
// `title`/`tags` sur notes verrouillées (`encrypted_content IS NOT NULL`).
27-
// v7 (1.1.7) : `notes.enc_v` — version du format de `encrypted_content`
27+
// v7 (2.0.0) : `notes.enc_v` — version du format de `encrypted_content`
2828
// (1 = contenu seul, 2 = titre + contenu).
29-
// v8 (1.1.7) : DROP `note_embeddings` — retrait de la recherche
29+
// v8 (2.0.0) : DROP `note_embeddings` — retrait de la recherche
3030
// sémantique. Ces vecteurs étaient dérivés du texte EN CLAIR des notes.
3131
static const int dbVersion = 9;
3232

@@ -145,7 +145,7 @@ class AppConstants {
145145
/// d'une éventuelle DB en clair vers une DB chiffrée par la KEK du vault.
146146
static const String prefKeyDbEncryptedV1 = 'db_encrypted_v1';
147147

148-
/// Purge unique des modèles orphelins laissés par l'IA embarquée (v1.1.7).
148+
/// Purge unique des modèles orphelins laissés par l'IA embarquée (v2.0.0).
149149
/// Voir `_purgeOrphanModelsOnce` dans `main.dart`.
150150
static const String prefKeyOrphanModelsPurged = 'orphan_models_purged_v1';
151151

lib/data/db/database.dart

0 Bytes
Binary file not shown.

lib/data/models/note.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ class Note {
5656
/// Il n'existe plus d'autre dérivé du texte en clair à purger. La
5757
/// recherche sémantique en produisait un — un vecteur calculé sur le
5858
/// contenu déchiffré, qui survivait à la mise au coffre s'il n'était pas
59-
/// supprimé explicitement. Elle a été retirée en v1.1.7, et la migration
59+
/// supprimé explicitement. Elle a été retirée en v2.0.0, et la migration
6060
/// de schéma v8 a supprimé la table qui les stockait.
6161
///
6262
/// Le déverrouillage en RAM produit un `Note` éphémère avec `content`

lib/main.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ Future<void> main() async {
5252
// a été tué pendant un share sheet précédent). Best-effort, fire-and-forget.
5353
unawaited(_purgeExportsCache());
5454

55-
// v1.1.7 — récupère l'espace laissé par l'IA retirée. Une seule fois.
55+
// v2.0.0 — récupère l'espace laissé par l'IA retirée. Une seule fois.
5656
unawaited(_purgeOrphanModelsOnce());
5757

5858
// VaultService injecté avant tout accès DB : `AppDatabase` réutilisera
@@ -196,7 +196,7 @@ Future<void> main() async {
196196
}
197197

198198
/// Supprime, UNE SEULE FOIS, les modèles devenus orphelins avec le retrait
199-
/// de l'IA embarquée (v1.1.7).
199+
/// de l'IA embarquée (v2.0.0).
200200
///
201201
/// Un utilisateur qui avait importé Gemma garde sinon **jusqu'à 530 Mo** dans
202202
/// le stockage privé de l'application : un fichier que plus aucun code ne lit,

lib/services/backlinks_service.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ class BacklinksService {
5959
/// les frappes utilisateur pour que les backlinks remontent vite dans le
6060
/// panneau latéral. Cette valeur était volontairement plus courte que le
6161
/// debounce de 3 s de l'indexeur sémantique, qui espaçait des passes CPU
62-
/// coûteuses ; cet indexeur a disparu en v1.1.7.
62+
/// coûteuses ; cet indexeur a disparu en v2.0.0.
6363
///
6464
/// `BacklinksService` est le seul SERVICE abonné à `NotesRepository.changes`
6565
/// — mais pas le seul abonné : `HomeScreen` et `NoteEditorScreen` y

lib/services/legacy_model_files.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
///
33
/// Ce dossier contenait le `.task` Gemma importé à la main par l'utilisateur
44
/// et le cache MiniLM. Plus aucun code ne l'alimente depuis le retrait de l'IA
5-
/// en v1.1.7, mais un utilisateur qui met à jour depuis une version ≤ 1.1.6 en
5+
/// en v2.0.0, mais un utilisateur qui met à jour depuis une version ≤ 1.1.6 en
66
/// a toujours le contenu : **jusqu'à 530 Mo** qu'il ne voit pas, qu'aucun
77
/// écran ne mentionne, et qu'il ne peut effacer qu'en vidant les données de
88
/// l'application — ce qui détruirait aussi ses notes.

lib/services/security/panic_service.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ enum PanicStep {
109109
/// Purge `<appSupport>/models/` — le dossier où vivaient le modèle Gemma
110110
/// importé par l'utilisateur et le cache MiniLM.
111111
///
112-
/// Renommée depuis `embedderWipe` en v1.1.7 : elle portait le nom d'un
112+
/// Renommée depuis `embedderWipe` en v2.0.0 : elle portait le nom d'un
113113
/// composant supprimé, alors que son travail réel — effacer des fichiers
114114
/// hérités — lui a survécu.
115115
///

0 commit comments

Comments
 (0)