From e77ed0cdef7ec4496e74b24660baa932075280e0 Mon Sep 17 00:00:00 2001 From: LordMathis Date: Fri, 14 Nov 2025 20:25:40 +0100 Subject: [PATCH] Deep copy config for sanitization --- pkg/config/config.go | 25 +++++++++++++++++++++---- pkg/server/handlers_system.go | 7 +++++-- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/pkg/config/config.go b/pkg/config/config.go index c8ac108..b03af99 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -1,6 +1,7 @@ package config import ( + "encoding/json" "fmt" "log" "os" @@ -612,18 +613,34 @@ func getDefaultConfigLocations() []string { } // SanitizedCopy returns a copy of the AppConfig with sensitive information removed -func (cfg *AppConfig) SanitizedCopy() AppConfig { - // Create a copy of the config - sanitized := *cfg +func (cfg *AppConfig) SanitizedCopy() (AppConfig, error) { + // Deep copy via JSON marshal/unmarshal to avoid concurrent map access + data, err := json.Marshal(cfg) + if err != nil { + log.Printf("Failed to marshal config for sanitization: %v", err) + return AppConfig{}, err + } + + var sanitized AppConfig + if err := json.Unmarshal(data, &sanitized); err != nil { + log.Printf("Failed to unmarshal config for sanitization: %v", err) + return AppConfig{}, err + } // Clear sensitive information sanitized.Auth.InferenceKeys = []string{} sanitized.Auth.ManagementKeys = []string{} + // Clear API keys from nodes for nodeName, node := range sanitized.Nodes { node.APIKey = "" sanitized.Nodes[nodeName] = node } - return sanitized + // Preserve non-serialized fields + sanitized.Version = cfg.Version + sanitized.CommitHash = cfg.CommitHash + sanitized.BuildTime = cfg.BuildTime + + return sanitized, nil } diff --git a/pkg/server/handlers_system.go b/pkg/server/handlers_system.go index c53947c..0af346c 100644 --- a/pkg/server/handlers_system.go +++ b/pkg/server/handlers_system.go @@ -32,8 +32,11 @@ func (h *Handler) VersionHandler() http.HandlerFunc { // @Router /api/v1/config [get] func (h *Handler) ConfigHandler() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - // Return a sanitized copy of the configuration - sanitizedConfig := h.cfg.SanitizedCopy() + sanitizedConfig, err := h.cfg.SanitizedCopy() + if err != nil { + writeError(w, http.StatusInternalServerError, "sanitized_copy_error", "Failed to get sanitized config") + return + } writeJSON(w, http.StatusOK, sanitizedConfig) } }