mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-24 04:33:17 +00:00
Merge commit 'ad15366f3dc02480ede74dce80a074c190e83d3c'
Change-source: pulse-maintainer
This commit is contained in:
@@ -216,6 +216,7 @@ Pulse is secure by default. On first launch, you must retrieve a **Bootstrap Tok
|
||||
| Platform | Command |
|
||||
|----------|---------|
|
||||
| **Docker** | `docker exec pulse /app/pulse bootstrap-token` |
|
||||
| **Docker app UIs** (Unraid, Portainer, TrueNAS apps) | Open the Pulse container's console and run `/app/pulse bootstrap-token` |
|
||||
| **Kubernetes** | `kubectl exec -it <pod> -- /app/pulse bootstrap-token` |
|
||||
| **Systemd** | `sudo pulse bootstrap-token` |
|
||||
| **Proxmox LXC** | `pct exec <ctid> -- /usr/local/bin/pulse bootstrap-token` (run on the Proxmox host; the installer prints this command with your container ID at the end of the install) |
|
||||
|
||||
@@ -2057,6 +2057,11 @@ plaintext secret file on disk. Canonical runtime persistence must keep the
|
||||
token encrypted at rest, and any legacy plaintext bootstrap-token file must be
|
||||
treated only as migration input that is rewritten immediately into the
|
||||
encrypted canonical format on load.
|
||||
Operator guidance for recovering that token, in the startup log and on the
|
||||
first-run unlock screen, must name the supported command and never the token
|
||||
file, because the file holds ciphertext. The unlock screen lists the host,
|
||||
`docker exec`, in-container console (`/app/pulse bootstrap-token`) and
|
||||
`pct exec` forms without revealing the server's deployment details.
|
||||
Managed first-session proof may reset that boundary only through the dev-only
|
||||
`/api/security/dev/reset-first-run` route under authenticated
|
||||
`settings:write`; harnesses may not scrape `.env`, delete persisted token
|
||||
|
||||
@@ -1,28 +1,43 @@
|
||||
{
|
||||
"version": 1,
|
||||
"base_sha": "6d7e3342e56a4f8f2b411acb3df8dc7777d4ec7f",
|
||||
"verified_at": "2026-09-27T23:52:13Z",
|
||||
"base_sha": "75c72ef505b24e31214162b7b46f97e357528ae3",
|
||||
"verified_at": "2026-09-28T14:14:00Z",
|
||||
"result": "passed",
|
||||
"changed_paths": ["frontend-modern/src/api/settings.ts"],
|
||||
"changed_paths": [
|
||||
"frontend-modern/src/components/SetupWizard/steps/WelcomeStep.tsx",
|
||||
"frontend-modern/src/i18n/messages.de.ts",
|
||||
"frontend-modern/src/i18n/messages.es.ts",
|
||||
"frontend-modern/src/i18n/messages.ts"
|
||||
],
|
||||
"content_sha256": {
|
||||
"frontend-modern/src/api/settings.ts": "4172b94c268be6a0ea000e73d155e540f11776e1c59325250e13716722be5aeb"
|
||||
"frontend-modern/src/components/SetupWizard/steps/WelcomeStep.tsx": "cb25935ec49782592c1602ae1502f5becc94108d61c3a786bbd65654d757e540",
|
||||
"frontend-modern/src/i18n/messages.de.ts": "ca6bd4a42cac62c3bdec6ef25c35b5ec78b886d0455c6eab0ae8f154c0fd3361",
|
||||
"frontend-modern/src/i18n/messages.es.ts": "5b3867658b39164afdece84e7a1eb28195b18d810d9ca9f5ed6761a54e274dcd",
|
||||
"frontend-modern/src/i18n/messages.ts": "9e0bd2b4addcf984e499499460fee59f705d684cffb4fba1d7da0361cfbbdd31"
|
||||
},
|
||||
"routes": ["/tmp/telemetry-schema-2285.html"],
|
||||
"routes": [
|
||||
"/ (first-run unlock screen, fresh container)"
|
||||
],
|
||||
"viewports": [
|
||||
{"width": 1280, "height": 800},
|
||||
{"width": 390, "height": 844}
|
||||
{
|
||||
"width": 1280,
|
||||
"height": 800
|
||||
},
|
||||
{
|
||||
"width": 390,
|
||||
"height": 844
|
||||
}
|
||||
],
|
||||
"states": [
|
||||
"Production GeneralSettingsPanel mounted in an isolated Vite fixture with a synthetic schema-v18 telemetry-preview API response",
|
||||
"Preview payload displayed stable-channel skipped, metadata_error, and available outcomes with corresponding false, false, and true update_available booleans",
|
||||
"The payload block stayed inside the card; the metadata_error JSON scrolled within the block at 390px without page-level horizontal overflow",
|
||||
"Desktop and phone screenshots for all three outcomes were inspected for placement, clipping and scrolling"
|
||||
"Fresh rcourtman/pulse:latest (v6.4.1) container in first-run state, serving this branch's vite build via PULSE_FRONTEND_DIR, reached through an SSH tunnel to localhost",
|
||||
"Unlock setup lists four rows: direct host, Docker deployment, the new Container console (Unraid, Portainer, TrueNAS apps) row with /app/pulse bootstrap-token, and LXC",
|
||||
"At 390px the new label wraps to two lines and the command truncates like the existing rows, with no page-level horizontal overflow (scrollWidth 390)",
|
||||
"At 1280px all four commands render in full with no overflow"
|
||||
],
|
||||
"interactions": [
|
||||
"Clicked Preview payload and then Refresh payload twice per viewport, replacing the synthetic API outcome on each request",
|
||||
"Parsed the rendered payload JSON and asserted schema_version, update_channel, update_check_outcome and update_available",
|
||||
"Checked page and preview scroll widths at both viewports and checked for uncaught page errors"
|
||||
"Clicked the copy button on the Container console row and saw the Command copied to clipboard toast and the check icon",
|
||||
"Ran /app/pulse bootstrap-token from a shell inside the container as root and as the pulse user and confirmed it printed the token"
|
||||
],
|
||||
"command": "pulse-worker-browser tmp/browser-proof/telemetry-schema-2285.cjs (Playwright 1.56.1, Chromium 141.0.7390.37)",
|
||||
"notes": "Offline production-component fixture with synthetic API data, not a full application login, installed sender, receiver or release acceptance. The browser result and six screenshots are retained under tmp/browser-proof in this assigned workspace."
|
||||
"command": "Claude desktop browser pane against a pulse-dev probe container",
|
||||
"notes": "Backend was the published v6.4.1 image, not a build of this branch. The frontend is this branch. Telemetry was disabled on the probe containers."
|
||||
}
|
||||
|
||||
@@ -216,6 +216,7 @@ Pulse is secure by default. On first launch, you must retrieve a **Bootstrap Tok
|
||||
| Platform | Command |
|
||||
|----------|---------|
|
||||
| **Docker** | `docker exec pulse /app/pulse bootstrap-token` |
|
||||
| **Docker app UIs** (Unraid, Portainer, TrueNAS apps) | Open the Pulse container's console and run `/app/pulse bootstrap-token` |
|
||||
| **Kubernetes** | `kubectl exec -it <pod> -- /app/pulse bootstrap-token` |
|
||||
| **Systemd** | `sudo pulse bootstrap-token` |
|
||||
| **Proxmox LXC** | `pct exec <ctid> -- /usr/local/bin/pulse bootstrap-token` (run on the Proxmox host; the installer prints this command with your container ID at the end of the install) |
|
||||
|
||||
@@ -117,6 +117,10 @@ describe('WelcomeStep', () => {
|
||||
expect(
|
||||
screen.getByText('docker exec <pulse-container> /app/pulse bootstrap-token'),
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText('Container console (Unraid, Portainer, TrueNAS apps)'),
|
||||
).toBeInTheDocument();
|
||||
expect(screen.getByText('/app/pulse bootstrap-token')).toBeInTheDocument();
|
||||
// Absolute path, because pct exec runs with
|
||||
// PATH=/sbin:/bin:/usr/sbin:/usr/bin and cannot resolve /usr/local/bin.
|
||||
expect(
|
||||
|
||||
@@ -37,6 +37,13 @@ export const WelcomeStep: Component<WelcomeStepProps> = (props) => {
|
||||
label: t('setup.welcome.deploymentLabel.docker'),
|
||||
command: 'docker exec <pulse-container> /app/pulse bootstrap-token',
|
||||
},
|
||||
{
|
||||
// Unraid, Portainer and TrueNAS open a shell inside the container
|
||||
// itself, so the docker exec prefix above does not apply there.
|
||||
id: 'container-console',
|
||||
label: t('setup.welcome.deploymentLabel.containerConsole'),
|
||||
command: '/app/pulse bootstrap-token',
|
||||
},
|
||||
{
|
||||
id: 'lxc',
|
||||
label: t('setup.welcome.deploymentLabel.lxc'),
|
||||
|
||||
@@ -317,6 +317,8 @@ export const DE_MESSAGE_OVERRIDES = {
|
||||
'Pulse scheint in Docker zu laufen. Fuehren Sie den Befehl auf dem Docker-Host aus und ersetzen Sie <pulse-container> durch den Namen des laufenden Pulse-Containers.',
|
||||
'setup.welcome.deploymentHint.lxc':
|
||||
'Pulse scheint in LXC-Container {ctid} zu laufen. Fuehren Sie den Befehl auf dem Proxmox-Host aus, um in diesen Container zu wechseln und das einmalige Setup-Token auszugeben.',
|
||||
'setup.welcome.deploymentLabel.containerConsole':
|
||||
'Container-Konsole (Unraid, Portainer, TrueNAS-Apps)',
|
||||
'setup.welcome.deploymentLabel.containerized': 'Containerisierte Bereitstellung',
|
||||
'setup.welcome.deploymentLabel.direct': 'Direkte Host-Installation',
|
||||
'setup.welcome.deploymentLabel.docker': 'Docker-Bereitstellung',
|
||||
|
||||
@@ -309,6 +309,8 @@ export const ES_MESSAGE_OVERRIDES = {
|
||||
'Pulse parece ejecutarse en Docker. Ejecuta el comando en el host Docker y reemplaza <pulse-container> por el nombre del contenedor Pulse en ejecución.',
|
||||
'setup.welcome.deploymentHint.lxc':
|
||||
'Pulse parece ejecutarse en el contenedor LXC {ctid}. Ejecuta el comando en el host Proxmox para entrar en ese contenedor e imprimir el token de configuración de un solo uso.',
|
||||
'setup.welcome.deploymentLabel.containerConsole':
|
||||
'Consola del contenedor (Unraid, Portainer, apps de TrueNAS)',
|
||||
'setup.welcome.deploymentLabel.containerized': 'Despliegue contenedorizado',
|
||||
'setup.welcome.deploymentLabel.direct': 'Instalación directa en host',
|
||||
'setup.welcome.deploymentLabel.docker': 'Despliegue Docker',
|
||||
|
||||
@@ -301,6 +301,8 @@ export const EN_MESSAGES = {
|
||||
'Pulse appears to be running in Docker. Run the command on the Docker host and replace <pulse-container> with the running Pulse container name.',
|
||||
'setup.welcome.deploymentHint.lxc':
|
||||
'Pulse appears to be running in LXC container {ctid}. Run the command on the Proxmox host to execute into that container and print the one-time setup token.',
|
||||
'setup.welcome.deploymentLabel.containerConsole':
|
||||
'Container console (Unraid, Portainer, TrueNAS apps)',
|
||||
'setup.welcome.deploymentLabel.containerized': 'Containerized deployment',
|
||||
'setup.welcome.deploymentLabel.direct': 'Direct host install',
|
||||
'setup.welcome.deploymentLabel.docker': 'Docker deployment',
|
||||
@@ -694,6 +696,7 @@ export const FIRST_SESSION_MONITORING_MIGRATED_MESSAGE_KEYS = [
|
||||
'setup.welcome.deploymentHint.dockerNamed',
|
||||
'setup.welcome.deploymentHint.dockerUnnamed',
|
||||
'setup.welcome.deploymentHint.lxc',
|
||||
'setup.welcome.deploymentLabel.containerConsole',
|
||||
'setup.welcome.deploymentLabel.containerized',
|
||||
'setup.welcome.deploymentLabel.direct',
|
||||
'setup.welcome.deploymentLabel.docker',
|
||||
|
||||
@@ -62,7 +62,7 @@ func (r *Router) initializeBootstrapToken() {
|
||||
if created {
|
||||
logger.Warn().
|
||||
Str("token_path", path).
|
||||
Msg("Bootstrap setup token created on disk; reveal it locally with `pulse bootstrap-token` or by reading the token file path")
|
||||
Msg("Bootstrap setup token created; the file is encrypted, so reveal the token with `pulse bootstrap-token` (Docker: `docker exec <container> /app/pulse bootstrap-token`, or `/app/pulse bootstrap-token` from the container console)")
|
||||
} else {
|
||||
logger.Info().
|
||||
Str("token_path", path).
|
||||
|
||||
Reference in New Issue
Block a user