3147 Commits

Author SHA1 Message Date
rcourtman 01bf637d0d Fix QNAP agent duplicate processes during upgrades (#1317)
Add singleton watchdog with lock dir, pidfile tracking, and signal
traps to prevent multiple pulse-agent instances spawning on QNAP.
Tighten procfs matching to avoid killing unrelated processes.
v5.1.21
2026-03-06 11:40:53 +00:00
rcourtman 9244498b75 Bump version to 5.1.21 2026-03-06 11:05:01 +00:00
rcourtman 89577fe533 Fix OIDC token refresh bypass and guard AISettingsHandler nil path
The applyAuthContextHeaders early-return in CheckAuth skipped the OIDC
token refresh block, causing long-lived OIDC sessions to expire instead
of auto-refreshing. Move the refresh trigger into extractAndStoreAuthContext
so it fires at the middleware level before CheckAuth's early return.

Also add a nil guard on mtPersistence in AISettingsHandler.GetAIService
for non-default org paths, preventing a potential panic if background
code carries a non-default org context in v5 single-tenant mode.
2026-03-06 11:05:01 +00:00
rcourtman 743ef17b79 Fix AI and config profile handlers broken in v5 single-tenant mode
The single-tenant lockdown (499ab812e) set mtPersistence to nil but
only patched AISettingsHandler with a legacy fallback. AIHandler (chat
service) and ConfigProfileHandler were missed, so AI features (Patrol,
Chat) failed with "chat service not available" and config profiles
would panic on nil dereference. Wire legacy persistence into both
handlers and add the same fallback to ProfileSuggestionHandler.

Fixes #1322
2026-03-06 11:05:01 +00:00
rcourtman 73bf2c1c7b Auto-update Helm chart version to 5.1.20 helm-chart-5.1.20 2026-03-06 00:33:13 +00:00
rcourtman 4c5fbb0c04 Auto-update Helm chart documentation 2026-03-06 00:33:12 +00:00
rcourtman 6618db7799 Fix v5 single-tenant router test setup v5.1.20 2026-03-05 23:58:11 +00:00
rcourtman ed8283b223 Bump version to 5.1.20 2026-03-05 23:46:35 +00:00
rcourtman 499ab812e3 Fix post-release regressions and lock v5 to single-tenant runtime 2026-03-05 23:46:35 +00:00
rcourtman 464d3f8486 Fix stale queued notification delivery 2026-03-05 23:46:35 +00:00
rcourtman 74ce77132b Auto-update Helm chart version to 5.1.19 helm-chart-5.1.19 2026-03-05 11:21:24 +00:00
rcourtman 74c55c79bb Auto-update Helm chart documentation 2026-03-05 11:21:23 +00:00
rcourtman ba8490c252 fix(ui): use SolidJS class prop instead of deprecated className 2026-03-05 10:17:51 +00:00
rcourtman 7cfcaab250 chore: bump version to 5.1.19 v5.1.19 2026-03-05 10:01:43 +00:00
rcourtman 0493fb78bf fix(agent): detect rootless Docker/Podman sockets for other users (#1200)
When the agent runs as root, os.Getuid() returns 0 so it only probes
/run/user/0/docker.sock. Rootless Docker installs live at
/run/user/1000/docker.sock (or similar). Glob /run/user/*/docker.sock
and /run/user/*/podman/podman.sock to discover sockets for all users.
2026-03-05 10:01:43 +00:00
rcourtman 10872c8ca8 fix(patrol): remove noisy per-alert log when patrol is disabled (#1258)
The alert callback logged at Info level for every alert regardless of
whether patrol was enabled. TriggerPatrolForAlert already has an
enabled/running guard and its own debug logging.
2026-03-05 10:01:43 +00:00
rcourtman 1491e0ee6e fix(alerts): add stable sort tiebreaker to prevent hostname scrambling (#1218)
When multiple alerts fire in the same polling cycle they share identical
startTime values. Without a tiebreaker, JS sort returns them in arbitrary
order on each reactive recomputation, causing hostnames to visually
shuffle. Use alert.id as a deterministic lexicographic tiebreaker in both
the Overview and History tab sort comparators.
2026-03-05 10:01:43 +00:00
rcourtman 3a263bc4f0 fix(ai): pass correct identifiers to Docker container discovery (#1315)
Use host.agentId and container.name for DiscoveryTab props to match
backend storage keys. Previously host.id (derived ID) and container.id
(Docker hash) were used, causing discovery lookups to always miss.
2026-03-05 10:01:43 +00:00
rcourtman 72be883f4e fix(proxmox): prevent broken TLS config on auto-register fingerprint failure (#1303)
When FetchFingerprint fails during agent auto-registration, set verifySSL
based on whether a fingerprint was captured rather than hardcoding true.
Also heal already-broken nodes (verifySSL=true with empty fingerprint) on
legacy re-register to prevent permanent connection failures with self-signed
Proxmox certs.
2026-03-05 10:01:43 +00:00
rcourtman cdceccef05 fix(agent): kill old QNAP agent processes during upgrade (#1317)
Add stop_qnap_agents() helper that kills wrapper scripts before binaries
to prevent watchdog respawn, and uses path-based pkill patterns that work
with BusyBox and match agents at both old and new install paths.
2026-03-05 10:01:43 +00:00
rcourtman d4d67315de Auto-update Helm chart version to 5.1.18 helm-chart-5.1.18 2026-03-03 22:11:55 +00:00
rcourtman a3fcaafbdb test(notifications): remove queue stats race with background processor v5.1.18 2026-03-03 21:37:27 +00:00
rcourtman 1c9d53cf20 chore: bump version to 5.1.18 2026-03-03 20:56:04 +00:00
rcourtman ac83074fc2 fix(hostmetrics): skip network mounts before usage probe (#1313) 2026-03-03 20:27:41 +00:00
rcourtman 8818a740e2 fix(proxmox): prevent setup-script token drift and add lifecycle integration tests (#1312) 2026-03-03 20:11:01 +00:00
rcourtman a8e562034e fix(ai): restore dismissed patrol findings and add regression tests 2026-03-03 19:53:55 +00:00
rcourtman c7e0aa63d2 fix(installer): make proxmox auto-register token rotation deterministic 2026-03-03 19:50:33 +00:00
rcourtman a4571f580b fix(monitoring): harden VM memory selection and flag repeated VM usage 2026-03-03 16:19:17 +00:00
rcourtman ff9dc34687 Fix offline host visibility/alerting across restarts (#1311) 2026-03-03 15:43:29 +00:00
rcourtman adad2bbd1c fix(server): fail fast on frontend bind errors 2026-03-03 15:43:22 +00:00
rcourtman b38488f2da fix(proxmox): stabilize pulse monitor token lifecycle 2026-03-03 10:57:19 +00:00
rcourtman 768b6d8b7a fix(frontend): resolve npm audit advisories in lockfile 2026-03-02 23:59:34 +00:00
rcourtman 71a7249fd7 chore: bump version to 5.1.17 v5.1.17 helm-chart-5.1.17 2026-03-02 17:51:50 +00:00
rcourtman 510ec999ab fix(api): store TLS fingerprint during auto-registration (#1303)
The legacy auto-register endpoint captured TLS fingerprints via
FetchFingerprint() but never persisted them to the node config. Nodes
with self-signed certs registered via the agent would fail with
"x509: certificate signed by unknown authority" on subsequent polls.

Store the fingerprint in all add/update paths for both PVE and PBS,
guard updates against empty-fingerprint clobber when FetchFingerprint
fails, and pass the fingerprint to cluster detection configs.
2026-03-02 14:07:18 +00:00
rcourtman 10a4e994b6 fix(api): return 404 from undismiss endpoint for invalid finding IDs (#1300)
HandleUndismissFinding now checks both patrol and unified stores
before returning. Returns 404 with error message when the finding
is not found or not dismissed, instead of silently returning success.
2026-03-02 11:48:23 +00:00
rcourtman 60bdc9a101 fix(memory): skip meminfo-derived when balloon lacks cache metrics (#1302)
When the balloon driver reports Free but not Buffers or Cached, the
meminfo-derived fallback computed memAvailable = Free alone, counting
all reclaimable page cache as used memory. This caused Linux VMs to
show wildly inflated usage (e.g. 93% when actual is 21%).

Now meminfo-derived requires at least one cache metric (Buffers > 0
or Cached > 0) before trusting the value. When missing, the code
falls through to RRD/guest-agent/Total-Used fallbacks which provide
accurate cache-aware data. Both efficient and traditional polling
paths are now consistent.
2026-03-02 11:48:18 +00:00
rcourtman 9f8f372f7c chore: add .mcp.json to gitignore 2026-03-01 23:33:58 +00:00
rcourtman d43dfbc490 feat(ui): add host removal action to hosts table
Add an actions menu to the hosts overview with a "Remove host from
Pulse" button. Includes permission checks (requires settings:write
scope), confirmation handling, and a security regression test for
the delete endpoint scope enforcement.
2026-03-01 23:28:33 +00:00
rcourtman 5bd0563283 test(providers): update Ollama integration tests for timeout parameter 2026-03-01 23:28:16 +00:00
rcourtman f5365809b3 fix(installer): remove config backup that filled disk on upgrades
The backup_existing function copied the entire config directory
(including metrics.db at ~2.5GB) on every upgrade with no cleanup.
On small VMs this filled the disk within a few releases.

The upgrade only swaps the binary; config files are not modified,
so the backup served no practical purpose.
2026-03-01 23:20:08 +00:00
rcourtman 0c78fab337 Auto-update Helm chart documentation helm-chart-5.1.16 2026-03-01 23:15:53 +00:00
rcourtman fa48369dbb chore(release): bump version to 5.1.16 v5.1.16 2026-03-01 22:40:55 +00:00
rcourtman d46b5fc84b fix(ai): route OpenRouter slash-delimited models to OpenAI provider (#1296)
createProviderForModel() only handled "provider:model" colon format.
Models like "google/gemini-2.5-flash" or "google/gemini-2.0-flash:free"
(OpenRouter format) failed because the colon split produced invalid
provider names.

Now uses config.ParseModelString() which correctly detects slash-
delimited models as OpenRouter (routed via OpenAI-compatible API).
2026-03-01 22:29:45 +00:00
rcourtman 2fcddecf80 feat(api): add POST /api/ai/patrol/undismiss endpoint to revert suppressed findings (#1300)
The Undismiss() method existed on FindingsStore but was never exposed
via the API. Users who dismissed findings as "not_an_issue" had no way
to revert them.

- Add HandleUndismissFinding handler and route
- Add Undismiss() to UnifiedStore for parity with FindingsStore
- Also remove matching explicit suppression rules on undismiss
2026-03-01 22:29:36 +00:00
rcourtman 027fd9932c fix(proxmox): make monitor reload synchronous after auto-registration (#1303)
Auto-register was running the monitor reload in a background goroutine,
so the HTTP response was sent before the poller picked up the new node.
If reload failed or was slow, the node appeared in Settings > Proxmox
(reads config from disk) but not on the main Proxmox tab (reads from
active polling state).

Changed both auto-register paths to reload synchronously, matching the
manual add path (HandleAddNode).
2026-03-01 21:04:20 +00:00
rcourtman d852964696 fix(ai): record patrol and QuickAnalysis token usage in cost store for budget enforcement
Patrol runs, evaluation passes, and QuickAnalysis calls were consuming
LLM tokens without recording them in the cost store. This made the
cost_budget_usd_30d budget setting ineffective since enforceBudget()
never saw patrol spend.

- Add RecordUsage() to ai.Service for thread-safe cost recording
- Add recordPatrolUsage() helper to PatrolService, called on both
  success and error paths for main patrol and evaluation pass
- Record QuickAnalysis token usage in cost store
- Return partial PatrolResponse (with token counts) on error instead
  of nil, so callers can always record consumed tokens
- Propagate partial response through chat_service_adapter on error
2026-03-01 19:19:47 +00:00
rcourtman b1ff7e006f fix(ui): show PULSE_PUBLIC_URL value in settings and expand node tables to full width (#1305, #1304)
Expose PublicURL from runtime config in the system settings API response
so the frontend displays the actual value instead of the placeholder when
the env var is set.

Add w-full to PVE, PBS, and PMG node tables so they expand to fill the
container in full-width mode.
2026-03-01 14:42:30 +00:00
rcourtman c575c7e295 fix(patrol): rename wearout JSON field to ssd_life_remaining_pct (#1300)
The AI also receives disk data via tool calls (pulse_metrics type="disks"),
not just the patrol context table. The raw JSON field "wearout" was
ambiguous — rename to "ssd_life_remaining_pct" so the field name itself
communicates that 100 = healthy.
2026-02-27 23:12:27 +00:00
rcourtman 3006f51b60 fix(patrol): clarify wearout semantics so AI knows 100% = healthy (#1300)
The patrol context table header said "Wearout" and the tool returned a raw
"wearout" JSON field with no indication that 100 = full life remaining.
The AI interpreted "wearout: 100" as fully worn out and raised false
"100% Disk Wearout" findings on healthy NVMe drives.

Rename the patrol table column to "SSD Life Remaining (100%=new)" and
update the data type comment to clarify the semantics.
2026-02-27 23:05:02 +00:00
rcourtman aae6035e66 fix(docs): audit and fix agent docs vs install script discrepancies (#1299)
- Split configuration table into "Installer flags" and "Agent-only flags"
  so users know which flags work with `curl | bash` vs the binary directly
- Add missing --cacert and --env flags to installer docs
- Fix --disable-auto-update example (install script doesn't accept it;
  use --env PULSE_DISABLE_AUTO_UPDATE=true instead)
- Add --disable-docker/kubernetes/proxmox and --proxmox-type to
  install.sh show_help()
- Fix --enable-docker=false in CENTRALIZED_MANAGEMENT.md
2026-02-27 21:20:54 +00:00