diff --git a/README.md b/README.md index 0b8ecdeada..4444dab784 100644 --- a/README.md +++ b/README.md @@ -111,11 +111,16 @@ The GitHub installer installs the Pulse server. Install and upgrade agents ### Do you need an agent? Often not. Proxmox VE, PBS, and PMG are monitored through the Proxmox API -with a read-only token, so nothing runs on the host and the generated setup +with a read-only token, so no Pulse host agent is required. The generated setup script creates a privilege-separated monitoring user. Install the unified agent only where you want data the platform API cannot provide, such as host SMART health, temperatures, Docker hosts, or standalone machines. +**API-only does not mean guest-agent-free.** VM filesystem and memory requests through QEMU Guest Agent can share the channel used by freeze-enabled backups. +Read-only permissions do not prove backup safety. Do not add permissions, enable or restart an agent, or send manual guest-agent probes during a backup, freeze or thaw. +Use the existing [backup safety precaution](docs/VM_DISK_MONITORING.md#backup-safety). Stopping Pulse also stops its monitoring and alerts. +An OK backup task does not prove successful thaw. + The agent is operator-controlled by design. Command execution is off by default, the local listener binds to localhost, and generated systemd units ship hardened. On Linux, the installer's `--least-privilege` profile runs the diff --git a/docs/INSTALL.md b/docs/INSTALL.md index 872dd58ec1..8f9da3c3ac 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -275,6 +275,15 @@ The Proxmox path must be absolute. `pct exec` runs with `PATH=/sbin:/bin:/usr/sb ZFS/Ceph/mdadm detail, or other telemetry that requires local host access. See [Agent Security](AGENT_SECURITY.md). +**API-only does not mean guest-agent-free.** VM filesystem and memory requests +through QEMU Guest Agent can share the channel used by freeze-enabled backups. +Read-only permissions do not prove backup safety. Do not add permissions, +enable or restart an agent, or send manual guest-agent probes during a backup, +freeze or thaw. Use the existing +[backup safety precaution](VM_DISK_MONITORING.md#backup-safety). Stopping Pulse +also stops its monitoring and alerts. An OK backup task does not prove +successful thaw. + > **Note**: If you configure authentication via environment variables (`PULSE_AUTH_USER`/`PULSE_AUTH_PASS`), the bootstrap token is automatically removed and this step is skipped. --- diff --git a/frontend-modern/public/docs/INSTALL.md b/frontend-modern/public/docs/INSTALL.md index 872dd58ec1..8f9da3c3ac 100644 --- a/frontend-modern/public/docs/INSTALL.md +++ b/frontend-modern/public/docs/INSTALL.md @@ -275,6 +275,15 @@ The Proxmox path must be absolute. `pct exec` runs with `PATH=/sbin:/bin:/usr/sb ZFS/Ceph/mdadm detail, or other telemetry that requires local host access. See [Agent Security](AGENT_SECURITY.md). +**API-only does not mean guest-agent-free.** VM filesystem and memory requests +through QEMU Guest Agent can share the channel used by freeze-enabled backups. +Read-only permissions do not prove backup safety. Do not add permissions, +enable or restart an agent, or send manual guest-agent probes during a backup, +freeze or thaw. Use the existing +[backup safety precaution](VM_DISK_MONITORING.md#backup-safety). Stopping Pulse +also stops its monitoring and alerts. An OK backup task does not prove +successful thaw. + > **Note**: If you configure authentication via environment variables (`PULSE_AUTH_USER`/`PULSE_AUTH_PASS`), the bootstrap token is automatically removed and this step is skipped. --- diff --git a/frontend-modern/src/utils/__tests__/onboardingBackupSafety.test.ts b/frontend-modern/src/utils/__tests__/onboardingBackupSafety.test.ts new file mode 100644 index 0000000000..426a28bc41 --- /dev/null +++ b/frontend-modern/src/utils/__tests__/onboardingBackupSafety.test.ts @@ -0,0 +1,69 @@ +import { readFileSync } from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { describe, expect, it } from 'vitest'; +import { renderDocMarkdown } from '@/features/docs/docMarkdown'; + +const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../../..'); +const read = (name: string) => readFileSync(path.join(root, name), 'utf8'); + +function render(markdown: string, name: string): HTMLElement { + const article = document.createElement('article'); + article.innerHTML = renderDocMarkdown(markdown, name); + return article; +} + +const entries = [ + { + name: 'README', + source: 'README.md', + start: '### Do you need an agent?', + end: '\n> [!IMPORTANT]', + }, + { + name: 'INSTALL', + source: 'docs/INSTALL.md', + start: '### Step 2: Create Admin Account', + end: '\n> **Note**: If you configure authentication', + }, +]; + +describe.each(entries)('$name API-only onboarding safety', ({ name, source, start, end }) => { + const section = () => read(source).split(start)[1]?.split(end)[0] ?? ''; + const article = () => render(section(), name); + const text = () => article().textContent?.replace(/\s+/g, ' '); + + it('distinguishes absence of a Pulse host agent from active QEMU guest-agent reads', () => { + expect(section()).not.toBe(''); + expect(text()).toContain('API-only does not mean guest-agent-free'); + expect(text()).toContain('VM filesystem and memory requests through QEMU Guest Agent'); + expect(text()).toContain('channel used by freeze-enabled backups'); + expect(text()).toContain('Read-only permissions do not prove backup safety'); + expect(text()).not.toContain('nothing runs on the host'); + if (name === 'README') expect(text()).toContain('no Pulse host agent is required'); + }); + + it('does not prescribe probes or agent changes during a backup and explains the outage', () => { + expect(text()).toContain( + 'Do not add permissions, enable or restart an agent, or send manual guest-agent probes during a backup, freeze or thaw', + ); + expect(text()).toContain('Stopping Pulse also stops its monitoring and alerts'); + expect(text()).toContain('OK backup task does not prove successful thaw'); + expect(article().querySelector('pre')).toBeNull(); + }); + + it('resolves the existing full recovery precaution from the onboarding section', () => { + const link = article().querySelector('a[href="/docs/VM_DISK_MONITORING#backup-safety"]'); + expect(link?.textContent).toBe('backup safety precaution'); + const target = render(read('docs/VM_DISK_MONITORING.md'), 'VM_DISK_MONITORING'); + expect(target.querySelector('#backup-safety')).not.toBeNull(); + const targetText = target.textContent?.replace(/\s+/g, ' '); + expect(targetText).toContain('every filesystem covered by the backup'); + expect(targetText).toContain('workload liveness'); + expect(targetText).toContain('only if it was active beforehand'); + }); +}); + +it('ships the tested installation guidance without a divergent mirror', () => { + expect(read('frontend-modern/public/docs/INSTALL.md')).toBe(read('docs/INSTALL.md')); +});