TypeDialog/examples/08-encryption/TEST-SOPS-INTEGRATION.md

539 lines
11 KiB
Markdown
Raw Normal View History

# 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:<hex>`
- ✅ 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)
2025-12-24 03:15:02 +00:00
- [Encryption Architecture](../../docs/encryption-unified-architecture.md)