diff --git a/Cargo.toml b/Cargo.toml index 08ca617..f11824a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,12 @@ # file: Cargo.toml -# version: 534 +# version: 535 [workspace] resolver = "3" members = ["crates/ksp-app-backfill-desk", "crates/ksp-app-config-desk", "crates/ksp-app-solprices-desk", "crates/ksp-app-store-desk", "crates/ksp-app-wallet-desk", "crates/ksp-config-lib", "crates/ksp-core-lib", "crates/ksp-interface-lib", "crates/ksp-job-api", "crates/ksp-job-backfill-lib", "crates/ksp-logging-lib", "crates/ksp-offchain-transport-lib", "crates/ksp-onchain-transport-lib", "crates/ksp-program-api", "crates/ksp-raw-transaction-lib", "crates/ksp-store-api", "crates/ksp-store-lib", "crates/ksp-store-postgres-lib", "crates/ksp-wallet-lib", "crates/ksp-worker-api", "crates/ksp-worker-raw-transaction-ingest-lib"] [workspace.package] -version = "0.3.12-pre.9.fix.1" +version = "0.3.12-pre.10" edition = "2024" license = "MIT" repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project" diff --git a/crates/ksp-worker-raw-transaction-ingest-lib/tests/cross_layer_completeness.rs b/crates/ksp-worker-raw-transaction-ingest-lib/tests/cross_layer_completeness.rs new file mode 100644 index 0000000..e22e5d9 --- /dev/null +++ b/crates/ksp-worker-raw-transaction-ingest-lib/tests/cross_layer_completeness.rs @@ -0,0 +1,192 @@ +// file: crates/ksp-worker-raw-transaction-ingest-lib/tests/cross_layer_completeness.rs +// version: 1 + +//! Cross-layer completeness and security canaries for `0.3.12-pre.010`. + +fn dependency_names(manifest: &str) -> std::vec::Vec<&str> { + let mut section = ""; + let mut names = std::vec::Vec::new(); + for line in manifest.lines() { + let trimmed = line.trim(); + if trimmed.starts_with('[') && trimmed.ends_with(']') { + section = trimmed; + continue; + } + if section != "[dependencies]" || trimmed.is_empty() || trimmed.starts_with('#') { + continue; + } + let name = match trimmed.split_once('=') { + std::option::Option::Some((name, _)) => name.trim().trim_end_matches(".workspace"), + std::option::Option::None => continue, + }; + names.push(name); + } + names.sort_unstable(); + return names; +} + +#[test] +fn v0_3_12_pre_010_dependency_firewall_is_exact_across_transport_worker_common_raw_store() { + let transport = dependency_names(include_str!("../../ksp-onchain-transport-lib/Cargo.toml")); + let worker = dependency_names(include_str!("../Cargo.toml")); + let common_raw = dependency_names(include_str!("../../ksp-raw-transaction-lib/Cargo.toml")); + let store_api = dependency_names(include_str!("../../ksp-store-api/Cargo.toml")); + let store = dependency_names(include_str!("../../ksp-store-lib/Cargo.toml")); + assert_eq!( + transport, + std::vec![ + "futures-util", + "http", + "ksp-core-lib", + "ksp-logging-lib", + "reqwest", + "serde", + "serde_json", + "tokio", + "tokio-tungstenite", + "tonic", + "tonic-prost", + "yellowstone-grpc-proto", + ] + ); + assert_eq!( + worker, + std::vec![ + "ksp-core-lib", + "ksp-logging-lib", + "ksp-onchain-transport-lib", + "ksp-raw-transaction-lib", + "ksp-store-lib", + "ksp-worker-api", + "sha2", + "tokio", + ] + ); + assert_eq!(common_raw, std::vec!["base64", "ksp-core-lib", "ksp-store-api", "serde_json", "sha2"]); + assert_eq!(store_api, std::vec!["ksp-core-lib"]); + assert_eq!(store, std::vec!["ksp-logging-lib", "ksp-store-api", "ksp-store-postgres-lib"]); + for forbidden in ["ksp-config-lib", "ksp-job-api", "ksp-job-backfill-lib", "ksp-store-lib", "ksp-worker-api", "ksp-worker-raw-transaction-ingest-lib"] { + assert!(!transport.contains(&forbidden), "Transport crossed upward dependency boundary: {forbidden}"); + } + for forbidden in [ + "ksp-config-lib", + "ksp-job-api", + "ksp-job-backfill-lib", + "ksp-store-api", + "ksp-store-postgres-lib", + "reqwest", + "tonic", + "yellowstone-grpc-proto", + ] { + assert!(!worker.contains(&forbidden), "Worker crossed direct lower/backend dependency boundary: {forbidden}"); + } + for forbidden in [ + "ksp-config-lib", + "ksp-job-api", + "ksp-job-backfill-lib", + "ksp-onchain-transport-lib", + "ksp-store-lib", + "ksp-store-postgres-lib", + "ksp-worker-api", + ] { + assert!(!common_raw.contains(&forbidden), "Common RAW crossed dependency boundary: {forbidden}"); + } + for forbidden in ["ksp-config-lib", "ksp-onchain-transport-lib", "ksp-raw-transaction-lib", "ksp-store-lib", "ksp-store-postgres-lib", "ksp-worker-api"] { + assert!(!store_api.contains(&forbidden), "Store API crossed dependency boundary: {forbidden}"); + } + for forbidden in ["ksp-config-lib", "ksp-job-api", "ksp-job-backfill-lib", "ksp-onchain-transport-lib", "ksp-raw-transaction-lib", "ksp-worker-api"] { + assert!(!store.contains(&forbidden), "Store facade crossed dependency boundary: {forbidden}"); + } + return; +} + +#[test] +fn v0_3_12_pre_010_legacy_v0_fixture_matrix_is_exact_across_transport_worker_and_common_raw() { + let worker = include_str!("../unit_tests/runtime_resources.rs"); + let common_raw_wire = include_str!("../../ksp-raw-transaction-lib/unit_tests/wire.rs"); + let transport = include_str!("../../ksp-onchain-transport-lib/unit_tests/rpc_transactions.rs"); + for required in [ + "pre_004_observed_get_transaction_closes_signal_to_common_raw_ingress_with_composite_provenance", + "pre_004_finalized_hydration_preserves_request_and_provenance_commitment", + "pre_004_v0_null_and_omitted_wire_fields_preserve_common_raw_semantics", + r#"\"version\":\"legacy\""#, + r#"\"version\":0"#, + ] { + assert!(worker.contains(required), "Worker Legacy/V0 fixture missing: {required}"); + } + for required in [ + "LEGACY_GOLDEN_BASE64", + "V0_GOLDEN_BASE64", + "pre_006_legacy_v0_and_v1_wire_goldens_are_exact", + "RawSolanaMessageVersion::Legacy", + "RawSolanaMessageVersion::V0", + ] { + assert!(common_raw_wire.contains(required), "Common RAW Legacy/V0 golden missing: {required}"); + } + for required in [ + "confirmed_transaction_fixture_preserves_meta_version_and_transaction_index_states", + "typed_get_transaction_modern_covers_all_agave_v4_2_1_encoding_labels_and_response_shapes", + "SolanaTransactionVersion::Legacy", + ] { + assert!(transport.contains(required), "Transport getTransaction fixture missing: {required}"); + } + return; +} + +#[test] +fn v0_3_12_pre_010_redaction_scanner_matrix_is_present_across_all_layers() { + let transport_subscribe = include_str!("../../ksp-onchain-transport-lib/unit_tests/grpc_subscribe.rs"); + let transport_unary = include_str!("../../ksp-onchain-transport-lib/unit_tests/grpc_unary.rs"); + let worker = include_str!("hardening.rs"); + let common_raw = include_str!("../../ksp-raw-transaction-lib/unit_tests/canonical.rs"); + let store_api = include_str!("../../ksp-store-api/tests/security_hardening.rs"); + let store = include_str!("../../ksp-store-lib/tests/hardening_completeness.rs"); + assert!(transport_subscribe.contains("yellowstone_subscribe_debug_omits_filter_names_and_future_payloads")); + assert!(transport_unary.contains("yellowstone_remote_status_does_not_copy_message_details_or_metadata")); + for required in [ + "pre_010_debug_and_settings_errors_redact_worker_identity_and_invalid_values", + "v0_3_12_pre_003_private_signal_debug_and_shape_do_not_expose_signature_filters_or_payload", + "v0_3_12_pre_004_hydration_provenance_and_remote_material_are_bounded_and_redacted", + "v0_3_12_pre_008_reconnect_projection_is_source_neutral_bounded_and_contains_no_replay_material", + "v0_3_12_pre_009_hydration_retry_ownership_and_no_orphan_cleanup_are_explicit", + ] { + assert!(worker.contains(required), "Worker security scanner missing: {required}"); + } + assert!(common_raw.contains("pre_002_material_and_wire_debug_do_not_render_transaction_or_meta_material")); + assert!(store_api.contains("pre_007_raw_debug_surfaces_do_not_render_payload_hash_signature_or_account_bytes")); + assert!(store.contains("pre_009_secret_canary_never_crosses_settings_or_pre_io_error_debug")); + return; +} + +#[test] +fn v0_3_12_pre_010_public_roots_keep_implementation_modules_private() { + let roots = [ + ("transport", include_str!("../../ksp-onchain-transport-lib/src/lib.rs")), + ("worker", include_str!("../src/lib.rs")), + ("common_raw", include_str!("../../ksp-raw-transaction-lib/src/lib.rs")), + ("store_api", include_str!("../../ksp-store-api/src/lib.rs")), + ("store", include_str!("../../ksp-store-lib/src/lib.rs")), + ]; + for (layer, root) in roots { + assert!(!root.contains("pub mod "), "public implementation module leaked from {layer}"); + } + let worker = include_str!("../src/lib.rs"); + for line in worker.lines() { + let trimmed = line.trim(); + if !trimmed.starts_with("pub use ") { + continue; + } + for forbidden in [ + "RawTransactionAdmission", + "RawTransactionIngress", + "RawTransactionIngestPersistencePort", + "JoinHandle", + "JoinSet", + "HttpTransportPool", + "SolanaYellowstoneGrpcSubscribeSession", + ] { + assert!(!trimmed.contains(forbidden), "Worker implementation type leaked publicly: {forbidden}"); + } + } + return; +} diff --git a/crates/ksp-worker-raw-transaction-ingest-lib/tests/release_completeness.rs b/crates/ksp-worker-raw-transaction-ingest-lib/tests/release_completeness.rs index 613af4b..45c3445 100644 --- a/crates/ksp-worker-raw-transaction-ingest-lib/tests/release_completeness.rs +++ b/crates/ksp-worker-raw-transaction-ingest-lib/tests/release_completeness.rs @@ -1,5 +1,5 @@ // file: crates/ksp-worker-raw-transaction-ingest-lib/tests/release_completeness.rs -// version: 8 +// version: 9 //! Release-completeness canaries through the `pre.010` public/release/security hardening tranche. @@ -109,6 +109,7 @@ fn pre_010_external_hardening_suite_is_present_and_scoped() { "v0_3_12_pre_006_source_coalescence_is_bounded_stop_preemptible_and_redacted", "v0_3_12_pre_007_processing_frontier_is_bounded_processing_only_and_redacted", "v0_3_12_pre_008_reconnect_projection_is_source_neutral_bounded_and_contains_no_replay_material", + "v0_3_12_pre_009_hydration_retry_ownership_and_no_orphan_cleanup_are_explicit", "pre_010_lower_layers_have_no_dependency_return_to_concrete_worker", "v0_3_12_pre_002_public_root_exposes_contract_types_without_transport_implementation_paths", ] { @@ -134,3 +135,45 @@ fn pre_010_external_hardening_suite_is_present_and_scoped() { assert!(public_api.contains("pre_008_snapshot_surface_and_common_projection_are_public_and_stable")); return; } + +#[test] +fn v0_3_12_pre_010_cross_layer_completeness_suite_is_present_and_exact() -> std::io::Result<()> { + let test_root = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("tests"); + let entries = match std::fs::read_dir(test_root) { + std::result::Result::Ok(value) => value, + std::result::Result::Err(error) => return std::result::Result::Err(error), + }; + let mut names = std::vec::Vec::new(); + for entry in entries { + let entry = match entry { + std::result::Result::Ok(value) => value, + std::result::Result::Err(error) => return std::result::Result::Err(error), + }; + let file_type = match entry.file_type() { + std::result::Result::Ok(value) => value, + std::result::Result::Err(error) => return std::result::Result::Err(error), + }; + if !file_type.is_file() { + continue; + } + let name = match entry.file_name().into_string() { + std::result::Result::Ok(value) => value, + std::result::Result::Err(_) => continue, + }; + if name.ends_with(".rs") { + names.push(name); + } + } + names.sort_unstable(); + assert_eq!(names, std::vec!["cross_layer_completeness.rs", "dependency_boundary.rs", "hardening.rs", "public_api.rs", "release_completeness.rs"]); + let cross_layer = include_str!("cross_layer_completeness.rs"); + for required in [ + "v0_3_12_pre_010_dependency_firewall_is_exact_across_transport_worker_common_raw_store", + "v0_3_12_pre_010_legacy_v0_fixture_matrix_is_exact_across_transport_worker_and_common_raw", + "v0_3_12_pre_010_redaction_scanner_matrix_is_present_across_all_layers", + "v0_3_12_pre_010_public_roots_keep_implementation_modules_private", + ] { + assert!(cross_layer.contains(required), "required pre.010 cross-layer canary missing: {required}"); + } + return std::result::Result::Ok(()); +} diff --git a/deltas/0.3.12/pre.010.md b/deltas/0.3.12/pre.010.md new file mode 100644 index 0000000..e9f66ff --- /dev/null +++ b/deltas/0.3.12/pre.010.md @@ -0,0 +1,68 @@ + + + +# Delta `0.3.12-pre.010` + +## Base + +`0.3.12-pre.009-fix.001`. + +## Objectif + +Fermer la tranche `pre.010` par un audit cross-layer déterministe de complétude et de sécurité entre Transport, Worker RawTransaction, Common RAW et Store, sans ajouter de comportement runtime. + +## Fichiers ajoutés + +- `crates/ksp-worker-raw-transaction-ingest-lib/tests/cross_layer_completeness.rs` ; +- `deltas/0.3.12/pre.010.md`. + +## Fichiers modifiés + +- `Cargo.toml` ; +- `crates/ksp-worker-raw-transaction-ingest-lib/tests/release_completeness.rs` ; +- `docs/validation/029-V0_3_12_YELLOWSTONE_HYDRATION_CONTINUITY.md`. + +## Fichiers supprimés + +Aucun. + +## Décisions + +- la version workspace devient `0.3.12-pre.10` ; +- aucun fichier Rust de production n'est modifié ; +- le firewall de dépendances est vérifié sur les manifests Transport, Worker, Common RAW, Store API et Store façade ; +- les fixtures Legacy/V0 déjà matérialisées dans Transport/Worker/Common RAW deviennent une matrice de complétude explicitement vérifiée ; +- les scanners/redaction déjà présents dans chaque couche sont vérifiés comme matrice de sécurité cross-layer ; +- l'inventaire public Worker reste strictement inchangé ; +- aucun nouveau comportement de reconnect, replay, hydration, persistence, repair ou checkpoint n'est introduit. + +## Validations exécutées dans l'environnement d'assemblage + +- `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` ; +- canaris statiques `pre.010` ; +- vérification d'inventaire du delta ; +- `unzip -t` ; +- reproduction byte-à-byte du delta sur `0.3.12-pre.009-fix.001`. + +## Validations non exécutées localement + +`cargo`, `rustc` et `rustfmt` ne sont pas installés dans l'environnement d'assemblage. Aucun PASS Cargo local n'est revendiqué. + +## Gate opérateur requis + +```bash +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 +cargo check --workspace +cargo clippy --workspace --all-targets --all-features -- -D warnings +cargo test -p ksp-onchain-transport-lib +cargo test -p ksp-raw-transaction-lib +cargo test -p ksp-store-api +cargo test -p ksp-store-lib --no-default-features +cargo test -p ksp-worker-raw-transaction-ingest-lib +cargo tree -p ksp-worker-raw-transaction-ingest-lib --edges normal +cargo tree -p ksp-worker-raw-transaction-ingest-lib -e features +cargo tree --duplicates +``` diff --git a/docs/validation/029-V0_3_12_YELLOWSTONE_HYDRATION_CONTINUITY.md b/docs/validation/029-V0_3_12_YELLOWSTONE_HYDRATION_CONTINUITY.md index 7eb3e3a..36a04ac 100644 --- a/docs/validation/029-V0_3_12_YELLOWSTONE_HYDRATION_CONTINUITY.md +++ b/docs/validation/029-V0_3_12_YELLOWSTONE_HYDRATION_CONTINUITY.md @@ -1,5 +1,5 @@ - + # Validation v0.3.12 — Yellowstone + hydration HTTP + continuité de run du Worker RawTransaction @@ -1857,3 +1857,69 @@ cargo test -p ksp-onchain-transport-lib cargo test -p ksp-worker-raw-transaction-ingest-lib ``` +## 78. Gate opérateur `pre.009-fix.001` + +Le gate opérateur communiqué pour `0.3.12-pre.9.fix.1` est entièrement vert : + +```text +General Rust rule audit : clean +Rust export completeness audit : 0 candidate(s) +KSP workspace Rust rule audit : clean +Markdown table audit : clean (340 tables, 819 fichiers) +cargo check --workspace : PASS +cargo clippy --workspace --all-targets --all-features -- -D warnings : PASS +ksp-onchain-transport-lib : 388 unit PASS, 51 public_api PASS, 43 release_completeness PASS, doc-tests PASS +ksp-worker-raw-transaction-ingest-lib : 66 unit PASS, 9 dependency_boundary PASS, 16 hardening PASS, 9 public_api PASS, 3 release_completeness PASS +``` + +Les smokes réseau restent `ignored` et operator-only. `pre.009-fix.001` devient la base autoritaire de `pre.010`. + +## 79. Audit cross-layer completeness/security `pre.010` + +`pre.010` n'ajoute aucun comportement runtime. La tranche matérialise les preuves de complétude et de sécurité entre : + +```text +ksp-onchain-transport-lib +-> ksp-worker-raw-transaction-ingest-lib +-> ksp-raw-transaction-lib +-> ksp-store-lib / ksp-store-api +``` + +Les canaris ajoutés couvrent : + +```text +firewall exact des dépendances normales de chaque couche +absence d'edge Worker direct vers Config, Job, Store API/backend, reqwest, tonic ou proto +Common RAW dépend uniquement de Core + Store API + primitives de canonicalisation +Store API reste Core-only ; Store façade reste backend-neutral côté consommateurs +fixtures Legacy/V0 présentes de Transport à Worker puis Common RAW +wire goldens Legacy/V0 Common RAW présents et exécutables par gate ciblé +matrice de redaction Transport/Worker/Common RAW/Store présente +aucun pub mod sur les cinq racines concernées +aucun type d'implémentation Worker ajouté à la surface publique +inventaire des fichiers d'intégration Worker exact +inventaire des exports publics Worker inchangé +``` + +Aucune modification de reconnect/replay, frontier, hydration, admission, persistence, provenance ou Store n'est introduite. + +Le gate opérateur `pre.010` doit inclure les couches réellement auditées : + +```bash +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 +cargo check --workspace +cargo clippy --workspace --all-targets --all-features -- -D warnings +cargo test -p ksp-onchain-transport-lib +cargo test -p ksp-raw-transaction-lib +cargo test -p ksp-store-api +cargo test -p ksp-store-lib --no-default-features +cargo test -p ksp-worker-raw-transaction-ingest-lib +cargo tree -p ksp-worker-raw-transaction-ingest-lib --edges normal +cargo tree -p ksp-worker-raw-transaction-ingest-lib -e features +cargo tree --duplicates +``` + +Dans l'environnement d'assemblage, `cargo`, `rustc` et `rustfmt` ne sont pas installés ; aucun gate Cargo local n'est revendiqué. +