Commit Graph

1202 Commits

Author SHA1 Message Date
rcourtman
ee63d438cc docs: standardize markdown syntax and remove deprecated sensor-proxy docs 2026-01-20 09:43:49 +00:00
rcourtman
1c22688d9b fix: standardize API version format and guest key separators
Closes #1115 (discussion feedback)

Two API consistency issues reported by @FabienD74:

1. Version format mismatch in /api/version:
   - currentVersion: "5.0.16" (no prefix)
   - latestVersion: "v5.0.16" (with prefix)

   Fixed: LatestVersion now strips the "v" prefix to match CurrentVersion format.

2. Guest ID separator inconsistency:
   - Some code used colons: "instance:node:vmid"
   - BuildGuestKey used dashes: "instance-node-vmid"

   Fixed: BuildGuestKey now uses colon separator matching the canonical
   format used by makeGuestID in the monitoring package. The existing
   legacy migration in GetWithLegacyMigration handles old dash-format
   entries in guest_metadata.json.
2026-01-19 22:20:18 +00:00
rcourtman
a6a8efaa65 test: Add comprehensive test coverage across packages
New test files with expanded coverage:

API tests:
- ai_handler_test.go: AI handler unit tests with mocking
- agent_profiles_tools_test.go: Profile management tests
- alerts_endpoints_test.go: Alert API endpoint tests
- alerts_test.go: Updated for interface changes
- audit_handlers_test.go: Audit handler tests
- frontend_embed_test.go: Frontend embedding tests
- metadata_handlers_test.go, metadata_provider_test.go: Metadata tests
- notifications_test.go: Updated for interface changes
- profile_suggestions_test.go: Profile suggestion tests
- saml_service_test.go: SAML authentication tests
- sensor_proxy_gate_test.go: Sensor proxy tests
- updates_test.go: Updated for interface changes

Agent tests:
- dockeragent/signature_test.go: Docker agent signature tests
- hostagent/agent_metrics_test.go: Host agent metrics tests
- hostagent/commands_test.go: Command execution tests
- hostagent/network_helpers_test.go: Network helper tests
- hostagent/proxmox_setup_test.go: Updated setup tests
- kubernetesagent/*_test.go: Kubernetes agent tests

Core package tests:
- monitoring/kubernetes_agents_test.go, reload_test.go
- remoteconfig/client_test.go, signature_test.go
- sensors/collector_test.go
- updates/adapter_installsh_*_test.go: Install adapter tests
- updates/manager_*_test.go: Update manager tests
- websocket/hub_*_test.go: WebSocket hub tests

Library tests:
- pkg/audit/export_test.go: Audit export tests
- pkg/metrics/store_test.go: Metrics store tests
- pkg/proxmox/*_test.go: Proxmox client tests
- pkg/reporting/reporting_test.go: Reporting tests
- pkg/server/*_test.go: Server tests
- pkg/tlsutil/extra_test.go: TLS utility tests

Total: ~8000 lines of new test code
2026-01-19 19:26:18 +00:00
rcourtman
d06ed2edb3 refactor: Add testability improvements to core packages
hostagent/commands.go:
- Extract execCommandContext as mockable variable

hostagent/proxmox_setup.go:
- Convert stateFilePath constants to variables (testable)
- Extract runCommand and lookPath as mockable functions
- Add duplicate comment (minor cleanup needed)

notifications/notifications.go:
- Add GetQueueStats() method for interface compliance
- Used by NotificationMonitor interface

updates/manager.go:
- Add AddSSEClient, RemoveSSEClient, GetSSECachedStatus methods
- Enables interface-based SSE client management

pkg/audit/export.go:
- Minor testability improvements

go.mod/go.sum:
- Add stretchr/objx v0.5.2 (test mocking dependency)
2026-01-19 19:25:38 +00:00
rcourtman
dc16c94766 fix: Add robustness improvements to approval, auth, and server
approval/store.go:
- Make Approve() idempotent - return success if already approved
- Handles double-clicks and race conditions gracefully

auth.go:
- Add dev mode admin bypass (disabled by default)
- When ALLOW_ADMIN_BYPASS=1, sets X-Authenticated-User header

server.go:
- Call router.StopOpenCodeAI() during shutdown
- Ensures AI service stops cleanly on server termination
2026-01-19 19:24:45 +00:00
rcourtman
f478046696 refactor(api): Add interfaces to handlers for testability
Extract interfaces from concrete monitor type dependencies:

alerts.go:
- Add AlertManager, ConfigPersistence, AlertMonitor interfaces
- Change AlertHandlers to accept AlertMonitor interface

notifications.go:
- Add NotificationManager, NotificationConfigPersistence interfaces
- Add NotificationMonitor interface
- Change NotificationHandlers to accept NotificationMonitor interface

updates.go:
- Add UpdatesMonitor interface
- Change UpdatesHandlers to accept interface

audit_handlers.go:
- Update to use interface-based injection

profile_suggestions.go:
- Minor interface alignment

Benefits:
- Handlers can now be tested with mock implementations
- Decouples handlers from concrete monitoring.Monitor type
- Works with monitor_wrappers.go added in previous commit
2026-01-19 19:21:46 +00:00
rcourtman
5dc0177ec2 refactor(ai): Rename findings adapter and add chat patrol alias
- Rename findings_mcp_adapter.go -> findings_tools_adapter.go
- Update imports from mcp to tools package
- Add findings_tools_adapter_test.go with basic tests
- Add SetChatPatrol method as alias for SetOpenCodePatrol
  (maintains API compatibility during transition)
2026-01-19 19:20:49 +00:00
rcourtman
ffb8928dbf refactor(api): Update handlers for native AI chat service
Adapts API handlers to use the new native chat service:

ai_handler.go:
- Replace opencode.Service with chat.Service
- Add AIService interface for testability
- Add factory function for service creation (mockable)
- Update provider wiring to use tools package types

ai_handlers.go:
- Add Notable field to model list response
- Simplify command approval - execution handled by agentic loop
- Remove inline command execution from approval endpoint

router.go:
- Update imports: mcp -> tools, opencode -> chat
- Add monitor wrapper types for cleaner dependency injection
- Update patrol wiring for new chat service

agent_profiles:
- Rename agent_profiles_mcp.go -> agent_profiles_tools.go
- Update imports for tools package

monitor_wrappers.go:
- New file with wrapper types for alert/notification monitors
- Enables interface-based dependency injection
2026-01-19 19:20:00 +00:00
rcourtman
0f5807d0f9 refactor(ai): Remove deprecated opencode sidecar package
The opencode package implemented the old architecture where:
- Pulse ran an OpenCode subprocess as a sidecar
- AI messages were proxied through OpenCode
- OpenCode connected back to Pulse's MCP server for tool access

This is now replaced by the native chat service (internal/ai/chat)
which calls AI providers directly and executes tools inline.

Removed files:
- sidecar.go: OpenCode process management
- service.go: Message proxying and session management
- client.go: HTTP client for OpenCode API
- bridge.go: MCP tool bridging
- patrol.go: Patrol context extraction
- *_test.go: Associated tests

Benefits of new architecture:
- No external subprocess dependency
- Direct streaming from AI providers
- Lower latency (no proxy hop)
- Simpler deployment
2026-01-19 19:18:14 +00:00
rcourtman
17ca31a557 refactor(ai): Replace mcp package with tools package for direct tool execution
This refactoring removes the MCP (Model Context Protocol) server layer and
converts AI tools to be called directly by the chat service.

Key changes:
- Rename package from internal/ai/mcp to internal/ai/tools
- Remove server.go - tools no longer exposed via MCP server
- Tools are now called directly by the chat service via ExecuteTool()

New tools added:
- Kubernetes: clusters, nodes, pods, deployments (4 tools)
- PMG: mail gateway status, mail stats, queues, spam stats (4 tools)
- Infrastructure: snapshots, PBS jobs, backup tasks, network stats,
  disk I/O, cluster status, swarm, services, tasks, recent tasks,
  physical disks, RAID status, host Ceph, resource disks (14 tools)
- Patrol: connection health, resolved alerts (2 tools)

Test coverage:
- Added comprehensive test files for adapters, infrastructure,
  patrol, profiles, and query tools

Total tools: 50 (was ~25)
2026-01-19 19:17:24 +00:00
rcourtman
5ff4f97a0d feat(ai): Add native chat service with streaming and tool execution
Replace the OpenCode sidecar with a native chat service that handles:
- Real-time streaming responses from AI providers
- Multi-turn conversation sessions with history
- Tool execution with automatic function calling
- Agentic workflows for autonomous task completion
- Patrol integration for automated health analysis

The chat service directly communicates with AI providers using the
new StreamingProvider interface, eliminating the need for an external
sidecar process. Sessions are managed in-memory with configurable
history limits.

Key components:
- service.go: Main chat service with provider integration
- session.go: Session management and message history
- agentic.go: Agentic loop for autonomous tool execution
- patrol.go: Patrol-specific chat context and analysis
- tools.go: Tool execution bridge to tools package
- types.go: Chat message and event type definitions
2026-01-19 19:12:04 +00:00
rcourtman
4fe3d7df77 feat(ai): Add streaming support and notable models to AI providers
- Add ChatStream method to all providers (Anthropic, OpenAI, Gemini, Ollama)
  for real-time streaming of AI responses with tool call support
- Add StreamingProvider interface with StreamEvent types for content,
  thinking, tool_start, tool_end, done, and error events
- Add notable models feature that fetches model metadata from models.dev
  to identify recent/recommended models (within last 3 months)
- Add Notable field to ModelInfo struct to flag "latest and greatest" models
- Add SupportsThinking method to check for extended reasoning capability

The streaming support enables real-time AI chat responses instead of
waiting for complete responses. The notable models feature helps users
identify which models are current and recommended.
2026-01-19 19:10:58 +00:00
rcourtman
17dec929a0 feat: Add mention support for webhook alerts. Related to #1118
Adds a Mention field to webhook configurations that allows users to tag
individuals or groups when alerts are sent. This works with:

- Discord: @everyone, <@USER_ID>, <@&ROLE_ID>
- Microsoft Teams: @General, user email
- Mattermost: @channel, @all, @username

The mention is included in the webhook payload via the {{.Mention}} template
variable. Built-in templates for Discord, Slack, and Teams now conditionally
include mentions when configured.

Backend changes:
- Add Mention field to WebhookConfig struct
- Add Mention field to WebhookPayloadData for template access
- Pass mention through sendGroupedWebhook

Frontend changes:
- Add mention field to Webhook interface
- Add Mention input to webhook configuration form
- Show service-specific help text for mention formats
2026-01-18 15:16:37 +00:00
rcourtman
71bcc570ad fix: Add nil checks in findDuplicate() to prevent crash. Related to #1119
When a resource exists in the hostname or IP index but has been removed from
the main resources map, looking up and accessing .Type would cause a nil
pointer dereference panic.

The MachineID lookup already had this check, but hostname and IP lookups
were missing it. This adds consistent nil checking across all three lookup
paths.
2026-01-18 13:41:00 +00:00
rcourtman
204a9fe084 perf: Cache agent profiles to prevent disk I/O on every report. Related to #1094
GetHostAgentConfig was loading profiles and assignments from disk on
every agent report (every 10-30 seconds per host). With multiple hosts,
this caused disk I/O contention that eventually led to request timeouts.

Added in-memory caching with 60-second TTL:
- Fast path reads from cache without locks when valid
- Double-checked locking pattern for cache refresh
- Cache auto-invalidates after TTL, no manual invalidation needed
2026-01-17 22:31:02 +00:00
rcourtman
432f13b6f5 feat(ai): add Docker update management MCP tools
Add three new MCP tools for Docker container update management:
- pulse_list_docker_updates: list containers with pending updates
- pulse_check_docker_updates: trigger update check on a host
- pulse_update_docker_container: apply update with approval workflow

Changes:
- Add UpdatesProvider interface to executor.go
- Add response types to data_types.go
- Add UpdatesMCPAdapter to adapters.go
- Register tools and handlers in tools_infrastructure.go
- Add SetUpdatesProvider() to service.go
- Wire provider in router.go wireOpenCodeProviders()
2026-01-17 15:47:36 +00:00
rcourtman
4cea85ec97 feat(mcp): expand MCP tools and add session management APIs
New API endpoints:
- POST /api/ai/sessions/{id}/summarize - Compress context
- GET /api/ai/sessions/{id}/diff - Get file changes
- POST /api/ai/sessions/{id}/fork - Branch conversation
- POST /api/ai/sessions/{id}/revert - Undo changes
- POST /api/ai/sessions/{id}/unrevert - Restore reverted changes

MCP provider wiring:
- Storage, backup, disk health providers
- Metrics history, baseline, pattern detection
- Findings manager and metadata updater

Tool improvements:
- pulse_get_topology: Unified infrastructure view
- Improved tool descriptions with usage examples
- Better license checking with logging
2026-01-17 14:43:58 +00:00
rcourtman
c26f0e6e6c feat(ai): improve OpenCode integration and control level handling
OpenCode client improvements:
- Fix session listing with proper timestamp parsing
- Model selection with provider inference (anthropic, google, etc)
- Add session management APIs (summarize, diff, fork, revert)
- Generated session titles from first user message

Control level refactoring:
- IsAutonomous() helper for cleaner checks
- Legacy autonomous_mode maps to control_level for backwards compat
- Simplified system instructions (rely on tool descriptions instead)

Includes tests for model provider inference.
2026-01-17 14:43:28 +00:00
rcourtman
103eb9c3e0 feat(monitoring): auto-detect Docker inside LXC containers
Adds automatic Docker detection for Proxmox LXC containers:
- New HasDocker and DockerCheckedAt fields on Container model
- Docker socket check via connected agents on first run, restart, or start
- Parallel checking with timeouts for efficiency
- Caches results and only re-checks after state transitions

This enables the AI to know which LXC containers are Docker hosts
for better infrastructure guidance.
2026-01-17 14:42:52 +00:00
rcourtman
3512069965 feat(license): grant Pro features in dev mode
Extends the demo mode behavior to also apply when PULSE_DEV=true,
allowing developers to test Pro features during development without
requiring a license key.
2026-01-17 14:42:27 +00:00
rcourtman
3096ec53b5 fix: preserve alert activation state when saving config. Related to #1096 2026-01-16 14:24:02 +00:00
rcourtman
035436ad6e fix: add mutex to prevent concurrent map writes in Docker agent CPU tracking
The agent was crashing with 'fatal error: concurrent map writes' when
handleCheckUpdatesCommand spawned a goroutine that called collectOnce
concurrently with the main collection loop. Both code paths access
a.prevContainerCPU without synchronization.

Added a.cpuMu mutex to protect all accesses to prevContainerCPU in:
- pruneStaleCPUSamples()
- collectContainer() delete operation
- calculateContainerCPUPercent()

Related to #1063
2026-01-15 21:10:55 +00:00
rcourtman
a7de907c35 chore: remove internal planning doc, add gitignore patterns
- Remove docs/AGENTS_AI_SCOPE_PLAN.md (internal dev doc)
- Add gitignore patterns for *_PLAN.md, *_ROADMAP.md, *IMPLEMENTATION*.md in docs/
2026-01-15 13:53:42 +00:00
rcourtman
8c7581d32c feat(profiles): add AI-assisted profile suggestions
Add ability for users to describe what kind of agent profile they need
in natural language, and have AI generate a suggestion with name,
description, config values, and rationale.

- Add ProfileSuggestionHandler with schema-aware prompting
- Add SuggestProfileModal component with example prompts
- Update AgentProfilesPanel with suggest button and description field
- Streamline ValidConfigKeys to only agent-supported settings
- Update profile validation tests for simplified schema
2026-01-15 13:24:18 +00:00
rcourtman
9b49d3171d feat(pbs): add datastore exclusion to reduce PBS log noise
Users with removable/unmounted datastores (e.g., external HDDs for
offline backup) experienced excessive PBS log entries because Pulse
was querying all datastores including unavailable ones.

Added `excludeDatastores` field to PBS node configuration that accepts
patterns to exclude specific datastores from monitoring:
- Exact names: "exthdd1500gb"
- Prefix patterns: "ext*"
- Suffix patterns: "*hdd"
- Contains patterns: "*removable*"

Pattern matching is case-insensitive.

Fixes #1105
2026-01-14 12:26:18 +00:00
rcourtman
3e74e689cd fix(api): increase Docker agent report size limit from 512KB to 2MB
Users with 100+ containers were hitting the payload size limit,
causing "Failed to decode request body" 400 errors. This aligns
the Docker agent limit with the Kubernetes agent limit (2MB).

Fixes #1104
2026-01-14 12:20:39 +00:00
rcourtman
038b57ee43 feat(ai): proxy OpenCode API paths for iframe embedding
OpenCode's frontend uses window.location.origin for API calls. When
embedded in Pulse's iframe, this points to Pulse instead of OpenCode.

This commit proxies OpenCode's API paths through Pulse:
- /global/, /session/, /tui/, /config/, /file/, /find/, /instance/,
  /mcp/, /permission/, /project/, /provider/, /pty/, /question/,
  /experimental/

Changes:
- router.go: Add OpenCode API paths to route check and register handlers
- ai_handler.go: Add HandleOpenCodeAPI to proxy requests to OpenCode
- vite.config.ts: Add proxy entries for OpenCode API paths
- AIChat.tsx: Revert to iframe approach now that proxying works
- ThinkingBlock.tsx: Make collapsible for better UX
2026-01-14 10:52:33 +00:00
rcourtman
7f9995adf3 fix(ai): rewrite OpenCode asset paths for iframe embedding
OpenCode's HTML uses absolute paths like /assets/... for static files.
When embedded in Pulse's iframe, these paths don't go through the
/opencode/ proxy and fail to load.

Modified the proxy's ModifyResponse to rewrite src="/" and href="/"
attributes in HTML responses to include the /opencode/ prefix, ensuring
all assets load correctly through the proxy.
2026-01-14 10:35:37 +00:00
rcourtman
875d244b66 fix(ai): allow OpenCode UI to be embedded in iframe
The OpenCode reverse proxy now properly modifies response headers to
allow iframe embedding within Pulse's AI panel:

- ai_handler.go: Add ModifyResponse to strip X-Frame-Options and modify
  CSP frame-ancestors from OpenCode's responses
- security.go: Skip frame-related security headers for /opencode/ paths
  since the proxy manages its own headers

This fixes the "refused to connect" error when opening the AI sidebar.
2026-01-14 10:28:30 +00:00
rcourtman
316c3cbb6f feat(ai): embed OpenCode web UI in Pulse AI panel
Replace custom Chat components with an iframe that embeds OpenCode's
native web UI. This provides a more polished experience and automatically
benefits from OpenCode improvements.

Changes:
- Add reverse proxy for /opencode/ route to OpenCode's web server
- Simplify AIChat component to iframe wrapper with header
- Add GetBaseURL() method to OpenCode service
- Configure Vite proxy for development

The Pulse Pro value proposition is now: managed OpenCode deployment
with rich MCP tools that provide infrastructure context.
2026-01-14 09:53:02 +00:00
rcourtman
9cd53814a3 feat(alerts): add per-volume disk thresholds for host agents
Allow users to set custom disk usage thresholds per mounted filesystem
on host agents, rather than applying a single threshold to all volumes.

This addresses NAS/NVR use cases where some volumes (e.g., NVR storage)
intentionally run at 99% while others need strict monitoring.

Backend:
- Check for disk-specific overrides before using HostDefaults.Disk
- Override key format: host:<hostId>/disk:<mountpoint>
- Support both custom thresholds and disable per-disk

Frontend:
- Add 'hostDisk' resource type
- Add "Host Disks" collapsible section in Thresholds → Hosts tab
- Group disks by host for easier navigation

Closes #1103
2026-01-13 23:38:20 +00:00
rcourtman
d73e57af86 Initialize SQLite audit logger for Pro license with audit_logging feature
The audit logging feature was showing the UI for Pro users but the
SQLiteLogger was never actually initialized - it fell back to the
ConsoleLogger which only writes to console and returns empty arrays
for queries.

This fix:
- Adds initAuditLoggerIfLicensed() helper to license_handlers.go
- Calls it when loading a persisted license at startup
- Calls it when activating a new license via API
- Creates SQLiteLogger with 90-day default retention when audit_logging
  feature is enabled

The audit.db will be created in {dataDir}/audit/ when Pro is licensed.
2026-01-13 10:06:48 +00:00
rcourtman
b177812fd3 revert: remove accidentally committed WIP OpenCode changes
Reverts unintended changes from 4e064aa0 that broke the frontend build.
The workflow fix for cmd/pulse package build remains intact.
2026-01-13 09:15:42 +00:00
rcourtman
4e064aa0cc fix: build entire cmd/pulse package, not just main.go
The static binary build was only compiling main.go, missing bootstrap.go
and config.go which define osExit, bootstrapTokenCmd, and configCmd.
2026-01-13 09:06:21 +00:00
rcourtman
d389345153 fix(hosts): calculate Used memory from Total-Free for host agents in LXC
The previous fix (4090d981) addressed memory reporting for Docker agents
running in LXC containers, but the same issue also affects host agents.
When gopsutil runs inside an LXC, it can read Total and Free memory
from cgroup limits, but reports 0 for Used memory.

Added the same Total - Free fallback calculation to the host agent
processing path, which populates the Hosts tab.

Fixes #1075
2026-01-12 21:19:40 +00:00
rcourtman
da6ee7b1a6 feat(sso): implement SAML session storage for Single Logout support
- Add SAML session fields (ProviderID, NameID, SessionIndex) to
  SessionData and sessionPersisted structs for persistence
- Add CreateSAMLSession method to store SAML-authenticated sessions
- Add GetSAMLSessionInfo method to retrieve SAML session data
- Update establishSAMLSession to properly store SAML info instead
  of delegating to OIDC session creation
- Implement getSAMLSessionInfo to retrieve session info for SLO

This enables proper SAML Single Logout by storing the NameID and
SessionIndex from the SAML assertion, which are required to construct
valid LogoutRequest messages to the IdP.
2026-01-12 16:37:07 +00:00
rcourtman
2fdf7906e6 feat(models): add agent profile validation
- Add profile validation for agent configuration
- Implement validation rules for profile fields
2026-01-12 15:21:05 +00:00
rcourtman
3febd3266e feat(ai): add approval store and dry-run simulator for AI Auto-Fix
- Add approval store for tracking AI-suggested changes
- Implement SQLite-backed persistence for approvals
- Add dry-run simulator for testing AI fixes safely
- Support simulated execution with rollback capability
2026-01-12 15:20:16 +00:00
rcourtman
97701297c4 feat(sso): add SAML 2.0 and multi-provider SSO support
- Add SAML 2.0 Service Provider implementation using crewjam/saml
- Support IdP metadata from URL or raw XML
- Add multi-provider SSO configuration model
- Implement provider management API (CRUD operations)
- Add provider connection testing endpoint
- Add IdP metadata preview endpoint
- Add SSOProvidersPanel component for settings UI
- Support attribute-based role mapping (groups → Pulse roles)

API endpoints:
- GET/POST /api/security/sso/providers - List/create providers
- GET/PUT/DELETE /api/security/sso/providers/{id} - Provider CRUD
- POST /api/security/sso/providers/test - Test connection
- POST /api/security/sso/providers/metadata/preview - Preview metadata
- /api/saml/{id}/login, /acs, /metadata, /logout, /slo - SAML endpoints
2026-01-12 15:19:59 +00:00
rcourtman
1dda538265 fix(models): extend namespace disambiguation to SyncGuestBackupTimes (#1095)
The previous commit fixed namespace disambiguation for backup alerts,
but the Overview display uses SyncGuestBackupTimes to populate backup
timestamps on VMs/Containers. This commit extends the same namespace
matching logic to that function.

Also tightened the matching algorithm to use suffix matching instead
of substring matching, preventing false positives like "pve" matching
"pve-nat".
2026-01-12 15:11:59 +00:00
rcourtman
a88edd7c8f fix(alerts): disambiguate PBS backups using namespace for multi-PVE setups (#1095)
When multiple PVE instances have VMs with overlapping VMIDs, PBS backups
were being matched to the wrong VM because the code would just use the
first matching guest. Now when a PBS backup has a namespace, it attempts
to match that namespace to the PVE instance name to find the correct VM.

This helps users who have separate PBS instances backing up different
PVE clusters with namespaces like "pve1", "nat", etc.
2026-01-12 14:55:17 +00:00
rcourtman
4090d98160 fix(docker): calculate Used memory from Total-Free in Docker-in-LXC
When running Docker inside an LXC container, gopsutil can read the
Total memory (from cgroup limits) and Free memory correctly, but
returns 0 for Used memory. This caused the display to show "0B / 7GB"
even though memory was being used.

Added a fallback that calculates Used = Total - Free when Used is 0
but Total and Free are valid. This completes the fallback chain for
Docker-in-LXC memory reporting.

Fixes #1075
2026-01-12 14:04:38 +00:00
rcourtman
b2a6cd0fa3 fix(agent): add FreeBSD platform support to agent download and UI (#1051)
- Add freebsd-amd64 and freebsd-arm64 to normalizeUnifiedAgentArch()
  so the download endpoint serves FreeBSD binaries when requested
- Add FreeBSD/pfSense/OPNsense platform option to agent setup UI
  with note about bash installation requirement
- Add FreeBSD test cases to unified_agent_test.go

Fixes installation on pfSense/OPNsense where users were getting 404
errors because the backend didn't recognize the freebsd-amd64 arch
parameter from install.sh.
2026-01-11 23:51:12 +00:00
rcourtman
f527e6ebd0 docs: fix Kubernetes DaemonSet deployment guide
Fixes #1091 - addresses all three documentation issues reported:

1. Binary path: Changed from /usr/local/bin/pulse-agent (which doesn't
   exist in the main image) to /opt/pulse/bin/pulse-agent-linux-amd64

2. PULSE_AGENT_ID: Added to example and documented why it's required
   for DaemonSets (prevents token conflicts when all pods share one
   API token)

3. Resource visibility flags: Added PULSE_KUBE_INCLUDE_ALL_PODS and
   PULSE_KUBE_INCLUDE_ALL_DEPLOYMENTS to example, with explanation
   of the default behavior (show only problematic resources)

Also added tolerations, resource requests/limits, and ARM64 note.
2026-01-11 21:43:23 +00:00
rcourtman
8eabd266fc fix(frontend): extend kiosk mode to Docker and Hosts pages
Kiosk mode (?kiosk=1) now hides the filter panel on all main views:
- Proxmox dashboard (already supported)
- Docker hosts page (added)
- Hosts overview page (added)

This ensures a clean display when using token auth for dashboard/kiosk
displays without the search and filter controls visible.

Follow-up fix for #1055
2026-01-11 12:16:20 +00:00
rcourtman
d197955272 feat(notifications): add Mattermost webhook template with rich formatting
Add a dedicated Mattermost webhook template that uses Markdown formatting
in the text field. Unlike Slack (which supports blocks), Mattermost only
renders the "text" field, so this template includes:

- Emoji indicators for alert severity (🚨 critical, ⚠️ warning, ℹ️ info)
- Bold resource name and node
- Markdown table with all alert details
- Link to view alert in Pulse

This provides much more context than the previous Slack template's
fallback text which only showed "Pulse Alert: Critical - <HOSTNAME>".

Addresses #1084
2026-01-11 12:00:39 +00:00
rcourtman
80444a9022 fix(monitor): use cluster quorum status instead of endpoint count for health
Previously, when some cluster endpoints were unreachable (e.g., backup
nodes intentionally offline), the cluster was marked as "degraded" even
though the Proxmox cluster itself was healthy and had quorum.

Now the connection health check queries the Proxmox cluster's actual
quorum status. A cluster is only marked "degraded" if it has lost
quorum (not enough votes for consensus), which is the actual indicator
of cluster instability.

This means:
- Cluster with quorum + some nodes offline = "healthy"
- Cluster without quorum = "degraded" (warning)
- All endpoints down = "error"

Fixes #1085
2026-01-11 11:54:02 +00:00
rcourtman
9cd79daa68 fix(hostagent): prevent data mixing when multiple nodes share hostname
When multiple PVE nodes have the same hostname (e.g., both named "pve"),
auto-linking would incorrectly link all host agents to the first matching
node, causing temperature and sensor data to be mixed/duplicated.

Changes:
- findLinkedProxmoxEntity now detects hostname collisions and refuses
  to auto-link, logging a warning instead
- Added manual link API endpoint (POST /api/agents/host/link) so users
  can explicitly link agents to the correct nodes
- Added State.LinkHostAgentToNode for bidirectional manual linking

Fixes #1081
2026-01-10 23:12:51 +00:00
rcourtman
a978693cb1 fix(dockeragent): use TotalMemoryBytes fallback for memory.Total
The previous fix (4ff9e58c) added a fallback for TotalMemoryBytes in
the agent when Docker's info.MemTotal returns 0 in LXC environments.
However, the server was not using TotalMemoryBytes to populate the
memory.Total field - it only used gopsutil's Memory.TotalBytes.

When gopsutil also fails to read memory in the LXC container, the
frontend would see memory.Total=0 and wouldn't fall back to
totalMemoryBytes due to JavaScript's nullish coalescing (??) only
triggering on null/undefined, not on 0.

This fix ensures the server uses TotalMemoryBytes as a fallback for
memory.Total when gopsutil returns 0, providing a complete fix chain:
1. Agent: Falls back to gopsutil when Docker returns 0
2. Server: Falls back to TotalMemoryBytes when gopsutil returns 0

Fixes #1075
2026-01-10 22:45:41 +00:00
rcourtman
55f5f071ed fix: replace hallucinated upgrade URLs with correct pulserelay.pro
Previous LLM sessions incorrectly inserted fake URLs (pulse.sh/pro and
yourpulse.io/pro) for the Pro upgrade links. Neither domain exists.

Replaced all 34 instances with the correct URL: https://pulserelay.pro/

Fixes #1077
2026-01-10 22:45:40 +00:00