mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 20:01:09 +02:00
Critical security and correctness fixes for the sync server: Security: - Fix WebSocket JWT validation — was completely broken (hardcoded "pending-auth"). Now validates JWT via JWKS, rejects invalid tokens, enforces 10-second auth deadline, sends auth-ok confirmation. - Add 10 MB request body size limit (prevents OOM attacks) - Validate op field (must be insert/update/delete) - Validate table and id fields (must be non-empty) - Abort sync on RecordChange failure (was silently continuing) Correctness: - Fix silent JSON unmarshal errors in store (now returns error) - Copy client set before iterating in NotifyUser (prevents race) - Add write timeout on WebSocket notifications Testing (19 tests, 0 -> 100% for unit-testable code): - auth: token extraction, validator init, missing auth handling - config: defaults, env override, invalid port - sync: op validation, changeset validation, response format, field change round-trip, body size constant Documentation: - Add CLAUDE.md with architecture, sync protocol, LWW explanation, API endpoints, configuration, security notes Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
69 lines
1.6 KiB
Go
69 lines
1.6 KiB
Go
package config
|
|
|
|
import (
|
|
"os"
|
|
"testing"
|
|
)
|
|
|
|
func TestLoadDefaults(t *testing.T) {
|
|
// Clear env vars to test defaults
|
|
os.Unsetenv("PORT")
|
|
os.Unsetenv("DATABASE_URL")
|
|
os.Unsetenv("JWKS_URL")
|
|
os.Unsetenv("CORS_ORIGINS")
|
|
|
|
cfg := Load()
|
|
|
|
if cfg.Port != 3050 {
|
|
t.Errorf("Port = %d, want 3050", cfg.Port)
|
|
}
|
|
if cfg.DatabaseURL == "" {
|
|
t.Error("DatabaseURL should not be empty")
|
|
}
|
|
if cfg.JWKSUrl == "" {
|
|
t.Error("JWKSUrl should not be empty")
|
|
}
|
|
if cfg.CORSOrigins == "" {
|
|
t.Error("CORSOrigins should not be empty")
|
|
}
|
|
}
|
|
|
|
func TestLoadFromEnv(t *testing.T) {
|
|
os.Setenv("PORT", "8080")
|
|
os.Setenv("DATABASE_URL", "postgresql://test:test@db:5432/test")
|
|
os.Setenv("JWKS_URL", "https://auth.example.com/jwks")
|
|
os.Setenv("CORS_ORIGINS", "https://app.example.com")
|
|
defer func() {
|
|
os.Unsetenv("PORT")
|
|
os.Unsetenv("DATABASE_URL")
|
|
os.Unsetenv("JWKS_URL")
|
|
os.Unsetenv("CORS_ORIGINS")
|
|
}()
|
|
|
|
cfg := Load()
|
|
|
|
if cfg.Port != 8080 {
|
|
t.Errorf("Port = %d, want 8080", cfg.Port)
|
|
}
|
|
if cfg.DatabaseURL != "postgresql://test:test@db:5432/test" {
|
|
t.Errorf("DatabaseURL = %q, want postgresql://test:test@db:5432/test", cfg.DatabaseURL)
|
|
}
|
|
if cfg.JWKSUrl != "https://auth.example.com/jwks" {
|
|
t.Errorf("JWKSUrl = %q, want https://auth.example.com/jwks", cfg.JWKSUrl)
|
|
}
|
|
if cfg.CORSOrigins != "https://app.example.com" {
|
|
t.Errorf("CORSOrigins = %q, want https://app.example.com", cfg.CORSOrigins)
|
|
}
|
|
}
|
|
|
|
func TestLoadInvalidPort(t *testing.T) {
|
|
os.Setenv("PORT", "not-a-number")
|
|
defer os.Unsetenv("PORT")
|
|
|
|
cfg := Load()
|
|
|
|
// Invalid port should fall back to 0 (strconv.Atoi error)
|
|
if cfg.Port != 0 {
|
|
t.Errorf("Port = %d, want 0 for invalid input", cfg.Port)
|
|
}
|
|
}
|