- Add internal/types package with type-safe wrappers for IDs, hashes, paths, and credentials (FileID, BlobID, ChunkHash, etc.) - Implement driver.Valuer and sql.Scanner for UUID-based types - Add `vaultik version` command showing version, commit, go version - Add `--verify` flag to restore command that checksums all restored files against expected chunk hashes with progress bar - Remove fetch.go (dead code, functionality in restore) - Clean up TODO.md, remove completed items - Update all database and snapshot code to use new custom types
148 lines
4.4 KiB
Go
148 lines
4.4 KiB
Go
package config
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
)
|
|
|
|
const (
|
|
TEST_SNEAK_AGE_PUBLIC_KEY = "age1278m9q7dp3chsh2dcy82qk27v047zywyvtxwnj4cvt0z65jw6a7q5dqhfj"
|
|
TEST_INTEGRATION_AGE_PUBLIC_KEY = "age1ezrjmfpwsc95svdg0y54mums3zevgzu0x0ecq2f7tp8a05gl0sjq9q9wjg"
|
|
TEST_INTEGRATION_AGE_PRIVATE_KEY = "AGE-SECRET-KEY-19CR5YSFW59HM4TLD6GXVEDMZFTVVF7PPHKUT68TXSFPK7APHXA2QS2NJA5"
|
|
)
|
|
|
|
func TestMain(m *testing.M) {
|
|
// Set up test environment
|
|
testConfigPath := filepath.Join("..", "..", "test", "config.yaml")
|
|
if absPath, err := filepath.Abs(testConfigPath); err == nil {
|
|
_ = os.Setenv("VAULTIK_CONFIG", absPath)
|
|
}
|
|
|
|
code := m.Run()
|
|
os.Exit(code)
|
|
}
|
|
|
|
// TestConfigLoad ensures the config package can be imported and basic functionality works
|
|
func TestConfigLoad(t *testing.T) {
|
|
// Use the test config file
|
|
configPath := os.Getenv("VAULTIK_CONFIG")
|
|
if configPath == "" {
|
|
t.Fatal("VAULTIK_CONFIG environment variable not set")
|
|
}
|
|
|
|
// Test loading the config
|
|
cfg, err := Load(configPath)
|
|
if err != nil {
|
|
t.Fatalf("Failed to load config: %v", err)
|
|
}
|
|
|
|
// Basic validation
|
|
if len(cfg.AgeRecipients) != 2 {
|
|
t.Errorf("Expected 2 age recipients, got %d", len(cfg.AgeRecipients))
|
|
}
|
|
if cfg.AgeRecipients[0] != TEST_SNEAK_AGE_PUBLIC_KEY {
|
|
t.Errorf("Expected first age recipient to be %s, got '%s'", TEST_SNEAK_AGE_PUBLIC_KEY, cfg.AgeRecipients[0])
|
|
}
|
|
|
|
if len(cfg.Snapshots) != 1 {
|
|
t.Errorf("Expected 1 snapshot, got %d", len(cfg.Snapshots))
|
|
}
|
|
|
|
testSnap, ok := cfg.Snapshots["test"]
|
|
if !ok {
|
|
t.Fatal("Expected 'test' snapshot to exist")
|
|
}
|
|
|
|
if len(testSnap.Paths) != 2 {
|
|
t.Errorf("Expected 2 paths in test snapshot, got %d", len(testSnap.Paths))
|
|
}
|
|
|
|
if testSnap.Paths[0] != "/tmp/vaultik-test-source" {
|
|
t.Errorf("Expected first path to be '/tmp/vaultik-test-source', got '%s'", testSnap.Paths[0])
|
|
}
|
|
|
|
if cfg.S3.Bucket != "vaultik-test-bucket" {
|
|
t.Errorf("Expected S3 bucket to be 'vaultik-test-bucket', got '%s'", cfg.S3.Bucket)
|
|
}
|
|
|
|
if cfg.Hostname != "test-host" {
|
|
t.Errorf("Expected hostname to be 'test-host', got '%s'", cfg.Hostname)
|
|
}
|
|
}
|
|
|
|
// TestConfigFromEnv tests loading config path from environment variable
|
|
func TestConfigFromEnv(t *testing.T) {
|
|
configPath := os.Getenv("VAULTIK_CONFIG")
|
|
if configPath == "" {
|
|
t.Skip("VAULTIK_CONFIG not set")
|
|
}
|
|
|
|
// Verify the file exists
|
|
if _, err := os.Stat(configPath); os.IsNotExist(err) {
|
|
t.Errorf("Config file does not exist at path from VAULTIK_CONFIG: %s", configPath)
|
|
}
|
|
}
|
|
|
|
// TestExtractAgeSecretKey tests extraction of AGE-SECRET-KEY from various inputs
|
|
func TestExtractAgeSecretKey(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
input string
|
|
expected string
|
|
}{
|
|
{
|
|
name: "plain key",
|
|
input: "AGE-SECRET-KEY-19CR5YSFW59HM4TLD6GXVEDMZFTVVF7PPHKUT68TXSFPK7APHXA2QS2NJA5",
|
|
expected: "AGE-SECRET-KEY-19CR5YSFW59HM4TLD6GXVEDMZFTVVF7PPHKUT68TXSFPK7APHXA2QS2NJA5",
|
|
},
|
|
{
|
|
name: "key with trailing newline",
|
|
input: "AGE-SECRET-KEY-19CR5YSFW59HM4TLD6GXVEDMZFTVVF7PPHKUT68TXSFPK7APHXA2QS2NJA5\n",
|
|
expected: "AGE-SECRET-KEY-19CR5YSFW59HM4TLD6GXVEDMZFTVVF7PPHKUT68TXSFPK7APHXA2QS2NJA5",
|
|
},
|
|
{
|
|
name: "full age-keygen output",
|
|
input: `# created: 2025-01-14T12:00:00Z
|
|
# public key: age1ezrjmfpwsc95svdg0y54mums3zevgzu0x0ecq2f7tp8a05gl0sjq9q9wjg
|
|
AGE-SECRET-KEY-19CR5YSFW59HM4TLD6GXVEDMZFTVVF7PPHKUT68TXSFPK7APHXA2QS2NJA5
|
|
`,
|
|
expected: "AGE-SECRET-KEY-19CR5YSFW59HM4TLD6GXVEDMZFTVVF7PPHKUT68TXSFPK7APHXA2QS2NJA5",
|
|
},
|
|
{
|
|
name: "age-keygen output with extra blank lines",
|
|
input: `# created: 2025-01-14T12:00:00Z
|
|
# public key: age1ezrjmfpwsc95svdg0y54mums3zevgzu0x0ecq2f7tp8a05gl0sjq9q9wjg
|
|
|
|
AGE-SECRET-KEY-19CR5YSFW59HM4TLD6GXVEDMZFTVVF7PPHKUT68TXSFPK7APHXA2QS2NJA5
|
|
|
|
`,
|
|
expected: "AGE-SECRET-KEY-19CR5YSFW59HM4TLD6GXVEDMZFTVVF7PPHKUT68TXSFPK7APHXA2QS2NJA5",
|
|
},
|
|
{
|
|
name: "key with leading whitespace",
|
|
input: " AGE-SECRET-KEY-19CR5YSFW59HM4TLD6GXVEDMZFTVVF7PPHKUT68TXSFPK7APHXA2QS2NJA5 ",
|
|
expected: "AGE-SECRET-KEY-19CR5YSFW59HM4TLD6GXVEDMZFTVVF7PPHKUT68TXSFPK7APHXA2QS2NJA5",
|
|
},
|
|
{
|
|
name: "empty input",
|
|
input: "",
|
|
expected: "",
|
|
},
|
|
{
|
|
name: "only comments",
|
|
input: "# this is a comment\n# another comment",
|
|
expected: "# this is a comment\n# another comment",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := extractAgeSecretKey(tt.input)
|
|
if result != tt.expected {
|
|
t.Errorf("extractAgeSecretKey(%q) = %q, want %q", tt.input, result, tt.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|