test: Add comprehensive test suite for secret manager - CLI, debug, secret, and vault tests with in-memory filesystem for fast isolated testing

This commit is contained in:
2025-05-29 09:52:05 -07:00
parent 7dc14da4af
commit b26794e21a
4 changed files with 969 additions and 0 deletions

View File

@@ -0,0 +1,188 @@
package secret
import (
"bytes"
"os"
"path/filepath"
"testing"
"git.eeqj.de/sneak/secret/pkg/agehd"
"github.com/spf13/afero"
)
func TestPerSecretKeyFunctionality(t *testing.T) {
// Create an in-memory filesystem for testing
fs := afero.NewMemMapFs()
// Set up test environment variables
oldMnemonic := os.Getenv(EnvMnemonic)
defer func() {
if oldMnemonic == "" {
os.Unsetenv(EnvMnemonic)
} else {
os.Setenv(EnvMnemonic, oldMnemonic)
}
}()
// Set test mnemonic for direct encryption/decryption
testMnemonic := "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
os.Setenv(EnvMnemonic, testMnemonic)
// Set up a test vault structure
baseDir := "/test-config/berlin.sneak.pkg.secret"
stateDir := baseDir
vaultDir := filepath.Join(baseDir, "vaults.d", "test-vault")
// Create vault directory structure
err := fs.MkdirAll(filepath.Join(vaultDir, "secrets.d"), 0700)
if err != nil {
t.Fatalf("Failed to create vault directory: %v", err)
}
// Generate a long-term keypair for the vault using the test mnemonic
ltIdentity, err := agehd.DeriveIdentity(testMnemonic, 0)
if err != nil {
t.Fatalf("Failed to generate long-term identity: %v", err)
}
// Write long-term public key
ltPubKeyPath := filepath.Join(vaultDir, "pub.age")
err = afero.WriteFile(
fs,
ltPubKeyPath,
[]byte(ltIdentity.Recipient().String()),
0600,
)
if err != nil {
t.Fatalf("Failed to write long-term public key: %v", err)
}
// Set current vault
currentVaultPath := filepath.Join(baseDir, "currentvault")
err = afero.WriteFile(fs, currentVaultPath, []byte(vaultDir), 0600)
if err != nil {
t.Fatalf("Failed to set current vault: %v", err)
}
// Create vault instance
vault := NewVault(fs, "test-vault", stateDir)
// Test data
secretName := "test-secret"
secretValue := []byte("this is a test secret value")
// Test AddSecret
t.Run("AddSecret", func(t *testing.T) {
err := vault.AddSecret(secretName, secretValue, false)
if err != nil {
t.Fatalf("AddSecret failed: %v", err)
}
// Verify that all expected files were created
secretDir := filepath.Join(vaultDir, "secrets.d", secretName)
// Check value.age exists (the new per-secret key architecture format)
secretExists, err := afero.Exists(
fs,
filepath.Join(secretDir, "value.age"),
)
if err != nil || !secretExists {
t.Fatalf("value.age file was not created")
}
// Check metadata exists
metadataExists, err := afero.Exists(
fs,
filepath.Join(secretDir, "secret-metadata.json"),
)
if err != nil || !metadataExists {
t.Fatalf("secret-metadata.json file was not created")
}
t.Logf("All expected files created successfully")
})
// Test GetSecret
t.Run("GetSecret", func(t *testing.T) {
retrievedValue, err := vault.GetSecret(secretName)
if err != nil {
t.Fatalf("GetSecret failed: %v", err)
}
if !bytes.Equal(retrievedValue, secretValue) {
t.Fatalf(
"Retrieved value doesn't match original. Expected: %s, Got: %s",
string(secretValue),
string(retrievedValue),
)
}
t.Logf("Successfully retrieved secret: %s", string(retrievedValue))
})
// Test that different secrets get different keys
t.Run("DifferentSecretsGetDifferentKeys", func(t *testing.T) {
secretName2 := "test-secret-2"
secretValue2 := []byte("this is another test secret")
// Add second secret
err := vault.AddSecret(secretName2, secretValue2, false)
if err != nil {
t.Fatalf("Failed to add second secret: %v", err)
}
// Verify both secrets can be retrieved correctly
value1, err := vault.GetSecret(secretName)
if err != nil {
t.Fatalf("Failed to retrieve first secret: %v", err)
}
value2, err := vault.GetSecret(secretName2)
if err != nil {
t.Fatalf("Failed to retrieve second secret: %v", err)
}
if !bytes.Equal(value1, secretValue) {
t.Fatalf("First secret value mismatch")
}
if !bytes.Equal(value2, secretValue2) {
t.Fatalf("Second secret value mismatch")
}
t.Logf(
"Successfully verified that different secrets have different keys",
)
})
}
func TestSecretNameValidation(t *testing.T) {
tests := []struct {
name string
valid bool
}{
{"valid-name", true},
{"valid.name", true},
{"valid_name", true},
{"valid/path/name", true},
{"123valid", true},
{"", false},
{"Invalid-Name", false}, // uppercase not allowed
{"invalid name", false}, // space not allowed
{"invalid@name", false}, // @ not allowed
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
result := isValidSecretName(test.name)
if result != test.valid {
t.Errorf(
"isValidSecretName(%q) = %v, want %v",
test.name,
result,
test.valid,
)
}
})
}
}