diff --git a/Cargo.toml b/Cargo.toml index 7b52a37..9f326c4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,12 @@ # file: Cargo.toml -# version: 87 +# version: 88 [workspace] resolver = "3" members = ["crates/ksp-app-config-desk", "crates/ksp-config-lib", "crates/ksp-core-lib", "crates/ksp-logging-lib"] [workspace.package] -version = "0.1.4-pre.16.fix.1" +version = "0.1.4-pre.16.fix.2" edition = "2024" license = "MIT" repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project" diff --git a/crates/ksp-logging-lib/tests/ownership.rs b/crates/ksp-logging-lib/tests/ownership.rs index 77b4096..6a69d1b 100644 --- a/crates/ksp-logging-lib/tests/ownership.rs +++ b/crates/ksp-logging-lib/tests/ownership.rs @@ -1,8 +1,73 @@ // file: crates/ksp-logging-lib/tests/ownership.rs -// version: 1 +// version: 2 //! Integration audit ensuring KSP crates do not bypass the logging facade. +fn manifest_declares_direct_dependency(manifest: &str, dependency_name: &str) -> bool { + let mut section = ""; + for raw_line in manifest.lines() { + let line = raw_line.trim(); + if line.starts_with('[') && line.ends_with(']') { + section = &line[1..line.len() - 1]; + let direct_table_suffix = std::format!(".dependencies.{dependency_name}"); + if section == std::format!("dependencies.{dependency_name}") + || section == std::format!("dev-dependencies.{dependency_name}") + || section == std::format!("build-dependencies.{dependency_name}") + || section.ends_with(direct_table_suffix.as_str()) + { + return true; + } + continue; + } + if line.is_empty() || line.starts_with('#') { + continue; + } + let dependency_section = section == "dependencies" + || section == "dev-dependencies" + || section == "build-dependencies" + || section.ends_with(".dependencies") + || section.ends_with(".dev-dependencies") + || section.ends_with(".build-dependencies"); + if !dependency_section { + continue; + } + let assignment = line.split_once('='); + let name = match assignment { + std::option::Option::Some((name, _)) => name.trim(), + std::option::Option::None => continue, + }; + if name == dependency_name || name == std::format!("{dependency_name}.workspace") { + return true; + } + } + return false; +} + +fn source_uses_direct_path(source: &str, path: &str) -> bool { + let mut search_start = 0usize; + while search_start < source.len() { + let remaining = &source[search_start..]; + let relative_index = match remaining.find(path) { + std::option::Option::Some(index) => index, + std::option::Option::None => return false, + }; + let index = search_start + relative_index; + if index == 0 { + return true; + } + let previous = source[..index].chars().next_back(); + let embedded_in_identifier = match previous { + std::option::Option::Some(character) => character.is_ascii_alphanumeric() || character == '_', + std::option::Option::None => false, + }; + if !embedded_in_identifier { + return true; + } + search_start = index + path.len(); + } + return false; +} + fn collect_rust_files(directory: &std::path::Path, files: &mut std::vec::Vec) { let entries_result = std::fs::read_dir(directory); let entries = match entries_result { @@ -25,6 +90,20 @@ fn collect_rust_files(directory: &std::path::Path, files: &mut std::vec::Vec manifest, std::result::Result::Err(_) => continue, }; + assert!(!manifest_declares_direct_dependency(manifest.as_str(), "tracing"), "{} depends directly on tracing", manifest_path.display(),); assert!( - !manifest.contains("tracing.workspace") && !manifest.contains("\ntracing =") && !manifest.contains("[dependencies.tracing]"), - "{} depends directly on tracing", + !manifest_declares_direct_dependency(manifest.as_str(), "tracing-subscriber"), + "{} depends directly on tracing-subscriber", + manifest_path.display(), + ); + assert!( + !manifest_declares_direct_dependency(manifest.as_str(), "tracing-appender"), + "{} depends directly on tracing-appender", manifest_path.display(), ); - assert!(!manifest.contains("tracing-subscriber"), "{} depends directly on tracing-subscriber", manifest_path.display()); - assert!(!manifest.contains("tracing-appender"), "{} depends directly on tracing-appender", manifest_path.display()); } let mut rust_files = std::vec::Vec::new(); collect_rust_files(crate_path.as_path(), &mut rust_files); @@ -73,9 +156,13 @@ fn workspace_crates_do_not_bypass_ksp_logging_facade() { std::result::Result::Ok(source) => source, std::result::Result::Err(_) => continue, }; - assert!(!source.contains("tracing::"), "{} bypasses ksp-logging-lib via tracing", rust_file.display()); - assert!(!source.contains("tracing_subscriber::"), "{} bypasses ksp-logging-lib via tracing-subscriber", rust_file.display()); - assert!(!source.contains("tracing_appender::"), "{} bypasses ksp-logging-lib via tracing-appender", rust_file.display()); + assert!(!source_uses_direct_path(source.as_str(), "tracing::"), "{} bypasses ksp-logging-lib via tracing", rust_file.display()); + assert!( + !source_uses_direct_path(source.as_str(), "tracing_subscriber::"), + "{} bypasses ksp-logging-lib via tracing-subscriber", + rust_file.display(), + ); + assert!(!source_uses_direct_path(source.as_str(), "tracing_appender::"), "{} bypasses ksp-logging-lib via tracing-appender", rust_file.display(),); } } } diff --git a/deltas/0.1.4/pre.016-fix.002.md b/deltas/0.1.4/pre.016-fix.002.md new file mode 100644 index 0000000..5d48884 --- /dev/null +++ b/deltas/0.1.4/pre.016-fix.002.md @@ -0,0 +1,22 @@ +# 0.1.4-pre.016-fix.002 + +## Objet + +Corriger le faux positif de l’audit d’ownership Logging introduit par la détection textuelle trop large de la dépendance `tracing`. + +## Correction + +- remplace la recherche de sous-chaîne `tracing.workspace` par une détection des déclarations de dépendances Cargo exactes ; +- autorise donc correctement `tauri-plugin-tracing.workspace = true` dans une application Tauri ; +- continue d’interdire une dépendance directe à `tracing`, `tracing-subscriber` ou `tracing-appender` dans toute crate KSP autre que `ksp-logging-lib` ; +- couvre les formes `dependency.workspace = true`, `dependency = { ... }` et `[dependencies.dependency]`, y compris les tables de dépendances target/dev/build ; +- corrige également le scanner Rust afin que `tauri_plugin_tracing::...` ne soit pas confondu avec un chemin direct `tracing::...` ; +- ajoute des tests de régression pour les deux faux positifs tout en conservant le rejet des accès directs. + +## Portée + +Aucun changement du runtime Logging, de Config Desk, du hot reload, des profils, de Chrono ou de `config/std.logging.json`. + +## Version technique + +`0.1.4-pre.16.fix.2`