Files
galaxy-game/gateway/internal/config/config_test.go
T
2026-04-09 15:27:14 +02:00

1382 lines
44 KiB
Go

package config
import (
"crypto/ed25519"
"crypto/sha256"
"crypto/x509"
"encoding/pem"
"os"
"path/filepath"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestLoadFromEnv(t *testing.T) {
customResponseSignerPrivateKeyPEMPath := new(string)
*customResponseSignerPrivateKeyPEMPath = writeTestResponseSignerPEMFile(t)
customShutdownTimeout := new(string)
*customShutdownTimeout = "17s"
customPublicHTTPAddr := new(string)
*customPublicHTTPAddr = "127.0.0.1:9090"
customAuthServiceBaseURL := new(string)
*customAuthServiceBaseURL = " http://127.0.0.1:8082/ "
customAuthenticatedGRPCAddr := new(string)
*customAuthenticatedGRPCAddr = "127.0.0.1:9191"
customAuthenticatedGRPCFreshnessWindow := new(string)
*customAuthenticatedGRPCFreshnessWindow = "90s"
customSessionCacheRedisAddr := new(string)
*customSessionCacheRedisAddr = "127.0.0.1:6379"
customSessionEventsRedisStream := new(string)
*customSessionEventsRedisStream = "gateway:session_events"
customClientEventsRedisStream := new(string)
*customClientEventsRedisStream = "gateway:client_events"
emptyPublicHTTPAddr := new(string)
*emptyPublicHTTPAddr = ""
whitespacePublicHTTPAddr := new(string)
*whitespacePublicHTTPAddr = " "
emptyAuthenticatedGRPCAddr := new(string)
*emptyAuthenticatedGRPCAddr = ""
whitespaceAuthenticatedGRPCAddr := new(string)
*whitespaceAuthenticatedGRPCAddr = " "
emptySessionCacheRedisAddr := new(string)
*emptySessionCacheRedisAddr = ""
whitespaceSessionCacheRedisAddr := new(string)
*whitespaceSessionCacheRedisAddr = " "
zeroShutdownTimeout := new(string)
*zeroShutdownTimeout = "0s"
negativeShutdownTimeout := new(string)
*negativeShutdownTimeout = "-1s"
invalidShutdownTimeout := new(string)
*invalidShutdownTimeout = "later"
zeroAuthenticatedGRPCFreshnessWindow := new(string)
*zeroAuthenticatedGRPCFreshnessWindow = "0s"
invalidAuthenticatedGRPCFreshnessWindow := new(string)
*invalidAuthenticatedGRPCFreshnessWindow = "later"
tests := []struct {
name string
shutdownTimeout *string
publicHTTPAddr *string
authServiceBaseURL *string
authenticatedGRPCAddr *string
authenticatedGRPCFreshnessWindow *string
sessionCacheRedisAddr *string
responseSignerPrivateKeyPEMPath *string
want Config
wantErr string
}{
{
name: "required redis address with default optional values",
sessionCacheRedisAddr: customSessionCacheRedisAddr,
responseSignerPrivateKeyPEMPath: customResponseSignerPrivateKeyPEMPath,
want: Config{
ShutdownTimeout: 5 * time.Second,
Logging: DefaultLoggingConfig(),
PublicHTTP: DefaultPublicHTTPConfig(),
AdminHTTP: DefaultAdminHTTPConfig(),
AuthenticatedGRPC: DefaultAuthenticatedGRPCConfig(),
SessionCacheRedis: SessionCacheRedisConfig{
Addr: "127.0.0.1:6379",
DB: defaultSessionCacheRedisDB,
KeyPrefix: defaultSessionCacheRedisKeyPrefix,
LookupTimeout: defaultSessionCacheRedisLookupTimeout,
},
ReplayRedis: DefaultReplayRedisConfig(),
SessionEventsRedis: SessionEventsRedisConfig{
Stream: "gateway:session_events",
ReadBlockTimeout: defaultSessionEventsRedisReadBlockTimeout,
},
ClientEventsRedis: ClientEventsRedisConfig{
Stream: "gateway:client_events",
ReadBlockTimeout: defaultClientEventsRedisReadBlockTimeout,
},
ResponseSigner: ResponseSignerConfig{
PrivateKeyPEMPath: *customResponseSignerPrivateKeyPEMPath,
},
},
},
{
name: "custom shutdown timeout",
shutdownTimeout: customShutdownTimeout,
sessionCacheRedisAddr: customSessionCacheRedisAddr,
responseSignerPrivateKeyPEMPath: customResponseSignerPrivateKeyPEMPath,
want: Config{
ShutdownTimeout: 17 * time.Second,
Logging: DefaultLoggingConfig(),
PublicHTTP: DefaultPublicHTTPConfig(),
AdminHTTP: DefaultAdminHTTPConfig(),
AuthenticatedGRPC: DefaultAuthenticatedGRPCConfig(),
SessionCacheRedis: SessionCacheRedisConfig{
Addr: "127.0.0.1:6379",
DB: defaultSessionCacheRedisDB,
KeyPrefix: defaultSessionCacheRedisKeyPrefix,
LookupTimeout: defaultSessionCacheRedisLookupTimeout,
},
ReplayRedis: DefaultReplayRedisConfig(),
SessionEventsRedis: SessionEventsRedisConfig{
Stream: "gateway:session_events",
ReadBlockTimeout: defaultSessionEventsRedisReadBlockTimeout,
},
ClientEventsRedis: ClientEventsRedisConfig{
Stream: "gateway:client_events",
ReadBlockTimeout: defaultClientEventsRedisReadBlockTimeout,
},
ResponseSigner: ResponseSignerConfig{
PrivateKeyPEMPath: *customResponseSignerPrivateKeyPEMPath,
},
},
},
{
name: "custom public http address",
publicHTTPAddr: customPublicHTTPAddr,
sessionCacheRedisAddr: customSessionCacheRedisAddr,
responseSignerPrivateKeyPEMPath: customResponseSignerPrivateKeyPEMPath,
want: Config{
ShutdownTimeout: 5 * time.Second,
Logging: DefaultLoggingConfig(),
PublicHTTP: func() PublicHTTPConfig {
cfg := DefaultPublicHTTPConfig()
cfg.Addr = "127.0.0.1:9090"
return cfg
}(),
AdminHTTP: DefaultAdminHTTPConfig(),
AuthenticatedGRPC: DefaultAuthenticatedGRPCConfig(),
SessionCacheRedis: SessionCacheRedisConfig{
Addr: "127.0.0.1:6379",
DB: defaultSessionCacheRedisDB,
KeyPrefix: defaultSessionCacheRedisKeyPrefix,
LookupTimeout: defaultSessionCacheRedisLookupTimeout,
},
ReplayRedis: DefaultReplayRedisConfig(),
SessionEventsRedis: SessionEventsRedisConfig{
Stream: "gateway:session_events",
ReadBlockTimeout: defaultSessionEventsRedisReadBlockTimeout,
},
ClientEventsRedis: ClientEventsRedisConfig{
Stream: "gateway:client_events",
ReadBlockTimeout: defaultClientEventsRedisReadBlockTimeout,
},
ResponseSigner: ResponseSignerConfig{
PrivateKeyPEMPath: *customResponseSignerPrivateKeyPEMPath,
},
},
},
{
name: "custom auth service base url",
authServiceBaseURL: customAuthServiceBaseURL,
sessionCacheRedisAddr: customSessionCacheRedisAddr,
responseSignerPrivateKeyPEMPath: customResponseSignerPrivateKeyPEMPath,
want: Config{
ShutdownTimeout: 5 * time.Second,
Logging: DefaultLoggingConfig(),
PublicHTTP: DefaultPublicHTTPConfig(),
AuthService: AuthServiceConfig{
BaseURL: "http://127.0.0.1:8082",
},
AdminHTTP: DefaultAdminHTTPConfig(),
AuthenticatedGRPC: DefaultAuthenticatedGRPCConfig(),
SessionCacheRedis: SessionCacheRedisConfig{
Addr: "127.0.0.1:6379",
DB: defaultSessionCacheRedisDB,
KeyPrefix: defaultSessionCacheRedisKeyPrefix,
LookupTimeout: defaultSessionCacheRedisLookupTimeout,
},
ReplayRedis: DefaultReplayRedisConfig(),
SessionEventsRedis: SessionEventsRedisConfig{
Stream: "gateway:session_events",
ReadBlockTimeout: defaultSessionEventsRedisReadBlockTimeout,
},
ClientEventsRedis: ClientEventsRedisConfig{
Stream: "gateway:client_events",
ReadBlockTimeout: defaultClientEventsRedisReadBlockTimeout,
},
ResponseSigner: ResponseSignerConfig{
PrivateKeyPEMPath: *customResponseSignerPrivateKeyPEMPath,
},
},
},
{
name: "custom authenticated grpc address",
authenticatedGRPCAddr: customAuthenticatedGRPCAddr,
sessionCacheRedisAddr: customSessionCacheRedisAddr,
responseSignerPrivateKeyPEMPath: customResponseSignerPrivateKeyPEMPath,
want: Config{
ShutdownTimeout: 5 * time.Second,
Logging: DefaultLoggingConfig(),
PublicHTTP: DefaultPublicHTTPConfig(),
AdminHTTP: DefaultAdminHTTPConfig(),
AuthenticatedGRPC: func() AuthenticatedGRPCConfig {
cfg := DefaultAuthenticatedGRPCConfig()
cfg.Addr = "127.0.0.1:9191"
return cfg
}(),
SessionCacheRedis: SessionCacheRedisConfig{
Addr: "127.0.0.1:6379",
DB: defaultSessionCacheRedisDB,
KeyPrefix: defaultSessionCacheRedisKeyPrefix,
LookupTimeout: defaultSessionCacheRedisLookupTimeout,
},
ReplayRedis: DefaultReplayRedisConfig(),
SessionEventsRedis: SessionEventsRedisConfig{
Stream: "gateway:session_events",
ReadBlockTimeout: defaultSessionEventsRedisReadBlockTimeout,
},
ClientEventsRedis: ClientEventsRedisConfig{
Stream: "gateway:client_events",
ReadBlockTimeout: defaultClientEventsRedisReadBlockTimeout,
},
ResponseSigner: ResponseSignerConfig{
PrivateKeyPEMPath: *customResponseSignerPrivateKeyPEMPath,
},
},
},
{
name: "custom authenticated grpc freshness window",
authenticatedGRPCFreshnessWindow: customAuthenticatedGRPCFreshnessWindow,
sessionCacheRedisAddr: customSessionCacheRedisAddr,
responseSignerPrivateKeyPEMPath: customResponseSignerPrivateKeyPEMPath,
want: Config{
ShutdownTimeout: 5 * time.Second,
Logging: DefaultLoggingConfig(),
PublicHTTP: DefaultPublicHTTPConfig(),
AdminHTTP: DefaultAdminHTTPConfig(),
AuthenticatedGRPC: func() AuthenticatedGRPCConfig {
cfg := DefaultAuthenticatedGRPCConfig()
cfg.FreshnessWindow = 90 * time.Second
return cfg
}(),
SessionCacheRedis: SessionCacheRedisConfig{
Addr: "127.0.0.1:6379",
DB: defaultSessionCacheRedisDB,
KeyPrefix: defaultSessionCacheRedisKeyPrefix,
LookupTimeout: defaultSessionCacheRedisLookupTimeout,
},
ReplayRedis: DefaultReplayRedisConfig(),
SessionEventsRedis: SessionEventsRedisConfig{
Stream: "gateway:session_events",
ReadBlockTimeout: defaultSessionEventsRedisReadBlockTimeout,
},
ClientEventsRedis: ClientEventsRedisConfig{
Stream: "gateway:client_events",
ReadBlockTimeout: defaultClientEventsRedisReadBlockTimeout,
},
ResponseSigner: ResponseSignerConfig{
PrivateKeyPEMPath: *customResponseSignerPrivateKeyPEMPath,
},
},
},
{
name: "zero shutdown timeout",
shutdownTimeout: zeroShutdownTimeout,
wantErr: "must be positive",
},
{
name: "negative shutdown timeout",
shutdownTimeout: negativeShutdownTimeout,
wantErr: "must be positive",
},
{
name: "invalid shutdown timeout",
shutdownTimeout: invalidShutdownTimeout,
wantErr: "parse GATEWAY_SHUTDOWN_TIMEOUT",
},
{
name: "empty public http address",
publicHTTPAddr: emptyPublicHTTPAddr,
wantErr: "GATEWAY_PUBLIC_HTTP_ADDR must not be empty",
},
{
name: "whitespace public http address",
publicHTTPAddr: whitespacePublicHTTPAddr,
wantErr: "GATEWAY_PUBLIC_HTTP_ADDR must not be empty",
},
{
name: "empty authenticated grpc address",
authenticatedGRPCAddr: emptyAuthenticatedGRPCAddr,
sessionCacheRedisAddr: customSessionCacheRedisAddr,
wantErr: "GATEWAY_AUTHENTICATED_GRPC_ADDR must not be empty",
},
{
name: "whitespace authenticated grpc address",
authenticatedGRPCAddr: whitespaceAuthenticatedGRPCAddr,
sessionCacheRedisAddr: customSessionCacheRedisAddr,
wantErr: "GATEWAY_AUTHENTICATED_GRPC_ADDR must not be empty",
},
{
name: "zero authenticated grpc freshness window",
authenticatedGRPCFreshnessWindow: zeroAuthenticatedGRPCFreshnessWindow,
sessionCacheRedisAddr: customSessionCacheRedisAddr,
wantErr: authenticatedGRPCFreshnessWindowEnvVar + " must be positive",
},
{
name: "invalid authenticated grpc freshness window",
authenticatedGRPCFreshnessWindow: invalidAuthenticatedGRPCFreshnessWindow,
sessionCacheRedisAddr: customSessionCacheRedisAddr,
wantErr: "parse " + authenticatedGRPCFreshnessWindowEnvVar,
},
{
name: "missing session cache redis address",
responseSignerPrivateKeyPEMPath: customResponseSignerPrivateKeyPEMPath,
wantErr: "GATEWAY_SESSION_CACHE_REDIS_ADDR must not be empty",
},
{
name: "empty session cache redis address",
sessionCacheRedisAddr: emptySessionCacheRedisAddr,
responseSignerPrivateKeyPEMPath: customResponseSignerPrivateKeyPEMPath,
wantErr: "GATEWAY_SESSION_CACHE_REDIS_ADDR must not be empty",
},
{
name: "whitespace session cache redis address",
sessionCacheRedisAddr: whitespaceSessionCacheRedisAddr,
responseSignerPrivateKeyPEMPath: customResponseSignerPrivateKeyPEMPath,
wantErr: "GATEWAY_SESSION_CACHE_REDIS_ADDR must not be empty",
},
{
name: "missing response signer private key path",
sessionCacheRedisAddr: customSessionCacheRedisAddr,
wantErr: responseSignerPrivateKeyPEMPathEnvVar + " must not be empty",
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
restoreEnvs(t,
shutdownTimeoutEnvVar,
publicHTTPAddrEnvVar,
authServiceBaseURLEnvVar,
authenticatedGRPCAddrEnvVar,
authenticatedGRPCFreshnessWindowEnvVar,
sessionCacheRedisAddrEnvVar,
sessionEventsRedisStreamEnvVar,
clientEventsRedisStreamEnvVar,
responseSignerPrivateKeyPEMPathEnvVar,
)
setEnvValue(t, shutdownTimeoutEnvVar, tt.shutdownTimeout)
setEnvValue(t, publicHTTPAddrEnvVar, tt.publicHTTPAddr)
setEnvValue(t, authServiceBaseURLEnvVar, tt.authServiceBaseURL)
setEnvValue(t, authenticatedGRPCAddrEnvVar, tt.authenticatedGRPCAddr)
setEnvValue(t, authenticatedGRPCFreshnessWindowEnvVar, tt.authenticatedGRPCFreshnessWindow)
setEnvValue(t, sessionCacheRedisAddrEnvVar, tt.sessionCacheRedisAddr)
setEnvValue(t, sessionEventsRedisStreamEnvVar, customSessionEventsRedisStream)
setEnvValue(t, clientEventsRedisStreamEnvVar, customClientEventsRedisStream)
setEnvValue(t, responseSignerPrivateKeyPEMPathEnvVar, tt.responseSignerPrivateKeyPEMPath)
cfg, err := LoadFromEnv()
if tt.wantErr != "" {
require.Error(t, err)
require.ErrorContains(t, err, tt.wantErr)
return
}
require.NoError(t, err)
assert.Equal(t, tt.want, cfg)
})
}
}
func TestLoadFromEnvOperationalSettings(t *testing.T) {
t.Parallel()
customSessionCacheRedisAddr := new(string)
*customSessionCacheRedisAddr = "127.0.0.1:6379"
customSessionEventsRedisStream := new(string)
*customSessionEventsRedisStream = "gateway:session_events"
customClientEventsRedisStream := new(string)
*customClientEventsRedisStream = "gateway:client_events"
customResponseSignerPrivateKeyPEMPath := new(string)
*customResponseSignerPrivateKeyPEMPath = writeTestResponseSignerPEMFile(t)
customLogLevel := new(string)
*customLogLevel = "debug"
customAdminAddr := new(string)
*customAdminAddr = "127.0.0.1:8081"
customAdminReadTimeout := new(string)
*customAdminReadTimeout = "4s"
customPublicReadTimeout := new(string)
*customPublicReadTimeout = "12s"
customPublicAuthUpstreamTimeout := new(string)
*customPublicAuthUpstreamTimeout = "1500ms"
customGRPCConnectionTimeout := new(string)
*customGRPCConnectionTimeout = "7s"
customGRPCDownstreamTimeout := new(string)
*customGRPCDownstreamTimeout = "9s"
invalidLogLevel := new(string)
*invalidLogLevel = "verbose"
tests := []struct {
name string
envs map[string]*string
assert func(t *testing.T, cfg Config)
wantErr string
}{
{
name: "custom operational settings",
envs: map[string]*string{
sessionCacheRedisAddrEnvVar: customSessionCacheRedisAddr,
sessionEventsRedisStreamEnvVar: customSessionEventsRedisStream,
clientEventsRedisStreamEnvVar: customClientEventsRedisStream,
responseSignerPrivateKeyPEMPathEnvVar: customResponseSignerPrivateKeyPEMPath,
logLevelEnvVar: customLogLevel,
adminHTTPAddrEnvVar: customAdminAddr,
adminHTTPReadTimeoutEnvVar: customAdminReadTimeout,
publicHTTPReadTimeoutEnvVar: customPublicReadTimeout,
publicAuthUpstreamTimeoutEnvVar: customPublicAuthUpstreamTimeout,
authenticatedGRPCConnectionTimeoutEnvVar: customGRPCConnectionTimeout,
authenticatedGRPCDownstreamTimeoutEnvVar: customGRPCDownstreamTimeout,
},
assert: func(t *testing.T, cfg Config) {
t.Helper()
assert.Equal(t, "debug", cfg.Logging.Level)
assert.Equal(t, "127.0.0.1:8081", cfg.AdminHTTP.Addr)
assert.Equal(t, 4*time.Second, cfg.AdminHTTP.ReadTimeout)
assert.Equal(t, 12*time.Second, cfg.PublicHTTP.ReadTimeout)
assert.Equal(t, 1500*time.Millisecond, cfg.PublicHTTP.AuthUpstreamTimeout)
assert.Equal(t, 7*time.Second, cfg.AuthenticatedGRPC.ConnectionTimeout)
assert.Equal(t, 9*time.Second, cfg.AuthenticatedGRPC.DownstreamTimeout)
},
},
{
name: "invalid log level",
envs: map[string]*string{
sessionCacheRedisAddrEnvVar: customSessionCacheRedisAddr,
sessionEventsRedisStreamEnvVar: customSessionEventsRedisStream,
clientEventsRedisStreamEnvVar: customClientEventsRedisStream,
responseSignerPrivateKeyPEMPathEnvVar: customResponseSignerPrivateKeyPEMPath,
logLevelEnvVar: invalidLogLevel,
},
wantErr: logLevelEnvVar + " must be one of",
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
restoreEnvs(t, append(
append(
append(
append(operationalEnvVars(), sessionCacheRedisEnvVars()...),
sessionEventsRedisEnvVars()...,
),
clientEventsRedisEnvVars()...,
),
responseSignerPrivateKeyPEMPathEnvVar,
)...)
for envVar, value := range tt.envs {
setEnvValue(t, envVar, value)
}
cfg, err := LoadFromEnv()
if tt.wantErr != "" {
require.Error(t, err)
require.ErrorContains(t, err, tt.wantErr)
return
}
require.NoError(t, err)
tt.assert(t, cfg)
})
}
}
func TestLoadFromEnvAuthService(t *testing.T) {
t.Parallel()
customSessionCacheRedisAddr := new(string)
*customSessionCacheRedisAddr = "127.0.0.1:6379"
customSessionEventsRedisStream := new(string)
*customSessionEventsRedisStream = "gateway:session_events"
customClientEventsRedisStream := new(string)
*customClientEventsRedisStream = "gateway:client_events"
customResponseSignerPrivateKeyPEMPath := new(string)
*customResponseSignerPrivateKeyPEMPath = writeTestResponseSignerPEMFile(t)
invalidRelativeURL := new(string)
*invalidRelativeURL = "/authsession"
invalidURL := new(string)
*invalidURL = "://bad"
tests := []struct {
name string
value *string
wantErr string
}{
{
name: "relative url rejected",
value: invalidRelativeURL,
wantErr: authServiceBaseURLEnvVar + " must be an absolute URL",
},
{
name: "malformed url rejected",
value: invalidURL,
wantErr: "parse " + authServiceBaseURLEnvVar,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
restoreEnvs(t,
authServiceBaseURLEnvVar,
sessionCacheRedisAddrEnvVar,
sessionEventsRedisStreamEnvVar,
clientEventsRedisStreamEnvVar,
responseSignerPrivateKeyPEMPathEnvVar,
)
setEnvValue(t, authServiceBaseURLEnvVar, tt.value)
setEnvValue(t, sessionCacheRedisAddrEnvVar, customSessionCacheRedisAddr)
setEnvValue(t, sessionEventsRedisStreamEnvVar, customSessionEventsRedisStream)
setEnvValue(t, clientEventsRedisStreamEnvVar, customClientEventsRedisStream)
setEnvValue(t, responseSignerPrivateKeyPEMPathEnvVar, customResponseSignerPrivateKeyPEMPath)
_, err := LoadFromEnv()
require.Error(t, err)
require.ErrorContains(t, err, tt.wantErr)
})
}
}
func TestLoadFromEnvAuthenticatedGRPCAntiAbuse(t *testing.T) {
customSessionCacheRedisAddr := new(string)
*customSessionCacheRedisAddr = "127.0.0.1:6379"
customSessionEventsRedisStream := new(string)
*customSessionEventsRedisStream = "gateway:session_events"
customClientEventsRedisStream := new(string)
*customClientEventsRedisStream = "gateway:client_events"
customResponseSignerPrivateKeyPEMPath := new(string)
*customResponseSignerPrivateKeyPEMPath = writeTestResponseSignerPEMFile(t)
customIPRequests := new(string)
*customIPRequests = "240"
customIPWindow := new(string)
*customIPWindow = "2m"
customIPBurst := new(string)
*customIPBurst = "60"
customSessionRequests := new(string)
*customSessionRequests = "120"
customSessionWindow := new(string)
*customSessionWindow = "90s"
customSessionBurst := new(string)
*customSessionBurst = "30"
customUserRequests := new(string)
*customUserRequests = "180"
customUserWindow := new(string)
*customUserWindow = "3m"
customUserBurst := new(string)
*customUserBurst = "45"
customMessageClassRequests := new(string)
*customMessageClassRequests = "75"
customMessageClassWindow := new(string)
*customMessageClassWindow = "45s"
customMessageClassBurst := new(string)
*customMessageClassBurst = "15"
zeroIPRequests := new(string)
*zeroIPRequests = "0"
tests := []struct {
name string
ipRequests *string
ipWindow *string
ipBurst *string
sessionRequests *string
sessionWindow *string
sessionBurst *string
userRequests *string
userWindow *string
userBurst *string
messageClassRequests *string
messageClassWindow *string
messageClassBurst *string
want AuthenticatedGRPCAntiAbuseConfig
wantErr string
}{
{
name: "custom authenticated grpc anti abuse config",
ipRequests: customIPRequests,
ipWindow: customIPWindow,
ipBurst: customIPBurst,
sessionRequests: customSessionRequests,
sessionWindow: customSessionWindow,
sessionBurst: customSessionBurst,
userRequests: customUserRequests,
userWindow: customUserWindow,
userBurst: customUserBurst,
messageClassRequests: customMessageClassRequests,
messageClassWindow: customMessageClassWindow,
messageClassBurst: customMessageClassBurst,
want: AuthenticatedGRPCAntiAbuseConfig{
IP: AuthenticatedRateLimitConfig{
Requests: 240,
Window: 2 * time.Minute,
Burst: 60,
},
Session: AuthenticatedRateLimitConfig{
Requests: 120,
Window: 90 * time.Second,
Burst: 30,
},
User: AuthenticatedRateLimitConfig{
Requests: 180,
Window: 3 * time.Minute,
Burst: 45,
},
MessageClass: AuthenticatedRateLimitConfig{
Requests: 75,
Window: 45 * time.Second,
Burst: 15,
},
},
},
{
name: "zero authenticated grpc ip requests",
ipRequests: zeroIPRequests,
wantErr: authenticatedGRPCIPRateLimitRequestsEnvVar + " must be positive",
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
restoreEnvs(
t,
sessionCacheRedisAddrEnvVar,
authenticatedGRPCIPRateLimitRequestsEnvVar,
authenticatedGRPCIPRateLimitWindowEnvVar,
authenticatedGRPCIPRateLimitBurstEnvVar,
authenticatedGRPCSessionRateLimitRequestsEnvVar,
authenticatedGRPCSessionRateLimitWindowEnvVar,
authenticatedGRPCSessionRateLimitBurstEnvVar,
authenticatedGRPCUserRateLimitRequestsEnvVar,
authenticatedGRPCUserRateLimitWindowEnvVar,
authenticatedGRPCUserRateLimitBurstEnvVar,
authenticatedGRPCMessageClassRateLimitRequestsEnvVar,
authenticatedGRPCMessageClassRateLimitWindowEnvVar,
authenticatedGRPCMessageClassRateLimitBurstEnvVar,
sessionEventsRedisStreamEnvVar,
clientEventsRedisStreamEnvVar,
responseSignerPrivateKeyPEMPathEnvVar,
)
setEnvValue(t, sessionCacheRedisAddrEnvVar, customSessionCacheRedisAddr)
setEnvValue(t, sessionEventsRedisStreamEnvVar, customSessionEventsRedisStream)
setEnvValue(t, clientEventsRedisStreamEnvVar, customClientEventsRedisStream)
setEnvValue(t, responseSignerPrivateKeyPEMPathEnvVar, customResponseSignerPrivateKeyPEMPath)
setEnvValue(t, authenticatedGRPCIPRateLimitRequestsEnvVar, tt.ipRequests)
setEnvValue(t, authenticatedGRPCIPRateLimitWindowEnvVar, tt.ipWindow)
setEnvValue(t, authenticatedGRPCIPRateLimitBurstEnvVar, tt.ipBurst)
setEnvValue(t, authenticatedGRPCSessionRateLimitRequestsEnvVar, tt.sessionRequests)
setEnvValue(t, authenticatedGRPCSessionRateLimitWindowEnvVar, tt.sessionWindow)
setEnvValue(t, authenticatedGRPCSessionRateLimitBurstEnvVar, tt.sessionBurst)
setEnvValue(t, authenticatedGRPCUserRateLimitRequestsEnvVar, tt.userRequests)
setEnvValue(t, authenticatedGRPCUserRateLimitWindowEnvVar, tt.userWindow)
setEnvValue(t, authenticatedGRPCUserRateLimitBurstEnvVar, tt.userBurst)
setEnvValue(t, authenticatedGRPCMessageClassRateLimitRequestsEnvVar, tt.messageClassRequests)
setEnvValue(t, authenticatedGRPCMessageClassRateLimitWindowEnvVar, tt.messageClassWindow)
setEnvValue(t, authenticatedGRPCMessageClassRateLimitBurstEnvVar, tt.messageClassBurst)
cfg, err := LoadFromEnv()
if tt.wantErr != "" {
require.Error(t, err)
require.ErrorContains(t, err, tt.wantErr)
return
}
require.NoError(t, err)
assert.Equal(t, tt.want, cfg.AuthenticatedGRPC.AntiAbuse)
})
}
}
func TestLoadFromEnvSessionCacheRedis(t *testing.T) {
customResponseSignerPrivateKeyPEMPath := new(string)
*customResponseSignerPrivateKeyPEMPath = writeTestResponseSignerPEMFile(t)
customSessionEventsRedisStream := new(string)
*customSessionEventsRedisStream = "gateway:session_events"
customClientEventsRedisStream := new(string)
*customClientEventsRedisStream = "gateway:client_events"
customRedisAddr := new(string)
*customRedisAddr = "127.0.0.1:6380"
customRedisUsername := new(string)
*customRedisUsername = "gateway"
customRedisPassword := new(string)
*customRedisPassword = "secret"
customRedisDB := new(string)
*customRedisDB = "7"
customRedisKeyPrefix := new(string)
*customRedisKeyPrefix = "edge:session:"
customRedisLookupTimeout := new(string)
*customRedisLookupTimeout = "750ms"
customRedisTLSEnabled := new(string)
*customRedisTLSEnabled = "true"
negativeRedisDB := new(string)
*negativeRedisDB = "-1"
invalidRedisLookupTimeout := new(string)
*invalidRedisLookupTimeout = "later"
invalidRedisTLSEnabled := new(string)
*invalidRedisTLSEnabled = "maybe"
tests := []struct {
name string
envs map[string]*string
want SessionCacheRedisConfig
wantErr string
}{
{
name: "custom redis config",
envs: map[string]*string{
sessionCacheRedisAddrEnvVar: customRedisAddr,
sessionCacheRedisUsernameEnvVar: customRedisUsername,
sessionCacheRedisPasswordEnvVar: customRedisPassword,
sessionCacheRedisDBEnvVar: customRedisDB,
sessionCacheRedisKeyPrefixEnvVar: customRedisKeyPrefix,
sessionCacheRedisLookupTimeoutEnvVar: customRedisLookupTimeout,
sessionCacheRedisTLSEnabledEnvVar: customRedisTLSEnabled,
},
want: SessionCacheRedisConfig{
Addr: "127.0.0.1:6380",
Username: "gateway",
Password: "secret",
DB: 7,
KeyPrefix: "edge:session:",
LookupTimeout: 750 * time.Millisecond,
TLSEnabled: true,
},
},
{
name: "negative redis db",
envs: map[string]*string{
sessionCacheRedisAddrEnvVar: customRedisAddr,
sessionCacheRedisDBEnvVar: negativeRedisDB,
},
wantErr: sessionCacheRedisDBEnvVar + " must not be negative",
},
{
name: "invalid redis lookup timeout",
envs: map[string]*string{
sessionCacheRedisAddrEnvVar: customRedisAddr,
sessionCacheRedisLookupTimeoutEnvVar: invalidRedisLookupTimeout,
},
wantErr: "parse " + sessionCacheRedisLookupTimeoutEnvVar,
},
{
name: "invalid redis tls flag",
envs: map[string]*string{
sessionCacheRedisAddrEnvVar: customRedisAddr,
sessionCacheRedisTLSEnabledEnvVar: invalidRedisTLSEnabled,
},
wantErr: "parse " + sessionCacheRedisTLSEnabledEnvVar,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
restoreEnvs(t, append(append(append(sessionCacheRedisEnvVars(), sessionEventsRedisEnvVars()...), clientEventsRedisEnvVars()...), responseSignerPrivateKeyPEMPathEnvVar)...)
setEnvValue(t, responseSignerPrivateKeyPEMPathEnvVar, customResponseSignerPrivateKeyPEMPath)
setEnvValue(t, sessionEventsRedisStreamEnvVar, customSessionEventsRedisStream)
setEnvValue(t, clientEventsRedisStreamEnvVar, customClientEventsRedisStream)
for envVar, value := range tt.envs {
setEnvValue(t, envVar, value)
}
cfg, err := LoadFromEnv()
if tt.wantErr != "" {
require.Error(t, err)
require.ErrorContains(t, err, tt.wantErr)
return
}
require.NoError(t, err)
assert.Equal(t, tt.want, cfg.SessionCacheRedis)
})
}
}
func TestLoadFromEnvReplayRedis(t *testing.T) {
customSessionCacheRedisAddr := new(string)
*customSessionCacheRedisAddr = "127.0.0.1:6380"
customSessionEventsRedisStream := new(string)
*customSessionEventsRedisStream = "gateway:session_events"
customClientEventsRedisStream := new(string)
*customClientEventsRedisStream = "gateway:client_events"
customResponseSignerPrivateKeyPEMPath := new(string)
*customResponseSignerPrivateKeyPEMPath = writeTestResponseSignerPEMFile(t)
customReplayRedisKeyPrefix := new(string)
*customReplayRedisKeyPrefix = "edge:replay:"
customReplayRedisReserveTimeout := new(string)
*customReplayRedisReserveTimeout = "500ms"
emptyReplayRedisKeyPrefix := new(string)
*emptyReplayRedisKeyPrefix = ""
invalidReplayRedisReserveTimeout := new(string)
*invalidReplayRedisReserveTimeout = "later"
tests := []struct {
name string
envs map[string]*string
want ReplayRedisConfig
wantErr string
}{
{
name: "custom replay redis config",
envs: map[string]*string{
sessionCacheRedisAddrEnvVar: customSessionCacheRedisAddr,
replayRedisKeyPrefixEnvVar: customReplayRedisKeyPrefix,
replayRedisReserveTimeoutEnvVar: customReplayRedisReserveTimeout,
},
want: ReplayRedisConfig{
KeyPrefix: "edge:replay:",
ReserveTimeout: 500 * time.Millisecond,
},
},
{
name: "empty replay redis key prefix",
envs: map[string]*string{
sessionCacheRedisAddrEnvVar: customSessionCacheRedisAddr,
replayRedisKeyPrefixEnvVar: emptyReplayRedisKeyPrefix,
},
wantErr: replayRedisKeyPrefixEnvVar + " must not be empty",
},
{
name: "invalid replay redis reserve timeout",
envs: map[string]*string{
sessionCacheRedisAddrEnvVar: customSessionCacheRedisAddr,
replayRedisReserveTimeoutEnvVar: invalidReplayRedisReserveTimeout,
},
wantErr: "parse " + replayRedisReserveTimeoutEnvVar,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
restoreEnvs(t, append(append(append(append(sessionCacheRedisEnvVars(), replayRedisEnvVars()...), sessionEventsRedisEnvVars()...), clientEventsRedisEnvVars()...), responseSignerPrivateKeyPEMPathEnvVar)...)
setEnvValue(t, responseSignerPrivateKeyPEMPathEnvVar, customResponseSignerPrivateKeyPEMPath)
setEnvValue(t, sessionEventsRedisStreamEnvVar, customSessionEventsRedisStream)
setEnvValue(t, clientEventsRedisStreamEnvVar, customClientEventsRedisStream)
for envVar, value := range tt.envs {
setEnvValue(t, envVar, value)
}
cfg, err := LoadFromEnv()
if tt.wantErr != "" {
require.Error(t, err)
require.ErrorContains(t, err, tt.wantErr)
return
}
require.NoError(t, err)
assert.Equal(t, tt.want, cfg.ReplayRedis)
})
}
}
func TestLoadFromEnvSessionEventsRedis(t *testing.T) {
customSessionCacheRedisAddr := new(string)
*customSessionCacheRedisAddr = "127.0.0.1:6380"
customResponseSignerPrivateKeyPEMPath := new(string)
*customResponseSignerPrivateKeyPEMPath = writeTestResponseSignerPEMFile(t)
customClientEventsRedisStream := new(string)
*customClientEventsRedisStream = "gateway:client_events"
customStream := new(string)
*customStream = "edge:session_events"
customReadBlockTimeout := new(string)
*customReadBlockTimeout = "1500ms"
emptyStream := new(string)
*emptyStream = ""
invalidReadBlockTimeout := new(string)
*invalidReadBlockTimeout = "later"
tests := []struct {
name string
envs map[string]*string
want SessionEventsRedisConfig
wantErr string
}{
{
name: "custom session events redis config",
envs: map[string]*string{
sessionCacheRedisAddrEnvVar: customSessionCacheRedisAddr,
sessionEventsRedisStreamEnvVar: customStream,
sessionEventsRedisReadBlockTimeoutEnvVar: customReadBlockTimeout,
},
want: SessionEventsRedisConfig{
Stream: "edge:session_events",
ReadBlockTimeout: 1500 * time.Millisecond,
},
},
{
name: "missing session events redis stream",
envs: map[string]*string{
sessionCacheRedisAddrEnvVar: customSessionCacheRedisAddr,
},
wantErr: sessionEventsRedisStreamEnvVar + " must not be empty",
},
{
name: "empty session events redis stream",
envs: map[string]*string{
sessionCacheRedisAddrEnvVar: customSessionCacheRedisAddr,
sessionEventsRedisStreamEnvVar: emptyStream,
},
wantErr: sessionEventsRedisStreamEnvVar + " must not be empty",
},
{
name: "invalid session events read block timeout",
envs: map[string]*string{
sessionCacheRedisAddrEnvVar: customSessionCacheRedisAddr,
sessionEventsRedisStreamEnvVar: customStream,
sessionEventsRedisReadBlockTimeoutEnvVar: invalidReadBlockTimeout,
},
wantErr: "parse " + sessionEventsRedisReadBlockTimeoutEnvVar,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
restoreEnvs(t, append(append(append(sessionCacheRedisEnvVars(), sessionEventsRedisEnvVars()...), clientEventsRedisEnvVars()...), responseSignerPrivateKeyPEMPathEnvVar)...)
setEnvValue(t, responseSignerPrivateKeyPEMPathEnvVar, customResponseSignerPrivateKeyPEMPath)
setEnvValue(t, clientEventsRedisStreamEnvVar, customClientEventsRedisStream)
for envVar, value := range tt.envs {
setEnvValue(t, envVar, value)
}
cfg, err := LoadFromEnv()
if tt.wantErr != "" {
require.Error(t, err)
require.ErrorContains(t, err, tt.wantErr)
return
}
require.NoError(t, err)
assert.Equal(t, tt.want, cfg.SessionEventsRedis)
})
}
}
func TestLoadFromEnvClientEventsRedis(t *testing.T) {
customSessionCacheRedisAddr := new(string)
*customSessionCacheRedisAddr = "127.0.0.1:6380"
customResponseSignerPrivateKeyPEMPath := new(string)
*customResponseSignerPrivateKeyPEMPath = writeTestResponseSignerPEMFile(t)
customSessionEventsRedisStream := new(string)
*customSessionEventsRedisStream = "gateway:session_events"
customStream := new(string)
*customStream = "edge:client_events"
customReadBlockTimeout := new(string)
*customReadBlockTimeout = "1500ms"
emptyStream := new(string)
*emptyStream = ""
invalidReadBlockTimeout := new(string)
*invalidReadBlockTimeout = "later"
tests := []struct {
name string
envs map[string]*string
want ClientEventsRedisConfig
wantErr string
}{
{
name: "custom client events redis config",
envs: map[string]*string{
sessionCacheRedisAddrEnvVar: customSessionCacheRedisAddr,
clientEventsRedisStreamEnvVar: customStream,
clientEventsRedisReadBlockTimeoutEnvVar: customReadBlockTimeout,
},
want: ClientEventsRedisConfig{
Stream: "edge:client_events",
ReadBlockTimeout: 1500 * time.Millisecond,
},
},
{
name: "missing client events redis stream",
envs: map[string]*string{
sessionCacheRedisAddrEnvVar: customSessionCacheRedisAddr,
},
wantErr: clientEventsRedisStreamEnvVar + " must not be empty",
},
{
name: "empty client events redis stream",
envs: map[string]*string{
sessionCacheRedisAddrEnvVar: customSessionCacheRedisAddr,
clientEventsRedisStreamEnvVar: emptyStream,
},
wantErr: clientEventsRedisStreamEnvVar + " must not be empty",
},
{
name: "invalid client events read block timeout",
envs: map[string]*string{
sessionCacheRedisAddrEnvVar: customSessionCacheRedisAddr,
clientEventsRedisStreamEnvVar: customStream,
clientEventsRedisReadBlockTimeoutEnvVar: invalidReadBlockTimeout,
},
wantErr: "parse " + clientEventsRedisReadBlockTimeoutEnvVar,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
restoreEnvs(t, append(append(append(sessionCacheRedisEnvVars(), sessionEventsRedisEnvVars()...), clientEventsRedisEnvVars()...), responseSignerPrivateKeyPEMPathEnvVar)...)
setEnvValue(t, responseSignerPrivateKeyPEMPathEnvVar, customResponseSignerPrivateKeyPEMPath)
setEnvValue(t, sessionEventsRedisStreamEnvVar, customSessionEventsRedisStream)
for envVar, value := range tt.envs {
setEnvValue(t, envVar, value)
}
cfg, err := LoadFromEnv()
if tt.wantErr != "" {
require.Error(t, err)
require.ErrorContains(t, err, tt.wantErr)
return
}
require.NoError(t, err)
assert.Equal(t, tt.want, cfg.ClientEventsRedis)
})
}
}
func TestLoadFromEnvPublicHTTPAntiAbuse(t *testing.T) {
requiredSessionCacheRedisAddr := new(string)
*requiredSessionCacheRedisAddr = "127.0.0.1:6379"
requiredSessionEventsRedisStream := new(string)
*requiredSessionEventsRedisStream = "gateway:session_events"
requiredClientEventsRedisStream := new(string)
*requiredClientEventsRedisStream = "gateway:client_events"
requiredResponseSignerPrivateKeyPEMPath := new(string)
*requiredResponseSignerPrivateKeyPEMPath = writeTestResponseSignerPEMFile(t)
customPublicAuthMaxBodyBytes := new(string)
*customPublicAuthMaxBodyBytes = "4096"
customBrowserAssetRequests := new(string)
*customBrowserAssetRequests = "150"
customBrowserAssetWindow := new(string)
*customBrowserAssetWindow = "2m"
customConfirmBurst := new(string)
*customConfirmBurst = "3"
negativePublicAuthMaxBodyBytes := new(string)
*negativePublicAuthMaxBodyBytes = "-1"
zeroPublicMiscRequests := new(string)
*zeroPublicMiscRequests = "0"
invalidSendIdentityWindow := new(string)
*invalidSendIdentityWindow = "later"
tests := []struct {
name string
envs map[string]*string
want PublicHTTPAntiAbuseConfig
wantErr string
}{
{
name: "custom anti abuse config",
envs: map[string]*string{
publicAuthMaxBodyBytesEnvVar: customPublicAuthMaxBodyBytes,
browserAssetRateLimitRequestsEnvVar: customBrowserAssetRequests,
browserAssetRateLimitWindowEnvVar: customBrowserAssetWindow,
confirmEmailCodeIdentityRateLimitBurstEnvVar: customConfirmBurst,
},
want: func() PublicHTTPAntiAbuseConfig {
cfg := DefaultPublicHTTPConfig().AntiAbuse
cfg.PublicAuth.MaxBodyBytes = 4096
cfg.BrowserAsset.RateLimit.Requests = 150
cfg.BrowserAsset.RateLimit.Window = 2 * time.Minute
cfg.ConfirmEmailCodeIdentity.RateLimit.Burst = 3
return cfg
}(),
},
{
name: "negative public auth max body bytes",
envs: map[string]*string{
publicAuthMaxBodyBytesEnvVar: negativePublicAuthMaxBodyBytes,
},
wantErr: publicAuthMaxBodyBytesEnvVar + " must not be negative",
},
{
name: "zero public misc requests",
envs: map[string]*string{
publicMiscRateLimitRequestsEnvVar: zeroPublicMiscRequests,
},
wantErr: publicMiscRateLimitRequestsEnvVar + " must be positive",
},
{
name: "invalid send identity window",
envs: map[string]*string{
sendEmailCodeIdentityRateLimitWindowEnvVar: invalidSendIdentityWindow,
},
wantErr: "parse " + sendEmailCodeIdentityRateLimitWindowEnvVar,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
restoreEnvs(t, append(append(append(append(publicAntiAbuseEnvVars(), sessionCacheRedisAddrEnvVar), sessionEventsRedisEnvVars()...), clientEventsRedisEnvVars()...), responseSignerPrivateKeyPEMPathEnvVar)...)
setEnvValue(t, sessionCacheRedisAddrEnvVar, requiredSessionCacheRedisAddr)
setEnvValue(t, sessionEventsRedisStreamEnvVar, requiredSessionEventsRedisStream)
setEnvValue(t, clientEventsRedisStreamEnvVar, requiredClientEventsRedisStream)
setEnvValue(t, responseSignerPrivateKeyPEMPathEnvVar, requiredResponseSignerPrivateKeyPEMPath)
for envVar, value := range tt.envs {
setEnvValue(t, envVar, value)
}
cfg, err := LoadFromEnv()
if tt.wantErr != "" {
require.Error(t, err)
require.ErrorContains(t, err, tt.wantErr)
return
}
require.NoError(t, err)
assert.Equal(t, tt.want, cfg.PublicHTTP.AntiAbuse)
})
}
}
// restoreEnv resets envVar after the test mutates process-wide environment
// state.
func restoreEnv(t *testing.T, envVar string) {
t.Helper()
previousValue, hadPreviousValue := os.LookupEnv(envVar)
t.Cleanup(func() {
var err error
if hadPreviousValue {
err = os.Setenv(envVar, previousValue)
} else {
err = os.Unsetenv(envVar)
}
require.NoError(t, err)
})
}
// setEnvValue updates envVar to value or unsets it when value is nil.
func setEnvValue(t *testing.T, envVar string, value *string) {
t.Helper()
var err error
if value == nil {
err = os.Unsetenv(envVar)
} else {
err = os.Setenv(envVar, *value)
}
require.NoError(t, err)
}
func restoreEnvs(t *testing.T, envVars ...string) {
t.Helper()
for _, envVar := range envVars {
restoreEnv(t, envVar)
}
}
func publicAntiAbuseEnvVars() []string {
return []string{
publicAuthMaxBodyBytesEnvVar,
publicAuthRateLimitRequestsEnvVar,
publicAuthRateLimitWindowEnvVar,
publicAuthRateLimitBurstEnvVar,
browserBootstrapMaxBodyBytesEnvVar,
browserBootstrapRateLimitRequestsEnvVar,
browserBootstrapRateLimitWindowEnvVar,
browserBootstrapRateLimitBurstEnvVar,
browserAssetMaxBodyBytesEnvVar,
browserAssetRateLimitRequestsEnvVar,
browserAssetRateLimitWindowEnvVar,
browserAssetRateLimitBurstEnvVar,
publicMiscMaxBodyBytesEnvVar,
publicMiscRateLimitRequestsEnvVar,
publicMiscRateLimitWindowEnvVar,
publicMiscRateLimitBurstEnvVar,
sendEmailCodeIdentityRateLimitRequestsEnvVar,
sendEmailCodeIdentityRateLimitWindowEnvVar,
sendEmailCodeIdentityRateLimitBurstEnvVar,
confirmEmailCodeIdentityRateLimitRequestsEnvVar,
confirmEmailCodeIdentityRateLimitWindowEnvVar,
confirmEmailCodeIdentityRateLimitBurstEnvVar,
}
}
func operationalEnvVars() []string {
return []string{
logLevelEnvVar,
publicHTTPAddrEnvVar,
publicHTTPReadHeaderTimeoutEnvVar,
publicHTTPReadTimeoutEnvVar,
publicHTTPIdleTimeoutEnvVar,
publicAuthUpstreamTimeoutEnvVar,
authServiceBaseURLEnvVar,
adminHTTPAddrEnvVar,
adminHTTPReadHeaderTimeoutEnvVar,
adminHTTPReadTimeoutEnvVar,
adminHTTPIdleTimeoutEnvVar,
authenticatedGRPCAddrEnvVar,
authenticatedGRPCConnectionTimeoutEnvVar,
authenticatedGRPCDownstreamTimeoutEnvVar,
authenticatedGRPCFreshnessWindowEnvVar,
}
}
func sessionCacheRedisEnvVars() []string {
return []string{
sessionCacheRedisAddrEnvVar,
sessionCacheRedisUsernameEnvVar,
sessionCacheRedisPasswordEnvVar,
sessionCacheRedisDBEnvVar,
sessionCacheRedisKeyPrefixEnvVar,
sessionCacheRedisLookupTimeoutEnvVar,
sessionCacheRedisTLSEnabledEnvVar,
}
}
func replayRedisEnvVars() []string {
return []string{
replayRedisKeyPrefixEnvVar,
replayRedisReserveTimeoutEnvVar,
}
}
func sessionEventsRedisEnvVars() []string {
return []string{
sessionEventsRedisStreamEnvVar,
sessionEventsRedisReadBlockTimeoutEnvVar,
}
}
func clientEventsRedisEnvVars() []string {
return []string{
clientEventsRedisStreamEnvVar,
clientEventsRedisReadBlockTimeoutEnvVar,
}
}
func writeTestResponseSignerPEMFile(t *testing.T) string {
t.Helper()
seed := sha256.Sum256([]byte("gateway-config-test-response-signer"))
privateKey := ed25519.NewKeyFromSeed(seed[:])
encodedPrivateKey, err := x509.MarshalPKCS8PrivateKey(privateKey)
require.NoError(t, err)
path := filepath.Join(t.TempDir(), "response-signer.pem")
err = os.WriteFile(path, pem.EncodeToMemory(&pem.Block{
Type: "PRIVATE KEY",
Bytes: encodedPrivateKey,
}), 0o600)
require.NoError(t, err)
return path
}