Standardize file permissions using constants and fix parameter ordering inconsistencies
This commit is contained in:
parent
8dc2e9d748
commit
a4d7225036
@ -36,7 +36,7 @@ func (cli *CLIInstance) Init(cmd *cobra.Command) error {
|
||||
stateDir := cli.GetStateDir()
|
||||
secret.DebugWith("Creating state directory", slog.String("path", stateDir))
|
||||
|
||||
if err := cli.fs.MkdirAll(stateDir, 0700); err != nil {
|
||||
if err := cli.fs.MkdirAll(stateDir, secret.DirPerms); err != nil {
|
||||
secret.Debug("Failed to create state directory", "error", err)
|
||||
return fmt.Errorf("failed to create state directory: %w", err)
|
||||
}
|
||||
@ -101,7 +101,7 @@ func (cli *CLIInstance) Init(cmd *cobra.Command) error {
|
||||
vaultDir := filepath.Join(stateDir, "vaults.d", "default")
|
||||
ltPubKey := ltIdentity.Recipient().String()
|
||||
secret.DebugWith("Storing long-term public key", slog.String("pubkey", ltPubKey), slog.String("vault_dir", vaultDir))
|
||||
if err := afero.WriteFile(cli.fs, filepath.Join(vaultDir, "pub.age"), []byte(ltPubKey), 0600); err != nil {
|
||||
if err := afero.WriteFile(cli.fs, filepath.Join(vaultDir, "pub.age"), []byte(ltPubKey), secret.FilePerms); err != nil {
|
||||
secret.Debug("Failed to write long-term public key", "error", err)
|
||||
return fmt.Errorf("failed to write long-term public key: %w", err)
|
||||
}
|
||||
@ -154,7 +154,7 @@ func (cli *CLIInstance) Init(cmd *cobra.Command) error {
|
||||
}
|
||||
|
||||
// Write encrypted long-term private key
|
||||
if err := afero.WriteFile(cli.fs, filepath.Join(unlockKeyDir, "longterm.age"), encryptedLtPrivKey, 0600); err != nil {
|
||||
if err := afero.WriteFile(cli.fs, filepath.Join(unlockKeyDir, "longterm.age"), encryptedLtPrivKey, secret.FilePerms); err != nil {
|
||||
return fmt.Errorf("failed to write encrypted long-term private key: %w", err)
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
package secret
|
||||
|
||||
import "os"
|
||||
|
||||
const (
|
||||
// AppID is the unique identifier for this application
|
||||
AppID = "berlin.sneak.pkg.secret"
|
||||
@ -10,3 +12,12 @@ const (
|
||||
EnvUnlockPassphrase = "SB_UNLOCK_PASSPHRASE"
|
||||
EnvGPGKeyID = "SB_GPG_KEY_ID"
|
||||
)
|
||||
|
||||
// File system permission constants
|
||||
const (
|
||||
// DirPerms is the permission used for directories (read-write-execute for owner only)
|
||||
DirPerms os.FileMode = 0700
|
||||
|
||||
// FilePerms is the permission used for sensitive files (read-write for owner only)
|
||||
FilePerms os.FileMode = 0600
|
||||
)
|
||||
|
@ -240,7 +240,7 @@ func CreateKeychainUnlockKey(fs afero.Fs, stateDir string) (*KeychainUnlockKey,
|
||||
}
|
||||
|
||||
unlockKeyDir := filepath.Join(vaultDir, "unlock.d", keychainItemName)
|
||||
if err := fs.MkdirAll(unlockKeyDir, 0700); err != nil {
|
||||
if err := fs.MkdirAll(unlockKeyDir, DirPerms); err != nil {
|
||||
return nil, fmt.Errorf("failed to create unlock key directory: %w", err)
|
||||
}
|
||||
|
||||
@ -259,7 +259,7 @@ func CreateKeychainUnlockKey(fs afero.Fs, stateDir string) (*KeychainUnlockKey,
|
||||
// Step 3: Store age public key as plaintext
|
||||
agePublicKeyString := ageIdentity.Recipient().String()
|
||||
agePubKeyPath := filepath.Join(unlockKeyDir, "pub.age")
|
||||
if err := afero.WriteFile(fs, agePubKeyPath, []byte(agePublicKeyString), 0600); err != nil {
|
||||
if err := afero.WriteFile(fs, agePubKeyPath, []byte(agePublicKeyString), FilePerms); err != nil {
|
||||
return nil, fmt.Errorf("failed to write age public key: %w", err)
|
||||
}
|
||||
|
||||
@ -271,7 +271,7 @@ func CreateKeychainUnlockKey(fs afero.Fs, stateDir string) (*KeychainUnlockKey,
|
||||
}
|
||||
|
||||
agePrivKeyPath := filepath.Join(unlockKeyDir, "priv.age")
|
||||
if err := afero.WriteFile(fs, agePrivKeyPath, encryptedAgePrivKey, 0600); err != nil {
|
||||
if err := afero.WriteFile(fs, agePrivKeyPath, encryptedAgePrivKey, FilePerms); err != nil {
|
||||
return nil, fmt.Errorf("failed to write encrypted age private key: %w", err)
|
||||
}
|
||||
|
||||
@ -342,7 +342,7 @@ func CreateKeychainUnlockKey(fs afero.Fs, stateDir string) (*KeychainUnlockKey,
|
||||
|
||||
// Write encrypted long-term private key
|
||||
ltPrivKeyPath := filepath.Join(unlockKeyDir, "longterm.age")
|
||||
if err := afero.WriteFile(fs, ltPrivKeyPath, encryptedLtPrivKeyToAge, 0600); err != nil {
|
||||
if err := afero.WriteFile(fs, ltPrivKeyPath, encryptedLtPrivKeyToAge, FilePerms); err != nil {
|
||||
return nil, fmt.Errorf("failed to write encrypted long-term private key: %w", err)
|
||||
}
|
||||
|
||||
@ -383,7 +383,7 @@ func CreateKeychainUnlockKey(fs afero.Fs, stateDir string) (*KeychainUnlockKey,
|
||||
return nil, fmt.Errorf("failed to marshal unlock key metadata: %w", err)
|
||||
}
|
||||
|
||||
if err := afero.WriteFile(fs, filepath.Join(unlockKeyDir, "unlock-metadata.json"), metadataBytes, 0600); err != nil {
|
||||
if err := afero.WriteFile(fs, filepath.Join(unlockKeyDir, "unlock-metadata.json"), metadataBytes, FilePerms); err != nil {
|
||||
return nil, fmt.Errorf("failed to write unlock key metadata: %w", err)
|
||||
}
|
||||
|
||||
|
@ -188,7 +188,7 @@ func CreatePGPUnlockKey(fs afero.Fs, stateDir string, gpgKeyID string) (*PGPUnlo
|
||||
}
|
||||
|
||||
unlockKeyDir := filepath.Join(vaultDir, "unlock.d", unlockKeyName)
|
||||
if err := fs.MkdirAll(unlockKeyDir, 0700); err != nil {
|
||||
if err := fs.MkdirAll(unlockKeyDir, DirPerms); err != nil {
|
||||
return nil, fmt.Errorf("failed to create unlock key directory: %w", err)
|
||||
}
|
||||
|
||||
@ -201,7 +201,7 @@ func CreatePGPUnlockKey(fs afero.Fs, stateDir string, gpgKeyID string) (*PGPUnlo
|
||||
// Step 2: Store age public key as plaintext
|
||||
agePublicKeyString := ageIdentity.Recipient().String()
|
||||
agePubKeyPath := filepath.Join(unlockKeyDir, "pub.age")
|
||||
if err := afero.WriteFile(fs, agePubKeyPath, []byte(agePublicKeyString), 0600); err != nil {
|
||||
if err := afero.WriteFile(fs, agePubKeyPath, []byte(agePublicKeyString), FilePerms); err != nil {
|
||||
return nil, fmt.Errorf("failed to write age public key: %w", err)
|
||||
}
|
||||
|
||||
@ -265,7 +265,7 @@ func CreatePGPUnlockKey(fs afero.Fs, stateDir string, gpgKeyID string) (*PGPUnlo
|
||||
|
||||
// Write encrypted long-term private key
|
||||
ltPrivKeyPath := filepath.Join(unlockKeyDir, "longterm.age")
|
||||
if err := afero.WriteFile(fs, ltPrivKeyPath, encryptedLtPrivKeyToAge, 0600); err != nil {
|
||||
if err := afero.WriteFile(fs, ltPrivKeyPath, encryptedLtPrivKeyToAge, FilePerms); err != nil {
|
||||
return nil, fmt.Errorf("failed to write encrypted long-term private key: %w", err)
|
||||
}
|
||||
|
||||
@ -277,7 +277,7 @@ func CreatePGPUnlockKey(fs afero.Fs, stateDir string, gpgKeyID string) (*PGPUnlo
|
||||
}
|
||||
|
||||
agePrivKeyPath := filepath.Join(unlockKeyDir, "priv.age.gpg")
|
||||
if err := afero.WriteFile(fs, agePrivKeyPath, encryptedAgePrivKey, 0600); err != nil {
|
||||
if err := afero.WriteFile(fs, agePrivKeyPath, encryptedAgePrivKey, FilePerms); err != nil {
|
||||
return nil, fmt.Errorf("failed to write encrypted age private key: %w", err)
|
||||
}
|
||||
|
||||
@ -302,7 +302,7 @@ func CreatePGPUnlockKey(fs afero.Fs, stateDir string, gpgKeyID string) (*PGPUnlo
|
||||
return nil, fmt.Errorf("failed to marshal unlock key metadata: %w", err)
|
||||
}
|
||||
|
||||
if err := afero.WriteFile(fs, filepath.Join(unlockKeyDir, "unlock-metadata.json"), metadataBytes, 0600); err != nil {
|
||||
if err := afero.WriteFile(fs, filepath.Join(unlockKeyDir, "unlock-metadata.json"), metadataBytes, FilePerms); err != nil {
|
||||
return nil, fmt.Errorf("failed to write unlock key metadata: %w", err)
|
||||
}
|
||||
|
||||
|
@ -25,10 +25,10 @@ func (m *MockVault) GetDirectory() (string, error) {
|
||||
func (m *MockVault) AddSecret(name string, value []byte, force bool) error {
|
||||
// Simplified implementation for testing
|
||||
secretDir := filepath.Join(m.directory, "secrets.d", name)
|
||||
if err := m.fs.MkdirAll(secretDir, 0700); err != nil {
|
||||
if err := m.fs.MkdirAll(secretDir, DirPerms); err != nil {
|
||||
return err
|
||||
}
|
||||
return afero.WriteFile(m.fs, filepath.Join(secretDir, "value.age"), value, 0600)
|
||||
return afero.WriteFile(m.fs, filepath.Join(secretDir, "value.age"), value, FilePerms)
|
||||
}
|
||||
|
||||
func (m *MockVault) GetName() string {
|
||||
@ -70,7 +70,7 @@ func TestPerSecretKeyFunctionality(t *testing.T) {
|
||||
vaultDir := filepath.Join(baseDir, "vaults.d", "test-vault")
|
||||
|
||||
// Create vault directory structure
|
||||
err := fs.MkdirAll(filepath.Join(vaultDir, "secrets.d"), 0700)
|
||||
err := fs.MkdirAll(filepath.Join(vaultDir, "secrets.d"), DirPerms)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create vault directory: %v", err)
|
||||
}
|
||||
@ -95,7 +95,7 @@ func TestPerSecretKeyFunctionality(t *testing.T) {
|
||||
|
||||
// Set current vault
|
||||
currentVaultPath := filepath.Join(baseDir, "currentvault")
|
||||
err = afero.WriteFile(fs, currentVaultPath, []byte(vaultDir), 0600)
|
||||
err = afero.WriteFile(fs, currentVaultPath, []byte(vaultDir), FilePerms)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to set current vault: %v", err)
|
||||
}
|
||||
|
@ -34,108 +34,142 @@ func resolveVaultSymlink(fs afero.Fs, symlinkPath string) (string, error) {
|
||||
|
||||
// First try to handle the path as a real symlink (works on Unix systems)
|
||||
if _, ok := fs.(*afero.OsFs); ok {
|
||||
secret.Debug("Trying real filesystem symlink resolution")
|
||||
secret.Debug("Using real filesystem symlink resolution")
|
||||
|
||||
// Check if it's a real symlink first (will work on Unix)
|
||||
linkTarget, err := os.Readlink(symlinkPath)
|
||||
// Check if the symlink exists
|
||||
secret.Debug("Checking symlink target", "symlink_path", symlinkPath)
|
||||
target, err := os.Readlink(symlinkPath)
|
||||
if err == nil {
|
||||
// Successfully read as symlink (Unix path)
|
||||
secret.Debug("Successfully read as real symlink", "target", linkTarget)
|
||||
secret.Debug("Symlink points to", "target", target)
|
||||
|
||||
// Convert relative paths to absolute if needed
|
||||
if !filepath.IsAbs(linkTarget) {
|
||||
linkTarget = filepath.Join(filepath.Dir(symlinkPath), linkTarget)
|
||||
// On real filesystem, we need to handle relative symlinks
|
||||
// by resolving them relative to the symlink's directory
|
||||
if !filepath.IsAbs(target) {
|
||||
// Get the current directory before changing
|
||||
originalDir, err := os.Getwd()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to get current directory: %w", err)
|
||||
}
|
||||
secret.Debug("Got current directory", "original_dir", originalDir)
|
||||
|
||||
// Change to the symlink's directory
|
||||
symlinkDir := filepath.Dir(symlinkPath)
|
||||
secret.Debug("Changing to symlink directory", "symlink_path", symlinkDir)
|
||||
secret.Debug("About to call os.Chdir - this might hang if symlink is broken")
|
||||
if err := os.Chdir(symlinkDir); err != nil {
|
||||
return "", fmt.Errorf("failed to change to symlink directory: %w", err)
|
||||
}
|
||||
secret.Debug("Changed to symlink directory successfully - os.Chdir completed")
|
||||
|
||||
// Get the absolute path of the target
|
||||
secret.Debug("Getting absolute path of current directory")
|
||||
absolutePath, err := os.Getwd()
|
||||
if err != nil {
|
||||
// Try to restore original directory before returning error
|
||||
_ = os.Chdir(originalDir)
|
||||
return "", fmt.Errorf("failed to get absolute path: %w", err)
|
||||
}
|
||||
secret.Debug("Got absolute path", "absolute_path", absolutePath)
|
||||
|
||||
// Restore the original directory
|
||||
secret.Debug("Restoring original directory", "original_dir", originalDir)
|
||||
if err := os.Chdir(originalDir); err != nil {
|
||||
return "", fmt.Errorf("failed to restore original directory: %w", err)
|
||||
}
|
||||
secret.Debug("Restored original directory successfully")
|
||||
|
||||
// Use the absolute path of the target
|
||||
target = absolutePath
|
||||
}
|
||||
|
||||
secret.Debug("Resolved symlink path", "path", linkTarget)
|
||||
return linkTarget, nil
|
||||
secret.Debug("resolveVaultSymlink completed successfully", "result", target)
|
||||
return target, nil
|
||||
}
|
||||
|
||||
secret.Debug("Not a real symlink or on Windows, trying as regular file", "error", err)
|
||||
}
|
||||
|
||||
// For Windows or in-memory filesystems, or when symlink reading fails:
|
||||
// Read the path from a regular file (our fallback approach)
|
||||
secret.Debug("Reading symlink target from file")
|
||||
content, err := afero.ReadFile(fs, symlinkPath)
|
||||
// Fallback: treat it as a regular file containing the target path
|
||||
secret.Debug("Fallback: trying to read regular file with target path")
|
||||
|
||||
fileData, err := afero.ReadFile(fs, symlinkPath)
|
||||
if err != nil {
|
||||
secret.Debug("Failed to read from file", "error", err)
|
||||
return "", fmt.Errorf("failed to read vault path: %w", err)
|
||||
secret.Debug("Failed to read target path file", "error", err)
|
||||
return "", fmt.Errorf("failed to read vault symlink: %w", err)
|
||||
}
|
||||
|
||||
targetPath := string(content)
|
||||
secret.Debug("Read target path from file", "target_path", targetPath)
|
||||
return targetPath, nil
|
||||
target := string(fileData)
|
||||
secret.Debug("Read target path from file", "target", target)
|
||||
|
||||
secret.Debug("resolveVaultSymlink completed via fallback", "result", target)
|
||||
return target, nil
|
||||
}
|
||||
|
||||
// GetCurrentVault gets the currently selected vault
|
||||
// GetCurrentVault gets the current vault from the file system
|
||||
func GetCurrentVault(fs afero.Fs, stateDir string) (*Vault, error) {
|
||||
secret.Debug("Getting current vault", "state_dir", stateDir)
|
||||
|
||||
// Check if current vault symlink exists
|
||||
// Check if the current vault symlink exists
|
||||
currentVaultPath := filepath.Join(stateDir, "currentvault")
|
||||
secret.Debug("Checking current vault symlink", "path", currentVaultPath)
|
||||
|
||||
secret.Debug("Checking current vault symlink", "path", currentVaultPath)
|
||||
_, err := fs.Stat(currentVaultPath)
|
||||
if err != nil {
|
||||
secret.Debug("Failed to stat current vault symlink", "error", err, "path", currentVaultPath)
|
||||
return nil, fmt.Errorf("failed to read current vault symlink: %w", err)
|
||||
}
|
||||
|
||||
secret.Debug("Current vault symlink exists")
|
||||
|
||||
// Resolve symlink to get target path
|
||||
// Resolve the symlink to get the actual vault directory
|
||||
secret.Debug("Resolving vault symlink")
|
||||
targetPath, err := resolveVaultSymlink(fs, currentVaultPath)
|
||||
if err != nil {
|
||||
secret.Debug("Failed to resolve vault symlink", "error", err)
|
||||
return nil, fmt.Errorf("failed to resolve vault symlink: %w", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
secret.Debug("Resolved vault symlink", "target_path", targetPath)
|
||||
|
||||
// Extract vault name from target path
|
||||
// Extract the vault name from the path
|
||||
// The path will be something like "/path/to/vaults.d/default"
|
||||
vaultName := filepath.Base(targetPath)
|
||||
secret.Debug("Extracted vault name", "vault_name", vaultName)
|
||||
|
||||
secret.Debug("Current vault resolved", "vault_name", vaultName, "target_path", targetPath)
|
||||
|
||||
// Create and return Vault instance
|
||||
secret.Debug("Creating NewVault instance")
|
||||
vault := NewVault(fs, vaultName, stateDir)
|
||||
secret.Debug("Created NewVault instance successfully")
|
||||
|
||||
return vault, nil
|
||||
// Create and return the vault
|
||||
return NewVault(fs, stateDir, vaultName), nil
|
||||
}
|
||||
|
||||
// ListVaults returns a list of available vault names
|
||||
// ListVaults lists all vaults in the state directory
|
||||
func ListVaults(fs afero.Fs, stateDir string) ([]string, error) {
|
||||
vaultsDir := filepath.Join(stateDir, "vaults.d")
|
||||
|
||||
// Check if vaults directory exists
|
||||
exists, err := afero.DirExists(fs, vaultsDir)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to check vaults directory: %w", err)
|
||||
return nil, fmt.Errorf("failed to check if vaults directory exists: %w", err)
|
||||
}
|
||||
if !exists {
|
||||
return []string{}, nil
|
||||
}
|
||||
|
||||
// Read directory contents
|
||||
files, err := afero.ReadDir(fs, vaultsDir)
|
||||
// Read the vaults directory
|
||||
entries, err := afero.ReadDir(fs, vaultsDir)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read vaults directory: %w", err)
|
||||
}
|
||||
|
||||
// Extract vault names
|
||||
var vaults []string
|
||||
for _, file := range files {
|
||||
if file.IsDir() {
|
||||
vaults = append(vaults, file.Name())
|
||||
for _, entry := range entries {
|
||||
if entry.IsDir() {
|
||||
vaults = append(vaults, entry.Name())
|
||||
}
|
||||
}
|
||||
|
||||
return vaults, nil
|
||||
}
|
||||
|
||||
// CreateVault creates a new vault with the given name
|
||||
// CreateVault creates a new vault
|
||||
func CreateVault(fs afero.Fs, stateDir string, name string) (*Vault, error) {
|
||||
secret.Debug("Creating new vault", "name", name, "state_dir", stateDir)
|
||||
|
||||
@ -150,39 +184,32 @@ func CreateVault(fs afero.Fs, stateDir string, name string) (*Vault, error) {
|
||||
vaultDir := filepath.Join(stateDir, "vaults.d", name)
|
||||
secret.Debug("Creating vault directory structure", "vault_dir", vaultDir)
|
||||
|
||||
// Check if vault already exists
|
||||
exists, err := afero.DirExists(fs, vaultDir)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to check if vault exists: %w", err)
|
||||
}
|
||||
if exists {
|
||||
return nil, fmt.Errorf("vault %s already exists", name)
|
||||
}
|
||||
|
||||
// Create vault directory
|
||||
if err := fs.MkdirAll(vaultDir, 0700); err != nil {
|
||||
// Create main vault directory
|
||||
if err := fs.MkdirAll(vaultDir, secret.DirPerms); err != nil {
|
||||
return nil, fmt.Errorf("failed to create vault directory: %w", err)
|
||||
}
|
||||
|
||||
// Create subdirectories
|
||||
// Create secrets directory
|
||||
secretsDir := filepath.Join(vaultDir, "secrets.d")
|
||||
if err := fs.MkdirAll(secretsDir, 0700); err != nil {
|
||||
if err := fs.MkdirAll(secretsDir, secret.DirPerms); err != nil {
|
||||
return nil, fmt.Errorf("failed to create secrets directory: %w", err)
|
||||
}
|
||||
|
||||
// Create unlock keys directory
|
||||
unlockKeysDir := filepath.Join(vaultDir, "unlock.d")
|
||||
if err := fs.MkdirAll(unlockKeysDir, 0700); err != nil {
|
||||
if err := fs.MkdirAll(unlockKeysDir, secret.DirPerms); err != nil {
|
||||
return nil, fmt.Errorf("failed to create unlock keys directory: %w", err)
|
||||
}
|
||||
|
||||
// Select the new vault as current
|
||||
// Select the newly created vault as current
|
||||
secret.Debug("Selecting newly created vault as current", "name", name)
|
||||
if err := SelectVault(fs, stateDir, name); err != nil {
|
||||
return nil, fmt.Errorf("failed to select new vault: %w", err)
|
||||
return nil, fmt.Errorf("failed to select vault: %w", err)
|
||||
}
|
||||
|
||||
// Create and return the vault
|
||||
secret.Debug("Successfully created vault", "name", name)
|
||||
return NewVault(fs, name, stateDir), nil
|
||||
return NewVault(fs, stateDir, name), nil
|
||||
}
|
||||
|
||||
// SelectVault selects the given vault as the current vault
|
||||
@ -206,35 +233,33 @@ func SelectVault(fs afero.Fs, stateDir string, name string) error {
|
||||
return fmt.Errorf("vault %s does not exist", name)
|
||||
}
|
||||
|
||||
// Create/update current vault symlink
|
||||
// Create or update the current vault symlink/file
|
||||
currentVaultPath := filepath.Join(stateDir, "currentvault")
|
||||
targetPath := filepath.Join(stateDir, "vaults.d", name)
|
||||
|
||||
// Remove existing symlink if it exists
|
||||
if exists, _ := afero.Exists(fs, currentVaultPath); exists {
|
||||
// First try to remove existing symlink if it exists
|
||||
if _, err := fs.Stat(currentVaultPath); err == nil {
|
||||
secret.Debug("Removing existing current vault symlink", "path", currentVaultPath)
|
||||
if err := fs.Remove(currentVaultPath); err != nil {
|
||||
secret.Debug("Failed to remove existing symlink", "error", err, "path", currentVaultPath)
|
||||
// On some systems, removing a symlink may fail
|
||||
// Just ignore and try to create/update it anyway
|
||||
}
|
||||
}
|
||||
|
||||
// Create new symlink pointing to the vault
|
||||
targetPath := vaultDir
|
||||
secret.Debug("Creating vault symlink", "target", targetPath, "link", currentVaultPath)
|
||||
|
||||
// For real filesystems, try to create a real symlink first
|
||||
// Try to create a real symlink first (works on Unix systems)
|
||||
if _, ok := fs.(*afero.OsFs); ok {
|
||||
if err := os.Symlink(targetPath, currentVaultPath); err != nil {
|
||||
// If symlink creation fails, fall back to writing target path to file
|
||||
secret.Debug("Failed to create real symlink, falling back to file", "error", err)
|
||||
if err := afero.WriteFile(fs, currentVaultPath, []byte(targetPath), 0600); err != nil {
|
||||
return fmt.Errorf("failed to create vault symlink: %w", err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// For in-memory filesystems, write target path to file
|
||||
if err := afero.WriteFile(fs, currentVaultPath, []byte(targetPath), 0600); err != nil {
|
||||
return fmt.Errorf("failed to create vault symlink: %w", err)
|
||||
secret.Debug("Creating vault symlink", "target", targetPath, "link", currentVaultPath)
|
||||
if err := os.Symlink(targetPath, currentVaultPath); err == nil {
|
||||
secret.Debug("Successfully selected vault", "vault_name", name)
|
||||
return nil
|
||||
}
|
||||
// If symlink creation fails, fall back to regular file
|
||||
}
|
||||
|
||||
// Fallback: create a regular file with the target path
|
||||
secret.Debug("Fallback: creating regular file with target path", "target", targetPath)
|
||||
if err := afero.WriteFile(fs, currentVaultPath, []byte(targetPath), secret.FilePerms); err != nil {
|
||||
return fmt.Errorf("failed to select vault: %w", err)
|
||||
}
|
||||
|
||||
secret.Debug("Successfully selected vault", "vault_name", name)
|
||||
|
@ -120,7 +120,7 @@ func (v *Vault) AddSecret(name string, value []byte, force bool) error {
|
||||
|
||||
// Create secret directory
|
||||
secret.Debug("Creating secret directory", "secret_dir", secretDir)
|
||||
if err := v.fs.MkdirAll(secretDir, 0700); err != nil {
|
||||
if err := v.fs.MkdirAll(secretDir, secret.DirPerms); err != nil {
|
||||
secret.Debug("Failed to create secret directory", "error", err, "secret_dir", secretDir)
|
||||
return fmt.Errorf("failed to create secret directory: %w", err)
|
||||
}
|
||||
@ -145,7 +145,7 @@ func (v *Vault) AddSecret(name string, value []byte, force bool) error {
|
||||
// Step 2: Store the secret's public key
|
||||
pubKeyPath := filepath.Join(secretDir, "pub.age")
|
||||
secret.Debug("Writing secret public key", "path", pubKeyPath)
|
||||
if err := afero.WriteFile(v.fs, pubKeyPath, []byte(secretPublicKey), 0600); err != nil {
|
||||
if err := afero.WriteFile(v.fs, pubKeyPath, []byte(secretPublicKey), secret.FilePerms); err != nil {
|
||||
secret.Debug("Failed to write secret public key", "error", err, "path", pubKeyPath)
|
||||
return fmt.Errorf("failed to write secret public key: %w", err)
|
||||
}
|
||||
@ -167,7 +167,7 @@ func (v *Vault) AddSecret(name string, value []byte, force bool) error {
|
||||
// Step 4: Store the encrypted secret value as value.age
|
||||
valuePath := filepath.Join(secretDir, "value.age")
|
||||
secret.Debug("Writing encrypted secret value", "path", valuePath)
|
||||
if err := afero.WriteFile(v.fs, valuePath, encryptedValue, 0600); err != nil {
|
||||
if err := afero.WriteFile(v.fs, valuePath, encryptedValue, secret.FilePerms); err != nil {
|
||||
secret.Debug("Failed to write encrypted secret value", "error", err, "path", valuePath)
|
||||
return fmt.Errorf("failed to write encrypted secret value: %w", err)
|
||||
}
|
||||
@ -209,7 +209,7 @@ func (v *Vault) AddSecret(name string, value []byte, force bool) error {
|
||||
// Step 7: Store the encrypted secret private key as priv.age
|
||||
privKeyPath := filepath.Join(secretDir, "priv.age")
|
||||
secret.Debug("Writing encrypted secret private key", "path", privKeyPath)
|
||||
if err := afero.WriteFile(v.fs, privKeyPath, encryptedPrivKey, 0600); err != nil {
|
||||
if err := afero.WriteFile(v.fs, privKeyPath, encryptedPrivKey, secret.FilePerms); err != nil {
|
||||
secret.Debug("Failed to write encrypted secret private key", "error", err, "path", privKeyPath)
|
||||
return fmt.Errorf("failed to write encrypted secret private key: %w", err)
|
||||
}
|
||||
@ -240,7 +240,7 @@ func (v *Vault) AddSecret(name string, value []byte, force bool) error {
|
||||
|
||||
metadataPath := filepath.Join(secretDir, "secret-metadata.json")
|
||||
secret.Debug("Writing secret metadata", "path", metadataPath)
|
||||
if err := afero.WriteFile(v.fs, metadataPath, metadataBytes, 0600); err != nil {
|
||||
if err := afero.WriteFile(v.fs, metadataPath, metadataBytes, secret.FilePerms); err != nil {
|
||||
secret.Debug("Failed to write secret metadata", "error", err, "path", metadataPath)
|
||||
return fmt.Errorf("failed to write secret metadata: %w", err)
|
||||
}
|
||||
|
@ -288,7 +288,7 @@ func (v *Vault) SelectUnlockKey(keyID string) error {
|
||||
}
|
||||
|
||||
// Create new symlink
|
||||
return afero.WriteFile(v.fs, currentUnlockKeyPath, []byte(targetKeyDir), 0600)
|
||||
return afero.WriteFile(v.fs, currentUnlockKeyPath, []byte(targetKeyDir), secret.FilePerms)
|
||||
}
|
||||
|
||||
// CreatePassphraseKey creates a new passphrase-protected unlock key
|
||||
@ -301,7 +301,7 @@ func (v *Vault) CreatePassphraseKey(passphrase string) (*secret.PassphraseUnlock
|
||||
// Create unlock key directory with timestamp
|
||||
timestamp := time.Now().Format("2006-01-02.15.04")
|
||||
unlockKeyDir := filepath.Join(vaultDir, "unlock.d", "passphrase")
|
||||
if err := v.fs.MkdirAll(unlockKeyDir, 0700); err != nil {
|
||||
if err := v.fs.MkdirAll(unlockKeyDir, secret.DirPerms); err != nil {
|
||||
return nil, fmt.Errorf("failed to create unlock key directory: %w", err)
|
||||
}
|
||||
|
||||
@ -313,7 +313,7 @@ func (v *Vault) CreatePassphraseKey(passphrase string) (*secret.PassphraseUnlock
|
||||
|
||||
// Write public key
|
||||
pubKeyPath := filepath.Join(unlockKeyDir, "pub.age")
|
||||
if err := afero.WriteFile(v.fs, pubKeyPath, []byte(unlockIdentity.Recipient().String()), 0600); err != nil {
|
||||
if err := afero.WriteFile(v.fs, pubKeyPath, []byte(unlockIdentity.Recipient().String()), secret.FilePerms); err != nil {
|
||||
return nil, fmt.Errorf("failed to write unlock key public key: %w", err)
|
||||
}
|
||||
|
||||
@ -326,7 +326,7 @@ func (v *Vault) CreatePassphraseKey(passphrase string) (*secret.PassphraseUnlock
|
||||
|
||||
// Write encrypted private key
|
||||
privKeyPath := filepath.Join(unlockKeyDir, "priv.age")
|
||||
if err := afero.WriteFile(v.fs, privKeyPath, encryptedPrivKey, 0600); err != nil {
|
||||
if err := afero.WriteFile(v.fs, privKeyPath, encryptedPrivKey, secret.FilePerms); err != nil {
|
||||
return nil, fmt.Errorf("failed to write encrypted unlock key private key: %w", err)
|
||||
}
|
||||
|
||||
@ -346,8 +346,8 @@ func (v *Vault) CreatePassphraseKey(passphrase string) (*secret.PassphraseUnlock
|
||||
}
|
||||
|
||||
metadataPath := filepath.Join(unlockKeyDir, "unlock-metadata.json")
|
||||
if err := afero.WriteFile(v.fs, metadataPath, metadataBytes, 0600); err != nil {
|
||||
return nil, fmt.Errorf("failed to write metadata: %w", err)
|
||||
if err := afero.WriteFile(v.fs, metadataPath, metadataBytes, secret.FilePerms); err != nil {
|
||||
return nil, fmt.Errorf("failed to write unlock key metadata: %w", err)
|
||||
}
|
||||
|
||||
// Encrypt long-term private key to this unlock key if vault is unlocked
|
||||
@ -359,7 +359,7 @@ func (v *Vault) CreatePassphraseKey(passphrase string) (*secret.PassphraseUnlock
|
||||
}
|
||||
|
||||
ltPrivKeyPath := filepath.Join(unlockKeyDir, "longterm.age")
|
||||
if err := afero.WriteFile(v.fs, ltPrivKeyPath, encryptedLtPrivKey, 0600); err != nil {
|
||||
if err := afero.WriteFile(v.fs, ltPrivKeyPath, encryptedLtPrivKey, secret.FilePerms); err != nil {
|
||||
return nil, fmt.Errorf("failed to write encrypted long-term private key: %w", err)
|
||||
}
|
||||
}
|
||||
|
@ -128,7 +128,7 @@ func TestVaultOperations(t *testing.T) {
|
||||
|
||||
// Write the correct public key to the pub.age file
|
||||
pubKeyPath := filepath.Join(vaultDir, "pub.age")
|
||||
err = afero.WriteFile(fs, pubKeyPath, []byte(ltPublicKey), 0600)
|
||||
err = afero.WriteFile(fs, pubKeyPath, []byte(ltPublicKey), secret.FilePerms)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to write long-term public key: %v", err)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user