Commit Graph

1051 Commits

Author SHA1 Message Date
rcourtman 60d7db6ef9 Harden agentexec token binding and disk filtering 2026-04-23 15:54:48 +01:00
rcourtman 8b6a429186 Surface standalone agent identity in infrastructure settings 2026-04-23 15:03:41 +01:00
rcourtman a5687cd22e Formalize v6 paid-surface classification 2026-04-23 14:53:41 +01:00
rcourtman 60f97ccd51 Deduplicate represented infrastructure hosts by alias 2026-04-23 14:21:45 +01:00
rcourtman 2ae16e885b Render Proxmox cluster members beneath cluster row 2026-04-23 13:28:31 +01:00
rcourtman 0e08caee77 Fix prerelease unified-agent release asset lookup 2026-04-23 13:15:52 +01:00
rcourtman 83444d7510 Model Proxmox cluster grouping in infrastructure settings 2026-04-23 12:30:20 +01:00
rcourtman 642da71a85 Surface agent version in infrastructure settings 2026-04-22 22:57:08 +01:00
rcourtman 5b79a80e1a Group attached agents under owning sources 2026-04-22 21:19:06 +01:00
rcourtman 0a4584535e Preserve agent rows across monitor reloads 2026-04-22 20:48:16 +01:00
rcourtman 2b618c8eaa Fix setup-script teardown symmetry 2026-04-22 20:26:15 +01:00
rcourtman df04b9b1ff Fix reviewed Proxmox setup convergence 2026-04-22 19:54:20 +01:00
rcourtman 48e4ec818c Make self-hosted settings plan-owned 2026-04-22 19:49:50 +01:00
rcourtman 74c2660f8d Expose infrastructure onboarding diagnostics 2026-04-22 15:37:56 +01:00
rcourtman e55013d14f Bound Stripe webhook dedupe retention 2026-04-22 13:37:05 +01:00
rcourtman 8a42bb432e Harden commercial callback and transport URL policy 2026-04-22 10:57:21 +01:00
rcourtman 752f9a49ea Require fresh browser session for ownership transfer 2026-04-22 09:41:30 +01:00
rcourtman c0ac251316 Require target-organization approval for org shares 2026-04-22 09:16:40 +01:00
rcourtman 2806cc6c9e Split audit log access into dedicated token scope 2026-04-22 07:59:12 +01:00
rcourtman ce9b89abee Make hosted signup responses privacy-safe 2026-04-22 07:12:56 +01:00
rcourtman 583471b5ee Harden API request and bootstrap state handling 2026-04-22 05:42:45 +01:00
rcourtman 178c073830 Keep bootstrap setup tokens out of logs 2026-04-22 05:30:40 +01:00
rcourtman ccb2edc3b8 Require explicit websocket origin continuity 2026-04-22 04:46:13 +01:00
rcourtman 14fc2bd4f0 Fail closed on wildcard trusted proxy configuration 2026-04-22 04:23:23 +01:00
rcourtman 4720807ae5 Require signed installer downloads and local release sidecars 2026-04-22 03:51:46 +01:00
rcourtman f7c1d9b629 Require accepted org invitations and stable runtime capabilities 2026-04-22 03:06:22 +01:00
rcourtman 7be844f23a Require signed unified agent release assets 2026-04-22 02:00:29 +01:00
rcourtman 43922161e4 Harden connection probe and simple stats rendering 2026-04-22 01:18:33 +01:00
rcourtman 70acd663bd Strengthen export and license persistence encryption 2026-04-22 01:03:10 +01:00
rcourtman 586473ee31 Bind recovery and bootstrap auth to direct loopback 2026-04-22 00:39:53 +01:00
rcourtman 360d08104e Compile out release env guardrail bypasses 2026-04-22 00:05:57 +01:00
rcourtman 3ec2c0779e Harden agent command and deploy trust boundaries 2026-04-21 23:50:34 +01:00
rcourtman 02e9107ac4 Harden cloud handoff membership authorization 2026-04-21 23:18:35 +01:00
rcourtman 62ec34ef02 Route hostname lookups through canonical equivalence 2026-04-21 22:47:23 +01:00
rcourtman 074b04eb76 Prove offline Proxmox node visibility in v6
Refs #1433
2026-04-21 22:23:53 +01:00
rcourtman e1c852350e fix: rebuild unified-seed source mappings for dashboard trends 2026-04-21 18:30:49 +01:00
rcourtman 770cceae52 Fix self-hosted community entitlements reporting expired state 2026-04-20 23:48:31 +01:00
rcourtman d8d94c48e1 Expose local commercial funnel diagnostics 2026-04-20 22:27:34 +01:00
rcourtman c20766b7b8 Instrument self-hosted billing conversion stages 2026-04-20 21:46:59 +01:00
rcourtman c4a4d175ce Fix v6 dry run backend contract regressions 2026-04-20 14:57:49 +01:00
rcourtman 6db9aeadcf Prepare the v6 stable promotion candidate 2026-04-20 14:09:17 +01:00
rcourtman ec28bb3314 Accept aggregator semantic IDs on node mutation endpoints
The unified /api/connections aggregator emits IDs as {type}:{name}
(e.g. "pve:delly"), but the PUT/DELETE/refresh-cluster/test endpoints
only parsed the legacy {type}-{index} array-position form. That left
the new Connection surface unable to drive any mutation against the
entries it lists.

HandleUpdateNode, HandleDeleteNode, HandleRefreshClusterNodes, and
HandleTestNode now route the incoming ID through a shared
resolveNodeID helper: colon-form resolves by Name (404 on miss),
dash-form keeps the existing index semantics. Frontend connection
client gains setEnabled/remove that dispatch to the right per-type
endpoint by ID prefix.
2026-04-19 20:42:22 +01:00
rcourtman f221a71569 Probe web-UI root so PVE/PBS/PMG detection survives the 3s auth delay
/api2/json/version requires authentication, and PVE/PBS deliberately delay
401 responses by ~3s as a timing-attack mitigation. Our 3s probe budget
fired right as the 401 arrived — every probe returned zero candidates
against real targets.

Switch the PVE/PBS/PMG fingerprint path to the web-UI root (/), which
serves the login page in <100ms and carries the same identifying Server
banner (PVE/PMG) or an unambiguous HTML title (PBS, which omits the
Server header on /). Drop versionHintsFromProxmoxBody — /version was the
only caller, and we can surface version after authentication instead.

Verified end-to-end against a live PVE (delly:8006, 41ms) and live PBS
(100.106.60.119:8007, 70ms); fan-out on a bare hostname returns the
correct product.
2026-04-19 20:10:45 +01:00
rcourtman 406b966b86 v6(settings): phase 8 — per-surface Monitor* scope for TrueNAS and VMware
Adds positive MonitorDatasets/Pools/Replication booleans to TrueNASInstance
and MonitorVMs/Hosts/Datastores to VMwareVCenterInstance, matching the
PVE/PBS/PMG scope pattern. NewInstance defaults all surfaces to true;
ApplyDefaults migrates legacy all-false records to all-true so existing
truenas.json / vmware.json on disk continue monitoring after upgrade.

The unified connections aggregator now reads those booleans into the
Scope map and flips SupportsScope to true for both types, so the Scope
UI in the ConnectionEditor is a straight wire-through to the native
config fields — no new storage or adapter layer. Per-type API clients,
form state, and the TrueNAS and VMware credential slots render the same
three-checkbox "Collection scope" panel used by PVE/PBS/PMG, replacing
the old per-type Stop-this-surface dialog end-to-end from the editor's
side.

Contracts updated: agent-lifecycle, api-contracts, storage-recovery.
Tests: truenas.test.ts and vmware.test.ts round-trip the new monitor*
flags through list + update payloads; config tests cover the legacy
all-false ApplyDefaults migration; aggregator test asserts the scope map
and SupportsScope: true for both types.

Provider Refresh paths still fetch everything in one trip; honoring
Monitor* inside VMware and TrueNAS pollers is deferred to a follow-up.
2026-04-19 15:02:18 +01:00
rcourtman 9e60f2aec6 Scrub stale community billing caps
Refs #1429
2026-04-19 12:17:20 +01:00
rcourtman 9c3d96cab2 Add unified connections API (list + probe) with Disabled flag
Introduces GET /api/connections and POST /api/connections/probe as the
backend half of the one-ledger / one-editor connection redesign.

- GET /api/connections aggregates PVE/PBS/PMG/VMware/TrueNAS/agent rows
  into a unified Connection shape with derived state (active, paused,
  unauthorized, unreachable, stale, pending) computed from in-memory
  scheduler health plus agent Host.LastSeen. No new persisted state.
- POST /api/connections/probe fingerprints a host across the five
  supported products in parallel (2s dial + 1s read, 3s total, max 5
  concurrent). Admin-gated (RequireAdmin + ScopeSettingsWrite) to block
  unauthenticated SSRF against internal hosts.
- Disabled bool on PVEInstance/PBSInstance/PMGInstance (zero-value =
  enabled, preserves existing nodes.json); pollers skip disabled
  instances at client init, reconnect, and per-node iteration.
- NodeConfigRequest/Response gain Enabled; write path translates
  *bool -> Disabled so omitted field leaves state untouched.
- ConnectionsAPI frontend client (list/probe) typed off the Go shape.

Contracts updated: api-contracts, monitoring, agent-lifecycle,
performance-and-scalability, storage-recovery. Proofs added:
contract_test.go JSON snapshot for Connection and ProbeResponse,
monitoring guardrails for the Disabled-skip behavior, and a vitest
mock-client test for ConnectionsAPI.

Frontend editor / drawer / table rewrite lands in a separate block.
2026-04-19 11:42:53 +01:00
rcourtman 329f59eddb Add health-state indicators to Infrastructure, Storage, Workloads, and Recovery summaries
Summary cards now show degraded/alerting/failing counts rather than raw
online/offline splits, giving operators an at-a-glance health posture without
drilling into the full resource list.

- InfrastructureSummary/infrastructureSummaryModel: adds degraded and alerting
  counts derived from resource statuses and active alerts
- StorageSummary/StoragePageSummary/useStoragePageSummary: adds poolsDegraded
  and disksFailing indicators, shows "all healthy" when zero degradation
- WorkloadsSummary/useDashboardWorkloadDerivedState: adds alerting guest count
  from activeAlerts accessor, included in summary header counts
- RecoverySummary: adds aggregate health-state summary row
- useDashboardState: threads alertsEnabled through workload derived state
- Fix monitored-system cap test helper to use TierEnterprise so limits are
  honored (self-hosted tiers are now uncapped per the v6 product model)
- Update registry and governance test snapshots to include
  useStoragePageSummary.test.ts in the storage-product-surface proof set
2026-04-19 08:35:45 +01:00
rcourtman 9bac3f421d Fix agent-token fallback to reject cross-org tokens and update security contract test
Two test regressions introduced when agent-report tokens were allowed as
fallback auth for /api/auto-register:

1. Org mismatch was not checked: a token belonging to org-a could authenticate
   a request whose context carried org-b. Add an explicit org consistency check
   before setting authenticated=true in the fallback path.

2. The security regression test assumed only setup tokens could authenticate
   auto-register. That contract has intentionally changed: agent-report tokens
   can now authenticate but are restricted to updating existing nodes (403 for
   new-node attempts). Update the test to assert the actual security boundary.
2026-04-18 23:10:50 +01:00
rcourtman 688bdd4246 Fix PVE connection health key in registration check
The isKnownDisconnected helper was building the key as
instanceType+"-"+instanceName ("pve-delly"), but the PVE
PollProvider's connectionKey function returns the bare instance
name ("delly"). PBS uses "pbs-"+name. The mismatch meant the
disconnected-node check always missed, rendering the server-side
stale-token detection inert.

Fix: use type-specific key construction matching the PollProvider
connectionKey implementations.
2026-04-18 22:37:24 +01:00
rcourtman 501c61b82f Fix PVE stale token self-healing after failed registration
Two gaps in the existing flow allowed a disconnected PVE node to stay
broken indefinitely even after the agent restarted:

1. Server-side: autoRegisteredNodeExists checked only that a PVE/PBS
   instance existed in the config, not whether its connection was
   healthy. A node with a stale token would return registered=true on
   every check, causing the agent to skip re-registration forever.
   Fixed: also consult GetConnectionStatuses(); return registered=false
   when the monitor has a definitive disconnected entry so the agent can
   rotate and re-register.

2. Agent-side: the type-specific registration marker was cleared only on
   success. If rotation succeeded but the Pulse update failed (e.g.
   transient network error), the old marker from a previous successful
   registration persisted, leaving next-startup to skip setup again.
   Fixed: clear the marker before entering the token setup/rotation
   phase so any failure leaves the system in a retriable state.

Together these two fixes make the stale-token scenario self-healing:
the monitor detects the broken connection, the next agent startup sees
registered=false, clears its marker, rotates the token, and updates
Pulse — without manual intervention.
2026-04-18 22:07:30 +01:00