1
0
mirror of https://github.com/pocket-id/pocket-id.git synced 2026-02-13 00:15:14 +00:00

feat: remove DbProvider env variable and calculate it dynamically (#1114)

This commit is contained in:
Kyle Mendell
2025-11-27 14:38:06 -06:00
committed by Elias Schneider
parent 3420a00073
commit ba2f0f18f4
3 changed files with 43 additions and 76 deletions

View File

@@ -38,38 +38,42 @@ const (
) )
type EnvConfigSchema struct { type EnvConfigSchema struct {
AppEnv AppEnv `env:"APP_ENV" options:"toLower"` AppEnv AppEnv `env:"APP_ENV" options:"toLower"`
LogLevel string `env:"LOG_LEVEL" options:"toLower"` EncryptionKey []byte `env:"ENCRYPTION_KEY" options:"file"`
AppURL string `env:"APP_URL" options:"toLower,trimTrailingSlash"` AppURL string `env:"APP_URL" options:"toLower,trimTrailingSlash"`
DbProvider DbProvider `env:"DB_PROVIDER" options:"toLower"` DbProvider DbProvider
DbConnectionString string `env:"DB_CONNECTION_STRING" options:"file"` DbConnectionString string `env:"DB_CONNECTION_STRING" options:"file"`
FileBackend string `env:"FILE_BACKEND" options:"toLower"` TrustProxy bool `env:"TRUST_PROXY"`
UploadPath string `env:"UPLOAD_PATH"` AuditLogRetentionDays int `env:"AUDIT_LOG_RETENTION_DAYS"`
S3Bucket string `env:"S3_BUCKET"` AnalyticsDisabled bool `env:"ANALYTICS_DISABLED"`
S3Region string `env:"S3_REGION"` AllowDowngrade bool `env:"ALLOW_DOWNGRADE"`
S3Endpoint string `env:"S3_ENDPOINT"` InternalAppURL string `env:"INTERNAL_APP_URL"`
S3AccessKeyID string `env:"S3_ACCESS_KEY_ID"` UiConfigDisabled bool `env:"UI_CONFIG_DISABLED"`
S3SecretAccessKey string `env:"S3_SECRET_ACCESS_KEY"`
S3ForcePathStyle bool `env:"S3_FORCE_PATH_STYLE"` FileBackend string `env:"FILE_BACKEND" options:"toLower"`
S3DisableDefaultIntegrityChecks bool `env:"S3_DISABLE_DEFAULT_INTEGRITY_CHECKS"` UploadPath string `env:"UPLOAD_PATH"`
EncryptionKey []byte `env:"ENCRYPTION_KEY" options:"file"` S3Bucket string `env:"S3_BUCKET"`
Port string `env:"PORT"` S3Region string `env:"S3_REGION"`
Host string `env:"HOST" options:"toLower"` S3Endpoint string `env:"S3_ENDPOINT"`
UnixSocket string `env:"UNIX_SOCKET"` S3AccessKeyID string `env:"S3_ACCESS_KEY_ID"`
UnixSocketMode string `env:"UNIX_SOCKET_MODE"` S3SecretAccessKey string `env:"S3_SECRET_ACCESS_KEY"`
MaxMindLicenseKey string `env:"MAXMIND_LICENSE_KEY" options:"file"` S3ForcePathStyle bool `env:"S3_FORCE_PATH_STYLE"`
GeoLiteDBPath string `env:"GEOLITE_DB_PATH"` S3DisableDefaultIntegrityChecks bool `env:"S3_DISABLE_DEFAULT_INTEGRITY_CHECKS"`
GeoLiteDBUrl string `env:"GEOLITE_DB_URL"`
LocalIPv6Ranges string `env:"LOCAL_IPV6_RANGES"` Port string `env:"PORT"`
UiConfigDisabled bool `env:"UI_CONFIG_DISABLED"` Host string `env:"HOST" options:"toLower"`
MetricsEnabled bool `env:"METRICS_ENABLED"` UnixSocket string `env:"UNIX_SOCKET"`
TracingEnabled bool `env:"TRACING_ENABLED"` UnixSocketMode string `env:"UNIX_SOCKET_MODE"`
LogJSON bool `env:"LOG_JSON"` LocalIPv6Ranges string `env:"LOCAL_IPV6_RANGES"`
TrustProxy bool `env:"TRUST_PROXY"`
AuditLogRetentionDays int `env:"AUDIT_LOG_RETENTION_DAYS"` MaxMindLicenseKey string `env:"MAXMIND_LICENSE_KEY" options:"file"`
AnalyticsDisabled bool `env:"ANALYTICS_DISABLED"` GeoLiteDBPath string `env:"GEOLITE_DB_PATH"`
AllowDowngrade bool `env:"ALLOW_DOWNGRADE"` GeoLiteDBUrl string `env:"GEOLITE_DB_URL"`
InternalAppURL string `env:"INTERNAL_APP_URL"`
LogLevel string `env:"LOG_LEVEL" options:"toLower"`
MetricsEnabled bool `env:"METRICS_ENABLED"`
TracingEnabled bool `env:"TRACING_ENABLED"`
LogJSON bool `env:"LOG_JSON"`
} }
var EnvConfig = defaultConfig() var EnvConfig = defaultConfig()
@@ -130,17 +134,14 @@ func ValidateEnvConfig(config *EnvConfigSchema) error {
return errors.New("ENCRYPTION_KEY must be at least 16 bytes long") return errors.New("ENCRYPTION_KEY must be at least 16 bytes long")
} }
switch config.DbProvider { switch {
case DbProviderSqlite: case config.DbConnectionString == "":
if config.DbConnectionString == "" { config.DbProvider = DbProviderSqlite
config.DbConnectionString = defaultSqliteConnString config.DbConnectionString = defaultSqliteConnString
} case strings.HasPrefix(config.DbConnectionString, "postgres://") || strings.HasPrefix(config.DbConnectionString, "postgresql://"):
case DbProviderPostgres: config.DbProvider = DbProviderPostgres
if config.DbConnectionString == "" {
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'") config.DbProvider = DbProviderSqlite
} }
parsedAppUrl, err := url.Parse(config.AppURL) parsedAppUrl, err := url.Parse(config.AppURL)

View File

@@ -31,7 +31,6 @@ 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") // 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")
@@ -43,7 +42,6 @@ func TestParseEnvConfig(t *testing.T) {
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_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")
@@ -52,20 +50,8 @@ func TestParseEnvConfig(t *testing.T) {
assert.Equal(t, DbProviderPostgres, EnvConfig.DbProvider) assert.Equal(t, DbProviderPostgres, EnvConfig.DbProvider)
}) })
t.Run("should fail with invalid DB_PROVIDER", func(t *testing.T) {
EnvConfig = defaultConfig()
t.Setenv("DB_PROVIDER", "invalid")
t.Setenv("DB_CONNECTION_STRING", "test")
t.Setenv("APP_URL", "http://localhost:3000")
err := parseAndValidateEnvConfig(t)
require.Error(t, err)
assert.ErrorContains(t, err, "invalid DB_PROVIDER value")
})
t.Run("should fail when ENCRYPTION_KEY is too short", func(t *testing.T) { t.Run("should fail when ENCRYPTION_KEY is too short", func(t *testing.T) {
EnvConfig = defaultConfig() EnvConfig = defaultConfig()
t.Setenv("DB_PROVIDER", "sqlite")
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")
t.Setenv("ENCRYPTION_KEY", "short") t.Setenv("ENCRYPTION_KEY", "short")
@@ -77,7 +63,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("APP_URL", "http://localhost:3000") t.Setenv("APP_URL", "http://localhost:3000")
err := parseAndValidateEnvConfig(t) err := parseAndValidateEnvConfig(t)
@@ -85,19 +70,8 @@ func TestParseEnvConfig(t *testing.T) {
assert.Equal(t, defaultSqliteConnString, EnvConfig.DbConnectionString) assert.Equal(t, defaultSqliteConnString, EnvConfig.DbConnectionString)
}) })
t.Run("should fail when Postgres DB_CONNECTION_STRING is missing", func(t *testing.T) {
EnvConfig = defaultConfig()
t.Setenv("DB_PROVIDER", "postgres")
t.Setenv("APP_URL", "http://localhost:3000")
err := parseAndValidateEnvConfig(t)
require.Error(t, err)
assert.ErrorContains(t, err, "missing required env var 'DB_CONNECTION_STRING' for Postgres")
})
t.Run("should fail with invalid APP_URL", func(t *testing.T) { t.Run("should fail with invalid APP_URL", func(t *testing.T) {
EnvConfig = defaultConfig() EnvConfig = defaultConfig()
t.Setenv("DB_PROVIDER", "sqlite")
t.Setenv("DB_CONNECTION_STRING", "file:test.db") t.Setenv("DB_CONNECTION_STRING", "file:test.db")
t.Setenv("APP_URL", "€://not-a-valid-url") t.Setenv("APP_URL", "€://not-a-valid-url")
@@ -108,7 +82,6 @@ func TestParseEnvConfig(t *testing.T) {
t.Run("should fail when APP_URL contains path", func(t *testing.T) { t.Run("should fail when APP_URL contains path", func(t *testing.T) {
EnvConfig = defaultConfig() EnvConfig = defaultConfig()
t.Setenv("DB_PROVIDER", "sqlite")
t.Setenv("DB_CONNECTION_STRING", "file:test.db") t.Setenv("DB_CONNECTION_STRING", "file:test.db")
t.Setenv("APP_URL", "http://localhost:3000/path") t.Setenv("APP_URL", "http://localhost:3000/path")
@@ -119,7 +92,6 @@ func TestParseEnvConfig(t *testing.T) {
t.Run("should fail with invalid INTERNAL_APP_URL", func(t *testing.T) { t.Run("should fail with invalid INTERNAL_APP_URL", func(t *testing.T) {
EnvConfig = defaultConfig() EnvConfig = defaultConfig()
t.Setenv("DB_PROVIDER", "sqlite")
t.Setenv("DB_CONNECTION_STRING", "file:test.db") t.Setenv("DB_CONNECTION_STRING", "file:test.db")
t.Setenv("INTERNAL_APP_URL", "€://not-a-valid-url") t.Setenv("INTERNAL_APP_URL", "€://not-a-valid-url")
@@ -130,7 +102,6 @@ func TestParseEnvConfig(t *testing.T) {
t.Run("should fail when INTERNAL_APP_URL contains path", func(t *testing.T) { t.Run("should fail when INTERNAL_APP_URL contains path", func(t *testing.T) {
EnvConfig = defaultConfig() EnvConfig = defaultConfig()
t.Setenv("DB_PROVIDER", "sqlite")
t.Setenv("DB_CONNECTION_STRING", "file:test.db") t.Setenv("DB_CONNECTION_STRING", "file:test.db")
t.Setenv("INTERNAL_APP_URL", "http://localhost:3000/path") t.Setenv("INTERNAL_APP_URL", "http://localhost:3000/path")
@@ -141,7 +112,6 @@ func TestParseEnvConfig(t *testing.T) {
t.Run("should parse boolean environment variables correctly", func(t *testing.T) { t.Run("should parse boolean environment variables correctly", func(t *testing.T) {
EnvConfig = defaultConfig() EnvConfig = defaultConfig()
t.Setenv("DB_PROVIDER", "sqlite")
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")
t.Setenv("UI_CONFIG_DISABLED", "true") t.Setenv("UI_CONFIG_DISABLED", "true")
@@ -196,7 +166,6 @@ func TestParseEnvConfig(t *testing.T) {
t.Run("should parse string environment variables correctly", func(t *testing.T) { t.Run("should parse string environment variables correctly", func(t *testing.T) {
EnvConfig = defaultConfig() EnvConfig = defaultConfig()
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", "PRODUCTION") t.Setenv("APP_ENV", "PRODUCTION")
@@ -217,7 +186,6 @@ func TestParseEnvConfig(t *testing.T) {
t.Run("should normalize file backend and default upload path", func(t *testing.T) { t.Run("should normalize file backend and default upload path", func(t *testing.T) {
EnvConfig = defaultConfig() EnvConfig = defaultConfig()
t.Setenv("DB_PROVIDER", "sqlite")
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")
t.Setenv("FILE_BACKEND", "FILESYSTEM") t.Setenv("FILE_BACKEND", "FILESYSTEM")
@@ -231,7 +199,6 @@ func TestParseEnvConfig(t *testing.T) {
t.Run("should fail with invalid FILE_BACKEND value", func(t *testing.T) { t.Run("should fail with invalid FILE_BACKEND value", func(t *testing.T) {
EnvConfig = defaultConfig() EnvConfig = defaultConfig()
t.Setenv("DB_PROVIDER", "sqlite")
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")
t.Setenv("FILE_BACKEND", "invalid") t.Setenv("FILE_BACKEND", "invalid")

View File

@@ -21,7 +21,6 @@ services:
service: pocket-id service: pocket-id
environment: environment:
- APP_ENV=test - APP_ENV=test
- DB_PROVIDER=postgres
- DB_CONNECTION_STRING=postgres://postgres:postgres@postgres:5432/pocket-id - DB_CONNECTION_STRING=postgres://postgres:postgres@postgres:5432/pocket-id
- FILE_BACKEND=${FILE_BACKEND} - FILE_BACKEND=${FILE_BACKEND}
depends_on: depends_on: