v0.2.5-pre.010.fix.001

This commit is contained in:
2026-08-20 11:17:12 +02:00
parent 5bf9651038
commit c0b131bf6f
97 changed files with 2277 additions and 655 deletions

View File

@@ -1,5 +1,5 @@
<!-- file: docs/formats/KSPWALLET_V1.md -->
<!-- version: 9 -->
<!-- version: 10 -->
# `.kspwallet` V1 — spécification du format natif Wallet KSP
@@ -1029,7 +1029,9 @@ Cette sonde n'est pas une dépendance KSP et n'est pas requise au runtime ; elle
Le profil de création `64 MiB / 3 / 1` est cohérent avec la seconde recommandation Argon2id de RFC 9106 pour les environnements contraints. Les paramètres restent sérialisés par slot afin que les futurs defaults puissent évoluer sans rendre les wallets existants illisibles. XChaCha20-Poly1305 conserve une clé 256 bits et un nonce 192 bits généré par le CSPRNG OS. Les signatures d'état utilisent Ed25519 au format 64 octets défini par RFC 8032.
Le graphe Cargo final observé au gate `pre.009` conserve une seule génération `ed25519-dalek 2.2.0`, une seule `solana-address 2.7.0` et un unique parent KSP direct de `solana-keypair 3.1.2` : `ksp-wallet-lib`. Les doublons `digest 0.10/0.11`, `crypto-common 0.1/0.2`, `block-buffer 0.10/0.12`, `cpufeatures 0.2/0.3`, `getrandom 0.3/0.4`, `rand 0.9/0.10`, `rand_core 0.6/0.9/0.10`, `sha2 0.10/0.11` et `syn 2/3` sont transitoires et imposés par les générations actuellement consommées par RustCrypto, Solana et Logging ; KSP n'ajoute pas une deuxième dépendance directe pour les contourner.
Le graphe Cargo observé au gate historique `pre.009` conservait une seule génération `ed25519-dalek 2.2.0`. `pre.010-fix.001` met à niveau la dépendance directe KSP vers `ed25519-dalek 3.0.0`; `solana-keypair 3.1.2` restant sur Dalek `2.x`, le graphe post-fix doit donc contenir **deux générations Dalek intentionnelles** (`3.0.0` direct KSP et `2.2.0` transitive Solana), tout en conservant une seule `solana-address 2.7.0` et un unique parent KSP direct de `solana-keypair` : `ksp-wallet-lib`. Les doublons `digest 0.10/0.11`, `crypto-common 0.1/0.2`, `block-buffer 0.10/0.12`, `cpufeatures 0.2/0.3`, `getrandom 0.3/0.4`, `rand 0.9/0.10`, `rand_core 0.6/0.9/0.10`, `sha2 0.10/0.11` et `syn 2/3` restent des conséquences transitives des générations RustCrypto/Solana/Logging.
Cette évolution de dépendance d'implémentation **ne modifie aucun octet du format V1**, aucun domaine de transcript/AAD, aucune taille de clé/signature ni aucun algorithme sérialisé : Ed25519 reste Ed25519 et les fixtures/vecteurs V1 restent les contrats d'interopérabilité.
Limites explicitement conservées en V1 :

View File

@@ -1,5 +1,5 @@
<!-- file: docs/plans/012-V0_2_5_WALLET_FOUNDATION_PLAN.md -->
<!-- version: 13 -->
<!-- version: 14 -->
# Plan `0.2.5` — Wallet foundation
@@ -363,7 +363,7 @@ Il faut distinguer :
**keypair Solana** : immuable dans V1 après création/import. Aucun `replace_keypair` n'est exposé. Toute tentative de modifier `secret` ou la Pubkey metadata sans une réécriture OWNER valide échoue sur la `state_signature`; même avec OWNER, l'import d'une autre keypair crée un nouveau `.kspwallet` au lieu de muter l'identité cryptographique existante.
## 8. Primitives et dépendances réauditées jusquau 2026-08-19
## 8. Primitives et dépendances réauditées jusquau 2026-08-20
Aucune dépendance ci-dessous n'est ajoutée dans `pre.001`. Ce sont les candidates pour les tranches qui les consommeront réellement.
@@ -380,7 +380,7 @@ Aucune dépendance ci-dessous n'est ajoutée dans `pre.001`. Ce sont les candida
La génération SDK récente définit `Pubkey` comme alias du type `Address`, mais l'écosystème a déjà connu des incompatibilités lorsque plusieurs générations de `solana-address` coexistent. `pre.002` verrouille donc la surface publique Wallet sur **`ksp_core_lib::Pubkey` exclusivement** et n'ajoute aucune dépendance directe `solana-pubkey`. `pre.005` introduit réellement `solana-keypair 3.1.2` uniquement pour posséder/valider la keypair Ed25519 ; la Pubkey Wallet reste construite via `ksp_core_lib::Pubkey` depuis les 32 octets publics du keypair, sans exposer un second type d'adresse KSP.
Un `cargo tree` est obligatoire avec `pre.005` afin de confirmer l'unification de `solana-address`, `ed25519-dalek`, `rand/getrandom` et d'éviter des duplications crypto injustifiées.
Un `cargo tree` est obligatoire avec `pre.005` puis à chaque changement de génération crypto afin de distinguer les convergences réellement possibles des doublons imposés par upstream. Le gate `pre.009` observait encore une génération unique `ed25519-dalek 2.2.0`; `pre.010-fix.001` réouvre explicitement cet audit après passage du Dalek direct KSP à `3.0.0`.
Audit source notable : `solana-keypair 3.1.2` contient un bloc `unsafe` interne dans sa conversion Base58 vers `String`. Cela ne modifie pas la règle `#![forbid(unsafe_code)]` du code KSP. `pre.008` conserve finalement le codec maintenu par `solana-keypair` au lieu d'ajouter un second codec `bs58` direct ; `pre.009` classe donc cet `unsafe` comme implémentation upstream auditée, sans `unsafe` KSP et sans duplication de codec.
@@ -415,7 +415,9 @@ AES-GCM-SIV apporte une meilleure tolérance à la réutilisation accidentelle d
`zeroize 1.9.0` est retenu et devient la seule nouvelle dépendance tierce de `pre.002`, car les wrappers `ViewPassword` / `OwnerPassword` lutilisent immédiatement pour leur nettoyage au `Drop`. `secrecy` n'est pas ajouté tant qu'un besoin ergonomique concret n'est pas démontré ; des types KSP simples imposent eux-mêmes redaction/non-Clone et utilisent `zeroize`.
`pre.005` introduit directement **`ed25519-dalek ^2.2`** avec `default-features = false` et les features `signature` + `zeroize`. La génération `3.0.0`, bien que plus récente, n'est volontairement pas ajoutée : `solana-keypair 3.1.2` dépend de `ed25519-dalek ^2.1.1`, donc la branche directe `2.2` permet à Cargo d'unifier une seule génération Dalek et d'activer `zeroize` sur la `SigningKey` utilisée à la fois par l'autorité de format KSP et par le wrapper Solana. Une duplication `2.x + 3.x` n'apporterait aucune capacité nécessaire à V1.
`pre.005` avait initialement introduit `ed25519-dalek ^2.2` afin de converger avec `solana-keypair 3.1.2`. Cette décision est **supersédée par `pre.010-fix.001`** : `ed25519-dalek 3.0.0` est stable depuis le 2026-07-06, utilise Rust 2024 et apporte la génération courante de l'API Dalek. KSP passe donc sa dépendance directe à **`ed25519-dalek ^3.0`**, conserve `default-features = false` et active localement uniquement `signature` + `zeroize`.
`solana-keypair 3.1.2` reste toutefois sur sa branche Dalek `2.x`. Le tree post-fix doit donc montrer **deux générations Dalek intentionnelles** : `3.0.0` directement pour KSP et `2.2.0` transitivement via `solana-keypair`. Cette duplication est désormais acceptée parce qu'elle est imposée par les contraintes upstream ; KSP ne rétrograde pas sa dépendance directe uniquement pour obtenir une unicité artificielle. Le wire `.kspwallet` V1 et les primitives Ed25519 restent inchangés.
### 8.6 État des audits de sécurité publics
@@ -1135,7 +1137,8 @@ pre.007 signature Solana + alias/notes + rotations passwords + disable/recreate
pre.008 import/export adapters + Solana CLI JSON + generic keypair Base58 + inspect
pre.009 audit security/interoperability/compliance + adversarial vectors/tests + cargo trees acquis
pre.010 spec finale + README/USAGE + graphes/docs + candidate de clôture + prompt 0.2.6 acquis
rel.001 publication strictement publicationnelle prochaine
pre.010-fix.001 Dalek direct ^3.0 + normalisation Rust workspace + audit structurel + prompt 0.2.6 renforcé en validation
rel.001 publication strictement publicationnelle après validation du fix
```
Une `fix` ou tranche supplémentaire est préférable à la suppression d'une garantie sécurité si un des gates révèle une incompatibilité.
@@ -1150,17 +1153,20 @@ pre.003 base64 ^0.23
pre.004 argon2 ^0.5
chacha20poly1305 ^0.11
getrandom ^0.4
pre.005 ed25519-dalek ^2.2
pre.005 ed25519-dalek ^2.2 à l'origine
solana-keypair ^3.1
pre.010-fix.001
ed25519-dalek ^3.0 direct KSP
tokio déjà workspace, feature locale rt pour spawn_blocking
pre.006 tempfile ^3.27
pre.007 aucune nouvelle dépendance tierce
pre.008 aucune nouvelle dépendance tierce
pre.009 aucune nouvelle dépendance tierce
pre.010 aucune nouvelle dépendance tierce (documentation uniquement)
pre.010-fix.001 mise à niveau de la dépendance directe ed25519-dalek ^3.0 ; aucune nouvelle famille de dépendance
```
Toutes les dépendances tierces communes restent centralisées sous `[workspace.dependencies]`; le membre Wallet active uniquement les features nécessaires. `ed25519-dalek ^2.2` est volontairement aligné avec la contrainte `^2.1.1` de `solana-keypair 3.1.2` afin de permettre une seule génération Dalek et d'activer `zeroize` sur la `SigningKey` partagée par résolution Cargo.
Toutes les dépendances tierces communes restent centralisées sous `[workspace.dependencies]`; le membre Wallet active uniquement les features nécessaires. À partir de `pre.010-fix.001`, le direct KSP est `ed25519-dalek ^3.0` avec `signature` + `zeroize`, tandis que `solana-keypair 3.1.2` conserve sa génération Dalek `2.x` transitive. Les deux générations sont auditées séparément et leur coexistence est acceptée tant que Solana n'a pas mig son propre contrat.
Dépendances réauditées mais **non retenues directement** en `0.2.5` :
@@ -1214,7 +1220,7 @@ https://docs.rs/chacha20poly1305/0.11.0/
https://docs.rs/aes-gcm-siv/0.12.0/
https://docs.rs/getrandom/0.4.3/
https://docs.rs/zeroize/1.9.0/
https://docs.rs/ed25519-dalek/2.2.0/
https://docs.rs/ed25519-dalek/3.0.0/
https://docs.rs/base64/0.23.1/
https://docs.rs/tempfile/3.27.0/
```

View File

@@ -1,74 +1,108 @@
<!-- file: docs/rules/PROMPT_STRUCTURE.md -->
<!-- version: 4 -->
<!-- version: 5 -->
# Structure des prompts KSP
## Portée
Ce document définit le contrat normatif des prompts de reprise KSP, leur cycle de vie et les règles de dimensionnement des releases/sessions qu'ils préparent.
Ce document définit le contrat normatif des prompts de reprise KSP, leur cycle de vie et les règles de dimensionnement des releases/sessions qu'ils préparent. Un prompt de démarrage est un **contrat opératoire autonome** : une nouvelle session ne doit pas dépendre d'une mémoire implicite pour retrouver les règles déjà acquises.
## Série, release concrète et session
Une notation de série telle que `0.1.x` regroupe des fonctionnalités apparentées. Elle n'est pas une unité de session et n'a pas à être réalisable en une seule session.
Exemple : `0.1.x` peut regrouper plusieurs releases concrètes comme `0.1.1`, `0.1.2`, `0.1.3`, chacune avec son propre cycle de prereleases et, en principe, sa propre session de travail principale.
Le contrôle de charge s'applique donc d'abord à **la release concrète préparée** et à ses prereleases, pas à toute la série fonctionnelle.
Le contrôle de charge s'applique d'abord à **la release concrète préparée** et à ses prereleases. Une release concrète doit être planifiée pour être ouverte et clôturée dans une seule session de chat ; si cette clôture paraît incertaine, elle est scindée avant l'implémentation lourde.
## Cycle d'une release concrète
Sauf raison explicitement documentée :
- `pre.001` = brainstorming/audit si nécessaire + planification + découpage de la release ;
- `pre.001` = lectures obligatoires + audit interne/externe + brainstorming + sizing + planification ;
- les prereleases intermédiaires = tranches bornées de développement/validation ;
- la dernière prerelease = validation finale + documentation + nettoyage/archivage + préparation du prompt/release suivante.
- la dernière prerelease = validation finale + documentation + nettoyage/archivage + prompt de la release suivante ;
- une `fix` corrige l'étape réellement livrée sans réécrire l'historique.
## Dimensionnement des prereleases
## Dimensionnement
Lors de `pre.001`, une prerelease intermédiaire estimée à plus d'environ **15 à 20 minutes de travail effectif de session** doit être scindée.
Lors de `pre.001`, une prerelease intermédiaire estimée à plus d'environ **15 à 20 minutes de travail effectif** est scindée. Cette durée est un budget de planification, jamais une promesse temporelle.
Cette durée est un budget de planification et non une promesse d'exécution.
La trajectoire initiale est **souple** : elle indique un nombre prévisionnel de prereleases, leur objectif et leur ordre, mais autorise l'insertion de tranches/fixes lorsqu'un audit ou une validation révèle un besoin réel. La fermeture ne doit jamais être forcée pour respecter un numéro prévu.
Si la complexité réelle augmente, la tranche est redécoupée plutôt que surchargée.
## Structure obligatoire d'un prompt de démarrage
## Dimensionnement d'une release/session
Un prompt de nouvelle session contient explicitement, dans un ordre facile à retrouver :
Avant de finaliser le prompt d'une release concrète, vérifier que son plan complet est compatible avec une session de qualité.
1. identité de la release et base exacte requise ;
2. mission et résultat attendu ;
3. **sources de vérité internes obligatoires et ordre de lecture** ;
4. sources externes normatives à réauditer lorsque la fraîcheur importe ;
5. état validé à préserver, y compris règles de dépendances et frontières ;
6. décisions acquises et questions réellement ouvertes ;
7. objectifs/livrables et hors périmètre ;
8. contraintes sécurité/API/architecture spécifiques ;
9. **première mission `pre.001` détaillée et critères de sortie de ce gate** ;
10. **prévision souple initiale des prereleases**, visible et détaillée ;
11. règles de versionnement, deltas, commits et tags ;
12. procédure d'application/validation opérateur ;
13. validations Rust/frontend/Tauri/réseau pertinentes ;
14. critères de clôture de la release ;
15. release/session suivante envisagée ;
16. **instruction d'ouverture** indiquant ce que la prochaine session doit faire en premier et ce qu'elle ne doit pas commencer avant le gate.
Si une release concrète paraît trop lourde, la scinder en plusieurs releases de la même série lorsque les fonctions restent du même groupe, ou changer de série si une frontière fonctionnelle différente le justifie.
## Sources de vérité et reprise
Exemple : si `0.1.1` devient trop large, créer `0.1.2` plutôt que forcer tout `0.1.x` dans une seule session.
- Le prompt ordonne explicitement la lecture de `RULES.md`, `docs/000-README.md`, règles spécialisées, architecture, plan/validation de la release précédente et sources métier pertinentes.
- Lorsqu'une archive/base opérateur est fournie, elle est déclarée autoritaire par rapport aux souvenirs, snippets ou artefacts anciens.
- Le prompt ne recopie pas toutes les règles, mais rappelle les règles qui conditionnent directement la session et exige la lecture des fichiers normatifs.
- Les décisions historiques ne sont pas réinventées lors de la nouvelle session ; une divergence avec la base réelle déclenche un audit, pas une supposition.
Une série complète peut naturellement s'étendre sur de nombreuses sessions.
## Force opératoire du `pre.001`
Une **release concrète**, en revanche, doit être planifiée pour être ouverte et clôturée dans une seule session de chat. Une version volontairement laissée ouverte pour être reprise dans une autre session n'est pas un découpage acceptable.
Le prompt doit rendre impossible une interprétation « commencer à coder immédiatement ». La première tranche exige au minimum :
Si `pre.001` révèle qu'une clôture dans la session est incertaine, la release est scindée **avant l'implémentation fonctionnelle lourde**. Cette contrainte s'ajoute au budget de 1520 minutes par prerelease ; elle ne le remplace pas.
```text
lecture des sources internes obligatoires
inventaire de l'état réel de la base
récupération des dépendances/versions actuelles si concernées
comparaison avec les références historiques utiles
brainstorming des risques/frontières
sizing de la release et de chaque tranche
prévision souple recalibrée
liste des validations/gates
```
## Structure recommandée d'un prompt
L'implémentation fonctionnelle lourde commence seulement lorsque ce gate est cohérent. Les corrections triviales nécessaires pour rendre l'audit lui-même exécutable restent autorisées.
1. Identité de la série et de la release concrète visée ;
2. Mission ;
3. Base requise ;
4. État validé à préserver ;
5. Sources de vérité internes ;
6. Sources externes normatives ;
7. Décisions acquises ;
8. Objectifs et livrables ;
9. Hors périmètre ;
10. Méthode de travail ;
11. Versionnement/deltas/commits ;
12. Contraintes techniques spécifiques ;
13. Plan initial souple et prereleases bornées ;
14. Validations attendues ;
15. Critères de sortie ;
16. Préparation de la release/session suivante.
## Validation Rust obligatoire dans les prompts
Toute release susceptible de modifier du Rust rappelle explicitement la séquence KSP :
```bash
cargo fmt --all
python3 scripts/audit_rust_workspace_rules.py
cargo check --workspace
cargo clippy --workspace --all-targets
```
Pendant le développement, les tests ciblés suivent ces contrôles. La fermeture d'une prerelease technique/release inclut `cargo test --workspace` et les `cargo tree` pertinents lorsque le graphe de dépendances a changé ou constitue un gate de la tranche.
Un prompt interdit de déclarer réussie une commande qui n'a pas réellement été exécutée. Il rappelle que `rustfmt` et Clippy ne remplacent pas l'audit structurel KSP.
## Dépendances et fraîcheur
Lorsqu'une tranche ajoute, met à jour ou dépend fortement d'une bibliothèque externe :
- vérifier la version stable réellement courante au début de la tranche ;
- préférer les sources primaires de la crate/projet ;
- vérifier les features réellement nécessaires et les contraintes de versions transitives ;
- documenter les doublons transitifs acceptés plutôt que forcer artificiellement une unification incompatible ;
- ne pas conserver dans un prompt une version historique comme si elle était nécessairement toujours actuelle.
## Règles de rédaction
- Le prompt référence les sources canoniques au lieu de recopier inutilement leur contenu.
- Une règle normative appartient à `docs/rules/`.
- Une décision durable appartient à `docs/architecture/`.
- Une idée non décidée appartient à `docs/IDEAS.md`.
- Un prompt doit signaler les questions ouvertes plutôt que les résoudre arbitrairement.
- Une release concrète manifestement surdimensionnée doit être redécoupée avant ouverture de sa session principale.
- Le prompt doit être autoportant sans devenir une copie intégrale des règles.
- Les titres `Première mission`, `Prévision souple`, `Validation` et `Instruction d'ouverture` doivent être immédiatement repérables.
- Une règle normative appartient à `docs/rules/`, une décision durable à `docs/architecture/`, une idée non décidée à `docs/IDEAS.md`.
- Le prompt signale les questions ouvertes au lieu de les résoudre arbitrairement.
- Une release surdimensionnée est redécoupée avant ouverture de son développement lourd.
- Le prompt conserve les conventions KSP de delta minimal, version de fichiers, Cargo version technique, commits et tags stables.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/rules/RULES_KSP.md -->
<!-- version: 34 -->
<!-- version: 35 -->
# Règles spécifiques à KSP
@@ -252,7 +252,7 @@
- **KSP-REL-006** — Une release ou prerelease trop grosse est scindée plutôt que compressée pour respecter un numéro prévu.
- **KSP-REL-007** — La dernière prerelease d'une release fonctionnelle réalise par défaut validations finales, documentation, nettoyage/archivage, changelog et prompt de la release suivante.
- **KSP-REL-008** — La première release fonctionnelle sélectionnée est `0.1.1`, dédiée à la stabilisation de `ksp-core-lib`.
- **KSP-REL-009** — Après toute modification d'un fichier Rust, la tranche concernée exécute avant livraison au minimum `cargo fmt --all`, `cargo check --workspace` et `cargo clippy --workspace --all-targets`. Une commande non exécutée n'est jamais déclarée réussie.
- **KSP-REL-009** — Après toute modification d'un fichier Rust, la tranche concernée exécute avant livraison au minimum `cargo fmt --all`, `python3 scripts/audit_rust_workspace_rules.py`, `cargo check --workspace` et `cargo clippy --workspace --all-targets`, dans cet ordre. L'audit structurel complète rustfmt/Clippy et ne peut être ignoré parce que la compilation est verte. Une commande non exécutée n'est jamais déclarée réussie.
- **KSP-REL-010** — Pendant le développement courant d'une crate, les tests Rust privilégient la portée ciblée `cargo test -p <crate>` et, si utile, ses tests d'intégration nommés. `cargo test --workspace` est conservé pour l'ouverture ou la fermeture d'une session/version et pour les validations globales explicitement justifiées.
- **KSP-REL-011** — Les validations d'une crate incluent les audits `cargo tree` pertinents pour son graphe réel : arbre normal, doublons et features lorsque ces vues apportent une information utile. Les crates fondamentales/complétées conservent leurs canaries de dépendances.
- **KSP-REL-012** — Toute crate ou composant KSP considéré comme complété possède un `README.md` descriptif durable avant clôture de sa release.

View File

@@ -1,11 +1,11 @@
<!-- file: docs/rules/RULES_RUST.md -->
<!-- version: 5 -->
<!-- version: 6 -->
# Règles Rust générales
## Portée
Les règles `RUST-*` s'appliquent aux crates, sources, tests, exemples et outils Rust de KSP. Elles sont conçues pour rester réutilisables hors de KSP lorsque la règle ne dépend pas de son architecture.
Les règles `RUST-*` s'appliquent à tous les fichiers Rust de KSP : crates, sources, tests, exemples et outils. Elles reprennent les règles déjà éprouvées sur les générations précédentes du projet et les rendent explicites afin que `rustfmt` et Clippy ne soient jamais considérés comme des contrôles structurels suffisants.
## Édition et lints
@@ -13,33 +13,54 @@ Les règles `RUST-*` s'appliquent aux crates, sources, tests, exemples et outils
- **RUST-BASE-002** — Chaque `lib.rs` et `main.rs` contient `#![warn(missing_docs)]`, `#![deny(unreachable_pub)]` et `#![forbid(unsafe_code)]`.
- **RUST-BASE-003** — Les lints communs sont déclarés au niveau workspace et hérités par les crates.
- **RUST-BASE-004** — Le code `unsafe` est interdit.
- **RUST-BASE-005** — Tout fichier Rust possède les en-têtes `// file: ...` et `// version: N`, et se termine par exactement une fin de ligne.
## Documentation des API
## Documentation des API et contrats internes
- **RUST-DOC-001** — Tout élément `pub` ou `pub(crate)` possède une rustdoc utile au point de déclaration.
- **RUST-DOC-002** — Toute réexportation `pub use` ou `pub(crate) use` dans `lib.rs` ou `main.rs` possède également une rustdoc utile.
- **RUST-DOC-003** — La façade d'une crate doit permettre de comprendre son API sans dépendre de ses chemins de modules internes.
- **RUST-DOC-001** — Tout élément `pub` ou `pub(crate)` possède une rustdoc utile au point de déclaration. Cette règle couvre aussi les méthodes associées et les champs nommés visibles à ces niveaux.
- **RUST-DOC-002** — Toute réexportation `pub use` ou `pub(crate) use` dans `lib.rs` ou `main.rs` possède sa propre rustdoc utile et adjacente.
- **RUST-DOC-003** — La façade d'une crate doit permettre de comprendre son API publique et ses contrats crate-wide sans dépendre de chemins de modules internes.
- **RUST-DOC-004** — Les rustdocs et commentaires du code sont en anglais ; la documentation Markdown KSP reste en français sauf document explicitement destiné à une audience différente.
## Imports et chemins
- **RUST-IMPORT-001** — `use` est interdit pour les constantes, fonctions, structures, énumérations, unions, alias de types, modules et macros.
- **RUST-IMPORT-002** — `use` est autorisé uniquement pour un trait lorsque la résolution de méthode, une macro de dérivation ou une contrainte du langage l'exige réellement.
- **RUST-IMPORT-003** — Un import de trait reste étroit et ne mélange pas de non-traits dans un import groupé.
- **RUST-IMPORT-002** — `use` est autorisé uniquement pour un trait lorsqu'une résolution de méthode, une dérivation ou une contrainte du langage l'exige réellement. Le motif est explicité sur la ligne par `rust-rules: trait-import`.
- **RUST-IMPORT-003** — Les imports de traits restent étroits ; un import de trait ne mélange jamais d'éléments non-traits.
- **RUST-IMPORT-004** — Les glob imports et imports groupés par accolades sont interdits.
- **RUST-IMPORT-005** — Pour un élément externe, utiliser directement le chemin public le plus court fourni par la crate propriétaire.
- **RUST-IMPORT-006** — Pour un élément `pub` d'une crate KSP, l'API est réexportée au crate-root et consommée depuis une autre crate via `owner_crate::Item`.
- **RUST-IMPORT-007** — Dans sa propre crate, un élément `pub` ou `pub(crate)` partagé est consommé via `crate::Item` après réexport approprié.
- **RUST-IMPORT-008** — Un helper strictement privé au module reste privé et est appelé localement ; dans un sous-module de tests, un élément privé du module parent est appelé via `super::Item`.
- **RUST-IMPORT-009** — Les réexports ne sont pas groupés par accolades et les alias `as` sont interdits dans les réexports.
- **RUST-IMPORT-010** — Un réexport d'un module interne commence par `self::`.
- **RUST-IMPORT-005** — Les alias `as` sont interdits dans tous les `use`, réexports et déclarations `extern crate`. Le symbole reçoit son nom canonique dans son module propriétaire.
- **RUST-IMPORT-006** — Les déclarations `use` sont au niveau du module, dans le bloc d'en-tête avant les déclarations métier. Aucun `use` n'est introduit dans une fonction, méthode, bloc, test ou branche conditionnelle.
- **RUST-IMPORT-007** — Pour un élément fourni par une crate externe, utiliser directement le chemin public le plus court exposé par cette crate ; ne pas créer un import non-trait pour raccourcir ce chemin.
- **RUST-IMPORT-008** — Pour un élément `pub` d'une crate KSP, la crate propriétaire le réexporte au crate-root. Une autre crate l'appelle via `owner_crate::Item`.
- **RUST-IMPORT-009** — Dans sa propre crate, un élément `pub` ou `pub(crate)` partagé est appelé via `crate::Item`, y compris depuis son module de déclaration lorsque le contrat est crate-wide.
- **RUST-IMPORT-010** — Un chemin `crate::module::Item` est interdit pour un élément partagé `pub`/`pub(crate)` qui peut être consommé via le crate-root. Le chemin du module interne n'est pas une façade.
- **RUST-IMPORT-011** — Un élément strictement privé à un module n'est pas réexporté et est appelé par son nom local dans ce module.
- **RUST-IMPORT-012** — Dans un sous-module de tests, `super::Item` est réservé à un élément strictement privé du module parent. Un élément `pub` ou `pub(crate)` continue d'être appelé via `crate::Item`.
- **RUST-IMPORT-013** — Les réexports internes commencent par `self::`. Un réexport d'une crate externe peut utiliser directement le chemin externe canonique.
- **RUST-IMPORT-014** — Un export correspond à une ligne de réexport distincte ; les accolades ne servent jamais à regrouper une façade.
- **RUST-IMPORT-015** — Une crate externe rendue publique uniquement pour l'hygiène d'une macro exportée conserve son nom canonique, porte `#[doc(hidden)]` et ne devient pas une API de consommation. `ksp-logging-lib::tracing` est ce bridge technique pour les macros Logging ; les autres crates KSP n'y accèdent jamais directement.
## Visibilité et façade de crate
- **RUST-API-001** — Aucun `pub mod` n'est autorisé ; les modules restent privés et l'API externe est constituée par des réexports explicites au crate-root.
- **RUST-API-001** — Aucun `pub mod` n'est autorisé ; les modules restent privés et l'API externe est constituée exclusivement par des réexports explicites au crate-root.
- **RUST-API-002** — `pub(in ...)` et `pub(super)` sont interdits.
- **RUST-API-003** — Un élément `pub` inaccessible depuis la façade de sa crate est une erreur de conception.
- **RUST-API-004** — Un élément `pub(crate)` utilisé hors de son module est réexporté au crate-root via `pub(crate) use`.
- **RUST-API-005** — Les chemins internes de modules ne constituent pas une API stable.
- **RUST-API-004** — Un élément `pub(crate)` consommé hors de son module est réexporté au crate-root via `pub(crate) use` puis appelé via `crate::Item`.
- **RUST-API-005** — Les chemins internes de modules ne constituent jamais une API stable.
- **RUST-API-006** — Si deux éléments crate-wide auraient le même nom au crate-root, ils sont renommés dans leurs modules propriétaires avec des noms canoniques non ambigus ; un alias de réexport n'est pas utilisé pour masquer la collision.
## Formatage, blocs et ordre
- **RUST-FMT-001** — `rustfmt.toml` à la racine est la configuration canonique du formatage Rust.
- **RUST-FMT-002** — `cargo fmt --all` est exécuté après chaque modification Rust avant l'audit structurel et les validations Cargo.
- **RUST-FMT-003** — Aucune ligne vide n'est conservée à l'intérieur du corps d'une fonction ou méthode, ni à l'intérieur d'une définition `struct` ou `enum`.
- **RUST-FMT-004** — Les lignes vides séparent les fonctions/méthodes, types, blocs `impl` et grandes sections logiques ; elles ne fragmentent pas un bloc homogène de déclarations.
- **RUST-FMT-005** — Les blocs homogènes sont ordonnés alphabétiquement par nom lorsque l'ordre n'a pas de signification sémantique.
- **RUST-FMT-006** — Les constantes de module forment des blocs sans ligne vide interne, ordonnés par visibilité `pub`, puis `pub(crate)`, puis privée, et alphabétiquement dans chaque niveau.
- **RUST-FMT-007** — Dans une façade, le bloc `pub use` précède le bloc `pub(crate) use`; une seule ligne vide sépare les deux blocs, aucune ligne vide n'existe à l'intérieur d'un bloc, et les symboles sont ordonnés alphabétiquement.
- **RUST-FMT-008** — Les déclarations `mod` d'un même bloc sont ordonnées alphabétiquement ; les modules de tests conditionnels restent après les modules de production.
- **RUST-FMT-009** — Lorsqu'un `struct` et ses blocs `impl` forment une unité locale sans contrainte de séparation, l'implémentation suit la structure. Les éléments visibles précèdent les helpers privés lorsqu'aucun ordre métier ou protocolaire n'impose l'inverse.
- **RUST-FMT-010** — L'ordre alphabétique n'écrase jamais un ordre contractuel ou sémantique : wire fields, comptes Solana, étapes de protocole, priorités, transitions d'état, tableaux de dispatch et séquences explicitement normatives conservent leur ordre défini.
## Contrôle de flux et erreurs
@@ -49,15 +70,7 @@ Les règles `RUST-*` s'appliquent aux crates, sources, tests, exemples et outils
- **RUST-ERR-004** — `anyhow` et `thiserror` ne sont pas utilisés par défaut ; leur introduction exige une justification architecturale.
- **RUST-ERR-005** — Les erreurs publiques sont typées lorsque leur contrat est stable.
- **RUST-ERR-006** — Les tests peuvent utiliser `unwrap` ou `expect` uniquement dans la limite explicitement autorisée par la configuration Clippy.
- **RUST-ERR-007** — Avant dattacher une erreur externe comme `source` de `ksp_core_lib::Error`, la crate propriétaire vérifie que sa chaîne `Debug`/`source` ne peut pas exposer de secret ou de donnée sensible. Lorsquune dépendance fournit une primitive de neutralisation, elle est appliquée avant `with_source`; en particulier une `reqwest::Error` issue dune requête vers un endpoint potentiellement credential-bearing est attachée uniquement après `without_url()`.
## Formatage
- **RUST-FMT-001** — `rustfmt.toml` à la racine est la configuration canonique du formatage Rust.
- **RUST-FMT-002** — `cargo fmt --all` est exécuté après chaque modification Rust avant les validations de compilation et de test.
- **RUST-FMT-003** — Les fichiers Rust ne contiennent pas de lignes vides à l'intérieur d'une fonction, structure, énumération ou implémentation courte.
- **RUST-FMT-004** — Les lignes vides séparent uniquement des fonctions, types, blocs `impl` ou sections logiques distinctes.
- **RUST-FMT-005** — Les groupes homogènes de `pub use` ou `pub(crate) use` ne contiennent pas de ligne vide interne ; `pub use` précède `pub(crate) use` lorsqu'ils coexistent.
- **RUST-ERR-007** — Avant d'attacher une erreur externe comme `source` de `ksp_core_lib::Error`, la crate propriétaire vérifie que sa chaîne `Debug`/`source` ne peut pas exposer de secret. Lorsqu'une dépendance fournit une primitive de neutralisation, elle est appliquée avant `with_source`.
## Helpers et duplication
@@ -71,31 +84,40 @@ Les règles `RUST-*` s'appliquent aux crates, sources, tests, exemples et outils
- **RUST-DEP-002** — Une dépendance uniquement utilisée par les tests reste dans `[dev-dependencies]`.
- **RUST-DEP-003** — Les features sont minimales et explicites.
- **RUST-DEP-004** — Les lockfiles de dépendances ne sont pas versionnés dans KSP.
- **RUST-DEP-005** — KSP privilégie les versions récentes compatibles. Toute version volontairement contrainte ou ancienne doit être documentée avec sa raison et la condition permettant de lever la contrainte.
- **RUST-DEP-005** — KSP privilégie les versions récentes compatibles. Toute version volontairement contrainte ou ancienne est documentée avec sa raison et la condition permettant de lever la contrainte.
## Assertions de collections
## Assertions et organisation des tests
- **RUST-TEST-001** — Un test vérifiant uniquement l'appartenance à un ensemble peut trier les valeurs obtenues et attendues avant `assert_eq!` lorsque l'ordre n'est pas contractuel.
- **RUST-TEST-002** — Une collection n'est jamais triée artificiellement dans un test lorsque l'ordre fait partie du contrat, notamment pour comptes Solana, metas, instructions, signers, événements, étapes de pipeline, priorités ou journaux ordonnés.
- **RUST-TEST-002** — Une collection n'est jamais triée artificiellement lorsque l'ordre fait partie du contrat, notamment pour comptes Solana, metas, instructions, signers, événements, étapes de pipeline, priorités ou journaux ordonnés.
- **RUST-TEST-003** — Les tests unitaires sont placés autant que possible dans `unit_tests/` et reflètent l'arborescence de `src/`.
- **RUST-TEST-004** — Un fichier `unit_tests/...` est rattaché explicitement au module de production via `#[cfg(test)]` et `#[path = ...]`; il peut tester les éléments privés de ce module.
- **RUST-TEST-005** — `tests/` est réservé aux vrais tests d'intégration consommant uniquement l'API publique de la crate.
- **RUST-TEST-006** — Toute partie pertinente de l'API publique est couverte, lorsque possible, par un test d'intégration afin de valider les réexports et la visibilité réellement consommables.
- **RUST-TEST-007** — La colocalisation d'un test unitaire dans le fichier de production reste une exception justifiée.
## Organisation des tests
## Audit structurel automatisé
- **RUST-TEST-003** — Les sources de tests unitaires sont placées autant que possible dans un répertoire `unit_tests/` à la racine de la crate et reflètent autant que possible l'arborescence et les noms des modules sous `src/`.
- **RUST-TEST-004** — Un fichier sous `unit_tests/` reste un vrai test unitaire : il est rattaché explicitement sous `#[cfg(test)]` au module de production qu'il teste et peut donc tester ses éléments privés.
- **RUST-TEST-005** — Le répertoire Cargo standard `tests/` est réservé aux tests d'intégration. Les fichiers qui y sont découverts comme cibles d'intégration testent la crate comme un consommateur externe et n'utilisent que son API publique.
- **RUST-TEST-006** — Toute partie pertinente de l'API publique d'une bibliothèque KSP doit, lorsque cela est techniquement possible, être couverte par de vrais tests d'intégration sous `tests/`, afin de valider notamment les réexports, la visibilité et le contrat réellement consommable depuis une autre crate.
- **RUST-TEST-007** — La séparation physique sous `unit_tests/` est la convention préférée et doit être utilisée au maximum. La colocalisation d'un test unitaire dans le fichier/module de production n'est autorisée qu'en dernier recours lorsqu'un rattachement externe serait techniquement impossible, incorrect ou créerait une complexité disproportionnée clairement justifiable.
- **RUST-TEST-008** — Un test unitaire séparé suit autant que possible le même chemin relatif et le même nom que le module testé, afin que la correspondance `src/...``unit_tests/...` soit immédiatement identifiable.
- **RUST-AUDIT-001** — `scripts/audit_rust_workspace_rules.py` est le point d'entrée obligatoire de l'audit Rust KSP. Il exécute les audits généraux, la complétude des réexports/chemins et les frontières KSP sans fusionner leurs responsabilités.
- **RUST-AUDIT-002** — L'audit est dependency-free côté Python standard et échoue avec un code non nul dès qu'une violation mécanique est détectée.
- **RUST-AUDIT-003** — L'audit contrôle au minimum : headers/version/newline, lints de crate-root, visibilité interdite, `use`/aliases/groupes/globs/scope, rustdocs visibles, ordre des imports/réexports/constantes, lignes vides dans fonctions/structs/enums, complétude des réexports crate-root, chemins `crate::module::Item`, usage de `super::` dans les tests séparés et frontières KSP directement vérifiables.
- **RUST-AUDIT-004** — Les règles contextuelles qui ne peuvent pas être prouvées sans interpréter la sémantique restent des critères de revue humaine ; le script ne doit pas produire de faux sentiment de complétude.
## Contrôle de clôture Rust
## Contrôle avant livraison
Lorsqu'une tranche contient du Rust, les contrôles minimaux sont :
Après toute modification Rust, la séquence minimale est :
```bash
cargo fmt --all
python3 scripts/audit_rust_workspace_rules.py
cargo check --workspace
cargo test --workspace
cargo clippy --workspace --all-targets
```
Les audits structurels automatisés seront ajoutés lorsqu'ils existeront dans KSP ; une règle ne doit pas prétendre qu'un script inexistant a été exécuté.
Pendant le développement, des tests ciblés suivent ce gate. À la fermeture d'une prerelease technique/release, exécuter également :
```bash
cargo test --workspace
```
Une commande non exécutée n'est jamais déclarée réussie. `rustfmt`, `cargo check` et Clippy ne remplacent pas l'audit structurel KSP.

View File

@@ -1,11 +1,11 @@
<!-- file: docs/validation/008-V0_2_5_WALLET_SECURITY_COMPLIANCE.md -->
<!-- version: 3 -->
<!-- version: 4 -->
# Validation `0.2.5` — Wallet security / interoperability / compliance
## 1. Objet
Cette matrice constitue la validation durable de clôture de `0.2.5`. `pre.009` ferme le gate technique security/interoperability/compliance et `pre.010` y ajoute les preuves opérateur et le gate documentaire final. Elle ne remplace ni la spécification [`../formats/KSPWALLET_V1.md`](../formats/KSPWALLET_V1.md), ni le threat model du plan [`../plans/012-V0_2_5_WALLET_FOUNDATION_PLAN.md`](../plans/012-V0_2_5_WALLET_FOUNDATION_PLAN.md), ni les deltas.
Cette matrice constitue la validation durable de clôture de `0.2.5`. `pre.009` a fermé le premier gate technique security/interoperability/compliance et `pre.010` a ajouté le gate documentaire. `pre.010-fix.001` rouvre volontairement le gate technique pour la mise à niveau `ed25519-dalek 3.0.0` et la normalisation Rust workspace-wide avant toute publication stable. Elle ne remplace ni la spécification [`../formats/KSPWALLET_V1.md`](../formats/KSPWALLET_V1.md), ni le threat model du plan [`../plans/012-V0_2_5_WALLET_FOUNDATION_PLAN.md`](../plans/012-V0_2_5_WALLET_FOUNDATION_PLAN.md), ni les deltas.
Le verdict recherché porte sur quatre axes :
@@ -268,8 +268,51 @@ aucun fichier Rust ni manifest Cargo n'est modifié par pre.010
workspace.package.version reste 0.2.5-pre.9 car pre.010 est doc-only
```
## 12. Verdict final candidate `0.2.5`
## 12. Correctif technique `pre.010-fix.001`
Le verdict security/interoperability/compliance est **positif**. Le checkpoint opérateur `pre.009` est vert et n'impose aucune remédiation de code, de dépendance, de wire ou de cryptographie. `pre.010` reste donc strictement documentaire et nintroduit aucun changement technique.
Le correctif de clôture apporte deux changements qui exigent une nouvelle validation opérateur :
Après validation du delta documentaire, la suite est `0.2.5-rel.001`, strictement publicationnelle : version Cargo stable `0.2.5`, statut stable/CHANGELOG/delta de publication, validations finales puis tag Git `v0.2.5`. Aucune nouvelle fonctionnalité Wallet n'est attendue dans `rel.001`.
```text
ed25519-dalek direct KSP : ^2.2 -> ^3.0
normalisation Rust workspace + scripts/audit_rust_workspace_rules.py obligatoire
```
Le résultat `pre.009` des sections 6 et 10 reste une preuve historique valide pour l'état `2.2.0`; il ne doit pas être présenté comme le tree final après le fix. `solana-keypair 3.1.2` conserve actuellement sa branche Dalek `2.x`, donc le tree attendu après le fix est :
```text
ed25519-dalek 3.0.0
<- ksp-wallet-lib direct
ed25519-dalek 2.2.0
<- solana-keypair 3.1.2
<- ksp-wallet-lib
solana-address 2.7.0
<- solana-keypair 3.1.2
<- solana-pubkey 4.3.0 via ksp-core-lib
```
Gate opérateur post-fix :
```bash
cargo fmt --all
python3 scripts/audit_rust_workspace_rules.py
cargo check --workspace
cargo clippy --workspace --all-targets
cargo test -p ksp-wallet-lib
cargo test --workspace
cargo tree -p ksp-wallet-lib
cargo tree -p ksp-wallet-lib -d
cargo tree -i ed25519-dalek@3.0.0
cargo tree -i ed25519-dalek@2.2.0
cargo tree -i solana-keypair@3.1.2
cargo tree -i solana-address@2.7.0
```
Le fix ne modifie ni le wire `.kspwallet` V1, ni les paramètres Argon2/XChaCha, ni la sémantique Ed25519, ni les capabilities VIEW/OWNER. Le verdict final reste **en attente de ce checkpoint opérateur**.
## 13. Verdict final candidate `0.2.5`
Le verdict `pre.009` était positif pour l'état alors audité, mais **la candidate stable n'est plus considérée fermée tant que `pre.010-fix.001` n'a pas passé son gate opérateur**. Le changement de génération Dalek et la normalisation Rust sont intentionnels et ne changent pas le wire V1, mais ils constituent un changement technique réel qui doit être compilé, linté et testé dans l'environnement opérateur.
Après validation complète de `pre.010-fix.001`, le verdict peut redevenir positif et seulement alors `0.2.5-rel.001` redevient la prochaine étape publicationnelle.