naru-config 0.7.0

A security-first configuration manager with encryption and audit logging
Documentation
use crate::core::schema_model::FieldDefinition;
use crate::core::string_validator::validate_string_with_rules;
use crate::core::type_validator::{validate_boolean, validate_integer_with_rules};

pub fn validate_value(value: &str, field: &FieldDefinition) -> Result<(), String> {
    match field.r#type.as_str() {
        "integer" => {
            validate_integer_with_rules(
                value,
                field
                    .validation
                    .as_ref()
                    .unwrap_or(&crate::core::schema_model::ValidationRules::new()),
            )?;
        }
        "boolean" => {
            validate_boolean(value).map(|_| ())?;
        }
        "string" | _ => {
            if let Some(rules) = &field.validation {
                validate_string_with_rules(value, rules)?;
            }
        }
    }

    Ok(())
}

pub mod type_validator {
    pub use crate::core::type_validator::*;
}

pub mod string_validator {
    pub use crate::core::string_validator::*;
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::core::schema_model::{FieldDefinition, ValidationRules};

    #[test]
    fn test_validate_integer() {
        let field = FieldDefinition {
            key: "age".into(),
            r#type: "integer".into(),
            description: None,
            validation: Some(ValidationRules {
                min_value: Some(0),
                max_value: Some(120),
                min_length: None,
                max_length: None,
                pattern: None,
            }),
            is_secret: false,
        };

        assert!(validate_value("25", &field).is_ok());
        assert!(validate_value("-1", &field).is_err());
        assert!(validate_value("121", &field).is_err());
        assert!(validate_value("abc", &field).is_err());
    }

    #[test]
    fn test_validate_string() {
        let field = FieldDefinition {
            key: "username".into(),
            r#type: "string".into(),
            description: None,
            validation: Some(ValidationRules {
                min_length: Some(3),
                max_length: Some(10),
                min_value: None,
                max_value: None,
                pattern: None,
            }),
            is_secret: false,
        };

        assert!(validate_value("admin", &field).is_ok());
        assert!(validate_value("ab", &field).is_err());
    }

    #[test]
    fn test_validate_pattern() {
        let field = FieldDefinition {
            key: "email".into(),
            r#type: "string".into(),
            description: None,
            validation: Some(ValidationRules {
                min_length: None,
                max_length: None,
                min_value: None,
                max_value: None,
                pattern: Some(r"^[\w\.-]+@[\w\.-]+\.\w+$".to_string()),
            }),
            is_secret: false,
        };

        assert!(validate_value("test@example.com", &field).is_ok());
        assert!(validate_value("invalid-email", &field).is_err());
    }

    #[test]
    fn test_validate_boolean_strict() {
        let field = FieldDefinition {
            key: "active".into(),
            r#type: "boolean".into(),
            description: None,
            validation: None,
            is_secret: false,
        };

        assert!(validate_value("true", &field).is_ok());
        assert!(validate_value("false", &field).is_ok());
        assert!(validate_value("1", &field).is_err());
    }
}