Commit graph

1798 commits

Author SHA1 Message Date
rcourtman
307bb9f6cc feat: add Linux agent archives to releases and improve version mismatch detection
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
2025-12-16 22:51:10 +00:00
rcourtman
0b65d68682 fix: backup matching uses instance+VMID to prevent cross-instance collisions
Previously, SyncGuestBackupTimes matched backups to guests using only VMID.
This caused newly created containers to incorrectly show old backup times
from different containers on other Proxmox instances that happened to have
the same VMID.

Now uses composite key (instance+VMID) for PVE storage backups to ensure
proper isolation. PBS backups still use VMID matching (since they aggregate
from multiple sources) but only as a fallback.

Fixes issue where ollama LXC showed 'last backup 3 months ago' despite
being created yesterday.
2025-12-16 22:19:19 +00:00
rcourtman
26133cf0cf feat: Improve cluster endpoint error messages for users
- Add sanitizeEndpointError() to transform raw Go errors into user-friendly messages
- Transform 'context deadline exceeded' into helpful messages mentioning possible causes
- Storage timeout errors now suggest checking PBS/NFS/Ceph backend connectivity
- Connection refused, certificate errors, and auth errors get actionable hints
- Apply sanitization everywhere cluster endpoint lastError is stored
- Add comprehensive tests for all error transformations
2025-12-16 21:50:02 +00:00
rcourtman
433b5b5d3a test: add regression test for OIDC env vars with nil config (#853)
Adds TestOIDCEnvVarsWithNilConfig to catch the case where OIDC_* env
vars were silently ignored when no oidc.enc file existed. This documents
the proper pattern of initializing OIDCConfig before calling MergeFromEnv.
2025-12-16 21:02:47 +00:00
rcourtman
6bfa8a3837 fix: AI model selector dropdown overflow on small screens
Add max-height and overflow-y-auto to the model selector dropdown in
the AI chat panel to prevent it from extending past the screen when
there are many models available (e.g., with Ollama).

Fixes feedback from discussion #845
2025-12-16 20:59:42 +00:00
rcourtman
9dc365c9c6 fix: OIDC env vars ignored when no oidc.enc file exists
When OIDC_* environment variables were set but no oidc.enc config file
existed, cfg.OIDC was nil and MergeFromEnv would silently return without
applying the env vars (due to nil receiver check).

Fix: Initialize cfg.OIDC to default values before merging env vars if
it's nil. This ensures OIDC can be configured purely through environment
variables without requiring a pre-existing config file.

Related to #853
2025-12-16 20:25:56 +00:00
rcourtman
358d38f97f fix: Allow printable ASCII in alert IDs for acknowledge requests
Reverts overly strict alert ID validation that was rejecting valid
alert IDs containing special characters. Docker host IDs can contain
user-supplied data like hostnames which may include parentheses,
brackets, or other printable ASCII characters.

The previous validation only allowed alphanumeric + limited punctuation,
which caused 400 errors when acknowledging alerts from Docker hosts
with special characters in their identifiers.

Related to #852
2025-12-16 20:10:31 +00:00
rcourtman
7f4161802a Add PNG version of logo for GitHub App 2025-12-16 19:35:43 +00:00
rcourtman
a9c0a4d682 feat: configurable backup freshness thresholds for dashboard indicator
Adds FreshHours and StaleHours settings to control when the dashboard
backup indicator shows green (fresh), amber (stale), or red (critical).

- Backend: Added FreshHours/StaleHours to BackupAlertConfig (default 24/72 hours)
- Frontend: getBackupInfo() now accepts optional thresholds parameter
- Dashboard/GuestRow components use thresholds from alert config
- Settings saved/loaded with alert configuration

Closes #839
2025-12-16 16:36:08 +00:00
rcourtman
cb960a04e3 Add comprehensive AI test coverage
- Add integration tests for Ollama provider (17 tests against real API)
- Add unit tests for baseline, correlation, patterns, memory, knowledge, cost packages
- Add context formatter and builder tests
- Add factory tests for provider initialization
- Add Makefile targets: test-integration, test-all
- Clean up test theatre (removed struct field tests)

Integration tests require Ollama at OLLAMA_URL (default: 192.168.0.124:11434)
Run with: make test-integration
2025-12-16 12:33:06 +00:00
rcourtman
e41b805de2 fix: Retry-After header now uses actual limiter window
Previously the Retry-After header was hardcoded to "60" seconds
regardless of the rate limiter's actual window duration. Now uses
the limiter's configured window (e.g., 600 seconds for recovery
endpoints, 300 for exports).

Related to #579
2025-12-16 10:07:16 +00:00
rcourtman
a028f312de Auto-update Helm chart version to 5.0.0-rc.3 2025-12-16 09:52:51 +00:00
rcourtman
1971b956ae Auto-update Helm chart documentation 2025-12-16 09:52:51 +00:00
rcourtman
e7e9797319 chore: bump version to 5.0.0-rc.3 2025-12-16 09:22:50 +00:00
rcourtman
a8957a2e7b feat(ui): make AI settings page more compact and user-friendly
- Replace verbose info banner with streamlined layout
- Add collapsible 'Advanced Model Selection' accordion for Chat/Patrol models
- Make AI Patrol Settings section collapsible with inline summary badges
- Compact Cost Controls into single-row inline layout
- Reduce form spacing for tighter presentation
- Remove unused formHelpText import

Also includes:
- OpenAI provider fixes for max_tokens parameters
- Security setup CSRF and 401 fixes
- Minor UI tweaks
2025-12-16 09:20:09 +00:00
rcourtman
03182123f6 fix(sensor-proxy): remove pct pull fallback that causes PVE task errors
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
2025-12-16 00:02:34 +00:00
rcourtman
101fa62997 fix(security): show actual backend error instead of misleading DISABLE_AUTH message
The frontend was incorrectly assuming any 401/403 response from the
quick-setup endpoint meant the legacy DISABLE_AUTH flag was present.

This was wrong - the real causes are typically:
- Missing bootstrap token (for first-run setup)
- Invalid bootstrap token
- Authentication required for existing setups

Now the frontend properly displays the actual error message from the
backend, which includes helpful instructions for retrieving the
bootstrap token.
2025-12-15 22:30:24 +00:00
rcourtman
a3909f1b39 fix: strip provider prefix from all AI provider models and instant URL refresh
Backend fixes:
- Strip provider prefix (anthropic:, openai:, deepseek:, ollama:) in all
  provider Chat methods and constructors for robust handling
- Models are now correctly parsed regardless of caller format

Frontend fixes:
- Tool cards now persist in AI chat after approval execution by adding
  to streamEvents array
- Dashboard now listens for pulse:metadata-changed custom event
- AI Chat emits this event when set_resource_url tool completes
- Guest URL icons now update instantly when AI sets them
2025-12-15 19:18:09 +00:00
rcourtman
43d658556b feat(ai): improve AI settings first-time setup UX
- Add setup modal that appears when enabling AI without configured provider
- Modal allows selecting provider (Anthropic, OpenAI, DeepSeek, Ollama)
- Enter API key/URL and enable AI in one smooth flow
- Reorder backend to apply API keys before enabled check
- Fix Ollama to strip 'ollama:' prefix from model names
- Simplify backend error message for unconfigured providers
2025-12-15 18:59:19 +00:00
rcourtman
fe20b2c55b fix(ai): add fallback default model when Ollama model is empty
When model is not explicitly set in config or request, fall back to
llama3 to prevent 'model is required' errors from Ollama.
2025-12-15 16:59:51 +00:00
rcourtman
71783f8852 fix(ai): normalize Ollama base URL to prevent 405 errors
Users sometimes enter URLs with trailing slashes or include the /api path:
- http://host:11434/  -> would become http://host:11434//api/chat
- http://host:11434/api -> would become http://host:11434/api/api/chat

Now we strip trailing slashes and /api suffix during client initialization.

Fixes #847
2025-12-15 16:51:52 +00:00
rcourtman
0d2d71b238 Add sponsor button to repo 2025-12-15 16:27:10 +00:00
rcourtman
d43cb9fce9 fix(ci): pass explicit version to demo server update
Previously the workflow ran install.sh without --version, which caused it
to download the latest stable release instead of the target release tag.

This was causing the demo server to downgrade from RC versions to stable
when triggered via workflow_dispatch.
2025-12-15 16:11:49 +00:00
rcourtman
61da37a427 Auto-update Helm chart version to 5.0.0-rc.2 2025-12-15 14:46:45 +00:00
rcourtman
e7f85e5539 Auto-update Helm chart documentation 2025-12-15 14:46:41 +00:00
rcourtman
b6df03e989 perf(ci): use amd64-only for preflight staging images
Skip arm64 QEMU emulation in preflight tests - staging images are only
used for integration tests which run on amd64. This cuts ~20-30 minutes
off the release pipeline.

Multi-arch Docker images are still built in the final release job via
publish-docker.yml.
2025-12-15 14:27:34 +00:00
rcourtman
cb268727e4 fix(sensor-proxy): correctly skip selfheal regeneration during selfheal runs
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
2025-12-15 14:06:40 +00:00
rcourtman
92e8de4802 chore: bump version to 5.0.0-rc.2 2025-12-15 13:38:45 +00:00
rcourtman
2209565eae fix(sensor-proxy): skip selfheal reinstall when service is healthy
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
2025-12-15 13:31:18 +00:00
rcourtman
b6cc57590a fix(ai): use configured provider's default model when no model set
When a user configures only Ollama (or any single provider) via the
multi-provider UI without explicitly selecting a model, GetModel() now
returns that provider's default model instead of falling back to the
legacy Provider field which defaults to "anthropic".

This fixes "API key is required for anthropic" errors when enabling AI
with only Ollama configured.

Related to #847
2025-12-15 11:18:05 +00:00
rcourtman
609aa98030 fix(sensor-proxy): skip prerelease versions in selfheal update check
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
2025-12-15 11:03:32 +00:00
rcourtman
06ae5295b3 fix(ai): send Ollama URL when using default localhost address
The form pre-fills the Ollama URL field with http://localhost:11434 but
compared it against that same default value to detect changes. This meant
users configuring Ollama with the default URL never actually saved it.

Also shows actual backend error messages instead of generic "Failed to update"
when toggling the AI enable switch.

Related to #847
2025-12-15 10:03:15 +00:00
rcourtman
eac510bb5e fix(ai): allow enabling AI when any provider is configured
The enable validation was using the legacy single-provider model which
checked settings.Provider and settings.APIKey. Users configuring Ollama
via the new multi-provider UI (setting ollama_base_url) couldn't enable
AI because settings.Provider defaulted to "anthropic" which required an
API key.

Now checks GetConfiguredProviders() first - if any provider is configured
(Anthropic, OpenAI, DeepSeek, or Ollama), AI can be enabled.

Related to #847
2025-12-15 09:43:17 +00:00
rcourtman
4bd9c3cf69 fix(sensor-proxy): prevent installer hang on control-plane sync
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.
2025-12-15 08:39:06 +00:00
rcourtman
3bc2b4944b fix(sensor-proxy): add timeouts to pmxcfs operations in installer
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
2025-12-15 07:04:14 +00:00
rcourtman
854f89aa24 fix(agent): stop running agent before TrueNAS reinstall to avoid "text file busy"
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
2025-12-15 04:03:06 +00:00
rcourtman
5609f5a6af docs: fix Docker socket mount path for standalone sensor proxy
The standalone installer creates the socket at /mnt/pulse-proxy on the host,
not /run/pulse-sensor-proxy. Updated documentation to show the correct mount:
  /mnt/pulse-proxy:/run/pulse-sensor-proxy:ro

Related to #822
2025-12-15 02:08:15 +00:00
rcourtman
3b4c77de28 fix(ui): add CPU tooltip to Proxmox Overview. Related to #816 2025-12-15 02:06:12 +00:00
rcourtman
02c4131853 fix(agent): use /etc/machine-id in LXC containers to avoid ID collisions
LXC containers share the host's /sys/class/dmi/id/product_uuid, which
causes gopsutil to return identical HostIDs for all LXC containers on
the same physical host. This results in agent ID collisions where
multiple LXC containers appear as a single host in Pulse.

The fix detects LXC containers and prefers /etc/machine-id (which is
unique per container) over gopsutil's HostID.

Related to #773
2025-12-14 23:05:32 +00:00
rcourtman
9e7240042f fix(ui): apply threshold-based coloring to memory bars
Fixes #828

Memory bars were always showing green regardless of usage percentage.
Added getMemoryColor() function that applies threshold-based coloring:
- Green: Below 70%
- Yellow/Orange: 70-90%
- Red: Above 90%

This matches the existing disk bar behavior and restores the expected
visual warning for high memory usage.
2025-12-14 22:11:07 +00:00
rcourtman
3948652a21 fix(docker): truncate long image names in container table
Fixes #825

Long Docker image names (like Immich postgres containers) were expanding
the entire table row, requiring horizontal scrolling to see CPU/Memory.

Changed the image cell to use:
- Inline style max-width (more reliable in table layouts)
- Block span with truncate class
- overflow-hidden on parent container

Images now truncate with ellipsis at 200px, with full name in tooltip.
2025-12-14 22:05:38 +00:00
rcourtman
b004f6d017 fix(ui): stabilize type badge order in unified agents table
Fixes #773

The type badge order was flapping between 'Host Docker' and 'Docker Host'
because Array.from(new Set([...])) doesn't preserve insertion order reliably.

Added a sortTypes helper that ensures types are always displayed in a
consistent order: 'host' before 'docker'. This prevents visual flapping
even when the underlying data sources update at slightly different times.
2025-12-14 21:51:06 +00:00
rcourtman
00bbe59fcc fix(install): add retry logic and better error output for script download
Addresses #827

- Added 3-retry logic with 2-second delays between attempts
- Increased timeout from 15s to 30s for slower connections
- Show actual curl error instead of suppressing stderr
- Provide workaround instructions (download manually then run)
- Show the URL being downloaded for easier debugging
2025-12-14 21:38:59 +00:00
rcourtman
4d7285613f fix(sensor-proxy): add --proxy-url flag for manual URL override
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
2025-12-14 21:15:55 +00:00
rcourtman
ce10dbad60 feat(docker-agent): add payload size logging for debugging body-too-large errors
Related to #823

- Log payload size (in KB and bytes) at debug level
- Warn when payload approaches 400KB (512KB limit)
- Helps diagnose 'request body too large' errors
2025-12-14 21:10:06 +00:00
rcourtman
aca2534a1a fix: Quick tips banner incorrectly states 0 disables alerts, should be -1
The Quick tips banner on the Alerts page said "Set any threshold to 0" but
the actual code uses -1 to disable alerts. The tooltips on individual fields
were correct; only the top-of-page banner was wrong.

Related to #843
2025-12-14 19:08:24 +00:00
rcourtman
49c30ea412 fix: update UnifiedAgents test for 'Force Docker' label change 2025-12-14 18:11:13 +00:00
rcourtman
bc82c4a144 fix: prevent race conditions in release workflows
- Remove 'release: published' triggers from publish-docker, promote-floating-tags, and helm-pages workflows
- All these workflows now only run via workflow_dispatch, triggered by create-release.yml in sequence
- Add image availability check in promote-floating-tags to wait for Docker images
- create-release.yml now dispatches: publish-docker, promote-floating-tags, helm-pages, update-demo-server
- This prevents the race condition where workflows triggered by release event run before Docker images are ready
2025-12-14 18:07:46 +00:00
rcourtman
7b54326889 feat: add draft_only option to release workflow for review before publishing 2025-12-14 17:16:03 +00:00
rcourtman
a5963e9a2b fix: add is_prerelease to workflow outputs for downstream jobs 2025-12-14 17:07:18 +00:00