use crate::types::{TypedValue, ValueType};
const VAULT_PREFIX: &str = "$ANSIBLE_VAULT;";
pub fn check_key_conflicts(keys: &[String]) -> Result<(), String> {
for i in 0..keys.len() {
for j in 0..keys.len() {
if i == j {
continue;
}
if keys[j].starts_with(&format!("{}.", keys[i])) {
return Err(format!(
"conflicting keys: '{}' overlaps with '{}'",
keys[i], keys[j]
));
}
}
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_no_conflicts() {
let keys = vec!["first".to_string(), "second".to_string(), "third.carrot".to_string()];
assert!(check_key_conflicts(&keys).is_ok());
}
#[test]
fn test_direct_prefix_conflict() {
let keys = vec!["second".to_string(), "second.a".to_string()];
assert!(check_key_conflicts(&keys).is_err());
}
#[test]
fn test_deep_prefix_conflict() {
let keys = vec!["second.a".to_string(), "second.a.v".to_string()];
assert!(check_key_conflicts(&keys).is_err());
}
#[test]
fn test_non_prefix_similar_names() {
let keys = vec!["second".to_string(), "secondly".to_string()];
assert!(check_key_conflicts(&keys).is_ok());
}
#[test]
fn test_empty_keys() {
assert!(check_key_conflicts(&[]).is_ok());
}
#[test]
fn test_single_key() {
assert!(check_key_conflicts(&["first".to_string()]).is_ok());
}
}
pub fn is_encrypted(value: &TypedValue) -> (bool, Option<String>) {
let TypedValue::String(s) = value else {
return (false, None);
};
match s.find(VAULT_PREFIX) {
Some(idx) => (true, Some(s[idx..].to_string())),
None => (false, None),
}
}
pub fn is_encryptable(vt: ValueType) -> bool {
matches!(
vt,
ValueType::String | ValueType::Integer | ValueType::Bool | ValueType::Number
)
}