secret/test_secret_manager.sh
2025-05-28 14:06:29 -07:00

785 lines
27 KiB
Bash
Executable File

#!/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 <gpg-key-id>"
echo "secret enroll sep # macOS only"
echo "secret keys list"
echo "secret key select <key-id>"
echo "secret keys rm <key-id>"
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"