#!/bin/bash set -e # Exit on any error # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # Test configuration TEST_MNEMONIC="abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about" TEST_PASSPHRASE="test-passphrase-123" TEMP_DIR="$(mktemp -d)" SECRET_BINARY="./secret" echo -e "${BLUE}=== Secret Manager Comprehensive Test Script ===${NC}" echo -e "${YELLOW}Using temporary directory: $TEMP_DIR${NC}" # Function to print test steps print_step() { echo -e "\n${BLUE}Step $1: $2${NC}" } # Function to print success print_success() { echo -e "${GREEN}✓ $1${NC}" } # Function to print error and exit print_error() { echo -e "${RED}✗ $1${NC}" exit 1 } # Function to print warning (for expected failures) print_warning() { echo -e "${YELLOW}⚠ $1${NC}" } # Function to clear state directory and reset environment reset_state() { echo -e "${YELLOW}Resetting state directory...${NC}" # Safety checks before removing anything if [ -z "$TEMP_DIR" ]; then print_error "TEMP_DIR is not set, cannot reset state safely" fi if [ ! -d "$TEMP_DIR" ]; then print_error "TEMP_DIR ($TEMP_DIR) is not a directory, cannot reset state safely" fi # Additional safety: ensure TEMP_DIR looks like a temp directory case "$TEMP_DIR" in /tmp/* | /var/folders/* | */tmp/*) # Looks like a reasonable temp directory path ;; *) print_error "TEMP_DIR ($TEMP_DIR) does not look like a safe temporary directory path" ;; esac # Now it's safe to remove contents - use find to avoid glob expansion issues find "${TEMP_DIR:?}" -mindepth 1 -delete 2>/dev/null || true unset SB_SECRET_MNEMONIC unset SB_UNLOCK_PASSPHRASE export SB_SECRET_STATE_DIR="$TEMP_DIR" } # Cleanup function cleanup() { echo -e "\n${YELLOW}Cleaning up...${NC}" rm -rf "$TEMP_DIR" unset SB_SECRET_STATE_DIR unset SB_SECRET_MNEMONIC unset SB_UNLOCK_PASSPHRASE echo -e "${GREEN}Cleanup complete${NC}" } # Set cleanup trap trap cleanup EXIT # Build the secret binary if it doesn't exist if [ ! -f "$SECRET_BINARY" ]; then print_step "0" "Building secret binary" go build -o "$SECRET_BINARY" ./cmd/secret/ print_success "Built secret binary" fi # Test 1: Set up environment variables print_step "1" "Setting up environment variables" export SB_SECRET_STATE_DIR="$TEMP_DIR" export SB_SECRET_MNEMONIC="$TEST_MNEMONIC" print_success "Environment variables set" echo " SB_SECRET_STATE_DIR=$SB_SECRET_STATE_DIR" echo " SB_SECRET_MNEMONIC=$TEST_MNEMONIC" # Test 2: Initialize the secret manager (should create default vault) print_step "2" "Initializing secret manager (creates default vault)" # Set passphrase for init command only export SB_UNLOCK_PASSPHRASE="$TEST_PASSPHRASE" if $SECRET_BINARY init > /dev/null 2>&1; then print_success "Secret manager initialized with default vault" else print_error "Failed to initialize secret manager" fi # Unset passphrase after init unset SB_UNLOCK_PASSPHRASE # Verify directory structure was created if [ -d "$TEMP_DIR" ]; then print_success "State directory created: $TEMP_DIR" else print_error "State directory was not created" fi # Test 3: Vault management print_step "3" "Testing vault management" # List vaults (should show default) echo "Listing vaults..." if $SECRET_BINARY vault list > /dev/null 2>&1; then VAULTS=$($SECRET_BINARY vault list) echo "Available vaults: $VAULTS" print_success "Listed vaults successfully" else print_error "Failed to list vaults" fi # Create a new vault echo "Creating new vault 'work'..." if $SECRET_BINARY vault create work > /dev/null 2>&1; then print_success "Created vault 'work'" else print_error "Failed to create vault 'work'" fi # Create another vault echo "Creating new vault 'personal'..." if $SECRET_BINARY vault create personal > /dev/null 2>&1; then print_success "Created vault 'personal'" else print_error "Failed to create vault 'personal'" fi # List vaults again (should show default, work, personal) echo "Listing vaults after creation..." if $SECRET_BINARY vault list > /dev/null 2>&1; then VAULTS=$($SECRET_BINARY vault list) echo "Available vaults: $VAULTS" print_success "Listed vaults after creation" else print_error "Failed to list vaults after creation" fi # Switch to work vault echo "Switching to 'work' vault..." if $SECRET_BINARY vault select work > /dev/null 2>&1; then print_success "Switched to 'work' vault" else print_error "Failed to switch to 'work' vault" fi # Test 4: Import functionality with different environment variable combinations print_step "4" "Testing import functionality with different environment variable combinations" # Test 4a: Import with mnemonic env var set, no passphrase env var echo -e "\n${YELLOW}Test 4a: Import with SB_SECRET_MNEMONIC set, SB_UNLOCK_PASSPHRASE unset${NC}" reset_state export SB_SECRET_MNEMONIC="$TEST_MNEMONIC" # Create a vault first if $SECRET_BINARY vault create test-vault > /dev/null 2>&1; then print_success "Created test-vault for import testing" else print_error "Failed to create test-vault" fi # Import should prompt for passphrase echo "Importing with mnemonic env var set, should prompt for passphrase..." if echo "$TEST_PASSPHRASE" | $SECRET_BINARY import test-vault > /dev/null 2>&1; then print_success "Import succeeded with mnemonic env var (prompted for passphrase)" else print_error "Import failed with mnemonic env var" fi # Test 4b: Import with passphrase env var set, no mnemonic env var echo -e "\n${YELLOW}Test 4b: Import with SB_UNLOCK_PASSPHRASE set, SB_SECRET_MNEMONIC unset${NC}" reset_state export SB_UNLOCK_PASSPHRASE="$TEST_PASSPHRASE" # Create a vault first if $SECRET_BINARY vault create test-vault2 > /dev/null 2>&1; then print_success "Created test-vault2 for import testing" else print_error "Failed to create test-vault2" fi # Import should prompt for mnemonic echo "Importing with passphrase env var set, should prompt for mnemonic..." if echo "$TEST_MNEMONIC" | $SECRET_BINARY import test-vault2 > /dev/null 2>&1; then print_success "Import succeeded with passphrase env var (prompted for mnemonic)" else print_error "Import failed with passphrase env var" fi # Test 4c: Import with both env vars set echo -e "\n${YELLOW}Test 4c: Import with both SB_SECRET_MNEMONIC and SB_UNLOCK_PASSPHRASE set${NC}" reset_state export SB_SECRET_MNEMONIC="$TEST_MNEMONIC" export SB_UNLOCK_PASSPHRASE="$TEST_PASSPHRASE" # Create a vault first if $SECRET_BINARY vault create test-vault3 > /dev/null 2>&1; then print_success "Created test-vault3 for import testing" else print_error "Failed to create test-vault3" fi # Import should not prompt for anything echo "Importing with both env vars set, should not prompt..." if $SECRET_BINARY import test-vault3 > /dev/null 2>&1; then print_success "Import succeeded with both env vars (no prompts)" else print_error "Import failed with both env vars" fi # Test 4d: Import with neither env var set echo -e "\n${YELLOW}Test 4d: Import with neither SB_SECRET_MNEMONIC nor SB_UNLOCK_PASSPHRASE set${NC}" reset_state # Create a vault first if $SECRET_BINARY vault create test-vault4 > /dev/null 2>&1; then print_success "Created test-vault4 for import testing" else print_error "Failed to create test-vault4" fi # Import should prompt for both mnemonic and passphrase echo "Importing with neither env var set, should prompt for both..." if expect -c " spawn $SECRET_BINARY import test-vault4 expect \"Enter your BIP39 mnemonic phrase:\" send \"$TEST_MNEMONIC\n\" expect \"Enter passphrase for unlock key:\" send \"$TEST_PASSPHRASE\n\" expect \"Confirm passphrase:\" send \"$TEST_PASSPHRASE\n\" expect eof " > /dev/null 2>&1; then print_success "Import succeeded with no env vars (prompted for both)" else print_error "Import failed with no env vars" fi # Test 4e: Import into non-existent vault (should fail) echo -e "\n${YELLOW}Test 4e: Import into non-existent vault (should fail)${NC}" reset_state export SB_SECRET_MNEMONIC="$TEST_MNEMONIC" export SB_UNLOCK_PASSPHRASE="$TEST_PASSPHRASE" echo "Importing into non-existent vault (should fail)..." if $SECRET_BINARY import nonexistent-vault > /dev/null 2>&1; then print_error "Import should have failed for non-existent vault" else print_success "Import correctly failed for non-existent vault" fi # Test 4f: Import with invalid mnemonic (should fail) echo -e "\n${YELLOW}Test 4f: Import with invalid mnemonic (should fail)${NC}" reset_state export SB_SECRET_MNEMONIC="invalid mnemonic phrase that should not work" export SB_UNLOCK_PASSPHRASE="$TEST_PASSPHRASE" # Create a vault first if $SECRET_BINARY vault create test-vault5 > /dev/null 2>&1; then print_success "Created test-vault5 for invalid mnemonic testing" else print_error "Failed to create test-vault5" fi echo "Importing with invalid mnemonic (should fail)..." if $SECRET_BINARY import test-vault5 > /dev/null 2>&1; then print_error "Import should have failed with invalid mnemonic" else print_success "Import correctly failed with invalid mnemonic" fi # Reset state for remaining tests reset_state export SB_SECRET_MNEMONIC="$TEST_MNEMONIC" # Test 5: Original import functionality test (using mnemonic-based) print_step "5" "Testing original import functionality" # Initialize to create default vault if (echo "$TEST_PASSPHRASE"; echo "$TEST_PASSPHRASE") | $SECRET_BINARY init > /dev/null 2>&1; then print_success "Initialized for Step 5 testing" else print_error "Failed to initialize for Step 5 testing" fi # Create work vault for import testing if $SECRET_BINARY vault create work > /dev/null 2>&1; then print_success "Created work vault for import testing" else print_error "Failed to create work vault" fi # Switch to work vault echo "Switching to 'work' vault..." if $SECRET_BINARY vault select work > /dev/null 2>&1; then print_success "Switched to 'work' vault" else print_error "Failed to switch to 'work' vault" fi # Import into work vault using mnemonic (should derive long-term key) echo "Importing mnemonic into 'work' vault..." # Set passphrase for import command only export SB_UNLOCK_PASSPHRASE="$TEST_PASSPHRASE" if $SECRET_BINARY import work > /dev/null 2>&1; then print_success "Imported mnemonic into 'work' vault" else print_error "Failed to import mnemonic into 'work' vault" fi # Unset passphrase after import unset SB_UNLOCK_PASSPHRASE # Switch back to default vault echo "Switching back to 'default' vault..." if $SECRET_BINARY vault select default > /dev/null 2>&1; then print_success "Switched back to 'default' vault" else print_error "Failed to switch back to 'default' vault" fi # Test 6: Unlock key management print_step "6" "Testing unlock key management" # Create passphrase-protected unlock key echo "Creating passphrase-protected unlock key..." # Note: This test uses stdin input instead of environment variable to test the traditional approach if echo "$TEST_PASSPHRASE" | $SECRET_BINARY keys add passphrase > /dev/null 2>&1; then print_success "Created passphrase-protected unlock key" else print_error "Failed to create passphrase-protected unlock key" fi # List unlock keys echo "Listing unlock keys..." if $SECRET_BINARY keys list > /dev/null 2>&1; then KEYS=$($SECRET_BINARY keys list) echo "Available unlock keys: $KEYS" print_success "Listed unlock keys" else print_error "Failed to list unlock keys" fi # Test 7: Secret management with mnemonic (keyless operation) print_step "7" "Testing mnemonic-based secret operations (keyless)" # Add secrets using mnemonic (no unlock key required) echo "Adding secrets using mnemonic-based long-term key..." # Test secret 1 if echo "my-super-secret-password" | $SECRET_BINARY add "database/password" > /dev/null 2>&1; then print_success "Added secret: database/password" else print_error "Failed to add secret: database/password" fi # Test secret 2 if echo "api-key-12345" | $SECRET_BINARY add "api/key" > /dev/null 2>&1; then print_success "Added secret: api/key" else print_error "Failed to add secret: api/key" fi # Test secret 3 (with path) if echo "ssh-private-key-content" | $SECRET_BINARY add "ssh/private-key" > /dev/null 2>&1; then print_success "Added secret: ssh/private-key" else print_error "Failed to add secret: ssh/private-key" fi # Test secret 4 (with dots and underscores) if echo "jwt-secret-token" | $SECRET_BINARY add "app.config_jwt_secret" > /dev/null 2>&1; then print_success "Added secret: app.config_jwt_secret" else print_error "Failed to add secret: app.config_jwt_secret" fi # Retrieve secrets using mnemonic echo "Retrieving secrets using mnemonic-based long-term key..." # Retrieve and verify secret 1 RETRIEVED_SECRET1=$($SECRET_BINARY get "database/password" 2>/dev/null) if [ "$RETRIEVED_SECRET1" = "my-super-secret-password" ]; then print_success "Retrieved and verified secret: database/password" else print_error "Failed to retrieve or verify secret: database/password" fi # Retrieve and verify secret 2 RETRIEVED_SECRET2=$($SECRET_BINARY get "api/key" 2>/dev/null) if [ "$RETRIEVED_SECRET2" = "api-key-12345" ]; then print_success "Retrieved and verified secret: api/key" else print_error "Failed to retrieve or verify secret: api/key" fi # Retrieve and verify secret 3 RETRIEVED_SECRET3=$($SECRET_BINARY get "ssh/private-key" 2>/dev/null) if [ "$RETRIEVED_SECRET3" = "ssh-private-key-content" ]; then print_success "Retrieved and verified secret: ssh/private-key" else print_error "Failed to retrieve or verify secret: ssh/private-key" fi # List all secrets echo "Listing all secrets..." if $SECRET_BINARY list > /dev/null 2>&1; then SECRETS=$($SECRET_BINARY list) echo "Secrets in current vault:" echo "$SECRETS" | while read -r secret; do echo " - $secret" done print_success "Listed all secrets" else print_error "Failed to list secrets" fi # Test 8: Secret management without mnemonic (traditional unlock key approach) print_step "8" "Testing traditional unlock key approach" # Temporarily unset mnemonic to test traditional approach unset SB_SECRET_MNEMONIC # Add a secret using traditional unlock key approach echo "Adding secret using traditional unlock key..." if echo "traditional-secret-value" | $SECRET_BINARY add "traditional/secret" > /dev/null 2>&1; then print_success "Added secret using traditional approach: traditional/secret" else print_error "Failed to add secret using traditional approach" fi # Retrieve secret using traditional unlock key approach RETRIEVED_TRADITIONAL=$($SECRET_BINARY get "traditional/secret" 2>/dev/null) if [ "$RETRIEVED_TRADITIONAL" = "traditional-secret-value" ]; then print_success "Retrieved and verified traditional secret: traditional/secret" else print_error "Failed to retrieve or verify traditional secret" fi # Test 9: Advanced unlock key management print_step "9" "Testing advanced unlock key management" # Re-enable mnemonic for key operations export SB_SECRET_MNEMONIC="$TEST_MNEMONIC" # Create PGP unlock key (if GPG is available) echo "Testing PGP unlock key creation..." if command -v gpg >/dev/null 2>&1; then # This would require a GPG key ID - for testing we'll just check the command exists if $SECRET_BINARY keys add pgp --help > /dev/null 2>&1; then print_success "PGP unlock key command available" else print_warning "PGP unlock key command not yet implemented" fi else print_warning "GPG not available for PGP unlock key testing" fi # Test Secure Enclave (macOS only) if [[ "$OSTYPE" == "darwin"* ]]; then echo "Testing Secure Enclave unlock key creation..." if $SECRET_BINARY enroll sep > /dev/null 2>&1; then print_success "Created Secure Enclave unlock key" else print_warning "Secure Enclave unlock key creation not yet implemented" fi else print_warning "Secure Enclave only available on macOS" fi # Get current unlock key ID for testing echo "Getting current unlock key for testing..." if $SECRET_BINARY keys list > /dev/null 2>&1; then CURRENT_KEY_ID=$($SECRET_BINARY keys list | head -n1 | awk '{print $1}') if [ -n "$CURRENT_KEY_ID" ]; then print_success "Found unlock key ID: $CURRENT_KEY_ID" # Test key selection echo "Testing unlock key selection..." if $SECRET_BINARY key select "$CURRENT_KEY_ID" > /dev/null 2>&1; then print_success "Selected unlock key: $CURRENT_KEY_ID" else print_warning "Unlock key selection not yet implemented" fi fi fi # Test 10: Secret name validation and edge cases print_step "10" "Testing secret name validation and edge cases" # Test valid names VALID_NAMES=("valid-name" "valid.name" "valid_name" "valid/path/name" "123valid" "a" "very-long-name-with-many-parts/and/paths") for name in "${VALID_NAMES[@]}"; do if echo "test-value" | $SECRET_BINARY add "$name" --force > /dev/null 2>&1; then print_success "Valid name accepted: $name" else print_error "Valid name rejected: $name" fi done # Test invalid names (these should fail) echo "Testing invalid names (should fail)..." INVALID_NAMES=("Invalid-Name" "invalid name" "invalid@name" "invalid#name" "invalid%name" "") for name in "${INVALID_NAMES[@]}"; do if echo "test-value" | $SECRET_BINARY add "$name" > /dev/null 2>&1; then print_error "Invalid name accepted (should have been rejected): '$name'" else print_success "Invalid name correctly rejected: '$name'" fi done # Test 11: Overwrite protection and force flag print_step "11" "Testing overwrite protection and force flag" # Try to add existing secret without --force (should fail) if echo "new-value" | $SECRET_BINARY add "database/password" > /dev/null 2>&1; then print_error "Overwrite protection failed - secret was overwritten without --force" else print_success "Overwrite protection working - secret not overwritten without --force" fi # Try to add existing secret with --force (should succeed) if echo "new-password-value" | $SECRET_BINARY add "database/password" --force > /dev/null 2>&1; then print_success "Force overwrite working - secret overwritten with --force" # Verify the new value RETRIEVED_NEW=$($SECRET_BINARY get "database/password" 2>/dev/null) if [ "$RETRIEVED_NEW" = "new-password-value" ]; then print_success "Overwritten secret has correct new value" else print_error "Overwritten secret has incorrect value" fi else print_error "Force overwrite failed - secret not overwritten with --force" fi # Test 12: Cross-vault operations print_step "12" "Testing cross-vault operations" # Switch to work vault and add secrets there echo "Switching to 'work' vault for cross-vault testing..." if $SECRET_BINARY vault select work > /dev/null 2>&1; then print_success "Switched to 'work' vault" # Add work-specific secrets if echo "work-database-password" | $SECRET_BINARY add "work/database" > /dev/null 2>&1; then print_success "Added work-specific secret" else print_error "Failed to add work-specific secret" fi # List secrets in work vault if $SECRET_BINARY list > /dev/null 2>&1; then WORK_SECRETS=$($SECRET_BINARY list) echo "Secrets in work vault: $WORK_SECRETS" print_success "Listed work vault secrets" else print_error "Failed to list work vault secrets" fi else print_error "Failed to switch to 'work' vault" fi # Switch back to default vault echo "Switching back to 'default' vault..." if $SECRET_BINARY vault select default > /dev/null 2>&1; then print_success "Switched back to 'default' vault" # Verify default vault secrets are still there if $SECRET_BINARY get "database/password" > /dev/null 2>&1; then print_success "Default vault secrets still accessible" else print_error "Default vault secrets not accessible" fi else print_error "Failed to switch back to 'default' vault" fi # Test 13: File structure verification print_step "13" "Verifying file structure" echo "Checking file structure in $TEMP_DIR..." if [ -d "$TEMP_DIR/vaults.d/default/secrets.d" ]; then print_success "Default vault structure exists" # Check a specific secret's file structure SECRET_DIR="$TEMP_DIR/vaults.d/default/secrets.d/database%password" if [ -d "$SECRET_DIR" ]; then print_success "Secret directory exists: database%password" # Check required files for per-secret key architecture FILES=("value.age" "pub.age" "priv.age" "secret-metadata.json") for file in "${FILES[@]}"; do if [ -f "$SECRET_DIR/$file" ]; then print_success "Required file exists: $file" else print_error "Required file missing: $file" fi done else print_error "Secret directory not found" fi else print_error "Default vault structure not found" fi # Check work vault structure if [ -d "$TEMP_DIR/vaults.d/work" ]; then print_success "Work vault structure exists" else print_error "Work vault structure not found" fi # Check configuration files if [ -f "$TEMP_DIR/configuration.json" ]; then print_success "Global configuration file exists" else print_warning "Global configuration file not found (may not be implemented yet)" fi # Check current vault symlink if [ -L "$TEMP_DIR/currentvault" ] || [ -f "$TEMP_DIR/currentvault" ]; then print_success "Current vault link exists" else print_error "Current vault link not found" fi # Test 14: Environment variable error handling print_step "14" "Testing environment variable error handling" # Test with non-existent state directory export SB_SECRET_STATE_DIR="/nonexistent/directory" if $SECRET_BINARY get "database/password" > /dev/null 2>&1; then print_error "Should have failed with non-existent state directory" else print_success "Correctly failed with non-existent state directory" fi # Test init with non-existent directory (should work) if $SECRET_BINARY init > /dev/null 2>&1; then print_success "Init works with non-existent state directory" else print_error "Init should work with non-existent state directory" fi # Reset to working directory export SB_SECRET_STATE_DIR="$TEMP_DIR" # Test 15: Unlock key removal print_step "15" "Testing unlock key removal" # Re-enable mnemonic export SB_SECRET_MNEMONIC="$TEST_MNEMONIC" # Create another unlock key for testing removal echo "Creating additional unlock key for removal testing..." # Use stdin input instead of environment variable if echo "another-passphrase" | $SECRET_BINARY keys add passphrase > /dev/null 2>&1; then print_success "Created additional unlock key" # Get the key ID and try to remove it if $SECRET_BINARY keys list > /dev/null 2>&1; then KEY_TO_REMOVE=$($SECRET_BINARY keys list | tail -n1 | awk '{print $1}') if [ -n "$KEY_TO_REMOVE" ]; then echo "Attempting to remove unlock key: $KEY_TO_REMOVE" if $SECRET_BINARY keys rm "$KEY_TO_REMOVE" > /dev/null 2>&1; then print_success "Removed unlock key: $KEY_TO_REMOVE" else print_warning "Unlock key removal not yet implemented" fi fi fi else print_warning "Could not create additional unlock key for removal testing" fi # Test 16: Mixed approach compatibility print_step "16" "Testing mixed approach compatibility" # Verify mnemonic can access traditional secrets RETRIEVED_MIXED=$($SECRET_BINARY get "traditional/secret" 2>/dev/null) if [ "$RETRIEVED_MIXED" = "traditional-secret-value" ]; then print_success "Mnemonic can access traditional secrets" else print_error "Mnemonic cannot access traditional secrets" fi # Test without mnemonic but with unlock key unset SB_SECRET_MNEMONIC if $SECRET_BINARY get "database/password" > /dev/null 2>&1; then print_success "Traditional unlock key can access mnemonic-created secrets" else print_warning "Traditional unlock key cannot access mnemonic-created secrets (may need implementation)" fi # Re-enable mnemonic for final tests export SB_SECRET_MNEMONIC="$TEST_MNEMONIC" # Final summary echo -e "\n${GREEN}=== Test Summary ===${NC}" echo -e "${GREEN}✓ Environment variable support (SB_SECRET_STATE_DIR, SB_SECRET_MNEMONIC)${NC}" echo -e "${GREEN}✓ Secret manager initialization${NC}" echo -e "${GREEN}✓ Vault management (create, list, select)${NC}" echo -e "${GREEN}✓ Import functionality with all environment variable combinations${NC}" echo -e "${GREEN}✓ Import error handling (non-existent vault, invalid mnemonic)${NC}" echo -e "${GREEN}✓ Unlock key management (passphrase, PGP, SEP)${NC}" echo -e "${GREEN}✓ Mnemonic-based secret operations (keyless)${NC}" echo -e "${GREEN}✓ Traditional unlock key operations${NC}" echo -e "${GREEN}✓ Secret name validation${NC}" echo -e "${GREEN}✓ Overwrite protection and force flag${NC}" echo -e "${GREEN}✓ Cross-vault operations${NC}" echo -e "${GREEN}✓ Per-secret key file structure${NC}" echo -e "${GREEN}✓ Unlock key removal${NC}" echo -e "${GREEN}✓ Mixed approach compatibility${NC}" echo -e "${GREEN}✓ Error handling${NC}" echo -e "\n${GREEN}🎉 Comprehensive test completed!${NC}" # Show usage examples for all implemented functionality echo -e "\n${BLUE}=== Complete Usage Examples ===${NC}" echo -e "${YELLOW}# Environment setup:${NC}" echo "export SB_SECRET_STATE_DIR=\"/path/to/your/secrets\"" echo "export SB_SECRET_MNEMONIC=\"your twelve word mnemonic phrase here\"" echo "" echo -e "${YELLOW}# Initialization:${NC}" echo "secret init" echo "" echo -e "${YELLOW}# Vault management:${NC}" echo "secret vault list" echo "secret vault create work" echo "secret vault select work" echo "" echo -e "${YELLOW}# Import mnemonic (different combinations):${NC}" echo "# With mnemonic env var set:" echo "export SB_SECRET_MNEMONIC=\"abandon abandon...\"" echo "echo \"passphrase\" | secret import work" echo "" echo "# With passphrase env var set:" echo "export SB_UNLOCK_PASSPHRASE=\"passphrase\"" echo "echo \"abandon abandon...\" | secret import work" echo "" echo "# With both env vars set:" echo "export SB_SECRET_MNEMONIC=\"abandon abandon...\"" echo "export SB_UNLOCK_PASSPHRASE=\"passphrase\"" echo "secret import work" echo "" echo "# With neither env var set:" echo "(echo \"abandon abandon...\"; echo \"passphrase\") | secret import work" echo "" echo -e "${YELLOW}# Unlock key management:${NC}" echo "echo \"passphrase\" | secret keys add passphrase" echo "secret keys add pgp " echo "secret enroll sep # macOS only" echo "secret keys list" echo "secret key select " echo "secret keys rm " echo "" echo -e "${YELLOW}# Secret management:${NC}" echo "echo \"my-secret\" | secret add \"app/password\"" echo "echo \"my-secret\" | secret add \"app/password\" --force" echo "secret get \"app/password\"" echo "secret list" echo "" echo -e "${YELLOW}# Cross-vault operations:${NC}" echo "secret vault select work" echo "echo \"work-secret\" | secret add \"work/database\"" echo "secret vault select default"