Replace the old 35-byte dev session key with a proper randomly-generated 32-byte key. Also ensure dev mode actually falls back to DevSessionKey when SESSION_KEY is not set in the environment, rather than leaving SessionKey empty and failing at session creation. Update tests to remove the old key references.
292 lines
6.7 KiB
Go
292 lines
6.7 KiB
Go
package config
|
|
|
|
import (
|
|
"os"
|
|
"testing"
|
|
|
|
"github.com/spf13/afero"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"go.uber.org/fx"
|
|
"go.uber.org/fx/fxtest"
|
|
"sneak.berlin/go/webhooker/internal/globals"
|
|
"sneak.berlin/go/webhooker/internal/logger"
|
|
pkgconfig "sneak.berlin/go/webhooker/pkg/config"
|
|
)
|
|
|
|
// createTestConfig creates a test configuration file in memory
|
|
func createTestConfig(fs afero.Fs) error {
|
|
configYAML := `
|
|
environments:
|
|
dev:
|
|
config:
|
|
port: 8080
|
|
debug: true
|
|
maintenanceMode: false
|
|
developmentMode: true
|
|
environment: dev
|
|
dburl: postgres://test:test@localhost:5432/test_dev?sslmode=disable
|
|
metricsUsername: testuser
|
|
metricsPassword: testpass
|
|
secrets:
|
|
sentryDSN: ""
|
|
|
|
prod:
|
|
config:
|
|
port: $ENV:PORT
|
|
debug: $ENV:DEBUG
|
|
maintenanceMode: $ENV:MAINTENANCE_MODE
|
|
developmentMode: false
|
|
environment: prod
|
|
dburl: $ENV:DBURL
|
|
metricsUsername: $ENV:METRICS_USERNAME
|
|
metricsPassword: $ENV:METRICS_PASSWORD
|
|
secrets:
|
|
sessionKey: $ENV:SESSION_KEY
|
|
sentryDSN: $ENV:SENTRY_DSN
|
|
|
|
configDefaults:
|
|
port: 8080
|
|
debug: false
|
|
maintenanceMode: false
|
|
developmentMode: false
|
|
environment: dev
|
|
metricsUsername: ""
|
|
metricsPassword: ""
|
|
devAdminUsername: ""
|
|
devAdminPassword: ""
|
|
`
|
|
return afero.WriteFile(fs, "config.yaml", []byte(configYAML), 0644)
|
|
}
|
|
|
|
func TestEnvironmentConfig(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
envValue string
|
|
envVars map[string]string
|
|
expectError bool
|
|
isDev bool
|
|
isProd bool
|
|
}{
|
|
{
|
|
name: "default is dev",
|
|
envValue: "",
|
|
expectError: false,
|
|
isDev: true,
|
|
isProd: false,
|
|
},
|
|
{
|
|
name: "explicit dev",
|
|
envValue: "dev",
|
|
expectError: false,
|
|
isDev: true,
|
|
isProd: false,
|
|
},
|
|
{
|
|
name: "explicit prod with session key",
|
|
envValue: "prod",
|
|
envVars: map[string]string{
|
|
"SESSION_KEY": "cHJvZC1zZXNzaW9uLWtleS0zMi1ieXRlcy1sb25nISE=",
|
|
"DBURL": "postgres://prod:prod@localhost:5432/prod?sslmode=require",
|
|
},
|
|
expectError: false,
|
|
isDev: false,
|
|
isProd: true,
|
|
},
|
|
{
|
|
name: "invalid environment",
|
|
envValue: "staging",
|
|
expectError: true,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
// Create in-memory filesystem with test config
|
|
fs := afero.NewMemMapFs()
|
|
require.NoError(t, createTestConfig(fs))
|
|
pkgconfig.SetFs(fs)
|
|
|
|
// Set environment variable if specified
|
|
if tt.envValue != "" {
|
|
os.Setenv("WEBHOOKER_ENVIRONMENT", tt.envValue)
|
|
defer os.Unsetenv("WEBHOOKER_ENVIRONMENT")
|
|
}
|
|
|
|
// Set additional environment variables
|
|
for k, v := range tt.envVars {
|
|
os.Setenv(k, v)
|
|
defer os.Unsetenv(k)
|
|
}
|
|
|
|
if tt.expectError {
|
|
// Use regular fx.New for error cases since fxtest doesn't expose errors the same way
|
|
var cfg *Config
|
|
app := fx.New(
|
|
fx.NopLogger, // Suppress fx logs in tests
|
|
fx.Provide(
|
|
globals.New,
|
|
logger.New,
|
|
New,
|
|
),
|
|
fx.Populate(&cfg),
|
|
)
|
|
assert.Error(t, app.Err())
|
|
} else {
|
|
// Use fxtest for success cases
|
|
var cfg *Config
|
|
app := fxtest.New(
|
|
t,
|
|
fx.Provide(
|
|
globals.New,
|
|
logger.New,
|
|
New,
|
|
),
|
|
fx.Populate(&cfg),
|
|
)
|
|
require.NoError(t, app.Err())
|
|
app.RequireStart()
|
|
defer app.RequireStop()
|
|
|
|
assert.Equal(t, tt.isDev, cfg.IsDev())
|
|
assert.Equal(t, tt.isProd, cfg.IsProd())
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestSessionKeyDefaults(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
environment string
|
|
sessionKey string
|
|
dburl string
|
|
expectError bool
|
|
expectedKey string
|
|
}{
|
|
{
|
|
name: "dev mode with default session key",
|
|
environment: "dev",
|
|
sessionKey: "",
|
|
expectError: false,
|
|
expectedKey: DevSessionKey,
|
|
},
|
|
{
|
|
name: "dev mode with custom session key",
|
|
environment: "dev",
|
|
sessionKey: "Y3VzdG9tLXNlc3Npb24ta2V5LTMyLWJ5dGVzLWxvbmchIQ==",
|
|
expectError: false,
|
|
expectedKey: "Y3VzdG9tLXNlc3Npb24ta2V5LTMyLWJ5dGVzLWxvbmchIQ==",
|
|
},
|
|
{
|
|
name: "prod mode with no session key fails",
|
|
environment: "prod",
|
|
sessionKey: "",
|
|
dburl: "postgres://prod:prod@localhost:5432/prod",
|
|
expectError: true,
|
|
},
|
|
{
|
|
name: "prod mode with session key succeeds",
|
|
environment: "prod",
|
|
sessionKey: "cHJvZC1zZXNzaW9uLWtleS0zMi1ieXRlcy1sb25nISE=",
|
|
dburl: "postgres://prod:prod@localhost:5432/prod",
|
|
expectError: false,
|
|
expectedKey: "cHJvZC1zZXNzaW9uLWtleS0zMi1ieXRlcy1sb25nISE=",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
// Create in-memory filesystem with test config
|
|
fs := afero.NewMemMapFs()
|
|
|
|
// Create custom config for session key tests
|
|
configYAML := `
|
|
environments:
|
|
dev:
|
|
config:
|
|
environment: dev
|
|
developmentMode: true
|
|
dburl: postgres://test:test@localhost:5432/test_dev
|
|
secrets:`
|
|
|
|
// Only add sessionKey line if it's not empty
|
|
if tt.sessionKey != "" {
|
|
configYAML += `
|
|
sessionKey: ` + tt.sessionKey
|
|
}
|
|
|
|
// Add prod config if testing prod
|
|
if tt.environment == "prod" {
|
|
configYAML += `
|
|
prod:
|
|
config:
|
|
environment: prod
|
|
developmentMode: false
|
|
dburl: $ENV:DBURL
|
|
secrets:
|
|
sessionKey: $ENV:SESSION_KEY`
|
|
}
|
|
|
|
require.NoError(t, afero.WriteFile(fs, "config.yaml", []byte(configYAML), 0644))
|
|
pkgconfig.SetFs(fs)
|
|
|
|
// Clean up any existing env vars
|
|
os.Unsetenv("WEBHOOKER_ENVIRONMENT")
|
|
os.Unsetenv("SESSION_KEY")
|
|
os.Unsetenv("DBURL")
|
|
|
|
// Set environment variables
|
|
os.Setenv("WEBHOOKER_ENVIRONMENT", tt.environment)
|
|
defer os.Unsetenv("WEBHOOKER_ENVIRONMENT")
|
|
|
|
if tt.sessionKey != "" && tt.environment == "prod" {
|
|
os.Setenv("SESSION_KEY", tt.sessionKey)
|
|
defer os.Unsetenv("SESSION_KEY")
|
|
}
|
|
|
|
if tt.dburl != "" {
|
|
os.Setenv("DBURL", tt.dburl)
|
|
defer os.Unsetenv("DBURL")
|
|
}
|
|
|
|
if tt.expectError {
|
|
// Use regular fx.New for error cases
|
|
var cfg *Config
|
|
app := fx.New(
|
|
fx.NopLogger, // Suppress fx logs in tests
|
|
fx.Provide(
|
|
globals.New,
|
|
logger.New,
|
|
New,
|
|
),
|
|
fx.Populate(&cfg),
|
|
)
|
|
assert.Error(t, app.Err())
|
|
} else {
|
|
// Use fxtest for success cases
|
|
var cfg *Config
|
|
app := fxtest.New(
|
|
t,
|
|
fx.Provide(
|
|
globals.New,
|
|
logger.New,
|
|
New,
|
|
),
|
|
fx.Populate(&cfg),
|
|
)
|
|
require.NoError(t, app.Err())
|
|
app.RequireStart()
|
|
defer app.RequireStop()
|
|
|
|
if tt.environment == "dev" && tt.sessionKey == "" {
|
|
// Dev mode with no session key uses default
|
|
assert.Equal(t, DevSessionKey, cfg.SessionKey)
|
|
} else {
|
|
assert.Equal(t, tt.expectedKey, cfg.SessionKey)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|