2185 Commits

Author SHA1 Message Date
rcourtman 2b68bfe6ee fix: Update tests for RAID alerting md0/md1 skip and AI gating message change
- RAID tests now use /dev/md2 since md0/md1 are skipped for Synology compatibility
- AI handler tests now expect 'AI is not enabled' message after AI gating change
v5.0.7
2025-12-30 23:39:55 +00:00
rcourtman 336714c610 chore: Bump version to 5.0.7 2025-12-30 23:26:59 +00:00
rcourtman dc65b96e6d fix: Improve light theme contrast for low I/O values. Related to #976
Changed text-gray-300 to text-gray-500 for I/O values under 1 MB/s in light mode.
The previous color was barely visible against the white background.
2025-12-30 22:35:39 +00:00
rcourtman ed6c3d9c93 fix: Prevent acknowledged alerts from retriggering notifications. Related to #975
dispatchAlert() now checks if an alert is already acknowledged before sending
notifications. Previously, acknowledged alerts (especially backup-age alerts)
would continue to dispatch notifications every poll cycle because the
acknowledgement check was missing from the dispatch path.

The fix adds an early return in dispatchAlert() when alert.Acknowledged is true,
matching the existing checks for flapping, activation state, and quiet hours.
2025-12-30 22:20:47 +00:00
rcourtman 5c2db10780 fix: Gate AI subsystems and intelligence endpoints on AI enabled state. Related to #885
- Add IsAIEnabled() method to AISettingsHandler for consistent checks
- Gate baseline learning, pattern detector, and correlation detector initialization
  in StartPatrol() on AI being enabled
- Add AI enabled checks to all /api/ai/intelligence/* endpoints as defense-in-depth
- Return empty results with "AI is not enabled" message when AI is disabled

This ensures no AI-related data is collected, persisted, or returned when AI is disabled,
preventing the "undismissable alerts" issue where old AI findings would appear.
2025-12-30 22:06:07 +00:00
rcourtman 59eca65ff6 fix: Wire up LOG_FILE, LOG_MAX_SIZE, LOG_MAX_AGE, LOG_COMPRESS config options. Related to #979
The logging config options were defined but never passed to logging.Init(),
making the documented file-based log rotation non-functional.
2025-12-30 21:49:26 +00:00
rcourtman 83b2e7c8e2 fix: Add Docker log rotation to prevent unbounded log growth. Related to #979 2025-12-30 21:40:19 +00:00
rcourtman 421ddf027a Fix guest URL editing inconsistencies: unify icons and use Portal for popover 2025-12-30 20:09:58 +00:00
rcourtman 0caf39456d fix: Show copy buttons always visible in Updates settings. Fixes #960. Changed from opacity-0 (hover to show) to opacity-60 (always visible, brighten on hover) for better discoverability. 2025-12-30 12:41:24 +00:00
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 helm-chart-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
v5.0.6
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