Commit Graph

2058 Commits

Author SHA1 Message Date
rcourtman e1b3af7ca0 feat: Agent collects S.M.A.R.T. disk data via smartctl. Related to #907
- Add smartctl package to collect disk temperature and health data
- Add SMART field to agent Sensors struct
- Host agent now runs smartctl to collect disk temps when available
- Backend processes agent SMART data for temperature display
- Graceful fallback when smartctl not installed
2025-12-25 11:37:53 +00:00
rcourtman ea0fafd5c8 fix: Use LinkedNodeID for temperature matching to fix duplicate hostname bug
When two Proxmox nodes have the same hostname (e.g., 'px1' on different IPs),
the getHostAgentTemperature function was matching by hostname alone, causing
both nodes to show temperature from whichever host agent appeared first.

The fix:
- Added getHostAgentTemperatureByID that first tries matching by LinkedNodeID
  (the unique node ID) before falling back to hostname matching
- Updated the caller to pass modelNode.ID for precise matching
- Maintains backwards compatibility for setups where linking hasn't occurred

Related to #891
2025-12-25 10:00:19 +00:00
rcourtman ce962a38c7 fix(#903): Add 2-minute timeout for pending config sync
If an agent doesn't confirm the config change within 2 minutes (e.g., offline),
the sync indicator is cleared and a warning notification is shown. This prevents
the spinner from spinning forever when agents are unreachable.

The toggle returns to showing the agent-reported state after timeout, allowing
users to retry the toggle if needed.
2025-12-25 08:19:43 +00:00
rcourtman f63a4c8ca2 fix(#903): Optimistic toggle with sync indicator for AI commands
The toggle now:
1. Immediately shows the desired state after clicking (optimistic update)
2. Displays a spinning sync icon while waiting for agent confirmation
3. Disables the toggle during sync to prevent double-clicks
4. Reverts to original state if the API call fails
5. Clears sync state once agent reports the expected value

This provides clear visual feedback about the async nature of remote config
without requiring users to understand the underlying polling mechanism.
2025-12-25 08:15:35 +00:00
rcourtman f4c426cbdf fix: Properly close command client WebSocket when disabling remotely
When the server disables command execution for an agent, we now properly
call Close() on the command client to tear down the WebSocket connection.
Previously we just set the pointer to nil which left the goroutine running
with an orphaned connection.
2025-12-25 08:09:42 +00:00
rcourtman a38c071644 feat(#903): Remote agent configuration for AI command execution
This implements full remote configuration for the AI command execution setting:

Backend:
- Add CommandsEnabled field to HostMetadata for persistent storage
- Add GetHostAgentConfig/UpdateHostAgentConfig methods to Monitor
- Add /api/agents/host/{id}/config endpoint (GET for agents, PATCH for UI)
- Server includes config in report response for immediate agent application
- Agent parses response and dynamically enables/disables command client

Frontend:
- Add 'AI Commands' toggle column in Managed Agents table
- Toggle immediately updates server config; agent applies on next heartbeat
- Add 'Enable AI command execution' checkbox in agent installer wizard
- Checkbox adds --enable-commands flag to generated install commands

This allows users to:
1. Enable at install time via checkbox in the wizard
2. Toggle remotely via the Managed Agents UI for existing agents
3. Agents apply changes automatically on their next report cycle
2025-12-25 08:07:28 +00:00
rcourtman ac2b765ca5 feat: Agent reports CommandsEnabled status to server. Related to #903
- Add CommandsEnabled field to AgentInfo in pkg/agents/host/report.go
- Agent now reports whether AI command execution is enabled
- Server stores and exposes this via Host model
- Frontend can now show which agents have commands enabled
- This provides visibility before implementing remote configuration
2025-12-25 07:55:22 +00:00
rcourtman 57d57de28c fix: Node disk column respects Trends view mode. Related to #904
The disk column for Proxmox nodes was always showing bars even when
Trends (sparklines) view mode was selected. Memory column was correctly
checking viewMode() but disk was not.

Added the same Show when={viewMode() === 'sparklines'} conditional
to the disk column rendering in NodeSummaryTable.
2025-12-25 05:08:34 +00:00
rcourtman c6125ae5d7 fix: Allow dismissing AI findings without Pro license. Related to #885
Users who accumulated AI patrol findings before the patrol-without-AI
bug was fixed (24c4bb0b) could not dismiss them because the dismiss and
resolve endpoints required a Pro license.

Changes:
- Remove Pro license requirement from /api/ai/patrol/dismiss endpoint
- Remove Pro license requirement from /api/ai/patrol/resolve endpoint
- Add ClearAll() method to FindingsStore for bulk clearing
- Add DELETE /api/ai/patrol/findings endpoint for clearing all findings
- Add "Clear All" button to AI Insights UI

Users can now dismiss or resolve any findings they can see, and admins
can clear all findings at once if needed.
2025-12-25 05:06:26 +00:00
rcourtman 08e9202b71 fix: Immediately broadcast backup/snapshot updates to frontend
Backup and snapshot polling runs asynchronously and could take 20-45 seconds to complete, but WebSocket broadcasts happened on a separate fixed-interval timer. This caused frontend to show stale data until a broadcast happened to coincide with completed polling - which could take hours.

Now broadcasts state immediately after backup/snapshot polling completes, ensuring users see changes within seconds.

Related to #895
2025-12-25 00:09:07 +00:00
rcourtman bb51e8dfd3 fix: VERSION file should not have v prefix 2025-12-24 23:15:09 +00:00
rcourtman 096f4aa57b fix: Remove agent should delete all types, not just first (#898)
When removing a unified agent that has both host and docker types,
clicking Remove only deleted the first type (host), leaving docker
behind.

Also fix: Host stats now greyed out when offline (#899)

On the Hosts page, CPU/Memory/Disk/Uptime now show a placeholder
dash when the host is offline, matching the Proxmox page behavior.
The entire row is also dimmed for visual consistency.
2025-12-24 22:34:38 +00:00
rcourtman f208cbb905 chore: bump version to v5.0.3 2025-12-24 22:21:03 +00:00
rcourtman 61b69fe2e9 fix: Managed Agents deduplicating by hostname instead of id
When multiple agents share the same hostname (e.g., 'px1'), the Managed
Agents view was showing only the last-added agent because it was using
hostname as the Map key.

Changed keying from hostname to id so that each agent shows separately.
The host+docker type merging now only happens when agents share the same
id (indicating the same physical machine).

Related to #891
2025-12-24 21:28:01 +00:00
rcourtman a1eb9cf118 fix: Group VMs by instance instead of node for duplicate hostname support
When multiple Proxmox instances share the same hostname (e.g., 'px1'),
VMs were incorrectly grouped together under a single heading.

Changed grouping key from guest.node (raw hostname) to guest.instance
(disambiguated name like 'px1 (10.0.2.224)') to properly separate VMs
from different Proxmox instances.

Related to #891
2025-12-24 21:26:11 +00:00
rcourtman 50e2e82a38 fix: Host Agents alert toggle button not working. Fixes #893
The toggleDisabled function was missing hostAgentsWithOverrides() in the
allResources array and 'hostAgent' in the allowed resource types check,
causing the toggle button to silently return without doing anything.
2025-12-24 19:42:41 +00:00
rcourtman c69c5d3152 feat: Add SysV init support for legacy systems. Related to #894
Adds support for systems that use SysV init (like Asustor NAS) that don't have
systemd, OpenRC, or launchd. The installer now:

- Detects /etc/init.d as a fallback when no other init system is found
- Creates an LSB-compliant init script with start/stop/restart/status
- Uses update-rc.d (Debian) or chkconfig (RHEL) to enable on boot
- Falls back to manual rc.d symlink creation if neither tool is available
- Properly cleans up on uninstall
2025-12-24 19:40:23 +00:00
rcourtman 90c6954406 Auto-update Helm chart version to 5.0.2 2025-12-24 18:36:23 +00:00
rcourtman 86815425bc Auto-update Helm chart documentation 2025-12-24 18:36:23 +00:00
rcourtman e2d80e8b6d chore: bump version to 5.0.2 2025-12-24 17:46:47 +00:00
rcourtman 5e59bfe2fc feat: Commands disabled by default, require --enable-commands to opt-in
BREAKING CHANGE: AI command execution on agents is now disabled by default.
Users who want AI auto-fix must explicitly enable it with --enable-commands
flag or PULSE_ENABLE_COMMANDS=true environment variable.

Changes:
- Add --enable-commands flag (opt-in for command execution)
- Commands disabled by default for security (defense-in-depth)
- --disable-commands is now deprecated (logs warning, no longer needed)
- PULSE_DISABLE_COMMANDS deprecated in favor of PULSE_ENABLE_COMMANDS
- Update installer script to use --enable-commands
- Backwards compatibility: PULSE_DISABLE_COMMANDS=false still enables commands

This addresses community feedback about secure defaults for arbitrary
command execution on production infrastructure.

Related to #889
2025-12-24 17:36:44 +00:00
rcourtman dfe31fdf17 feat: add --disable-commands flag to installer script. Related to #889 2025-12-24 17:09:48 +00:00
rcourtman dab442adf3 docs: add backup permissions fix for v4→v5 upgrades
Users upgrading from v4 may have tokens that lack PVEDatastoreAdmin
permission on /storage, causing backups to not appear.

Added section to UPGRADE_v5.md with quick fix command and alternative
approach (re-run agent setup).

Related to #883
2025-12-24 16:33:01 +00:00
rcourtman de448dade6 fix: apply duplicate hostname fix to HandleAddNode (manual UI)
Extended Issue #891 fix to cover manual node addition via the UI:

1. HandleAddNode now checks for duplicates by Host URL (not name)
2. Disambiguator applied to PVE, PBS, and PMG node creation
3. Error message updated: 'host URL already exists' instead of 'name already exists'

This ensures the fix works whether nodes are added via:
- Agent auto-registration ✓
- Manual UI setup ✓

All node creation paths now consistently:
- Match by Host URL only
- Disambiguate duplicate hostnames with IP: 'px1' → 'px1 (10.0.2.224)'
2025-12-24 16:17:37 +00:00
rcourtman 3bef45a8d4 fix: handle DHCP IP changes without creating duplicates
Follow-up to #891 fix - also match by name+tokenID to handle the case
where the same physical host gets a new IP (DHCP). This ensures:

1. Same hostname + DIFFERENT token = different physical hosts → create separate nodes
2. Same hostname + SAME token = same host with new IP → update existing node

Also updates the host URL when an existing node is matched, so IP changes
are properly reflected in the saved configuration.
2025-12-24 16:09:22 +00:00
rcourtman 72c05acd88 fix: allow duplicate hostnames for different Proxmox hosts. Related to #891
PROBLEM:
When two Proxmox hosts have the same hostname (e.g., 'px1' on different networks),
the auto-registration was matching by name and overwriting the first with the second.
This has been a recurring issue (#104) with at least 3 prior fix attempts.

ROOT CAUSE:
The auto-register handler matched existing nodes by BOTH Host URL and Name.
Matching by name is incorrect - different physical hosts can share hostnames.

FIXES:
1. Remove name-based matching in auto-registration - match by Host URL only
2. Add disambiguateNodeName() to append IP when duplicate hostnames exist
3. Add regression tests to prevent this from breaking again

Now when registering two hosts named 'px1':
- First becomes: px1
- Second becomes: px1 (10.0.2.224)
Both are stored as separate nodes with their own credentials.
2025-12-24 16:05:07 +00:00
rcourtman 9343575a67 fix: AI Patrol only runs when AI is enabled. Related to #885
Users who haven't enabled AI were seeing AI patrol findings from
heuristic analysis that they couldn't dismiss (license-gated).

- IsPatrolEnabled() now checks if Enabled is true
- IsAlertTriggeredAnalysisEnabled() also checks Enabled
- Updated tests to reflect new behavior

AI patrol and alert-triggered analysis require AI to be enabled
as a master switch. This prevents confusing UX where users see
AI features without having configured them.
2025-12-24 16:05:07 +00:00
rcourtman 1635d2a395 fix: AI request timeout setting not persisting. Related to #884
Added request_timeout_seconds field to:
- AISettingsResponse struct (for GET responses)
- AISettingsUpdateRequest struct (for PUT requests)
- HandleUpdateAISettings handler logic (validation + persistence)
- HandleGetAISettings response builder

The frontend was already sending request_timeout_seconds but the
backend was ignoring it. Now the setting persists correctly.
2025-12-24 16:05:07 +00:00
rcourtman b65fcb1bc0 Auto-update Helm chart version to 5.0.1 2025-12-24 11:54:55 +00:00
rcourtman 0bc1cfa72e Auto-update Helm chart documentation 2025-12-24 11:54:54 +00:00
rcourtman d231651017 chore: bump version to 5.0.1 2025-12-24 11:05:31 +00:00
rcourtman c175ef0340 feat(ui): Add request timeout setting to AI config. Fixes #880
Users can now adjust the AI request timeout in Settings → AI.
Default remains 300s (5 min), but users with slow Ollama hardware
can increase this to prevent timeouts.
2025-12-24 10:55:29 +00:00
rcourtman 708dc964df feat: Add configurable AI request timeout for slow hardware. Related to #880
Adds RequestTimeoutSeconds to AI config (default 300s / 5 min).
Users with low-power hardware running Ollama can increase this
value in Settings to prevent timeouts on slower inference.
2025-12-24 10:52:11 +00:00
rcourtman 2798877aa7 fix: license persistence survives Docker container recreation
Docker users were losing their license activation on every update because
/etc/machine-id changes when the container is recreated.

Changes:
- Store persistent encryption key in /data/.license-key (survives container updates)
- Fall back to machine-id for backwards compatibility with existing installations
- Existing users only need to re-enter their key once, then it persists forever

Fixes issue reported by customer upgrading from RC to v5.0.0.
2025-12-24 10:32:26 +00:00
rcourtman 948989cb08 fix: Per-node TLS fingerprints for cluster peers (TOFU)
When a PVE cluster has unique self-signed certificates on each node, Pulse
would mark secondary nodes as unhealthy because only the primary node's
fingerprint was used for all connections.

Now, during cluster discovery, Pulse captures each node's TLS fingerprint
and uses it when connecting to that specific node. This enables
"Trust On First Use" (TOFU) for clusters with unique per-node certs.

Changes:
- Add Fingerprint field to ClusterEndpoint config
- Add FetchFingerprint() to tlsutil for capturing node certs
- validateNodeAPI() now captures and returns fingerprints during discovery
- NewClusterClient() accepts endpointFingerprints map for per-node certs
- All client creation paths use per-endpoint fingerprints when available

Related to #879
2025-12-24 10:05:03 +00:00
rcourtman 216b1d3e97 fix(ci): add run-name to workflows for reliable tag extraction 2025-12-24 09:41:26 +00:00
rcourtman 105766f66d Auto-update Helm chart version to 5.0.0 2025-12-24 09:38:53 +00:00
rcourtman f1e1a2278d Auto-update Helm chart documentation 2025-12-24 09:29:49 +00:00
rcourtman 16823750aa docs: expand AI Patrol documentation with full context explanation
- Add comprehensive explanation of what data Patrol receives
- Document the enriched context (trends, baselines, predictions)
- Explain operational memory (notes, dismissed alerts, incidents)
- Clarify why Patrol catches issues that static alerts miss
- Mark Patrol as Pro feature with link to pulserelay.pro
2025-12-23 23:21:36 +00:00
rcourtman f3c95e9189 feat: add AI Patrol upgrade prompt in AI Chat
Show a non-intrusive upgrade prompt after users send their first message
in AI Chat, encouraging them to try AI Patrol with Pulse Pro.

- Only shows if user doesn't have a Pro license
- Dismissible with X button
- Links to pulserelay.pro landing page
- Subtle purple gradient styling matching the AI theme
2025-12-23 22:49:10 +00:00
rcourtman e1f94283d2 fix(ai): prevent false-positive backup findings from alert-triggered analysis
Alert-triggered AI analysis was passing nil for lastBackup when analyzing
guests, causing 'Never backed up' findings even when backup data existed.

- Pass actual LastBackup timestamp from VM/Container state in analyzeGuestFromAlert
- Add regression test to verify backup data is correctly passed through

Fixes false positive 'Never backed up' alerts appearing when CPU/memory alerts fire.
2025-12-23 21:11:35 +00:00
rcourtman 3933032c90 chore: bump VERSION to 5.0.0 2025-12-23 20:18:49 +00:00
rcourtman 8079508c49 fix(agentexec): eliminate race conditions in WebSocket message sending
- Move deadline/pong handler setup BEFORE registering agent in map
- Use writeMu mutex consistently for all WebSocket writes
- Prevents race between registration response and ExecuteCommand calls
- Fixes flaky TestExecuteCommand_RoundTripViaWebSocket in CI
2025-12-23 20:05:46 +00:00
rcourtman 37be81d9aa docs: add Pulse Pro section to README 2025-12-23 19:56:18 +00:00
rcourtman 02c10a4c62 ci: disable cancel-in-progress to stop cancellation spam 2025-12-23 18:57:51 +00:00
rcourtman a18bd57cde fix(demo): allow AI chat in read-only mode
Whitelists /api/ai/execute in the DemoModeMiddleware so users can
interact with the mock AI assistant while keeping the rest of the
system read-only and hardened.
2025-12-23 18:52:13 +00:00
rcourtman 72211078cc fix(demo): support patrol analysis mock
Adds structured XML finding responses to the demo mock AI service.
This prevents the background patrol service from failing with 'Analysis failed'
when running in demo mode without a real LLM provider.
2025-12-23 18:48:50 +00:00
rcourtman 381ba740a4 fix(demo): generate realistic spaced patrol history
Updates the demo data generator to create patrol runs spaced 6 hours apart
over the last 3 days, rather than clustering them all in the last hour.
This provides a more authentic viewing experience on the demo dashboard.
2025-12-23 18:42:49 +00:00
rcourtman 10047b2192 fix(ai): force enabled state in demo mode
Ensures the AI settings endpoint reports enabled=true and configured=true
when running in demo mode (PULSE_MOCK_MODE=true), even if no provider is
configured. This unlocks the frontend UI to allow interaction with the
mock AI assistant.
2025-12-23 18:39:34 +00:00
rcourtman 8666961201 feat(ai): add mock chat response for demo mode
Allows the AI Assistant to provide realistic canned responses on the
live demo server without needing a real API key. Handled automatically
when PULSE_MOCK_MODE=true and no provider is configured.
2025-12-23 18:34:38 +00:00