# 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
```text

---

## 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
```text

### 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
```text

### 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
```text

**Expected Output:**
```yaml
creation_rules:
  - path_regex: .*
    age: age1xxxxxxxxxxxxxxxxxxxxx
```text

---

## 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
```text

### 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,...]
```text

### 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
```text

### 2.4 Clean Up

```bash
# Remove test file
rm test-secret.yaml
```text

**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]"
# }
```text

**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
```text

### 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"
# }
```text

**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
```text

### 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..."
# }
```text

**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
```text

---

## 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]"
# }
```text

### 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..."
# }
```text

### 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..."
# }
```text

**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
```text

### 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
```text

---

## 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
```text

### 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
```text

---

## Troubleshooting

### Problem: "config file not found"

```bash
# Error: config file not found, or has no creation rules
```text

**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/
```text

### Problem: "no identity matched key"

```bash
# Error: no identity matched key
```text

**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
```text

### Problem: typedialog times out or hangs

```bash
# typedialog seems to be waiting for input
```text

**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
```text

### Problem: "Backend 'sops' not available"

```bash
# Error: Backend 'sops' not available
```text

**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
```text

---

## 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)
