From df185985eb5a55e9e73ea69abd902d527f994068 Mon Sep 17 00:00:00 2001 From: rcourtman Date: Sun, 9 Nov 2025 23:41:55 +0000 Subject: [PATCH] Fix bootstrap token path display for Docker deployments (related to #680) The first-run setup UI was displaying incorrect bootstrap token paths for Docker deployments. It showed `/etc/pulse/.bootstrap_token` regardless of deployment type, but Docker containers use `/data/.bootstrap_token` by default (via PULSE_DATA_DIR env var). Changes: - Extended `/api/security/status` endpoint to include `bootstrapTokenPath` and `isDocker` fields when a bootstrap token is active - Updated FirstRunSetup component to fetch and display the correct path dynamically based on actual deployment configuration - For Docker deployments, UI now shows both `docker exec` command and in-container command - Falls back to showing both standard and Docker paths if API data unavailable (backward compatibility) This fix ensures users always see the correct command for their specific deployment, including custom PULSE_DATA_DIR configurations. --- .../src/components/FirstRunSetup.tsx | 48 +++++++++++++++---- internal/api/router.go | 6 +++ 2 files changed, 45 insertions(+), 9 deletions(-) diff --git a/frontend-modern/src/components/FirstRunSetup.tsx b/frontend-modern/src/components/FirstRunSetup.tsx index a991e62..c5726ed 100644 --- a/frontend-modern/src/components/FirstRunSetup.tsx +++ b/frontend-modern/src/components/FirstRunSetup.tsx @@ -25,6 +25,8 @@ export const FirstRunSetup: Component<{ force?: boolean; showLegacyBanner?: bool const [bootstrapToken, setBootstrapToken] = createSignal(''); const [isUnlocking, setIsUnlocking] = createSignal(false); const [isUnlocked, setIsUnlocked] = createSignal(false); + const [bootstrapTokenPath, setBootstrapTokenPath] = createSignal(''); + const [isDocker, setIsDocker] = createSignal(false); const applyTheme = (mode: 'system' | 'light' | 'dark') => { if (mode === 'light') { @@ -44,7 +46,7 @@ export const FirstRunSetup: Component<{ force?: boolean; showLegacyBanner?: bool } }; - onMount(() => { + onMount(async () => { // Check for saved theme preference const savedTheme = localStorage.getItem(STORAGE_KEYS.DARK_MODE); if (savedTheme === 'false') { @@ -62,6 +64,20 @@ export const FirstRunSetup: Component<{ force?: boolean; showLegacyBanner?: bool document.documentElement.classList.remove('dark'); } } + + // Fetch bootstrap token path from API + try { + const response = await fetch('/api/security/status'); + if (response.ok) { + const data = await response.json(); + if (data.bootstrapTokenPath) { + setBootstrapTokenPath(data.bootstrapTokenPath); + setIsDocker(data.isDocker || false); + } + } + } catch (error) { + console.error('Failed to fetch bootstrap token path:', error); + } }); const generatePassword = () => { @@ -287,16 +303,30 @@ IMPORTANT: Keep these credentials secure!

To begin setup, retrieve the bootstrap token from your Pulse host:

-
+ +
+
# Standard installation:
+ cat /etc/pulse/.bootstrap_token +
+
+
# Docker/Helm:
+ cat /data/.bootstrap_token +
+
+ } + >
-
# Standard installation:
- cat /etc/pulse/.bootstrap_token + +
# From Docker host:
+ docker exec pulse cat {bootstrapTokenPath()} +
# Or from inside container:
+
+ cat {bootstrapTokenPath()}
-
-
# Docker/Helm:
- cat /data/.bootstrap_token -
- + {/* Token Input */} diff --git a/internal/api/router.go b/internal/api/router.go index f4a4ba5..8a9d2a3 100644 --- a/internal/api/router.go +++ b/internal/api/router.go @@ -467,6 +467,12 @@ func (r *Router) setupRoutes() { } } + // Add bootstrap token location for first-run setup UI + if r.bootstrapTokenHash != "" { + status["bootstrapTokenPath"] = r.bootstrapTokenPath + status["isDocker"] = os.Getenv("PULSE_DOCKER") == "true" + } + if r.config.DisableAuthEnvDetected { status["deprecatedDisableAuth"] = true status["message"] = "DISABLE_AUTH is deprecated and no longer disables authentication. Remove the environment variable and restart Pulse to manage authentication from the UI."