nushell-plugins/nu_plugin_kms/TEST_VERIFICATION.md

507 lines
11 KiB
Markdown
Raw Normal View History

# nu_plugin_kms - Verification and Testing Guide
**Date**: 2025-10-08
**Status**: Ready for Testing
## Quick Verification
### 1. Verify Binary Exists
```bash
cd /Users/Akasha/project-provisioning/provisioning/core/plugins/nushell-plugins/nu_plugin_kms
# Check binary exists
ls -lh target/release/nu_plugin_kms
# Expected output:
# -rwxr-xr-x 1 user staff X.XM Oct 8 XX:XX target/release/nu_plugin_kms
```
### 2. Register Plugin with Nushell
```bash
# Register plugin
nu -c "plugin add target/release/nu_plugin_kms"
# Verify registration
nu -c "plugin list | where name =~ kms"
# Expected output shows commands:
# - kms encrypt
# - kms decrypt
# - kms generate-key
# - kms status
```
### 3. Test Plugin Help
```bash
# Check command help
nu -c "kms encrypt --help"
nu -c "kms decrypt --help"
nu -c "kms generate-key --help"
nu -c "kms status --help"
```
## Backend Testing
### Age Backend (Simplest - No External Dependencies)
#### Setup
```bash
# Install Age (if not already installed)
brew install age # macOS
# or
apt install age # Ubuntu/Debian
# Generate Age key
age-keygen -o ~/.age/test-key.txt
# Extract public key
export AGE_RECIPIENT=$(grep "public key:" ~/.age/test-key.txt | cut -d: -f2 | xargs)
export AGE_IDENTITY="$HOME/.age/test-key.txt"
echo "Age Recipient: $AGE_RECIPIENT"
echo "Age Identity: $AGE_IDENTITY"
```
#### Test Encryption
```bash
# Test 1: Encrypt with Age
nu -c "kms encrypt 'Hello, Age!' --backend age --key $AGE_RECIPIENT" > /tmp/encrypted.txt
cat /tmp/encrypted.txt
# Expected: -----BEGIN AGE ENCRYPTED FILE-----
# base64data...
# -----END AGE ENCRYPTED FILE-----
```
#### Test Decryption
```bash
# Test 2: Decrypt with Age
nu -c "kms decrypt '$(cat /tmp/encrypted.txt)' --backend age --key $AGE_IDENTITY"
# Expected output: Hello, Age!
```
#### Test Key Generation
```bash
# Test 3: Generate new Age key pair
nu -c "kms generate-key --backend age"
# Expected output (record):
# {
# plaintext: "AGE-SECRET-KEY-...",
# ciphertext: "age1..."
# }
```
#### Test Auto-Detection
```bash
# Test 4: Auto-detect Age backend
nu -c "kms status"
# Expected output:
# {
# backend: "age",
# available: true,
# config: "recipient: age1..., identity: set"
# }
```
### RustyVault Backend
#### Setup
```bash
# Start RustyVault in Docker
docker run -d --name rustyvault \
-p 8200:8200 \
-e VAULT_DEV_ROOT_TOKEN_ID=test-token \
tongsuo/rustyvault:latest
# Wait for startup
sleep 5
# Set environment
export RUSTYVAULT_ADDR="http://localhost:8200"
export RUSTYVAULT_TOKEN="test-token"
# Enable Transit engine
docker exec rustyvault \
vault secrets enable transit
# Create encryption key
docker exec rustyvault \
vault write -f transit/keys/provisioning-main
```
#### Test Encryption
```bash
# Test 1: Encrypt with RustyVault
nu -c "kms encrypt 'Secret data!' --backend rustyvault --key provisioning-main"
# Expected output: vault:v1:XXXXXXXXXX...
```
#### Test Decryption
```bash
# Test 2: Encrypt and then decrypt
ENCRYPTED=$(nu -c "kms encrypt 'RustyVault test' --backend rustyvault --key provisioning-main")
nu -c "kms decrypt '$ENCRYPTED' --backend rustyvault --key provisioning-main"
# Expected output: RustyVault test
```
#### Test Key Generation
```bash
# Test 3: Generate AES256 data key
nu -c "kms generate-key --backend rustyvault --spec AES256"
# Expected output (record):
# {
# plaintext: "base64-encoded-key",
# ciphertext: "vault:v1:..."
# }
```
#### Test Status
```bash
# Test 4: Check RustyVault status
nu -c "kms status"
# Expected output:
# {
# backend: "rustyvault",
# available: true,
# config: "addr: http://localhost:8200"
# }
```
#### Cleanup
```bash
# Stop and remove RustyVault container
docker stop rustyvault
docker rm rustyvault
```
### HTTP Fallback Backend
#### Setup (Mock Server)
```bash
# Create simple mock KMS server with Python
cat > /tmp/mock_kms_server.py << 'EOF'
#!/usr/bin/env python3
from http.server import HTTPServer, BaseHTTPRequestHandler
import json
import base64
class KMSHandler(BaseHTTPRequestHandler):
def do_POST(self):
content_length = int(self.headers['Content-Length'])
body = self.rfile.read(content_length)
data = json.loads(body)
if self.path == '/api/v1/kms/encrypt':
# Simple XOR "encryption"
plaintext = base64.b64decode(data['plaintext'])
ciphertext = base64.b64encode(bytes(b ^ 0x42 for b in plaintext)).decode()
response = {'ciphertext': ciphertext}
elif self.path == '/api/v1/kms/decrypt':
# Simple XOR "decryption"
ciphertext = base64.b64decode(data['ciphertext'])
plaintext = base64.b64encode(bytes(b ^ 0x42 for b in ciphertext)).decode()
response = {'plaintext': plaintext}
elif self.path == '/api/v1/kms/generate-data-key':
# Generate random key
import secrets
key = secrets.token_bytes(32)
plaintext = base64.b64encode(key).decode()
ciphertext = base64.b64encode(bytes(b ^ 0x42 for b in key)).decode()
response = {'plaintext': plaintext, 'ciphertext': ciphertext}
else:
self.send_response(404)
self.end_headers()
return
self.send_response(200)
self.send_header('Content-Type', 'application/json')
self.end_headers()
self.wfile.write(json.dumps(response).encode())
if __name__ == '__main__':
server = HTTPServer(('localhost', 8081), KMSHandler)
print('Mock KMS server running on http://localhost:8081')
server.serve_forever()
EOF
chmod +x /tmp/mock_kms_server.py
# Start mock server in background
python3 /tmp/mock_kms_server.py &
MOCK_SERVER_PID=$!
# Set environment
export KMS_HTTP_URL="http://localhost:8081"
export KMS_HTTP_BACKEND="mock"
```
#### Test HTTP Backend
```bash
# Test 1: Encrypt
nu -c "kms encrypt 'HTTP test data' --backend mock"
# Test 2: Encrypt and decrypt
ENCRYPTED=$(nu -c "kms encrypt 'Round trip test' --backend mock")
nu -c "kms decrypt '$ENCRYPTED' --backend mock"
# Test 3: Generate key
nu -c "kms generate-key --backend mock --spec AES256"
# Test 4: Status
nu -c "kms status"
```
#### Cleanup
```bash
# Stop mock server
kill $MOCK_SERVER_PID
```
## Integration Tests
### Test Auto-Detection Priority
```bash
# Test 1: RustyVault has priority
export RUSTYVAULT_ADDR="http://localhost:8200"
export RUSTYVAULT_TOKEN="test-token"
export AGE_RECIPIENT="age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p"
nu -c "kms status"
# Expected: backend = "rustyvault"
# Test 2: Age when RustyVault not set
unset RUSTYVAULT_ADDR
unset RUSTYVAULT_TOKEN
nu -c "kms status"
# Expected: backend = "age"
# Test 3: HTTP fallback when nothing set
unset AGE_RECIPIENT
nu -c "kms status"
# Expected: backend = "cosmian" (or configured HTTP backend)
```
### Test Error Handling
```bash
# Test 1: Missing required flags
nu -c "kms encrypt 'data' --backend age"
# Expected: Error about missing --key recipient
# Test 2: Invalid recipient format
nu -c "kms encrypt 'data' --backend age --key invalid"
# Expected: Error about invalid Age recipient format
# Test 3: Missing environment variable
unset RUSTYVAULT_TOKEN
nu -c "kms encrypt 'data' --backend rustyvault"
# Expected: Error about RUSTYVAULT_TOKEN not set
# Test 4: Invalid key spec
nu -c "kms generate-key --backend rustyvault --spec INVALID"
# Expected: Error about invalid key spec
```
### Test Binary Data
```bash
# Test handling of non-UTF8 data
dd if=/dev/urandom bs=1024 count=1 | base64 > /tmp/random.b64
# Encrypt binary data
ENCRYPTED=$(cat /tmp/random.b64 | nu -c "kms encrypt $in --backend age --key $AGE_RECIPIENT")
# Decrypt and compare
DECRYPTED=$(nu -c "kms decrypt '$ENCRYPTED' --backend age --key $AGE_IDENTITY")
# Verify round-trip
if [ "$(cat /tmp/random.b64)" = "$DECRYPTED" ]; then
echo "✅ Binary data round-trip successful"
else
echo "❌ Binary data round-trip failed"
fi
```
## Performance Benchmarks
### Age Performance
```bash
# Benchmark encryption (1000 iterations)
time for i in {1..1000}; do
nu -c "kms encrypt 'test data' --backend age --key $AGE_RECIPIENT" > /dev/null
done
# Expected: ~10-20ms per operation
```
### RustyVault Performance
```bash
# Benchmark encryption (1000 iterations)
time for i in {1..1000}; do
nu -c "kms encrypt 'test data' --backend rustyvault --key provisioning-main" > /dev/null
done
# Expected: ~20-50ms per operation (includes HTTP overhead)
```
### Memory Usage
```bash
# Monitor memory during operations
while true; do
nu -c "kms encrypt 'test data' --backend age --key $AGE_RECIPIENT" > /dev/null
ps aux | grep nu_plugin_kms | grep -v grep
sleep 1
done
# Expected: Stable memory usage, no leaks
```
## Verification Checklist
### Compilation
- [x] `cargo check` passes
- [x] `cargo build --release` succeeds
- [x] Binary created in `target/release/nu_plugin_kms`
- [x] File size reasonable (< 50MB)
### Plugin Registration
- [ ] Plugin registers with Nushell
- [ ] All 4 commands visible in `plugin list`
- [ ] Help text accessible for each command
### Age Backend
- [ ] Encryption works with recipient
- [ ] Decryption works with identity file
- [ ] Key generation produces valid key pair
- [ ] Status shows correct backend
- [ ] Auto-detection works when env vars set
### RustyVault Backend
- [ ] Encryption works with Transit engine
- [ ] Decryption works correctly
- [ ] Data key generation works
- [ ] Status shows correct backend
- [ ] Auto-detection works when env vars set
### HTTP Fallback
- [ ] Encryption works with HTTP service
- [ ] Decryption works correctly
- [ ] Data key generation works
- [ ] Status shows correct backend
- [ ] Auto-detection works as fallback
### Error Handling
- [ ] Missing flags produce clear errors
- [ ] Invalid inputs rejected gracefully
- [ ] Network errors handled properly
- [ ] Missing env vars reported clearly
### Integration
- [ ] Auto-detection priority correct
- [ ] Multiple backends can coexist
- [ ] Environment switching works
- [ ] Binary data handled correctly
## Success Criteria
**Basic Functionality**
- All backends encrypt and decrypt successfully
- Key generation works for all backends
- Status command reports correctly
**Robustness**
- Error messages are clear and actionable
- No panics or crashes
- Memory usage is stable
**Performance**
- Operations complete in reasonable time
- No memory leaks
- Concurrent operations work
**Usability**
- Auto-detection works as expected
- Environment configuration is straightforward
- Help text is clear
## Troubleshooting
### Plugin Not Loading
```bash
# Check plugin is registered
nu -c "plugin list" | grep kms
# If not registered, add it
nu -c "plugin add /path/to/nu_plugin_kms"
# Check for errors
nu -c "plugin list --version"
```
### Environment Variables Not Working
```bash
# Check env vars are set
env | grep -E '(RUSTYVAULT|AGE|KMS)'
# Test in new shell
bash -c 'export AGE_RECIPIENT=...; nu -c "kms status"'
```
### Compilation Errors
```bash
# Clean build
cargo clean
# Update dependencies
cargo update
# Rebuild
cargo build --release
```
## Next Steps
After successful verification:
1. **Documentation**: Update user guides with examples
2. **Integration**: Connect to config encryption module
3. **CI/CD**: Add automated tests to pipeline
4. **Deployment**: Package for distribution
5. **Monitoring**: Add telemetry and logging