- crypto.go: Add runtime validation to Encrypt() that verifies the key file
still exists on disk before encrypting. If the key was deleted while Pulse
is running, encryption now fails with a clear error instead of creating
orphaned data that can never be decrypted.
- hot-dev.sh: Auto-generate encryption key for production data directory
(/etc/pulse) when HOT_DEV_USE_PROD_DATA=true and key is missing. This
prevents startup failures and ensures encrypted data can be created.
- Added test TestEncryptRefusesAfterKeyDeleted to verify the protection works.
Release improvements:
- Add standalone Linux agent archives (amd64, arm64, armv7, armv6, 386) to releases
- Previously only Darwin/Windows had standalone agent downloads
Agent version mismatch detection:
- New agentVersion.ts utility compares agent versions against server version
- DockerHostSummaryTable now shows accurate 'outdated' warnings when
agent version is older than the connected Pulse server
- Better tooltips explain version status and upgrade instructions
The installer had a fallback that tried to copy the sensor-proxy binary from
inside the Pulse container using `pct pull`. However, the paths it tried
(/opt/pulse/bin/pulse-sensor-proxy-linux-amd64) don't exist in Pulse containers.
When pct pull fails, Proxmox logs a task error visible in the UI, even though
the error is harmless and expected. This caused recurring "TASK ERROR: failed
to open /opt/pulse/bin/pulse-sensor-proxy-linux-amd64: No such file or directory"
messages every time the selfheal timer ran and couldn't download from GitHub.
The pct pull approach was never going to succeed for LXC-installed Pulse instances
since the binary doesn't exist at those paths inside the container. Removing it
eliminates the spurious error messages.
Related to #817
The PULSE_SENSOR_PROXY_SELFHEAL env var is set to "1", but the check
was only looking for "true", causing selfheal to regenerate itself on
every run. This meant the cached installer would overwrite the selfheal
script with its (potentially older) version, defeating any fixes in
the selfheal script.
Now correctly checks for both "true" and "1".
Related to #849
The selfheal timer was running the full installer every 5 minutes even when
the service was already running and healthy. This caused unnecessary:
- Pulse service restarts
- Config migrations
- Socket setup
- 172MB memory spikes and 15s CPU usage per run
Now the selfheal exits early after checking service health, only proceeding
to reinstall logic if the service is actually failing.
Fixes#849
The selfheal timer was downloading prerelease versions (e.g., v5.0.0-rc.1)
even when users had the stable channel selected. This happened because
fetch_latest_release_tag() didn't filter out prereleases from the GitHub
releases API response.
Now both the Python-based parser and the grep fallback skip prereleases:
- Python: checks `release.get("prerelease")` field
- Grep fallback: filters out -rc, -alpha, -beta patterns
Related to #849
Fixes#819
The installer was hanging at 'Pending control-plane sync detected' because
systemctl start ran synchronously, waiting for the selfheal service to complete.
If the control-plane sync failed or took a long time (e.g., Proxmox node not
configured in Pulse yet), the installer would hang indefinitely.
Changed to use 'systemctl start --no-block' to run the selfheal service
asynchronously in the background. The sync will still be attempted, but the
installer will complete immediately and show the success message.
The container config backup and pct commands could hang indefinitely
when the Proxmox cluster filesystem (pmxcfs) is slow or unresponsive.
This caused the installer to appear to hang after printing
"Configuring socket bind mount..." with no further output.
Added timeout protection to:
- Container config backup cp operation
- pct status check
- pct config verification
- Config rollback cp operation
Related to #738
On TrueNAS, the runtime binary may be in /root/bin or /var/tmp while
the install script only checked INSTALL_DIR (/data/pulse-agent).
This left the running process using the binary when the script tried
to copy a new version, causing "Text file busy" errors.
Now explicitly stop the service and kill any pulse-agent processes
before modifying binaries on TrueNAS systems.
Related to #846
Closes#826
The error messages suggested using --proxy-url but the flag was never
implemented. This adds the flag so users can manually specify the
proxy URL when:
- Auto IP detection produces malformed results
- The desired IP is not the primary IP
- Multi-homed hosts need a specific interface
- Install script now auto-detects Docker, Kubernetes, and Proxmox
- Platform monitoring is enabled automatically when detected
- Users can override with --disable-* or --enable-* flags
- Allow same token to register multiple hosts (one per hostname)
- Update tests to reflect new multi-host token behavior
- Improve CompleteStep and UnifiedAgents UI components
- Update UNIFIED_AGENT.md documentation
The previous fix added legacy cleanup for systemd/macOS but missed the
Unraid-specific section. Now removes pulse-host-agent and pulse-docker-agent
entries from /boot/config/go and cleans up /boot/config/pulse directory.
The --uninstall flag now removes:
- Unified pulse-agent (service, binary, logs)
- Legacy pulse-host-agent (service, binary, logs)
- Legacy pulse-docker-agent (service, binary, logs)
- Agent state directory (/var/lib/pulse-agent)
- All related log files
Works on Linux (systemd), macOS (launchd), and other supported platforms.
- Add host metadata API for custom URL editing on hosts page
- Enhance AI routing with unified resource provider lookup
- Add encryption key watcher script for debugging key issues
- Improve AI service with better command timeout handling
- Update dev environment workflow with key monitoring docs
- Fix resource store deduplication logic
- Add AI service with Anthropic, OpenAI, and Ollama providers
- Add AI chat UI component with streaming responses
- Add AI settings page for configuration
- Add agent exec framework for command execution
- Add API endpoints for AI chat and configuration
On TrueNAS SCALE 24.04+, the root filesystem including /usr/local/bin
is read-only. The installer now tries multiple locations for the
runtime binary:
1. Execute directly from /data (if no noexec mount)
2. /usr/local/bin (older TrueNAS versions)
3. /root/bin (TrueNAS SCALE 24.04+)
4. /var/tmp (last resort)
The bootstrap script is also updated to use the determined runtime
location rather than hardcoding /usr/local/bin.
Related to #801
On systems with net.ipv6.bindv6only=1 (including some Proxmox 8
configurations), using ":8443" results in IPv6-only binding. Users
reported curl to 127.0.0.1:8443 hanging while [::1]:8443 worked.
Changed default from ":8443" to "0.0.0.0:8443" to explicitly bind IPv4.
Related to #805
When using --http-addr 0.0.0.0:8443 (to bind to IPv4 only), the URL
construction was broken, producing URLs like https://192.168.31.110.0.0.0:8443
Now correctly extracts the port number from both ":8443" and "0.0.0.0:8443"
formats using ${HTTP_ADDR##*:} instead of ${HTTP_ADDR#:}
Related to #805
TrueNAS SCALE's /data partition may have exec=off, preventing binaries
from executing. The installer now:
- Stores the binary in /data/pulse-agent/ for persistence
- Copies it to /usr/local/bin (tmpfs, allows exec) for runtime
- Updates the bootstrap script to copy on each boot
Related to #801
Added fallback detection for TrueNAS systems that may not have
/etc/truenas-version or other standard markers:
1. Check if hostname contains "truenas" (common default hostname)
2. Test if /usr/local/bin is actually writable - if not and /data
exists, use TrueNAS installation paths
This fixes installations on TrueNAS systems where the standard
detection files are missing but the filesystem is still immutable.
Related to #801
The SNAPSHOT_START extraction used grep in a pipeline with pipefail
enabled. When a container config has no snapshot sections (no lines
starting with '['), grep returns exit code 1, causing set -e to
terminate the script without any error message.
This affected newly created containers that hadn't been snapshotted yet,
which is the common case for fresh Pulse installations via community
scripts.
Related to #780
The install script was not passing the --enable-host=false flag to the
agent when --disable-host was specified. Since the agent defaults to
enabling host monitoring, it was ignored.
Also adds TrueNAS SCALE support to the unified agent installer:
- Detects TrueNAS SCALE via /etc/truenas-version and other markers
- Installs to /data/pulse-agent (persists across TrueNAS upgrades)
- Creates Init/Shutdown task to restore service after TrueNAS updates
- Adds uninstall support for TrueNAS SCALE
Related to #800, #801
Reading and writing container config from /etc/pve/lxc/ can hang
indefinitely if the Proxmox cluster filesystem (pmxcfs) is slow or
unresponsive. This causes the installer to appear to hang after
"Configuring socket bind mount..." with no further output.
Add 10-second timeouts to both cp operations and provide helpful error
messages suggesting the user check cluster health with 'pvecm status'.
Related to #738
The VERSION variable was hardcoded to v4.32.0 instead of being empty,
which prevented the "fetch latest release" logic from running. When
VERSION is empty, REQUESTED_VERSION defaults to "latest" which triggers
proper release detection via GitHub API.
Related to #738
When running install-sensor-proxy.sh on multiple nodes in a cluster, each
installation was removing all existing pulse-managed-key entries before
adding its own. This caused the following scenario:
1. Run script on node A: node A's key is added to all nodes
2. Run script on node B: node B's key replaces node A's key on all nodes
3. Result: node A's proxy can no longer SSH to other nodes
The fix changes the behavior to:
- Check if the specific SSH key already exists on the target
- Only add the key if not present (idempotent)
- Never remove existing pulse-managed-key entries
This allows multiple sensor-proxy installations to coexist in a cluster,
with each node's proxy key authorized on all nodes.
Related to #738
The previous commit left broken indentation and an orphaned else block
in the cleanup section. This fixes the structure to properly handle
the cluster nodes vs standalone node cases.
Related to #738
Replace brittle pvecm nodes CLI parsing with pvesh API calls. The old
approach used awk field positions ($4) which breaks across Proxmox
versions, locales, or output format changes.
Added get_cluster_node_names() helper that:
- Prefers pvesh get /cluster/status --output-format json (structured)
- Falls back to pvecm nodes CLI parsing if pvesh unavailable
- Uses python3 for JSON parsing (always available on Proxmox)
Related to #738
The awk was using $NF which returns "(local)" on the local node's line
instead of the hostname. Changed to $4 which is the actual hostname field.
Related to #738
For multi-network Proxmox clusters (e.g., separate corosync and
management networks), the installer now uses `pvecm nodes` to get
hostnames and resolves them via /etc/hosts. This automatically
prefers management IPs when the cluster has proper /etc/hosts
configuration.
Falls back to the previous `pvecm status` IP extraction if hostname
resolution doesn't yield results.
Related to #738
Switch from sc.exe create to PowerShell's New-Service cmdlet for
creating the Windows service. New-Service provides better error
handling and is more reliable. Keep sc.exe only for configuring
service recovery options (restart on failure), which New-Service
doesn't support.
Related to #776
Related to #738
Fixes two issues discovered by k5madsen:
1. Missing jq dependency: The sensor wrapper script uses jq extensively to
parse SMART data JSON from smartctl but the installer never checked if
jq was installed. Added jq to REQUIRED_CMDS list.
2. Secondary node support: When running on a secondary Proxmox cluster node
where the container doesn't exist locally, the script now:
- Warns instead of failing with "Container does not exist"
- Continues installation for host temperature monitoring
- Skips container-specific socket mount configuration
This allows users to run the installer on all cluster nodes (as intended)
to ensure the sensor-proxy service is available when containers migrate.
The binPath parameter value needs outer quotes when it contains
embedded quotes and spaces. Without this, SC.EXE parses the value
incorrectly and fails to create the service.
Related to #776
- Add error handling for sc.exe delete in uninstall logic
- Add error handling for legacy agent service deletion
- Add error handling for existing service deletion before reinstall
- Show warnings when service deletion fails instead of silently continuing
Related to #735
The unified installer was missing --agent-id support that existed in
the legacy host-agent installer. This parameter allows users to specify
a custom agent identifier instead of using auto-generated IDs.
Updated both install.sh (Linux/macOS/Synology/Unraid) and install.ps1
(Windows) to accept --agent-id and pass it through to the agent binary.
Related to #772
- Add Administrator privilege check at script start
- Replace silent `| Out-Null` with proper error handling for sc.exe
- Exit with error if service creation fails
- Add try/catch for Start-Service with proper error reporting
Related to #735, #760, #751
The unified agent system replaced install-host-agent.sh with install.sh.
This commit updates all references:
- Dockerfile: removed COPY for deleted script
- router.go: serve install.sh at /install-host-agent.sh endpoint (backwards compatible)
- build-release.sh: removed copy of deleted script
- validate-release.sh: removed validation of deleted script
- install.sh: updated script list for bare-metal installs
Scripts like install.sh and install-sensor-proxy.sh are now attached
as release assets and downloaded from releases/latest/download/ URLs.
This ensures users always get scripts compatible with their installed
version, even while development continues on main.
Changes:
- build-release.sh: copy install scripts to release directory
- create-release.yml: upload scripts as release assets
- Updated all documentation and code references to use release URLs
- Scripts reference each other via release URLs for consistency
Issues found during scenario testing:
1. Version propagation: The hostagent and dockeragent packages were
reporting their own Version (0.1.0-dev) instead of the unified
agent's version. Added AgentVersion config field to pass the
parent's version down.
2. macOS legacy cleanup: The install.sh script was missing cleanup
for pulse-docker-agent on macOS.
3. Windows legacy cleanup: The install.ps1 script was missing cleanup
for legacy PulseHostAgent and PulseDockerAgent services.
These fixes ensure:
- Unified agent reports consistent version across host/docker metrics
- Legacy agents are properly removed on all platforms during upgrade
- Users migrating from legacy agents get a clean transition
Add seamless migration path from legacy agents to unified agent:
- Add AgentType field to report payloads (unified vs legacy detection)
- Update server to detect legacy agents by type instead of version
- Add UI banner showing upgrade command when legacy agents are detected
- Add deprecation notice to install-host-agent.ps1
- Create install-docker-agent.sh stub that redirects to unified installer
Legacy agents (pulse-host-agent, pulse-docker-agent) now show a "Legacy"
badge in the UI with a one-click copy command to upgrade to the unified
agent.
Implement self-update capability for the unified pulse-agent binary:
- Add internal/agentupdate package with cross-platform update logic
- Hourly version checks against /api/agent/version endpoint
- SHA256 checksum verification for downloaded binaries
- Atomic binary replacement with backup/rollback on failure
- Support for Linux, macOS, and Windows (10 platform/arch combinations)
Build and release changes:
- Dockerfile builds unified agent for all platforms
- build-release.sh includes unified agent in release artifacts
- validate-release.sh validates unified agent binaries
- Install scripts (install.sh, install.ps1) use correct URL format
Related to #727, #737