Enhancements for OIDC authentication based on user feedback from issue #327:
1. Add OIDC logout URL support
- New OIDC_LOGOUT_URL environment variable
- UI field in OIDC settings panel for logout URL configuration
- Properly redirects to IdP logout endpoint (e.g., Authentik end-session)
- Stored in config and returned via security status API
2. Fix redirect URL help text in UI
- Handle empty defaultRedirect string properly
- Improved help text when PUBLIC_URL is not set
- Clarify when auto-detection vs manual config is needed
3. Documentation improvements
- Add note about using https:// in PUBLIC_URL/OIDC_REDIRECT_URL when behind TLS proxy
- Document OIDC_LOGOUT_URL environment variable
- Clarify X-Forwarded-Proto header behavior in OIDC docs
- Add better guidance for Authentik users on HTTPS setup
4. Frontend improvements
- Add HS256 signature algorithm error message in Login component
- Display OIDC logout URL when available
These changes address the remaining OIDC UX issues reported by users,
particularly around logout functionality and reverse proxy configuration.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Fixes multiple OIDC authentication issues reported in GitHub issue #327:
1. Fix DISABLE_AUTH=true disabling OIDC sessions
- Reorder authentication checks to validate proxy auth and OIDC sessions
before checking DISABLE_AUTH flag
- Allows OIDC to function even when basic auth is disabled
2. Fix missing username display for OIDC users
- Add GetSessionUsername() function to look up username from session ID
- Set X-Authenticated-User header for OIDC authenticated requests
- Update security status endpoint to return oidcUsername field
- Display OIDC username in UI header alongside logout button
3. Fix missing logout button for OIDC users
- Set hasAuth(true) when OIDC session is detected in frontend
- Update security status endpoint to return OIDC info even when
DISABLE_AUTH=true
- Properly initialize WebSocket and load user preferences for OIDC sessions
4. Add documentation for Authentik HS256/RS256 issue
- Document requirement for RSA signing key in Authentik
- Add troubleshooting entry for signature algorithm mismatch
- Provide clear resolution steps in CONFIGURATION.md and OIDC.md
All changes maintain backward compatibility and follow defensive security
practices. X-Forwarded-Proto header handling was verified to be correct.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Enhanced Quick Setup script to detect existing SSH configuration
- Offers Keep/Remove/Skip options when SSH key already exists
- Provides clean removal of SSH key from authorized_keys
- Shows manual removal instructions for lm-sensors package
- Fixed ConfigWatcher panic on double-close during shutdown
- Fixed node deletion to allow removing the last node
- Added SaveNodesConfigAllowEmpty method for explicit admin actions
- Fixed deleted node host extraction before removal
- Display Quick Setup command after copying to clipboard
- Improved node name matching for temperature data
- Handles .lan suffix variations between config and WebSocket state
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Remove excessive emojis and decorative elements
- Use clear, concise language throughout
- Simplify progress indicators to simple checkmarks
- Remove unnecessary tips and verbose explanations
- Improve error message clarity
- Use proper capitalization (not ALL CAPS for emphasis)
- Clean up temperature monitoring prompt to be more direct
The setup script now presents a more professional, enterprise-ready
appearance while maintaining all functionality.
- Add getOrGenerateSSHKey() function that automatically generates SSH keypair if needed
- Embed SSH public key directly in setup scripts (no manual copy/paste required)
- Simplify temperature monitoring setup - user just types 'y' and it's done
- Improves UX: removes manual steps for SSH key setup
Changes:
- internal/api/config_handlers.go: Add SSH key generation and auto-embedding
- frontend-modern/src/components/Settings/NodeModal.tsx: Remove dead setupCode modal code
- Setup script now includes embedded SSH_PUBLIC_KEY variable
User workflow before:
1. Run setup script
2. Prompted to run commands on Pulse server
3. Copy SSH public key manually
4. Paste into setup script
5. Done
User workflow now:
1. Run setup script
2. Type 'y' for temperature monitoring
3. Done (SSH key automatically installed)
This commit addresses critical issues where nodes configuration was being
lost or corrupted, causing user frustration and data loss.
## Changes:
### 1. Sync Script Protection (sync-production-config.sh)
- Never overwrites newer dev config with older production files
- Validates timestamps before syncing
- Shows detailed logging of sync decisions
- Prevents accidental overwrites of working configuration
### 2. Timestamped Backups (persistence.go)
- Creates timestamped backup before EVERY save (e.g., nodes.enc.backup-20251001-073000)
- Maintains "latest" backup for quick recovery
- Auto-cleans old backups (keeps last 10)
- Ensures we can always recover from corruption
### 3. Empty Config Protection (persistence.go)
- BLOCKS attempts to save empty nodes config when existing nodes exist
- Prevents accidental data wipes
- Returns error with clear message about what was blocked
### 4. Enhanced Corruption Recovery (persistence.go)
- Detects "cipher: message authentication failed" errors
- Automatically attempts recovery from backup files
- Renames corrupted files with timestamps for forensics
- Logs detailed recovery process
### 5. Performance Logging (GuestRow.tsx)
- Added timing for individual metadata API calls
- Helps identify performance bottlenecks
## Why This Matters:
Previous behavior allowed:
- Corrupted files to overwrite working configs
- Empty configs to delete all nodes
- No way to recover from corruption
- Race conditions during rapid restarts
New behavior ensures:
- Multiple backup copies always exist
- Corruption auto-recovers from backups
- Empty saves are blocked
- Sync script validates before overwriting
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
addresses #481
The frontend expects a disk object with {total, used, free, usage} fields
but the backend was only sending flat diskUsed/diskTotal values. This
caused the DISK column to show disk I/O values instead of disk usage.
Added DiskObj field to VMFrontend and ContainerFrontend structs and
populated it in the converters, matching how Memory is already handled.
addresses #476
added Instance field to StorageBackup and GuestSnapshot structs in both
backend and frontend to properly handle nodes with duplicate hostnames.
updated backup and snapshot counting logic to use instance ID instead of
hostname, consistent with the VM/container/storage count fixes.
this completes the fix for #476 - all counts and groupings now use unique
instance IDs instead of hostnames.
addresses mock data not keeping up with new features added in v4.16.0. mock nodes now generate realistic CPU package, core, and NVMe temperatures to match the temperature monitoring feature.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Addresses #327 - Users behind reverse proxies (Traefik, nginx, etc) were
experiencing redirect loop issues because the redirect URL was being built
with http:// instead of https:// when X-Forwarded-Proto was set.
Changes:
- Build OIDC redirect URL dynamically from each request instead of at startup
- Respect X-Forwarded-Proto and X-Forwarded-Host headers from reverse proxies
- Update UI help text to clarify auto-detection behavior
- Add debug logging to show how redirect URL is constructed
When redirect URL is not explicitly configured, Pulse now builds it from
the incoming request headers, properly detecting HTTPS when behind a proxy.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
addresses #327
Fixed issues when PUBLIC_URL is not set:
- Better error message explaining how to fix missing redirect URL
- Help text now shows actionable guidance instead of incomplete message
- Hide IdP redirect URL hint when no default is available
addresses #327
- added detailed logging when ID token verification fails
- added better error messages for common OIDC issues
- updated docs with Authentik-specific configuration
- added troubleshooting section for redirect loops and invalid_id_token errors
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- add dedicated Temperature column in node summary table with color coding
- add temperature threshold configuration in alert settings
- default threshold: 80°C trigger / 75°C clear
- temperature alerts integrated with existing alert system
- configurable per-node or globally via alert overrides
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Changed from scary warnings to confident, reassuring tone:
Before:
- "⚠️ IMPORTANT: This grants SSH access..."
- Emphasized risks and compromise scenarios
- Made users feel unsafe enabling the feature
After:
- "Works just like Ansible, Saltstack, etc."
- Emphasizes this is industry-standard approach
- Compares to trusted automation tools
- Focuses on what it does, not what could go wrong
- Still transparent about security model
- Removes duplicate/contradictory sections
The feature is secure and follows best practices. The messaging should
reflect confidence in the design while still being transparent.
Users should feel good about enabling it, not scared.
- Make it clear SSH setup is OPTIONAL
- Explain security model upfront before user commits
- Detail exactly what access is being granted (root SSH, sensors only)
- Warn users to only proceed if they trust Pulse server
- Better differentiate public vs private keys
- Show exactly where the key is stored
- Explain how to revoke access
- Add comprehensive security documentation
- Include advanced option for command restrictions in authorized_keys
- Add risk assessment and best practices
This ensures users make informed decisions about SSH access to their
critical Proxmox infrastructure.
- Prompts user to set up SSH access during auto-setup
- Guides user to paste their Pulse server's public key
- Adds key to /root/.ssh/authorized_keys
- Installs lm-sensors automatically
- Runs sensors-detect --auto for proper sensor detection
- Optional: user can skip and set up later manually
- Includes validation of SSH key format
- Shows clear instructions for manual setup if skipped
This ensures temperature monitoring works out-of-the-box for users
who run the auto-setup script.
addresses #101
- Implement SSH-based temperature collector using lm-sensors
- Add Temperature struct to node models (CPU package, cores, NVMe)
- Collect temps during node polling (5s timeout, non-blocking)
- Display temperature in node cards with color coding:
- Green: <60°C
- Yellow: 60-80°C
- Red: >80°C
- Shows CPU temp or falls back to load average if unavailable
- Tooltip includes NVMe drive temps when present
- Uses root SSH access (no additional auth setup needed for now)
- Temperature data only collected for online nodes
Added detailed debug-level logs throughout the OIDC flow:
- Provider initialization (issuer, endpoints, scopes)
- Login flow tracking (client ID, redirect URL)
- Token exchange success/failure details
- Claims extraction (username, email, groups)
- Access control checks (why restrictions passed/failed)
Enhanced error logs to include issuer URL and actual error details in
audit events instead of generic "failed" messages.
Updated docs with Debug Logging section showing example output and
troubleshooting guidance for common issues like group restrictions.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
addresses data loss issue where encryption key regeneration silently
orphaned all encrypted configuration (nodes, email, webhooks).
Changes:
- Check for existing .enc files before generating new encryption key
- Refuse to start if encrypted data exists but key is missing/invalid
- Forces explicit user action (restore key backup or delete .enc files)
- Prevents silent data loss from key regeneration
This ensures encrypted data is never accidentally orphaned when the
encryption key is lost or corrupted.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
addresses #477
Expanded the timezone dropdown from 11 options to 70+ common IANA
timezones covering all major regions (Africa, Americas, Asia,
Australia, Europe, Pacific).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
addresses #471
when pulse restarts (service restart, container restart, etc), active alerts
are loaded from disk but notifications were never sent for these restored
alerts. this caused users to miss critical ongoing alerts that existed before
the restart.
the issue was particularly noticeable with memory alerts on VMs - if a VM's
memory was genuinely high and an alert was created, then pulse restarted, the
alert would show in 'Active Alerts' but no webhook notification would be sent.
however, manually creating a 'fake' alert by lowering thresholds would work
because those are new alerts.
fix: now sends notifications for restored critical alerts that started within
the last 2 hours. adds a 10-second delay after restart to allow the system
to stabilize before sending notifications. warning-level alerts are not
re-notified to avoid spam on restart.
Addresses #450, #451, #406
- Initialize all variables at top of script to prevent "unbound variable" errors with set -u
- BUILD_FROM_SOURCE, SKIP_DOWNLOAD, IN_CONTAINER, IN_DOCKER now set at line 20-27
- ENABLE_AUTO_UPDATES, FORCE_VERSION, FORCE_CHANNEL, SOURCE_BRANCH also moved to top
- Removed duplicate assignments from argument parsing section
- Restore /bin/update command creation for ProxmoxVE LXC installations
- Creates update script that re-runs install.sh for easy updates
- Allows backend to properly detect ProxmoxVE deployment type
- Users can now run "update" in LXC console as documented
- Update deployment detection to recognize install.sh in update command
- Previously only looked for legacy "pulse.sh" reference
- Now checks for both pulse.sh and install.sh
Addresses multiple issues identified during comprehensive alert system audit:
1. Fix ZFS device loop lock issue
- Moved lock acquisition outside loop in checkZFSPoolHealth
- Changed clearAlert to clearAlertNoLock when lock already held
- Prevents multiple lock acquisitions in same iteration
2. Add alert deduplication on restore
- Prevents duplicate alerts after service restart
- Tracks seen alert IDs during LoadActiveAlerts
- Logs warnings for any duplicates found
3. Add API input validation
- validateAlertID function prevents DOS attacks
- Limit alert ID length to 500 characters
- Whitelist allowed characters (alphanumeric, -, _, :, /, .)
- Cap history limit parameter at 10,000 records
- Applied validation to acknowledge, unacknowledge, and clear endpoints
4. Add panic recovery to goroutines
- All SaveActiveAlerts goroutines now have defer/recover
- Cleanup goroutines protected from panics
- Contextual error logging for each goroutine type
5. Document lock ordering
- Added comprehensive documentation for Manager mutexes
- Explains m.mu and resolvedMutex relationship
- Clarifies acquisition rules to prevent deadlocks
- Inline comments for resolvedMutex field
These fixes improve stability, security, data integrity, and maintainability
of the alert system without breaking API compatibility.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Corrected widespread misinformation claiming API tokens cannot access guest agent data on Proxmox 9.
Changes:
- Rewrote VM_DISK_MONITORING.md with accurate technical explanation
- Deleted VM_DISK_STATS_TROUBLESHOOTING.md (contained false information)
- Updated FAQ.md with correct quick reference and troubleshooting link
- Added comprehensive VM disk troubleshooting section to TROUBLESHOOTING.md
- Fixed README.md troubleshooting reference
- Updated frontend tooltip to show accurate permission requirements
- Corrected backend log messages to remove "known limitation" language
- Updated test-vm-disk.sh diagnostic script with accurate guidance
Key corrections:
- API tokens work fine for guest agent queries on both PVE 8 and 9
- Proxmox API returning disk=0 is normal behavior, not a bug
- Both tokens and passwords work equally well
- Only requirements: guest agent installed + proper permissions
- Permission issues are config problems, not authentication method limitations
Documentation now provides clear user journey: FAQ → Troubleshooting → Full Guide
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Adds DEMO_MODE environment variable that blocks all write operations
while allowing full read/view functionality. Includes banner notification
in UI when demo mode is active.
Addresses need for safe public demo instances.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Added streaming discovery that shows servers as they're found
- Backend sends WebSocket updates for each discovered server
- Frontend displays servers immediately without waiting for full scan
- Created sync-production-config.sh to preserve nodes when switching modes
- Updated toggle-mock.sh to sync config when disabling mock mode
- Dev environment now maintains separate config that syncs from production
- Enabled discovery service in dev environment by default
addresses real-time discovery UX and mock/production mode configuration persistence
The aggressive use of cluster/resources was breaking storage collection
for setups with multiple standalone nodes or improperly clustered nodes.
Now only uses cluster/resources when explicitly configured as a cluster,
falling back to traditional node-by-node polling otherwise.
This should fix the missing storage issue where one node's storage
wasn't showing after upgrading to rc5.
The issue was that when a node was successfully polled but returned empty storage
(e.g., due to API permissions), it was still marked as 'successfully polled'.
This prevented the preservation logic from keeping existing storage data.
Now if a node returns empty storage but we have existing storage for that node,
we don't mark it as polled, allowing the preservation logic to keep the data.
This should fix the issue where storage disappears from one node in #448.
- Send error result to channel when storage query times out so preservation logic works
- Ensures storage data is preserved for nodes that experience timeouts
- Fixes issue where storage/backups would disappear when a node times out
When a node's storage query times out, don't return empty storage which would wipe out existing data. Instead, skip the node entirely so the preservation logic can maintain the existing storage information.
Removed the flexible ID matching code that was added for backward compatibility. Since we've fixed the frontend to generate IDs consistently with the backend, we don't need the complexity of trying multiple ID formats.
This keeps the codebase simpler and more maintainable.