Switch from relative paths to bare names in pointer files
- currentvault now contains just the vault name (e.g., "default") - current-unlocker now contains just the unlocker name (e.g., "passphrase") - current version file now contains just the version (e.g., "20231215.001") - Resolution functions prepend the appropriate directory prefix
This commit is contained in:
parent
949a5aee61
commit
20690ba652
@ -332,12 +332,12 @@ func test01Initialize(t *testing.T, tempDir, testMnemonic, testPassphrase string
|
||||
defaultVaultDir := filepath.Join(vaultsDir, "default")
|
||||
verifyFileExists(t, defaultVaultDir)
|
||||
|
||||
// Check currentvault file contains the relative path
|
||||
// Check currentvault file contains the vault name
|
||||
currentVaultFile := filepath.Join(tempDir, "currentvault")
|
||||
targetBytes, err := os.ReadFile(currentVaultFile)
|
||||
require.NoError(t, err, "should be able to read currentvault file")
|
||||
target := string(targetBytes)
|
||||
assert.Equal(t, "vaults.d/default", target, "currentvault should contain relative path")
|
||||
assert.Equal(t, "default", target, "currentvault should contain vault name")
|
||||
|
||||
// Verify vault structure
|
||||
pubKeyFile := filepath.Join(defaultVaultDir, "pub.age")
|
||||
@ -463,7 +463,7 @@ func test03CreateVault(t *testing.T, tempDir string, runSecret func(...string) (
|
||||
targetBytes, err := os.ReadFile(currentVaultFile)
|
||||
require.NoError(t, err, "should be able to read currentvault file")
|
||||
target := string(targetBytes)
|
||||
assert.Equal(t, "vaults.d/work", target, "currentvault should contain relative path to work")
|
||||
assert.Equal(t, "work", target, "currentvault should contain vault name")
|
||||
|
||||
// Verify work vault has basic structure
|
||||
unlockersDir := filepath.Join(workVaultDir, "unlockers.d")
|
||||
@ -593,12 +593,11 @@ func test05AddSecret(t *testing.T, tempDir, testMnemonic string, runSecret func(
|
||||
currentLink := filepath.Join(secretDir, "current")
|
||||
verifyFileExists(t, currentLink)
|
||||
|
||||
// Verify current file contains the version path
|
||||
// Verify current file contains the version name
|
||||
targetBytes, err := os.ReadFile(currentLink)
|
||||
require.NoError(t, err, "should read current file")
|
||||
target := string(targetBytes)
|
||||
expectedTarget := filepath.Join("versions", versionName)
|
||||
assert.Equal(t, expectedTarget, target, "current file should point to version")
|
||||
assert.Equal(t, versionName, target, "current file should contain version name")
|
||||
|
||||
// Verify we can retrieve the secret
|
||||
getOutput, err := runSecretWithEnv(map[string]string{
|
||||
@ -685,8 +684,7 @@ func test07AddSecretVersion(t *testing.T, tempDir, testMnemonic string, runSecre
|
||||
targetBytes, err := os.ReadFile(currentLink)
|
||||
require.NoError(t, err, "should read current file")
|
||||
target := string(targetBytes)
|
||||
expectedTarget := filepath.Join("versions", newVersion)
|
||||
assert.Equal(t, expectedTarget, target, "current file should point to new version")
|
||||
assert.Equal(t, newVersion, target, "current file should contain version name")
|
||||
|
||||
// Verify we get the new value when retrieving the secret
|
||||
getOutput, err := runSecretWithEnv(map[string]string{
|
||||
@ -801,7 +799,7 @@ func test10PromoteVersion(t *testing.T, tempDir, testMnemonic string, runSecret
|
||||
targetBytes, err := os.ReadFile(currentLink)
|
||||
require.NoError(t, err, "should read current file")
|
||||
target := string(targetBytes)
|
||||
assert.Equal(t, filepath.Join("versions", version002), target, "current should initially point to .002")
|
||||
assert.Equal(t, version002, target, "current should initially point to .002")
|
||||
|
||||
// Promote the old version
|
||||
output, err := runSecretWithEnv(map[string]string{
|
||||
@ -816,8 +814,7 @@ func test10PromoteVersion(t *testing.T, tempDir, testMnemonic string, runSecret
|
||||
newTargetBytes, err := os.ReadFile(currentLink)
|
||||
require.NoError(t, err, "should read current file after promotion")
|
||||
newTarget := string(newTargetBytes)
|
||||
expectedTarget := filepath.Join("versions", version001)
|
||||
assert.Equal(t, expectedTarget, newTarget, "current file should now point to .001")
|
||||
assert.Equal(t, version001, newTarget, "current file should now point to .001")
|
||||
|
||||
// Verify we now get the old value when retrieving the secret
|
||||
getOutput, err := runSecretWithEnv(map[string]string{
|
||||
@ -1240,7 +1237,7 @@ func test14SwitchVault(t *testing.T, tempDir string, runSecret func(...string) (
|
||||
targetBytes, err := os.ReadFile(currentVaultFile)
|
||||
require.NoError(t, err, "should read currentvault file")
|
||||
target := string(targetBytes)
|
||||
assert.Equal(t, "vaults.d/default", target, "currentvault should point to default")
|
||||
assert.Equal(t, "default", target, "currentvault should contain vault name")
|
||||
|
||||
// Switch to work vault
|
||||
_, err = runSecret("vault", "select", "work")
|
||||
@ -1250,7 +1247,7 @@ func test14SwitchVault(t *testing.T, tempDir string, runSecret func(...string) (
|
||||
targetBytes, err = os.ReadFile(currentVaultFile)
|
||||
require.NoError(t, err, "should read currentvault file")
|
||||
target = string(targetBytes)
|
||||
assert.Equal(t, "vaults.d/work", target, "currentvault should point to work")
|
||||
assert.Equal(t, "work", target, "currentvault should contain vault name")
|
||||
|
||||
// Switch back to default
|
||||
_, err = runSecret("vault", "select", "default")
|
||||
@ -1989,11 +1986,11 @@ func test29SymlinkHandling(t *testing.T, tempDir, secretPath, testMnemonic strin
|
||||
currentVaultFile := filepath.Join(tempDir, "currentvault")
|
||||
verifyFileExists(t, currentVaultFile)
|
||||
|
||||
// Read the file
|
||||
// Read the file - should contain just the vault name
|
||||
targetBytes, err := os.ReadFile(currentVaultFile)
|
||||
require.NoError(t, err, "should read currentvault file")
|
||||
target := string(targetBytes)
|
||||
assert.Contains(t, target, "vaults.d", "should point to vaults.d directory")
|
||||
assert.NotContains(t, target, "/", "should be bare vault name without path")
|
||||
|
||||
// Test version current file
|
||||
defaultVaultDir := filepath.Join(tempDir, "vaults.d", "default")
|
||||
@ -2004,7 +2001,7 @@ func test29SymlinkHandling(t *testing.T, tempDir, secretPath, testMnemonic strin
|
||||
targetBytes, err = os.ReadFile(currentLink)
|
||||
require.NoError(t, err, "should read current version file")
|
||||
target = string(targetBytes)
|
||||
assert.Contains(t, target, "versions", "should point to versions directory")
|
||||
assert.NotContains(t, target, "/", "should be bare version name without path")
|
||||
|
||||
// Test that current file updates properly
|
||||
// Add new version
|
||||
@ -2024,7 +2021,7 @@ func test29SymlinkHandling(t *testing.T, tempDir, secretPath, testMnemonic strin
|
||||
require.NoError(t, err, "should read updated current file")
|
||||
newTarget := string(newTargetBytes)
|
||||
assert.NotEqual(t, target, newTarget, "current file should point to new version")
|
||||
assert.Contains(t, newTarget, "versions", "new current file should still point to versions directory")
|
||||
assert.NotContains(t, newTarget, "/", "new current file should be bare version name")
|
||||
}
|
||||
|
||||
func test30BackupRestore(t *testing.T, tempDir, secretPath, testMnemonic string, runSecretWithEnv func(map[string]string, ...string) (string, error)) {
|
||||
|
||||
@ -101,10 +101,9 @@ func (m *MockVault) AddSecret(name string, value *memguard.LockedBuffer, _ bool)
|
||||
return err
|
||||
}
|
||||
|
||||
// Create current symlink pointing to the version
|
||||
// Create current file pointing to the version (just the version name)
|
||||
currentLink := filepath.Join(secretDir, "current")
|
||||
// For MemMapFs, write a file with the target path
|
||||
if err := afero.WriteFile(m.fs, currentLink, []byte("versions/"+versionName), 0o600); err != nil {
|
||||
if err := afero.WriteFile(m.fs, currentLink, []byte(versionName), 0o600); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@ -431,6 +431,7 @@ func ListVersions(fs afero.Fs, secretDir string) ([]string, error) {
|
||||
}
|
||||
|
||||
// GetCurrentVersion returns the version that the "current" file points to
|
||||
// The file contains just the version name (e.g., "20231215.001")
|
||||
func GetCurrentVersion(fs afero.Fs, secretDir string) (string, error) {
|
||||
currentPath := filepath.Join(secretDir, "current")
|
||||
|
||||
@ -439,27 +440,21 @@ func GetCurrentVersion(fs afero.Fs, secretDir string) (string, error) {
|
||||
return "", fmt.Errorf("failed to read current version file: %w", err)
|
||||
}
|
||||
|
||||
target := strings.TrimSpace(string(fileData))
|
||||
version := strings.TrimSpace(string(fileData))
|
||||
|
||||
// Extract version from path (e.g., "versions/20231215.001" -> "20231215.001")
|
||||
parts := strings.Split(target, "/")
|
||||
if len(parts) >= 2 && parts[0] == "versions" {
|
||||
return parts[1], nil
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("invalid current version file format: %s", target)
|
||||
return version, nil
|
||||
}
|
||||
|
||||
// SetCurrentVersion updates the "current" file to point to a specific version
|
||||
// The file contains just the version name (e.g., "20231215.001")
|
||||
func SetCurrentVersion(fs afero.Fs, secretDir string, version string) error {
|
||||
currentPath := filepath.Join(secretDir, "current")
|
||||
targetPath := filepath.Join("versions", version)
|
||||
|
||||
// Remove existing file if it exists
|
||||
_ = fs.Remove(currentPath)
|
||||
|
||||
// Write the relative path to the file
|
||||
if err := afero.WriteFile(fs, currentPath, []byte(targetPath), FilePerms); err != nil {
|
||||
// Write just the version name to the file
|
||||
if err := afero.WriteFile(fs, currentPath, []byte(version), FilePerms); err != nil {
|
||||
return fmt.Errorf("failed to create current version file: %w", err)
|
||||
}
|
||||
|
||||
|
||||
@ -296,12 +296,12 @@ func TestGetCurrentVersion(t *testing.T) {
|
||||
fs := afero.NewMemMapFs()
|
||||
secretDir := "/test/secret"
|
||||
|
||||
// Simulate symlink with file content (works for both OsFs and MemMapFs)
|
||||
// The current file contains just the version name
|
||||
currentPath := filepath.Join(secretDir, "current")
|
||||
err := fs.MkdirAll(secretDir, 0o755)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = afero.WriteFile(fs, currentPath, []byte("versions/20231216.001"), 0o600)
|
||||
err = afero.WriteFile(fs, currentPath, []byte("20231216.001"), 0o600)
|
||||
require.NoError(t, err)
|
||||
|
||||
version, err := GetCurrentVersion(fs, secretDir)
|
||||
|
||||
@ -45,16 +45,16 @@ func TestVaultWithRealFilesystem(t *testing.T) {
|
||||
t.Fatalf("Failed to get vault directory: %v", err)
|
||||
}
|
||||
|
||||
// Verify the currentvault file exists and contains the right relative path
|
||||
// Verify the currentvault file exists and contains just the vault name
|
||||
currentVaultPath := filepath.Join(stateDir, "currentvault")
|
||||
currentVaultContents, err := os.ReadFile(currentVaultPath)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to read currentvault file: %v", err)
|
||||
}
|
||||
|
||||
expectedRelativePath := "vaults.d/test-vault"
|
||||
if string(currentVaultContents) != expectedRelativePath {
|
||||
t.Errorf("Expected currentvault to contain %q, got %q", expectedRelativePath, string(currentVaultContents))
|
||||
expectedVaultName := "test-vault"
|
||||
if string(currentVaultContents) != expectedVaultName {
|
||||
t.Errorf("Expected currentvault to contain %q, got %q", expectedVaultName, string(currentVaultContents))
|
||||
}
|
||||
|
||||
// Test that ResolveVaultSymlink correctly resolves the path
|
||||
|
||||
@ -33,7 +33,7 @@ func isValidVaultName(name string) bool {
|
||||
}
|
||||
|
||||
// ResolveVaultSymlink reads the currentvault file to get the path to the current vault
|
||||
// The file contains a relative path to the vault directory
|
||||
// The file contains just the vault name (e.g., "default")
|
||||
func ResolveVaultSymlink(fs afero.Fs, currentVaultPath string) (string, error) {
|
||||
secret.Debug("resolveVaultSymlink starting", "path", currentVaultPath)
|
||||
|
||||
@ -44,13 +44,13 @@ func ResolveVaultSymlink(fs afero.Fs, currentVaultPath string) (string, error) {
|
||||
return "", fmt.Errorf("failed to read currentvault file: %w", err)
|
||||
}
|
||||
|
||||
// The file contains a relative path like "vaults.d/default"
|
||||
relativePath := strings.TrimSpace(string(fileData))
|
||||
secret.Debug("Read relative path from file", "relative_path", relativePath)
|
||||
// The file contains just the vault name like "default"
|
||||
vaultName := strings.TrimSpace(string(fileData))
|
||||
secret.Debug("Read vault name from file", "vault_name", vaultName)
|
||||
|
||||
// Resolve to absolute path relative to the state directory
|
||||
// Resolve to absolute path: stateDir/vaults.d/vaultName
|
||||
stateDir := filepath.Dir(currentVaultPath)
|
||||
absolutePath := filepath.Join(stateDir, relativePath)
|
||||
absolutePath := filepath.Join(stateDir, "vaults.d", vaultName)
|
||||
|
||||
secret.Debug("Resolved to absolute path", "absolute_path", absolutePath)
|
||||
|
||||
@ -256,9 +256,8 @@ func SelectVault(fs afero.Fs, stateDir string, name string) error {
|
||||
return fmt.Errorf("vault %s does not exist", name)
|
||||
}
|
||||
|
||||
// Create or update the currentvault file with the relative path
|
||||
// Create or update the currentvault file with just the vault name
|
||||
currentVaultPath := filepath.Join(stateDir, "currentvault")
|
||||
relativePath := filepath.Join("vaults.d", name)
|
||||
|
||||
// Remove existing file if it exists
|
||||
if _, err := fs.Stat(currentVaultPath); err == nil {
|
||||
@ -266,9 +265,9 @@ func SelectVault(fs afero.Fs, stateDir string, name string) error {
|
||||
_ = fs.Remove(currentVaultPath)
|
||||
}
|
||||
|
||||
// Write the relative path to the file
|
||||
secret.Debug("Writing currentvault file", "relative_path", relativePath)
|
||||
if err := afero.WriteFile(fs, currentVaultPath, []byte(relativePath), secret.FilePerms); err != nil {
|
||||
// Write just the vault name to the file
|
||||
secret.Debug("Writing currentvault file", "vault_name", name)
|
||||
if err := afero.WriteFile(fs, currentVaultPath, []byte(name), secret.FilePerms); err != nil {
|
||||
return fmt.Errorf("failed to select vault: %w", err)
|
||||
}
|
||||
|
||||
|
||||
@ -99,23 +99,23 @@ func (v *Vault) GetCurrentUnlocker() (secret.Unlocker, error) {
|
||||
}
|
||||
|
||||
// resolveUnlockerDirectory reads the current-unlocker file to get the unlocker directory path
|
||||
// The file contains a relative path to the unlocker directory
|
||||
// The file contains just the unlocker name (e.g., "passphrase")
|
||||
func (v *Vault) resolveUnlockerDirectory(currentUnlockerPath string) (string, error) {
|
||||
secret.Debug("Reading current-unlocker file", "path", currentUnlockerPath)
|
||||
|
||||
unlockerDirBytes, err := afero.ReadFile(v.fs, currentUnlockerPath)
|
||||
unlockerNameBytes, err := afero.ReadFile(v.fs, currentUnlockerPath)
|
||||
if err != nil {
|
||||
secret.Debug("Failed to read current-unlocker file", "error", err, "path", currentUnlockerPath)
|
||||
|
||||
return "", fmt.Errorf("failed to read current unlocker: %w", err)
|
||||
}
|
||||
|
||||
relativePath := strings.TrimSpace(string(unlockerDirBytes))
|
||||
secret.Debug("Read relative path from file", "relative_path", relativePath)
|
||||
unlockerName := strings.TrimSpace(string(unlockerNameBytes))
|
||||
secret.Debug("Read unlocker name from file", "unlocker_name", unlockerName)
|
||||
|
||||
// Resolve to absolute path relative to the vault directory
|
||||
// Resolve to absolute path: vaultDir/unlockers.d/unlockerName
|
||||
vaultDir := filepath.Dir(currentUnlockerPath)
|
||||
absolutePath := filepath.Join(vaultDir, relativePath)
|
||||
absolutePath := filepath.Join(vaultDir, "unlockers.d", unlockerName)
|
||||
|
||||
secret.Debug("Resolved to absolute path", "absolute_path", absolutePath)
|
||||
|
||||
@ -277,7 +277,7 @@ func (v *Vault) SelectUnlocker(unlockerID string) error {
|
||||
return fmt.Errorf("unlocker with ID %s not found", unlockerID)
|
||||
}
|
||||
|
||||
// Create/update current-unlocker file with relative path
|
||||
// Create/update current-unlocker file with just the unlocker name
|
||||
currentUnlockerPath := filepath.Join(vaultDir, "current-unlocker")
|
||||
|
||||
// Remove existing file if it exists
|
||||
@ -289,15 +289,12 @@ func (v *Vault) SelectUnlocker(unlockerID string) error {
|
||||
}
|
||||
}
|
||||
|
||||
// Compute relative path from vault directory to unlocker directory
|
||||
relativePath, err := filepath.Rel(vaultDir, targetUnlockerDir)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to compute relative path: %w", err)
|
||||
}
|
||||
// Get just the unlocker name (basename of the directory)
|
||||
unlockerName := filepath.Base(targetUnlockerDir)
|
||||
|
||||
// Write the relative path to the file
|
||||
secret.Debug("Writing current-unlocker file", "relative_path", relativePath)
|
||||
if err := afero.WriteFile(v.fs, currentUnlockerPath, []byte(relativePath), secret.FilePerms); err != nil {
|
||||
// Write just the unlocker name to the file
|
||||
secret.Debug("Writing current-unlocker file", "unlocker_name", unlockerName)
|
||||
if err := afero.WriteFile(v.fs, currentUnlockerPath, []byte(unlockerName), secret.FilePerms); err != nil {
|
||||
return fmt.Errorf("failed to create current-unlocker file: %w", err)
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user