# 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