mirror of
https://github.com/pocket-id/pocket-id.git
synced 2025-12-23 17:25:22 +03:00
fix: make environment variables case insensitive where necessary (#954)
fix #935
This commit is contained in:
@@ -32,17 +32,17 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type EnvConfigSchema struct {
|
type EnvConfigSchema struct {
|
||||||
AppEnv string `env:"APP_ENV"`
|
AppEnv string `env:"APP_ENV" options:"toLower"`
|
||||||
LogLevel string `env:"LOG_LEVEL"`
|
LogLevel string `env:"LOG_LEVEL" options:"toLower"`
|
||||||
AppURL string `env:"APP_URL"`
|
AppURL string `env:"APP_URL" options:"toLower"`
|
||||||
DbProvider DbProvider `env:"DB_PROVIDER"`
|
DbProvider DbProvider `env:"DB_PROVIDER" options:"toLower"`
|
||||||
DbConnectionString string `env:"DB_CONNECTION_STRING" options:"file"`
|
DbConnectionString string `env:"DB_CONNECTION_STRING" options:"file"`
|
||||||
UploadPath string `env:"UPLOAD_PATH"`
|
UploadPath string `env:"UPLOAD_PATH"`
|
||||||
KeysPath string `env:"KEYS_PATH"`
|
KeysPath string `env:"KEYS_PATH"`
|
||||||
KeysStorage string `env:"KEYS_STORAGE"`
|
KeysStorage string `env:"KEYS_STORAGE"`
|
||||||
EncryptionKey []byte `env:"ENCRYPTION_KEY" options:"file"`
|
EncryptionKey []byte `env:"ENCRYPTION_KEY" options:"file"`
|
||||||
Port string `env:"PORT"`
|
Port string `env:"PORT"`
|
||||||
Host string `env:"HOST"`
|
Host string `env:"HOST" options:"toLower"`
|
||||||
UnixSocket string `env:"UNIX_SOCKET"`
|
UnixSocket string `env:"UNIX_SOCKET"`
|
||||||
UnixSocketMode string `env:"UNIX_SOCKET_MODE"`
|
UnixSocketMode string `env:"UNIX_SOCKET_MODE"`
|
||||||
MaxMindLicenseKey string `env:"MAXMIND_LICENSE_KEY" options:"file"`
|
MaxMindLicenseKey string `env:"MAXMIND_LICENSE_KEY" options:"file"`
|
||||||
@@ -112,31 +112,40 @@ func parseEnvConfig() error {
|
|||||||
return fmt.Errorf("error parsing env config: %w", err)
|
return fmt.Errorf("error parsing env config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = resolveFileBasedEnvVariables(&EnvConfig)
|
err = prepareEnvConfig(&EnvConfig)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error preparing env config: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = validateEnvConfig(&EnvConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate the environment variables
|
return nil
|
||||||
EnvConfig.LogLevel = strings.ToLower(EnvConfig.LogLevel)
|
|
||||||
if _, err := sloggin.ParseLevel(EnvConfig.LogLevel); err != nil {
|
}
|
||||||
|
|
||||||
|
// validateEnvConfig checks the EnvConfig for required fields and valid values
|
||||||
|
func validateEnvConfig(config *EnvConfigSchema) error {
|
||||||
|
if _, err := sloggin.ParseLevel(config.LogLevel); err != nil {
|
||||||
return errors.New("invalid LOG_LEVEL value. Must be 'debug', 'info', 'warn' or 'error'")
|
return errors.New("invalid LOG_LEVEL value. Must be 'debug', 'info', 'warn' or 'error'")
|
||||||
}
|
}
|
||||||
|
|
||||||
switch EnvConfig.DbProvider {
|
switch config.DbProvider {
|
||||||
case DbProviderSqlite:
|
case DbProviderSqlite:
|
||||||
if EnvConfig.DbConnectionString == "" {
|
if config.DbConnectionString == "" {
|
||||||
EnvConfig.DbConnectionString = defaultSqliteConnString
|
config.DbConnectionString = defaultSqliteConnString
|
||||||
}
|
}
|
||||||
case DbProviderPostgres:
|
case DbProviderPostgres:
|
||||||
if EnvConfig.DbConnectionString == "" {
|
if config.DbConnectionString == "" {
|
||||||
return errors.New("missing required env var 'DB_CONNECTION_STRING' for Postgres database")
|
return errors.New("missing required env var 'DB_CONNECTION_STRING' for Postgres database")
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return errors.New("invalid DB_PROVIDER value. Must be 'sqlite' or 'postgres'")
|
return errors.New("invalid DB_PROVIDER value. Must be 'sqlite' or 'postgres'")
|
||||||
}
|
}
|
||||||
|
|
||||||
parsedAppUrl, err := url.Parse(EnvConfig.AppURL)
|
parsedAppUrl, err := url.Parse(config.AppURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("APP_URL is not a valid URL")
|
return errors.New("APP_URL is not a valid URL")
|
||||||
}
|
}
|
||||||
@@ -145,10 +154,10 @@ func parseEnvConfig() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Derive INTERNAL_APP_URL from APP_URL if not set; validate only when provided
|
// Derive INTERNAL_APP_URL from APP_URL if not set; validate only when provided
|
||||||
if EnvConfig.InternalAppURL == "" {
|
if config.InternalAppURL == "" {
|
||||||
EnvConfig.InternalAppURL = EnvConfig.AppURL
|
config.InternalAppURL = config.AppURL
|
||||||
} else {
|
} else {
|
||||||
parsedInternalAppUrl, err := url.Parse(EnvConfig.InternalAppURL)
|
parsedInternalAppUrl, err := url.Parse(config.InternalAppURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("INTERNAL_APP_URL is not a valid URL")
|
return errors.New("INTERNAL_APP_URL is not a valid URL")
|
||||||
}
|
}
|
||||||
@@ -157,25 +166,26 @@ func parseEnvConfig() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch EnvConfig.KeysStorage {
|
switch config.KeysStorage {
|
||||||
// KeysStorage defaults to "file" if empty
|
// KeysStorage defaults to "file" if empty
|
||||||
case "":
|
case "":
|
||||||
EnvConfig.KeysStorage = "file"
|
config.KeysStorage = "file"
|
||||||
case "database":
|
case "database":
|
||||||
if EnvConfig.EncryptionKey == nil {
|
if config.EncryptionKey == nil {
|
||||||
return errors.New("ENCRYPTION_KEY must be non-empty when KEYS_STORAGE is database")
|
return errors.New("ENCRYPTION_KEY must be non-empty when KEYS_STORAGE is database")
|
||||||
}
|
}
|
||||||
case "file":
|
case "file":
|
||||||
// All good, these are valid values
|
// All good, these are valid values
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("invalid value for KEYS_STORAGE: %s", EnvConfig.KeysStorage)
|
return fmt.Errorf("invalid value for KEYS_STORAGE: %s", config.KeysStorage)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// resolveFileBasedEnvVariables uses reflection to automatically resolve file-based secrets
|
// prepareEnvConfig processes special options for EnvConfig fields
|
||||||
func resolveFileBasedEnvVariables(config *EnvConfigSchema) error {
|
func prepareEnvConfig(config *EnvConfigSchema) error {
|
||||||
val := reflect.ValueOf(config).Elem()
|
val := reflect.ValueOf(config).Elem()
|
||||||
typ := val.Type()
|
typ := val.Type()
|
||||||
|
|
||||||
@@ -183,48 +193,65 @@ func resolveFileBasedEnvVariables(config *EnvConfigSchema) error {
|
|||||||
field := val.Field(i)
|
field := val.Field(i)
|
||||||
fieldType := typ.Field(i)
|
fieldType := typ.Field(i)
|
||||||
|
|
||||||
// Only process string and []byte fields
|
|
||||||
isString := field.Kind() == reflect.String
|
|
||||||
isByteSlice := field.Kind() == reflect.Slice && field.Type().Elem().Kind() == reflect.Uint8
|
|
||||||
if !isString && !isByteSlice {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only process fields with the "options" tag set to "file"
|
|
||||||
optionsTag := fieldType.Tag.Get("options")
|
optionsTag := fieldType.Tag.Get("options")
|
||||||
if optionsTag != "file" {
|
options := strings.Split(optionsTag, ",")
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only process fields with the "env" tag
|
for _, option := range options {
|
||||||
envTag := fieldType.Tag.Get("env")
|
switch option {
|
||||||
if envTag == "" {
|
case "toLower":
|
||||||
continue
|
if field.Kind() == reflect.String {
|
||||||
}
|
field.SetString(strings.ToLower(field.String()))
|
||||||
|
}
|
||||||
envVarName := envTag
|
case "file":
|
||||||
if commaIndex := len(envTag); commaIndex > 0 {
|
err := resolveFileBasedEnvVariable(field, fieldType)
|
||||||
envVarName = envTag[:commaIndex]
|
if err != nil {
|
||||||
}
|
return err
|
||||||
|
}
|
||||||
// If the file environment variable is not set, skip
|
}
|
||||||
envVarFileName := envVarName + "_FILE"
|
|
||||||
envVarFileValue := os.Getenv(envVarFileName)
|
|
||||||
if envVarFileValue == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
fileContent, err := os.ReadFile(envVarFileValue)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to read file for env var %s: %w", envVarFileName, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if isString {
|
|
||||||
field.SetString(strings.TrimSpace(string(fileContent)))
|
|
||||||
} else {
|
|
||||||
field.SetBytes(fileContent)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// resolveFileBasedEnvVariable checks if an environment variable with the suffix "_FILE" is set,
|
||||||
|
// reads the content of the file specified by that variable, and sets the corresponding field's value.
|
||||||
|
func resolveFileBasedEnvVariable(field reflect.Value, fieldType reflect.StructField) error {
|
||||||
|
// Only process string and []byte fields
|
||||||
|
isString := field.Kind() == reflect.String
|
||||||
|
isByteSlice := field.Kind() == reflect.Slice && field.Type().Elem().Kind() == reflect.Uint8
|
||||||
|
if !isString && !isByteSlice {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only process fields with the "env" tag
|
||||||
|
envTag := fieldType.Tag.Get("env")
|
||||||
|
if envTag == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
envVarName := envTag
|
||||||
|
if commaIndex := len(envTag); commaIndex > 0 {
|
||||||
|
envVarName = envTag[:commaIndex]
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the file environment variable is not set, skip
|
||||||
|
envVarFileName := envVarName + "_FILE"
|
||||||
|
envVarFileValue := os.Getenv(envVarFileName)
|
||||||
|
if envVarFileValue == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
fileContent, err := os.ReadFile(envVarFileValue)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to read file for env var %s: %w", envVarFileName, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if isString {
|
||||||
|
field.SetString(strings.TrimSpace(string(fileContent)))
|
||||||
|
} else {
|
||||||
|
field.SetBytes(fileContent)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -17,18 +17,19 @@ func TestParseEnvConfig(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("should parse valid SQLite config correctly", func(t *testing.T) {
|
t.Run("should parse valid SQLite config correctly", func(t *testing.T) {
|
||||||
EnvConfig = defaultConfig()
|
EnvConfig = defaultConfig()
|
||||||
t.Setenv("DB_PROVIDER", "sqlite")
|
t.Setenv("DB_PROVIDER", "SQLITE") // should be lowercased automatically
|
||||||
t.Setenv("DB_CONNECTION_STRING", "file:test.db")
|
t.Setenv("DB_CONNECTION_STRING", "file:test.db")
|
||||||
t.Setenv("APP_URL", "http://localhost:3000")
|
t.Setenv("APP_URL", "HTTP://LOCALHOST:3000")
|
||||||
|
|
||||||
err := parseEnvConfig()
|
err := parseEnvConfig()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Equal(t, DbProviderSqlite, EnvConfig.DbProvider)
|
assert.Equal(t, DbProviderSqlite, EnvConfig.DbProvider)
|
||||||
|
assert.Equal(t, "http://localhost:3000", EnvConfig.AppURL)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("should parse valid Postgres config correctly", func(t *testing.T) {
|
t.Run("should parse valid Postgres config correctly", func(t *testing.T) {
|
||||||
EnvConfig = defaultConfig()
|
EnvConfig = defaultConfig()
|
||||||
t.Setenv("DB_PROVIDER", "postgres")
|
t.Setenv("DB_PROVIDER", "POSTGRES")
|
||||||
t.Setenv("DB_CONNECTION_STRING", "postgres://user:pass@localhost/db")
|
t.Setenv("DB_CONNECTION_STRING", "postgres://user:pass@localhost/db")
|
||||||
t.Setenv("APP_URL", "https://example.com")
|
t.Setenv("APP_URL", "https://example.com")
|
||||||
|
|
||||||
@@ -51,7 +52,6 @@ func TestParseEnvConfig(t *testing.T) {
|
|||||||
t.Run("should set default SQLite connection string when DB_CONNECTION_STRING is empty", func(t *testing.T) {
|
t.Run("should set default SQLite connection string when DB_CONNECTION_STRING is empty", func(t *testing.T) {
|
||||||
EnvConfig = defaultConfig()
|
EnvConfig = defaultConfig()
|
||||||
t.Setenv("DB_PROVIDER", "sqlite")
|
t.Setenv("DB_PROVIDER", "sqlite")
|
||||||
t.Setenv("DB_CONNECTION_STRING", "") // Explicitly empty
|
|
||||||
t.Setenv("APP_URL", "http://localhost:3000")
|
t.Setenv("APP_URL", "http://localhost:3000")
|
||||||
|
|
||||||
err := parseEnvConfig()
|
err := parseEnvConfig()
|
||||||
@@ -192,25 +192,25 @@ func TestParseEnvConfig(t *testing.T) {
|
|||||||
t.Setenv("DB_PROVIDER", "postgres")
|
t.Setenv("DB_PROVIDER", "postgres")
|
||||||
t.Setenv("DB_CONNECTION_STRING", "postgres://test")
|
t.Setenv("DB_CONNECTION_STRING", "postgres://test")
|
||||||
t.Setenv("APP_URL", "https://prod.example.com")
|
t.Setenv("APP_URL", "https://prod.example.com")
|
||||||
t.Setenv("APP_ENV", "staging")
|
t.Setenv("APP_ENV", "STAGING")
|
||||||
t.Setenv("UPLOAD_PATH", "/custom/uploads")
|
t.Setenv("UPLOAD_PATH", "/custom/uploads")
|
||||||
t.Setenv("KEYS_PATH", "/custom/keys")
|
t.Setenv("KEYS_PATH", "/custom/keys")
|
||||||
t.Setenv("PORT", "8080")
|
t.Setenv("PORT", "8080")
|
||||||
t.Setenv("HOST", "127.0.0.1")
|
t.Setenv("HOST", "LOCALHOST")
|
||||||
t.Setenv("UNIX_SOCKET", "/tmp/app.sock")
|
t.Setenv("UNIX_SOCKET", "/tmp/app.sock")
|
||||||
t.Setenv("MAXMIND_LICENSE_KEY", "test-license")
|
t.Setenv("MAXMIND_LICENSE_KEY", "test-license")
|
||||||
t.Setenv("GEOLITE_DB_PATH", "/custom/geolite.mmdb")
|
t.Setenv("GEOLITE_DB_PATH", "/custom/geolite.mmdb")
|
||||||
|
|
||||||
err := parseEnvConfig()
|
err := parseEnvConfig()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Equal(t, "staging", EnvConfig.AppEnv)
|
assert.Equal(t, "staging", EnvConfig.AppEnv) // lowercased
|
||||||
assert.Equal(t, "/custom/uploads", EnvConfig.UploadPath)
|
assert.Equal(t, "/custom/uploads", EnvConfig.UploadPath)
|
||||||
assert.Equal(t, "8080", EnvConfig.Port)
|
assert.Equal(t, "8080", EnvConfig.Port)
|
||||||
assert.Equal(t, "127.0.0.1", EnvConfig.Host)
|
assert.Equal(t, "localhost", EnvConfig.Host) // lowercased
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestResolveFileBasedEnvVariables(t *testing.T) {
|
func TestPrepareEnvConfig_FileBasedAndToLower(t *testing.T) {
|
||||||
// Create temporary directory for test files
|
// Create temporary directory for test files
|
||||||
tempDir := t.TempDir()
|
tempDir := t.TempDir()
|
||||||
|
|
||||||
@@ -225,103 +225,34 @@ func TestResolveFileBasedEnvVariables(t *testing.T) {
|
|||||||
err = os.WriteFile(dbConnFile, []byte(dbConnContent), 0600)
|
err = os.WriteFile(dbConnFile, []byte(dbConnContent), 0600)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Create a binary file for testing binary data handling
|
|
||||||
binaryKeyFile := tempDir + "/binary_key.bin"
|
binaryKeyFile := tempDir + "/binary_key.bin"
|
||||||
binaryKeyContent := []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10}
|
binaryKeyContent := []byte{0x01, 0x02, 0x03, 0x04}
|
||||||
err = os.WriteFile(binaryKeyFile, binaryKeyContent, 0600)
|
err = os.WriteFile(binaryKeyFile, binaryKeyContent, 0600)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
t.Run("should read file content for fields with options:file tag", func(t *testing.T) {
|
t.Run("should process toLower and file options", func(t *testing.T) {
|
||||||
config := defaultConfig()
|
config := defaultConfig()
|
||||||
|
config.AppEnv = "STAGING"
|
||||||
|
config.Host = "LOCALHOST"
|
||||||
|
|
||||||
// Set environment variables pointing to files
|
|
||||||
t.Setenv("ENCRYPTION_KEY_FILE", encryptionKeyFile)
|
t.Setenv("ENCRYPTION_KEY_FILE", encryptionKeyFile)
|
||||||
t.Setenv("DB_CONNECTION_STRING_FILE", dbConnFile)
|
t.Setenv("DB_CONNECTION_STRING_FILE", dbConnFile)
|
||||||
|
|
||||||
err := resolveFileBasedEnvVariables(&config)
|
err := prepareEnvConfig(&config)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Verify file contents were read correctly
|
assert.Equal(t, "staging", config.AppEnv)
|
||||||
|
assert.Equal(t, "localhost", config.Host)
|
||||||
assert.Equal(t, []byte(encryptionKeyContent), config.EncryptionKey)
|
assert.Equal(t, []byte(encryptionKeyContent), config.EncryptionKey)
|
||||||
assert.Equal(t, dbConnContent, config.DbConnectionString)
|
assert.Equal(t, dbConnContent, config.DbConnectionString)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("should skip fields without options:file tag", func(t *testing.T) {
|
|
||||||
config := defaultConfig()
|
|
||||||
originalAppURL := config.AppURL
|
|
||||||
|
|
||||||
// Set a file for a field that doesn't have options:file tag
|
|
||||||
t.Setenv("APP_URL_FILE", "/tmp/nonexistent.txt")
|
|
||||||
|
|
||||||
err := resolveFileBasedEnvVariables(&config)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
// AppURL should remain unchanged
|
|
||||||
assert.Equal(t, originalAppURL, config.AppURL)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("should skip non-string fields", func(t *testing.T) {
|
|
||||||
// This test verifies that non-string fields are skipped
|
|
||||||
// We test this indirectly by ensuring the function doesn't error
|
|
||||||
// when processing the actual EnvConfigSchema which has bool fields
|
|
||||||
config := defaultConfig()
|
|
||||||
|
|
||||||
err := resolveFileBasedEnvVariables(&config)
|
|
||||||
require.NoError(t, err)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("should skip when _FILE environment variable is not set", func(t *testing.T) {
|
|
||||||
config := defaultConfig()
|
|
||||||
originalEncryptionKey := config.EncryptionKey
|
|
||||||
|
|
||||||
// Don't set ENCRYPTION_KEY_FILE environment variable
|
|
||||||
|
|
||||||
err := resolveFileBasedEnvVariables(&config)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
// EncryptionKey should remain unchanged
|
|
||||||
assert.Equal(t, originalEncryptionKey, config.EncryptionKey)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("should handle multiple file-based variables simultaneously", func(t *testing.T) {
|
|
||||||
config := defaultConfig()
|
|
||||||
|
|
||||||
// Set multiple file environment variables
|
|
||||||
t.Setenv("ENCRYPTION_KEY_FILE", encryptionKeyFile)
|
|
||||||
t.Setenv("DB_CONNECTION_STRING_FILE", dbConnFile)
|
|
||||||
|
|
||||||
err := resolveFileBasedEnvVariables(&config)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
// All should be resolved correctly
|
|
||||||
assert.Equal(t, []byte(encryptionKeyContent), config.EncryptionKey)
|
|
||||||
assert.Equal(t, dbConnContent, config.DbConnectionString)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("should handle mixed file and non-file environment variables", func(t *testing.T) {
|
|
||||||
config := defaultConfig()
|
|
||||||
|
|
||||||
// Set both file and non-file environment variables
|
|
||||||
t.Setenv("ENCRYPTION_KEY_FILE", encryptionKeyFile)
|
|
||||||
|
|
||||||
err := resolveFileBasedEnvVariables(&config)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
// File-based should be resolved, others should remain as set by env parser
|
|
||||||
assert.Equal(t, []byte(encryptionKeyContent), config.EncryptionKey)
|
|
||||||
assert.Equal(t, "http://localhost:1411", config.AppURL)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("should handle binary data correctly", func(t *testing.T) {
|
t.Run("should handle binary data correctly", func(t *testing.T) {
|
||||||
config := defaultConfig()
|
config := defaultConfig()
|
||||||
|
|
||||||
// Set environment variable pointing to binary file
|
|
||||||
t.Setenv("ENCRYPTION_KEY_FILE", binaryKeyFile)
|
t.Setenv("ENCRYPTION_KEY_FILE", binaryKeyFile)
|
||||||
|
|
||||||
err := resolveFileBasedEnvVariables(&config)
|
err := prepareEnvConfig(&config)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Verify binary data was read correctly without corruption
|
|
||||||
assert.Equal(t, binaryKeyContent, config.EncryptionKey)
|
assert.Equal(t, binaryKeyContent, config.EncryptionKey)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user