Commit graph

809 commits

Author SHA1 Message Date
rcourtman
50843d3013 test: Add LoadAPITokens error path tests
- Test nonexistent file returns empty slice (not error)
- Test empty file returns empty slice
- Test invalid JSON returns error
- Improves LoadAPITokens coverage from 80% to 93.3%
2025-12-01 15:00:56 +00:00
rcourtman
9461afc0be test: Add renderWebhookURL URL parsing error test
Add test case for malformed IPv6 URL that triggers url.Parse error.
Improves coverage from 90% to 95%. The remaining 5% is a template
Execute error path that's effectively unreachable with current types.
2025-12-01 14:57:25 +00:00
rcourtman
e774feb8ba test: Add HasScope edge case tests for API tokens
- Test empty scope always returns true
- Test explicit wildcard scope in list grants any scope
- Improves coverage from 85.7% to 100%
2025-12-01 14:51:58 +00:00
rcourtman
4973eb4c8a test: Improve coverage for cluster config handler functions
- deriveSchemeAndPort: 87.5% → 100%
  - Empty/whitespace string handling
  - Invalid URL parsing fallback
  - Host without port
- ensureHostHasPort: 91.7% → 100%
  - Empty port returns host unchanged
  - Protocol-relative URL handling (//host)
2025-12-01 14:46:00 +00:00
rcourtman
c6030d1b13 test: Add tests for ResetRateLimitForIP function
- Test nil globalRateLimitConfig early return (no panic)
- Test actual rate limit reset clears IP from limiter
- Improves coverage from 80% to 100%
2025-12-01 14:38:26 +00:00
rcourtman
5431ad2595 test: Add taskHeap.Less tiebreaker test case
When tasks have identical NextRun and Priority, the Less function
falls back to comparing InstanceName alphabetically. Add test to
cover this edge case branch, improving Less coverage to 100%.
2025-12-01 14:36:32 +00:00
rcourtman
737c02983f test: Improve coverage for security utility functions
- Add fmt.Stringer test cases for isEmptyInterface (80% -> 100%)
- Expand isTrustedNetwork tests with edge cases (80% -> 100%)
  - Empty/invalid IP strings
  - Invalid CIDR handling
  - Whitespace trimming in CIDRs
  - Multiple network matching
2025-12-01 14:33:31 +00:00
rcourtman
17512e076a test: Add tests for updates package utility functions
- TestNormalizeGitDescribeVersion: Git describe format parsing
- TestSanitizeError: Error message length truncation
- TestStatusDelayForStage: Update stage delay logic
Coverage: updates 41.5% → 41.6%
2025-12-01 14:18:54 +00:00
rcourtman
2947c3dce1 test: Add tests for monitoring helper and normalize functions
- TestCloneStringFloatMap: Deep copy verification for float maps
- TestCloneStringMap: Deep copy verification for string maps
- TestNormalizeAgentVersion: Version prefix normalization
- TestNormalizePBSNamespacePath: PBS namespace path handling
- TestNamespacePathsForDatastore: Datastore namespace extraction
- TestNormalizeDockerHostID: Docker host ID normalization
Coverage: monitoring 42.2% → 42.5%
2025-12-01 14:14:48 +00:00
rcourtman
b863b2473d test: Add tests for config handler utility functions
- TestSanitizeErrorMessage: All operation types and error hiding
- TestFindExistingGuestURL: Node matching and edge cases
- TestMatchInstanceNameByHost: Host normalization and matching
Coverage: api 27.7% → 28.0%
2025-12-01 14:09:35 +00:00
rcourtman
4058e575f7 test: Add tests for metric threshold lookup functions
- normalizeMetricTimeThresholds: key normalization, invalid value filtering
- getThresholdForMetric: all metric types, empty config, case sensitivity
- getThresholdForMetricFromConfig: hysteresis application, all metric types

Coverage: alerts 49.0% → 49.9%
2025-12-01 14:01:25 +00:00
rcourtman
be5a6eb97e test: Add tests for OIDC handler utility functions
- sanitizeOIDCReturnTo: path validation, protocol-relative URL rejection
- addQueryParam: URL building, encoding, fragment preservation
- extractStringClaim: type handling (string, []string, []interface{})
- extractStringSliceClaim: slice extraction with comma/space splitting
- matchesValue: case-insensitive value matching
- matchesDomain: email domain validation with @ handling
- intersects: set intersection with case normalization
- buildRedirectURL: proxy header handling (X-Forwarded-Proto/Host)

Coverage: api 26.7% → 27.7%
2025-12-01 13:56:38 +00:00
rcourtman
23794987f0 test: Add tests for alerts clone functions and parsePulseTags
- cloneThreshold: nil handling, value copying, pointer independence
- cloneStringPtr: nil handling, string copying, pointer independence
- cloneThresholdConfig: full config deep copy verification
- ensureHysteresisThreshold: default clear calculation, edge cases
- parsePulseTags: tag parsing, case insensitivity, whitespace handling

Coverage: alerts 48.9% → 49.0%
2025-12-01 13:52:09 +00:00
rcourtman
03d41fb71b test: Add tests for notification config copy functions
Tests for defensive copy functions that ensure data isolation:
- copyEmailConfig: copies email config with slice independence
- copyWebhookConfigs: deep copies webhooks including maps
- copyAppriseConfig: copies apprise config with slice independence
- buildNotificationTestAlert: validates test alert structure

Tests verify that modifying copies doesn't affect originals,
critical for concurrent access safety.
2025-12-01 13:43:52 +00:00
rcourtman
447478785b test: Add unit tests for filter_evaluation.go functions
Tests for alert filter evaluation logic:
- evaluateVMCondition: metric/text/raw conditions for VMs
- evaluateContainerCondition: same for containers
- evaluateFilterStack: AND/OR logic with multiple conditions
- evaluateFilterCondition: type dispatch

74 test cases covering:
- All metric types (cpu, memory, disk, diskread, diskwrite, network)
- All comparison operators (>, <, >=, <=, =, ==)
- Text search fields (name, node, vmid) with case insensitivity
- Raw text search across multiple fields
- Value type conversions (int to float64)
- Edge cases (zero, empty, invalid types)

Coverage improved from 46.8% to 48.9%.
2025-12-01 13:34:23 +00:00
rcourtman
93ea641791 test: Add unit tests for container_parsing.go pure functions
Tests for LXC container config parsing functions:
- sanitizeRootFSDevice: rootfs device extraction
- collectIPsFromInterface: recursive IP extraction from various types
- parseContainerRawIPs: JSON IP parsing
- parseContainerConfigNetworks: network interface parsing with MAC
  normalization, CIDR stripping, sorting
- parseContainerMountMetadata: mount point metadata parsing
- extractContainerRootDeviceFromConfig: root device extraction
- mergeContainerNetworkInterface: interface merging by name/MAC
- convertContainerDiskInfo: Proxmox disk info conversion
- ensureContainerRootDiskEntry: root disk entry creation

91+ test cases covering edge cases, invalid data, and complex scenarios.
Coverage improved from 40.6% to 42.2%.
2025-12-01 13:28:39 +00:00
rcourtman
611e606513 test: Add unit tests for docker_host_identity.go pure functions
Tests for all 9 functions handling Docker host identification:
- uniqueNonEmptyStrings: dedupe with order preservation
- sanitizeDockerHostSuffix: string cleaning for IDs
- tokenHintFromRecord: redacted token hints
- dockerHostIDExists: ID existence check
- dockerHostSuffixCandidates: candidate suffix generation
- fallbackDockerHostID: hash-based ID generation
- findMatchingDockerHost: host matching by various criteria
- generateDockerHostIdentifier: unique ID generation with suffixes
- resolveDockerHostIdentifier: main resolver orchestration

86 test cases covering edge cases (nil, empty, whitespace), Unicode
handling, and complex matching scenarios.
2025-12-01 13:20:30 +00:00
rcourtman
19bc5f7977 test: Add unit tests for convertDockerServices
Tests cover nil/empty inputs, basic field copying, time fields
(CreatedAt/UpdatedAt with nil and zero value handling), update status
conversion, endpoint ports, and labels cloning.
2025-12-01 13:15:29 +00:00
rcourtman
c2de40d696 test: Add error path tests for loadOrCreateBootstrapToken
Cover all error branches in bootstrap token loading:
- Empty/whitespace dataPath validation
- os.MkdirAll failure (directory creation blocked by file)
- os.WriteFile failure (read-only directory)
- os.ReadFile failure (permission denied on existing file)
- Empty file contents after read
- Whitespace-only file contents

Also adds test for generateBootstrapToken helper function.
2025-12-01 13:00:27 +00:00
rcourtman
e6b9bd501d test: Add error path tests for renderWebhookURL and UpdateAllowedPrivateCIDRs
Add comprehensive error handling tests for two pure functions:

renderWebhookURL (8 new test cases):
- Empty/whitespace URL template validation
- Invalid template syntax (unclosed braces, undefined functions)
- Template producing empty URL
- Missing scheme or host in rendered URL

UpdateAllowedPrivateCIDRs (expanded from 8 to 29 cases):
- Invalid IP addresses (garbage, out of range, malformed)
- Invalid CIDR notation (prefix too large, negative, non-numeric)
- Malformed strings (double slash, invalid IP with valid prefix)
- Success cases for valid IPv4/IPv6 CIDRs and bare IPs
2025-12-01 12:58:15 +00:00
rcourtman
e2df1d0ed4 test: Add unit tests for api_tokens.go pure functions
Add comprehensive tests for tokenPrefix, tokenSuffix, normalizeScopes,
and IsKnownScope functions. Coverage increased 42.7% -> 43.3%.
2025-12-01 12:32:37 +00:00
rcourtman
2990864f66 test: Add unit tests for guest_metadata.go pure functions
Add comprehensive tests for:
- guestMetadataCacheKey: cache key generation with edge cases
- cloneStringSlice: nil/empty handling, deep copy verification
- cloneGuestNetworkInterfaces: nil/empty, deep address copy
- processGuestNetworkInterfaces: IP filtering (loopback, link-local),
  deduplication, sorting, whitespace trimming, traffic-only interfaces

Increases monitoring package coverage from 38.9% to 39.6%.
2025-12-01 12:18:59 +00:00
rcourtman
845b096240 test: Add error path tests for acknowledgeDockerCommand
- Use public API AcknowledgeDockerHostCommand instead of private function
- Use strings.Contains instead of custom helper functions
- Add test case for empty hostID (skips validation, succeeds)
2025-12-01 12:08:16 +00:00
rcourtman
46a72a7600 Fix outdated error message path for removed Docker hosts
The error message referenced "Settings -> Docker -> Removed hosts" but
that UI path no longer exists. The correct path is now
"Settings -> Agents -> Removed Docker Hosts".

Related to #778
2025-12-01 12:03:05 +00:00
rcourtman
827a8b4d37 test: Add unit tests for email_enhanced.go error handling
Add comprehensive tests for EnhancedEmailManager covering:
- Rate limiting (exceeds limit, resets after minute, concurrency, negative values)
- Provider username defaults (SendGrid, SparkPost, Resend, Postmark)
- TLS routing (TLS, StartTLS, plain connections)
- Retry logic (retries on failure, rate limit prevents retry)
- Connection error handling for sendTLS, sendStartTLS, sendPlain

This is the first test file for email_enhanced.go which previously had
0% coverage on sendTLS, sendStartTLS, and TestConnection functions.
2025-12-01 11:46:44 +00:00
rcourtman
f02a340d72 refactor: Extract filter evaluation functions to separate file
Move guest threshold resolution and filter evaluation logic from
alerts.go to filter_evaluation.go for better code organization.

Extracted functions:
- evaluateFilterCondition
- evaluateVMCondition
- evaluateContainerCondition
- evaluateFilterStack
- getGuestThresholds

This reduces alerts.go by ~370 lines and isolates the rule evaluation
engine that determines which thresholds apply to guests.
2025-12-01 11:28:43 +00:00
rcourtman
72420a616a ADA changes (auto-committed by cron safety check) 2025-12-01 11:20:57 +00:00
rcourtman
22b429a1c9 test: Add unit tests for validateIPAddress, validatePort, defaultPortForNodeType
Cover API validation functions that were previously untested:
- validateIPAddress: IPv4/IPv6 validation with edge cases
- validatePort: Port range validation (1-65535)
- defaultPortForNodeType: Proxmox node type to default port mapping
2025-12-01 11:06:50 +00:00
rcourtman
56726f15e0 refactor: Extract guest metadata functions to separate file
Move 17 guest-metadata-related functions from monitor.go to new
guest_metadata.go file. This includes:
- Guest agent API call retry logic
- Guest metadata caching (fetch, reserve, schedule, clear)
- Network interface processing and cloning
- OS info extraction
- Type conversion utilities (stringValue, anyToInt64)

Reduces monitor.go by 541 lines (8932 → 8391).
2025-12-01 10:53:41 +00:00
rcourtman
0b2485b26b refactor: Extract container parsing functions to separate file
Move 13 related container parsing functions from monitor.go (9359 lines)
to container_parsing.go (451 lines). Reduces monitor.go by 427 lines.

Functions extracted:
- ensureContainerRootDiskEntry
- convertContainerDiskInfo
- sanitizeRootFSDevice
- parseContainerRawIPs
- collectIPsFromInterface
- sanitizeGuestAddressStrings
- dedupeStringsPreserveOrder
- containerNetworkDetails struct
- containerMountMetadata struct
- parseContainerConfigNetworks
- parseContainerMountMetadata
- mergeContainerNetworkInterface
- extractContainerRootDeviceFromConfig
2025-12-01 10:40:48 +00:00
rcourtman
82c7925895 refactor: Remove dead HandleTestExistingNode function
This function was superseded by HandleTestNode which is wired to the
router at /api/config/nodes/{id}/test. The old function was not
registered in the router and served no purpose.

Removes 121 lines of unused code.
2025-12-01 10:21:50 +00:00
rcourtman
5a4bc3b053 refactor: Extract Docker host identifier functions to separate file
Move 9 related pure functions from monitor.go (9616 lines) to
docker_host_identity.go (281 lines). Reduces monitor.go by 257 lines.

Functions extracted:
- tokenHintFromRecord
- resolveDockerHostIdentifier
- findMatchingDockerHost
- dockerHostIDExists
- generateDockerHostIdentifier
- dockerHostSuffixCandidates
- sanitizeDockerHostSuffix
- fallbackDockerHostID
- uniqueNonEmptyStrings
2025-12-01 10:03:47 +00:00
rcourtman
8ebc8fc892 ADA changes (auto-committed by cron safety check) 2025-12-01 09:51:17 +00:00
rcourtman
f9abaf26f3 Add rp1_adc to CPU chip detection in sensors parser
The host-agent's isCPUChip function was missing rp1_adc (Raspberry Pi RP1 ADC),
which is already detected in the monitoring package. This sync ensures consistent
CPU temperature chip detection across both code paths.
2025-12-01 09:45:39 +00:00
rcourtman
8b3d8d3e86 Add unit tests for websocket Hub.checkOrigin function
Test coverage for CORS origin validation including:
- No origin header (non-browser clients)
- Same-origin requests with/without proxy headers
- Wildcard and explicit allowed origins
- Private network fallback (192.168.x, 10.x, localhost, .local, .lan)
- Public IP/domain rejection
- X-Forwarded-Proto/Host/Scheme header handling
- WebSocket protocol normalization (ws->http, wss->https)

Coverage: 37.3% → 48.6%
2025-12-01 09:33:40 +00:00
rcourtman
0d786d42c9 Add unit tests for notification utility functions
Tests for annotateResolvedMetadata, resolveAppriseNotificationType,
normalizeQueueType, and resolvedTimeFromAlerts (44 test cases).
Coverage 38.0% → 39.0%.
2025-12-01 02:04:27 +00:00
rcourtman
0c50d9e6b7 Add unit tests for error classification functions in monitoring
Add 56 test cases covering:
- isTransientError: 13 cases for context errors, retryable MonitorErrors,
  and standard error types (nil, Canceled, DeadlineExceeded, Timeout, etc.)
- shouldTryPortlessFallback: 14 cases for connection error patterns that
  trigger port fallback (refused, reset, no such host, timeout variants)
- shouldAttemptFallback: 13 cases for timeout/deadline/canceled patterns
  used in storage polling fallback
- classifyDLQReason: 8 cases for dead letter queue reason classification
  (max_retry_attempts vs permanent_failure)
- Edge cases: 3 cases for overlapping error patterns and partial matches

First test file for these error classification utilities used in retry
and fallback decision logic.
2025-12-01 01:37:28 +00:00
rcourtman
5fcd4e9cb9 Add unit tests for extractHostAndPort utility function
27 test cases covering URL/host:port parsing for node configuration:
- Scheme stripping (http://, https://)
- Path removal from URLs
- IPv4 addresses with and without ports
- IPv6 addresses (bracketed with port, unbracketed)
- Edge cases (empty string, localhost, port-only)
- Error cases (malformed brackets)

Documents current behavior: bracketed IPv6 without port returns error
(net.SplitHostPort limitation).
2025-12-01 01:19:10 +00:00
rcourtman
a21dd8c3d2 Add unit tests for system_settings.go map utility functions
52 test cases covering:
- firstValueForKeys: 18 cases for multi-key lookup with priority ordering
- hasAnyKey: 15 cases for key existence checking
- discoveryConfigMap: 19 cases for nested config extraction with camelCase/snake_case support

Tests verify edge cases including nil maps, empty key slices, type assertion failures,
and priority ordering for field name variants used in configuration parsing.
2025-12-01 01:05:07 +00:00
rcourtman
fb240c2d40 Add unit tests for monitor.go type conversion utilities
Add 97 test cases for four utility functions in monitor.go:
- stringValue (30 cases): Type-to-string conversion for various Go types
  including string, int types, float types, json.Number, fmt.Stringer
- anyToInt64 (34 cases): Interface-to-int64 conversion with overflow
  handling, string parsing, and json.Number support
- parseInterfaceStat (15 cases): Interface stat map parsing for network
  interface statistics
- extractGuestOSInfo (18 cases): QEMU guest agent OS info extraction
  with fallback logic for various Linux distros, Windows, FreeBSD

Coverage for these functions: 0% → 100%
Package coverage: 37.5% → 38.5%
2025-12-01 00:51:20 +00:00
rcourtman
0198eaf6c8 Add unit tests for monitoring utility functions
Added comprehensive tests for 6 previously untested pure utility functions:
- sortContent: sorts comma-separated storage content values
- formatSeconds: converts total seconds to HH:MM:SS format
- dedupeStringsPreserveOrder: deduplicates strings while preserving order
- sanitizeGuestAddressStrings: validates and filters IP addresses
- copyFloatPointer: creates independent copy of float64 pointer
- clampInterval: clamps time.Duration to specified bounds

Tests cover edge cases including empty inputs, boundary conditions,
special values (DHCP, loopback addresses), and various separators.
Coverage increased from 36.8% to 37.5%.
2025-12-01 00:37:24 +00:00
rcourtman
51671d2a56 Add unit tests for RecoveryTokenStore
20 test cases covering:
- Token generation (uniqueness, expiry durations, format)
- Token validation (valid, invalid, expired, used, empty store)
- Concurrent use protection (replay attack prevention)
- Cleanup routine (expired tokens, used tokens, stop signal)
- Persistence (save, load, filter expired on load)
- Edge cases (missing file, invalid JSON)
2025-12-01 00:06:32 +00:00
rcourtman
990a00c5be Add unit tests for normalizePVEUser and shouldSkipClusterAutoDetection 2025-11-30 23:53:41 +00:00
rcourtman
6ff3f57ac7 Add unit tests for security lockout and session management functions
Tests for internal/api/security.go:
- RecordFailedLogin: increments counts, triggers lockout at max attempts
- ClearFailedLogins: clears count and lockout state
- GetLockoutInfo: returns correct attempts/lockout status
- ResetLockout: admin lockout reset functionality
- TrackUserSession: user/session tracking
- GetSessionUsername: session lookup
- clearCSRFCookie: nil safety, cookie attributes
- issueNewCSRFCookie: nil safety, empty session handling
- FailedLogin/AuditEvent struct field validation

30 test cases covering lockout, session tracking, and CSRF functions.
2025-11-30 23:33:51 +00:00
rcourtman
314669d584 Add unit tests for SessionStore (internal/api)
Coverage for sessionHash, CreateSession, ValidateSession,
ValidateAndExtendSession, DeleteSession, persistence, and cleanup.
21 test cases covering session lifecycle, expiration handling,
and disk persistence. Coverage 25.0% → 25.3%.
2025-11-30 23:18:34 +00:00
rcourtman
554d44aba0 Add unit tests for auth helper functions (internal/api)
Tests for detectProxy, isConnectionSecure, getCookieSettings, and
generateSessionToken functions. Covers proxy detection for various
headers including X-Forwarded-For, CF-Ray, Forwarded (RFC 7239),
and secure connection detection via TLS and proxy headers.
2025-11-30 23:04:44 +00:00
rcourtman
3378814a05 Add unit tests for bootstrap token functions (internal/api)
20 test cases covering:
- generateBootstrapToken: uniqueness, format, hex encoding
- loadOrCreateBootstrapToken: new token creation, existing token loading,
  empty/whitespace paths, empty token files, directory creation, file permissions
- bootstrapTokenValid: nil router safety, empty hash/token handling
- clearBootstrapToken: nil safety, file deletion, state clearing

First test file for bootstrap_token.go security utilities.
2025-11-30 22:54:28 +00:00
rcourtman
0538e8f013 Add unit tests for diagnostic snapshot key generation functions
32 test cases covering makeNodeSnapshotKey and makeGuestSnapshotKey
utility functions used for diagnostic memory snapshot storage. Tests
cover simple inputs, edge cases (empty strings, negative VMIDs),
special characters, and key uniqueness verification. Also includes
struct field tests for NodeMemoryRaw and VMMemoryRaw.

First test file for diagnostic_snapshots.go. Coverage 36.7% → 36.8%.
2025-11-30 22:34:09 +00:00
rcourtman
d99f5b067f Add unit tests for UpdaterRegistry (internal/updates)
27 test cases covering:
- NewUpdaterRegistry initialization
- Register and Get operations
- Overwrite behavior when re-registering
- Error handling for unregistered deployment types
- Multiple deployment types
- UpdateRequest, UpdatePlan, UpdateProgress struct fields
- Mock updater interface compliance

Coverage 41.1% → 41.5%.
2025-11-30 22:19:06 +00:00
rcourtman
54fab46bd6 Fix backup status indicator not showing for guests
The backup status indicator feature was incomplete - it added the UI
component but never populated VM/Container LastBackup from actual
backup data. Now SyncGuestBackupTimes() is called after storage
backups and PBS backups are polled, matching each guest's VMID to
its most recent backup timestamp.

Fixes #786
2025-11-30 22:13:46 +00:00
rcourtman
a7b1cf2ae9 Add unit tests for isRetryableWebhookError (internal/notifications)
47 test cases covering webhook retry logic classification:
- Network errors: timeout, connection refused/reset, DNS lookup, network unreachable
- HTTP 5xx server errors: all status codes 500-599 (retryable)
- HTTP 4xx client errors: all status codes 400-499 except 429 (not retryable)
- HTTP 429 rate limiting: special case (retryable)
- Case insensitivity verification
- Real-world error message patterns from Go net/http
- All status code boundary tests

Coverage 37.4% -> 38.0%.
2025-11-30 22:03:26 +00:00
rcourtman
ece30e9345 Add unit tests for State methods (internal/models)
51 test cases covering Docker host and generic Host state management:
- UpsertDockerHost, RemoveDockerHost, GetDockerHosts
- SetDockerHostStatus, SetDockerHostHidden, SetDockerHostPendingUninstall
- SetDockerHostCommand, SetDockerHostCustomDisplayName
- TouchDockerHost, RemoveStaleDockerHosts
- AddRemovedDockerHost, RemoveRemovedDockerHost, GetRemovedDockerHosts
- UpsertHost, GetHosts, RemoveHost, SetHostStatus, TouchHost
- UpdateRecentlyResolved

Coverage 44.0% → 68.3%.
2025-11-30 21:49:43 +00:00
rcourtman
fe8ee86f4e Add unit tests for MetricsHistory (internal/monitoring)
58 test cases covering:
- NewMetricsHistory: constructor and initialization (4 cases)
- appendMetric: time-series append with retention and max limits (5 cases)
- cleanupMetrics: old point removal with cutoff time (5 cases)
- AddGuestMetric: all 7 metric types + unknown type handling (8 cases)
- AddNodeMetric: cpu/memory/disk + unknown type (4 cases)
- AddStorageMetric: usage/used/total/avail + unknown type (5 cases)
- GetGuestMetrics: duration filtering, nonexistent, zero duration (6 cases)
- GetNodeMetrics: duration filtering and edge cases (5 cases)
- GetAllGuestMetrics: multi-metric retrieval (3 cases)
- GetAllStorageMetrics: storage metric retrieval (2 cases)
- Cleanup: retention enforcement across all metric types (1 case)
- Multiple guests isolation: verify metrics don't leak (1 case)
- MaxDataPoints enforcement: oldest points dropped (1 case)
- RetentionTime enforcement: old points removed on append (1 case)

First comprehensive unit test file for metrics_history.go core
functions. Existing concurrency test in separate file.
2025-11-30 21:34:07 +00:00
rcourtman
dadbc180e3 Add unit tests for HTTPClient (internal/tempproxy)
23 test cases covering NewHTTPClient, IsAvailable, GetTemperature,
and HealthCheck including success paths, error handling (401, 403,
429, 5xx), JSON parsing, URL encoding, retry behavior, and connection
errors.

Coverage: 22.4% → 47.6%
2025-11-30 21:18:14 +00:00
rcourtman
94952577e2 Add unit tests for importTransaction (internal/config)
24 test cases covering transaction lifecycle: staging, commit, rollback, and cleanup.
Tests include atomic commit behavior, backup/restore on failure, directory creation,
permission handling, and idempotent cleanup.

First test file for import_transaction.go. Coverage 42.4% → 42.7%.
2025-11-30 21:04:41 +00:00
rcourtman
0eb0824c0a Add unit tests for GuestMetadataStore (internal/config)
22 test cases covering CRUD operations (Get, GetAll, Set, Delete,
ReplaceAll), persistence (Load, save with atomic write, directory
creation), legacy ID migration (GetWithLegacyMigration for clustered
and standalone formats), round-trip verification, and concurrency.

First test file for guest_metadata.go, complementing the similar
docker_metadata_test.go added in previous run.
2025-11-30 20:48:05 +00:00
rcourtman
f8c7a30d28 Fix cluster proxy token collision - store per-node control tokens
When multiple cluster nodes register sensor-proxy, each registration
was overwriting the previous node's control token on the shared
PVEInstance. This caused "Proxy token not recognized" errors on all
but the last-registered node.

Changes:
- Add TemperatureProxyControlToken field to ClusterEndpoint struct
- Store control tokens per-endpoint for cluster registrations
- Check both instance-level and endpoint-level tokens when validating

Related to #738
2025-11-30 20:37:58 +00:00
rcourtman
db56cb7d0d Add unit tests for UpdateHistory (internal/updates)
47 test cases covering:
- NewUpdateHistory: directory creation, loading existing entries
- CreateEntry: event ID generation, timestamp handling, persistence
- UpdateEntry: updates, persistence verification, error handling
- GetEntry: retrieval by ID, non-existent entry errors
- ListEntries: filtering by status/action/deployment type, limits
- GetLatestSuccessful: finding recent successful entries
- Cache management: trimming when exceeding max size
- LoadCache: malformed JSON handling, empty lines
- Type definitions and constant validation
2025-11-30 20:34:40 +00:00
rcourtman
2e884f4a71 Add unit tests for DockerMetadataStore (internal/config)
22 test cases covering:
- Get/GetAll: retrieval of container/service metadata
- GetHostMetadata/GetAllHostMetadata: retrieval of host metadata
- Set: add/update metadata with persistence
- SetHostMetadata: add/update/delete host metadata
- Delete: remove container metadata
- ReplaceAll: bulk replace with nil entry handling
- Load: versioned format, legacy format, nonexistent file, invalid JSON
- Save: directory creation, atomic write
- Round-trip: full persistence cycle verification
- Concurrent access safety

First test file for docker_metadata.go.
2025-11-30 17:20:46 +00:00
rcourtman
6bda5e4d4a Add unit tests for mdadm parseDetail function 2025-11-30 16:42:12 +00:00
rcourtman
ee066d086a Add unit tests for OIDC configuration helpers
Test coverage for internal/config/oidc.go functions:
- normaliseList: 8 cases for deduplication, trimming, empty handling
- parseDelimited: 8 cases for comma/space separation
- DefaultRedirectURL: 7 cases for URL construction
- OIDCConfig.Clone: 2 cases for deep copy behavior
- OIDCConfig.ApplyDefaults: 9 cases for defaults and normalization
- OIDCConfig.Validate: 9 cases for validation rules
- OIDCConfig.MergeFromEnv: 5 cases for environment variable merging
- NewOIDCConfig: constructor verification

Total: 56 new test cases (583 lines).
2025-11-30 16:22:43 +00:00
rcourtman
2620aa5db5 Add unit tests for security.go IP parsing utilities
- extractRemoteIP: 17 test cases for remote address parsing
  (IPv4/IPv6 with/without ports, bracketed notation, edge cases)
- firstValidForwardedIP: 21 test cases for X-Forwarded-For parsing
  (single/multiple IPs, invalid entries, IPv4/IPv6 mixed)
- isPrivateIPExtended: 33 test cases extending existing coverage
  (RFC 1918 boundaries, loopback range, IPv6 private/local, ports)

Total: 71 new test cases for IP address handling utilities.
2025-11-30 15:48:45 +00:00
rcourtman
2c26054d57 Add unit tests for router.go proxy header utility functions (api)
Add 77 test cases for 4 previously untested utility functions:
- firstForwardedValue: 14 cases for X-Forwarded-For header parsing
- sanitizeForwardedHost: 27 cases for host sanitization with scheme/port handling
- isLoopbackHost: 20 cases for loopback detection (localhost, 127.x, ::1)
- shouldAppendForwardedPort: 16 cases for port appending decisions

Key edge cases covered:
- IPv6 address bracket handling in sanitizeForwardedHost
- Case-insensitive localhost detection
- Full 127.0.0.0/8 loopback range validation
- strconv.Atoi accepts negative port strings (documented as current behavior)
2025-11-30 15:34:32 +00:00
rcourtman
930e003519 Add unit tests for normalizeUnifiedAgentArch and getClientIP (api)
Tests for unified_agent.go:
- normalizeUnifiedAgentArch: 51 test cases covering all supported
  architectures (linux/darwin/windows), case insensitivity,
  whitespace handling, and invalid inputs

Tests for updates.go:
- getClientIP: 18 test cases covering X-Forwarded-For priority,
  X-Real-IP fallback, RemoteAddr extraction, IPv4/IPv6 support,
  nil header safety, and case insensitivity
2025-11-30 15:05:37 +00:00
rcourtman
04d4b6606a Add unit tests for CSRF token store (api) 2025-11-30 14:55:47 +00:00
rcourtman
fe3f32ebcc Add unit tests for responseWriter middleware wrapper (api)
Tests for the responseWriter struct in middleware.go:
- APIError.Error() interface implementation (3 cases)
- WriteHeader once-only semantics (4 cases)
- Write with implicit WriteHeader (3 cases)
- StatusCode nil safety (4 cases)
- Hijack support detection (2 cases)
- Flush support detection (3 cases)
- Full flow integration and edge cases (4 cases)

First test file for middleware.go. 22 test cases total covering
HTTP response wrapper behavior used by ErrorHandler middleware.
2025-11-30 14:33:38 +00:00
rcourtman
39d02d62a3 Add unit tests for temperature proxy utility functions (api)
- extractHostPart: 22 test cases covering URL parsing, hostname extraction
- buildAuthorizedNodeList: 8 test cases for PVE instance node list building
- generateSecureToken: 5 test cases for cryptographic token generation
- proxySyncState: 6 test cases for sync status tracking and snapshots

First test file for temperature_proxy.go utility functions.
2025-11-30 14:07:04 +00:00
rcourtman
07587ec818 Add unit tests for GetRateLimiterForEndpoint (api)
37 test cases covering endpoint routing to rate limiters:
- Authentication endpoints (login, logout, change-password, auth/*)
- Recovery endpoints (security/recovery)
- Export/Import endpoints (config/export, config/import)
- Configuration write operations (POST/PUT/DELETE to config/*)
- Configuration read operations (GET to config/*, discover, security/status)
- Update endpoints (updates/*)
- WebSocket endpoints (/ws/*)
- Public endpoints (health, version, metrics, etc.)
- General API fallback
- Case insensitivity (uppercase paths)
- Lazy initialization when globalRateLimitConfig is nil
- Priority ordering tests for overlapping patterns
2025-11-30 13:48:23 +00:00
rcourtman
aee687bb03 Add unit tests for DemoModeMiddleware (api)
26 test cases covering:
- Demo mode disabled (all requests pass through)
- Demo mode enabled with read-only methods (GET/HEAD/OPTIONS allowed)
- WebSocket upgrade handling (case-insensitive)
- Auth endpoint allowlist (login, OIDC, logout)
- Modification request blocking (POST/PUT/DELETE/PATCH)
- Partial path match rejection (security)
- Response format verification (JSON error response)

First test file for demo_middleware.go. Tests verify correct header
setting (X-Demo-Mode) and error response structure.
2025-11-30 13:34:08 +00:00
rcourtman
28a0851868 Add unit tests for container disk usage utility functions (monitoring) 2025-11-30 13:20:39 +00:00
rcourtman
926fe5495f Add unit tests for missing ToFrontend converters (models)
Added 17 new test functions covering:
- DockerHost.ToFrontend() with variants for empty display name, swarm,
  services, tasks, and command status
- Host.ToFrontend() with display name fallback logic
- CephCluster.ToFrontend() including empty pools/services case
- ReplicationJob.ToFrontend() including nil time handling
- DockerServiceUpdate.ToFrontend()
- DockerContainer.ToFrontend() for Podman info

Coverage improved from 33.0% to 44.0% in internal/models package.
2025-11-30 13:03:45 +00:00
rcourtman
fb976acfc3 Add unit tests for ZFS storage utility functions (hostmetrics)
65 test cases covering 8 functions:
- parseZpoolList: zpool command output parsing (15 cases)
- uniqueZFSPools: pool name deduplication (7 cases)
- bestZFSMountpoints: mountpoint selection logic (8 cases)
- zfsMountpointScore: mountpoint scoring algorithm (7 cases)
- zfsPoolFromDevice: pool name extraction (6 cases)
- calculatePercent: percentage calculation (7 cases)
- clampPercent: value clamping (8 cases)
- bestZFSPoolDatasets: dataset selection (7 cases)

First comprehensive unit test coverage for internal/hostmetrics
package ZFS utilities.
2025-11-30 12:50:58 +00:00
rcourtman
ef241d0581 Add unit tests for toDockerHostCommandFrontend converter 2025-11-30 12:38:59 +00:00
rcourtman
d89ba45284 Fix Windows agent self-update restart failure
syscall.Exec is not supported on Windows, causing self-update to fail
with "failed to restart: not supported by windows".

Split restart logic into platform-specific files:
- restart_unix.go: Uses syscall.Exec for in-place process replacement
- restart_windows.go: Uses os.Exit(0) to let Windows SCM restart service

Related to #735
2025-11-30 12:02:43 +00:00
rcourtman
151db60267 Add unit tests for discovery config functions (config)
Add tests for CloneDiscoveryConfig and NormalizeDiscoveryConfig:
- CloneDiscoveryConfig: 7 tests verifying deep copy, slice independence
- NormalizeDiscoveryConfig: 16 tests covering defaults, validation,
  sanitization, edge cases

Total: 23 test cases for discovery config handling.
2025-11-30 10:49:03 +00:00
rcourtman
562fc59c56 Add unit tests for alert utility functions (alerts)
Test coverage for isMonitorOnlyAlert, quietHoursCategoryForAlert, and
ensureValidHysteresis functions that were previously untested. Improves
internal/alerts coverage from 46.4% to 46.8%.
2025-11-30 10:35:22 +00:00
rcourtman
0d22d3d2e4 Add unit tests for host alert utility functions (alerts)
Test hostResourceID, hostDisplayName, hostInstanceName,
sanitizeHostComponent, sanitizeRAIDDevice, and hostDiskResourceID.
2025-11-30 10:20:26 +00:00
rcourtman
702e56c97a Add unit tests for hasLegacyThresholds function (diagnostics)
Covers all legacy threshold field detection paths including
CPU, Memory, Disk, DiskRead, DiskWrite, NetworkIn, NetworkOut,
and mixed modern/legacy configurations.
2025-11-30 10:05:33 +00:00
rcourtman
73e5ff0914 Add unit tests for dockeragent runtime detection functions
Test coverage for:
- detectRuntime: 11 test cases covering podman/docker detection via
  endpoint path, InitBinary, ServerVersion, DriverStatus, SecurityOptions
- buildRuntimeCandidates: 6 test cases verifying candidate ordering,
  deduplication, and preference-based filtering
- randomDuration: 5 test cases for boundary conditions and randomness
- determineSelfUpdateArch: validates architecture detection output

Coverage increased from 17.5% to 21.4%.
2025-11-30 08:47:46 +00:00
rcourtman
f9a64b3251 Add unit tests for notification security utilities (notifications)
Test 7 security-related functions with 118 test cases:
- formatWebhookDuration: webhook payload duration formatting
- isNumeric: Telegram chat_id validation helper
- extractTelegramChatID: Telegram webhook URL parsing
- isPrivateIP: SSRF protection (private IP detection)
- isNumericIP: HTTPS IP address detection
- isEmptyInterface: custom field validation
- ensurePushoverCustomFieldAliases: Pushover legacy field aliasing
2025-11-30 08:05:04 +00:00
rcourtman
132dae92a9 Add unit tests for notification template functions (notifications)
Test GetEmailProviders and GetWebhookTemplates functions covering:
- Provider/template uniqueness, required fields, valid values
- Known provider settings (Gmail, SendGrid, custom)
- Known webhook services (Discord, Slack, Telegram, PagerDuty)
- Payload template validation for required alert fields
2025-11-30 07:48:53 +00:00
rcourtman
19e1d81779 Add unit tests for sanitizeCIDRList (config) 2025-11-30 07:35:52 +00:00
rcourtman
a32aa60600 Add unit tests for config utility functions (config)
Test coverage for IsPasswordHashed, IsValidDiscoveryEnvironment, and
splitAndTrim functions. 63 test cases covering bcrypt hash validation,
discovery environment validation, and comma-separated string parsing.
2025-11-30 07:27:59 +00:00
rcourtman
90e1b8e546 Add unit tests for RateTracker.CalculateRates (monitoring) 2025-11-30 07:07:18 +00:00
rcourtman
d69e1545f2 Add unit tests for alert utility functions (alerts)
Test coverage for pure utility functions:
- sanitizeAlertKey: string normalization for alert IDs
- abs: absolute value for float64
- isQueueOutlier: queue anomaly detection logic
- scaleThreshold: threshold scaling with ceiling
- calculateMedianInt: integer median calculation

78 test cases added, coverage improved from 45.3% to 46.2%.
2025-11-30 06:34:55 +00:00
rcourtman
15d6cae7dd Add unit tests for adaptive scheduler interval selection (scheduler)
46 test cases covering:
- clampFloat helper (9 cases: range checks, boundary conditions)
- Staleness score impact (5 cases: 0/0.25/0.5/0.75/1 scores)
- Error penalty (5 cases: 0 to 10 errors, min clamping)
- Queue depth stretching (5 cases: 1 to 50 depth, max clamping)
- EMA smoothing (convergence behavior with alpha=0.6)
- Jitter (bounds checking, deterministic tests with seeded RNG)
- Boundary conditions (6 cases: zero/negative intervals, max<min)
- Combined factors (3 cases: all factors interacting)
- State persistence (per-instance EMA state isolation)

First unit test file for scheduler.go (previously only had integration tests).
2025-11-30 06:11:22 +00:00
rcourtman
8eea32678e Add unit tests for Docker swarm utility functions (dockeragent)
Test coverage for serviceMode, buildContainerIndex, lookupContainer,
copyStringMap, and isTaskCompletedState. 52 test cases covering service
mode detection, container index building/lookup, and task state classification.
Coverage improved from 14.7% to 17.5%.
2025-11-30 05:32:52 +00:00
rcourtman
36b1c9cf63 Add unit tests for Alert clone and metadata utility functions (alerts)
Tests for:
- normalizePoweredOffSeverity: Verifies severity normalization to warning/critical
- cloneMetadata: Deep copy functionality for metadata maps
- cloneMetadataValue: Type-specific cloning for various slice and map types
- Alert.Clone: Full alert cloning with pointer field independence

46 test cases covering nil handling, deep copy verification, slice/map
independence, and all supported metadata value types.

Coverage improved from 44.8% to 45.3%.
2025-11-30 05:19:38 +00:00
rcourtman
73e5352812 Add unit tests for extractPodmanMetadata and detectHostRemovedError (dockeragent)
- TestExtractPodmanMetadata: 14 test cases covering pod metadata, infra
  containers, compose metadata, auto-update settings, user namespace
  handling, whitespace trimming, and precedence rules
- TestDetectHostRemovedError: 11 test cases covering JSON parsing,
  case-insensitive matching, error code validation, and edge cases

Coverage improved from 11.7% to 14.7% for internal/dockeragent.
2025-11-30 05:03:31 +00:00
rcourtman
722ea83b5d Add unit tests for RateLimiter (internal/api/ratelimit.go)
16 test cases covering:
- Basic rate limiting with Allow() (limit enforcement, different IPs)
- Sliding window behavior (time-based expiry, partial expiry)
- Edge cases (zero limit, large limit, empty IP)
- Cleanup routine (full cleanup, partial cleanup)
- Concurrent access (thread safety with 100 parallel attempts)
- Middleware integration (allowed/denied paths, X-Forwarded-For)

First test file for internal/api package.
2025-11-30 04:33:59 +00:00
rcourtman
c2233fb3f8 Add unit tests for temperature utility functions
Add focused unit tests for four utility functions in temperature.go:
- extractTempInput: 16 test cases for sensor value extraction
- extractCoreNumber: 18 test cases for core number parsing
- extractHostname: 21 test cases for URL hostname extraction
- normalizeSMARTEntries: 15 test cases for SMART data normalization

70 test cases total covering type conversions, edge cases,
boundary conditions, and error handling paths.
2025-11-30 04:20:28 +00:00
rcourtman
ed3c992968 Add unit tests for InstallShAdapter utility functions
- Test parseProgress: 23 test cases for progress parsing from install.sh output
- Test readLastLines: 11 test cases including edge cases
- Test version pattern validation: 45 test cases for command injection prevention
- Test DockerUpdater and AURUpdater basic functionality
- Fix bug in readLastLines: handle n<=0 to prevent slice bounds panic

Coverage increased from 35.9% to 38.2%
2025-11-30 04:04:27 +00:00
rcourtman
351ef94368 Add unit tests for agentupdate utility functions
Tests for:
- verifyBinaryMagic: ELF/Mach-O/PE magic byte validation
- determineArch: platform architecture detection
- unraidPersistentPath: Unraid persistence path generation
- isUnraid: Unraid environment detection
- New(): updater initialization with various configs
- Config defaults and constants

Coverage: 12.9% -> 13.4%
2025-11-30 03:48:50 +00:00
rcourtman
d2a8184833 Add unit tests for notification queue utility functions
Test coverage for calculateBackoff (exponential backoff calculation),
NotificationQueueStatus constants, and QueuedNotification struct fields.
15 test cases covering backoff timing, cap behavior, and struct defaults.
2025-11-30 03:19:23 +00:00
rcourtman
b763ccc412 Add unit tests for HTTP metrics utility functions
83 test cases covering classifyStatus, isNumeric, looksLikeUUID,
normalizeSegment, and normalizeRoute functions used for Prometheus
metrics aggregation. Tests cover status code classification, numeric
string validation, UUID format detection, URL segment normalization,
and route path normalization with query param stripping.
2025-11-30 02:48:05 +00:00
rcourtman
6267554b74 Add unit tests for version utility functions
Test coverage for pure functions in internal/updates/version.go:
- Version.String() - 6 test cases
- Version.Compare() - 14 test cases (major/minor/patch/prerelease)
- Version.IsNewerThan() - 4 test cases
- Version.IsPrerelease() - 4 test cases
- compareInts() - 7 test cases
- extractRCNumber() - 12 test cases
- envBool() - 17 test cases
- sanitizePrereleaseIdentifier() - 14 test cases

Coverage: 35.2% -> 35.9%
2025-11-30 02:03:35 +00:00
rcourtman
9f2798cc96 Add unit tests for config encryption functions
Tests encryptWithPassphrase and decryptWithPassphrase:
- Roundtrip encryption/decryption with various data types
- Unique output verification (random salt/nonce)
- Wrong passphrase rejection
- Tampered ciphertext detection
- Minimum size validation
- Base64 roundtrip (matching export/import flow)
2025-11-30 01:48:20 +00:00
rcourtman
3c24a51298 Add unit tests for hostagent utility functions
Test normalisePlatform (darwin->macos normalization, case handling,
whitespace trimming) and isLoopback (case-insensitive flag matching).
Package had no tests previously.
2025-11-30 01:34:55 +00:00
rcourtman
ed3773b324 Add unit tests for email template utility functions
Test coverage for titleCase, formatDuration, pluralize, formatMetricValue,
and formatMetricThreshold functions. 71 test cases covering edge cases,
boundary conditions, and all metric type variants.
2025-11-30 01:03:05 +00:00
rcourtman
c91375230b Add unit tests for discovery config_override utility functions
Tests for parseCIDRs, parseCIDRMap, environmentFromOverride,
shouldPruneContainerNetworks, isLikelyContainerPhase, filterPhasesForEnvironment,
and ApplyConfigToProfile. Coverage increased from 29.0% to 51.0%.
2025-11-30 00:50:07 +00:00
rcourtman
d11d81688a Add unit tests for websocket utility functions
Test coverage for pure utility functions:
- isValidPrivateOrigin: validates private network origins (security)
- normalizeForwardedProto: normalizes ws/wss to http/https for proxies
- sanitizeValue: handles NaN/Inf values in JSON data
- cloneMetadata/cloneMetadataValue: deep copies metadata maps/slices
- cloneAlert/cloneAlertData: deep copies alert structures

Coverage increased from 20.9% to 37.3% (80 test cases).
2025-11-30 00:34:38 +00:00
rcourtman
04c12414d2 Add unit tests for diagnostics utility functions
Test coverage for 9 pure functions in internal/api/diagnostics.go:
- isFallbackMemorySource: 13 cases covering fallback and non-fallback sources
- copyStringSlice: 4 cases including nil handling and copy verification
- normalizeHostForComparison: 16 cases for URL normalization
- normalizeVersionLabel: 11 cases for version prefix handling
- contains: 8 cases for string slice membership
- containsFold: 11 cases for case-insensitive matching
- interfaceToStringSlice: 9 cases for type conversion
- preferredDockerHostName: 5 cases for name preference hierarchy
- formatTimeMaybe: 3 cases for time formatting
2025-11-30 00:18:41 +00:00
rcourtman
4244cf6f20 Consolidate duplicate normalizeVersion functions into shared utility
- Move normalizeVersion to utils.NormalizeVersion for single source of truth
- Update agentupdate and dockeragent packages to use shared function
- Add 14 test cases for version normalization

This prevents bugs like issue #773 where a fix applied to one copy
but not the other caused an update loop.
2025-11-29 22:57:33 +00:00
rcourtman
cf17d327f1 Add unit tests for dockeragent utility functions
Tests for calculateCPUPercent, calculateMemoryUsage, safeFloat,
parseTime, trimLeadingSlash, and summarizeBlockIO. 28 test cases
covering edge cases like zero deltas, cache handling, NaN/Inf,
and case-insensitive op matching.

Coverage improved from 8.0% to 11.7%.
2025-11-29 22:18:10 +00:00
rcourtman
1b3effcb10 Fix redactSecretsFromURL matching params with prefixed names
The function was using substring matching for sensitive param names,
causing parameters like "extra_token" or "myapikey" to be incorrectly
redacted when they matched "token=" or "apikey=" as substrings.

Now checks for proper boundary characters (? or &) before matching,
so only actual parameter names are redacted.

Related to ADA knowledge entry: "Query param redaction uses substring matching"
2025-11-29 22:03:15 +00:00
rcourtman
46f90e1585 Show CPU core count on EnhancedCPUBar progress bar 2025-11-29 21:47:22 +00:00
rcourtman
0dd65c5db2 Add unit tests for TaskQueue Upsert and Remove methods 2025-11-29 21:38:33 +00:00
rcourtman
a5fea152e8 Add unit tests for HandleLookup hostname matching
Tests cover the hostname lookup paths in HandleLookup:
- Exact hostname match (case-insensitive)
- DisplayName match (case-insensitive)
- Short hostname match (before first dot)
- Priority of exact over short match
- Sorted iteration order behavior
- Not-found cases

12 test cases covering all hostname matching code paths.
2025-11-29 20:20:15 +00:00
rcourtman
7704a18e52 ADA: Add unit tests for isDirectLoopbackRequest 2025-11-29 20:07:59 +00:00
rcourtman
9393574f05 ADA: Add unit tests for Ceph helper functions
Test coverage for isCephStorageType, countServiceDaemons,
extractCephCheckSummary, and summarizeCephHealth functions.
These parse Ceph storage types and health status JSON.
2025-11-29 19:49:43 +00:00
rcourtman
5eb793f4bb ADA: Add unit tests for TaskQueue.Snapshot 2025-11-29 19:38:54 +00:00
rcourtman
277ec7e9da ADA: Add unit tests for validateSystemSettings 2025-11-29 19:08:58 +00:00
rcourtman
ce47e8ca9d ADA: Add unit tests for sanitizeInstallerURL and sanitizeSetupAuthToken
Add comprehensive test coverage for security-critical URL and token
sanitization functions in config_handlers.go. These functions protect
the setup script endpoint from injection attacks.

TestSanitizeInstallerURL (23 cases): empty/whitespace handling, valid
http/https URLs, fragment stripping, query preservation, control character
rejection, invalid scheme rejection (ftp/file/javascript/data), and
missing host validation.

TestSanitizeSetupAuthToken (19 cases): empty/whitespace handling, valid
hex tokens of various lengths (32-128 chars), mixed case hex, control
character rejection, non-hex character rejection, and length validation.
2025-11-29 18:35:27 +00:00
rcourtman
fce4168f82 ADA: Add unit tests for validateBcryptHash helper function
Tests cover valid bcrypt hash formats ($2a$, $2b$, $2y$), truncated/too-long
hashes, empty input, and invalid prefixes (md5-style, $2x$, no prefix).
2025-11-29 18:06:19 +00:00
rcourtman
9647313570 ADA: Fix redactSecretsFromURL bug and add unit tests
The Telegram bot token redaction had an off-by-one bug: it searched for
the next "/" starting from the "/bot" position, which found the "/" in
"/bot" itself (offset 0) instead of the next "/" after the token.

Result: tokens were not properly redacted and the URL got corrupted with
duplicated path segments, potentially leaking secrets to logs/API responses.

Fix: search from idx+4 (after "/bot") and handle edge cases where there's
no trailing slash (token at end of URL or before query string).

Added 20 comprehensive test cases covering:
- No secrets (passthrough)
- Telegram bot tokens (various patterns)
- Query parameter secrets (token, apikey, api_key, key, secret, password)
- Multiple parameters and edge cases
2025-11-29 17:36:32 +00:00
rcourtman
f4cfe96943 ADA: Add normalizeCommandStatus helper with unit tests
Extract command status normalization logic from HandleCommandAck into
a dedicated helper function. This improves testability and makes the
status alias handling explicit and documented.

The function accepts client-provided status strings and maps them to
internal status constants:
- acknowledged: "", "ack", "acknowledged"
- completed: "success", "completed", "complete"
- failed: "fail", "failed", "error"

Adds 25 table-driven test cases covering all aliases, case insensitivity,
whitespace handling, and invalid inputs.
2025-11-29 17:06:18 +00:00
rcourtman
5201bd7087 Add unit tests for metrics.go helper functions
Test normalizeLabel, normalizeNodeLabel, splitInstanceKey,
breakerStateToValue, sanitizeInstanceLabels, makeMetricKey,
and makeNodeMetricKey with 36 test cases covering edge cases
like empty strings, whitespace, and invalid inputs.
2025-11-29 16:44:37 +00:00
rcourtman
61bb124692 Extract filesystem filtering logic into pkg/fsfilters
Move the inline filesystem skip logic from pollVMsAndContainersEfficient
into a reusable ShouldSkipFilesystem function. This consolidates filtering
for virtual filesystems (tmpfs, cgroup, etc.), network mounts (nfs, cifs,
fuse), and special mountpoints (/dev, /proc, /snap, etc.) into one tested
location.

Reduces cyclomatic complexity of pollVMsAndContainersEfficient and adds
28 test cases covering virtual fs types, network mounts, special mounts,
Windows paths, and edge cases.
2025-11-29 16:38:08 +00:00
rcourtman
69a7d96e4b Merge branch 'ada/20241129-parseversion-test' 2025-11-29 16:32:33 +00:00
rcourtman
a4ef95ef9e Add unit tests for ParseVersion function
Tests basic version parsing, v prefix stripping, prerelease,
build metadata, and error cases for invalid input.
2025-11-29 16:00:44 +00:00
rcourtman
ac5992b6c6 Add regression test for normalizeVersion
Prevents recurrence of the infinite update loop bug fixed in 1b866598
where version prefix mismatch caused continuous self-updates.
2025-11-29 15:22:05 +00:00
rcourtman
e29fda5e5a Rebuild agent token bindings on API token config reload
When api_tokens.json is modified on disk, the ConfigWatcher reloads
the tokens into memory. However, the Monitor's dockerTokenBindings and
hostTokenBindings maps were not synchronized with the new token set,
causing orphaned bindings when agents reconnect after reinstall.

Add SetAPITokenReloadCallback to ConfigWatcher that triggers Monitor's
new RebuildTokenBindings method after token reload. This method
reconstructs the binding maps from current Docker host and host agent
state, keeping only bindings for tokens that still exist in config.

Related to #773
2025-11-29 14:09:30 +00:00
courtmanr@gmail.com
ae3a349124 Refine memory visualization with StackedMemoryBar component
- Add StackedMemoryBar component to visualize Active/Balloon/Swap memory
- Integrate StackedMemoryBar into NodeSummaryTable, GuestRow, HostsOverview, and DockerUnifiedTable
- Add TemperatureGauge component for temperature visualization
- Standardize replication job status indicators with StatusDot
- Fix mock data generator to use realistic balloon memory values (0 by default, small % when active)
- Add StackedContainerBar for Docker container status visualization
- Add ZFSHealthMap component for storage pool health visualization
2025-11-29 13:48:30 +00:00
rcourtman
c3a5aacd21 Fix standalone docker agent version comparison prefix mismatch
The unified agent got the version normalization fix (1b866598), but the
standalone docker agent's checkForUpdates() still used direct string
comparison. When server returns "4.34.0" and agent has "v4.34.0", this
caused an infinite self-update loop.

Apply the same normalizeVersion() function used in the unified agent.

Related to #773
2025-11-29 00:04:43 +00:00
rcourtman
806cdd2d87 Fix Docker CPU calculation on systemUsage counter reset
When systemUsage counter goes backward (common in unprivileged LXC
containers), the previous code used the absolute value as systemDelta.
This created an artificially small denominator, inflating CPU to ~100%.

Now leaves systemDelta as 0 on counter reset, falling through to the
time-based calculation which produces accurate results.

Related to #770
2025-11-28 15:07:49 +00:00
rcourtman
8afc4d0c6c Fix hideLocalLogin toggle persistence and login page UI
- Add hideLocalLogin handler in HandleUpdateSystemSettings() so the
  toggle setting is saved to system.json
- Conditionally hide "or" divider and admin credentials message when
  local login is hidden

Related to #750
2025-11-28 09:05:41 +00:00
rcourtman
1b866598c4 Fix agent self-update infinite loop due to version prefix mismatch
The agent's CurrentVersion includes the "v" prefix (e.g., "v4.33.1") but
the server's /api/agent/version endpoint returns versions without it
(e.g., "4.33.1"). This caused the comparison to always fail, triggering
an infinite self-update loop every 30 seconds.

Normalize both versions by stripping the "v" prefix before comparison.

Related to #740
2025-11-28 06:07:20 +00:00
rcourtman
6ff5ae4200 fix: multiple agent installation and update issues
- Default enableDocker to false in UI to prevent unintended Docker
  agent activation on host-only installs (Related to #766)
- Deploy agent scripts and binaries during web UI upgrades, not just
  the main binary (Related to #760)
- Apply symlink resolution fix to standalone docker agent self-update
  to prevent cross-device rename failures (Related to #737)
2025-11-27 15:49:03 +00:00
rcourtman
cb8c46cfb6 fix: add hash check to polling fallback and persist sidebar state
- Add content hash check to config watcher polling path to match fsnotify
  behavior, preventing unnecessary restarts when .env is touched but
  content unchanged (Related to #748)
- Change settings sidebar to expanded by default and persist user
  preference using usePersistentSignal (Related to #764)
2025-11-27 15:24:23 +00:00
rcourtman
f7ffb36c41 chore: remove dead code and unused exports
Remove ~900 lines of unused code identified by static analysis:

Go:
- internal/logging: Remove 10 unused functions (InitFromConfig, New,
  FromContext, WithLogger, etc.) that were built but never integrated
- cmd/pulse-sensor-proxy: Remove 7 dead validation functions for a
  removed command execution feature
- internal/metrics: Remove 8 unused notification metric functions and
  10 Prometheus metrics that were never wired up

Frontend:
- Delete ActivationBanner.tsx stub component
- Remove unused exports: stopMetricsSampler, getSamplerStatus,
  formatSpeedCompact, parseMetricKey, getResourceAlerts
2025-11-27 13:17:39 +00:00
rcourtman
4cfd1473ba fix(mock): adjust backup time distribution for more realistic data
Reduce never-backed-up guests from 10% to 5% so most mock guests
show backup status rather than grey shields.
2025-11-27 11:04:20 +00:00
courtmanr@gmail.com
0a12200e58 fix(tests): resolve flaky ID generation and symlink resolution on macOS 2025-11-27 10:50:13 +00:00
rcourtman
e9ac1429c0 refactor: remove unnecessary type conversions
Remove redundant type conversions identified by unconvert linter:
- Remove int() conversions for already-int VMID fields
- Remove int64() conversions for already-int64 arithmetic results
- Remove uint64() conversions for already-uint64 Disk/MaxDisk fields
- Remove int() on syscall.Stdin (already int constant)
2025-11-27 10:33:35 +00:00
rcourtman
67b60adb65 style: fix revive linter warnings
- Mark unused stub parameters with underscore
- Rename 'copy' variable to avoid shadowing builtin
- Remove unnecessary else blocks after return statements
2025-11-27 10:26:26 +00:00
rcourtman
1fb4a2c2c6 chore: remove deprecated build tags and use strings.ReplaceAll
- Remove redundant // +build directives (go:build is sufficient in Go 1.17+)
- Replace strings.Replace(..., -1) with strings.ReplaceAll
2025-11-27 10:16:08 +00:00
rcourtman
31927f71e9 fix: mark unused parameters to satisfy unparam linter
Mark intentionally unused parameters with underscore to:
- Silence unparam warnings for legitimate unused parameters
- Keep function signatures intact for API compatibility
- Remove unused req from serveChecksum helper
2025-11-27 10:12:48 +00:00
rcourtman
252d060a58 refactor: use builtin max() and fix unused parameter
- Replace custom maxInt64 helper with Go 1.21+ builtin max()
- Mark unused cfg parameter in newAdaptiveIntervalSelector
- Remove test for deleted helper function
2025-11-27 10:08:37 +00:00
rcourtman
16603e8b4a fix: remove ineffectual assignments
- Fix loop variable reassignment in config_handlers.go
- Remove redundant boolean assignments in swarm.go
2025-11-27 09:48:29 +00:00
rcourtman
60cd019d33 chore: update to non-deprecated Docker SDK types
- Use container.Summary instead of types.Container
- Use swarmtypes.ServiceListOptions instead of types.ServiceListOptions
- Use swarmtypes.TaskListOptions instead of types.TaskListOptions

These types were deprecated in favor of package-specific types.
2025-11-27 09:36:05 +00:00
rcourtman
d7d1631e1c style: use direct type conversions in model converters
Replace struct literal copies with direct type conversions where
the source and destination types have identical field layouts.
2025-11-27 09:24:39 +00:00
rcourtman
95a258ac32 refactor: replace deprecated strings.Title with custom titleCase
Add simple titleCase functions that handle ASCII strings without
the Unicode punctuation issues of strings.Title.
2025-11-27 09:22:52 +00:00
rcourtman
7dad9c7a17 style: fix additional staticcheck warnings
- Lowercase error messages (ST1005)
- Use context.Background() instead of nil (SA1012)
- Fix rand.Intn(1) which always returns 0 (SA4030)
- Remove unnecessary nil check before len() (S1009)
2025-11-27 09:21:11 +00:00
rcourtman
8a1ee3b05e style: fix staticcheck style warnings
- Merge variable declaration with assignment (S1021)
- Use unconditional strings.TrimPrefix (S1017)
- Remove unnecessary nil checks around range (S1031)
- Remove unnecessary fmt.Sprintf (S1039)
- Use copy() instead of manual loop (S1001)
- Use time.Until instead of t.Sub(time.Now()) (S1024)
- Use buf.String() instead of string(buf.Bytes()) (S1030)
2025-11-27 09:19:33 +00:00
rcourtman
e25e1af8cb chore: fix staticcheck SA warnings
- Fix SA4006 unused value issues in ssh.go, validation.go, generator.go
- Replace deprecated ioutil with io/os in config.go
- Replace deprecated tar.TypeRegA with tar.TypeReg
- Remove deprecated rand.Seed calls (auto-seeded in Go 1.20+)
- Fix always-true nil check in main.go
- Fix impossible nil comparison in tempproxy/client.go
- Add nil check for config in monitor.New()
2025-11-27 09:16:53 +00:00
rcourtman
4fd3bdbc04 chore: fix staticcheck U1000 unused code warnings
- Remove unused ipv6Regex from validation.go
- Suppress unused recordAlertFired/recordAlertResolved hooks (kept for future use)
- Remove unused apiLimiter rate limiter
- Remove unused stopOnce fields from csrf_store.go and session_store.go
- Remove unused lastBroadcast field from hub.go
- Remove unused lastUsedIndex field from cluster_client.go
2025-11-27 09:12:17 +00:00
rcourtman
4f25aa9ca1 chore: cleanup proxmox IsAuthError and remove stray comment
- Make IsAuthError unexported (isAuthError) since it's only used internally
- Remove stray '// test comment' from docker_metadata.go
2025-11-27 08:59:01 +00:00
rcourtman
3b23d16c23 chore: remove unused ClusterHealth types
Remove internal/models/cluster.go containing ClusterHealth and
ClusterNodeStatus types that were never used in the codebase.
2025-11-27 08:45:50 +00:00
rcourtman
93723d95c6 chore: remove unused API response types
Remove ChartData, Dataset, ConfigImportResponse, ConfigExportResponse,
InstallScriptResponse, ErrorResponse, and SuccessResponse types that
were defined but never used in the codebase.
2025-11-27 08:37:22 +00:00
rcourtman
4f6c24802c style: fix whitespace in middleware.go 2025-11-27 08:34:31 +00:00
rcourtman
c8e76a52b7 chore: remove unused store methods
Remove 121 lines of unused store methods:
- CSRFTokenStore: Stop, ExtendCSRFToken
- SessionStore: Stop, ExtendSession, GetSession
- RecoveryTokenStore: Stop, save, GetActiveTokenCount, ValidateRecoveryToken

These methods were part of a standard store pattern but never wired up
to the application lifecycle. The constant-time validation variant is
used instead of the timing-vulnerable ValidateRecoveryToken.
2025-11-27 08:31:50 +00:00
rcourtman
72b2444a6c chore: remove unused DockerMetadataHandler.Reload method 2025-11-27 05:14:56 +00:00
rcourtman
b0ce0d932f chore: remove additional dead code
Remove 241 lines of unreachable code across internal and pkg:
- internal/crypto/crypto.go: unused NewCryptoManager wrapper
- internal/monitoring/scheduler.go: unused fixedIntervalSelector type
- internal/ssh/knownhosts/manager.go: unused hostKeyExists function
- internal/updates/manager.go: unused getLatestRelease wrapper
- internal/updates/updater.go: unused GetAll method
- pkg/discovery/discovery.go: unused scanWorker and runPhase (legacy compat)
- pkg/proxmox/client.go: unused post, getTaskStatus, waitForTaskCompletion, getTaskLog
- pkg/proxmox/cluster_client.go: unused markUnhealthy wrapper
2025-11-27 05:13:26 +00:00
rcourtman
25542ae51d chore: remove more dead code
Remove 330 lines of unreachable code:
- internal/monitoring/temperature_service.go: unused temperature service abstraction
- internal/monitoring/temperature.go: unused NewTemperatureCollector wrapper
- internal/mock/generator.go: unused GenerateAlerts function
- internal/mock/integration.go: unused ToggleMockMode wrapper
- internal/notifications/notifications.go: unused sendEmailWithContent,
  generatePayloadFromTemplate, isPrivateRange172, groupAlerts
- internal/notifications/email_providers.go: unused GetProviderDefaults
2025-11-27 00:10:55 +00:00
rcourtman
28aaecd74d chore: remove dead code and unused files
Remove 604 lines of unreachable code identified by deadcode analysis:
- internal/config/credentials.go: unused credential resolver
- internal/config/registration.go: unused registration config
- internal/monitoring/poller.go: unused channel-based polling (keep types)
- internal/api/middleware.go: unused TimeoutHandler, JSONHandler, NewAPIError, ValidationError
- internal/api/security.go: unused IsLockedOut, SecurityHeaders
- internal/api/auth.go: unused min helper
- internal/config/config.go: unused SaveConfig
- internal/config/client_helpers.go: unused CreatePBSConfigFromFields
- internal/logging/logging.go: unused NewRequestID
2025-11-27 00:05:04 +00:00
rcourtman
506484b072 chore: remove unused API types
Remove 261 lines of unused type definitions from types.go:
- NodeRequest, SettingsRequest (unused, actual impl in config_handlers.go)
- ConfigResponse, NodeConfig, SettingsConfig (unused)
- BackupResponse, BackupInfo, MetricsResponse, MetricData (unused)
- StorageResponse, StorageInfo, StorageTotals (unused)
- DiagnosticsResponse and related types (unused)
- SecurityStatusResponse, ExportRequest, ImportRequest (unused)
- NotificationTestRequest, UpdateCheckResponse (unused)
- WebSocketMessage, LoginRequest, LoginResponse (unused)
- TestConnectionResponse, NodeConnectionResponse (unused)
- DiscoveryResponse, DiscoveredServer (pkg/discovery has own types)
- AutoRegisterResponse (unused)
2025-11-26 23:51:41 +00:00
rcourtman
2fe7bb6141 style: fix gofmt formatting inconsistencies
Run gofmt -w to fix tab/space inconsistencies across 33 files.
2025-11-26 23:44:36 +00:00
rcourtman
b40a33fd2b fix: prevent context leak in temperature collection
- Use defer for tempCancel() to ensure context is always cancelled
- Remove redundant shouldCollect variable that was always true
- Fix indentation after removing the unnecessary conditional block
2025-11-26 23:43:18 +00:00
rcourtman
91c72a274c feat: add backup status indicator to guest table
Shows shield icon next to guest name when backup is stale or missing:
- Yellow shield: backup 24-72 hours old
- Red shield: backup older than 72 hours
- Gray shield: no backup found

Fresh backups (<24h) show no indicator to keep the UI clean.
Templates are excluded from backup status display.
2025-11-26 21:30:41 +00:00
rcourtman
d2a303ed0c fix: resolve symlinks for agent self-update to avoid cross-device rename
When the agent binary is symlinked (e.g., from /opt/pulse/bin to
/usr/local/bin), the self-update would fail with "invalid cross-device
link" because os.Rename() doesn't work across filesystems.

Now resolves symlinks before update and creates the temp file in the
same directory as the real binary.

Related to #737
2025-11-26 20:16:09 +00:00
courtmanr@gmail.com
c021dc6ca5 Enhance table responsiveness across multiple components 2025-11-26 17:57:09 +00:00
rcourtman
7fd49fb54a test: add additional tests for internal/agentupdate
Add 6 tests covering:
- Config struct zero value defaults
- NewUpdater with InsecureSkipVerify option
- NewUpdater with Disabled option
- determineArch format validation
- verifyBinaryMagic on directories
- Package constants validation
2025-11-26 14:37:01 +00:00
rcourtman
36544d7487 test: add unit tests for internal/models converters
Add 22 tests covering:
- zeroIfNegative helper function
- copyStringFloatMap deep copy helper
- Node.ToFrontend with display name fallback
- VM.ToFrontend including tags, backup time, negative values
- Container.ToFrontend
- DockerContainer.ToFrontend with ports, networks, mounts, block IO
- DockerService.ToFrontend with endpoint ports
- DockerSwarmInfo.ToFrontend
- Storage.ToFrontend
- hostSensorSummaryToFrontend nil handling
- RemovedDockerHost.ToFrontend
- DockerServicePort.ToFrontend
- DockerTask.ToFrontend with timestamps
2025-11-26 14:33:57 +00:00
rcourtman
3c499322b9 test: add unit tests for internal/metrics
Add 14 tests covering:
- RecordAlertFired, RecordAlertResolved, RecordAlertAcknowledged
- RecordNotificationSent with success/failure
- RecordNotificationRetry, RecordNotificationDLQ
- RecordGroupedNotification with various counts
- RecordAlertEscalation with various levels
- RecordAlertSuppressed with various reasons
- UpdateQueueDepth, UpdateHistorySize
- RecordHistorySaveError
- Metric vector initialization verification
2025-11-26 14:27:54 +00:00
rcourtman
cf45a62c12 test: add unit tests for internal/tempproxy
Add 24 tests covering:
- ErrorType enum constants
- ProxyError Error() and Unwrap() methods
- calculateBackoff exponential backoff with jitter
- contains case-insensitive substring matching
- classifyError error classification for node, auth, SSH, sensor, rate limit, timeout, transport
- RPCRequest and RPCResponse struct fields
- Client struct fields
2025-11-26 14:26:59 +00:00
rcourtman
65b0644027 test: add unit tests for internal/agentbinaries 2025-11-26 14:17:58 +00:00
rcourtman
35412b63d8 test: add unit tests for system package 2025-11-26 14:11:25 +00:00
rcourtman
61b2bfe624 test: add unit tests for types package 2025-11-26 14:10:21 +00:00
rcourtman
0396053b73 test: add unit tests for hostagent package 2025-11-26 14:09:55 +00:00
rcourtman
159a1cb3a3 test: add unit tests for errors package 2025-11-26 14:09:14 +00:00
rcourtman
ae876b4a10 test: add unit tests for sensors parser 2025-11-26 14:06:56 +00:00
rcourtman
4bdf1664bb test: add unit tests for utils package
- Test ID generation (uniqueness, format)
- Test JSON response writing (various types, headers)
- Test boolean parsing (truthy/falsy values)
- Test environment variable trimming
- Test data directory resolution
- Test large payload handling
2025-11-26 13:56:30 +00:00
rcourtman
d37247d220 test: add unit tests for crypto package
- Test encrypt/decrypt round-trip (various data types)
- Test string encryption (base64 output)
- Test key persistence across manager instances
- Test key file permissions (0600)
- Test decryption of invalid/corrupted data
- Test encryption uniqueness (random nonce)
- Test orphaned data protection
- Test large data encryption (1MB)
2025-11-26 13:52:05 +00:00
rcourtman
16d70123bf test: add unit tests for auth package
- Test API token generation (uniqueness, format)
- Test API token hashing (SHA3-256, deterministic)
- Test constant-time token comparison
- Test token hash detection
- Test password hashing (bcrypt, salted)
- Test password verification
- Test password complexity validation
- Verify bcrypt cost and minimum password length constants
2025-11-26 13:51:13 +00:00
rcourtman
1ccbdfe046 test: add unit tests for agentupdate security features
- Test binary magic verification (ELF, PE, Mach-O)
- Test architecture detection
- Test Unraid persistent path generation
- Test updater configuration defaults
- Test edge cases: empty files, too short, non-existent
2025-11-26 13:50:19 +00:00
rcourtman
09ec0c3f01 security: harden agent installers and auto-update mechanism
Install script (scripts/install.sh):
- Add multi-platform support: Unraid, OpenRC/Alpine, Synology DSM 6/7
- Add input validation for URL, token format, and interval
- Add binary magic verification (ELF/Mach-O/PE)
- Add cleanup trap for temp files
- Wrap script in main() for partial download protection
- Fix shellcheck compliance issues
- Add curl timeouts

Agent auto-update (agentupdate, dockeragent):
- Enforce TLS 1.2 minimum version
- Make SHA256 checksum verification mandatory
- Add 100MB binary size limit
- Add binary magic verification before replacement
- Add Unraid persistent binary update after self-update
- Add 5-minute download timeout

Frontend:
- Update Linux install description to note auto-detection of init systems
2025-11-26 13:14:58 +00:00
rcourtman
7f449d30e0 fix: cache daemon ID at init to prevent Podman token binding conflicts
Podman can return unstable or empty daemon IDs across API calls. When
the agent fetched info.ID on every report cycle, this could cause the
agent identity to change mid-session, triggering "token already in use"
errors on the server.

Cache the daemon ID at initialization and use it consistently for all
reports.

Related to #740
2025-11-26 10:23:22 +00:00
rcourtman
d07ad8fd3e fix: use correct script paths in unified agent handlers
The unified agent handlers were using r.config.AppRoot which pointed
to /app, but scripts are in /opt/pulse/scripts. Updated to match the
pattern used by other script handlers - check /opt/pulse/scripts first,
then fall back to project root for dev environment.

Also added no-cache headers to prevent stale scripts being served.
2025-11-26 10:05:43 +00:00
rcourtman
21c033c144 fix: remove references to deleted install-host-agent.sh script
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
2025-11-26 09:57:06 +00:00
rcourtman
e467523a61 feat: serve install scripts from GitHub releases instead of main branch
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
2025-11-26 08:59:59 +00:00
rcourtman
0f0832d30f fix: propagate unified agent version and improve legacy cleanup
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
2025-11-25 23:39:10 +00:00
rcourtman
920f271b41 feat: improve legacy agent detection and migration UX
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.
2025-11-25 23:26:22 +00:00
rcourtman
ee35d9e5a5 feat: add auto-update support for 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
2025-11-25 23:15:03 +00:00
courtmanr@gmail.com
ebcafa1dac feat: adaptive node table layout, guest row fixes, and legacy agent detection
- Implemented adaptive layout for NodeSummaryTable with responsive columns and sticky name column.
- Fixed GuestRow background display issues.
- Added IsLegacy field to Host and DockerHost models to flag legacy agents (version < 1.0.0).
- Updated monitor to populate IsLegacy based on agent version.
2025-11-25 17:19:36 +00:00
courtmanr@gmail.com
26ebd476da WIP: Save all pending changes including frontend updates and unified agent scaffolding 2025-11-25 11:27:07 +00:00
courtmanr@gmail.com
af2caa4b81 Register unified installer routes
Exposes /api/install/install.sh and /api/install/install.ps1 for the unified agent installer.
2025-11-25 11:25:10 +00:00
courtmanr@gmail.com
3599c6592e Improve installer UX with pauses and popups on failure
Fixes #755. Adds interactive pauses and graphical popups (where available) to installer scripts when critical errors occur, ensuring troubleshooting guides are readable. Also clarifies 'build from source' instructions.
2025-11-25 11:17:37 +00:00
courtmanr@gmail.com
809676cb4f Further reduce setup script verbosity: silence token checks and consolidate permission logs 2025-11-25 10:20:17 +00:00
courtmanr@gmail.com
005a878681 Suppress 'User already exists' message in setup script 2025-11-25 10:16:08 +00:00
courtmanr@gmail.com
1f57a8c77a Improve setup script clarity: reduce verbosity and fix confusing messages 2025-11-25 10:13:20 +00:00
courtmanr@gmail.com
6887773b45 Improve setup script output by hiding irrelevant Docker/proxy info 2025-11-25 10:01:41 +00:00
courtmanr@gmail.com
75a9929afc Refactor: Parallelize PVE node polling 2025-11-25 08:38:03 +00:00
courtmanr@gmail.com
3acd29c3f3 Implement UI toggle for Hide Local Login (related to issue #750) 2025-11-25 08:14:19 +00:00
courtmanr@gmail.com
8b7ff2ad48 Relax container SSH check for temperature monitoring (ref #727) 2025-11-25 08:00:08 +00:00
courtmanr@gmail.com
ea8ae63d70 Fix: Prevent unnecessary config reloads by checking file content hash 2025-11-24 22:42:24 +00:00
courtmanr@gmail.com
5031ba481b Fix: Allow double slashes in install script URLs 2025-11-24 17:58:00 +00:00
courtmanr@gmail.com
6b84b9a2bf Add PULSE_AUTH_HIDE_LOCAL_LOGIN option to hide password form
Implements #750 - allows hiding the username/password login form when
using OIDC SSO to avoid user confusion, while maintaining security.

- Added HideLocalLogin config option (env: PULSE_AUTH_HIDE_LOCAL_LOGIN)
- Exposed hideLocalLogin in /api/security/status endpoint
- Updated Login.tsx to conditionally hide local login form
- Added escape hatch via ?show_local=true URL parameter

This approach avoids the security and upgrade issues that led to
DISABLE_AUTH being removed (see #707, #678), while solving the UX
problem of users being confused by multiple login options.
2025-11-24 17:40:43 +00:00
courtmanr@gmail.com
9caba86389 Fix #735: Allow HEAD requests for download endpoints and fix routing
- Allow HEAD requests in addition to GET for all download handlers
  (install scripts, binaries, checksums) to prevent 405 errors
- Add /uninstall-host-agent.sh to special routes in ServeHTTP
- Add test coverage for HEAD request handling
- Resolves 'method not allowed' errors during agent installation
2025-11-24 15:16:14 +00:00
courtmanr@gmail.com
07d8381858 Fix host agent registration verification issues (#746)
- Change default server listen addresses to empty string (listen on all interfaces including IPv6)
- Add short hostname matching fallback in host lookup API to handle FQDN vs short name mismatches
- Implement retry loop (30s) in both Windows and Linux/macOS installers for registration verification
- Fix lint errors: remove unnecessary fmt.Sprintf and nil checks before len()

This resolves the 'Installer could not yet confirm host registration with Pulse' warning
by addressing timing issues, hostname matching, and network connectivity.
2025-11-24 14:28:09 +00:00
courtmanr@gmail.com
08a83c9adb Add host agent checksum route and bump version to 4.32.6
- Add /download/pulse-host-agent.sha256 route to serve checksums
- Fixes 'Checksum not available' warning during host agent installation
- Bump version to 4.32.6

Related to #746
2025-11-24 07:57:17 +00:00
courtmanr@gmail.com
60721cbc22 Add mutex protection for config watcher reloads (re #748)
Introduced sync.RWMutex to protect concurrent access to configuration
fields (AuthUser, AuthPass, APITokens) that are modified by the
ConfigWatcher at runtime.

- Added global config.Mu RWMutex in internal/config/config.go
- Protected config updates in ConfigWatcher.reloadConfig() and reloadAPITokens()
- Protected config reads in CheckAuth and all API token handlers
- Protected Router.SetConfig() during full config reloads

This prevents race conditions when .env file changes trigger config
reloads while authentication handlers are reading the same fields.
2025-11-24 07:45:21 +00:00
courtmanr@gmail.com
68ffa1bc0b Feat: Add support for Raspberry Pi RP1 ADC temperature sensor (Fixes #745)
- Added 'rp1_adc' to the list of recognized CPU temperature chips
2025-11-23 22:33:16 +00:00
courtmanr@gmail.com
af7eabb56d Fix: Correct context cancellation in loop (Fixes #727)
- Replaced defer in loop with explicit cancellation to avoid resource leak
- Properly tagged issue #727
2025-11-23 22:28:28 +00:00
courtmanr@gmail.com
b34e18e839 Fix: Prevent single node auth failure from disabling global SSH temperature collection
- Removed global legacySSHDisabled flag that was triggered by any single node auth failure
- Changed disableLegacySSHOnAuthFailure to only log warnings
- Fixed potential context leak in monitor.go
- Updated tests to reflect removal of global disable logic
2025-11-23 22:24:15 +00:00
courtmanr@gmail.com
35392c1f96 Improve agent update logging and installer warnings (related to #737) 2025-11-23 22:07:37 +00:00
courtmanr@gmail.com
d0a725fde5 fix: Add dev environment fallback paths for Docker agent downloads
- Add fallback to project root scripts/ directory for install-docker-agent.sh
- Add fallback to project root bin/ directory for pulse-docker-agent binary
- Fixes 404 errors when downloading agent installer and binary in dev mode
- Production paths remain unchanged (/opt/pulse/...)
2025-11-23 16:01:40 +00:00
courtmanr@gmail.com
6e404b24eb Fix install-host-agent.sh function order, remove duplicate, and improve dev serving 2025-11-23 12:27:11 +00:00
courtmanr@gmail.com
4bf9c42dbc Fix temperature collection regression for cluster nodes. Related to #727 2025-11-23 12:13:57 +00:00
courtmanr@gmail.com
1945795d36 Fix ZFS storage reporting on TrueNAS SCALE (#718)
- Refactor collector to support mocking
- Fix ZFS detection to support 'fuse.zfs' and case-insensitivity
- Add regression tests for ZFS dataset deduplication
2025-11-22 23:53:39 +00:00
courtmanr@gmail.com
d5fdf2f471 fix: ensure proxmox nodes are displayed even if cluster endpoints are missing
Fixes #727. Previously, if temperature monitoring was enabled and a node wasn't found in ClusterEndpoints, the entire node processing was skipped. This change ensures we only skip temperature collection.
2025-11-22 23:31:30 +00:00
rcourtman
93d8c624b4 Persist PVE fallback host after portless retry 2025-11-22 17:06:15 +00:00
rcourtman
8606bb47cf Handle PVE portless fallback when default port fails 2025-11-22 17:01:16 +00:00
rcourtman
5dbaf7c596 Add OIDC CA bundle support 2025-11-22 09:44:03 +00:00
rcourtman
cd31bdece1 Add log level control to host agent
Related to #742
2025-11-22 07:48:34 +00:00
rcourtman
19a2cac355 Add log level control for docker agent
Related to #742
2025-11-22 07:43:48 +00:00
rcourtman
ee3f1e0cdb Handle standby SMART temps and capture disk identity 2025-11-22 07:35:13 +00:00
rcourtman
6ff54beb38 Handle ignored docker containers during alert reevaluation (related to #561) 2025-11-21 22:19:19 +00:00
rcourtman
4e68675e0b Add recovery notifications and grouping controls 2025-11-21 22:07:00 +00:00
rcourtman
19408fdb2b Related to #738: make pulse proxy mount migration-safe 2025-11-21 21:29:14 +00:00
rcourtman
1f2993f4a7 Guard WebSocket broadcast buffers when clients stall (Related to #734) 2025-11-21 10:14:10 +00:00
rcourtman
5a6c6091bf Honor configured PVE polling interval in scheduler 2025-11-20 22:00:56 +00:00
rcourtman
ac90859e42 Related to #727: normalize persisted Proxmox hosts 2025-11-20 19:58:05 +00:00
rcourtman
d6cbfc23ec Harden public URL detection and setup token handling 2025-11-20 19:27:14 +00:00
rcourtman
d779328878 Add Apprise test support for notifications
Related to #584
2025-11-20 17:54:20 +00:00
rcourtman
044dadcdf1 Related to #727: restore default Proxmox ports 2025-11-20 16:35:08 +00:00
rcourtman
823508dc48 Related to #712: auto-restore host agent binaries for download 2025-11-20 15:45:21 +00:00
courtmanr@gmail.com
838993cf40 Implement sensor proxy installation and configuration updates 2025-11-20 13:23:21 +00:00
courtmanr@gmail.com
6ca543beb6 refactor: simplify sensor proxy installer argument detection by validating CTID and defaulting to standalone mode. 2025-11-20 12:37:08 +00:00
courtmanr@gmail.com
8bfdf3769b Update config persistence, crypto, and dev script 2025-11-20 11:46:20 +00:00
rcourtman
f4e2cbca48 Improve token collision handling and installer subnet support 2025-11-20 09:45:36 +00:00
rcourtman
22f9750044 Respect user-provided node host URLs (Related to #724) 2025-11-20 09:40:38 +00:00
rcourtman
844c895521 WIP: Fix temperature proxy registration persistence (incomplete)
This commit contains multiple fixes for temperature proxy registration,
but the core issue remains unresolved.

## What's Fixed:
1. Added config pointer and reloadFunc to TemperatureProxyHandlers
2. Added SetConfig method to keep handler in sync with router config changes
3. Added config reload after registration to prevent monitor from overwriting
4. Fixed installer port conflict detection and duplicate YAML key issues
5. Added comprehensive debug logging throughout registration flow

## What's Still Broken:
The TemperatureProxyURL, TemperatureProxyToken, and TemperatureProxyControlToken
fields are NOT persisting to nodes.enc after SaveNodesConfig is called.

Debug logs confirm:
- HandleRegister correctly updates nodesConfig.PVEInstances[matchedIndex]
- The correct data is passed to SaveNodesConfig (verified in logs)
- SaveNodesConfig completes without errors
- Config reload executes successfully
- BUT after Pulse restart, the fields are empty when loaded from disk

The bug is in SaveNodesConfig serialization or file writing logic itself.

Related files:
- internal/api/temperature_proxy.go: Registration handler
- internal/config/persistence.go: SaveNodesConfig implementation
- internal/config/config.go: PVEInstance struct definition
2025-11-19 20:12:19 +00:00
rcourtman
c9c4a07508 test(setup): add fmt.Sprintf argument alignment validation test
Added TestPVESetupScriptArgumentAlignment to prevent future fmt.Sprintf
argument mismatch bugs in the PVE quick setup script template.

The test uses sentinel values (SENTINEL_URL, SENTINEL_HOST, deadbeef...)
to verify that critical placeholders receive the correct argument types:

✓ Repair block INSTALLER_URL uses pulseURL (not authToken)
✓ Repair --pulse-server flags use pulseURL (not authToken)
✓ Authorization headers use runtime $AUTH_TOKEN variable (not hardcoded)
✓ Token ID uses tokenName (pulse-*) (not pulseURL or authToken)

This test would have caught the bugs fixed in commits 2bb73d3c7 and
2053bc5e2, where:
- authToken appeared in --pulse-server URLs (argument shift)
- Authorization headers were hardcoded instead of using runtime variable

Recommended by Codex as a safeguard against this class of regression.
2025-11-19 14:53:44 +00:00
rcourtman
708675803f fix(setup): use runtime AUTH_TOKEN variable for Authorization headers
Changed Authorization headers in ssh-config and verify-temperature-ssh API
calls to use the runtime $AUTH_TOKEN variable instead of compile-time
hardcoded authToken.

This fixes a bug where users who override the auth token via:
- PULSE_SETUP_TOKEN environment variable
- Interactive prompt (when auth_token URL param omitted)

...would still send an empty Bearer token in the Authorization headers,
causing API calls to fail with 401 Unauthorized.

Changes:
- Line 4748: -H "Authorization: Bearer %s" → -H "Authorization: Bearer $AUTH_TOKEN"
- Line 4937: -H "Authorization: Bearer %s" → -H "Authorization: Bearer $AUTH_TOKEN"
- Removed 2 authToken arguments from fmt.Sprintf (lines 5059)

Now the script respects runtime token overrides in all code paths.

Identified by Codex during fmt.Sprintf argument alignment review.
2025-11-19 14:53:44 +00:00
rcourtman
82def8c679 fix(setup): correct fmt.Sprintf argument alignment for PVE quick setup
Fixed critical argument mismatch bug where fmt.Sprintf arguments didn't align
with template placeholders. This caused:
- authToken being passed where pulseURL expected (curl errors)
- pulseURL being passed where authToken expected (empty Authorization headers)
- tokenName misalignment (Token ID placeholder broken)

Root cause: Template has 51 %s placeholders (54 total - 3 escaped %%s), but
argument list had wrong count and ordering.

Solution: Rebuilt argument list (lines 5049-5059) with correct mapping:
- 27 pulseURL (all installer URLs, --pulse-server flags, API endpoints)
- 11 tokenName (token creation, checks, final Token ID)
- 3 authToken (AUTH_TOKEN variable + 2 Authorization headers)
- 3 serverHost (error message rerun hints)
- 1 each: serverName, time, pulseIP, storagePerms, SSH keys, minProxyReadyVersion

Verified with go vet (passes). Mapping confirmed by walking each placeholder
in template and matching to correct argument type.

Related to #TBD (user will test)
2025-11-19 14:53:44 +00:00
rcourtman
69133b45fc fix(setup): make manual repair instructions actionable
Issue: When deployment type cannot be determined, error message referenced
$PROXY_INSTALLER but deleted it immediately, making instructions unusable.

Fix: Provide complete curl commands that users can copy-paste directly:
  curl -fsSL $PULSE_URL/api/install/install-sensor-proxy.sh | bash -s -- ...

This ensures users have a working repair path even when auto-detection fails.

Identified by Codex final review.
2025-11-19 13:33:28 +00:00
rcourtman
7e505775ee fix(setup): production-ready sensor-proxy repair logic
Addresses all remaining issues from Codex final review:

Issue 1: SUMMARY_PROXY_INSTALLED unreliable (only set by install.sh)
Fix: Use PROXY_SOCKET_EXISTED_AT_START flag set at script start - works
     for all installation methods (manual, older installers, etc.)

Issue 2: CTID detection fails when container offline/renamed
Fix: Read SUMMARY_CTID from install_summary.json as fallback. Priority:
     1) Live PULSE_CTID detection
     2) SUMMARY_CTID from json file
     3) Standalone node detection

Issue 3: Failed repair disables working proxy (TEMPERATURE_ENABLED=false)
Fix: Keep TEMPERATURE_ENABLED=true in all failure paths. Comments explain:
     proxy was working before, keep it enabled even if repair fails.

This ensures turnkey repair works reliably across all deployment scenarios
without breaking existing working proxies.
2025-11-19 13:24:08 +00:00
rcourtman
6367c7265f fix(setup): comprehensive repair logic for existing sensor-proxy installations
Addresses all issues found in Codex review:

1. Prevent double-install: Check SUMMARY_PROXY_INSTALLED to distinguish
   between fresh installs (skip repair) vs existing installs (run repair)

2. Fix clustered node failures: Explicitly detect deployment type and bail
   out with clear error message if neither --ctid nor --standalone can be
   determined

3. Add health validation: Mirror main install path - verify service active,
   socket exists, and fetch SSH public key after repair

4. Capture installer output: Show full diagnostics on failure (tail -20)

5. Better error messages: Provide specific manual repair commands when
   deployment type cannot be auto-detected

This ensures the turnkey repair experience works reliably without regressing
fresh install UX.
2025-11-19 13:16:15 +00:00
rcourtman
217ed67ee6 fix(setup): properly reinstall sensor-proxy when socket exists (the real fix)
The previous attempt (ed04926) was ineffective - it only set TEMPERATURE_ENABLED=true
which was redundant (already set at line 4051) and didn't trigger the auto-install block
because that block is gated by SKIP_TEMPERATURE_PROMPT != true.

This fix actually downloads and runs install-sensor-proxy.sh when an existing
socket is detected, which:
- Refreshes control plane tokens (fixes 401 errors)
- Updates control plane URL to correct Pulse instance
- Rewrites config atomically (Phase 2 installer is idempotent)
- Maintains turnkey UX - rerunning setup script now actually works

Detected by Codex final review.
2025-11-19 13:08:54 +00:00
rcourtman
ed049263aa fix(setup): always reinstall sensor-proxy to refresh tokens and config
When sensor-proxy socket is detected, the setup script was skipping
temperature monitoring setup with 'already configured' message. This
left stale control plane URLs/tokens, breaking temperature monitoring.

Now follows Codex recommendation: treat existing installations as
upgrade/repair opportunities. The installer is idempotent (Phase 2),
so rerunning it safely refreshes tokens, updates URLs, and ensures
turnkey operation even on hosts with existing installations.

Changes:
- Remove early return when sensor-proxy socket detected
- Set TEMPERATURE_ENABLED=true to proceed with reinstall
- Update message to clarify repair/upgrade behavior
- Maintains turnkey promise: rerun setup and it just works
2025-11-19 12:52:08 +00:00
rcourtman
f4fd4924d6 fix(hostmetrics): dedupe ZFS pools for usable storage
Related to #718
2025-11-18 23:38:11 +00:00
rcourtman
bf63515ff4 feat: avoid redundant PBS snapshot polling (Related to #717) 2025-11-18 23:10:43 +00:00
rcourtman
999e4271a2 feat: surface LXC mountpoints in UI (related to #715) 2025-11-18 22:57:20 +00:00
rcourtman
3f46d35a81 feat: make PVE polling interval configurable (related to #467) 2025-11-18 21:30:04 +00:00
rcourtman
274c45799f Add direct node fallback for storage polling 2025-11-18 19:58:38 +00:00
rcourtman
2e7f693c8b Improve installer temperature proxy and backup polling 2025-11-18 18:42:33 +00:00
rcourtman
5438a25682 Don't disable storages when cluster metadata omits flags 2025-11-18 17:18:23 +00:00
rcourtman
d9c0ddaae2 Allow PBS backup poll to finish after poller returns 2025-11-18 16:55:46 +00:00
rcourtman
54c47fe2f5 Improve temperature proxy detection 2025-11-18 14:25:09 +00:00
rcourtman
b807fe8773 Allow temperature proxy to authorize standalone nodes 2025-11-18 10:30:41 +00:00
rcourtman
7fa39467c0 Fix setup-script tokens and proxy registration timing 2025-11-18 10:22:54 +00:00
rcourtman
527b7ceacc Skip inactive storages during content scans 2025-11-18 09:46:48 +00:00
rcourtman
5a570c89a5 Fix auto-registration token parsing and hostname 2025-11-18 09:10:03 +00:00
rcourtman
f7261f3080 Harden turnkey install and proxy auto-registration 2025-11-18 00:24:50 +00:00
rcourtman
a479040651 Improve temperature proxy workflow 2025-11-17 14:25:46 +00:00
rcourtman
5951a364f7 Auto-deploy proxy for standalone temp monitoring 2025-11-16 09:47:07 +00:00
rcourtman
3ffd79361d Allow socket proxy registration without URL 2025-11-15 22:14:32 +00:00
rcourtman
de5b314842 Improve temperature proxy control-plane flow 2025-11-15 21:49:51 +00:00
rcourtman
ec822575dd Improve update procedure tracking 2025-11-15 16:43:42 +00:00
rcourtman
4fbb118072 Add PULSE_LXC_CTID env override for LXC CTID detection
Modern Proxmox LXC containers (cgroup v2 + systemd) don't expose the CTID
inside the guest namespace. The auto-detection in DetectLXCCTID() works
for older LXC setups and when hostname is numeric, but fails for most
production containers where users set custom hostnames.

Changes:
- Added PULSE_LXC_CTID environment variable override in router.go:490-495
- Graceful fallback: auto-detect first, then check env var, then show placeholder
- UI already handles missing CTID by showing "pct exec <ctid>" placeholder

This provides a robust solution for thousands of users:
- Stock Proxmox LXC: Shows `pct exec <ctid>` placeholder (user substitutes manually)
- Custom hostname containers: Can set PULSE_LXC_CTID=171 in compose/systemd
- Numeric hostname containers: Auto-detected (backwards compatible)

Related: FirstRunSetup.tsx already has graceful fallback (line 336-339)
2025-11-15 13:25:07 +00:00
rcourtman
639635a84b Add Docker container name auto-detection to bootstrap UI
- Added DetectDockerContainerName() to detect container name from hostname
- Extended /api/security/status to expose dockerContainerName field
- Updated FirstRunSetup to show actual container name when detected:
  * Before: 'docker exec <container-name> cat /data/.bootstrap_token'
  * After: 'docker exec pulse cat /data/.bootstrap_token'

This reduces friction for users - no need to look up the container name.
Works when Docker container is named (--name flag), falls back to
placeholder for auto-generated container IDs.
2025-11-15 10:45:00 +00:00
rcourtman
ae0481c982 Improve bootstrap token UX with smart environment detection
- Added DetectLXCCTID() to internal/system/container.go to detect Proxmox container ID
- Extended /api/security/status to expose inContainer and lxcCtid fields
- Updated FirstRunSetup to show most relevant command based on detected environment:
  * LXC with CTID: Shows 'pct exec 171 -- cat /etc/pulse/.bootstrap_token'
  * Docker: Shows 'docker exec <container-name> cat /data/.bootstrap_token'
  * Bare metal: Shows 'cat /etc/pulse/.bootstrap_token'
- Collapsed alternative methods behind 'Show other retrieval methods' button

This addresses user feedback that showing all options was overwhelming.
Now users see the command most likely to work for their setup first,
with alternatives hidden but still accessible.
2025-11-15 10:18:59 +00:00
rcourtman
bcd8d4e0fa Fix critical cleanup implementation issues found by Codex review
**Host Detection**:
- Now detects localhost by hostname and FQDN, not just IP
- Fixes issue where nodes configured as https://hostname:8006 would skip
  localhost cleanup (API tokens, bind mounts, service removal)

**Systemd Sandbox**:
- Added /etc/pve and /etc/systemd/system to ReadWritePaths
- Allows cleanup script to modify Proxmox configs and systemd units

**Uninstaller Improvements**:
- Use UUID for transient unit names (prevents same-second collisions)
- Added --purge flag for complete removal
- Added --wait and --collect flags to capture exit code
- Now fails cleanup if uninstaller exits non-zero

**Path Migration**:
- Fixed all /usr/local references to use /opt/pulse/sensor-proxy
- Updated forced command in SSH authorized_keys
- Updated self-heal script installer path
- Updated Go backend removal helpers (supports both new and legacy paths)

These fixes address Codex findings: hostname detection, sandbox permissions,
transient unit collisions, incomplete purging, and incomplete path migration.

Related to cleanup implementation testing.
2025-11-15 00:33:41 +00:00
rcourtman
c9b4f7e88b Fix incorrect temperature data during cluster initialization
During cluster startup, nodes were temporarily using the primary cluster
endpoint for temperature collection before cluster metadata validation
completed. This caused all nodes to show the same (incorrect) temperature
values for ~4 minutes until validation finished and per-node endpoints
were established.

Example: minipc would show delly's temperature (90°C) instead of its own
(50°C) from startup until cluster validation completed.

Root cause:
- Temperature collection started immediately at startup
- Cluster endpoint validation happened asynchronously
- Code fell back to primary endpoint when ClusterEndpoints was empty
- All nodes used same endpoint, got same temperature data

Fix: Skip temperature collection for cluster nodes until:
1. ClusterEndpoints array is populated (validation complete)
2. Node's specific endpoint is found in the cluster metadata

This ensures correct temperature data from the very first collection,
maintaining data integrity during startup. When persisted config exists,
endpoints are available immediately so no delay occurs. For new clusters,
temperature collection begins once validation completes (~30s).

Preserves Pulse's correctness guarantee: users can trust metrics
immediately after restart without waiting for "warm-up" period.
2025-11-14 23:38:44 +00:00
rcourtman
387a68ef18 Allow dev builds to skip proxy version gate 2025-11-14 21:34:55 +00:00
rcourtman
7cfe998fca Make download tests use temp bin dir 2025-11-14 13:59:50 +00:00
rcourtman
20194d9bb7 Add CI build workflow and tighten proxy diagnostics 2025-11-14 13:32:29 +00:00
rcourtman
349f5627e5 monitoring: add poll watchdog to prevent worker leaks (refs #696) 2025-11-14 11:24:59 +00:00
rcourtman
6e9a62f663 Ensure Windows download finds .exe (related to #684) 2025-11-14 10:59:45 +00:00
rcourtman
70673c1fdc Improve temperature proxy diagnostics and tests 2025-11-13 22:31:53 +00:00
rcourtman
3c707a7368 Fix HTTP mode reliability: add context timeouts to SSH collection
Critical fix for intermittent HTTP endpoint hangs identified by Codex analysis.

## Root Cause
SSH collection via getTemperatureViaSSH() had no timeout, causing HTTP
handlers to block indefinitely when sensors command hung. This held node-level
mutexes and rate limit slots, creating cascading failures where subsequent
requests queued indefinitely.

## Solution
- Thread request context through to SSH execution
- Add exec.CommandContext with 15s timeout (vs 30s HTTP client timeout)
- Create execCommandWithLimitsContext() to wrap SSH commands
- Ensures handlers always release locks and respond within deadline

## Impact
- HTTP temps endpoint now responds in ~70ms consistently
- Temperature data successfully collected and displayed in Pulse
- Eliminates 'context deadline exceeded' errors
- Prevents node gate deadlocks from slow/stuck SSH sessions

Related to Codex session 019a7e99-00fc-7903-afa3-01100baf47c6
2025-11-13 19:09:50 +00:00
rcourtman
e2bd514899 Fix HTTP mode for pulse-sensor-proxy and improve installer safety
## HTTP Server Fixes
- Add source IP middleware to enforce allowed_source_subnets
- Fix missing source subnet validation for external HTTP requests
- HTTP health endpoint now respects subnet restrictions

## Installer Improvements
- Auto-configure allowed_source_subnets with Pulse server IP
- Add cluster node hostnames to allowed_nodes (not just IPs)
- Fix node validation to accept both hostnames and IPs
- Add Pulse server reachability check before installation
- Add port availability check for HTTP mode
- Add automatic rollback on service startup failure
- Add HTTP endpoint health check after installation
- Fix config backup and deduplication (prevent duplicate keys)
- Fix IPv4 validation with loopback rejection
- Improve registration retry logic with detailed errors
- Add automatic LXC bind mount cleanup on uninstall

## Temperature Collection Fixes
- Add local temperature collection for self-monitoring nodes
- Fix node identifier matching (use hostname not SSH host)
- Fix JSON double-encoding in HTTP client response

Related to #XXX (temperature monitoring fixes)
2025-11-13 18:22:36 +00:00
rcourtman
a2b8940873 Add Pulse API endpoints for temperature proxy registration
Implements REST API endpoints to enable automatic registration of
temperature proxies during sensor-proxy installation.

API endpoints:
- POST /api/temperature-proxy/register
  - Accepts: hostname, proxy_url
  - Returns: authentication token
  - Finds matching PVE instance and configures proxy URL/token
  - No authentication required (called during installation)

- DELETE /api/temperature-proxy/unregister?hostname=X
  - Removes proxy configuration from PVE instance
  - Requires admin authentication

Implementation:
- Uses config.ConfigPersistence for loading/saving nodes.enc
- Matches PVE instances by hostname in Host field or ClusterEndpoints
- Generates cryptographically secure random tokens (32 bytes, base64)
- Atomic config updates (load → modify → save)

Next step: Update install-sensor-proxy.sh to call registration API

Related to #571
2025-11-13 16:20:47 +00:00
rcourtman
22f092f941 Add HTTP mode to pulse-sensor-proxy for multi-instance temperature monitoring
This implements HTTP/HTTPS support for pulse-sensor-proxy to enable
temperature monitoring across multiple separate Proxmox instances.

Architecture changes:
- Dual-mode operation: Unix socket (local) + HTTPS (remote)
- Unix socket remains default for security/performance (no breaking change)
- HTTP mode enables temps from external PVE hosts

Backend implementation:
- Add HTTPS server with TLS + Bearer token authentication to sensor-proxy
- Add TemperatureProxyURL and TemperatureProxyToken fields to PVEInstance
- Add HTTP client (internal/tempproxy/http_client.go) for remote proxy calls
- Update temperature collector to prefer HTTP proxy when configured
- Fallback logic: HTTP proxy → Unix socket → direct SSH (if not containerized)

Configuration:
- pulse-sensor-proxy config: http_enabled, http_listen_addr, http_tls_cert/key, http_auth_token
- PVEInstance config: temperature_proxy_url, temperature_proxy_token
- Environment variables: PULSE_SENSOR_PROXY_HTTP_* for all HTTP settings

Security:
- TLS 1.2+ with modern cipher suites
- Constant-time token comparison (timing attack prevention)
- Rate limiting applied to HTTP requests (shared with socket mode)
- Audit logging for all HTTP requests

Next steps:
- Update installer script to support HTTP mode + auto-registration
- Add Pulse API endpoint for proxy registration
- Generate TLS certificates during installation
- Test multi-instance temperature collection

Related to #571 (multi-instance architecture)
2025-11-13 16:13:53 +00:00
rcourtman
56a7579c99 Add Remember Me feature with sliding session expiration (Related to #707)
Implements a "Remember Me" option that allows users to stay logged in
for 30 days instead of the default 24 hours. This addresses the pain
point of frequent re-authentication in LAN-only environments while
maintaining authentication security.

Backend changes:
- Add rememberMe field to login request handling
- Support variable session durations (24h default, 30d with Remember Me)
- Implement sliding session expiration that extends sessions on each
  authenticated request using the original duration
- Store OriginalDuration in session data for proper sliding window
- Update session cookie MaxAge to match session duration

Frontend changes:
- Add "Remember Me for 30 days" checkbox to login form
- Pass rememberMe flag in login request
- Improve UI with clear duration indication

Key features:
- Sessions extend automatically on each request (sliding window)
- Original duration preserved across session extension
- Backward compatible with existing sessions (legacy sessions work)
- Sessions persist across server restarts

This provides a better user experience for LAN deployments without
compromising security by completely disabling authentication.
2025-11-13 10:37:08 +00:00
rcourtman
1166576b21 Ensure agent ID collisions respect token boundaries (Related to #658) 2025-11-12 22:46:56 +00:00
rcourtman
bb55144637 Improve update integration diagnostics 2025-11-12 22:27:05 +00:00
rcourtman
98adb5e08e Preserve storage backups after partial failures (Related to #704) 2025-11-12 21:10:18 +00:00
rcourtman
3b079eeddb Add release dry run workflow and API update integration test 2025-11-12 21:02:52 +00:00
rcourtman
923293fbf7 Related to #692: Skip unsupported guest OS info calls 2025-11-12 19:17:09 +00:00
rcourtman
ff5de0147b Fix missing regexp import for path traversal validation 2025-11-12 16:34:16 +00:00
rcourtman
946e2e455f Security: Fix path traversal vulnerability in host-agent download endpoint
CRITICAL SECURITY FIX: The /download/pulse-host-agent endpoint was directly
concatenating user-supplied platform and arch query parameters into file paths
without validation, allowing path traversal attacks.

An attacker could request:
  /download/pulse-host-agent?platform=../../etc/passwd
to read arbitrary files from the container filesystem.

Fix: Add input validation to only allow alphanumeric characters and hyphens
in platform/arch parameters before using them in file paths.

Related: Codex security audit identified this during pre-release review
2025-11-12 16:27:11 +00:00
rcourtman
72642a2e52 Fix: Skip draft releases in update checker
Bug: Pulse was showing update notifications for draft releases because
the update checker didn't filter them out.

The GitHub API returns draft releases in the releases endpoint, and
Pulse was treating them as available updates even though they're not
published yet.

Fix:
- Added Draft field to ReleaseInfo struct
- Added draft filtering in both RC and stable channel logic
- Draft releases are now skipped with debug logging

This prevents users from seeing "Update available" notifications
when maintainers create draft releases during the release workflow.
2025-11-12 12:31:58 +00:00
rcourtman
48f8473200 Fix router to allow frontend pages without authentication
When a request for /login (or any other frontend route) comes in without
proper Accept headers (like from curl or some browsers), the server was
returning 'Authentication required' text instead of serving the frontend HTML.

This is because the router was checking authentication before serving ANY
non-API route, including frontend pages like /login, /dashboard, etc.

The fix: Frontend routes should always be served without backend auth checks.
The authentication logic runs in the frontend JavaScript after the page loads.

Backend auth should only block:
- API endpoints (/api/*)
- WebSocket connections (/ws*, /socket.io/*)
- Download endpoints (/download/*)
- Special scripts (/install-*.sh, etc.)

All other routes are frontend pages that need to be served to everyone so
the login page can load and handle auth in the browser.

This fixes the integration tests where Playwright couldn't see the login
form because the server was rejecting the /login request before serving HTML.

Related to #695 (release workflow integration tests)
2025-11-12 11:30:22 +00:00
rcourtman
db35ad7c88 Filter read-only filesystems from host agent disk metrics (related to #690)
Squashfs snap mounts on Ubuntu (and similar read-only filesystems like
erofs on Home Assistant OS) always report near-full usage and trigger
false disk alerts. The filter logic existed in Proxmox monitoring but
wasn't applied to host agents.

Changes:
- Extract read-only filesystem filter to shared pkg/fsfilters package
- Apply filter in hostmetrics.collectDisks() for host/docker agents
- Apply filter in monitor.ApplyHostReport() for backward compatibility
- Convert internal/monitoring/fs_filters.go to wrapper functions

This prevents squashfs, erofs, iso9660, cdfs, udf, cramfs, romfs, and
saturated overlay filesystems from generating alerts. Filtering happens
at both collection time (agents) and ingestion time (server) to ensure
older agents don't cause false alerts until they're updated.
2025-11-12 09:47:02 +00:00
rcourtman
d9e0505394 Fix notification manager deadlock in Stop()
Critical deadlock fix:
- Stop() was holding n.mu lock while calling queue.Stop()
- queue.Stop() waits for worker goroutines to finish
- Worker goroutines call ProcessQueuedNotification() which needs n.mu lock
- This created a classic lock-order deadlock

Fix:
- Unlock n.mu before calling queue.Stop()
- Relock after queue shutdown completes
- Workers can now finish and acquire lock as needed

This resolves 30-second test timeouts in notifications package.

Tests now complete in <1s instead of timing out at 30s.
2025-11-11 23:58:18 +00:00
rcourtman
fbeaa91fc0 Fix NVMe temperature merge test expectations
Update test expectations to match new SMART-preferred behavior:
- mergeNVMeTempsIntoDisks now prioritizes SMART temps over NVMe temps
- NVMe temps only applied to disks with Temperature == 0
- Tests were failing because disks started with non-zero temperatures
- Changed test disks to start with Temperature: 0 to simulate fresh disks

This change was introduced in commit 2a79d57f7 (Add SMART temperature
collection for physical disks) but tests weren't updated.

Fixes TestMergeNVMeTempsIntoDisks and TestMergeNVMeTempsIntoDisksClearsMissingOrInvalid.
2025-11-11 23:54:45 +00:00
rcourtman
02273e7fcb Fix monitoring test panic and goroutine leaks
Two critical fixes to prevent test timeouts:

1. Nil map panic in TestPollPVEInstanceUsesRRDMemUsedFallback:
   - Test monitor was missing nodeLastOnline map initialization
   - Panic occurred when pollPVEInstance tried to update nodeLastOnline[nodeID]
   - Caused deadlock when panic recovery tried to acquire already-held mutex
   - Added nodeLastOnline: make(map[string]time.Time) to test monitor

2. Alert manager goroutine leak in Docker tests:
   - newTestMonitor() created alert manager but never stopped it
   - Background goroutines (escalationChecker, periodicSaveAlerts) kept running
   - Added t.Cleanup(func() { m.alertManager.Stop() }) to test helper

These fixes resolve the 10+ minute test timeouts in CI workflows.

Related to workflow run 19281508603.
2025-11-11 23:52:24 +00:00
rcourtman
bbe11d1e7f Fix discovery test Prometheus metric collision
Remove t.Parallel() from tests that verify global Prometheus gauge values.
When tests run in parallel, they update the same global gauges
(discoveryScanServers, discoveryScanErrors) causing race conditions and
incorrect metric values.

Fixes test failure in workflow run 19281332332:
- TestPerformScanRecordsHistoryAndMetrics expected 2 servers, got 1

Related to release workflow preflight tests.
2025-11-11 23:34:49 +00:00
rcourtman
b41f8a2ac4 Fix backend test failures blocking release workflow
Three categories of fixes:

1. Goroutine leak causing 10-minute timeout:
   - Add defer mon.notificationMgr.Stop() in monitor_memory_test.go
   - Background goroutines from notification manager weren't being stopped

2. Database NULL column scanning errors:
   - Change LastError from string to *string in queue.go
   - Change PayloadBytes from int to *int in queue.go
   - SQL NULL values require pointer types in Go

3. SSRF protection blocking test servers:
   - Check allowlist for localhost before rejecting in notifications.go
   - Set PULSE_DATA_DIR to temp directory in tests
   - Add defer nm.Stop() calls to prevent goroutine leaks

Fixes for preflight test failures in workflow run 19280879903.
2025-11-11 23:27:03 +00:00
rcourtman
515987cc8b Fix failing backend tests in preflight checks
Fixes three test failures that were blocking release workflow:

1. TestApplyDockerReportGeneratesUniqueIDsForCollidingHosts:
   - Initialize dockerTokenBindings and dockerMetadataStore in test helper
   - These maps were nil causing panic on first access

2. TestSendGroupedAppriseHTTP & TestSendTestNotificationAppriseHTTP:
   - Configure allowlist to permit localhost (127.0.0.1) for test servers
   - SSRF protection was blocking httptest.NewServer() URLs
   - Tests need to allowlist the test server IP to bypass security checks

Related to workflow fix in 5fa78c3e3.
2025-11-11 23:02:45 +00:00
rcourtman
3e90737448 Fix guest agent OS info calls causing OpenBSD VM crashes (related to #692)
Add defensive mitigation to prevent repeated guest-get-osinfo calls that
trigger buggy behavior in QEMU guest agent 9.0.2 on OpenBSD 7.6.

The issue: OpenBSD doesn't have /etc/os-release (Linux convention), and
qemu-ga 9.0.2 appears to spawn excessive helper processes trying to read
this file whenever guest-get-osinfo is called. These helpers don't clean
up properly, eventually exhausting the process table and crashing the VM.

The fix: Track consecutive OS info failures per VM. After 3 failures,
automatically skip future guest-get-osinfo calls for that VM while
continuing to fetch other guest agent data (network interfaces, version).
This prevents triggering the buggy code path while maintaining most guest
agent functionality.

The counter resets on success, so if the guest agent is upgraded or the
issue is resolved, Pulse will automatically resume OS info collection.

Related to #692
2025-11-11 22:27:22 +00:00
rcourtman
b2d441852d Merge update service refactor with SSE and job queue
- Add job queue system to ensure only one update runs at a time
- Add Server-Sent Events (SSE) for real-time push updates
- Increase rate limit from 20/min to 60/min for update endpoints
- Add unit tests for queue and SSE functionality
- Frontend: Update modal now uses SSE with polling fallback

Eliminates: 429 rate limit errors, duplicate modals, race conditions
Related to #671
2025-11-11 10:06:16 +00:00
Claude
cc46e3c6f0
Refactor update service to eliminate polling and race conditions
This commit implements a comprehensive refactoring of the update system
to address race conditions, redundant polling, and rate limiting issues.

Backend changes:
- Add job queue system to ensure only ONE update runs at a time
- Implement Server-Sent Events (SSE) for real-time update progress
- Add rate limiting to /api/updates/status (5-second minimum per client)
- Create SSE broadcaster for push-based status updates
- Integrate job queue with update manager for atomic operations
- Add comprehensive unit tests for queue and SSE components

Frontend changes:
- Update UpdateProgressModal to use SSE as primary mechanism
- Implement automatic fallback to polling when SSE unavailable
- Maintain backward compatibility with existing update flow
- Clean up SSE connections on component unmount

API changes:
- Add new endpoint: GET /api/updates/stream (SSE)
- Enhance /api/updates/status with client-based rate limiting
- Return cached status with appropriate headers when rate limited

Benefits:
- Eliminates 429 rate limit errors during updates
- Only one update job can run at a time (prevents race conditions)
- Real-time updates via SSE reduce unnecessary polling
- Graceful degradation to polling when SSE unavailable
- Better resource utilization and reduced server load

Testing:
- All existing tests pass
- New unit tests for queue and SSE functionality
- Integration tests verify complete update flow
2025-11-11 09:33:05 +00:00
rcourtman
e894bc7b1d Fix recurring update issues (related to #671)
This commit addresses three recurring issues with the update system:

1. **Checksum mismatches (v4.27.0, v4.28.0):**
   - Root cause: Release process uploads checksums.txt first, but if artifacts
     are rebuilt after that upload, checksums become stale
   - Fix: Update RELEASE_CHECKLIST.md to REQUIRE running validate-release.sh
     before publishing (step 9, non-negotiable)
   - The validation script exists and catches these errors, but wasn't being
     enforced in the release process

2. **Duplicate error modals:**
   - Root cause: UpdateProgressModal rendered in both App.tsx
     (GlobalUpdateProgressWatcher) and UpdateBanner.tsx
   - Fix: Remove UpdateProgressModal from UpdateBanner.tsx
   - GlobalUpdateProgressWatcher automatically shows the modal when updates
     start, so the banner's modal is redundant

3. **Rate limiting too strict:**
   - Root cause: UpdateProgressModal polls /api/updates/status every 2 seconds
     (30 req/min), but rate limit was 20/min
   - Fix: Increase UpdateEndpoints rate limit from 20/min to 60/min
   - Allows modal to poll without hitting rate limits during updates

These were all manual process errors and configuration issues, not code bugs.
The validation script enforcement prevents future checksum mismatches.
2025-11-11 09:09:30 +00:00
rcourtman
accecdb50b Make api_tokens.json authoritative source for API tokens (fixes #685)
This is the proper architectural fix for #685. The previous commit was a
bandaid that prevented unnecessary .env writes. This commit addresses the
root cause: dual-source-of-truth for API tokens (.env vs api_tokens.json).

Changes:

1. Startup Migration (config.go:896-951):
   - When loading config, if API_TOKEN/API_TOKENS exist in .env but not in
     api_tokens.json, automatically migrate them
   - Migrated tokens are named "Migrated from .env (prefix)" for clarity
   - Logs a deprecation warning: API_TOKEN/API_TOKENS in .env are deprecated
   - Leaves .env untouched (safe for existing deployments)

2. Config Watcher Changes (watcher.go:338-424):
   - Only load tokens from .env if api_tokens.json is EMPTY
   - Once api_tokens.json has records, it becomes the authoritative source
   - .env changes no longer trigger token overwrites when api_tokens.json exists
   - Logs debug message when ignoring env tokens

Result:
- Existing deployments: env tokens automatically migrated to api_tokens.json
- UI-created tokens: never overwritten by .env changes
- Dark mode toggle: no longer triggers token reload from .env
- Backward compatible: fresh installs with API_TOKEN in .env still work
- Migration path: users can safely keep API_TOKEN in .env, it will be ignored

Future improvement: Add UI warning when API_TOKEN/API_TOKENS still present
in .env, prompting users to rotate tokens via the UI.
2025-11-11 00:17:40 +00:00
rcourtman
5d99fc2f2d Fix dark mode toggle wiping API tokens (related to #685)
Root cause: SaveSystemSettings calls updateEnvFile which rewrites .env on
any setting change, triggering the config watcher. The watcher sees API_TOKEN
in .env and replaces all UI-created tokens with "Environment token" records,
wiping out host-agent scoped tokens.

Fix: updateEnvFile now compares the new content with existing content and
skips the write if nothing changed. Since dark mode (and other UI settings)
are stored in system.json, not .env, toggling theme no longer triggers
unnecessary .env rewrites.

This prevents the config watcher from being triggered unnecessarily and
preserves UI-created API tokens when changing cosmetic settings.

Future improvement: Deprecate API_TOKEN/API_TOKENS from .env entirely and
make api_tokens.json the single source of truth (requires migration logic).
2025-11-11 00:11:41 +00:00
rcourtman
df185985eb Fix bootstrap token path display for Docker deployments (related to #680)
The first-run setup UI was displaying incorrect bootstrap token paths for
Docker deployments. It showed `/etc/pulse/.bootstrap_token` regardless of
deployment type, but Docker containers use `/data/.bootstrap_token` by
default (via PULSE_DATA_DIR env var).

Changes:
- Extended `/api/security/status` endpoint to include `bootstrapTokenPath`
  and `isDocker` fields when a bootstrap token is active
- Updated FirstRunSetup component to fetch and display the correct path
  dynamically based on actual deployment configuration
- For Docker deployments, UI now shows both `docker exec` command and
  in-container command
- Falls back to showing both standard and Docker paths if API data
  unavailable (backward compatibility)

This fix ensures users always see the correct command for their specific
deployment, including custom PULSE_DATA_DIR configurations.
2025-11-09 23:41:55 +00:00
rcourtman
a82a345cd6 Improve table column widths and sparkline visibility 2025-11-09 23:36:52 +00:00
rcourtman
425ea00ba2 Fix upgrade path when DISABLE_AUTH detected but no credentials exist (fixes #678)
Users upgrading from v4.25 (where DISABLE_AUTH actually disabled auth) to
v4.27.1 (where DISABLE_AUTH is ignored but triggers a deprecation warning)
were stuck in a catch-22:

- They had no credentials (old version had auth disabled)
- DISABLE_AUTH detection incorrectly required authentication
- Setup wizard returned 401, preventing first credential creation
- Could not complete setup to create credentials and remove flag

Root cause: When DISABLE_AUTH was detected, the code set forceRequested=true
which triggered the authentication requirement even when authConfigured=false.

Fix: Only require authentication when credentials actually exist. When no
auth is configured, allow the bootstrap token flow regardless of whether
DISABLE_AUTH is detected.

This lets users upgrade from legacy DISABLE_AUTH deployments by using the
bootstrap token to create their first credentials, then removing the flag.
2025-11-09 20:33:58 +00:00
rcourtman
62a9f40cc7 Fix diagnostics incorrectly warning about /run mount in Docker (related to #600)
The diagnostic code was warning ALL deployments using /run/pulse-sensor-proxy
socket path to "remove and re-add" their configuration to use /mnt/pulse-proxy
instead. This was incorrect for Docker deployments where /run is the correct
and documented mount path (see docker-compose.yml line 15).

The warning was only meant for LXC containers where the managed mount at
/mnt/pulse-proxy is preferred over a legacy hand-crafted /run mount.

Fix: Only show the warning in non-Docker environments (check PULSE_DOCKER env).
Docker deployments correctly use /run/pulse-sensor-proxy per compose file.

Impact: Docker users were seeing confusing diagnostic warnings telling them
to reconfigure a correct setup.
2025-11-09 16:49:49 +00:00