v0.1.3-pre.011
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-config-lib/unit_tests/environment.rs
|
||||
// version: 2
|
||||
// version: 3
|
||||
|
||||
#[test]
|
||||
fn process_environment_wins_over_dotenv_and_fallback_even_when_empty() {
|
||||
@@ -234,3 +234,129 @@ fn env_example_inventory_contains_current_runtime_variable_with_preceding_commen
|
||||
fn workspace_root() -> std::path::PathBuf {
|
||||
return std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../..");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn secret_environment_value_keeps_real_value_but_redacts_safe_and_debug_views() {
|
||||
let canary = "KSP_SECRET_CANARY_91b7c6";
|
||||
let mut process = std::collections::BTreeMap::<String, String>::new();
|
||||
process.insert("KSP_SECRET_TEST_TOKEN".to_owned(), canary.to_owned());
|
||||
let environment = super::ConfigEnvironment::from_maps(process, std::collections::BTreeMap::new());
|
||||
let resolved = environment.resolve_variable("KSP_SECRET_TEST_TOKEN", std::option::Option::None);
|
||||
assert!(resolved.is_ok(), "secret process value should resolve");
|
||||
let resolved = match resolved {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return,
|
||||
};
|
||||
assert_eq!(resolved.value(), canary);
|
||||
assert_eq!(resolved.safe_value(), crate::REDACTED_CONFIG_VALUE);
|
||||
assert_eq!(resolved.sensitivity(), crate::ConfigSensitivity::Secret);
|
||||
assert_eq!(resolved.source(), super::ConfigEnvironmentSource::Process);
|
||||
let debug = format!("{resolved:?}");
|
||||
assert!(!debug.contains(canary), "Debug must not reveal the secret canary");
|
||||
assert!(debug.contains(crate::REDACTED_CONFIG_VALUE));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn detailed_text_redacts_only_secret_segments_and_keeps_ordered_provenance() {
|
||||
let secret = "secret-canary-4a62";
|
||||
let mut process = std::collections::BTreeMap::<String, String>::new();
|
||||
process.insert("KSP_PUBLIC_HOST".to_owned(), "rpc.example.test".to_owned());
|
||||
process.insert("KSP_SECRET_TOKEN".to_owned(), secret.to_owned());
|
||||
let environment = super::ConfigEnvironment::from_maps(process, std::collections::BTreeMap::new());
|
||||
let resolved = environment.resolve_text_detailed("https://${KSP_PUBLIC_HOST}/?token=${KSP_SECRET_TOKEN}");
|
||||
assert!(resolved.is_ok(), "composed secret URL should resolve");
|
||||
let resolved = match resolved {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return,
|
||||
};
|
||||
assert_eq!(resolved.value(), "https://rpc.example.test/?token=secret-canary-4a62");
|
||||
assert_eq!(resolved.safe_value(), "https://rpc.example.test/?token=********");
|
||||
assert_eq!(resolved.sensitivity(), crate::ConfigSensitivity::Secret);
|
||||
assert_eq!(resolved.provenance().len(), 4);
|
||||
assert_eq!(resolved.provenance()[0], crate::ConfigValueProvenance::DocumentLiteral);
|
||||
assert_eq!(resolved.provenance()[1].variable_name(), std::option::Option::Some("KSP_PUBLIC_HOST"));
|
||||
assert_eq!(resolved.provenance()[2], crate::ConfigValueProvenance::DocumentLiteral);
|
||||
assert_eq!(resolved.provenance()[3].variable_name(), std::option::Option::Some("KSP_SECRET_TOKEN"));
|
||||
let debug = format!("{resolved:?}");
|
||||
assert!(!debug.contains(secret), "resolved text Debug must not reveal a secret segment");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn secret_fallback_inherits_secret_sensitivity_and_is_redacted() {
|
||||
let environment = super::ConfigEnvironment::from_maps(std::collections::BTreeMap::new(), std::collections::BTreeMap::new());
|
||||
let resolved = environment.resolve_text_detailed("token=${KSP_SECRET_TOKEN:-false-secret}");
|
||||
assert!(resolved.is_ok(), "secret fallback should resolve");
|
||||
let resolved = match resolved {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return,
|
||||
};
|
||||
assert_eq!(resolved.value(), "token=false-secret");
|
||||
assert_eq!(resolved.safe_value(), "token=********");
|
||||
assert_eq!(resolved.sensitivity(), crate::ConfigSensitivity::Secret);
|
||||
assert_eq!(resolved.provenance()[1].environment_source(), std::option::Option::Some(super::ConfigEnvironmentSource::Fallback));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn detailed_json_preserves_safe_tree_sensitivity_and_pointer_provenance() {
|
||||
let secret = "nested-secret-canary-2d11";
|
||||
let mut dotenv = std::collections::BTreeMap::<String, String>::new();
|
||||
dotenv.insert("KSP_SECRET_TOKEN".to_owned(), secret.to_owned());
|
||||
let environment = super::ConfigEnvironment::from_maps(std::collections::BTreeMap::new(), dotenv);
|
||||
let source = serde_json::json!({"transport": {"url": "https://host/?token=${KSP_SECRET_TOKEN}"}, "items": ["plain", 7]});
|
||||
let resolved = environment.resolve_json_detailed(&source);
|
||||
assert!(resolved.is_ok(), "detailed JSON should resolve");
|
||||
let resolved = match resolved {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return,
|
||||
};
|
||||
assert_eq!(resolved.value()["transport"]["url"], serde_json::Value::String(format!("https://host/?token={secret}")));
|
||||
assert_eq!(resolved.safe_value()["transport"]["url"], serde_json::Value::String("https://host/?token=********".to_owned()));
|
||||
assert_eq!(resolved.sensitivity(), crate::ConfigSensitivity::Secret);
|
||||
let provenance = resolved.provenance_at("/transport/url");
|
||||
assert!(provenance.is_some(), "JSON pointer provenance should exist");
|
||||
if let std::option::Option::Some(provenance) = provenance {
|
||||
assert_eq!(provenance.last().and_then(crate::ConfigValueProvenance::variable_name), std::option::Option::Some("KSP_SECRET_TOKEN"));
|
||||
}
|
||||
let debug = format!("{resolved:?}");
|
||||
assert!(!debug.contains(secret), "resolved JSON Debug must not reveal a secret canary");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn detailed_profile_environment_keeps_global_origin_and_adds_environment_provenance() {
|
||||
let workspace = workspace_root();
|
||||
let bootstrap = crate::ConfigBootstrapOptions::from_paths(workspace.join("config"), workspace.join("config/schemas"));
|
||||
let bootstrap = match bootstrap {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return,
|
||||
};
|
||||
let registry = crate::ConfigFileRegistry::defaults();
|
||||
let registry = match registry {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return,
|
||||
};
|
||||
let file_id = crate::ConfigFileId::new(crate::FILE_ID_STD_LOGGING);
|
||||
let file_id = match file_id {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return,
|
||||
};
|
||||
let engine = crate::ConfigDocumentEngine::new(bootstrap, registry);
|
||||
let profile = engine.load_resolved_profile(&file_id, std::option::Option::None);
|
||||
let profile = match profile {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return,
|
||||
};
|
||||
let environment = super::ConfigEnvironment::from_maps(std::collections::BTreeMap::new(), std::collections::BTreeMap::new());
|
||||
let effective = profile.resolve_effective_environment_detailed(&environment);
|
||||
assert!(effective.is_ok(), "detailed committed Logging profile should resolve");
|
||||
let effective = match effective {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return,
|
||||
};
|
||||
assert_eq!(profile.origin("logs_directory"), std::option::Option::Some(crate::ConfigValueOrigin::Global));
|
||||
assert_eq!(effective.value()["logs_directory"], serde_json::Value::String("logs".to_owned()));
|
||||
assert_eq!(effective.safe_value()["logs_directory"], serde_json::Value::String("logs".to_owned()));
|
||||
assert_eq!(
|
||||
effective.provenance_at("/logs_directory").and_then(|items| items.last()).and_then(crate::ConfigValueProvenance::variable_name),
|
||||
std::option::Option::Some("KSP_LOGS_DIRECTORY"),
|
||||
);
|
||||
}
|
||||
|
||||
31
crates/ksp-config-lib/unit_tests/sensitivity.rs
Normal file
31
crates/ksp-config-lib/unit_tests/sensitivity.rs
Normal file
@@ -0,0 +1,31 @@
|
||||
// file: crates/ksp-config-lib/unit_tests/sensitivity.rs
|
||||
// version: 1
|
||||
|
||||
#[test]
|
||||
fn environment_names_map_to_expected_sensitivity() {
|
||||
assert_eq!(super::ConfigSensitivity::from_variable_name("KSP_PUBLIC_ENDPOINT").ok(), std::option::Option::Some(super::ConfigSensitivity::Public));
|
||||
assert_eq!(super::ConfigSensitivity::from_variable_name("KSP_MODE").ok(), std::option::Option::Some(super::ConfigSensitivity::Internal));
|
||||
assert_eq!(super::ConfigSensitivity::from_variable_name("KSP_SECRET_PASSWORD").ok(), std::option::Option::Some(super::ConfigSensitivity::Secret));
|
||||
assert_eq!(super::ConfigSensitivity::from_variable_name("KSPB_PUBLIC_ENDPOINT").ok(), std::option::Option::Some(super::ConfigSensitivity::Public));
|
||||
assert_eq!(super::ConfigSensitivity::from_variable_name("KSPB_MODE").ok(), std::option::Option::Some(super::ConfigSensitivity::Internal));
|
||||
assert_eq!(super::ConfigSensitivity::from_variable_name("KSPB_SECRET_PASSWORD").ok(), std::option::Option::Some(super::ConfigSensitivity::Secret));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn strongest_sensitivity_follows_secret_internal_public_order() {
|
||||
assert_eq!(super::ConfigSensitivity::Public.strongest(super::ConfigSensitivity::Internal), super::ConfigSensitivity::Internal);
|
||||
assert_eq!(super::ConfigSensitivity::Internal.strongest(super::ConfigSensitivity::Secret), super::ConfigSensitivity::Secret);
|
||||
assert_eq!(super::ConfigSensitivity::Secret.strongest(super::ConfigSensitivity::Public), super::ConfigSensitivity::Secret);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn provenance_exposes_names_and_sources_without_values() {
|
||||
let process = super::ConfigValueProvenance::EnvironmentProcess { variable_name: "KSP_SECRET_TOKEN".to_owned() };
|
||||
let dotenv = super::ConfigValueProvenance::EnvironmentDotEnv { variable_name: "KSP_MODE".to_owned() };
|
||||
let fallback = super::ConfigValueProvenance::EnvironmentFallback { variable_name: "KSP_PUBLIC_HOST".to_owned() };
|
||||
assert_eq!(process.variable_name(), std::option::Option::Some("KSP_SECRET_TOKEN"));
|
||||
assert_eq!(process.environment_source(), std::option::Option::Some(crate::ConfigEnvironmentSource::Process));
|
||||
assert_eq!(dotenv.environment_source(), std::option::Option::Some(crate::ConfigEnvironmentSource::DotEnv));
|
||||
assert_eq!(fallback.environment_source(), std::option::Option::Some(crate::ConfigEnvironmentSource::Fallback));
|
||||
assert_eq!(super::ConfigValueProvenance::DocumentLiteral.variable_name(), std::option::Option::None);
|
||||
}
|
||||
Reference in New Issue
Block a user