Make API-only onboarding explicit about backup safety

The README said nothing runs on the host and first-time setup recommended API-only collection without the guest-agent caveat. Bring the existing QEMU backup-channel precaution to those entry points, name the monitoring and alert outage, and preserve the detailed recovery route. Rendered regressions verify the warning and real target anchor; no collector, permission or service-control change is made.

Contract-Neutral: Onboarding prose and rendered regression tests expose an existing backup precaution; guest collection, permissions, installer and service-control contracts are unchanged.
Change-source: pulse-maintainer
This commit is contained in:
pulse-triage[bot]
2026-10-06 08:51:54 +01:00
parent 4736dbda9c
commit 71cb18f45a
4 changed files with 93 additions and 1 deletions
+6 -1
View File
@@ -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
+9
View File
@@ -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.
---
+9
View File
@@ -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.
---
@@ -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'));
});