// file: crates/ksp-config-lib/tests/ownership.rs // version: 4 //! Workspace ownership audits for KSP application configuration boundaries. fn workspace_root() -> std::path::PathBuf { let manifest_directory = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")); let root = manifest_directory.parent().and_then(std::path::Path::parent); return match root { std::option::Option::Some(value) => value.to_path_buf(), std::option::Option::None => manifest_directory, }; } fn collect_rust_files(directory: &std::path::Path, files: &mut std::vec::Vec) { let entries = std::fs::read_dir(directory); let entries = match entries { std::result::Result::Ok(value) => value, std::result::Result::Err(_) => return, }; for entry in entries { let entry = match entry { std::result::Result::Ok(value) => value, std::result::Result::Err(_) => continue, }; let path = entry.path(); if path.is_dir() { collect_rust_files(path.as_path(), files); continue; } if path.extension().and_then(std::ffi::OsStr::to_str) == std::option::Option::Some("rs") { files.push(path); } } } fn collect_json_files(directory: &std::path::Path, files: &mut std::vec::Vec) { let entries = std::fs::read_dir(directory); let entries = match entries { std::result::Result::Ok(value) => value, std::result::Result::Err(_) => return, }; for entry in entries { let entry = match entry { std::result::Result::Ok(value) => value, std::result::Result::Err(_) => continue, }; let path = entry.path(); if path.is_dir() { collect_json_files(path.as_path(), files); continue; } if path.extension().and_then(std::ffi::OsStr::to_str) == std::option::Option::Some("json") { files.push(path); } } } fn non_comment_source(source: &str) -> String { let mut filtered = String::new(); for line in source.lines() { let trimmed = line.trim_start(); if trimmed.starts_with("//") { continue; } filtered.push_str(line); filtered.push('\n'); } return filtered; } fn collect_environment_names(source: &str, names: &mut std::collections::BTreeSet) { let bytes = source.as_bytes(); let mut index: usize = 0; while index < bytes.len() { let prefix_length = if bytes[index..].starts_with(b"KSPB_") { 5 } else if bytes[index..].starts_with(b"KSP_") { 4 } else { index += 1; continue; }; let mut end = index + prefix_length; while end < bytes.len() { let byte = bytes[end]; if byte.is_ascii_uppercase() || byte.is_ascii_digit() || byte == b'_' { end += 1; } else { break; } } let candidate = std::str::from_utf8(&bytes[index..end]); if let std::result::Result::Ok(candidate) = candidate && candidate.len() > prefix_length && !candidate.ends_with('_') && !is_environment_namespace_label(candidate) { names.insert(candidate.to_owned()); } index = end; } } fn is_environment_namespace_label(candidate: &str) -> bool { return matches!(candidate, "KSP_PUBLIC" | "KSP_SECRET" | "KSPB_PUBLIC" | "KSPB_SECRET"); } fn dotenv_example_assignments(source: &str) -> std::collections::BTreeMap { let mut assignments = std::collections::BTreeMap::::new(); for (line_index, line) in source.lines().enumerate() { let mut candidate = line.trim(); if let std::option::Option::Some(commented) = candidate.strip_prefix('#') { candidate = commented.trim_start(); } let separator = candidate.find('='); let separator = match separator { std::option::Option::Some(value) => value, std::option::Option::None => continue, }; let name = candidate[..separator].trim(); if (name.starts_with("KSP_") || name.starts_with("KSPB_")) && !name.ends_with('_') { assignments.insert(name.to_owned(), line_index); } } return assignments; } fn has_preceding_explanatory_comment(source: &str, assignment_line_index: usize) -> bool { let lines: std::vec::Vec<&str> = source.lines().collect(); if assignment_line_index == 0 || assignment_line_index > lines.len() { return false; } let mut index = assignment_line_index; while index > 0 { index -= 1; let trimmed = lines[index].trim(); if trimmed.is_empty() { continue; } if !trimmed.starts_with('#') { return false; } let comment = trimmed.trim_start_matches('#').trim_start(); if comment.starts_with("file:") || comment.starts_with("version:") { return false; } if comment.contains('=') && (comment.starts_with("KSP_") || comment.starts_with("KSPB_")) { return false; } return true; } return false; } #[test] fn foundational_dependency_direction_does_not_point_back_to_config() { let root = workspace_root(); for crate_name in ["ksp-core-lib", "ksp-logging-lib"] { let manifest_path = root.join("crates").join(crate_name).join("Cargo.toml"); let manifest = std::fs::read_to_string(manifest_path.as_path()); assert!(manifest.is_ok(), "unable to read {}", manifest_path.display()); if let std::result::Result::Ok(manifest) = manifest { assert!(!manifest.contains("ksp-config-lib"), "{} must not depend on ksp-config-lib", manifest_path.display()); } } } #[test] fn workspace_crates_do_not_read_ksp_environment_directly() { let root = workspace_root(); let crates_directory = root.join("crates"); let entries = std::fs::read_dir(crates_directory.as_path()); assert!(entries.is_ok(), "unable to inspect workspace crates at {}", crates_directory.display()); let entries = match entries { std::result::Result::Ok(value) => value, std::result::Result::Err(_) => return, }; for entry in entries { let entry = match entry { std::result::Result::Ok(value) => value, std::result::Result::Err(_) => continue, }; if !entry.path().is_dir() || entry.file_name() == std::ffi::OsStr::new("ksp-config-lib") { continue; } let mut rust_files = std::vec::Vec::new(); collect_rust_files(entry.path().as_path(), &mut rust_files); for rust_file in rust_files { let source = std::fs::read_to_string(rust_file.as_path()); assert!(source.is_ok(), "unable to read {}", rust_file.display()); let source = match source { std::result::Result::Ok(value) => non_comment_source(value.as_str()), std::result::Result::Err(_) => continue, }; let forbidden = [ "std::env::var(\"KSP_", "std::env::var(\"KSPB_", "std::env::var_os(\"KSP_", "std::env::var_os(\"KSPB_", "env::var(\"KSP_", "env::var(\"KSPB_", "env::var_os(\"KSP_", "env::var_os(\"KSPB_", "std::env::vars()", "std::env::vars_os()", ]; for token in forbidden { assert!(!source.contains(token), "{} bypasses ksp-config-lib for KSP/KSPB environment access via {token}", rust_file.display()); } } } } #[test] fn workspace_crates_do_not_hardcode_config_managed_physical_files() { let root = workspace_root(); let crates_directory = root.join("crates"); let entries = std::fs::read_dir(crates_directory.as_path()); assert!(entries.is_ok(), "unable to inspect workspace crates at {}", crates_directory.display()); let entries = match entries { std::result::Result::Ok(value) => value, std::result::Result::Err(_) => return, }; for entry in entries { let entry = match entry { std::result::Result::Ok(value) => value, std::result::Result::Err(_) => continue, }; if !entry.path().is_dir() || entry.file_name() == std::ffi::OsStr::new("ksp-config-lib") { continue; } let mut rust_files = std::vec::Vec::new(); collect_rust_files(entry.path().as_path(), &mut rust_files); for rust_file in rust_files { let source = std::fs::read_to_string(rust_file.as_path()); assert!(source.is_ok(), "unable to read {}", rust_file.display()); let source = match source { std::result::Result::Ok(value) => non_comment_source(value.as_str()), std::result::Result::Err(_) => continue, }; for token in [ "\".env\"", "\"composite.ksp-app-wallet-desk.json\"", "\"composite.schema.json\"", "\"std.logging.json\"", "\"std.logging.schema.json\"", "\"std.transport.json\"", "\"std.transport.schema.json\"", "\"std.wallet.json\"", "\"std.wallet.schema.json\"", ] { assert!(!source.contains(token), "{} hardcodes Config-managed physical resource {token}; use ksp-config-lib contracts", rust_file.display()); } } } } #[test] fn environment_name_scanner_ignores_namespace_labels_but_keeps_concrete_names() { let source = r#" const KSP_PUBLIC_LABEL: &str = "KSP_PUBLIC"; const KSP_SECRET_LABEL: &str = "KSP_SECRET"; const KSPB_PUBLIC_LABEL: &str = "KSPB_PUBLIC"; const KSPB_SECRET_LABEL: &str = "KSPB_SECRET"; const KSP_PUBLIC_RPC_URL: &str = "KSP_PUBLIC_RPC_URL"; const KSP_SECRET_API_KEY: &str = "KSP_SECRET_API_KEY"; const KSPB_PUBLIC_ENDPOINT: &str = "KSPB_PUBLIC_ENDPOINT"; const KSPB_SECRET_TOKEN: &str = "KSPB_SECRET_TOKEN"; "#; let mut names = std::collections::BTreeSet::::new(); collect_environment_names(source, &mut names); assert!(!names.contains("KSP_PUBLIC")); assert!(!names.contains("KSP_SECRET")); assert!(!names.contains("KSPB_PUBLIC")); assert!(!names.contains("KSPB_SECRET")); assert!(names.contains("KSP_PUBLIC_RPC_URL")); assert!(names.contains("KSP_SECRET_API_KEY")); assert!(names.contains("KSPB_PUBLIC_ENDPOINT")); assert!(names.contains("KSPB_SECRET_TOKEN")); } #[test] fn dotenv_example_covers_runtime_environment_names_with_comments() { let root = workspace_root(); let mut runtime_names = std::collections::BTreeSet::::new(); let config_directory = root.join("config"); let mut json_files = std::vec::Vec::new(); collect_json_files(config_directory.as_path(), &mut json_files); for json_file in json_files { let source = std::fs::read_to_string(json_file.as_path()); assert!(source.is_ok(), "unable to read {}", json_file.display()); if let std::result::Result::Ok(source) = source { collect_environment_names(source.as_str(), &mut runtime_names); } } let crates_directory = root.join("crates"); let crate_entries = std::fs::read_dir(crates_directory.as_path()); assert!(crate_entries.is_ok(), "unable to inspect workspace crates at {}", crates_directory.display()); let crate_entries = match crate_entries { std::result::Result::Ok(value) => value, std::result::Result::Err(_) => return, }; for entry in crate_entries { let entry = match entry { std::result::Result::Ok(value) => value, std::result::Result::Err(_) => continue, }; let source_directory = entry.path().join("src"); if !source_directory.is_dir() { continue; } let mut rust_files = std::vec::Vec::new(); collect_rust_files(source_directory.as_path(), &mut rust_files); for rust_file in rust_files { let source = std::fs::read_to_string(rust_file.as_path()); assert!(source.is_ok(), "unable to read {}", rust_file.display()); if let std::result::Result::Ok(source) = source { let source = non_comment_source(source.as_str()); collect_environment_names(source.as_str(), &mut runtime_names); } } } let example_path = root.join(ksp_config_lib::DEFAULT_DOTENV_EXAMPLE_PATH); let example = std::fs::read_to_string(example_path.as_path()); assert!(example.is_ok(), "unable to read canonical environment inventory {}", example_path.display()); let example = match example { std::result::Result::Ok(value) => value, std::result::Result::Err(_) => return, }; let assignments = dotenv_example_assignments(example.as_str()); assert!(!runtime_names.is_empty(), "runtime environment audit should discover at least one concrete KSP/KSPB variable"); for variable_name in runtime_names { let assignment_line = assignments.get(variable_name.as_str()); assert!(assignment_line.is_some(), ".env.example is missing runtime variable {variable_name}"); if let std::option::Option::Some(line_index) = assignment_line { assert!( has_preceding_explanatory_comment(example.as_str(), *line_index), ".env.example variable {variable_name} must be preceded by an explanatory comment", ); } } }