Commit graph

4826 commits

Author SHA1 Message Date
rcourtman
d744b6f495 fix: Show unsaved changes warning immediately when typing in Network settings. Fixes #959. Changed Public URL and CORS fields to use onInput instead of onChange for immediate feedback. 2025-12-30 12:36:51 +00:00
rcourtman
c22dac5d8d fix: Docker container memory now subtracts inactive_file on cgroup v2 systems. Fixes container memory reporting to match 'docker stats' output by excluding reclaimable filesystem cache. Related to #435 2025-12-30 12:31:57 +00:00
rcourtman
f855625f65 feat: Add full-width mode toggle for wider views on large monitors. Related to #974 2025-12-30 12:20:44 +00:00
rcourtman
a62d7dc78d fix: Improve host agent matching for temperature transport badge. Related to #971
The findMatchingHostAgent function now uses the proper linkedHostAgentId
relationship from the backend state, falling back to hostname matching only
if no linked agent is found. This fixes the 'Agent required' badge showing
incorrectly when agents are running and collecting data.
2025-12-30 09:50:40 +00:00
rcourtman
1cbe0691e3 feat(ui): implement alert overrides for backups/snapshots and add unsaved changes warning (fixes #961, fixes #959) 2025-12-30 08:46:48 +00:00
rcourtman
5cd6224997 fix(install): align bootstrap token path and data directory config (fixes #962) 2025-12-30 00:28:16 +00:00
rcourtman
b17891fd02 feat(ui): add 'Checking updates...' indicator for Docker hosts 2025-12-30 00:28:10 +00:00
rcourtman
065a59316f fix(alerts): respect per-guest backup and snapshot overrides (fixes #961) 2025-12-30 00:28:05 +00:00
rcourtman
56cb913a51 fix: Improve Kubernetes detection and add --kubeconfig flag to installer
- Search for kubeconfig in /home/*/.kube/config in addition to /root/.kube/config
- Add --kubeconfig installer flag to specify custom kubeconfig path
- Auto-detect and pass kubeconfig path to agent when Kubernetes is enabled
- Respect KUBECONFIG environment variable when kubectl is working

Related to discussion #968
2025-12-29 23:48:17 +00:00
rcourtman
6b2ec32ab3 chore: Ignore local agent startup script 2025-12-29 23:39:18 +00:00
rcourtman
df3ff171b9 fix: Honor DisableAutoUpdate config and disable Docker disk metrics by default 2025-12-29 23:37:30 +00:00
rcourtman
6ac5e3ebfe chore: Clean up build scripts and remove unused Docker agent entry point 2025-12-29 23:37:16 +00:00
rcourtman
e42cbe38f0 test: Improve discovery and Docker agent test coverage 2025-12-29 23:37:10 +00:00
rcourtman
4225f905b0 feat: Add manual Docker update check button. Related to #955 2025-12-29 23:37:05 +00:00
rcourtman
03e9f98ab6 fix: Exclude autofs mount type from disk counts. Related to #942 2025-12-29 23:36:58 +00:00
rcourtman
e6477a6998 fix: Resolve manifest lists for correct update detection. Related to #955 2025-12-29 17:36:16 +00:00
rcourtman
060334375f Fix docker hosts toast usage 2025-12-29 17:26:47 +00:00
rcourtman
c6bd8cb74c Improve internal package test coverage 2025-12-29 17:25:21 +00:00
rcourtman
d07b471e40 Refactor Docker agent: metrics collection, security checks, and batch updates
- Separated metrics collection into internal/dockeragent/collect.go
- Added agent self-update pre-flight check (--self-test)
- Implemented signed binary verification with key rotation for updates
- Added batch update support to frontend with parallel processing
- Cleaned up agent.go and added startup cleanup for backup containers
- Updated documentation for Docker features and agent security
2025-12-29 17:20:18 +00:00
rcourtman
d38a37fe3d fix: Improve useResourcesAsLegacy reactivity with array spreading
When returning legacy arrays directly from store state, the createMemo
wouldn't notify dependents because the same array reference was returned
even when its contents changed (via reconcile). The spread operator
creates a new array reference each time, ensuring downstream memos
like sortedHosts() properly re-run.

This is a defense-in-depth fix complementing commit f5c0af77 which
fixed HostRow destructuring. Together these ensure reliable real-time
updates on the Hosts page.

Related to #949
2025-12-29 16:27:58 +00:00
rcourtman
0c3ebef312 feat: Add Fahrenheit temperature unit option. Related to #957
- Add temperature unit preference in Settings > General
- Store preference in localStorage (temperatureUnit: 'celsius' | 'fahrenheit')
- Create formatTemperature() utility that respects the preference
- Update all temperature displays across the UI:
  - TemperatureGauge component
  - HostsOverview page (sensors, disk temps)
  - DiskList (SMART temperatures)
  - ThresholdSlider
  - ThresholdBadge
  - ThresholdsTable
  - ProxmoxNodesSection
  - NodeSummaryTable tooltips
  - Alert formatters
2025-12-29 16:16:30 +00:00
rcourtman
5ad1f5e847 feat: Merge linked host agent SMART temps into Physical Disks
When a host agent is running on a Proxmox node (linked host agent),
merge the agent's SMART disk temperature data into the Physical Disks
view for that node. This allows disk temps collected by pulse-agent
to populate the Physical Disks page without requiring Proxmox SMART
monitoring to be enabled.

Matching is done by WWN (most reliable), serial number, or device path.

Closes part of issue #909 (follow-up from MichiFr)
2025-12-29 15:39:20 +00:00
rcourtman
d377a5c464 fix: Pass SMART disk temperatures to frontend. Related to #941
The SMART disk temperature data was being collected by the agent but not
passed through to the frontend. Fixed by:

1. Added SMART field to HostSensorSummaryFrontend and created
   HostDiskSMARTFrontend type in models_frontend.go
2. Updated hostSensorSummaryToFrontend() in converters.go to include
   SMART data conversion
3. Added HostDiskSMART interface to frontend TypeScript types
4. Updated HostTemperatureCell to display disk temperatures in tooltip
   with a 'Disk Temperatures' section and fallback to SMART temps when
   no CPU/sensor temps are available
2025-12-29 15:27:46 +00:00
rcourtman
0a20eed07a fix: Normalize URL to prevent double-slash in agent download. Related to #956
Strip trailing slashes from PULSE_URL to prevent URLs like
http://host:7655//download/pulse-agent which incorrectly match
the frontend route instead of the download endpoint.
2025-12-29 14:57:28 +00:00
rcourtman
277aca3e4e fix: Only log 'Migration complete' when inline allowed_nodes actually migrated. Related to Discussion #946
The sensor proxy self-heal script runs every 5 minutes and calls migrate-to-file.
Previously it would print 'Migration complete' every time, even when already in
file mode with nothing to migrate.

Now migrateInlineToFile returns a boolean indicating if migration actually
occurred, and the CLI only prints the message when work was done.
2025-12-29 14:15:57 +00:00
rcourtman
4ce1d551e4 fix: Deduplicate disks by device+total to fix Synology storage overcounting. Related to #953
Synology NAS creates multiple shared folders (e.g., /volume1/docker, /volume1/photos)
that are all mount points on the same underlying BTRFS volume. Each reported the same
16TB total, causing Pulse to show 64TB+ instead of 16TB.

The fix tracks device+total combinations and only counts each unique pair once.
When duplicates are found, the shallowest mountpoint (e.g., /volume1) is preferred.

Added a unit test to verify the deduplication works correctly.
2025-12-29 14:03:32 +00:00
rcourtman
fd1f94babf fix: AI Commands toggle now updates immediately in UI. Related to #952
Previously, toggling AI Commands in the Agents view would show a pending state
and wait for the agent to confirm the change (up to 2 minutes). If the agent
was slow to report or the WebSocket update was missed, the toggle would appear
stuck.

Now, UpdateHostAgentConfig also updates the Host model in state immediately,
providing instant UI feedback. The agent will still receive the config on its
next report, but users see the change right away.

Added SetHostCommandsEnabled function to models.State for this purpose.
2025-12-29 13:56:29 +00:00
rcourtman
053a40d7df fix: Docker container update detection showing false positives
Fixed an issue where all Docker containers were showing 'click to update'
even when they were up to date. The root cause was comparing the wrong
digest types:

- Previously: Compared ImageID (local config hash) vs registry manifest digest
- Now: Uses RepoDigests from image inspect, which is the actual manifest
  digest that Docker received from the registry when pulling the image

For multi-arch images, the registry returns a manifest list digest, while
Docker stores the platform-specific image config digest locally. These
will never match, causing false positives for all multi-arch images.

Changes:
- Added ImageInspectWithRaw to dockerClient interface
- Added getImageRepoDigest method to extract RepoDigest from image
- Added matchesImageReference helper for Docker Hub naming conventions
- Added tests for matchesImageReference

Fixes #955
2025-12-29 13:49:04 +00:00
rcourtman
a4611739a9 fix: Hosts page not updating in real-time (SolidJS reactivity bug)
Fixed a critical reactivity bug in HostsOverview.tsx where the HostRow
component was destructuring props.host in the function body. In SolidJS,
this breaks reactivity because the destructured value is a static snapshot
captured at component creation time.

Changes:
- Removed 'const { host } = props' destructuring in HostRow
- Changed all 'host.' references to 'props.host.' to maintain reactivity
- Converted cpuPercent and diskStats to reactive getters (functions)
- Added documentation comment explaining why destructuring breaks reactivity

This fixes Issue #949 where CPU, memory, and disk values on the Hosts
page would stay stale until manual page refresh.

Related to #949
2025-12-29 11:45:45 +00:00
rcourtman
de36b2bc02 Auto-update Helm chart version to 5.0.6 2025-12-29 10:51:52 +00:00
rcourtman
4b75c81c47 Auto-update Helm chart documentation 2025-12-29 10:51:52 +00:00
rcourtman
46a7b7d10a docs: Add prominent VERSION file warning to GEMINI.md
- Add critical release section at top of file
- Make VERSION file requirement impossible to miss
- Explain that version_guard job will fail if VERSION doesn't match
2025-12-29 10:11:38 +00:00
rcourtman
3b506e3ecb docs: Add Docker container update documentation
- Document the new one-click container update feature
- Explain update detection, safety features, and requirements
- Bump VERSION to 5.0.6 for release
2025-12-29 10:06:34 +00:00
rcourtman
44fa50eed7 feat(dockeragent): improve test coverage and refactor registry dependencies
- Add comprehensive test coverage for agent report, flush buffer, and deps
- Expand flow, HTTP, CPU, and swarm test coverage
- Refactor registry access to use deps interface for better testability
- Add container update and self-update test scenarios
2025-12-29 09:57:45 +00:00
rcourtman
545990e48f feat: Allow reverting dismissed AI alerts from suppression rules
- Add Undismiss() method to FindingsStore to revert dismissed findings
- Include all dismissed findings in GetSuppressionRules() (not just suppressed)
- Add DismissedReason field to SuppressionRule struct
- Update DeleteSuppressionRule to handle dismissed (non-suppressed) findings
- Update frontend to show dismissal type badges (Suppressed/Expected/Noted)
- Change 'Delete' button to 'Reactivate' for dismissed findings

Related to #950
2025-12-29 09:44:36 +00:00
rcourtman
32111c7837 feat: Add --report-ip flag for multi-NIC systems (issue #945)
Allows specifying which IP address the agent should report, useful for:
- Multi-homed systems with separate management networks
- Systems with private monitoring interfaces
- VPN/overlay network scenarios

Usage:
  pulse-agent --report-ip 192.168.1.100
  PULSE_REPORT_IP=192.168.1.100 pulse-agent
2025-12-29 09:28:28 +00:00
rcourtman
ae1c39960f fix: Remove duplicate AI chat response streaming (issue #947)
Content was being streamed twice:
1. During each iteration of the tool loop (intended for intermediate feedback)
2. Again after the loop ended with finalContent (redundant)

This caused duplicate responses when using Ollama and other providers.
2025-12-29 09:18:05 +00:00
rcourtman
2bf8e044df feat: Add Docker container update capability
- Add container update command handling to unified agent
- Agent can now receive update_container commands from Pulse server
- Pulls latest image, stops container, creates backup, starts new container
- Automatic rollback on failure
- Backup container cleaned up after 5 minutes
- Added comprehensive test coverage for container update logic
2025-12-29 09:00:40 +00:00
rcourtman
3040800e7b fix: AI Patrol now respects exact user-configured thresholds
BREAKING CHANGE: AI Patrol now uses EXACT alert thresholds by default
instead of warning 5-15% before the threshold.

Changes:
- Default behavior: Patrol warns at your configured threshold (e.g., 96% = warns at 96%)
- New setting: 'use_proactive_thresholds' enables the old early-warning behavior
- API: Added use_proactive_thresholds to GET/PUT /api/settings/ai
- Backend: Added SetProactiveMode/GetProactiveMode to PatrolService
- Backend: Added GetThresholds to PatrolService for UI display
- Tests: Updated and added tests for both exact and proactive modes
- Also fixed unused imports in dockeragent/agent.go

When proactive mode is disabled (default):
- Watch: threshold - 5% (slight buffer)
- Warning: exact threshold

When proactive mode is enabled:
- Watch: threshold - 15%
- Warning: threshold - 5%

Related to #951
2025-12-29 08:40:34 +00:00
rcourtman
35a83afbcb fix: Filter overlay filesystems from disk metrics
Docker overlay filesystems were being counted as separate disks when
monitoring hosts running Docker. These are virtual layers, not actual
storage.

Added overlay and overlayfs to the virtualFSTypes list so they are
always excluded from disk usage calculations, regardless of their
reported usage percentage.

NFS and CIFS mounts were already being filtered correctly.

Related to #942
2025-12-28 16:12:18 +00:00
rcourtman
6f794753ee fix: Add Public URL setting for email notifications
Docker deployments with custom port mappings would show incorrect URLs
in email alerts because the auto-detection couldn't determine the
external port.

Added a "Public URL" setting in Settings > Network that allows users
to configure the dashboard URL used in email notifications.

- Added publicURL field to SystemSettings (persistence.go)
- Load/save publicURL in system settings handler
- Apply publicURL to notification manager on change
- Added UI input in NetworkSettingsPanel
- Shows env override warning if PULSE_PUBLIC_URL is set

Related to #944
2025-12-28 16:08:22 +00:00
rcourtman
76990a65a7 fix: Preserve user's configured hostname when agent registers with IP
When a node was manually added with a hostname (e.g., pve.example.com)
and then the agent registered using its IP address, the code would
correctly deduplicate but incorrectly overwrite the user's configured
hostname with the agent's IP.

Now when matching by IP resolution (hostname resolves to agent's IP),
we preserve the user's original hostname configuration instead of
replacing it with the IP.

Related to #940
2025-12-28 15:44:40 +00:00
rcourtman
9f3367da36 fix: Include GuestURL in NodeFrontend for cluster node navigation
The GuestURL field was missing from NodeFrontend and its converter,
causing configured Guest URLs to be ignored when clicking on cluster
node names. The frontend would fall back to the auto-detected IP
instead of using the user-configured Guest URL.

Related to #940
2025-12-28 14:49:49 +00:00
rcourtman
282b7a73cb fix: Allow deleting all digits in SMTP port field
The port field would immediately jump back to 587 when trying to clear
it because parseInt("") returns NaN, and NaN || 587 becomes 587.

Now the field allows empty values while typing, and only applies the
default (587) when the field loses focus with an invalid value.

Related to #935
2025-12-28 10:30:56 +00:00
rcourtman
ac1cc1e0a9 fix: Change email TLS/STARTTLS to mutually exclusive dropdown
TLS and STARTTLS are mutually exclusive encryption methods:
- TLS (port 465): Implicit encryption from connection start
- STARTTLS (port 587): Starts unencrypted, upgrades to TLS
- None (port 25): No encryption

Having both as independent checkboxes allowed invalid configurations.
Now uses a single dropdown with the three options.

Related to #936
2025-12-28 10:28:43 +00:00
rcourtman
9063695cba fix: Preserve alert acknowledgement across transient clears
When a powered-off VM is backed up by Proxmox, the VM status briefly
changes (e.g., to "running" during backup). This caused the powered-off
alert to be cleared, deleting the ackState record. When the backup
completed and the alert was recreated, it appeared as a new unacknowledged
alert, generating a new notification.

The fix preserves ackState when alerts are removed, allowing
preserveAlertState to restore the acknowledgement when the same alert
reappears. Stale ackState entries (for alerts that don't exist) are
cleaned up after 1 hour.

Related to #937
2025-12-28 10:24:04 +00:00
rcourtman
7f8c9e37b1 fix: Preserve webhook headers when toggling enable/disable
When GetWebhooks returns webhooks, headers and customFields are masked
with ***REDACTED*** for security. However, when the frontend toggled
a webhook's enabled state, it sent back the redacted values, which
overwrote the actual header values (like Authorization tokens).

This broke webhooks after disabling and re-enabling them, as the auth
headers were replaced with "***REDACTED***".

Now UpdateWebhook detects redacted values and preserves the original
headers/customFields from the existing webhook.

Related to #938
2025-12-28 10:19:32 +00:00
rcourtman
3025e5ba91 fix(docker): cross-compile main pulse binary for arm64
The previous commit forced the builder stage to linux/amd64 to avoid
QEMU timeouts, but forgot to add explicit GOARCH for the main pulse
binary. This caused amd64 binaries to be shipped in arm64 images,
resulting in "Exec format error" on ARM64 hosts.

Now the main pulse binary is cross-compiled for both amd64 and arm64
(like all the agent binaries already were), and the runtime stage
selects the correct binary based on TARGETARCH.

Related to #933
2025-12-28 09:52:31 +00:00
rcourtman
056f503516 test: Add comprehensive tests for update detection system
- Add registry checker tests (caching, enable/disable, parsing, concurrency)
- Add alert integration tests for update detection and Pro license gating
- Add API handler tests for /api/infra-updates endpoints
- Test cleanup of tracking maps when containers are removed
- Test threshold-based alerting behavior
2025-12-27 18:54:48 +00:00
rcourtman
d1a8383cd5 feat: Gate update alerts as Pro-only feature
- Add FeatureUpdateAlerts constant for Pro license gating
- Add feature to all Pro tier feature lists
- Add SetLicenseChecker method to alerts Manager
- Check Pro license in checkDockerContainerImageUpdate before alerting
- Wire license checker from router to alert manager

Free users still see update badges in the UI.
Pro users get proactive alerts after 24h of pending updates.
2025-12-27 18:28:09 +00:00