Skip to content

Commit 9d27241

Browse files
committed
refactor(secrets): standardize empty literals
1 parent 3a3daef commit 9d27241

File tree

6 files changed

+81
-49
lines changed

6 files changed

+81
-49
lines changed

cmd/inventory/main.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,10 @@ func main() {
2424

2525
// Load database configuration from secrets
2626
dbConfig := secretHelper.LoadDatabaseConfig()
27-
dsn := secretHelper.BuildDSN(dbConfig)
27+
dsn, err := secretHelper.BuildDSN(dbConfig)
28+
if err != nil {
29+
log.Fatalf("inventory dsn: %v", err)
30+
}
2831

2932
// Load TLS configuration from secrets
3033
tlsConfig := secretHelper.LoadTLSConfig("INVENTORY")

cmd/migrate/main.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,10 @@ func main() {
2626

2727
// Load database configuration
2828
dbConfig := secretHelper.LoadDatabaseConfig()
29-
databaseURL := secretHelper.BuildDSN(dbConfig)
29+
databaseURL, err := secretHelper.BuildDSN(dbConfig)
30+
if err != nil {
31+
log.Fatalf("migrate dsn: %v", err)
32+
}
3033

3134
// Create migrator instance
3235
m, err := migrate.New(*migrationsDir, databaseURL)

pkg/secrets/azure.go

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@ import (
1111
"github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets"
1212
)
1313

14+
const (
15+
azureKeyVaultURLKey = "AZURE_KEYVAULT_URL"
16+
azureClientIDKey = "AZURE_CLIENT_ID"
17+
dashRune = '-'
18+
defaultSecretName = "secret"
19+
)
20+
1421
// AzureManager implements secret management using Azure Key Vault
1522
type AzureManager struct {
1623
client *azsecrets.Client
@@ -19,10 +26,10 @@ type AzureManager struct {
1926

2027
// NewAzureManager creates a new Azure Key Vault-based secret manager
2128
func NewAzureManager(cfg Config) (*AzureManager, error) {
22-
vaultURL := cfg.Extra["AZURE_KEYVAULT_URL"]
23-
if vaultURL == "" {
24-
if vaultURL = os.Getenv("AZURE_KEYVAULT_URL"); vaultURL == "" {
25-
return nil, fmt.Errorf("AZURE_KEYVAULT_URL is required")
29+
vaultURL := cfg.Extra[azureKeyVaultURLKey]
30+
if vaultURL == emptyString {
31+
if vaultURL = os.Getenv(azureKeyVaultURLKey); vaultURL == emptyString {
32+
return nil, fmt.Errorf("%s is required", azureKeyVaultURLKey)
2633
}
2734
}
2835

@@ -46,7 +53,7 @@ func NewAzureManager(cfg Config) (*AzureManager, error) {
4653
// createAzureCredential creates an appropriate Azure credential
4754
func createAzureCredential(cfg Config) (azcore.TokenCredential, error) {
4855
// Try managed identity first (recommended for Azure-hosted applications)
49-
if clientID := cfg.Extra["AZURE_CLIENT_ID"]; clientID != "" {
56+
if clientID := cfg.Extra[azureClientIDKey]; clientID != emptyString {
5057
cred, err := azidentity.NewManagedIdentityCredential(&azidentity.ManagedIdentityCredentialOptions{
5158
ID: azidentity.ClientID(clientID),
5259
})
@@ -69,13 +76,13 @@ func (m *AzureManager) GetSecret(ctx context.Context, key string) (string, error
6976
secretName := m.normalizeSecretName(key)
7077

7178
// Get the latest version of the secret
72-
resp, err := m.client.GetSecret(ctx, secretName, "", nil)
79+
resp, err := m.client.GetSecret(ctx, secretName, emptyString, nil)
7380
if err != nil {
74-
return "", fmt.Errorf("failed to get secret %s: %w", secretName, err)
81+
return emptyString, fmt.Errorf("failed to get secret %s: %w", secretName, err)
7582
}
7683

7784
if resp.Value == nil {
78-
return "", fmt.Errorf("secret %s has no value", secretName)
85+
return emptyString, fmt.Errorf("secret %s has no value", secretName)
7986
}
8087

8188
return *resp.Value, nil
@@ -117,20 +124,20 @@ func (m *AzureManager) SetSecret(ctx context.Context, key, value string) error {
117124
func (m *AzureManager) normalizeSecretName(name string) string {
118125
// Replace invalid characters with dashes
119126
normalized := strings.Map(func(r rune) rune {
120-
if (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') || (r >= '0' && r <= '9') || r == '-' {
127+
if (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') || (r >= '0' && r <= '9') || r == dashRune {
121128
return r
122129
}
123-
return '-'
130+
return dashRune
124131
}, name)
125132

126133
// Remove leading/trailing dashes and ensure it starts with a letter or number
127-
normalized = strings.Trim(normalized, "-")
134+
normalized = strings.Trim(normalized, string(dashRune))
128135
if len(normalized) == 0 {
129-
normalized = "secret"
136+
normalized = defaultSecretName
130137
}
131138

132139
// Ensure it starts with alphanumeric
133-
if normalized[0] == '-' {
140+
if normalized[0] == dashRune {
134141
normalized = "s" + normalized
135142
}
136143

pkg/secrets/helper.go

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package secrets
22

33
import (
44
"context"
5+
"fmt"
56
"log"
67
"os"
78
"strings"
@@ -55,13 +56,16 @@ func (h *Helper) GetOrDefault(key, defaultValue string) string {
5556
return value
5657
}
5758

58-
// GetRequired gets a required secret, logging a fatal error if not found
59-
func (h *Helper) GetRequired(key string) string {
59+
// GetRequired gets a required secret, returning an error if not found
60+
func (h *Helper) GetRequired(key string) (string, error) {
6061
value, err := h.manager.GetSecret(h.ctx, key)
61-
if err != nil || value == "" {
62-
log.Fatalf("Required secret not found: %s", key)
62+
if err != nil {
63+
return "", err
6364
}
64-
return value
65+
if value == "" {
66+
return "", fmt.Errorf("required secret not found: %s", key)
67+
}
68+
return value, nil
6569
}
6670

6771
// GetMultipleOrDefaults gets multiple secrets with fallback defaults
@@ -125,18 +129,19 @@ func (h *Helper) LoadAPIKeys() map[string]string {
125129
}
126130

127131
// BuildDSN builds a database connection string from secret values
128-
func (h *Helper) BuildDSN(dbConfig map[string]string) string {
129-
if dbConfig["POSTGRES_PASSWORD"] == "" {
130-
log.Fatal("POSTGRES_PASSWORD is required")
132+
func (h *Helper) BuildDSN(dbConfig map[string]string) (string, error) {
133+
password, ok := dbConfig["POSTGRES_PASSWORD"]
134+
if !ok || password == "" {
135+
return "", fmt.Errorf("POSTGRES_PASSWORD is required")
131136
}
132137

133138
return BuildPostgresDSN(
134139
dbConfig["POSTGRES_USER"],
135-
dbConfig["POSTGRES_PASSWORD"],
140+
password,
136141
dbConfig["POSTGRES_HOST"],
137142
dbConfig["POSTGRES_PORT"],
138143
dbConfig["POSTGRES_DB"],
139-
)
144+
), nil
140145
}
141146

142147
// BuildPostgresDSN builds a PostgreSQL connection string

pkg/secrets/secrets.go

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import (
77
"strings"
88
)
99

10+
const emptyString = ""
11+
1012
// Manager defines the interface for secret management
1113
type Manager interface {
1214
GetSecret(ctx context.Context, key string) (string, error)
@@ -31,7 +33,7 @@ func NewManager(cfg Config) (Manager, error) {
3133
return NewVaultManager(cfg)
3234
case "azure":
3335
return NewAzureManager(cfg)
34-
case "env", "":
36+
case "env", emptyString:
3537
return NewEnvManager(cfg), nil
3638
default:
3739
return nil, fmt.Errorf("unsupported secret manager type: %s", cfg.Type)
@@ -41,7 +43,7 @@ func NewManager(cfg Config) (Manager, error) {
4143
// GetSecret is a convenience function to get a single secret
4244
func GetSecret(ctx context.Context, manager Manager, key, fallback string) string {
4345
value, err := manager.GetSecret(ctx, key)
44-
if err != nil || value == "" {
46+
if err != nil || value == emptyString {
4547
return fallback
4648
}
4749
return value
@@ -58,14 +60,14 @@ func NewEnvManager(cfg Config) *EnvManager {
5860
}
5961

6062
// GetSecret retrieves a secret from environment variables
61-
func (m *EnvManager) GetSecret(ctx context.Context, key string) (string, error) {
63+
func (m *EnvManager) GetSecret(_ context.Context, key string) (string, error) {
6264
envKey := key
63-
if m.prefix != "" {
65+
if m.prefix != emptyString {
6466
envKey = m.prefix + key
6567
}
6668

6769
value := os.Getenv(envKey)
68-
if value == "" {
70+
if value == emptyString {
6971
return "", fmt.Errorf("secret not found: %s", key)
7072
}
7173

@@ -88,9 +90,9 @@ func (m *EnvManager) GetSecrets(ctx context.Context, keys []string) (map[string]
8890
}
8991

9092
// SetSecret sets a secret in environment variables (not persistent)
91-
func (m *EnvManager) SetSecret(ctx context.Context, key, value string) error {
93+
func (m *EnvManager) SetSecret(_ context.Context, key, value string) error {
9294
envKey := key
93-
if m.prefix != "" {
95+
if m.prefix != emptyString {
9496
envKey = m.prefix + key
9597
}
9698

pkg/secrets/vault.go

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,18 @@ import (
1111
)
1212

1313
// VaultManager implements secret management using HashiCorp Vault
14+
const (
15+
slash = "/"
16+
valueKey = "value"
17+
dataKey = "data"
18+
vaultAddrKey = "VAULT_ADDR"
19+
vaultTokenFileKey = "VAULT_TOKEN_FILE"
20+
vaultTokenKey = "VAULT_TOKEN"
21+
vaultSecretPathKey = "VAULT_SECRET_PATH"
22+
vaultK8sRoleKey = "VAULT_K8S_ROLE"
23+
serviceAccountPath = "/var/run/secrets/kubernetes.io/serviceaccount/token"
24+
)
25+
1426
type VaultManager struct {
1527
client *api.Client
1628
prefix string
@@ -21,12 +33,12 @@ func NewVaultManager(cfg Config) (*VaultManager, error) {
2133
vaultConfig := api.DefaultConfig()
2234

2335
// Set Vault address
24-
if addr := cfg.Extra["VAULT_ADDR"]; addr != "" {
36+
if addr := cfg.Extra[vaultAddrKey]; addr != emptyString {
2537
vaultConfig.Address = addr
26-
} else if addr := os.Getenv("VAULT_ADDR"); addr != "" {
38+
} else if addr := os.Getenv(vaultAddrKey); addr != emptyString {
2739
vaultConfig.Address = addr
2840
} else {
29-
return nil, fmt.Errorf("VAULT_ADDR is required")
41+
return nil, fmt.Errorf("%s is required", vaultAddrKey)
3042
}
3143

3244
client, err := api.NewClient(vaultConfig)
@@ -41,14 +53,14 @@ func NewVaultManager(cfg Config) (*VaultManager, error) {
4153

4254
return &VaultManager{
4355
client: client,
44-
prefix: cfg.Extra["VAULT_SECRET_PATH"],
56+
prefix: cfg.Extra[vaultSecretPathKey],
4557
}, nil
4658
}
4759

4860
// authenticateVault handles Vault authentication using various methods
4961
func authenticateVault(client *api.Client, cfg Config) error {
5062
// Try token file first
51-
if tokenFile := cfg.Extra["VAULT_TOKEN_FILE"]; tokenFile != "" {
63+
if tokenFile := cfg.Extra[vaultTokenFileKey]; tokenFile != emptyString {
5264
token, err := readSecretFile(tokenFile)
5365
if err != nil {
5466
return fmt.Errorf("failed to read token file %s: %w", tokenFile, err)
@@ -58,21 +70,21 @@ func authenticateVault(client *api.Client, cfg Config) error {
5870
}
5971

6072
// Try direct token
61-
if token := cfg.Extra["VAULT_TOKEN"]; token != "" {
73+
if token := cfg.Extra[vaultTokenKey]; token != emptyString {
6274
client.SetToken(token)
6375
return nil
6476
}
6577

6678
// Try environment token
67-
if token := os.Getenv("VAULT_TOKEN"); token != "" {
79+
if token := os.Getenv(vaultTokenKey); token != emptyString {
6880
client.SetToken(token)
6981
return nil
7082
}
7183

7284
// Try Kubernetes authentication
73-
if serviceAccountTokenFile := "/var/run/secrets/kubernetes.io/serviceaccount/token"; fileExists(serviceAccountTokenFile) {
74-
if role := cfg.Extra["VAULT_K8S_ROLE"]; role != "" {
75-
return authenticateKubernetes(client, serviceAccountTokenFile, role)
85+
if fileExists(serviceAccountPath) {
86+
if role := cfg.Extra[vaultK8sRoleKey]; role != emptyString {
87+
return authenticateKubernetes(client, serviceAccountPath, role)
7688
}
7789
}
7890

@@ -105,7 +117,7 @@ func authenticateKubernetes(client *api.Client, tokenFile, role string) error {
105117
}
106118

107119
// GetSecret retrieves a secret from Vault
108-
func (m *VaultManager) GetSecret(ctx context.Context, key string) (string, error) {
120+
func (m *VaultManager) GetSecret(_ context.Context, key string) (string, error) {
109121
secretPath := m.buildSecretPath(key)
110122

111123
secret, err := m.client.Logical().Read(secretPath)
@@ -119,12 +131,12 @@ func (m *VaultManager) GetSecret(ctx context.Context, key string) (string, error
119131

120132
// Handle KV v2 (data wrapper)
121133
data := secret.Data
122-
if dataMap, ok := data["data"].(map[string]interface{}); ok {
134+
if dataMap, ok := data[dataKey].(map[string]interface{}); ok {
123135
data = dataMap
124136
}
125137

126138
// Get the value
127-
value, ok := data["value"]
139+
value, ok := data[valueKey]
128140
if !ok {
129141
// Try the key name itself
130142
value, ok = data[filepath.Base(key)]
@@ -161,13 +173,13 @@ func (m *VaultManager) SetSecret(ctx context.Context, key, value string) error {
161173
secretPath := m.buildSecretPath(key)
162174

163175
data := map[string]interface{}{
164-
"value": value,
176+
valueKey: value,
165177
}
166178

167179
// Handle KV v2 (data wrapper)
168180
if m.isKVv2() {
169181
data = map[string]interface{}{
170-
"data": data,
182+
dataKey: data,
171183
}
172184
}
173185

@@ -181,11 +193,11 @@ func (m *VaultManager) SetSecret(ctx context.Context, key, value string) error {
181193

182194
// buildSecretPath constructs the full secret path with prefix
183195
func (m *VaultManager) buildSecretPath(key string) string {
184-
if m.prefix == "" {
196+
if m.prefix == emptyString {
185197
return key
186198
}
187199

188-
return strings.TrimSuffix(m.prefix, "/") + "/" + strings.TrimPrefix(key, "/")
200+
return strings.TrimSuffix(m.prefix, slash) + slash + strings.TrimPrefix(key, slash)
189201
}
190202

191203
// isKVv2 checks if we're using KV secrets engine v2

0 commit comments

Comments
 (0)