feat(backend): reject non-positive token TTLs at config load

Every duration in the config is a token TTL (access, refresh, content). A zero
or negative value mints already-expired tokens — no login, no media playback —
and previously loaded silently. parseDuration now rejects <= 0 with a clear
error, so misconfiguration fails fast at startup instead of mysteriously at
runtime. The AuthService itself stays permissive (it's constructed directly in
tests with arbitrary TTLs); config load is the gate.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-15 17:56:25 +03:00
parent 6fba04cd00
commit 9937984a5a
2 changed files with 65 additions and 0 deletions
+57
View File
@@ -0,0 +1,57 @@
package config
import (
"strings"
"testing"
)
// setValidEnv sets every required variable to a valid dummy value, so a test can
// then override one var to exercise a single validation path.
func setValidEnv(t *testing.T) {
t.Helper()
t.Setenv("JWT_SECRET", "test-secret")
t.Setenv("ADMIN_PASSWORD", "test-password")
t.Setenv("DATABASE_URL", "postgres://u:p@localhost:5432/db?sslmode=disable")
t.Setenv("FILES_PATH", "/tmp/files")
t.Setenv("THUMBS_CACHE_PATH", "/tmp/thumbs")
t.Setenv("IMPORT_PATH", "/tmp/import")
// Pin the TTLs to valid values so an ambient env var can't perturb the case
// under test; individual tests override the one they exercise.
t.Setenv("JWT_ACCESS_TTL", "15m")
t.Setenv("JWT_REFRESH_TTL", "720h")
t.Setenv("CONTENT_TOKEN_TTL", "6h")
}
func TestLoadValid(t *testing.T) {
setValidEnv(t)
cfg, err := Load()
if err != nil {
t.Fatalf("Load: %v", err)
}
if cfg.JWTAccessTTL <= 0 || cfg.JWTRefreshTTL <= 0 || cfg.ContentTokenTTL <= 0 {
t.Fatalf("TTLs should be positive: access=%v refresh=%v content=%v",
cfg.JWTAccessTTL, cfg.JWTRefreshTTL, cfg.ContentTokenTTL)
}
}
func TestLoadRejectsNonPositiveTTL(t *testing.T) {
cases := []struct{ key, val string }{
{"JWT_ACCESS_TTL", "0"},
{"JWT_REFRESH_TTL", "-1h"},
{"CONTENT_TOKEN_TTL", "0s"},
}
for _, tc := range cases {
t.Run(tc.key, func(t *testing.T) {
setValidEnv(t)
t.Setenv(tc.key, tc.val)
_, err := Load()
if err == nil {
t.Fatalf("expected error for %s=%q", tc.key, tc.val)
}
if !strings.Contains(err.Error(), tc.key) || !strings.Contains(err.Error(), "must be positive") {
t.Fatalf("error should name %s and mention positivity, got: %v", tc.key, err)
}
})
}
}