From 5d99fc2f2d2e53ef096b6b3b4a906ce084bfabd8 Mon Sep 17 00:00:00 2001 From: rcourtman Date: Tue, 11 Nov 2025 00:11:41 +0000 Subject: [PATCH] Fix dark mode toggle wiping API tokens (related to #685) Root cause: SaveSystemSettings calls updateEnvFile which rewrites .env on any setting change, triggering the config watcher. The watcher sees API_TOKEN in .env and replaces all UI-created tokens with "Environment token" records, wiping out host-agent scoped tokens. Fix: updateEnvFile now compares the new content with existing content and skips the write if nothing changed. Since dark mode (and other UI settings) are stored in system.json, not .env, toggling theme no longer triggers unnecessary .env rewrites. This prevents the config watcher from being triggered unnecessarily and preserves UI-created API tokens when changing cosmetic settings. Future improvement: Deprecate API_TOKEN/API_TOKENS from .env entirely and make api_tokens.json the single source of truth (requires migration logic). --- internal/config/persistence.go | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/internal/config/persistence.go b/internal/config/persistence.go index 5328122..1080803 100644 --- a/internal/config/persistence.go +++ b/internal/config/persistence.go @@ -1342,6 +1342,12 @@ func (c *ConfigPersistence) updateEnvFile(envFile string, settings SystemSetting return nil } + // Read the existing .env file content + existingContent, err := os.ReadFile(envFile) + if err != nil { + return err + } + // Read the existing .env file file, err := os.Open(envFile) if err != nil { @@ -1377,12 +1383,20 @@ func (c *ConfigPersistence) updateEnvFile(envFile string, settings SystemSetting // Note: POLLING_INTERVAL is deprecated and no longer written - // Write the updated content back atomically + // Build the new content content := strings.Join(lines, "\n") if len(lines) > 0 && !strings.HasSuffix(content, "\n") { content += "\n" } + // Only write if content actually changed + // This prevents unnecessary .env rewrites that trigger the config watcher, + // which can cause API tokens to be overwritten (related to #685) + if string(existingContent) == content { + log.Debug().Str("file", envFile).Msg("Skipping .env update - content unchanged") + return nil + } + // Write to temp file first tempFile := envFile + ".tmp" if err := os.WriteFile(tempFile, []byte(content), 0644); err != nil {