Phase 1: Control Service skeleton (Go, SQLite, session login, Docker, Caddy)
- Go service with its own multi-stage Dockerfile and docker-compose.yml; runs as container webrestrict-control on port 8791. - SQLite schema for the full AGENTS.md §7 data model via versioned migrations (PRAGMA user_version); audit log is append-only. - Configuration from the process environment; the real env file is gitignored and a template is committed. No secrets in the repo. - Separate session login (signed HMAC cookie + CSRF) for Sam. - GET /health; HTMX + server-rendered dashboard styled with the Family Home Lab tokens.css (copied) and Inter fonts; dark mode; phone-friendly. - Caddy vhost for webrestrict.lab.audasmedia.com.au applied on .35 (Let's Encrypt cert issued); route recorded in deploy/caddy/webrestrict.caddy. - Unit tests for config, auth and store. Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
52
internal/config/config_test.go
Normal file
52
internal/config/config_test.go
Normal file
@@ -0,0 +1,52 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestLoadDefaultsAndValidation(t *testing.T) {
|
||||
t.Setenv("CONTROL_SESSION_SECRET", "0123456789abcdef")
|
||||
t.Setenv("CONTROL_ADMIN_PASSWORD", "hunter2")
|
||||
t.Setenv("CONTROL_ADDR", "")
|
||||
t.Setenv("CONTROL_DB_PATH", "")
|
||||
|
||||
cfg, err := Load()
|
||||
if err != nil {
|
||||
t.Fatalf("Load: %v", err)
|
||||
}
|
||||
if cfg.Addr != ":8791" {
|
||||
t.Errorf("Addr = %q, want :8791", cfg.Addr)
|
||||
}
|
||||
if cfg.DBPath != "/data/control.db" {
|
||||
t.Errorf("DBPath = %q, want /data/control.db", cfg.DBPath)
|
||||
}
|
||||
if cfg.AdminUsername != "sam" {
|
||||
t.Errorf("AdminUsername = %q, want sam", cfg.AdminUsername)
|
||||
}
|
||||
if cfg.SessionTTL != 12*time.Hour {
|
||||
t.Errorf("SessionTTL = %v, want 12h", cfg.SessionTTL)
|
||||
}
|
||||
if cfg.LogLevel != slog.LevelInfo {
|
||||
t.Errorf("LogLevel = %v, want info", cfg.LogLevel)
|
||||
}
|
||||
if !cfg.CookieSecure {
|
||||
t.Error("CookieSecure = false, want true by default")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadRequiresSecretAndPassword(t *testing.T) {
|
||||
t.Setenv("CONTROL_SESSION_SECRET", "")
|
||||
t.Setenv("CONTROL_ADMIN_PASSWORD", "hunter2")
|
||||
if _, err := Load(); err == nil {
|
||||
t.Error("expected error when session secret is missing")
|
||||
}
|
||||
|
||||
t.Setenv("CONTROL_SESSION_SECRET", "0123456789abcdef")
|
||||
t.Setenv("CONTROL_ADMIN_PASSWORD", "")
|
||||
t.Setenv("CONTROL_ADMIN_PASSWORD_HASH", "")
|
||||
if _, err := Load(); err == nil {
|
||||
t.Error("expected error when no admin password is set")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user