From 38b450cbcf26fd7c9a52f9584aef822e06150792 Mon Sep 17 00:00:00 2001 From: sneak Date: Wed, 9 Jul 2025 07:05:07 -0700 Subject: [PATCH] fix: resolve mnd and nestif linter errors - Added constants to replace magic numbers: - agePrivKeyPassphraseLength = 64 - versionNameParts = 2 - maxVersionsPerDay = 999 - Refactored crypto.go to reduce nesting complexity: - Inverted if condition to handle non-existent secret first - Extracted getSecretValue helper method --- internal/cli/crypto.go | 51 ++++++++++++++++------------- internal/secret/keychainunlocker.go | 6 +++- internal/secret/version.go | 9 +++-- 3 files changed, 40 insertions(+), 26 deletions(-) diff --git a/internal/cli/crypto.go b/internal/cli/crypto.go index 80a730e..4de16f9 100644 --- a/internal/cli/crypto.go +++ b/internal/cli/crypto.go @@ -74,29 +74,7 @@ func (cli *Instance) Encrypt(secretName, inputFile, outputFile string) error { return fmt.Errorf("failed to check if secret exists: %w", err) } - if exists { - // Secret exists, get the age secret key from it - var secretValue []byte - if os.Getenv(secret.EnvMnemonic) != "" { - secretValue, err = secretObj.GetValue(nil) - } else { - unlocker, unlockErr := vlt.GetCurrentUnlocker() - if unlockErr != nil { - return fmt.Errorf("failed to get current unlocker: %w", unlockErr) - } - secretValue, err = secretObj.GetValue(unlocker) - } - if err != nil { - return fmt.Errorf("failed to get secret value: %w", err) - } - - ageSecretKey = string(secretValue) - - // Validate that it's a valid age secret key - if !isValidAgeSecretKey(ageSecretKey) { - return fmt.Errorf("secret '%s' does not contain a valid age secret key", secretName) - } - } else { + if !exists { // Secret doesn't exist, generate new age key and store it identity, err := age.GenerateX25519Identity() if err != nil { @@ -110,6 +88,19 @@ func (cli *Instance) Encrypt(secretName, inputFile, outputFile string) error { if err != nil { return fmt.Errorf("failed to store age key: %w", err) } + } else { + // Secret exists, get the age secret key from it + secretValue, err := cli.getSecretValue(vlt, secretObj) + if err != nil { + return fmt.Errorf("failed to get secret value: %w", err) + } + + ageSecretKey = string(secretValue) + + // Validate that it's a valid age secret key + if !isValidAgeSecretKey(ageSecretKey) { + return fmt.Errorf("secret '%s' does not contain a valid age secret key", secretName) + } } // Parse the secret key @@ -247,3 +238,17 @@ func isValidAgeSecretKey(key string) bool { _, err := age.ParseX25519Identity(key) return err == nil } + +// getSecretValue retrieves the value of a secret using the appropriate unlocker +func (cli *Instance) getSecretValue(vlt *vault.Vault, secretObj *secret.Secret) ([]byte, error) { + if os.Getenv(secret.EnvMnemonic) != "" { + return secretObj.GetValue(nil) + } + + unlocker, err := vlt.GetCurrentUnlocker() + if err != nil { + return nil, fmt.Errorf("failed to get current unlocker: %w", err) + } + + return secretObj.GetValue(unlocker) +} diff --git a/internal/secret/keychainunlocker.go b/internal/secret/keychainunlocker.go index 5e71d43..0a34659 100644 --- a/internal/secret/keychainunlocker.go +++ b/internal/secret/keychainunlocker.go @@ -16,6 +16,10 @@ import ( "github.com/spf13/afero" ) +const ( + agePrivKeyPassphraseLength = 64 +) + // keychainItemNameRegex validates keychain item names // Allows alphanumeric characters, dots, hyphens, and underscores only var keychainItemNameRegex = regexp.MustCompile(`^[A-Za-z0-9._-]+$`) @@ -253,7 +257,7 @@ func CreateKeychainUnlocker(fs afero.Fs, stateDir string) (*KeychainUnlocker, er } // Step 2: Generate a random passphrase for encrypting the age private key - agePrivKeyPassphrase, err := generateRandomPassphrase(64) + agePrivKeyPassphrase, err := generateRandomPassphrase(agePrivKeyPassphraseLength) if err != nil { return nil, fmt.Errorf("failed to generate age private key passphrase: %w", err) } diff --git a/internal/secret/version.go b/internal/secret/version.go index 7d1ad60..2b35106 100644 --- a/internal/secret/version.go +++ b/internal/secret/version.go @@ -15,6 +15,11 @@ import ( "github.com/spf13/afero" ) +const ( + versionNameParts = 2 + maxVersionsPerDay = 999 +) + // VersionMetadata contains information about a secret version type VersionMetadata struct { ID string `json:"id"` // ULID @@ -87,7 +92,7 @@ func GenerateVersionName(fs afero.Fs, secretDir string) (string, error) { if entry.IsDir() && strings.HasPrefix(entry.Name(), prefix) { // Extract serial number parts := strings.Split(entry.Name(), ".") - if len(parts) == 2 { + if len(parts) == versionNameParts { var serial int if _, err := fmt.Sscanf(parts[1], "%03d", &serial); err == nil { if serial > maxSerial { @@ -100,7 +105,7 @@ func GenerateVersionName(fs afero.Fs, secretDir string) (string, error) { // Generate new version name newSerial := maxSerial + 1 - if newSerial > 999 { + if newSerial > maxVersionsPerDay { return "", fmt.Errorf("exceeded maximum versions per day (999)") }