POST /api/security/quick-setup with force=true sets the administrator
username and password and replaces every API token with a full-access
one. With authentication already configured, a token holding only
settings:write could call it, so settings:write was enough to take the
instance over, although the endpoint is documented as needing a
bootstrap token or an authenticated session.
A token caller now needs an instance-wide full-access token (full access,
bound only to the default organization) once the request would change
credentials. The not-forced "already configured" answer is unchanged, and
browser sessions, the bootstrap token and recovery token paths are
untouched.
The two existing force tests that used a settings:write caller are about
persistence rollback and settings preservation, so they now use a
full-access caller. The new tests use a deliberately weak password so a
caller that passes the check is stopped by validation before any
credential or session is written, and they fail when the check is removed.
Contract-Neutral: Behavioural fix that gives credential rotation the authority check regenerate-token and token management already have; no new API surface or contract.
Two authorization gaps where a token could do more than its scopes allow.
POST /api/security/regenerate-token replaces the whole token inventory,
wildcard tokens included, and issues a full-access credential (nil scopes
normalise to "*"). A token holding only settings:write could therefore
wipe every other token and mint an unrestricted one, which the normal
create and update paths refuse because a caller can only grant scopes it
holds. A token caller now needs full-access scope and must not be bound
to a non-default organization; anything narrower gets 403 and is pointed at
POST /api/security/tokens/{id}/rotate, which replaces one token. Admin
sessions are unchanged.
/api/resources/ is one prefix route gated on monitoring:read, but it also
dispatches POST link, unlink and report-merge, which persist resource
identity changes. A read-only token could change them. Anything other
than GET or HEAD on that prefix now needs monitoring:write; the more
specific registrations (operator-state, maintenance) keep their own gates.
Tests pin both boundaries and each fails when its fix is reverted. Two
existing regenerate tests that used a settings:write caller now use a
full-access one, since their subject is owner inheritance and rollback.
Contract-Neutral: Behavioural fix that enforces the documented token scope model; no new API surface or contract.
A provider opening a client workspace from the Pulse Account portal
arrives in that client's organization as its owner. ensureAdminSession
admits an org manager to the org-bound settings routes, but the security
status snapshot reported every settings capability as false for any
org-scoped session. Since the Settings navigation started hiding gated
panels in August, the owner saw only General: no Infrastructure page to
connect the client's Proxmox or install agents, and no Reporting page
for the client reports. The portal's handoff to
/settings/infrastructure fell through to General. Found on a fresh
v6.4.1 provider bundle, where /api/config/nodes answered 200 for the
same session that /api/security/status said could reach nothing.
Route and snapshot now share one settings-admin rule,
sessionUserHasSettingsAdminPrivileges. The snapshot keeps it out of
sessionIsAdmin: it widens only infrastructureRead, availabilityRead and
reportingRead, whose handlers read the organization's own config and
monitor state. Instance administration, detailLevel, authUsername and
billingAdmin stay withheld from org-scoped sessions, as the scoped
local session contract requires.
Quick security setup previously replaced system.json with defaults even for authenticated force reconfiguration. Initialize only absent settings under the persistence save mutex, preserving existing bytes and read failures. Cover credential rotation, custom and malformed settings, missing settings, and read errors without changing authorization or token scopes.
Change-source: pulse-maintainer
First-run setup saved the configured administrator but left the router authorizer on its startup identity. This split Settings capability checks: administrator-only panels remained visible while API Access and Pulse Intelligence were denied until restart. Keep the captured authorizer aligned when setup commits the identity, and clear its prior bypass on successful development reset.
Cover the exact split with real file-backed RBAC policy and session setup, preserve outsider denial and identity replacement, and synchronise concurrent policy reads. Extension implementations still require independent compatibility review; this is not installation or release acceptance.
Change-source: pulse-maintainer
Restore the complete live token inventory when durable writes fail during legacy regeneration, quick security setup, and container-runtime token preparation. Return an error instead of exposing or claiming an unpersisted credential.
Contract-Neutral: hardens internal failure handling without changing successful API payloads or extension contracts
canAccessPlatformAdminSurface publishes billingAdmin for any instance
administrator. RequirePlatformAdmin compared the session user against
cfg.AuthUser alone, so on an instance whose only administrators are SSO
principals the UI offered the surface and the route refused it. Same
capability against enforcement split as 28fd2d1c1, on the hosted routes.
The session branch now uses sessionUserCarriesAdminPrivileges, which is what
the capability already resolves to.
A straight swap would have been worse than the bug. That helper treats any SSO
principal as an administrator when no local admin is configured, and a hosted
control plane authenticates its tenants by SSO, so on a control plane with no
local admin every tenant would have become a platform admin. The session
branch is therefore also gated on the request not being org-scoped, matching
what ensureAdminSession and the security status snapshot already do. Removing
that gate lets an org-scoped tenant session reach the surface with a 200,
which the parity test pins.
The org-scope test itself was written inline in two places and is now one
helper, sessionIsOrgScoped, so the instance-versus-tenant boundary has a
single definition rather than a copy per caller.
RequireOrgOwnerOrPlatformAdmin is untouched. It has no session branch in its
platform-admin switch by design and requires org ownership instead.
Contract-Neutral: behavioral fix on existing routes, no request or response shape change; platform admin route aligned with the billingAdmin capability it already publishes
The privileged-session gate (ensureAdminSession) and the settings
capabilities snapshot only accepted a session whose username equals the
configured local admin identity. SSO users are keyed by their
provider-scoped principal (sso:oidc:...), which can never match, so an
SSO session was locked out of every settings-scoped route no matter what
roles it held. That made group role mappings (group=admin) appear
broken (#1535) and surfaced as 'Unable to load SSO providers' when an
SSO user opened the SSO settings panel (#1533).
A session user now passes the gate when their effective RBAC
permissions include the admin action on all resources, which is the
shape the built-in Administrator role assigns through group role
mappings. On an instance with no local admin identity configured at all
(the v5 OIDC-only pattern), SSO sessions pass as before the rewrite,
since they are the only administrators the instance has. Org-scoped
tenant sessions keep their own management rules.
Refs #1533, #1535
The loopback gate from 586473ee3 rejected non-loopback setup requests
before the bootstrap-token check could run, so a Proxmox-LXC install
(install script prints URL + token; user opens URL on workstation,
pastes token) hit "only available from localhost" even with the correct
token. The token is the security boundary — only callers with
filesystem access to the data dir can read it — so a valid token now
authorizes setup from any origin. No-token requests still require
direct loopback.
Updates the two contract/setup tests that pinned the old behavior.
Fixes discussion #1459.
Make direct CheckAuth failures return explicit auth-required responses while preserving route-specific auth errors through shared response capture.
Align API contract tests with uncapped self-hosted monitoring, route-local config import/export auth, and marketed entitlement upgrade reasons.
- Replace barrel import in AuditLogPanel.tsx to fix ad-blocker crash
- Remove all Enterprise/Pro badges from nav and feature headers
- Simplify upgrade CTAs to clean 'Upgrade to Pro' links
- Update docs: PULSE_PRO.md, API.md, README.md, SECURITY.md
- Align terminology: single Pro tier, no separate Enterprise tier
Also includes prior refactoring:
- Move auth package to pkg/auth for enterprise reuse
- Export server functions for testability
- Stabilize CLI tests
When no auth is configured (fresh install), CheckAuth allows all requests.
This creates a race condition where existing agents from a previous setup
can report data before the wizard completes security configuration.
This fix clears all host agents and docker hosts when /api/security/quick-setup
is called, ensuring the wizard shows a clean state after security is configured.
Added:
- State.ClearAllHosts() - removes all host agents
- State.ClearAllDockerHosts() - removes all docker hosts
- Monitor.ClearUnauthenticatedAgents() - clears both and resets token bindings
- Call to ClearUnauthenticatedAgents() in handleQuickSecuritySetupFixed()
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.
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.
The bootstrap token security requirement was added proactively but
lacked discoverability, causing user friction during first-run setup.
These improvements make the token easier to find while maintaining
the security benefit.
Improvements:
- Display bootstrap token prominently in startup logs with ASCII box
(previously: single line log message)
- Add `pulse bootstrap-token` CLI command to display token on demand
(Docker: docker exec <container> /app/pulse bootstrap-token)
- Improve error messages in quick-setup API to show exact commands
for retrieving token when missing or invalid
- Error messages now include both Docker and bare metal examples
User experience improvements:
- Token visible in `docker logs` output immediately
- Clear instructions printed with token
- Helpful error messages if token is wrong/missing
- CLI helper for operators who need to retrieve token later
Security unchanged:
- Bootstrap token still required for first-run setup
- Token still auto-deleted after successful setup
- No bypass mechanism added
Related to discussion about bootstrap token UX friction.
Introduces granular permission scopes for API tokens (docker:report, docker:manage, host-agent:report, monitoring:read/write, settings:read/write) allowing tokens to be restricted to minimum required access. Legacy tokens default to full access until scopes are explicitly configured.
Adds standalone host agent for monitoring Linux, macOS, and Windows servers outside Proxmox/Docker estates. New Servers workspace in UI displays uptime, OS metadata, and capacity metrics from enrolled agents.
Includes comprehensive token management UI overhaul with scope presets, inline editing, and visual scope indicators.
Improves configuration handling and system settings APIs to support
v4.24.0 features including runtime logging controls, adaptive polling
configuration, and enhanced config export/persistence.
Changes:
- Add config override system for discovery service
- Enhance system settings API with runtime logging controls
- Improve config persistence and export functionality
- Update security setup handling
- Refine monitoring and discovery service integration
These changes provide the backend support for the configuration
features documented in the v4.24.0 release.