fix(backend): harden final MVP invariants

This commit is contained in:
2026-07-22 01:24:41 +08:00
parent 251b212e06
commit 78d4845688
26 changed files with 977 additions and 175 deletions

View File

@@ -1,6 +1,7 @@
package config
import (
"fmt"
"os"
"path/filepath"
"strings"
@@ -45,5 +46,52 @@ func LoadFromDir(configDir string) (Config, error) {
if cfg.MaxUploadBytes <= 0 {
cfg.MaxUploadBytes = 32 << 20
}
if strings.TrimSpace(cfg.StorageDir) == "" {
return Config{}, fmt.Errorf("storage_dir must not be empty")
}
hasAllowedOrigin := false
for _, origin := range cfg.AllowedOrigins {
if strings.TrimSpace(origin) != "" {
hasAllowedOrigin = true
break
}
}
if !hasAllowedOrigin {
return Config{}, fmt.Errorf("allowed_origins must include at least one origin")
}
if err := validateSecret(cfg.Env, "auth_secret", cfg.AuthSecret); err != nil {
return Config{}, err
}
if err := validateSecret(cfg.Env, "ai_key_encryption_secret", cfg.AIKeyEncryptionSecret); err != nil {
return Config{}, err
}
return cfg, nil
}
func validateSecret(environment, field, value string) error {
secret := strings.TrimSpace(value)
if secret == "" {
return fmt.Errorf("%s must not be empty", field)
}
if strings.EqualFold(strings.TrimSpace(environment), "production") || strings.EqualFold(strings.TrimSpace(environment), "prod") {
if len(secret) < 32 || isCommonSecret(secret) {
return fmt.Errorf("%s must be at least 32 characters and must not use a development sentinel in production", field)
}
}
return nil
}
func isCommonSecret(value string) bool {
normalized := strings.ToLower(strings.TrimSpace(value))
for _, marker := range []string{"change-me", "changeme", "development", "dev-secret", "local-secret", "test-secret", "placeholder"} {
if strings.Contains(normalized, marker) {
return true
}
}
switch normalized {
case "secret", "password", "default", "admin":
return true
default:
return false
}
}