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/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