Heavy security and file splitting
CI / Go Tests (push) Successful in 15s
CI / Build (push) Successful in 9s
Format / gofmt (push) Successful in 7s
Release Artifacts / Validate release tag (push) Successful in 2s
Release Artifacts / Build and release executables (push) Successful in 15s
Release Artifacts / Build and release Docker image (push) Successful in 28s

This commit is contained in:
2026-06-01 20:15:28 -05:00
parent bdbe1a9416
commit ad4355df17
27 changed files with 1540 additions and 1166 deletions
+6 -2
View File
@@ -111,14 +111,18 @@ func (w *rollingFileWriter) rotateLocked() error {
}
return fmt.Errorf("stat rotated file %s: %w", from, err)
}
_ = os.Remove(to)
if err := os.Remove(to); err != nil && !os.IsNotExist(err) {
return fmt.Errorf("remove target backup slot %s: %w", to, err)
}
if err := os.Rename(from, to); err != nil {
return fmt.Errorf("rotate backup %s -> %s: %w", from, to, err)
}
}
firstBackup := rotatedLogPath(w.path, 1)
_ = os.Remove(firstBackup)
if err := os.Remove(firstBackup); err != nil && !os.IsNotExist(err) {
return fmt.Errorf("remove first backup %s: %w", firstBackup, err)
}
if _, err := os.Stat(w.path); err == nil {
if err := os.Rename(w.path, firstBackup); err != nil {
return fmt.Errorf("rotate current log to %s: %w", firstBackup, err)
+13
View File
@@ -347,6 +347,16 @@ func TestGenerateConfigCommandWritesDefaultYAML(t *testing.T) {
if !cfg.Security.RateLimitAPIWrite.Enabled {
t.Fatalf("security.rate_limit_api_write.enabled = %v, want true", cfg.Security.RateLimitAPIWrite.Enabled)
}
// Additional assertions act as golden checks against generate drift in defaults/comments/struct.
if cfg.Storage.CleanupInterval != "1m" {
t.Fatalf("storage.cleanup_interval = %q, want %q", cfg.Storage.CleanupInterval, "1m")
}
if !cfg.Security.HSTSEnabled {
t.Fatalf("security.hsts_enabled = %v, want true", cfg.Security.HSTSEnabled)
}
if cfg.Limits.RawCacheMaxEntries != 32 {
t.Fatalf("limits.raw_cache_max_entries = %d, want 32", cfg.Limits.RawCacheMaxEntries)
}
}
func TestGenerateConfigCommandRejectsUnexpectedArgs(t *testing.T) {
@@ -437,6 +447,9 @@ security:
if err != nil {
t.Fatalf("config.Load() error = %v", err)
}
if err := cfg.PrepareDataDir(); err != nil {
t.Fatalf("config.PrepareDataDir() error = %v", err)
}
logger := log.New(io.Discard, "", 0)
store, err := storage.NewFilesystemStore(cfg.Storage.DataDir, cfg.Storage.EncryptionKeyBytes)
if err != nil {
+16 -3
View File
@@ -12,7 +12,6 @@ import (
"sort"
"strings"
"syscall"
"time"
"github.com/spf13/cobra"
@@ -66,6 +65,12 @@ func run(configPath string, useEnv bool) error {
return fmt.Errorf("config load failed: %w", err)
}
// Prepare data dir + key (side effects) after pure Validate inside Load*/Default.
// This addresses the layering issue where Validate used to mutate FS.
if err := cfg.PrepareDataDir(); err != nil {
return fmt.Errorf("prepare storage data dir failed: %w", err)
}
logger := log.New(os.Stdout, "[scratchbox] ", log.LstdFlags|log.LUTC)
accessWriter, closeAccessWriter, err := newAccessLogWriter(cfg)
if err != nil {
@@ -114,7 +119,7 @@ func run(configPath string, useEnv bool) error {
go func() {
<-ctx.Done()
shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 10*time.Second)
shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), cfg.Server.ShutdownTimeoutDur)
defer shutdownCancel()
if err := httpServer.Shutdown(shutdownCtx); err != nil {
logger.Printf("http shutdown failed: %v", err)
@@ -143,7 +148,15 @@ func printEnvStartup() int {
return 0
}
for _, item := range entries {
fmt.Fprintf(os.Stdout, "[scratchbox] %s\n", item)
printItem := item
// Redact values for IP list config (security sensitive for allowlist/rate/proxy spoof surface).
// Rates and other are left as-is (numeric, not secret).
if strings.Contains(item, "ALLOWED_IPS=") || strings.Contains(item, "TRUSTED_PROXY_IPS=") {
if eq := strings.IndexByte(item, '='); eq >= 0 {
printItem = item[:eq+1] + "*** (redacted)"
}
}
fmt.Fprintf(os.Stdout, "[scratchbox] %s\n", printItem)
}
return len(entries)
}