chore: capture post-P0/P1 state for clean P2 start (working tree was dirty at task begin)

This commit is contained in:
2026-05-27 00:53:49 -05:00
parent 9cb38a9a18
commit 0c1840d223
17 changed files with 1500 additions and 170 deletions
+44 -2
View File
@@ -2,8 +2,11 @@ package config
import (
"fmt"
"net"
"os"
"strings"
"github.com/docker/go-units"
"gopkg.in/yaml.v3"
)
@@ -15,6 +18,10 @@ type Config struct {
MaxConcurrentRequests int64 `yaml:"max_concurrent_requests" default:"200"`
MaxRequestsPerClient int64 `yaml:"max_requests_per_client" default:"5"`
// P1 hardening limits (security/correctness)
MaxObjectSize string `yaml:"max_object_size" default:"0"` // 0=unlimited; e.g. "256MB" protects against OOM from huge/malicious upstream responses (P1-01)
TrustedProxies []string `yaml:"trusted_proxies"` // CIDR list; empty=never trust X-Forwarded-For (safe default, P1-02). See README security notes.
// Cache configuration
Cache CacheConfig `yaml:"cache"`
@@ -75,6 +82,12 @@ func LoadConfig(configPath string) (*Config, error) {
if config.MaxRequestsPerClient == 0 {
config.MaxRequestsPerClient = 3
}
if config.MaxObjectSize == "" {
config.MaxObjectSize = "0"
}
if config.TrustedProxies == nil {
config.TrustedProxies = []string{}
}
if config.Cache.Memory.Size == "" {
config.Cache.Memory.Size = "0"
}
@@ -99,8 +112,10 @@ func SaveDefaultConfig(configPath string) error {
defaultConfig := Config{
ListenAddress: ":80",
MaxConcurrentRequests: 50, // Reduced for home user (less concurrent load)
MaxRequestsPerClient: 3, // Reduced for home user (more conservative per client)
MaxConcurrentRequests: 50, // Reduced for home user (less concurrent load)
MaxRequestsPerClient: 3, // Reduced for home user (more conservative per client)
MaxObjectSize: "0", // 0=unlimited; set e.g. "512MB" for DoS protection on large bodies (P1-01)
TrustedProxies: []string{}, // Conservative default: never trust XFF (P1-02 spoof prevention)
Cache: CacheConfig{
Memory: MemoryConfig{
Size: "1GB", // Recommended for systems that can spare 1GB RAM for caching
@@ -133,6 +148,8 @@ func GetDefaultConfig() Config {
ListenAddress: ":80",
MaxConcurrentRequests: 50,
MaxRequestsPerClient: 3,
MaxObjectSize: "0", // 0=unlimited (override for bounded response safety)
TrustedProxies: []string{}, // safe default: do not trust forwarded headers
Cache: CacheConfig{
Memory: MemoryConfig{
Size: "1GB",
@@ -169,5 +186,30 @@ func (c Config) Validate() error {
return fmt.Errorf("disk cache enabled but no path specified")
}
// P1 light validation for security/resource fields (mirrors existing GC + path checks; fails fast before New)
if c.MaxObjectSize != "" && c.MaxObjectSize != "0" {
if _, err := units.FromHumanSize(c.MaxObjectSize); err != nil {
return fmt.Errorf("invalid max_object_size: %w", err)
}
}
for _, p := range c.TrustedProxies {
p = strings.TrimSpace(p)
if p == "" {
continue
}
if !strings.Contains(p, "/") {
if net.ParseIP(p) == nil {
return fmt.Errorf("invalid trusted_proxies entry (not IP or CIDR): %s", p)
}
continue
}
if _, _, err := net.ParseCIDR(p); err != nil {
return fmt.Errorf("invalid trusted_proxies CIDR: %s", p)
}
}
if c.MaxConcurrentRequests < 0 || c.MaxRequestsPerClient < 0 { // already covered above but explicit for P1 knobs
// covered by earlier checks
}
return nil
}