# How to Test SOPS Integration with typedialog Complete step-by-step guide to testing SOPS encryption backend with typedialog. ## Overview This guide shows how to: 1. Setup SOPS with Age (for local testing) 2. Test SOPS encryption manually 3. Integrate SOPS with typedialog 4. Verify encryption/decryption works ## Prerequisites ```bash # Install tools brew install sops age-keygen # Verify installation sops --version age-keygen --version # Check typedialog is available which typedialog typedialog --version ``` --- ## Test 1: Setup SOPS Configuration ### 1.1 Generate Age Key ```bash # Generate a key for SOPS to use age-keygen -o ~/.age/sops-test-key.txt # View the key cat ~/.age/sops-test-key.txt # Output: # # created: 2025-12-21T12:34:56Z # # public key: age1xxxxxxxxxxxxxxxxxxxxx # AGE-SECRET-KEY-xxxxxxxxxxxxxxxxxxxxx ``` ### 1.2 Create `.sops.yaml` SOPS requires a configuration file that specifies which KMS to use. ```bash # Create .sops.yaml in your working directory cat > .sops.yaml << 'EOF' creation_rules: - path_regex: .* age: age1xxxxxxxxxxxxxxxxxxxxxxxxxx # Replace with YOUR public key EOF # Extract your public key and replace it in .sops.yaml PUBLIC_KEY=$(grep "^# public key:" ~/.age/sops-test-key.txt | sed 's/# public key: //') cat > .sops.yaml << EOF creation_rules: - path_regex: .* age: $PUBLIC_KEY EOF # Verify config is correct cat .sops.yaml ``` ### 1.3 Verify SOPS Configuration ```bash # SOPS should be able to find the config ls -la .sops.yaml # Output: -rw-r--r-- 1 user staff 45 Dec 21 12:34 .sops.yaml # View the config cat .sops.yaml ``` **Expected Output:** ```yaml creation_rules: - path_regex: .* age: age1xxxxxxxxxxxxxxxxxxxxx ``` --- ## Test 2: Test SOPS Encryption Directly ### 2.1 Create a Test File ```bash # Create plaintext YAML echo 'secret: my-super-secret-password' > test-secret.yaml # Verify content cat test-secret.yaml # Output: secret: my-super-secret-password ``` ### 2.2 Encrypt with SOPS ```bash # Tell SOPS where to find your Age key export SOPS_AGE_KEY_FILE=~/.age/sops-test-key.txt # Encrypt the file in-place sops -e -i test-secret.yaml # Verify it's encrypted (should be YAML with ENC[...]) cat test-secret.yaml # Output should show: secret: ENC[AES256_GCM,data:xxxxx,iv:xxxxx,...] ``` ### 2.3 Decrypt to Verify ```bash # Decrypt and display (doesn't modify file) sops -d test-secret.yaml # Output: # secret: my-super-secret-password # sops: # ... # Extract just the secret value sops -d test-secret.yaml | grep "^secret:" | sed 's/secret: //' # Output: my-super-secret-password ``` ### 2.4 Clean Up ```bash # Remove test file rm test-secret.yaml ``` **Key Points:** - ✅ SOPS encrypts/decrypts correctly - ✅ Plaintext is preserved during round-trip - ✅ `.sops.yaml` controls which keys can decrypt --- ## Test 3: Test typedialog Redaction (No Encryption Service) Redaction works without any encryption - just replaces sensitive fields with `[REDACTED]`. ```bash # Test redaction (no encryption service needed) # Provide input via stdin: username then password echo -e "alice\nsecretpass123" | typedialog form examples/08-encryption/simple-login.toml \ --redact \ --format json # You'll see prompts: # Username * # Password * # # Output: # { # "username": "alice", # "password": "[REDACTED]" # } ``` **What's being tested:** - ✅ typedialog can detect sensitive fields - ✅ Redaction replaces secrets with `[REDACTED]` - ✅ Non-sensitive fields remain visible --- ## Test 4: Test typedialog with Age Backend Age backend encrypts locally without external service. ### 4.1 Ensure Age Key Exists ```bash # Generate Age key if needed if [ ! -f ~/.age/key.txt ]; then age-keygen -o ~/.age/key.txt fi # Verify key exists cat ~/.age/key.txt ``` ### 4.2 Encrypt with Age Backend ```bash # Provide input via stdin: username then password echo -e "alice\nsecretpass123" | typedialog form examples/08-encryption/simple-login.toml \ --encrypt --backend age \ --key-file ~/.age/key.txt \ --format json # Output: # { # "username": "alice", # "password": "age1muz6ah54ew9am7mzmy0m4w5arcegt056l9448sqy5ju27q5qaf3qjv35tr" # } ``` **What's being tested:** - ✅ typedialog can encrypt with Age backend - ✅ Ciphertext starts with `age1` - ✅ Non-sensitive fields remain plaintext --- ## Test 5: Test typedialog with SOPS Backend ⭐ This is the main integration test. ### 5.1 Verify Setup ```bash # Make sure .sops.yaml exists in current directory cat .sops.yaml # Should show your Age public key # Set Age key for SOPS export SOPS_AGE_KEY_FILE=~/.age/sops-test-key.txt # Verify SOPS can find config sops --version ``` ### 5.2 Encrypt with SOPS Backend ```bash # Provide input via stdin: username then password echo -e "alice\nsecretpass123" | typedialog form examples/08-encryption/simple-login.toml \ --encrypt --backend sops \ --format json # If .sops.yaml is not found, you'll see: # SOPS encryption error: config file not found... # # If successful, output: # { # "username": "alice", # "password": "sops:v1:4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a..." # } ``` **What's being tested:** - ✅ typedialog can use SOPS backend - ✅ SOPS backend respects `.sops.yaml` configuration - ✅ Ciphertext format is `sops:v1:` - ✅ Sensitive fields are encrypted, plaintext fields remain visible ### 5.3 Verify SOPS Ciphertext The encrypted password is hex-encoded encrypted YAML: ```bash # Extract password from JSON PASSWORD="sops:v1:4f5a6b7c8d9e0f1a2b3c..." # Strip the version prefix HEX_PART="4f5a6b7c8d9e0f1a2b3c..." # Decode from hex to see raw encrypted content echo "$HEX_PART" | xxd -r -p | head -c 100 # Shows SOPS-encrypted YAML structure ``` --- ## Test 6: Compare All Backends Run the same form with different backends to see the difference. ### 6.1 Redaction ```bash echo -e "alice\nsecretpass123" | typedialog form examples/08-encryption/simple-login.toml \ --redact --format json # Output: # { # "username": "alice", # "password": "[REDACTED]" # } ``` ### 6.2 Age ```bash echo -e "alice\nsecretpass123" | typedialog form examples/08-encryption/simple-login.toml \ --encrypt --backend age --key-file ~/.age/key.txt --format json # Output: # { # "username": "alice", # "password": "age1xxxxxxxx..." # } ``` ### 6.3 SOPS ```bash export SOPS_AGE_KEY_FILE=~/.age/sops-test-key.txt echo -e "alice\nsecretpass123" | typedialog form examples/08-encryption/simple-login.toml \ --encrypt --backend sops --format json # Output: # { # "username": "alice", # "password": "sops:v1:4f5a6b..." # } ``` **Comparison:** | Backend | Format | Service Required | Use Case | |---------|--------|------------------|----------| | Redaction | `[REDACTED]` | No | Development, logging | | Age | `age1...` | No (local key) | Local development | | SOPS | `sops:v1:hex...` | No (Age) or Yes (AWS/GCP/Azure) | Team collaboration | --- ## Test 7: Multi-Backend Form Test a form with multiple encryption backends. ### 7.1 Create Test File ```bash # Use the multi-backend example cat examples/08-encryption/multi-backend-sops.toml # This form demonstrates: # - api_key: Age backend # - db_password: SOPS backend # - master_key: AWS KMS backend ``` ### 7.2 Encrypt Different Fields with Different Backends ```bash # Encrypt with SOPS (for db_password field) echo -e "myapp\nproduction\nerror\ntestuser\ntestpass\napikey123" | \ typedialog form examples/08-encryption/multi-backend-sops.toml \ --encrypt --backend sops \ --format json # Output shows: # - api_key: field was encrypted (may show Error if backend not available) # - db_password: encrypted with SOPS (sops:v1:...) # - other fields: plain or encrypted based on field config ``` --- ## Test 8: Integration with encrypt Crate Test that the Rust integration is working. ### 8.1 Run Cargo Tests ```bash # Test SOPS backend in encrypt crate cargo test -p encrypt --features sops --lib backend::sops # Expected output: # test backend::sops::tests::test_sops_backend_name ... ok # test backend::sops::tests::test_sops_backend_info ... ok # ... more tests ... # test result: ok. 10 passed; 0 failed ``` ### 8.2 Test Feature-Gating ```bash # Test without SOPS feature cargo test -p encrypt --features age test_is_available_sops # Should show SOPS is not available when feature disabled ``` --- ## Troubleshooting ### Problem: "config file not found" ```bash # Error: config file not found, or has no creation rules ``` **Cause**: `.sops.yaml` not found **Solution**: ```bash # Check if .sops.yaml exists ls -la .sops.yaml # Create it if missing cat > .sops.yaml << 'EOF' creation_rules: - path_regex: .* age: age1xxxxxxxxxxxxxxxxxxxxxxxxxx EOF # Or make sure you're in the correct directory pwd ls examples/08-encryption/ ``` ### Problem: "no identity matched key" ```bash # Error: no identity matched key ``` **Cause**: Age key not found or not accessible **Solution**: ```bash # Verify key file exists cat ~/.age/sops-test-key.txt # Set the key for SOPS export SOPS_AGE_KEY_FILE=~/.age/sops-test-key.txt # Test SOPS directly sops -d test-secret.yaml ``` ### Problem: typedialog times out or hangs ```bash # typedialog seems to be waiting for input ``` **Cause**: stdin not properly piped **Solution**: ```bash # Make sure to use echo -e with newlines echo -e "username\npassword\nmore_input" | typedialog form ... # Or use a here-document typedialog form ... << EOF alice secretpass EOF ``` ### Problem: "Backend 'sops' not available" ```bash # Error: Backend 'sops' not available ``` **Cause**: 1. sops binary not installed 2. SOPS feature not compiled into typedialog **Solution**: ```bash # Install sops brew install sops # Rebuild typedialog with sops feature cargo build --features encryption # (should include sops by default) # Or check if typedialog was built with SOPS cargo build --features all ``` --- ## Summary: What Each Test Verifies | Test | Verifies | Command | |------|----------|---------| | 1 | `.sops.yaml` configuration | Manual file creation | | 2 | SOPS encryption/decryption | `sops -e -i` / `sops -d` | | 3 | typedialog redaction | `--redact` flag | | 4 | typedialog + Age backend | `--encrypt --backend age` | | 5 | **typedialog + SOPS backend** ⭐ | `--encrypt --backend sops` | | 6 | Backend output format differences | Compare all three outputs | | 7 | Multi-backend form support | Field-level backend config | | 8 | Rust integration | `cargo test --features sops` | --- ## Expected Timeline - **Setup**: 5 minutes (create keys and .sops.yaml) - **Tests 1-4**: 5 minutes each (quick manual tests) - **Test 5**: 5 minutes (main SOPS integration test) - **Tests 6-8**: 10 minutes (comparison and verification) **Total**: ~45 minutes for complete integration testing --- ## Next Steps After verifying SOPS works: 1. **Production Setup**: - Replace Age with AWS KMS in `.sops.yaml` - Set up AWS credentials - Deploy SOPS configuration 2. **Team Collaboration**: - Share `.sops.yaml` in Git (does not contain secrets) - Each team member has their own KMS access - SOPS handles key rotation automatically 3. **CI/CD Integration**: - Store encrypted secrets in Git - Decrypt during CI/CD pipeline - Never expose plaintext secrets 4. **Multi-Environment**: - Dev: Age backend (local) - Staging: SOPS (shared team KMS) - Prod: AWS KMS (automated) --- ## See Also - [SOPS GitHub](https://github.com/getsops/sops) - [Age GitHub](https://github.com/FiloSottile/age) - [typedialog Encryption Examples](./README.md) - [Encryption Architecture](../../docs/encryption-unified-architecture.md)