3093 Commits

Author SHA1 Message Date
rcourtman 7530b66254 fix(setup): escape printf %s in Sprintf template to fix format verb count (#1297)
The printf '%s\n' calls in shell code within the Go Sprintf template
were being counted as format verbs, causing a build failure (10 verbs
but 9 args). Using %%s produces literal %s in the output.
v5.1.15
2026-02-27 14:44:41 +00:00
rcourtman 2f059e650e chore(release): bump version to 5.1.15 2026-02-27 14:29:10 +00:00
rcourtman 8298852483 feat(installer): add QNAP QTS/QuTS hero agent support (#1253)
QNAP wipes /etc/init.d on every reboot, so the agent needs persistent
storage on a data volume and autorun.sh boot persistence via the flash
config partition. Adds detection, install (with watchdog wrapper), and
clean uninstall paths. Flash config mount/umount is fail-safe via
subshell isolation to prevent leaving the partition mounted on write
errors.
2026-02-27 14:19:40 +00:00
rcourtman 62225e0c12 fix(alerts): scope orphaned backup detection per PVE instance to prevent false positives (#1286)
The previous hasLiveInventory guard was a single boolean — if any PVE
instance had at least one live guest, orphan detection ran for all
instances. In multi-instance clusters with staggered polling, backups
from instances whose VMs hadn't been polled yet appeared orphaned,
producing false positive alerts with 0m duration.

Replace the global boolean with a per-instance map. PVE storage backups
now only run orphan detection when their specific instance has live
inventory. PBS/PMG backups (which span instances) retain the "any
instance has live guests" check.
2026-02-27 13:32:15 +00:00
rcourtman 4c7a79cecb fix(setup): preserve SSH authorized_keys symlink on Proxmox and fix key entry quoting (#1297)
The PVE setup script had three bugs in the temperature monitoring SSH key setup:

- Nested double quotes in SSH_SENSORS_KEY_ENTRY broke the bash string, causing
  "No such file or directory" errors for the key options
- The grep/mv pattern to update authorized_keys destroyed the symlink that
  Proxmox maintains from /root/.ssh/authorized_keys to /etc/pve/priv/
- The uninstall path grepped for "# pulse-managed-key" but keys were tagged
  "# pulse-sensors", so uninstall never cleaned up sensor keys

Fixes: resolve symlinks with readlink -f before operating, create temp files in
/tmp with mv-then-cp fallback for cross-device moves, escape inner quotes, and
broaden the uninstall filter to match all pulse-prefixed keys.
2026-02-27 13:23:03 +00:00
rcourtman 9aee8fa293 fix(ui): add Pro badge to Reporting tab and reduce patrol trigger log noise (#1285, #1258)
Show "Pro" badge on the Reporting settings tab so users know upfront
that advanced reporting requires a Pro license, rather than discovering
it after filling out the form.

Downgrade patrol trigger queue-full and rejection messages from Warn to
Debug — these are normal rate-limiting behavior, not actionable warnings.
2026-02-26 21:09:13 +00:00
rcourtman af712006c9 fix(ai): allow Gemini and other models via OpenRouter without false provider warning (#1296)
Model name detection used substring matching (.includes('gemini')) which
falsely required Gemini provider config for OpenRouter model IDs like
"google/gemini-2.5-flash". Now only known provider prefixes are treated
as explicit delimiters, slash-containing names route to OpenAI (OpenRouter
convention), and colons in model names (e.g. "llama3.2:latest") are no
longer misinterpreted as provider prefixes.
2026-02-26 20:49:10 +00:00
rcourtman fa519cd8ce fix(alerts): prevent false positive orphaned backup alerts during startup race (#1286)
Backup polling goroutines can snapshot state before VM/container polling
populates the guest inventory. When guestsByVMID is empty, every backup
appears orphaned. Gate orphan detection on hasLiveInventory (at least one
guest with non-empty ResourceID) and preserve existing orphan alerts when
inventory becomes unavailable.
2026-02-26 20:49:10 +00:00
rcourtman eb2397d99a fix(notifications): route escalation notifications to selected channels only (#1259)
Escalation was calling SendAlert() which always sends to all enabled
channels, ignoring the per-level channel selection (email/webhook/all).

Add SendAlertToChannels() that snapshots only the requested channel
configs and uses a distinct "_escalation" queue type so the dequeue
handler skips cooldown writes — preventing interference with the alert
manager's own re-notify cadence.
2026-02-26 20:49:10 +00:00
rcourtman c213e0ce30 Auto-update Helm chart documentation helm-chart-5.1.14 2026-02-25 00:14:54 +00:00
rcourtman a5fb155b88 chore(release): bump version to 5.1.14 v5.1.14 2026-02-24 23:39:42 +00:00
rcourtman 77bd2e70d9 fix(notifications): add service-specific resolved webhook templates (#1259)
Backport from v6 (88d5865a8). Recovery webhook notifications were using
the firing PayloadTemplate which services like Telegram, Teams, Discord
etc. silently rejected as malformed. Now uses a three-tier template
pipeline matching the firing path:
- Tier 1: Custom user template (if configured)
- Tier 2: Service-specific ResolvedPayloadTemplate (Discord green embed,
  Telegram chat_id+text, Slack header blocks, Teams MessageCard/Adaptive,
  PagerDuty event_action:"resolve", Pushover, Gotify, Mattermost)
- Tier 3: Generic JSON fallback (backward compatible)

Also adds Event, ResolvedAt, ResolvedAtISO fields to WebhookPayloadData.
2026-02-24 23:28:33 +00:00
rcourtman 6221be7311 fix(docker): serialize batch container updates per host (#1289)
The backend only allows one command per host at a time. The "Update All"
button was firing requests in parallel chunks, causing the second
container per host to fail with 400. Group targets by host and process
them sequentially within each host while still updating different hosts
in parallel.
2026-02-24 23:16:22 +00:00
rcourtman 24f5b1cb31 fix(patrol): cap per-run tokens and reset patrol session history 2026-02-24 11:29:47 +00:00
rcourtman 82ccb662f9 fix(notifications): use service-specific templates for resolved webhooks (#1068)
Recovery notifications for Discord, Slack, Teams, PagerDuty, and other
service webhooks were sending a generic JSON payload that lacked the
required format (e.g. Discord needs `embeds`, Slack needs `blocks`),
causing resolved notifications to silently fail.

- Add `prepareResolvedWebhookData` to build template data with Level="resolved"
- Route resolved webhooks through service-specific templates with full
  URL rendering, Telegram ChatID extraction, and PagerDuty routing_key
- Custom user templates take precedence over built-in service templates
- Return errors on service template failures instead of falling back to
  generic payloads that endpoints would reject
- Fix PagerDuty template to send event_action="resolve" for resolved alerts
2026-02-24 10:49:52 +00:00
rcourtman 4dc09a1240 feat(alerts): add dedicated backup-orphaned alert type (#1286)
Fire a warning alert immediately when a backup's guest no longer exists
in inventory, without requiring age thresholds to be breached. The
existing alertOrphaned toggle and ignoreVMIDs UI control this feature
with no frontend changes needed.
2026-02-24 09:07:43 +00:00
rcourtman ffc14c7507 fix(docker): stop CPU bars flickering for idle containers (#1288)
The isRunning prop used a `cpuPercent > 0` gate that treated idle
containers (0% CPU) as not-running, causing the bar to flip between
a percentage and an em-dash on every poll cycle. Remove the value
guard so visibility depends only on container running state, matching
how memory, disk, and restart columns already behave.
2026-02-23 22:05:18 +00:00
rcourtman cac5be2ca1 chore(frontend-modern): remove stale pnpm lockfile 2026-02-23 11:15:37 +00:00
rcourtman 5457b04608 fix(ai): deduplicate Docker host 3-way chain in mention picker (#1252)
Replace first-match-only logic in upsertMentionResource with a
union-merge algorithm that collects all matching keys, merges losers
into a canonical winner, and re-points aliases. This fixes the case
where a host agent bridges a VM and a DockerHost but only the first
alias match was merged, leaving a duplicate entry in the picker.
2026-02-22 15:15:14 +00:00
rcourtman 2140efce36 Auto-update Helm chart documentation helm-chart-5.1.13 2026-02-22 12:43:12 +00:00
rcourtman 180c8738b4 chore(release): bump version to 5.1.13 v5.1.13 2026-02-22 12:01:38 +00:00
rcourtman 54a1ace2c5 fix(installer): remove stale sensor-proxy mount entries that prevent LXC start after reboot (#1280)
The v4 installer added mount entries for /run/pulse-sensor-proxy to LXC
container configs. After upgrading to v5 and rebooting, /run (tmpfs) is
wiped and the container fails to start. The installer now detects and
removes these stale mp<N> and lxc.mount.entry references automatically
when run on a PVE host, and the upgrade docs include manual fix steps.
2026-02-22 10:52:12 +00:00
rcourtman f9654f5b7a Merge pull request #1279 from muratoda/feature/use-locale-aware-time-format
Change last refresh time display format to system locale
2026-02-21 23:11:48 +00:00
rcourtman 32746e2d2a fix(monitoring): use RRD memavailable fallback when PVE node cache metrics missing (#1270)
When Proxmox /nodes/{node}/status returns only total/used/free without
available/buffers/cached, EffectiveAvailable() returns Free (non-zero),
causing the RRD fallback gate to be skipped. This results in inflated
node memory where cache/buffers are counted as "used."

Widen the RRD fallback condition from requiring effectiveAvailable == 0
to triggering whenever missingCacheMetrics is true. Add negative caching
for failed RRD lookups (2-minute backoff) to avoid repeated retries.
2026-02-21 22:47:20 +00:00
rcourtman 1170da6a57 fix(ai): serialize linkedVmId/linkedContainerId and harden mention status (#1252)
HostFrontend was missing LinkedVmId and LinkedContainerId fields, so the
frontend dedup aliases for VM/container agents resolved to undefined and
never matched. Also add .trim() to getStatusColor and default host agent
status to 'online' to fix grey status dots.
2026-02-21 22:00:43 +00:00
rcourtman b445f8d8fa fix(agent): preserve user-configured host URL during agent re-registration (#1283)
When an agent re-registers with the same token, the DHCP matching case
would overwrite the Host field with the agent's local IP — even if the
user had edited it to a public URL or different IP. Now agent source
re-registrations always preserve the existing host, while non-agent
DHCP updates still work. Adds 5 regression tests covering hostname
preservation, public-IP preservation, agent DHCP, non-agent DHCP, and
PBS parity.
2026-02-21 12:46:02 +00:00
rcourtman 50e476c942 fix(ai): fix mention status colors and dedup for docker/VM/LXC agents (#1252)
Three fixes for remaining mention autocomplete issues:

- Status dots now correctly show green/red/yellow for online/offline/
  degraded statuses (previously only handled running/stopped/paused)
- Docker hosts merge with their host agent via agentId cross-reference
- VMs and LXC containers merge with host agents running inside them
  via linkedVmId/linkedContainerId backend ID aliases
2026-02-20 22:53:52 +00:00
rcourtman 06bd8cf2b6 Auto-update Helm chart documentation helm-chart-5.1.12 2026-02-20 20:56:23 +00:00
rcourtman 934b0f61a3 chore: bump version to 5.1.12 v5.1.12 2026-02-20 20:19:07 +00:00
rcourtman 3da224877c feat(agent): add --env flag for custom environment variables in service files (#1277)
Users can now pass --env KEY=VALUE (repeatable) to the install script to
inject custom environment variables into the agent's service file. Useful
for KUBECONFIG and similar paths not auto-detected by the installer.

The Settings UI adds a textarea for entering env vars that get appended
to the generated install command. Both frontend and script validate key
format and reject unsafe value characters.
2026-02-20 20:15:29 +00:00
rcourtman 3efb3fc1da fix(ai): deduplicate PVE node and host agent in AI mention autocomplete (#1252)
When a PVE node has a linked host agent (or vice versa), they now merge
into a single mention resource instead of appearing as duplicate entries.
Uses alias cross-referencing via both linkedHostAgentId and linkedNodeId
(node-backend-id) to handle one-way and two-way links.
2026-02-20 19:59:29 +00:00
rcourtman 1d07c1cd30 fix(agent): prevent duplicate PVE entries on agent re-registration (#1245)
Two changes to prevent duplicates in Settings > Virtual Environment:

1. Install script: only clear Proxmox state files on fresh installs,
   not upgrades. Previously every install forced re-registration.

2. Auto-register dedup: match agent re-registrations by server name
   when both the existing entry and new request have Pulse-created
   tokens (pulse-monitor@pam!pulse-*). This catches the case where
   the agent creates a new token after state files are cleared.
2026-02-20 19:38:03 +00:00
rcourtman 78c815915d feat(ui): add URL edit column to hosts and docker table views (#1276)
Add pencil icon + link column to the hosts overview table and the
docker unified table (containers and services), matching the existing
VM/guest URL column pattern. Uses the shared UrlEditPopover component
and existing metadata APIs. No backend changes needed.
2026-02-20 19:24:47 +00:00
rcourtman dacf0f86c4 fix(agent): collect temperature on FreeBSD via sysctl (#1254)
The agent gate only allowed temperature collection on Linux (lm-sensors).
FreeBSD exposes CPU and ACPI thermal zone temperatures via sysctl
(dev.cpu.N.temperature, hw.acpi.thermal.tzN.temperature). Parse sysctl
output directly in Go without shell involvement.
2026-02-20 19:00:40 +00:00
rcourtman 706502c22d fix(alerts): default NotifyOnResolve to true and prevent patrol queue spam (#1259, #1258)
Recovery notifications were silently disabled for users with pre-5.1.12
configs because the NotifyOnResolve bool field defaults to false when
absent from JSON. Use a *bool probe to detect missing field and default
to true.

Patrol trigger queue filled with warnings when the patrol loop wasn't
running. Gate TriggerPatrolForAlert on p.running and clear the flag
via defer when the loop exits.
2026-02-20 17:56:41 +00:00
rcourtman 6c78d78fc7 fix(webhooks): test button in edit form sends redacted headers (#1273)
When editing an existing webhook, header values are masked as
***REDACTED*** for security. The "Test" button in the edit form
sent these redacted values to the webhook endpoint, causing auth
failures (HTTP 403) on services like ntfy.sh that require tokens.

The test button outside the edit form worked because it used the
server-side saved config with real header values.

Fix: frontend now includes the webhook ID in test payloads for
existing webhooks, and the backend TestWebhook handler merges
redacted values with the saved originals before sending the test
(same logic already used by UpdateWebhook).
2026-02-20 13:31:52 +00:00
rcourtman fe2916ad4f fix(hosts): add URL field to host drawer overview tab (#1197)
The inline URL edit was removed from the hosts table in 5.1.2 and
the only way to set a host URL was buried in the Discovery tab
(which requires AI features and a successful discovery scan).

Adds a Web Interface URL field directly in the System card of the
host drawer's Overview tab - always accessible without AI/Pro.
Users can add, edit, and remove URLs with inline editing.

Also fixes the Discovery tab using GuestMetadataAPI instead of
HostMetadataAPI for host URLs, which caused saved URLs to not
appear in the hosts table.
2026-02-20 13:31:52 +00:00
rcourtman afb4dcc2bd fix(sso): return full provider config for edit form and register SSO users in RBAC (#1255)
Two remaining issues from #1255 after the 5.1.10 fixes:

1. OIDC/SAML provider edit fields appeared blank because the GET
   endpoint returned a flattened response while the frontend reads
   nested oidc/saml objects. Now returns the full provider config
   with secrets redacted (client secret, SP private key).

2. SSO users didn't appear in Settings > Users because RBAC entries
   were only created when group-role mappings matched. Now ensures
   every SSO user is registered in RBAC on login, even without
   role mappings.

Also fixes: SAML SP private key and certificate lost on edit (no
preservation logic existed), OIDC client secret preservation
hardened to check actual secret presence not just flag.
2026-02-20 13:31:52 +00:00
rcourtman 0ae2806f18 fix(memory): add guest agent /proc/meminfo fallback to avoid VM memory inflation (#1270)
Proxmox status.Mem includes page cache as "used" memory, inflating
reported VM usage. The existing fallbacks (balloon meminfo, RRD, linked
host agent) were frequently unavailable, causing most VMs to fall
through to the inflated status-mem source.

Adds a new last-resort fallback that reads /proc/meminfo via the QEMU
guest agent file-read endpoint to get accurate MemAvailable. Results
are cached (60s positive, 5min negative backoff for unsupported VMs).

Also fixes: RRD memavailable fallback missing from traditional polling
path, cache key collisions in multi-PVE setups, FreeMem underflow
guard inconsistency, and integer overflow in kB-to-bytes conversion.
2026-02-20 13:31:52 +00:00
rcourtman 8c7d507ea4 fix(alerts): make --disk-exclude suppress Proxmox SSD wear/health alerts (#1142)
The --disk-exclude agent flag only filtered local metric collection but
had no effect on server-side Proxmox disk health and SSD wearout alerts,
which poll the Proxmox API directly. Users excluding disks (e.g.
--disk-exclude sda) still received alerts for those disks.

Agent now sends its DiskExclude patterns in each report. The server
stores them on the Host model and consults them during Proxmox disk
polling — excluded disks get a synthetic healthy status passed to
CheckDiskHealth so any existing alerts clear immediately.

Also adds FreeBSD pseudo-filesystem types (fdescfs, devfs, linprocfs,
linsysfs) to the virtual FS filter and /var/run/ to special mount
prefixes, fixing false disk-full alerts on FreeBSD for fdescfs mounts.
2026-02-20 13:31:52 +00:00
muratoda b730b8be35 Change last refresh time display format to system locale 2026-02-19 23:33:18 +03:00
rcourtman bc378f0f60 Auto-update Helm chart documentation helm-chart-5.1.11 2026-02-19 20:23:27 +00:00
rcourtman d62b0bd0a4 chore: bump version to 5.1.11 v5.1.11 2026-02-19 19:47:10 +00:00
rcourtman fb7582c7e4 fix(memory): use linked Pulse host agent memory to avoid VM inflation (#1270)
When no guest agent MemInfo or RRD data is available, prefer the linked
Pulse host agent's memory (read from /proc/meminfo via gopsutil, which
excludes page cache) over Proxmox's status.Mem (total - free, inflated
by reclaimable cache). Applied to both efficient and traditional polling
paths. Diagnostic fields added to VMMemoryRaw for visibility.
2026-02-19 19:04:19 +00:00
rcourtman 04d8c45ede fix(install): pass --cacert CA certificate to agent via SSL_CERT_FILE (#1201)
The --cacert flag was only used for curl during installation. On systems
with custom CA certificates (e.g. TrueNAS CORE with certs in
/etc/certificates/CA), the agent process had no way to trust the custom
CA and users had to fall back to --insecure.

Set SSL_CERT_FILE in the agent's runtime environment when --cacert is
provided. Go's crypto/x509 reads this natively, so the agent trusts the
custom CA without any binary changes. All service types are covered:
systemd, upstart, launchd, FreeBSD rc.d, OpenRC, SysV init, and Unraid.

Also validates the --cacert path at install time: directories and missing
paths now fail early with a clear message instead of silently proceeding.
2026-02-19 09:55:09 +00:00
rcourtman 00afaec2ae fix(agent): add retry with backoff to Proxmox auto-registration (#1267, #1269, #1261, #1268)
registerWithPulse() was a one-shot call at agent startup — if it failed
(timing, transient network, Pulse not ready), the agent silently continued
as a generic Host forever. Wrap the HTTP POST in a retry loop with
exponential backoff (5s, 10s, 20s, 40s, 60s) and distinguish 4xx errors
(no retry) from 5xx/network errors (retry).
2026-02-18 16:05:40 +00:00
rcourtman 9d81de9fa5 Merge pull request #1274 from RaikaSurendra/feat/macos-docker-desktop-socket
feat(docker): add macOS Docker Desktop socket auto-detection
2026-02-18 14:51:03 +00:00
rcourtman b448d7eb20 Auto-update Helm chart version to 5.1.10 helm-chart-5.1.10 2026-02-18 14:04:19 +00:00
rcourtman a050a2ea7e Auto-update Helm chart documentation 2026-02-18 14:04:18 +00:00
Surendra Raika f663aade53 feat(docker): add macOS Docker Desktop socket auto-detection
Probe ~/.docker/run/docker.sock for RuntimeDocker and RuntimeAuto
before falling back to /var/run/docker.sock. This lets the agent
connect on macOS without requiring DOCKER_HOST to be set manually.

Ref #1200
2026-02-18 19:23:14 +05:30