diff --git a/Cargo.toml b/Cargo.toml index a4bf98c..341ab4b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,12 @@ # file: Cargo.toml -# version: 221 +# version: 222 [workspace] resolver = "3" members = ["crates/ksp-app-config-desk", "crates/ksp-app-wallet-desk", "crates/ksp-config-lib", "crates/ksp-core-lib", "crates/ksp-logging-lib", "crates/ksp-onchain-transport-lib", "crates/ksp-wallet-lib"] [workspace.package] -version = "0.2.8-pre.4" +version = "0.2.8-pre.4.fix.1" edition = "2024" license = "MIT" repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project" diff --git a/config/examples/std.transport.example.json b/config/examples/std.transport.example.json index 2c4cf73..0ee6885 100644 --- a/config/examples/std.transport.example.json +++ b/config/examples/std.transport.example.json @@ -102,6 +102,47 @@ } } ] + }, + { + "profile_id": "devnet_helius", + "endpoints": [ + { + "name": "devnet_public", + "enabled": true, + "provider": "solana-public", + "cluster": "devnet", + "url": "${KSP_PUBLIC_SOLANA_DEVNET_HTTP_URL:-https://api.devnet.solana.com}", + "connect_timeout_ms": 5000, + "request_timeout_ms": 15000, + "max_idle_connections_per_host": 8, + "roles": [ + { + "role": "default", + "enabled": true, + "request_kinds": [ + "*" + ], + "priority": 100, + "limits": { + "requests_per_second": 5, + "burst_capacity": 10, + "max_concurrent_requests": 8, + "pause_after_rate_limit_ms": 1000 + } + } + ] + } + ], + "ws_endpoints": [ + { + "name": "devnet_helius_ws", + "enabled": true, + "provider": "helius", + "cluster": "devnet", + "kind": "helius_laserstream", + "url": "wss://devnet.helius-rpc.com/?api-key=${KSP_SECRET_HELIUS_API_KEY:-replace-me}" + } + ] } ] } diff --git a/crates/ksp-config-lib/USAGE.md b/crates/ksp-config-lib/USAGE.md index a91434c..e7696c2 100644 --- a/crates/ksp-config-lib/USAGE.md +++ b/crates/ksp-config-lib/USAGE.md @@ -1,5 +1,5 @@ - + # Utilisation de ksp-config-lib @@ -142,7 +142,7 @@ let _ = (http_settings, ws_settings); `std.transport` V2 conserve `retry` et `profiles[].endpoints[]` pour HTTP, ajoute `ws_defaults` et `profiles[].ws_endpoints[]`, puis accepte les protocoles WebSocket `kind = "solana_standard"` et `kind = "helius_laserstream"`. Ce second discriminateur appartient exclusivement au namespace WebSocket et mappe vers `WsProtocolKind::HeliusLaserStream`; il ne préfigure aucun contrat LaserStream gRPC. Un `ws_endpoints[].session` optionnel surcharge seulement les paramètres génériques de `WsSessionSettings`. -Pour Helius LaserStream WebSocket, l'exemple versionné compose l'URL provider avec `${KSP_SECRET_HELIUS_API_KEY:-replace-me}`. Config reste l'unique propriétaire de cette variable : il résout la clé dans l'URL effective, transmet au Transport un `WsEndpointUrl` utilisable au runtime et redige la valeur dans la projection sûre et les représentations `Debug`. Transport ne lit jamais directement l'environnement. +Pour Helius LaserStream WebSocket, l'exemple versionné couvre explicitement les deux réseaux supportés par ce contrat : mainnet via `wss://mainnet.helius-rpc.com/?api-key=${KSP_SECRET_HELIUS_API_KEY:-replace-me}` et devnet via `wss://devnet.helius-rpc.com/?api-key=${KSP_SECRET_HELIUS_API_KEY:-replace-me}`. Les deux réseaux vivent dans des profils Config distincts afin de ne pas mélanger des clusters dans un même profil logique. Config reste l'unique propriétaire de `KSP_SECRET_HELIUS_API_KEY` : il résout la clé dans l'URL effective et transmet au Transport un `WsEndpointUrl` utilisable au runtime. Dans `safe_value`, Config conserve les segments littéraux non sensibles d'une chaîne composée et remplace uniquement chaque segment secret par `********` ; les projections deviennent donc respectivement `wss://mainnet.helius-rpc.com/?api-key=********` et `wss://devnet.helius-rpc.com/?api-key=********`. Les représentations `Debug` restent sûres et n'exposent jamais la clé réelle. Transport ne lit jamais directement l'environnement. Le même schema enregistré conserve la lecture stricte du V1 historique : dans ce cas `http_settings()` reste disponible et `ws_settings()` retourne `None`. Aucun `WsTransportSettings` vide n'est inventé pour simuler l'absence de WebSocket. diff --git a/crates/ksp-config-lib/unit_tests/fixtures/std.transport.json b/crates/ksp-config-lib/unit_tests/fixtures/std.transport.json index 16256fc..f67b34f 100644 --- a/crates/ksp-config-lib/unit_tests/fixtures/std.transport.json +++ b/crates/ksp-config-lib/unit_tests/fixtures/std.transport.json @@ -81,6 +81,47 @@ "url": "wss://mainnet.helius-rpc.com/?api-key=${KSP_SECRET_HELIUS_API_KEY:-fixture-helius-key}" } ] + }, + { + "profile_id": "helius_devnet", + "endpoints": [ + { + "name": "fixture_devnet_http", + "enabled": true, + "provider": "solana-public", + "cluster": "devnet", + "url": "https://api.devnet.solana.com", + "connect_timeout_ms": 750, + "request_timeout_ms": 2500, + "max_idle_connections_per_host": 3, + "roles": [ + { + "role": "default", + "enabled": true, + "request_kinds": [ + "*" + ], + "priority": 7, + "limits": { + "requests_per_second": 9, + "burst_capacity": 12, + "max_concurrent_requests": 4, + "pause_after_rate_limit_ms": 650 + } + } + ] + } + ], + "ws_endpoints": [ + { + "name": "fixture_helius_devnet_ws", + "enabled": true, + "provider": "helius", + "cluster": "devnet", + "kind": "helius_laserstream", + "url": "wss://devnet.helius-rpc.com/?api-key=${KSP_SECRET_HELIUS_API_KEY:-fixture-helius-key}" + } + ] } ] } diff --git a/crates/ksp-config-lib/unit_tests/transport.rs b/crates/ksp-config-lib/unit_tests/transport.rs index 10d86d7..ea73437 100644 --- a/crates/ksp-config-lib/unit_tests/transport.rs +++ b/crates/ksp-config-lib/unit_tests/transport.rs @@ -267,7 +267,7 @@ fn secret_websocket_url_is_runtime_available_but_safe_projection_is_redacted() { } #[test] -fn helius_laserstream_secret_api_key_maps_to_provider_protocol_and_safe_redaction() { +fn helius_laserstream_mainnet_and_devnet_api_key_map_to_protocol_and_safe_redaction() { let engine = fixture_engine(); let engine = match engine { std::result::Result::Ok(value) => value, @@ -277,33 +277,63 @@ fn helius_laserstream_secret_api_key_maps_to_provider_protocol_and_safe_redactio let mut process = std::collections::BTreeMap::::new(); process.insert("KSP_SECRET_HELIUS_API_KEY".to_owned(), canary.to_owned()); let environment = crate::ConfigEnvironment::from_maps(process, std::collections::BTreeMap::new()); - let resolved = engine.load_resolved_transport_config(std::option::Option::None, &environment); - assert!(resolved.is_ok(), "Helius LaserStream WebSocket endpoint should map without exposing its API key: {resolved:?}"); - let resolved = match resolved { + let mainnet = engine.load_resolved_transport_config(std::option::Option::None, &environment); + assert!(mainnet.is_ok(), "Helius mainnet WebSocket endpoint should map without exposing its API key: {mainnet:?}"); + let mainnet = match mainnet { std::result::Result::Ok(value) => value, std::result::Result::Err(_) => return, }; - let ws = resolved.ws_settings(); - assert!(ws.is_some(), "V2 fixture should expose WebSocket settings"); - if let std::option::Option::Some(ws) = ws { + let mainnet_ws = mainnet.ws_settings(); + assert!(mainnet_ws.is_some(), "V2 fixture should expose mainnet WebSocket settings"); + if let std::option::Option::Some(ws) = mainnet_ws { assert_eq!(ws.endpoints().len(), 2); let endpoint = &ws.endpoints()[1]; assert_eq!(endpoint.provider().as_str(), "helius"); + assert_eq!(endpoint.cluster().as_str(), "mainnet-beta"); assert_eq!(endpoint.protocol(), ksp_onchain_transport_lib::WsProtocolKind::HeliusLaserStream); assert_eq!(endpoint.url().as_str(), "wss://mainnet.helius-rpc.com/?api-key=helius-api-key-canary"); } - let safe_url = resolved.effective().safe_value().pointer("/ws_endpoints/1/url").and_then(serde_json::Value::as_str); - assert_eq!(safe_url, std::option::Option::Some(crate::REDACTED_CONFIG_VALUE)); - let provenance = resolved.effective().provenance_at("/ws_endpoints/1/url"); - assert!(provenance.is_some(), "Helius endpoint URL should retain secret environment provenance"); - if let std::option::Option::Some(provenance) = provenance { + let mainnet_safe_url = mainnet.effective().safe_value().pointer("/ws_endpoints/1/url").and_then(serde_json::Value::as_str); + assert_eq!(mainnet_safe_url, std::option::Option::Some("wss://mainnet.helius-rpc.com/?api-key=********")); + let mainnet_provenance = mainnet.effective().provenance_at("/ws_endpoints/1/url"); + assert!(mainnet_provenance.is_some(), "Helius mainnet endpoint URL should retain secret environment provenance"); + if let std::option::Option::Some(provenance) = mainnet_provenance { assert_eq!(provenance.len(), 1); assert_eq!(provenance[0].environment_source(), std::option::Option::Some(crate::ConfigEnvironmentSource::Process)); assert_eq!(provenance[0].variable_name(), std::option::Option::Some("KSP_SECRET_HELIUS_API_KEY")); } - let debug = format!("{resolved:?}"); - assert!(!debug.contains(canary)); - assert!(debug.contains(crate::REDACTED_CONFIG_VALUE)); + let devnet = engine.load_resolved_transport_config(std::option::Option::Some("helius_devnet"), &environment); + assert!(devnet.is_ok(), "Helius devnet WebSocket endpoint should map without exposing its API key: {devnet:?}"); + let devnet = match devnet { + std::result::Result::Ok(value) => value, + std::result::Result::Err(_) => return, + }; + let devnet_ws = devnet.ws_settings(); + assert!(devnet_ws.is_some(), "V2 fixture should expose devnet WebSocket settings"); + if let std::option::Option::Some(ws) = devnet_ws { + assert_eq!(ws.endpoints().len(), 1); + let endpoint = &ws.endpoints()[0]; + assert_eq!(endpoint.provider().as_str(), "helius"); + assert_eq!(endpoint.cluster().as_str(), "devnet"); + assert_eq!(endpoint.protocol(), ksp_onchain_transport_lib::WsProtocolKind::HeliusLaserStream); + assert_eq!(endpoint.url().as_str(), "wss://devnet.helius-rpc.com/?api-key=helius-api-key-canary"); + let _connect_future = ksp_onchain_transport_lib::HeliusLaserStreamWsSession::connect(endpoint.clone()); + } + let devnet_safe_url = devnet.effective().safe_value().pointer("/ws_endpoints/0/url").and_then(serde_json::Value::as_str); + assert_eq!(devnet_safe_url, std::option::Option::Some("wss://devnet.helius-rpc.com/?api-key=********")); + let devnet_provenance = devnet.effective().provenance_at("/ws_endpoints/0/url"); + assert!(devnet_provenance.is_some(), "Helius devnet endpoint URL should retain secret environment provenance"); + if let std::option::Option::Some(provenance) = devnet_provenance { + assert_eq!(provenance.len(), 1); + assert_eq!(provenance[0].environment_source(), std::option::Option::Some(crate::ConfigEnvironmentSource::Process)); + assert_eq!(provenance[0].variable_name(), std::option::Option::Some("KSP_SECRET_HELIUS_API_KEY")); + } + let mainnet_debug = format!("{mainnet:?}"); + let devnet_debug = format!("{devnet:?}"); + assert!(!mainnet_debug.contains(canary)); + assert!(!devnet_debug.contains(canary)); + assert!(mainnet_debug.contains(crate::REDACTED_CONFIG_VALUE)); + assert!(devnet_debug.contains(crate::REDACTED_CONFIG_VALUE)); } #[test] diff --git a/deltas/0.2.8/pre.004-fix.001.md b/deltas/0.2.8/pre.004-fix.001.md new file mode 100644 index 0000000..a7e7dda --- /dev/null +++ b/deltas/0.2.8/pre.004-fix.001.md @@ -0,0 +1,182 @@ + + + +# Delta `0.2.8-pre.004-fix.001` — redaction Helius Config + couverture Devnet + +## 1. Objet + +Ce fix corrige deux défauts circonscrits de `0.2.8-pre.004` : + +```text +1. faux négatif du nouveau canari de redaction `safe_value` Helius ; +2. représentation déterministe incomplète : mainnet était matérialisé, Devnet ne l'était pas encore. +``` + +Le résolveur Config, le mapping Config -> Transport et le moteur WebSocket restent inchangés. + +Version workspace : + +```text +0.2.8-pre.4.fix.1 +``` + +Livraison / commit attendu : + +```text +0.2.8-pre.004-fix.001 +v0.2.8-pre.004-fix.001 +``` + +Aucun tag prerelease. + +## 2. Preuve opérateur ayant déclenché le fix + +Le checkpoint `pre.004` reçu le 2026-08-23 donne : + +```text +cargo fmt --all OK +python3 scripts/audit_rust_workspace_rules.py clean +cargo check --workspace OK +cargo clippy --workspace --all-targets OK +cargo test -p ksp-config-lib FAIL 109/110 +cargo test -p ksp-onchain-transport-lib OK +cargo test --workspace FAIL sur le même test Config +``` + +L'échec exact est : + +```text +observé = wss://mainnet.helius-rpc.com/?api-key=******** +attendu = ******** +``` + +Le test avait déjà prouvé avant cette assertion que le schema accepte `helius_laserstream`, que l'adapter produit `WsProtocolKind::HeliusLaserStream` et que l'URL runtime contient la clé Helius résolue. + +## 3. Redaction Config confirmée + +Le contrat historique Config est segmentaire pour une chaîne composée : + +```text +source composée safe_value +https://rpc.example/?token=${SECRET} -> https://rpc.example/?token=******** +token=${SECRET} -> token=******** +``` + +La projection sûre conserve donc les littéraux non sensibles et masque uniquement le segment secret. + +Pour Helius : + +```text +mainnet runtime = wss://mainnet.helius-rpc.com/?api-key= +mainnet safe_value = wss://mainnet.helius-rpc.com/?api-key=******** + +devnet runtime = wss://devnet.helius-rpc.com/?api-key= +devnet safe_value = wss://devnet.helius-rpc.com/?api-key=******** +``` + +La clé réelle doit rester absente de `safe_value` et de toutes les représentations `Debug`. + +## 4. Couverture Helius Devnet ajoutée + +La documentation Helius WebSocket actuelle expose un endpoint unifié par réseau : + +```text +mainnet wss://mainnet.helius-rpc.com/?api-key= +devnet wss://devnet.helius-rpc.com/?api-key= +``` + +`pre.004` avait documenté les deux réseaux dans le plan mais n'avait matérialisé que mainnet dans l'exemple et la fixture Config. Le fix complète ce manque. + +Décision de structure : + +```text +mainnet et devnet vivent dans des profils Config distincts ; +un même profil logique ne mélange pas les deux clusters ; +la même variable KSP_SECRET_HELIUS_API_KEY peut alimenter les deux URLs ; +config/std.transport.json reste standard-only. +``` + +L'exemple versionné ajoute un profil `devnet_helius`. La fixture Config ajoute un profil `helius_devnet` et le test charge explicitement ce profil en plus du profil mainnet par défaut. + +## 5. Correction du test + +Le canari devient : + +```text +helius_laserstream_mainnet_and_devnet_api_key_map_to_protocol_and_safe_redaction +``` + +Il vérifie pour **mainnet et devnet** : + +```text +provider = helius +cluster exact +protocol = WsProtocolKind::HeliusLaserStream +URL runtime exacte avec la clé résolue +safe_value exact avec segment ******** +provenance = KSP_SECRET_HELIUS_API_KEY / Process +Debug sans la clé réelle +composition avec HeliusLaserStreamWsSession au moins sur le profil Devnet dédié +``` + +## 6. Invariants non modifiés + +Aucune modification n'est apportée à : + +```text +ConfigEnvironment / moteur de résolution +sensitivity / provenance semantics +JSON Schema Transport V2 +mapping helius_laserstream -> HeliusLaserStream +WsEndpointUrl +WsSession / façades / actor +config/std.transport.json canonique +transactionSubscribe +heartbeat +new dependency +``` + +`.env.example` conserve une seule variable `KSP_SECRET_HELIUS_API_KEY`, suffisante pour les deux endpoints Helius. + +## 7. Fichiers de la livraison + +Nouveau : + +```text +deltas/0.2.8/pre.004-fix.001.md +``` + +Modifiés : + +```text +Cargo.toml +config/examples/std.transport.example.json +crates/ksp-config-lib/unit_tests/fixtures/std.transport.json +crates/ksp-config-lib/unit_tests/transport.rs +crates/ksp-config-lib/USAGE.md +docs/plans/015-V0_2_8_HELIUS_LASERSTREAM_WEBSOCKET_PLAN.md +docs/validation/011-V0_2_8_HELIUS_LASERSTREAM_WEBSOCKET.md +``` + +Inchangés volontairement : + +```text +config/std.transport.json +config/schemas/std.transport.schema.json +.env.example +Transport WebSocket runtime +``` + +## 8. Validation à rejouer + +```bash +cargo fmt --all +python3 scripts/audit_rust_workspace_rules.py +cargo check --workspace +cargo clippy --workspace --all-targets +cargo test -p ksp-config-lib +cargo test -p ksp-onchain-transport-lib +cargo test --workspace +``` + +`pre.004` + `fix.001` restent non fermés jusqu'à réception de ce checkpoint intégralement vert. diff --git a/docs/plans/015-V0_2_8_HELIUS_LASERSTREAM_WEBSOCKET_PLAN.md b/docs/plans/015-V0_2_8_HELIUS_LASERSTREAM_WEBSOCKET_PLAN.md index b27fe3d..0b2d38f 100644 --- a/docs/plans/015-V0_2_8_HELIUS_LASERSTREAM_WEBSOCKET_PLAN.md +++ b/docs/plans/015-V0_2_8_HELIUS_LASERSTREAM_WEBSOCKET_PLAN.md @@ -1,9 +1,9 @@ - + # Plan `0.2.8` — Helius LaserStream WebSocket -> **Statut : `0.2.8-pre.003` est validé ; `0.2.8-pre.004` est préparé.** La façade `HeliusLaserStreamWsSession` possède désormais sa surface standard 6/6 validée. `pre.004` étend uniquement Config V2 au discriminateur WebSocket `helius_laserstream`, ajoute la fixture/exemple Helius et verrouille la résolution/redaction de `KSP_SECRET_HELIUS_API_KEY`, sans ouvrir `transactionSubscribe`. +> **Statut : `0.2.8-pre.003` est validé ; le checkpoint `0.2.8-pre.004` a révélé un faux négatif de test, puis la revue du fix a identifié l'omission d'une représentation Devnet Helius déterministe. `pre.004-fix.001` corrige les deux points et reste préparé.** Le runtime Config/Transport est inchangé : pour une chaîne composée, `safe_value` conserve les segments littéraux non sensibles et remplace uniquement le segment secret par `********`. Le fix couvre désormais mainnet et devnet sans ouvrir `transactionSubscribe`. ## 1. Objet, base et état courant @@ -27,10 +27,11 @@ pre.001-fix.002 forecast compact + namespace LaserStream WS/gRPC pre.002 socle protocolaire validé pre.002-fix.001 correction Clippy + normalisation structure documentaire validées pre.003 six familles standard Helius validées -pre.004 Config V2 Helius + secret/redaction préparés +pre.004 Config V2 Helius implémenté ; checkpoint bloqué par un faux négatif de test +pre.004-fix.001 correction safe_value + couverture Devnet Helius préparées -workspace.package.version courant = 0.2.8-pre.4 -commit attendu = v0.2.8-pre.004 +workspace.package.version courant = 0.2.8-pre.4.fix.1 +commit attendu = v0.2.8-pre.004-fix.001 aucun tag prerelease ``` @@ -50,8 +51,10 @@ pre.002 DONE — socle protocolaire : WsProtocolKind::HeliusLaserStream + faça fix.001 DONE — correction Clippy `implicit_return` + audit/normalisation structure docs pre.003 DONE — surface Helius standard supportée : account/logs/program/root/signature/slot + absence typée de block/slotsUpdates/vote sur Helius + non-régression standard 9/9 -pre.004 PREPARED — Config V2 helius_laserstream + schema/fixtures + mapping Config -> Transport - + stratégie de secret Helius et redaction URL +pre.004 CHECKPOINT — Config V2 helius_laserstream + schema/fixtures + mapping Config -> Transport + + stratégie de secret Helius et redaction URL ; runtime/check/clippy/Transport verts + fix.001 PREPARED — corrige le faux négatif `safe_value` + complète la représentation Devnet Helius + + mainnet/devnet dans des profils distincts, même secret, sans changement runtime pre.005 transactionSubscribe request typed + filters/options/tokenAccounts + transactionUnsubscribe + bounds 50k + maxSupportedTransactionVersion conditionnel pre.006 transactionNotification + actor integration + reconnect/resubscribe/unsubscribe races @@ -709,17 +712,18 @@ profiles[].ws_endpoints[].kind: helius_laserstream -> WsProtocolKind::HeliusLaserStream ``` -La fixture Config contient un endpoint Helius typé et l'exemple versionné montre la composition de l'URL mainnet. `config/std.transport.json` reste standard-only pour ne pas imposer de provider/credential dans la configuration par défaut. Les paramètres de `transactionSubscribe` restent runtime et n'appartiennent pas au profil endpoint Config. +La fixture Config contient un endpoint Helius mainnet typé ainsi qu'un profil Helius devnet distinct. L'exemple versionné matérialise lui aussi un profil mainnet et un profil devnet séparés ; aucun profil logique ne mélange les deux clusters. `config/std.transport.json` reste standard-only pour ne pas imposer de provider/credential dans la configuration par défaut. Les paramètres de `transactionSubscribe` restent runtime et n'appartiennent pas au profil endpoint Config. ### 7.13 Credentials L'api-key reste uniquement dans l'URL résolue : ```text -wss://mainnet.helius-rpc.com/?api-key=${KSP_SECRET_HELIUS_API_KEY:-replace-me} +mainnet = wss://mainnet.helius-rpc.com/?api-key=${KSP_SECRET_HELIUS_API_KEY:-replace-me} +devnet = wss://devnet.helius-rpc.com/?api-key=${KSP_SECRET_HELIUS_API_KEY:-replace-me} ``` -`KSP_SECRET_HELIUS_API_KEY` est inventorié dans `.env.example` sous forme commentée/placeholder. Config résout la clé au sein de l'URL effective, marque la valeur comme `Secret`, conserve l'URL réelle uniquement pour le runtime légitime et redige la projection sûre ainsi que `Debug`. Transport ne lit jamais `std::env` et reçoit uniquement un `WsEndpointUrl`. +`KSP_SECRET_HELIUS_API_KEY` est inventorié dans `.env.example` sous forme commentée/placeholder et est réutilisé pour les deux réseaux Helius. Config résout la clé au sein de chaque URL effective, marque le segment résolu comme `Secret` et conserve l'URL réelle uniquement pour le runtime légitime. Le contrat Config existant de redaction **segmentaire** s'applique aux chaînes composées : les littéraux sûrs sont conservés et le segment secret devient `********`, soit `wss://mainnet.helius-rpc.com/?api-key=********` ou `wss://devnet.helius-rpc.com/?api-key=********`. `Debug` n'expose jamais la clé réelle. Transport ne lit jamais `std::env` et reçoit uniquement un `WsEndpointUrl`. ## 8. Threat model provider @@ -890,7 +894,7 @@ validation finale fermée prompt 0.2.9 prêt ``` -## 13. Checkpoint `pre.004` +## 13. Checkpoint `pre.004` et `fix.001` Le checkpoint `pre.003` est fermé par preuve opérateur : @@ -910,8 +914,8 @@ Les preuves spécifiques `pre.003` sont acquises : fixture Helius 6/6, 38 tests ```text WsProtocolKind Config mapping helius_laserstream -> HeliusLaserStream JSON Schema V2 kind accepte solana_standard + helius_laserstream -fixture Config endpoint Helius avec interpolation d'api-key -example Config endpoint Helius mainnet explicite +fixture Config Helius mainnet + profil Helius devnet séparé, interpolation d'api-key +example Config profils Helius mainnet/devnet explicites et séparés secret KSP_SECRET_HELIUS_API_KEY safe projection / Debug credential Helius redacted Config -> Transport endpoint typé HeliusLaserStream @@ -921,7 +925,21 @@ heartbeat toujours absent new dependency aucune ``` -Le checkpoint opérateur requis avant de déclarer `pre.004` `DONE` est : +Le premier checkpoint opérateur `pre.004` reçu le 2026-08-23 donne : + +```text +cargo fmt --all OK +python3 scripts/audit_rust_workspace_rules.py clean +cargo check --workspace OK +cargo clippy --workspace --all-targets OK +cargo test -p ksp-config-lib FAIL 109/110 +cargo test -p ksp-onchain-transport-lib OK 314 unit + 38 public + 26 completeness + 4 doctests +cargo test --workspace FAIL sur le même test Config +``` + +L'unique échec opérateur compare `safe_value` à `********` alors que le résolveur produit correctement `wss://mainnet.helius-rpc.com/?api-key=********`. Les canaris historiques Config prouvent déjà ce contrat de redaction segmentaire pour les chaînes composées. La revue du fix a aussi identifié que `pre.004` ne matérialisait déterministiquement que mainnet alors que le contrat Helius WebSocket couvre mainnet et devnet. `pre.004-fix.001` corrige donc l'attente du test **et** ajoute un profil/fixture Devnet Helius séparé, sans modifier le résolveur, le schema, le mapping protocol ou le runtime Transport. + +Le checkpoint à rejouer avant de déclarer `pre.004` + `fix.001` `DONE` est : ```bash cargo fmt --all diff --git a/docs/validation/011-V0_2_8_HELIUS_LASERSTREAM_WEBSOCKET.md b/docs/validation/011-V0_2_8_HELIUS_LASERSTREAM_WEBSOCKET.md index c803cb1..e5c2ac0 100644 --- a/docs/validation/011-V0_2_8_HELIUS_LASERSTREAM_WEBSOCKET.md +++ b/docs/validation/011-V0_2_8_HELIUS_LASERSTREAM_WEBSOCKET.md @@ -1,9 +1,9 @@ - + # Validation `0.2.8` — Helius LaserStream WebSocket -> **Statut : `pre.003` validé ; `pre.004` préparé.** Les six wrappers standard Helius, leurs exact-wire fixtures, canaries publiques/release-completeness et compile-fail sont verts. La tranche courante ajoute uniquement le mapping Config V2 `helius_laserstream`, une fixture/exemple Helius et les preuves de résolution/redaction du secret provider. +> **Statut : `pre.003` validé ; `pre.004` a atteint son checkpoint avec un faux négatif Config et la revue a ensuite relevé l'absence d'un cas Devnet Helius déterministe. `pre.004-fix.001` couvre les deux corrections.** `fmt`, audit, `check`, `clippy` et Transport sont verts. Le fix aligne le test Helius sur la redaction segmentaire existante et exige désormais mainnet + devnet dans des profils distincts. ## 1. Références @@ -17,6 +17,8 @@ fix forecast/nomenclature deltas/0.2.8/pre.001-fix.002.md pre.002 deltas/0.2.8/pre.002.md pre.002 Clippy/docs fix deltas/0.2.8/pre.002-fix.001.md pre.003 deltas/0.2.8/pre.003.md +pre.004 deltas/0.2.8/pre.004.md +pre.004 redaction test fix deltas/0.2.8/pre.004-fix.001.md validation standard WS docs/validation/010-V0_2_7_ONCHAIN_WEBSOCKET.md HTTP compliance docs/validation/007-V0_2_4_HTTP_FINAL_COMPLIANCE.md KSP-TRANSPORT-007 docs/validation/005-V0_2_3_KSP_TRANSPORT_007_RETRO_AUDIT.md @@ -130,22 +132,22 @@ Verdict : **gate `0.2.8-pre.001` positif ; `pre.002` + `fix.001` et `pre.003` so ### 4.2 Invariants architecture -| Critère | Décision | Preuve cible | État | -|-------------------------------------|------------------------------------------------------------------|---------------------------------|--------| +| Critère | Décision | Preuve cible | État | +|-------------------------------------|------------------------------------------------------------------|---------------------------------|--------------------| | actor physique | un seul `WsSession` actor partagé | source/runtime canary | pre.002 implémenté | | façade standard | `SolanaStandardWsSession` | public API canary | pre.002 implémenté | | façade Helius | `HeliusLaserStreamWsSession` | public API canary | pre.002 implémenté | -| namespace LaserStream WS | `WsProtocolKind` + `ws_endpoints` possèdent `helius_laserstream` | API/Config/docs canary | pre.004 préparé | -| LaserStream gRPC | backend/type/Config distincts, hors `0.2.8` | absence de réutilisation WS | décidé | +| namespace LaserStream WS | `WsProtocolKind` + `ws_endpoints` possèdent `helius_laserstream` | API/Config/docs canary | pre.004 préparé | +| LaserStream gRPC | backend/type/Config distincts, hors `0.2.8` | absence de réutilisation WS | décidé | | escape hatch Helius | aucun `inner()`/`into_inner()` public | compile-fail/source canary | pre.002 implémenté | | generic Helius `WsSession::connect` | ne doit pas permettre de contourner la façade | invalid protocol pre-I/O canary | pre.002 implémenté | -| Helius unsupported | absent de la façade | compile-fail/API absence canary | pre.003 validé | -| standard Helius commun | délégation vers le même wire/actor | exact fixture | pre.003 validé | -| DTO duplication | seulement si wire/sémantique divergent | public/source audit | décidé | -| Config direction | Config -> Transport uniquement | ownership tests | pre.004 préparé | -| heartbeat | Helius-only, actor commun | deterministic timers | décidé | -| secret | query URL derrière `WsEndpointUrl` | redaction canaries | pre.004 préparé | -| new Rust dependency | aucune | manifest/tree audit | décidé | +| Helius unsupported | absent de la façade | compile-fail/API absence canary | pre.003 validé | +| standard Helius commun | délégation vers le même wire/actor | exact fixture | pre.003 validé | +| DTO duplication | seulement si wire/sémantique divergent | public/source audit | décidé | +| Config direction | Config -> Transport uniquement | ownership tests | pre.004 préparé | +| heartbeat | Helius-only, actor commun | deterministic timers | décidé | +| secret | query URL derrière `WsEndpointUrl` | redaction canaries | pre.004 préparé | +| new Rust dependency | aucune | manifest/tree audit | décidé | ## 5. Contrat `transactionSubscribe` à valider @@ -232,8 +234,8 @@ aucun payload brut dans logs/snapshots [x] KSP-TRANSPORT-007 inchangé — tests Transport/workspace verts [x] Config V1 HTTP-only backward readable — tests Config workspace verts [x] Config V2 solana_standard backward readable — tests Config workspace verts -[ ] Config V2 helius_laserstream mappe vers WsProtocolKind::HeliusLaserStream — pre.004 test ajouté, pending -[ ] schema V2 accepte helius_laserstream sans relâcher les autres contraintes — pre.004 fixture pending +[x] Config V2 helius_laserstream mappe vers WsProtocolKind::HeliusLaserStream — test pre.004 atteint cette assertion avant l'échec safe_value +[x] schema V2 accepte helius_laserstream sans relâcher les autres contraintes — fixture chargée par le test pre.004 [x] no Transport -> Config/Wallet/Store/Program/tracing direct — audits/tests ownership verts ``` @@ -241,8 +243,8 @@ aucun payload brut dans logs/snapshots ```text [x] api-key absente de Debug WsEndpointUrl — canaries héritées + pre.002 vert -[ ] KSP_SECRET_HELIUS_API_KEY redacted dans safe_value Config — pre.004 test ajouté, pending -[ ] KSP_SECRET_HELIUS_API_KEY absente de ResolvedTransportConfig Debug — pre.004 test ajouté, pending +[ ] KSP_SECRET_HELIUS_API_KEY redacted dans safe_value Config — comportement correct observé, attente du test corrigée par fix.001, checkpoint à rejouer +[ ] KSP_SECRET_HELIUS_API_KEY absente de ResolvedTransportConfig Debug — assertion située après le faux négatif, checkpoint fix.001 à rejouer [ ] api-key absente de Debug settings/session/subscription [ ] api-key absente des KspError safe contexts [ ] URL complète absente des snapshots @@ -293,16 +295,18 @@ La fixture Transport rapporte 314 tests unitaires verts, 38 tests public API ver Surface `pre.004` préparée : ```text -[ ] schema `ws_endpoints[].kind` accepte `helius_laserstream` -[ ] adapter Config mappe `helius_laserstream` vers `WsProtocolKind::HeliusLaserStream` -[ ] fixture Config matérialise un endpoint Helius typé -[ ] exemple Transport matérialise Helius mainnet sans credential réel -[ ] `.env.example` inventorie `KSP_SECRET_HELIUS_API_KEY` -[ ] interpolation du secret produit l'URL runtime Helius attendue -[ ] safe_value redige l'URL contenant l'api-key -[ ] Debug de `ResolvedTransportConfig` n'expose pas la clé -[ ] Config produit un endpoint composable avec `HeliusLaserStreamWsSession` -[ ] `config/std.transport.json` canonique reste standard-only +[x] schema `ws_endpoints[].kind` accepte `helius_laserstream` +[x] adapter Config mappe `helius_laserstream` vers `WsProtocolKind::HeliusLaserStream` +[x] fixture Config matérialise un endpoint Helius mainnet typé +[ ] fixture Config matérialise un profil Helius devnet distinct — ajouté par fix.001, checkpoint à rejouer +[x] exemple Transport matérialise Helius mainnet sans credential réel +[ ] exemple Transport matérialise Helius devnet dans un profil distinct — ajouté par fix.001, checkpoint à rejouer +[x] `.env.example` inventorie `KSP_SECRET_HELIUS_API_KEY` +[x] interpolation du secret produit l'URL runtime Helius attendue +[ ] safe_value conserve les littéraux Helius mainnet/devnet et redige uniquement l'api-key (`...api-key=********`) — fix.001 à rejouer +[ ] Debug de `ResolvedTransportConfig` n'expose pas la clé — assertion à rejouer après fix.001 +[x] Config produit un endpoint composable avec `HeliusLaserStreamWsSession` +[x] `config/std.transport.json` canonique reste standard-only ``` Aucun `transactionSubscribe`, heartbeat, changement du moteur WebSocket ou nouvelle dépendance n'est introduit dans cette tranche. @@ -333,7 +337,31 @@ Constats `pre.002-fix.001` : Aucun split en fichiers supplémentaires n'est retenu : les plans historiques `0.2.5`–`0.2.7` sont de taille comparable ou supérieure, et le contenu du plan `015` reste entièrement centré sur une seule release. Le problème identifié était **l'ordre interne et la duplication de responsabilités**, pas la nécessité d'un nouveau type de document. -## 12. Gate opérateur `pre.004` + +## 12. Gate opérateur `pre.004` / `fix.001` + +Premier passage `pre.004` reçu le 2026-08-23 : + +```text +[x] cargo fmt --all +[x] python3 scripts/audit_rust_workspace_rules.py = clean +[x] cargo check --workspace +[x] cargo clippy --workspace --all-targets +[ ] cargo test -p ksp-config-lib — 109/110 ; faux négatif safe_value Helius +[x] cargo test -p ksp-onchain-transport-lib — vert +[ ] cargo test --workspace — échoue uniquement sur le même test Config +``` + +Observation exacte : + +```text +observé = wss://mainnet.helius-rpc.com/?api-key=******** +attendu = ******** +``` + +L'observé est conforme au contrat historique du résolveur Config : dans une chaîne composée, les littéraux non sensibles restent visibles dans la projection sûre tandis que chaque placeholder secret est remplacé par `********`. Le fix ne modifie donc pas le runtime ; il corrige le canari pour attendre l'URL sûre segmentaire exacte. La revue du même checkpoint complète également la couverture Config avec un profil Helius Devnet distinct utilisant `wss://devnet.helius-rpc.com/?api-key=...`, afin que mainnet et devnet soient tous deux prouvés sans mélange de clusters. + +À rejouer après `pre.004-fix.001` : ```text [ ] cargo fmt --all @@ -345,4 +373,4 @@ Aucun split en fichiers supplémentaires n'est retenu : les plans historiques `0 [ ] cargo test --workspace ``` -Verdict courant : **`pre.003` DONE ; `pre.004` préparé, non déclaré `DONE` avant ce checkpoint.** +Verdict courant : **`pre.003` DONE ; `pre.004` fonctionnellement implémenté mais non fermé ; `pre.004-fix.001` PREPARED.**