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.
- 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
- 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
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
- 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
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)
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
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.
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.
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.
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.
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
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
- 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
- Document the new one-click container update feature
- Explain update detection, safety features, and requirements
- Bump VERSION to 5.0.6 for release
- 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
- 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
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
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.
- 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
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
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
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
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
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
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
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
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
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
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
- 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
- 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.