v0.3.2-pre.006

This commit is contained in:
2026-08-29 19:53:00 +02:00
parent c1dbaad88d
commit c4f56d9e85
18 changed files with 674 additions and 49 deletions

View File

@@ -1,5 +1,5 @@
<!-- file: docs/plans/023-V0_3_2_STORE_POSTGRES_FOUNDATION_PLAN.md -->
<!-- version: 7 -->
<!-- version: 8 -->
# Plan `0.3.2` — Store/PostgreSQL runtime foundation
@@ -942,7 +942,7 @@ Matérialiser `StoreSettings`, `StoreBackendSettings`, `PostgresStoreSettings`,
**Statut : matérialisé par `0.3.2-pre.003`, gate opérateur requis.**
La tranche fixe :
La tranche fixe initialement :
```text
73 exports crate-root de ksp-store-lib : 60 reexports ksp-store-api + 13 éléments runtime Store
@@ -980,9 +980,34 @@ ksp-store-postgres-lib
Après parsing, la policy KSP réécrit `application_name`, `connect_timeout`, `sslnegotiation` et `sslmode`; les `options=` serveur sont rejetées. `Disabled` force le plaintext, `VerifyFull` force TLS + roots système + identité serveur et interdit un target `hostaddr` sans `host` ainsi que les sockets Unix, sur lesquels PostgreSQL ne négocie pas TLS. Le pool applique `max_size` et deadlines `wait/create/recycle`, utilise le recycling `Verified`, et `Store::open` ne réussit qu'après une première acquisition physique. Les erreurs externes ne sont jamais conservées comme source/texte public. `Store::close` ferme et draine sous deadline; `Drop` reste best-effort. Aucun SQL KSP, migration ou table métier n'est introduit.
Le gate opérateur de `pre.005-fix.001` est vert : audits, workspace check/Clippy, tests backend, façade avec et sans feature PostgreSQL et compilation `--no-default-features` passent. Les versions résolues observées sont `tokio-postgres 0.7.18`, `deadpool-postgres 0.14.2` et `tokio-postgres-rustls 0.14.0`.
### `pre.006` — Migration/bootstrap foundation
Créer history metadata, sentinel, SHA-256, advisory lock borné, transaction, version/checksum/newer/missing handling et rollback. Aucun schéma RAW.
Statut : matérialisé par `0.3.2-pre.006`, gate Cargo opérateur à exécuter.
La tranche introduit un moteur privé `ksp-store-postgres-lib` sans crate de migration externe :
```text
sha2 0.11.x explicite
V000__bootstrap.sql embarqué par include_str!
ksp_store_schema_migrations uniquement
version 0 / nom bootstrap / SHA-256 exact du SQL
transaction unique
pg_try_advisory_xact_lock($1) KSP fixe sous deadline
statement_timeout transaction-local via set_config(..., true)
forme metadata minimale vérifiée
history divergente/missing -> migration mismatch
version appliquée > 0 -> schema newer
aucun down migration
aucun schéma RAW
```
`auto_migrate = false` ne crée jamais la metadata absente : l'ouverture échoue avec un état `migration_pending` sûr. Si la metadata existe, elle est toujours vérifiée. Une table valide mais sans sentinel n'est jamais réparée implicitement : elle est considérée divergente. Les colonnes metadata obligatoires sont vérifiées sans interdire d'éventuelles colonnes supplémentaires futures, afin qu'un ancien runtime puisse encore lire l'historique puis classer correctement une version plus récente comme `schema_newer`.
Le bootstrap version `0` est spécial : lorsque la metadata est absente et l'auto-migration autorisée, le DDL embarqué est exécuté puis le sentinel est inséré dans la même transaction. Toute erreur ou expiration fait abandonner la transaction ; le rollback PostgreSQL implicite au drop protège DDL + history du run courant. Les preuves concurrentes et rollback injecté sur serveur réel restent à `pre.008`.
Avec les quatre codes PostgreSQL ajoutés en `pre.005` puis les trois codes migration de `pre.006`, la façade atteint désormais 80 exports crate-root : 60 réexports `ksp-store-api` et 20 éléments runtime Store.
### `pre.007` — Composition end-to-end + health

View File

@@ -1,5 +1,5 @@
<!-- file: docs/validation/019-V0_3_2_STORE_POSTGRES_FOUNDATION.md -->
<!-- version: 7 -->
<!-- version: 8 -->
# Validation `0.3.2` — Store/PostgreSQL runtime foundation
@@ -60,7 +60,7 @@ Référence du gate :
```text
PostgreSQL 18.6
tokio-postgres 0.7.18
deadpool-postgres 0.14.1
deadpool-postgres 0.14.2
tokio-postgres-rustls 0.14.0
sha2 0.11.0
refinery 0.9.2 audité/rejeté
@@ -76,6 +76,8 @@ Le gate opérateur de `pre.003-fix.001`, fourni le 29 août 2026, est entièreme
Le gate opérateur de `pre.004-fix.001`, après correction manuelle des commentaires `.env.example`, est entièrement vert : audits Rust/Markdown, workspace check/Clippy, 126 tests `ksp-config-lib`, ownership, `ksp-store-lib` avec et sans feature PostgreSQL, compilation `--no-default-features` et 63 tests Config Desk passent. Cette base est l'entrée effective de `pre.005`.
Le gate opérateur de `pre.005-fix.001`, fourni le 29 août 2026, est entièrement vert : audits Rust/Markdown, workspace check/Clippy, 5 tests runtime backend, canaris de dépendances/API, façade avec et sans feature PostgreSQL et compilation `--no-default-features` passent. Cette base est l'entrée effective de `pre.006`.
## 3. Frontières Cargo
### V32-DEP-001 — Façade -> API
@@ -138,7 +140,7 @@ consumer ordinaire -> ksp-store-postgres-lib
Matérialisé par `pre.005` : les types physiques nécessaires sont publics uniquement dans la crate backend pour la frontière inter-crates et ne sont jamais réexportés par `ksp-store-lib`; `Pool/Client/Row/Statement` restent absents de sa crate-root.
Statut : `TODO gate opérateur pre.005 / TODO pre.009`.
Statut : `PASS pre.005-fix.001 opérateur / TODO pre.009`.
### V32-DEP-006 — `ksp-store-api` non régressé
@@ -205,7 +207,7 @@ Drop best-effort seulement
`pre.003` fixe les signatures `Store::open(settings).await` et `Store::close(self).await`. `pre.005` remplace le stop de staging PostgreSQL par l'ouverture physique : un succès exige `pool.get().await` après construction du pool, puis `close(self)` ferme et draine ce pool sous la deadline configurée. Aucun pool/client n'est exposé par la façade.
Statut : `PASS pre.003-fix.001 opérateur` pour les signatures / `TODO gate opérateur pre.005` pour l'ouverture et le shutdown physiques / `TODO pre.007` pour la composition health.
Statut : `PASS pre.003-fix.001 opérateur` pour les signatures / `PASS pre.005-fix.001 opérateur` pour l'ouverture et le shutdown physiques / `TODO pre.007` pour la composition health.
## 5. Config ownership
@@ -298,7 +300,7 @@ aucune valeur pathologique
Matérialisé par `pre.005` : `deadpool-postgres` possède un pool `max_size` explicite et applique les deadlines `wait/create/recycle`; `tokio-postgres::Config` reçoit aussi le `connect_timeout` typé après parsing de l'URI.
Statut : `TODO gate opérateur pre.005`.
Statut : `PASS pre.005-fix.001 opérateur`.
### V32-POOL-002 — Connection task ownership
@@ -306,7 +308,7 @@ Critère : chaque connection future tokio-postgres est pilotée par le manager r
`pre.005` délègue la création/recycle des connexions au `Manager` Deadpool retenu ; aucun `tokio::spawn` KSP n'est introduit dans Store. La preuve de non-régression détaillée reste au hardening.
Statut : `TODO gate opérateur pre.005 / TODO pre.009`.
Statut : `PASS pre.005-fix.001 opérateur / TODO pre.009`.
### V32-POOL-003 — Open failure safe
@@ -314,7 +316,7 @@ Critère : DNS/connect/auth/server errors ne copient ni URI ni texte remote arbi
Matérialisé par `pre.005` : parsing/connexion/pool/TLS sont ramenés à une classification backend locale sans conserver le texte des erreurs externes ni l'URI. La façade mappe vers des codes `store.postgres_*` stables avec contexte statique sûr.
Statut : `TODO gate opérateur pre.005`.
Statut : `PASS pre.005-fix.001 opérateur`.
### V32-POOL-004 — Close
@@ -329,7 +331,7 @@ aucune tâche volontairement laissée orpheline
`pre.005` matérialise déjà `Pool::close()` et un drain borné par `shutdown_timeout`; `Drop` ne fait qu'un `close()` best-effort. La preuve end-to-end avec backend réel reste réservée à `pre.007/pre.008`.
Statut : `TODO gate opérateur pre.005 / TODO pre.007/pre.008`.
Statut : `PASS pre.005-fix.001 opérateur / TODO pre.007/pre.008`.
## 7. TLS
@@ -344,7 +346,7 @@ VerifyFull
Matérialisé par `pre.005` : la surface physique accepte exactement `Disabled` et `VerifyFull`; l'URI parsée est ensuite normalisée vers `SslMode::Disable` ou `SslMode::Require`, donc elle ne peut pas modifier la policy typée.
Statut : `TODO gate opérateur pre.005`.
Statut : `PASS pre.005-fix.001 opérateur`.
### V32-TLS-002 — VerifyFull
@@ -360,7 +362,7 @@ aucun fallback plaintext
Matérialisé par `pre.005` : `VerifyFull` construit un `rustls::RootCertStore` à partir des roots système, utilise explicitement le provider AWS-LC, requiert un host TCP pour l'identité serveur, rejette `hostaddr` seul et les sockets Unix, et ne permet aucun fallback plaintext. Les erreurs de roots/certificats sont réduites à des compteurs sûrs.
Statut : `TODO gate opérateur pre.005`.
Statut : `PASS pre.005-fix.001 opérateur`.
### V32-TLS-003 — Pas de fichier TLS implicite
@@ -380,7 +382,9 @@ ksp_store_schema_migrations
et aucune table métier RAW/CORE/DECODE/SPECIALIZED.
Statut : `TODO pre.006`.
`pre.006` embarque exactement `migrations/V000__bootstrap.sql`, dont le seul DDL de production crée `ksp_store_schema_migrations`. Le canari source interdit les identifiants métier RAW/CORE/DECODE/SPECIALIZED dans le moteur et la ressource SQL.
Statut : `TODO gate opérateur pre.006 / TODO pre.008 live`.
### V32-MIG-002 — Version/checksum
@@ -394,25 +398,33 @@ sentinel bootstrap version 0
mismatch historique terminal
```
Statut : `TODO pre.006`.
`pre.006` calcule explicitement SHA-256 sur les octets exacts du SQL embarqué puis encode les 32 octets en 64 caractères hex minuscules. Le sentinel `(0, bootstrap, checksum)` est inséré dans la même transaction que la création metadata. Les tests unitaires figent le checksum du SQL committed et couvrent sentinel valide, missing, nom/checksum divergents et historique plus récent.
Statut : `TODO gate opérateur pre.006 / TODO pre.008 live`.
### V32-MIG-003 — Concurrence
Critère : deux runners concurrents sont sérialisés par advisory transaction lock avec attente bornée.
Statut : `TODO pre.006/pre.008`.
`pre.006` utilise une clé KSP fixe et `pg_try_advisory_xact_lock($1)` dans une boucle bornée par `migration_lock_timeout`, avec polling de 25 ms maximum. Aucun lock bloquant illimité n'est utilisé.
Statut : `TODO gate opérateur pre.006 / TODO pre.008 concurrence réelle`.
### V32-MIG-004 — Atomicité/recovery
Critère : échec d'une migration du run courant rollback DDL + history de ce run ; un rerun depuis état précédent reste sûr.
Statut : `TODO pre.006/pre.008`.
`pre.006` place lock, metadata DDL, sentinel et validation dans une transaction unique ; toute sortie d'erreur avant `commit()` droppe la transaction et PostgreSQL rollback le run courant. Un timeout externe borne également l'ensemble du bootstrap. L'injection d'échec et la preuve physique du rollback restent au smoke réel.
Statut : `TODO gate opérateur pre.006 / TODO pre.008 rollback réel`.
### V32-MIG-005 — Newer runtime guard
Critère : migration appliquée inconnue/supérieure à la liste embarquée produit `STORE_POSTGRES_SCHEMA_NEWER`, sans down migration.
Statut : `TODO pre.006`.
`pre.006` connaît uniquement la version `0`; toute history `> 0` est classée `SchemaNewer` par le backend puis `store.postgres_schema_newer` par la façade. Aucun chemin de down migration n'existe.
Statut : `TODO gate opérateur pre.006`.
### V32-MIG-006 — SQL injection
@@ -424,7 +436,9 @@ values paramétrées
aucun identifier physique user-configurable en 0.3.2
```
Statut : `TODO pre.006/pre.009`.
`pre.006` garde le DDL versionné sous `include_str!` et toutes les values variables des requêtes de contrôle (`lock key`, `statement_timeout`, history values) passent par paramètres. Les noms physiques sont des constantes KSP, jamais des settings.
Statut : `TODO gate opérateur pre.006 / TODO pre.009 hardening`.
### V32-MIG-007 — No business capability
@@ -539,9 +553,9 @@ Statut : `TODO pre.009`.
Cas : zéro, inversion, dépassement bornes pour pool/connect/migration/close.
Les bornes backend-neutral décidées en `pre.001` sont matérialisées et couvertes par tests unitaires en `pre.003`. Le parsing PostgreSQL et les timeouts physiques restent à `pre.005`.
Les bornes backend-neutral décidées en `pre.001` sont matérialisées et couvertes par tests unitaires en `pre.003`. `pre.005` applique physiquement `connect/wait/create/recycle/shutdown`; `pre.006` applique physiquement `migration_timeout` et `migration_lock_timeout`.
Statut : `PASS pre.003-fix.001 opérateur` pour les bornes backend-neutral / `TODO pre.005 / TODO pre.009` pour les timeouts physiques.
Statut : `PASS pre.003-fix.001 opérateur` pour les bornes backend-neutral / `PASS pre.005-fix.001 opérateur` pour pool/connect/shutdown / `TODO gate opérateur pre.006` pour migration / `TODO pre.009` hardening.
### V32-SEC-004 — Feature mismatch avant I/O
@@ -553,7 +567,7 @@ Statut : `PASS pre.003-fix.001 opérateur / TODO pre.009`.
Un serveur/test double qui renvoie un message contenant un canary ne doit pas le faire traverser l'erreur publique.
Statut : `TODO pre.005/pre.009`.
Statut : bridge de sanitization matérialisé en `pre.005`; `TODO pre.009` pour le canary serveur hostile.
## 12. Gates Rust/workspace