check / check (push) Canceled after 0s
Every answer carries the six security headers REPO_POLICIES.md lists. The Content-Security-Policy allows inline content only with a nonce made for that answer; the pages put it on their style and script blocks and drop their four style attributes. The request log and /ip/ take a forwarded address only from a proxy listed in TRUSTED_PROXIES, which stops the start when set but invalid: the last X-Forwarded-For entry that is not a trusted proxy. X-Real-IP and True-Client-IP are no longer read. The JSON routes and the health check send fixed messages in place of database, parser and resolver errors, and log the detail. Model: opus-5-5
119 lines
2.5 KiB
Go
119 lines
2.5 KiB
Go
package config
|
|
|
|
import (
|
|
"net/netip"
|
|
"runtime"
|
|
"slices"
|
|
"testing"
|
|
)
|
|
|
|
func TestNewReadsPort(t *testing.T) {
|
|
tests := map[string]int{
|
|
"": defaultPort,
|
|
"1": 1,
|
|
"9090": 9090,
|
|
"65535": 65535,
|
|
}
|
|
|
|
for value, want := range tests {
|
|
t.Run(value, func(t *testing.T) {
|
|
t.Setenv("PORT", value)
|
|
t.Setenv("XDG_DATA_HOME", "")
|
|
|
|
cfg, err := New()
|
|
if err != nil {
|
|
t.Fatalf("New() with PORT=%q: %v", value, err)
|
|
}
|
|
|
|
if cfg.Port != want {
|
|
t.Errorf("New() with PORT=%q: Port = %d, want %d", value, cfg.Port, want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNewRefusesInvalidPort(t *testing.T) {
|
|
for _, value := range []string{"0", "65536", "-1", "+9090", "http", "80.5"} {
|
|
t.Run(value, func(t *testing.T) {
|
|
t.Setenv("PORT", value)
|
|
t.Setenv("XDG_DATA_HOME", "")
|
|
|
|
_, err := New()
|
|
if err == nil {
|
|
t.Errorf("New() with PORT=%q returned no error", value)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNewReadsTrustedProxies(t *testing.T) {
|
|
t.Setenv("PORT", "")
|
|
t.Setenv("XDG_DATA_HOME", "")
|
|
|
|
t.Setenv("TRUSTED_PROXIES", "")
|
|
|
|
cfg, err := New()
|
|
if err != nil {
|
|
t.Fatalf("New() without TRUSTED_PROXIES: %v", err)
|
|
}
|
|
|
|
if len(cfg.TrustedProxies) != 0 {
|
|
t.Errorf("New() without TRUSTED_PROXIES: TrustedProxies = %v, want none",
|
|
cfg.TrustedProxies)
|
|
}
|
|
|
|
t.Setenv("TRUSTED_PROXIES", "10.0.0.0/8, 192.0.2.1,2001:db8::/32")
|
|
|
|
cfg, err = New()
|
|
if err != nil {
|
|
t.Fatalf("New() with TRUSTED_PROXIES: %v", err)
|
|
}
|
|
|
|
want := []netip.Prefix{
|
|
netip.MustParsePrefix("10.0.0.0/8"),
|
|
netip.MustParsePrefix("192.0.2.1/32"),
|
|
netip.MustParsePrefix("2001:db8::/32"),
|
|
}
|
|
if !slices.Equal(cfg.TrustedProxies, want) {
|
|
t.Errorf("TrustedProxies = %v, want %v", cfg.TrustedProxies, want)
|
|
}
|
|
}
|
|
|
|
func TestNewRefusesInvalidTrustedProxies(t *testing.T) {
|
|
invalid := []string{"proxy.example", "10.0.0.0/33", "192.0.2.1:80", "192.0.2.1,"}
|
|
for _, value := range invalid {
|
|
t.Run(value, func(t *testing.T) {
|
|
t.Setenv("PORT", "")
|
|
t.Setenv("XDG_DATA_HOME", "")
|
|
t.Setenv("TRUSTED_PROXIES", value)
|
|
|
|
_, err := New()
|
|
if err == nil {
|
|
t.Errorf("New() with TRUSTED_PROXIES=%q returned no error", value)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNewRefusesRelativeXDGDataHome(t *testing.T) {
|
|
if runtime.GOOS == "darwin" {
|
|
t.Skip("macOS does not read XDG_DATA_HOME")
|
|
}
|
|
|
|
t.Setenv("PORT", "")
|
|
|
|
t.Setenv("XDG_DATA_HOME", "relative/path")
|
|
|
|
_, err := New()
|
|
if err == nil {
|
|
t.Error("New() with a relative XDG_DATA_HOME returned no error")
|
|
}
|
|
|
|
t.Setenv("XDG_DATA_HOME", "/var/lib")
|
|
|
|
_, err = New()
|
|
if err != nil {
|
|
t.Errorf("New() with XDG_DATA_HOME=/var/lib: %v", err)
|
|
}
|
|
}
|