provisioning-core/nulib/domain/config/validators.nu

238 lines
7.5 KiB
Text
Raw Permalink Normal View History

# Module: Configuration Validators
# Purpose: Provides validation functions for configuration integrity, types, and semantic correctness.
# Dependencies: None (core utility)
# Configuration Validation and Detection Engine
# Validates configuration structures and detects potential security/dependency issues
use std log
# Validate interpolation patterns and detect potential issues
export def validate-interpolation [
config: record
--detailed = false # Show detailed validation results
] {
mut errors = []
mut warnings = []
# Convert config to JSON for pattern detection
let json_str = ($config | to json)
# Check for unresolved interpolation patterns
let unresolved_patterns = (detect-unresolved-patterns $json_str)
if ($unresolved_patterns | length) > 0 {
$errors = ($errors | append {
type: "unresolved_interpolation"
severity: "error"
patterns: $unresolved_patterns
message: $"Unresolved interpolation patterns found: ($unresolved_patterns | str join ', ')"
})
}
# Check for circular dependencies
let circular_deps = (detect-circular-dependencies $json_str)
if ($circular_deps | length) > 0 {
$errors = ($errors | append {
type: "circular_dependency"
severity: "error"
dependencies: $circular_deps
message: $"Circular interpolation dependencies detected: ($circular_deps | str join ', ')"
})
}
# Check for unsafe environment variable access
let unsafe_env_vars = (detect-unsafe-env-patterns $json_str)
if ($unsafe_env_vars | length) > 0 {
$warnings = ($warnings | append {
type: "unsafe_env_access"
severity: "warning"
variables: $unsafe_env_vars
message: $"Potentially unsafe environment variable access: ($unsafe_env_vars | str join ', ')"
})
}
# Validate git repository context
let git_validation = (validate-git-context $json_str)
if not $git_validation.valid {
$warnings = ($warnings | append {
type: "git_context"
severity: "warning"
message: $git_validation.message
})
}
let has_errors = ($errors | length) > 0
let has_warnings = ($warnings | length) > 0
if not $detailed and $has_errors {
let error_messages = ($errors | each { |err| $err.message })
error make {
msg: ($error_messages | str join "; ")
}
}
{
valid: (not $has_errors),
errors: $errors,
warnings: $warnings,
summary: {
total_errors: ($errors | length),
total_warnings: ($warnings | length),
interpolation_patterns_detected: (count-interpolation-patterns $json_str)
}
}
}
# Security-hardened interpolation with input validation
export def secure-interpolation [
config: record
--allow-unsafe = false # Allow potentially unsafe patterns
--max-depth = 5 # Maximum interpolation depth
] {
# Security checks before interpolation
let security_validation = (validate-interpolation-security $config $allow_unsafe)
if not $security_validation.valid {
error make {
msg: $"Security validation failed: ($security_validation.errors | str join '; ')"
}
}
# Apply interpolation with depth limiting
let base_path = ($config | get -o paths.base | default "")
if ($base_path | is-not-empty) {
interpolate-with-depth-limit $config $base_path $max_depth
} else {
$config
}
}
# Detect unresolved interpolation patterns
export def detect-unresolved-patterns [
text: string
] {
# Find patterns that look like interpolation but might not be handled
let unknown_patterns = ($text | str replace --regex "\\{\\{([^}]+)\\}\\}" "")
# Known patterns that should be resolved
let known_patterns = [
"paths.base" "env\\." "now\\." "git\\." "sops\\." "providers\\." "path\\.join"
]
mut unresolved = []
# Check for patterns that don't match known types
let all_matches = ($text | str replace --regex "\\{\\{([^}]+)\\}\\}" "$1")
if ($all_matches | str contains "{{") {
# Basic detection - in a real implementation, this would be more sophisticated
let potential_unknown = ($text | str replace --regex "\\{\\{(\\w+\\.\\w+)\\}\\}" "")
if ($text | str contains "{{unknown.") {
$unresolved = ($unresolved | append "unknown.*")
}
}
$unresolved
}
# Detect circular interpolation dependencies
export def detect-circular-dependencies [
text: string
] {
mut circular_deps = []
# Simple detection for self-referencing patterns
if (($text | str contains "{{paths.base}}") and ($text | str contains "paths.base.*{{paths.base}}")) {
$circular_deps = ($circular_deps | append "paths.base -> paths.base")
}
$circular_deps
}
# Detect unsafe environment variable patterns
export def detect-unsafe-env-patterns [
text: string
] {
mut unsafe_vars = []
# Patterns that might be dangerous
let dangerous_patterns = ["PATH" "LD_LIBRARY_PATH" "PYTHONPATH" "SHELL" "PS1"]
for pattern in $dangerous_patterns {
if ($text | str contains $"{{env.($pattern)}}") {
$unsafe_vars = ($unsafe_vars | append $pattern)
}
}
$unsafe_vars
}
# Validate git repository context for git interpolations
export def validate-git-context [
text: string
] {
if ($text | str contains "{{git.") {
# Check if we're in a git repository
let git_check = (do { ^git rev-parse --git-dir err> (if $nu.os-info.name == "windows" { "NUL" } else { "/dev/null" }) } | complete)
let is_git_repo = ($git_check.exit_code == 0)
if not $is_git_repo {
return {
valid: false
message: "Git interpolation patterns detected but not in a git repository"
}
}
}
{ valid: true, message: "" }
}
# Count interpolation patterns for metrics
export def count-interpolation-patterns [
text: string
] {
# Count all {{...}} patterns by finding matches
# Simple approximation: count occurrences of "{{"
let pattern_count = ($text | str replace --all "{{" "\n{{" | lines | where ($it | str contains "{{") | length)
$pattern_count
}
# Validate interpolation security
def validate-interpolation-security [
config: record
allow_unsafe: bool
] {
mut errors = []
let json_str = ($config | to json)
# Check for code injection patterns
let dangerous_patterns = [
"\\$\\(" "\\`" "\\;" "\\|\\|" "\\&&" "rm " "sudo " "eval " "exec "
]
for pattern in $dangerous_patterns {
if ($json_str =~ $pattern) {
$errors = ($errors | append $"Potential code injection pattern detected: ($pattern)")
}
}
# Check for unsafe environment variable access
if not $allow_unsafe {
let unsafe_env_vars = ["PATH" "LD_LIBRARY_PATH" "PYTHONPATH" "PS1" "PROMPT_COMMAND"]
for var in $unsafe_env_vars {
if ($json_str | str contains $"{{env.($var)}}") {
$errors = ($errors | append $"Unsafe environment variable access: ($var)")
}
}
}
# Check for path traversal attempts
if (($json_str | str contains "../") or ($json_str | str contains "..\\")) {
$errors = ($errors | append "Path traversal attempt detected")
}
{
valid: (($errors | length) == 0)
errors: $errors
}
}