230 lines
5.9 KiB
Markdown
230 lines
5.9 KiB
Markdown
|
|
# Encryption Testing - Quick Start
|
||
|
|
|
||
|
|
## Quick Summary
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# 1. Setup services (Age already configured, RustyVault requires Docker)
|
||
|
|
./scripts/encryption-test-setup.sh
|
||
|
|
|
||
|
|
# 2. Load environment
|
||
|
|
source /tmp/typedialog-env.sh
|
||
|
|
|
||
|
|
# 3. Test redaction (no service) - Simple example
|
||
|
|
typedialog form examples/08-encryption/simple-login.toml --redact --format json
|
||
|
|
|
||
|
|
# 4. Test Age encryption (requires ~/.age/key.txt)
|
||
|
|
typedialog form examples/08-encryption/simple-login.toml \
|
||
|
|
--encrypt --backend age \
|
||
|
|
--key-file ~/.age/key.txt \
|
||
|
|
--format json
|
||
|
|
|
||
|
|
# 5. Full feature demo (all encryption features)
|
||
|
|
typedialog form examples/08-encryption/credentials.toml --redact --format json
|
||
|
|
|
||
|
|
# 6. Run all integration tests
|
||
|
|
cargo test --test nickel_integration test_encryption -- --nocapture
|
||
|
|
```
|
||
|
|
|
||
|
|
## Example Forms
|
||
|
|
|
||
|
|
### Simple Login Form (`examples/08-encryption/simple-login.toml`)
|
||
|
|
|
||
|
|
Minimal example for quick testing:
|
||
|
|
|
||
|
|
- `username` (plaintext)
|
||
|
|
- `password` (sensitive, auto-detected from type)
|
||
|
|
|
||
|
|
**Use this for**:
|
||
|
|
|
||
|
|
- Quick verification of redaction
|
||
|
|
- Basic Age encryption testing
|
||
|
|
- First-time setup validation
|
||
|
|
|
||
|
|
### Full Credentials Form (`examples/08-encryption/credentials.toml`)
|
||
|
|
|
||
|
|
Comprehensive example demonstrating all encryption features:
|
||
|
|
|
||
|
|
- Non-sensitive fields: username, email, company
|
||
|
|
- Auto-detected sensitive: password, confirm_password (FieldType::Password)
|
||
|
|
- Explicitly marked sensitive: api_token, ssh_key, database_url
|
||
|
|
- Field-level backends: vault_token (RustyVault config)
|
||
|
|
- Override: demo_password (type=password but NOT sensitive)
|
||
|
|
|
||
|
|
**Use this for**:
|
||
|
|
|
||
|
|
- Testing field-level sensitivity control
|
||
|
|
- Field-specific encryption backend configuration
|
||
|
|
- Demonstrating RustyVault setup
|
||
|
|
|
||
|
|
### Nickel Schema (`examples/08-encryption/nickel-secrets.ncl`)
|
||
|
|
|
||
|
|
Demonstrates encryption in Nickel schema language:
|
||
|
|
|
||
|
|
- `Sensitive Backend="age"` annotations
|
||
|
|
- Key path specification
|
||
|
|
- Nested structure with sensitive fields
|
||
|
|
|
||
|
|
**Use this for**:
|
||
|
|
|
||
|
|
- Understanding Nickel contract syntax
|
||
|
|
- Converting Nickel schemas to TOML forms
|
||
|
|
|
||
|
|
See `examples/08-encryption/README.md` for detailed examples and testing instructions.
|
||
|
|
|
||
|
|
## Current Status
|
||
|
|
|
||
|
|
✅ **Age (Local encryption)** - Ready to test
|
||
|
|
|
||
|
|
- Public key: Generated automatically
|
||
|
|
- Private key: `~/.age/key.txt`
|
||
|
|
- No service required, uses CLI tool
|
||
|
|
- Forms ready: `simple-login.toml`, `credentials.toml`
|
||
|
|
|
||
|
|
✅ **Redaction** - Fully functional
|
||
|
|
|
||
|
|
- Works without any encryption service
|
||
|
|
- Auto-detects sensitive fields from FieldType::Password
|
||
|
|
- Field-level control with explicit `sensitive` flag
|
||
|
|
|
||
|
|
⏳ **RustyVault (HTTP service)** - Framework ready, tests pending
|
||
|
|
|
||
|
|
- Needs: Docker or manual build
|
||
|
|
- Service: `http://localhost:8200`
|
||
|
|
- API: Transit secrets engine
|
||
|
|
- Configuration demo: `credentials.toml` vault_token field
|
||
|
|
|
||
|
|
## Test Results
|
||
|
|
|
||
|
|
**Tests passing (redaction, metadata mapping):**
|
||
|
|
|
||
|
|
```text
|
||
|
|
cargo test --test nickel_integration test_encryption
|
||
|
|
```
|
||
|
|
|
||
|
|
Output:
|
||
|
|
|
||
|
|
```text
|
||
|
|
running 5 tests
|
||
|
|
test test_encryption_metadata_parsing ... ok
|
||
|
|
test test_encryption_metadata_in_nickel_field ... ok
|
||
|
|
test test_encryption_auto_detection_from_field_type ... ok
|
||
|
|
test test_encryption_roundtrip_with_redaction ... ok
|
||
|
|
test test_encryption_metadata_to_field_definition ... ok
|
||
|
|
|
||
|
|
test result: ok. 5 passed; 0 failed
|
||
|
|
```
|
||
|
|
|
||
|
|
All tests use the example forms for verification.
|
||
|
|
|
||
|
|
## Next Steps for Full Encryption Testing
|
||
|
|
|
||
|
|
### 1. Create test forms with encryption
|
||
|
|
|
||
|
|
**test_form_age.toml:**
|
||
|
|
|
||
|
|
```toml
|
||
|
|
name = "age_test"
|
||
|
|
display_mode = "complete"
|
||
|
|
|
||
|
|
[[fields]]
|
||
|
|
name = "username"
|
||
|
|
type = "text"
|
||
|
|
prompt = "Username"
|
||
|
|
sensitive = false
|
||
|
|
|
||
|
|
[[fields]]
|
||
|
|
name = "password"
|
||
|
|
type = "password"
|
||
|
|
prompt = "Password"
|
||
|
|
sensitive = true
|
||
|
|
encryption_backend = "age"
|
||
|
|
|
||
|
|
[fields.encryption_config]
|
||
|
|
key = "~/.age/key.txt"
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2. Test Age encryption manually
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Generate test message
|
||
|
|
echo "test-secret-123" > /tmp/test.txt
|
||
|
|
|
||
|
|
# Get public key
|
||
|
|
PUBLIC_KEY=$(grep "^public key:" ~/.age/key.txt | cut -d' ' -f3)
|
||
|
|
|
||
|
|
# Encrypt
|
||
|
|
age -r "$PUBLIC_KEY" /tmp/test.txt > /tmp/test.age
|
||
|
|
|
||
|
|
# Decrypt
|
||
|
|
age -d -i ~/.age/key.txt /tmp/test.age
|
||
|
|
# Output: test-secret-123
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3. Implement Age roundtrip test
|
||
|
|
|
||
|
|
File: `crates/typedialog-core/tests/encryption_roundtrip.rs`
|
||
|
|
|
||
|
|
```rust
|
||
|
|
#[test]
|
||
|
|
fn test_age_encrypt_decrypt_roundtrip() {
|
||
|
|
use typedialog_core::helpers::{EncryptionContext, transform_results};
|
||
|
|
|
||
|
|
let mut results = HashMap::new();
|
||
|
|
results.insert("secret".to_string(), json!("my-password"));
|
||
|
|
|
||
|
|
let field = FieldDefinition {
|
||
|
|
name: "secret".to_string(),
|
||
|
|
sensitive: Some(true),
|
||
|
|
encryption_backend: Some("age".to_string()),
|
||
|
|
encryption_config: Some({
|
||
|
|
let mut m = HashMap::new();
|
||
|
|
m.insert("key".to_string(), "~/.age/key.txt".to_string());
|
||
|
|
m
|
||
|
|
}),
|
||
|
|
..Default::default()
|
||
|
|
};
|
||
|
|
|
||
|
|
// Encrypt
|
||
|
|
let context = EncryptionContext::encrypt_with("age", Default::default());
|
||
|
|
let encrypted = transform_results(&results, &[field.clone()], &context, None)
|
||
|
|
.expect("Encryption failed");
|
||
|
|
|
||
|
|
// Verify ciphertext
|
||
|
|
let ciphertext = encrypted.get("secret").unwrap().as_str().unwrap();
|
||
|
|
assert!(ciphertext.starts_with("age1-"), "Should be Age format");
|
||
|
|
assert_ne!(ciphertext, "my-password", "Should be encrypted");
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### 4. Test with RustyVault (optional, requires Docker)
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Pull RustyVault image
|
||
|
|
docker pull rustyvault:latest
|
||
|
|
|
||
|
|
# Re-run setup script
|
||
|
|
./scripts/encryption-test-setup.sh
|
||
|
|
|
||
|
|
# Test encryption with vault
|
||
|
|
typedialog form test_form_age.toml \
|
||
|
|
--encrypt --backend rustyvault \
|
||
|
|
--vault-addr http://localhost:8200 \
|
||
|
|
--vault-token root \
|
||
|
|
--vault-key-path transit/keys/typedialog-key \
|
||
|
|
--format json
|
||
|
|
```
|
||
|
|
|
||
|
|
## Verification Checklist
|
||
|
|
|
||
|
|
- [ ] Age installed: `age --version`
|
||
|
|
- [ ] Age keys generated: `cat ~/.age/key.txt`
|
||
|
|
- [ ] Test redaction: `typedialog form ... --redact`
|
||
|
|
- [ ] Run encryption tests: `cargo test --test nickel_integration test_encryption`
|
||
|
|
- [ ] All 5 tests passing
|
||
|
|
- [ ] (Optional) Docker available for RustyVault
|
||
|
|
- [ ] (Optional) RustyVault running: `curl http://localhost:8200/v1/sys/health`
|
||
|
|
|
||
|
|
## Documentation
|
||
|
|
|
||
|
|
Full setup guide: See `docs/encryption-services-setup.md`
|