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

607 lines
17 KiB
Text

# Configuration Encryption System Tests
# Comprehensive test suite for encryption functionality
# Error handling: Guard patterns (no try-catch for field access)
# Selective imports (ADR-025 Phase 3 Layer 2).
use domain/config/encryption.nu [
contains-sensitive-data decrypt-config decrypt-config-memory encrypt-config
is-encrypted-config load-encrypted-config validate-encryption-config
]
use platform/kms/client.nu [kms-status]
# Test suite runner
export def run-encryption-tests [
--verbose (-v) # Verbose output
--test: string = "" # Run specific test (empty = all)
] {
print "🧪 Configuration Encryption Test Suite"
print "======================================"
print ""
mut results = []
# Test 1: Encryption detection
if ($test == "" or $test == "detection") {
print "🔍 Test 1: Encryption Detection"
let result = (test-encryption-detection)
$results = ($results | append $result)
show-test-result $result
print ""
}
# Test 2: Encrypt/Decrypt round-trip
if ($test == "" or $test == "roundtrip") {
print "🔍 Test 2: Encrypt/Decrypt Round-trip"
let result = (test-encrypt-decrypt-roundtrip)
$results = ($results | append $result)
show-test-result $result
print ""
}
# Test 3: Memory-only decryption
if ($test == "" or $test == "memory") {
print "🔍 Test 3: Memory-Only Decryption"
let result = (test-memory-only-decryption)
$results = ($results | append $result)
show-test-result $result
print ""
}
# Test 4: Sensitive data detection
if ($test == "" or $test == "sensitive") {
print "🔍 Test 4: Sensitive Data Detection"
let result = (test-sensitive-data-detection)
$results = ($results | append $result)
show-test-result $result
print ""
}
# Test 5: KMS backend integration
if ($test == "" or $test == "kms") {
print "🔍 Test 5: KMS Backend Integration"
let result = (test-kms-backend-integration)
$results = ($results | append $result)
show-test-result $result
print ""
}
# Test 6: Config loader integration
if ($test == "" or $test == "loader") {
print "🔍 Test 6: Config Loader Integration"
let result = (test-config-loader-integration)
$results = ($results | append $result)
show-test-result $result
print ""
}
# Test 7: Validation
if ($test == "" or $test == "validation") {
print "🔍 Test 7: Encryption Validation"
let result = (test-encryption-validation)
$results = ($results | append $result)
show-test-result $result
print ""
}
# Summary
print "📊 Test Summary"
print "=============="
let total = ($results | length)
let passed = ($results | where passed == true | length)
let failed = ($total - $passed)
print $" Total tests: ($total)"
print $" Passed: ($passed)"
print $" Failed: ($failed)"
print $" Success rate: (($passed * 100) / $total)%"
if $failed == 0 {
print ""
print "✅ All tests passed!"
} else {
print ""
print "❌ Some tests failed:"
for result in ($results | where passed == false) {
print $" • ($result.test_name): ($result.error)"
}
}
{
total: $total
passed: $passed
failed: $failed
results: $results
}
}
# Test 1: Encryption detection
def test-encryption-detection [] {
let test_name = "Encryption Detection"
let result = (do {
# Create test file
let test_file = "/tmp/test_plain.yaml"
"test: value" | save --force $test_file
# Should detect as not encrypted
let is_enc = (is-encrypted-config $test_file)
rm --force $test_file
if $is_enc {
error make {
msg: "Plain file incorrectly detected as encrypted"
}
}
"success"
} | complete)
if $result.exit_code == 0 {
{
test_name: $test_name
passed: true
error: null
}
} else {
{
test_name: $test_name
passed: false
error: $result.stderr
}
}
}
# Test 2: Encrypt/Decrypt round-trip
def test-encrypt-decrypt-roundtrip [] {
let test_name = "Encrypt/Decrypt Round-trip"
let result = (do {
# Create test file
let test_file = "/tmp/test_roundtrip.yaml"
let original_content = "test_key: secret_value"
$original_content | save --force $test_file
# Check if age is available
let age_check = (^which age | complete)
if $age_check.exit_code != 0 {
rm --force $test_file
return {
test_name: $test_name
passed: true
error: "Skipped: Age not installed"
skipped: true
}
}
# Check if SOPS recipients configured
let recipients = ($env.SOPS_AGE_RECIPIENTS? | default "")
if ($recipients | is-empty) {
rm --force $test_file
return {
test_name: $test_name
passed: true
error: "Skipped: SOPS_AGE_RECIPIENTS not configured"
skipped: true
}
}
# Encrypt the file
let encrypted_file = $"($test_file).enc"
encrypt-config $test_file $encrypted_file --kms="age"
# Verify it's encrypted
if not (is-encrypted-config $encrypted_file) {
rm --force $test_file $encrypted_file
error make {
msg: "File not encrypted after encrypt-config"
}
}
# Decrypt the file
let decrypted_file = $"($test_file).dec"
decrypt-config $encrypted_file $decrypted_file
# Verify content matches
let decrypted_content = (open $decrypted_file --raw)
# Cleanup
rm --force $test_file $encrypted_file $decrypted_file
if $decrypted_content != $original_content {
error make {
msg: "Decrypted content doesn't match original"
}
}
{
test_name: $test_name
passed: true
error: null
}
} | complete)
if $result.exit_code == 0 {
$result.stdout | from json
} else {
{
test_name: $test_name
passed: false
error: $result.stderr
}
}
}
# Test 3: Memory-only decryption
def test-memory-only-decryption [] {
let test_name = "Memory-Only Decryption"
let result = (do {
# Check if age is available
let age_check = (^which age | complete)
if $age_check.exit_code != 0 {
return {
test_name: $test_name
passed: true
error: "Skipped: Age not installed"
skipped: true
}
}
# Check if SOPS recipients configured
let recipients = ($env.SOPS_AGE_RECIPIENTS? | default "")
if ($recipients | is-empty) {
return {
test_name: $test_name
passed: true
error: "Skipped: SOPS_AGE_RECIPIENTS not configured"
skipped: true
}
}
# Create and encrypt test file
let test_file = "/tmp/test_memory.yaml"
let original_content = "secret: memory_test"
$original_content | save --force $test_file
let encrypted_file = $"($test_file).enc"
encrypt-config $test_file $encrypted_file --kms="age"
# Decrypt in memory
let decrypted_memory = (decrypt-config-memory $encrypted_file)
# Cleanup
rm --force $test_file $encrypted_file
# Verify no decrypted file was created
if ($"($encrypted_file).dec" | path exists) {
error make {
msg: "Decrypted file was created (should be memory-only)"
}
}
# Verify decrypted content
if $decrypted_memory != $original_content {
error make {
msg: "Memory-decrypted content doesn't match original"
}
}
{
test_name: $test_name
passed: true
error: null
}
} | complete)
if $result.exit_code == 0 {
$result.stdout | from json
} else {
{
test_name: $test_name
passed: false
error: $result.stderr
}
}
}
# Test 4: Sensitive data detection
def test-sensitive-data-detection [] {
let test_name = "Sensitive Data Detection"
let result = (do {
# Create test file with sensitive data
let test_file = "/tmp/test_sensitive.yaml"
let sensitive_content = "api_key: secret123\npassword: mypassword"
$sensitive_content | save --force $test_file
# Should detect sensitive data
let has_sensitive = (contains-sensitive-data $test_file)
# Create test file without sensitive data
let test_file_safe = "/tmp/test_safe.yaml"
let safe_content = "name: test\nvalue: 123"
$safe_content | save --force $test_file_safe
# Should not detect sensitive data
let has_no_sensitive = not (contains-sensitive-data $test_file_safe)
# Cleanup
rm --force $test_file $test_file_safe
if not ($has_sensitive and $has_no_sensitive) {
error make {
msg: "Sensitive data detection not working correctly"
}
}
{
test_name: $test_name
passed: true
error: null
}
} | complete)
if $result.exit_code == 0 {
$result.stdout | from json
} else {
{
test_name: $test_name
passed: false
error: $result.stderr
}
}
}
# Test 5: KMS backend integration
def test-kms-backend-integration [] {
let test_name = "KMS Backend Integration"
let result = (do {
# Test detection
let backend = (detect-kms-backend)
if ($backend | is-empty) {
error make {
msg: "Failed to detect KMS backend"
}
}
# Test status
let status = (kms-status)
if ($status.backend | is-empty) {
error make {
msg: "KMS status check failed"
}
}
{
test_name: $test_name
passed: true
error: null
details: {
detected_backend: $backend
status: $status
}
}
} | complete)
if $result.exit_code == 0 {
$result.stdout | from json
} else {
{
test_name: $test_name
passed: false
error: $result.stderr
}
}
}
# Test 6: Config loader integration
def test-config-loader-integration [] {
let test_name = "Config Loader Integration"
let result = (do {
# Create test directory
mkdir /tmp/test_config_loader
# Create plain config
let plain_config = "/tmp/test_config_loader/plain.yaml"
{test: "plain", value: 123} | to yaml | save --force $plain_config
# Load plain config (should work)
use loader.nu
let loaded_plain = (loader load-config-file $plain_config false false "yaml")
if ($loaded_plain.test != "plain") {
rm --force --recursive /tmp/test_config_loader
error make {
msg: "Failed to load plain config through loader"
}
}
# Cleanup
rm --force --recursive /tmp/test_config_loader
{
test_name: $test_name
passed: true
error: null
}
} | complete)
if $result.exit_code == 0 {
$result.stdout | from json
} else {
{
test_name: $test_name
passed: false
error: $result.stderr
}
}
}
# Test 7: Encryption validation
def test-encryption-validation [] {
let test_name = "Encryption Validation"
let result = (do {
# Run validation
let validation = (validate-encryption-config)
# Check that validation returns expected structure
if not (($validation | columns) | all { |col| $col in ["valid", "errors", "warnings", "summary"] }) {
error make {
msg: "Validation result structure incorrect"
}
}
{
test_name: $test_name
passed: true
error: null
details: $validation.summary
}
} | complete)
if $result.exit_code == 0 {
$result.stdout | from json
} else {
{
test_name: $test_name
passed: false
error: $result.stderr
}
}
}
# Show test result
def show-test-result [result: record] {
if $result.passed {
print $" ✅ ($result.test_name)"
# Guard: Check if skipped field exists in result
if ("skipped" in ($result | columns)) and ($result | get skipped) == true {
print $" ⚠️ ($result.error)"
}
} else {
print $" ❌ ($result.test_name)"
print $" Error: ($result.error)"
}
}
# Integration test with full workflow
export def test-full-encryption-workflow [] {
print "🧪 Full Encryption Workflow Test"
print "================================="
print ""
let test_dir = "/tmp/test_encryption_workflow"
mkdir $test_dir
let result = (do {
# Step 1: Create test config with sensitive data
print "📝 Step 1: Creating test configuration"
let config_file = $"($test_dir)/secure.yaml"
{
database: {
host: "localhost"
password: "supersecret123"
api_key: "key_abc123"
}
aws: {
access_key: "AKIAIOSFODNN7EXAMPLE"
secret_key: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
}
} | to yaml | save --force $config_file
print " ✅ Config created"
# Step 2: Detect sensitive data
print "🔍 Step 2: Detecting sensitive data"
let has_sensitive = (contains-sensitive-data $config_file)
if $has_sensitive {
print " ✅ Sensitive data detected"
} else {
print " ❌ Failed to detect sensitive data"
rm --force --recursive $test_dir
return
}
# Step 3: Check encryption prerequisites
print "🔧 Step 3: Checking encryption prerequisites"
let validation = (validate-encryption-config)
if $validation.valid {
print " ✅ Encryption system configured"
} else {
print " ⚠️ Encryption system has issues:"
for error in $validation.errors {
print $" • ($error.message)"
}
}
# Step 4: Encrypt config (if possible)
print "🔒 Step 4: Encrypting configuration"
let recipients = ($env.SOPS_AGE_RECIPIENTS? | default "")
if ($recipients | is-not-empty) {
let encrypt_result = (do {
encrypt-config $config_file --in-place --kms="age"
} | complete)
if $encrypt_result.exit_code == 0 {
print " ✅ Configuration encrypted"
# Step 5: Verify encryption
print "🔍 Step 5: Verifying encryption"
let is_enc = (is-encrypted-config $config_file)
if $is_enc {
print " ✅ Encryption verified"
} else {
print " ❌ File not encrypted"
}
# Step 6: Load encrypted config
print "📖 Step 6: Loading encrypted config"
let loaded = (load-encrypted-config $config_file)
if ($loaded.database.password == "supersecret123") {
print " ✅ Decrypted and loaded correctly"
} else {
print " ❌ Failed to load encrypted config"
}
} else {
print $" ❌ Encryption failed: ($encrypt_result.stderr)"
}
} else {
print " ⚠️ Skipped: SOPS_AGE_RECIPIENTS not configured"
}
print ""
print "✅ Workflow test completed"
} | complete)
if $result.exit_code != 0 {
print $"❌ Workflow test failed: ($result.stderr)"
}
# Cleanup
rm --force --recursive $test_dir
}
# Main help
export def main [] {
print "Configuration Encryption Tests"
print "=============================="
print ""
print "Commands:"
print " run-encryption-tests Run all tests"
print " run-encryption-tests --test <name> Run specific test"
print " test-full-encryption-workflow Run complete workflow test"
print ""
print "Available tests:"
print " detection - Encryption detection"
print " roundtrip - Encrypt/decrypt round-trip"
print " memory - Memory-only decryption"
print " sensitive - Sensitive data detection"
print " kms - KMS backend integration"
print " loader - Config loader integration"
print " validation - Encryption validation"
}