From 7377a6f6cd4dd9d5635a194fe243efb41dc915a1 Mon Sep 17 00:00:00 2001 From: SinuS Von SifriduS Date: Mon, 31 Aug 2026 11:17:09 +0200 Subject: [PATCH] v0.3.5-pre.005 --- Cargo.toml | 2 +- .../tests/dependency_boundary.rs | 13 +- .../tests/security_hardening.rs | 100 +++++++++++++ deltas/0.3.5/pre.005.md | 138 ++++++++++++++++++ ...022-V0_3_5_INTERFACE_ACQUISITION_EVENTS.md | 117 ++++++++++++++- 5 files changed, 366 insertions(+), 4 deletions(-) create mode 100644 crates/ksp-interface-lib/tests/security_hardening.rs create mode 100644 deltas/0.3.5/pre.005.md diff --git a/Cargo.toml b/Cargo.toml index a252323..0c6be34 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ resolver = "3" members = ["crates/ksp-app-config-desk", "crates/ksp-app-solprices-desk", "crates/ksp-app-wallet-desk", "crates/ksp-config-lib", "crates/ksp-core-lib", "crates/ksp-interface-lib", "crates/ksp-logging-lib", "crates/ksp-offchain-transport-lib", "crates/ksp-onchain-transport-lib", "crates/ksp-program-api", "crates/ksp-store-api", "crates/ksp-store-lib", "crates/ksp-store-postgres-lib", "crates/ksp-wallet-lib"] [workspace.package] -version = "0.3.5-pre.4" +version = "0.3.5-pre.5" edition = "2024" license = "MIT" repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project" diff --git a/crates/ksp-interface-lib/tests/dependency_boundary.rs b/crates/ksp-interface-lib/tests/dependency_boundary.rs index 7a60ed8..2494e7e 100644 --- a/crates/ksp-interface-lib/tests/dependency_boundary.rs +++ b/crates/ksp-interface-lib/tests/dependency_boundary.rs @@ -1,5 +1,5 @@ // file: crates/ksp-interface-lib/tests/dependency_boundary.rs -// version: 6 +// version: 7 //! Dependency and passive-surface canaries for the Interface foundation. @@ -159,3 +159,14 @@ fn v0_3_5_pre_004_acquisition_sources_remain_provider_neutral_and_runtime_free() } return; } + +#[test] +fn v0_3_5_pre_005_manifest_keeps_exact_core_only_graph_without_features_or_hidden_dependency_sections() { + let manifest = include_str!("../Cargo.toml"); + assert!(!manifest.contains("[features]")); + assert!(!manifest.contains("[dev-dependencies]")); + assert!(!manifest.contains("[build-dependencies]")); + assert_eq!(manifest.matches("ksp-core-lib").count(), 1); + assert_eq!(manifest.matches("[dependencies]").count(), 1); + return; +} diff --git a/crates/ksp-interface-lib/tests/security_hardening.rs b/crates/ksp-interface-lib/tests/security_hardening.rs new file mode 100644 index 0000000..0895226 --- /dev/null +++ b/crates/ksp-interface-lib/tests/security_hardening.rs @@ -0,0 +1,100 @@ +// file: crates/ksp-interface-lib/tests/security_hardening.rs +// version: 1 + +//! Adversarial and ownership-hardening canaries for passive Interface acquisition events. + +const HOSTILE_MARKER: &str = "INTERFACE-ACQUISITION-SECRET-CANARY"; + +#[test] +fn v0_3_5_pre_005_signature_and_event_debug_never_render_signature_bytes() { + let mut bytes = [0x41_u8; 64]; + bytes[..HOSTILE_MARKER.len()].copy_from_slice(HOSTILE_MARKER.as_bytes()); + let signature = ksp_interface_lib::TransactionSignature::new(bytes); + assert_eq!(signature.as_bytes(), &bytes); + let signature_debug = std::format!("{signature:?}"); + assert_eq!(signature_debug, "TransactionSignature(..)"); + assert!(!signature_debug.contains(HOSTILE_MARKER)); + let event = ksp_interface_lib::TransactionExecutionEvent::new(u64::MAX, signature, ksp_interface_lib::TransactionExecutionOutcome::Failed); + let event_debug = std::format!("{event:?}"); + assert!(event_debug.contains("TransactionExecutionEvent")); + assert!(event_debug.contains("18446744073709551615")); + assert!(event_debug.contains("Failed")); + assert!(!event_debug.contains(HOSTILE_MARKER)); + return; +} + +#[test] +fn v0_3_5_pre_005_acquisition_structs_keep_exact_minimal_fields_without_payload_or_source_metadata() { + let lifecycle_source = include_str!("../src/slot_lifecycle.rs"); + let execution_source = include_str!("../src/transaction_execution.rs"); + assert!(lifecycle_source.contains("pub struct SlotLifecycleEvent {\n slot: u64,\n stage: SlotLifecycleStage,\n}")); + assert!(execution_source.contains("pub struct TransactionSignature([u8; 64]);")); + assert!(execution_source.contains( + "pub struct TransactionExecutionEvent {\n slot: u64,\n signature: TransactionSignature,\n outcome: TransactionExecutionOutcome,\n}" + )); + for source in [lifecycle_source, execution_source] { + for forbidden in [ + "std::vec::Vec<", + "std::string::String", + "Box<", + "serde_json::Value", + "timestamp:", + "provider_id:", + "endpoint:", + "filter:", + "network:", + "payload:", + ] { + assert!(!source.contains(forbidden), "forbidden acquisition field/surface detected: {forbidden}"); + } + } + return; +} + +#[test] +fn v0_3_5_pre_005_interface_exports_no_second_raw_or_deferred_event_family() { + let crate_root = include_str!("../src/lib.rs"); + for forbidden in [ + "RawTransaction", + "RawAccount", + "RawPayload", + "RawPageCursor", + "RawRetention", + "RawObservation", + "TransactionLogEvent", + "TransactionCommitmentEvent", + "LedgerEntryEvent", + "VoteEvent", + "BlockEvent", + ] { + assert!(!crate_root.contains(forbidden), "forbidden Interface export detected: {forbidden}"); + } + return; +} + +#[test] +fn v0_3_5_pre_005_program_instruction_foundation_remains_bounded_and_unchanged() { + assert_eq!(ksp_interface_lib::MAX_PROGRAM_INSTRUCTION_ACCOUNTS, 255); + assert_eq!(ksp_interface_lib::MAX_PROGRAM_INSTRUCTION_DATA_LEN, 10_240); + let program_id = ksp_interface_lib::Pubkey::new_from_array([0xD1_u8; 32]); + let account = ksp_interface_lib::ProgramAccountMeta::readonly(ksp_interface_lib::Pubkey::new_from_array([0xD2_u8; 32]), false); + let admitted = ksp_interface_lib::ProgramInstruction::try_new( + program_id, + std::vec![account; ksp_interface_lib::MAX_PROGRAM_INSTRUCTION_ACCOUNTS], + std::vec![0x5A_u8; ksp_interface_lib::MAX_PROGRAM_INSTRUCTION_DATA_LEN], + ); + assert!(admitted.is_ok()); + let admitted = match admitted { + std::result::Result::Ok(value) => value, + std::result::Result::Err(_) => return, + }; + assert_eq!(admitted.accounts().len(), ksp_interface_lib::MAX_PROGRAM_INSTRUCTION_ACCOUNTS); + assert_eq!(admitted.data().len(), ksp_interface_lib::MAX_PROGRAM_INSTRUCTION_DATA_LEN); + let too_many_accounts = + ksp_interface_lib::ProgramInstruction::try_new(program_id, std::vec![account; ksp_interface_lib::MAX_PROGRAM_INSTRUCTION_ACCOUNTS + 1], std::vec![]); + assert!(too_many_accounts.is_err()); + let oversized_data = + ksp_interface_lib::ProgramInstruction::try_new(program_id, std::vec![], std::vec![0x5A_u8; ksp_interface_lib::MAX_PROGRAM_INSTRUCTION_DATA_LEN + 1]); + assert!(oversized_data.is_err()); + return; +} diff --git a/deltas/0.3.5/pre.005.md b/deltas/0.3.5/pre.005.md new file mode 100644 index 0000000..f1218c6 --- /dev/null +++ b/deltas/0.3.5/pre.005.md @@ -0,0 +1,138 @@ + + + +# Delta `0.3.5-pre.005` — hardening et complétude Interface + +## Base requise + +```text +0.3.5-pre.4 +``` + +Le gate opérateur de `pre.004` est entièrement propre : audits Rust/Markdown, `cargo check --workspace`, Clippy, tests `ksp-interface-lib` et `ksp-program-api` passent. + +## Version + +La tranche ajoute/modifie des sources Rust de test/canari. La version workspace devient : + +```text +0.3.5-pre.5 +``` + +## Mission + +Fermer le hardening fonctionnel de `0.3.5` sans ajouter de troisième famille Interface ni modifier les contrats de production admis : + +```text +SlotLifecycleEvent / SlotLifecycleStage +TransactionExecutionEvent / TransactionExecutionOutcome / TransactionSignature +``` + +## Hardening adversarial + +Le nouveau `tests/security_hardening.rs` vérifie : + +- conservation byte-exact d'une signature hostile de 64 octets ; +- redaction de la signature dans son `Debug` et dans celui de `TransactionExecutionEvent` ; +- conservation de `u64::MAX` sans narrowing ; +- structure minimale exacte des deux events ; +- absence de collection/payload/timestamp/provider/endpoint/filter/network dans les contrats acquisition ; +- absence de second RAW ou de famille reportée exportée silencieusement ; +- non-régression des bornes `ProgramInstruction` historiques. + +## Graphe et dépendances + +`tests/dependency_boundary.rs` ajoute un canari final imposant : + +```text +une seule section [dependencies] +exactement une référence ksp-core-lib +aucune [features] +aucune [dev-dependencies] +aucune [build-dependencies] +``` + +Le manifeste `ksp-interface-lib` reste inchangé et Core-only. + +## Candidats reportés + +Aucun candidat reporté n'est promu par hardening : + +```text +TransactionLogEvent -> idée différée +TransactionCommitmentEvent -> reporté +VoteEvent -> reporté +LedgerEntryEvent -> reporté +Account/Program RAW event -> rejet Interface +Transaction complète -> rejet Interface +Block event -> rejet Interface +Persisted-data available -> Store API owner +``` + +`TransactionLogEvent` devra être transféré vers TODO/IDEAS durable pendant `pre.007` s'il reste hors scope. + +## Fichiers + +Modifiés : + +```text +Cargo.toml +crates/ksp-interface-lib/tests/dependency_boundary.rs +docs/validation/022-V0_3_5_INTERFACE_ACQUISITION_EVENTS.md +``` + +Ajoutés : + +```text +crates/ksp-interface-lib/tests/security_hardening.rs +deltas/0.3.5/pre.005.md +``` + +Explicitement inchangés : + +```text +crates/ksp-interface-lib/Cargo.toml +crates/ksp-interface-lib/src/** +crates/ksp-interface-lib/unit_tests/** +crates/ksp-onchain-transport-lib/** +crates/ksp-store-api/** +crates/ksp-store-lib/** +crates/ksp-store-postgres-lib/** +crates/ksp-program-api/** +README.md +ROADMAP.md +CHANGELOG.md +``` + +## Validations exécutées dans l'environnement d'assemblage + +```text +python3 scripts/audit_rust_workspace_rules.py +python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.3.5 +``` + +## Validations non exécutées dans l'environnement d'assemblage + +`cargo` n'est pas installé dans le sandbox d'assemblage. Restent donc à exécuter côté opérateur : + +```text +cargo fmt --all +cargo check --workspace +cargo clippy --workspace --all-targets +cargo test -p ksp-interface-lib +cargo test -p ksp-program-api +``` + +## Décisions + +- deux familles acquisition exactement restent admises ; +- aucun contrat production n'est modifié ; +- aucun nouveau bound métier n'est inventé ; +- la signature reste une primitive passive fixe de 64 octets sans codec ; +- aucune metadata source/provider n'entre dans Interface ; +- aucun second RAW n'est créé ; +- Program instruction foundation reste inchangée. + +## Questions ouvertes + +Aucune question fonctionnelle bloquante pour `pre.006`. La seule idée différée explicitement à conserver durablement est `TransactionLogEvent`. diff --git a/docs/validation/022-V0_3_5_INTERFACE_ACQUISITION_EVENTS.md b/docs/validation/022-V0_3_5_INTERFACE_ACQUISITION_EVENTS.md index c5972be..f0c234a 100644 --- a/docs/validation/022-V0_3_5_INTERFACE_ACQUISITION_EVENTS.md +++ b/docs/validation/022-V0_3_5_INTERFACE_ACQUISITION_EVENTS.md @@ -1,11 +1,11 @@ - + # Validation `0.3.5` — Interface passive acquisition events ## 1. Portée -Ce document est ouvert par `0.3.5-pre.001`, corrigé par `0.3.5-pre.001-fix.001`, enrichi par `0.3.5-pre.002`, `pre.003` puis `pre.004`. `pre.002` matérialise `SlotLifecycleEvent`; `pre.003` ferme le gate `TransactionExecutionEvent` et admet la seconde famille passive minimale ; `pre.004` verrouille les canaris externes et la complétude de cette surface sans ajouter de contrat de production. +Ce document est ouvert par `0.3.5-pre.001`, corrigé par `0.3.5-pre.001-fix.001`, enrichi par `0.3.5-pre.002`, `pre.003`, `pre.004` puis `pre.005`. `pre.002` matérialise `SlotLifecycleEvent`; `pre.003` ferme le gate `TransactionExecutionEvent` et admet la seconde famille passive minimale ; `pre.004` verrouille les canaris externes et la complétude de cette surface sans ajouter de contrat de production ; `pre.005` ajoute le hardening adversarial et les canaris anti-duplication finaux, toujours sans nouvelle surface de production. Base : @@ -637,3 +637,116 @@ cargo test -p ksp-program-api ``` Les gates Cargo de `pre.004` restent à exécuter par l'opérateur dans le repository réel. + +## 28. Gate opérateur `pre.004` + +Le gate opérateur du `2026-08-31` est intégralement propre : + +```text +General Rust rule audit: clean +Rust export completeness audit: 0 candidate(s) +KSP workspace Rust rule audit: clean +Markdown table audit: clean (240 table(s), 142 file(s)) +cargo check --workspace: PASS +cargo clippy --workspace --all-targets: PASS +cargo test -p ksp-interface-lib: PASS +cargo test -p ksp-program-api: PASS +``` + +`ksp-interface-lib` exécute alors seize tests unitaires, cinq canaris de dependency boundary, deux canaris external consumer, quatre canaris de release completeness et les quatre tests publics des deux familles acquisition. `ksp-program-api` reste vert sans changement de contrat. + +## 29. Hardening final Interface — `pre.005` + +`pre.005` n'ajoute aucun type ni champ de production. La version workspace évolue vers `0.3.5-pre.5` parce que la tranche ajoute/modifie des sources Rust de test/canari. + +Le hardening verrouille explicitement : + +```text +TransactionSignature = exactement 64 octets déjà décodés +Debug TransactionSignature = redacted +Debug TransactionExecutionEvent = aucune signature brute +SlotLifecycleEvent = exactement slot + stage +TransactionExecutionEvent = exactement slot + signature + outcome +aucun Vec/String/Box/payload/timestamp/provider/endpoint/filter/network dans les events acquisition +aucun second RAW exporté depuis Interface +aucune famille deferred promue silencieusement +manifest Interface = Core-only, sans features/dev/build dependencies +ProgramInstruction foundation = bornes historiques inchangées +``` + +Le canari adversarial injecte une signature contenant un marqueur hostile lisible et vérifie que les octets exacts restent accessibles par `as_bytes()` tout en restant absents des surfaces `Debug`. L'event d'exécution conserve `u64::MAX` sans narrowing. + +Le contrôle anti-persistence interdit explicitement dans la façade Interface les familles `RawTransaction`, `RawAccount`, payload/cursor/retention/observation RAW. Interface conserve uniquement des faits event-only compacts. + +Le graphe reste : + +```text +ksp-interface-lib +└── ksp-core-lib +``` + +Le manifeste ne possède toujours ni `[features]`, ni `[dev-dependencies]`, ni `[build-dependencies]`. Aucun `serde`, codec, logging, runtime, Transport ou Store n'est ajouté. + +## 30. Inventaire des candidats reportés après hardening + +La clôture fonctionnelle de `pre.005` conserve exactement deux familles acquisition admises. Les autres candidats restent : + +```text +TransactionLogEvent -> idée différée ; aucun type 0.3.5 +TransactionCommitmentEvent -> reporté ; signatureSubscribe/getSignatureStatuses ne sont pas fusionnés +VoteEvent -> reporté ; vote gossip != transaction is_vote +LedgerEntryEvent -> reporté ; Yellowstone Entry reste mono-producer/protocol-specific +Account/Program event RAW -> rejet Interface ; Store/Transport owner +Transaction complète -> rejet Interface ; RawTransaction/Transport owner +Block event -> rejet Interface ; Transport/acquisition container +Persisted-data available -> rejet Interface ; Store API notification owner +``` + +`TransactionExecutionEvent` n'est plus un candidat reporté : il est admis depuis `pre.003`. `TransactionLogEvent` reste l'idée différée à transférer vers la surface TODO/IDEAS durable pendant la réconciliation documentaire `pre.007` si elle demeure hors scope. + +## 31. Fichiers de `pre.005` + +Modifiés : + +```text +Cargo.toml +crates/ksp-interface-lib/tests/dependency_boundary.rs +docs/validation/022-V0_3_5_INTERFACE_ACQUISITION_EVENTS.md +``` + +Ajoutés : + +```text +crates/ksp-interface-lib/tests/security_hardening.rs +deltas/0.3.5/pre.005.md +``` + +Explicitement inchangés : + +```text +crates/ksp-interface-lib/Cargo.toml +crates/ksp-interface-lib/src/** +crates/ksp-interface-lib/unit_tests/** +crates/ksp-onchain-transport-lib/** +crates/ksp-store-api/** +crates/ksp-store-lib/** +crates/ksp-store-postgres-lib/** +crates/ksp-program-api/** +README.md +ROADMAP.md +CHANGELOG.md +``` + +## 32. Gate opérateur demandé pour `pre.005` + +```text +cargo fmt --all +python3 scripts/audit_rust_workspace_rules.py +python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.3.5 +cargo check --workspace +cargo clippy --workspace --all-targets +cargo test -p ksp-interface-lib +cargo test -p ksp-program-api +``` + +Les gates Cargo de `pre.005` restent à exécuter par l'opérateur dans le repository réel.