mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-20 18:55:40 +00:00
Guard infrastructure import plan approvals
- add candidate import approval and preview gate for node onboarding - document metrics, availability, and proxy role behavior - lock config auth reads and preserve storage metrics fallback
This commit is contained in:
@@ -111,6 +111,13 @@ shared `/api/resources` payload carries a backend-authored Proxmox workload
|
||||
target linked to that node agent. Suppressing an inside-guest install cue for
|
||||
that case means governed actions have a node-agent path; it must not be
|
||||
presented as proof that a guest-local agent is installed.
|
||||
Candidate-sourced PVE/PBS/PMG onboarding remains lifecycle-owned even when the
|
||||
candidate starts in Discovery or a platform probe: the settings connection flow
|
||||
may preview the monitored-system impact and credential path, but setup
|
||||
commands, downloaded scripts, manual token command copies, and manual saves
|
||||
must stay blocked until the operator explicitly approves the candidate import
|
||||
plan. Type-first manual adds without a candidate must stay on the normal
|
||||
credential-entry path and must not synthesize a discovery import plan.
|
||||
Agent-facing operations-loop status wiring in `internal/api/router.go` and
|
||||
`internal/api/agent_resource_context.go` is lifecycle-adjacent only because it
|
||||
shares agent route infrastructure. Other handlers in `internal/api/` such as
|
||||
@@ -3173,6 +3180,16 @@ That same node setup modal owner must also stay on the direct
|
||||
`NodeModalStatusFooter.tsx`, `nodeModalModel.ts`, and `useNodeModalState.ts`,
|
||||
rather than relying only on broad lane ownership or downstream command tests
|
||||
to catch lifecycle drift in the settings surface.
|
||||
Candidate-sourced PVE/PBS/PMG node setup is part of that same node setup
|
||||
owner. When a connection originates from Discovery or the API platform probe,
|
||||
`InfrastructureWorkspace.tsx` must pass the candidate into
|
||||
`NodeCredentialSlot.tsx`, `infrastructureImportPlanModel.ts` must derive the
|
||||
endpoint, identity, credential path, collection scope, monitored-system preview
|
||||
request, and reset signature, and the setup surface must require explicit
|
||||
operator approval before any assisted setup command, downloaded setup script,
|
||||
manual token command copy, or manual save can proceed. Direct type-first adds
|
||||
with no candidate remain normal credential entry and must not fabricate an
|
||||
import plan.
|
||||
That same Proxmox lifecycle transport now explicitly includes the shared
|
||||
`frontend-modern/src/api/nodes.ts` client boundary itself: changes to setup
|
||||
command or install-command request transport must carry both lifecycle proof
|
||||
|
||||
@@ -151,6 +151,23 @@ configured admin role may pass admin gates. Installations that intentionally
|
||||
make every proxy-authenticated user an admin must do that by leaving the role
|
||||
header unset and protecting Pulse at the proxy/IdP layer.
|
||||
|
||||
Local credential auth reads are also part of this shared boundary. Handlers in
|
||||
`internal/api/auth.go` and `internal/api/router.go` that compare `AuthUser` and
|
||||
`AuthPass` must snapshot those mutable config fields while holding
|
||||
`config.Mu.RLock()` before running constant-time username or password-hash
|
||||
checks. CSRF bootstrap checks may snapshot local auth, API-token, and proxy
|
||||
secret presence under that same lock, then evaluate SSO provider state outside
|
||||
the config lock.
|
||||
|
||||
Candidate import plans for PVE/PBS/PMG onboarding are API-contract consumers,
|
||||
not local UI estimates. Probe and Discovery candidates must build their
|
||||
preview through `frontend-modern/src/api/monitoredSystemLedger.ts` and
|
||||
`POST /api/license/monitored-system-ledger/preview`, preserving source,
|
||||
resource type, name, hostname, host URL, and resource id in the request. The
|
||||
frontend may render the preview and approval state, but it must not persist a
|
||||
candidate or call node setup/save APIs until the operator has approved the
|
||||
current endpoint, credential path, and collection scope.
|
||||
|
||||
Assistant chat `workflow_state` events are a shared AI/API payload boundary.
|
||||
The backend source of truth is `internal/ai/chat.WorkflowStateData`, generated
|
||||
to `frontend-modern/src/api/generated/aiChatEvents.ts` by
|
||||
|
||||
@@ -193,6 +193,15 @@ deep-link flow. The self-hosted `Plans` page is not a deep-link-only flow:
|
||||
`system-billing` stays visible whenever commercial presentation is allowed,
|
||||
while demo or commercial-suppressed sessions may still hide it.
|
||||
|
||||
Candidate import-plan presentation inside the Infrastructure settings dialog is
|
||||
a shared primitive composition boundary. `NodeCandidateImportPlan.tsx` may use
|
||||
shared `Button`, checkbox styling, lucide icons, and
|
||||
`MonitoredSystemImpactPreview`, while `InfrastructureWorkspace.tsx` owns the
|
||||
route-backed dialog state that feeds probe or Discovery candidates into the
|
||||
credential slot. That surface must keep the approval card readable inside the
|
||||
existing dialog body and must not introduce a second nested modal, detached
|
||||
wizard shell, or page-local preview renderer for monitored-system impact.
|
||||
|
||||
Frontend localization is a shared primitive boundary. Locale support must flow
|
||||
through typed message catalogs with an English fallback and explicit seed
|
||||
locale coverage rather than page-local string switches.
|
||||
|
||||
@@ -371,6 +371,14 @@ truth for live infrastructure data.
|
||||
|
||||
## Current State
|
||||
|
||||
The monitoring-owned storage metrics runtime must preserve store-backed storage
|
||||
chart continuity during resolver warm-up. `syncUnifiedStorageMetrics` must
|
||||
prefer the resolver's canonical storage metrics target when it exists, but must
|
||||
fall back to the storage resource id instead of dropping the resource when the
|
||||
resolver has not yet produced a storage target. The fallback is a metrics
|
||||
continuity path for canonical storage resources, not a second storage identity
|
||||
or recovery-source model.
|
||||
|
||||
That same reloadable multi-tenant monitor boundary also owns instance-wide
|
||||
notification settings fan-out. `ForEachMonitor` visits every live tenant
|
||||
monitor so callers can propagate the webhook security allowlist and public
|
||||
|
||||
@@ -204,6 +204,12 @@ regression protection.
|
||||
fetches, Discovery probes, or page-local external-link logic on the table
|
||||
hot path.
|
||||
4. Keep shared auth gating in `internal/api/router.go` cheap and local: pre-auth quick-setup and recovery routing may short-circuit on loopback/session/token checks, but they must not trigger chart, metrics, or broad persistence fan-out on the protected request hot path.
|
||||
Reading mutable auth configuration for CSRF bootstrap and login checks must
|
||||
stay a short in-memory snapshot under `config.Mu.RLock()`: local
|
||||
username/password presence, API-token presence, and proxy-auth secret
|
||||
presence may be copied while locked, while SSO provider presence is checked
|
||||
after the lock is released. This preserves the protected hot path and avoids
|
||||
holding the config lock across provider/state work.
|
||||
The same rule applies to public setup-script lifecycle routes: `/api/auto-register`
|
||||
and `/api/auto-unregister` may bypass the global auth wall so their handlers can
|
||||
validate request-body setup tokens, but the router-level public-path check must
|
||||
|
||||
@@ -234,6 +234,12 @@ existing resource-policy redaction still governs any model-bound context.
|
||||
Pulse Mobile token scopes, bypass the server-minted credential requirement,
|
||||
or expose relay secrets beyond the existing public onboarding diagnostics.
|
||||
4. Change security/auth/token transport behavior through the shared `frontend-modern/src/api/security.ts`, `frontend-modern/src/components/Settings/APITokenManager.tsx`, `frontend-modern/src/components/Settings/apiTokenManagerModel.ts`, `frontend-modern/src/components/Settings/useAPITokenManagerState.ts`, `internal/api/security.go`, `internal/api/security_tokens.go`, and `internal/api/system_settings.go` boundary.
|
||||
Local username/password verification in `internal/api/auth.go` and
|
||||
`internal/api/router.go` must snapshot `AuthUser` and `AuthPass` under
|
||||
`config.Mu.RLock()` before comparison. Security/privacy may consume that
|
||||
shared auth result, but it must not read mutable credential fields outside
|
||||
the shared config lock or hold the lock across password hashing, session
|
||||
mutation, SSO provider checks, or response writing.
|
||||
Release metadata surfaced through `/api/version` remains outside token,
|
||||
auth, and privacy state. Adding or changing `agentUpdateTargetVersion`
|
||||
must stay limited to non-secret deployable release identity and must not
|
||||
|
||||
@@ -239,6 +239,11 @@ Storage/recovery auth-adjacent changes may consume SSO-authenticated sessions,
|
||||
but they must not reinterpret SAML or multi-provider SSO availability as a
|
||||
storage/recovery entitlement; that provider-route and license truth belongs to
|
||||
the shared API/security boundary.
|
||||
Storage/recovery may consume authenticated chart and report routes through the
|
||||
shared API boundary, but it must not own router-level auth configuration reads.
|
||||
Those reads stay API/security-owned and must snapshot mutable auth credentials
|
||||
under `config.Mu.RLock()` before storage-adjacent routes rely on the resulting
|
||||
session or API-token decision.
|
||||
Storage/recovery may also consume org-scoped session identity from the shared
|
||||
API boundary, but durable user IDs remain the authorization principal. Contact
|
||||
email may support display or legacy lookup only; storage and recovery surfaces
|
||||
|
||||
Reference in New Issue
Block a user