Commit Graph

11520 Commits

Author SHA1 Message Date
pulse-triage[bot] f3518d9b9b fix(provider-msp): qualify installer purchase guidance
Keep first-run evaluation and summary guidance conditional on actual Plan availability and confirmed active limits. Remove the ordinary manual-key purchase prompt while retaining the separate custom-license binding path, and update the installability contract and focused assertions in the same commit.

Change-source: pulse-maintainer
2026-09-24 04:52:30 +01:00
rcourtman 2752b1040e Merge pull request #2221 from rcourtman/claude/msp-setup-plan-hint
Point provider MSP setup at the portal Plan tab to buy
2026-09-24 04:32:24 +01:00
pulse-triage[bot] bd190e7560 Merge pull request #2222 from rcourtman/maintainer/20260924T025314Z
Confirm purchased MSP plans only after the new licence is active
2026-09-24 03:26:32 +00:00
pulse-triage[bot] 78a72ba652 Merge batch-start upstream main
Change-source: pulse-maintainer
2026-09-24 03:52:19 +01:00
rcourtman 9b16aeac9c Point provider MSP setup at the portal Plan tab to buy
setup.sh still told an evaluating provider to "request an upgrade" at
/msp.html#request, a form that waited on a human reply with a checkout
link. The portal now sells plans itself (Plan tab, Stripe checkout,
applied in seconds), so both the evaluation log line and the closing
summary send the provider there. The summary also stops printing the
lease signing public key as something the licence "must bind": the
portal purchase binds it without a copy step, and the key is still
available through --print-lease-signing-public-key for a custom licence.
2026-09-24 03:52:09 +01:00
pulse-triage[bot] f44c47f9de Merge pull request #2220 from rcourtman/maintainer/20260924T015622Z
Provider MSP setup starts a working control plane after client recovery
2026-09-24 02:50:33 +00:00
pulse-triage[bot] 65c8011d77 Merge provider Plan return correction with current main
Preserve the refreshed-plan confirmation and its generated portal assets over provider MSP client recovery. Change-source: pulse-maintainer

Change-source: pulse-maintainer
2026-09-24 03:21:23 +01:00
pulse-triage[bot] 0f7406695c Merge upstream provider MSP client recovery
Combine the already published #2216 recovery with the local first-run setup correction; preserve both release-control contract notes.

Change-source: pulse-maintainer
2026-09-24 03:12:51 +01:00
pulse-triage[bot] 60bfb2dbc2 fix(portal): confirm applied provider plan on refreshed main
Carry the checked checkout-return race correction onto the current main snapshot. Await the refreshed licence identity before announcing the paid plan; ignore overtaken plan reads after restart.

Contract-Neutral: Restores the existing provider-hosted Plan confirmation without changing plan, entitlement, route, price, or role contracts.
Change-source: pulse-maintainer
2026-09-24 03:05:07 +01:00
rcourtman a27a7d07f1 Merge pull request #2216 from rcourtman/claude/msp-support-network-reconcile
Keep provider MSP clients running across upgrades
2026-09-24 03:04:48 +01:00
pulse-triage[bot] 390e1f7824 Merge upstream main snapshot 68088a737c
Change-source: pulse-maintainer
2026-09-24 02:48:25 +01:00
pulse-triage[bot] 1a4504e1b2 fix(portal): confirm applied provider plan on current main candidate
Compose the provider-hosted Plan return race correction with the current provider MSP deployment and shorter-expiry repairs. The portal waits for the exact refreshed licence after control-plane restart and ignores an overtaken initial plan response.

Contract-Neutral: This restores the existing cloud-paid Plan contract to confirm the restarted control plane serves the refreshed licence; no plan, entitlement, route, price, or role contract changes.
Change-source: pulse-maintainer
2026-09-24 02:41:39 +01:00
pulse-triage[bot] 68088a737c Merge pull request #2219 from rcourtman/maintainer/20260924T005314Z
Honor shortened provider MSP paid-licence periods
2026-09-24 01:39:00 +00:00
pulse-triage[bot] 12ffa72a96 fix(provider-msp): leave first-run platform running
Start the provider services after licensed compose validation so the printed bootstrap and portal link have a live control plane. Correct the first-run prompt to name only operator-provided values and retain an install contract regression test.

Change-source: pulse-maintainer
2026-09-24 02:24:21 +01:00
rcourtman bd4cad1bb9 Merge remote-tracking branch 'origin/main' into claude/msp-support-network-reconcile
# Conflicts:
#	docs/release-control/v6/internal/subsystems/cloud-paid.md
#	docs/release-control/v6/internal/subsystems/deployment-installability.md
2026-09-24 02:23:30 +01:00
pulse-triage[bot] 53206a1e60 fix(portal): confirm applied provider plan before announcing it
A licence refresh can finish before the initial plan request, so the old
evaluation or renewal date was reported as active after restart. Match the
returned licence identity and expiry, ignore stale plan responses, and keep
polling until the serving control plane exposes that state. Add race and
same-plan renewal regression tests and update the embedded portal bundle.

Contract-Neutral: This restores the existing cloud-paid Plan contract to poll until the restarted control plane serves the refreshed licence; no plan, entitlement, route, price, or role contract changes.
Change-source: pulse-maintainer
2026-09-24 01:54:47 +01:00
pulse-triage[bot] 08b4fa835c fix(cloudcp): apply shortened provider MSP licence periods
A billing-cycle change can retain the licence ID and plan while moving the signed paid period earlier. Compare the full signed expiry, replace the old token and restart, with regression coverage and the matching cloud-paid contract guarantee.

Change-source: pulse-maintainer
2026-09-24 01:47:02 +01:00
rcourtman a384db5d34 Merge pull request #2215 from rcourtman/claude/msp-portal-purchase
Let a provider-hosted platform buy, renew and see its own plan
2026-09-24 01:23:02 +01:00
rcourtman 5c2b4de313 Apply a plan changed in Manage billing on return
A sandbox run of the purchase path showed that a provider who changed
plan in the Stripe billing portal came back to the portal's Clients page
still on the old plan. It stayed that way until the next six-hourly
refresh, unless they found the "Just paid? Apply my purchase now" button,
whose wording does not fit a plan change. Manage billing now returns to
?provider_msp_checkout=billing, and the Plan panel checks the licence
twice on the way back, which is enough for the plan-change webhook to
land without polling on every visit. In the same run Solo to Starter and
back applied about ten seconds after returning.

The paid panel also dropped "Licence valid to <date>". That date is the
paid period end plus 14 days of grace, so a buyer read it as the date they
had paid until. It now appears only once the licence is inside that grace,
as a warning that the subscription has not renewed.
2026-09-24 00:28:19 +01:00
rcourtman 4daf0df92c Keep provider MSP clients running across upgrades
Every upgrade.sh run recreates the control plane, and a recreated support
container is no longer attached to any client's isolated tenant network.
The health monitor then could not reach the clients, counted three
failures, and stopped each one, expecting the unless-stopped restart policy
to bring it back. Docker never restarts a container stopped through the
API, so every client workspace stayed down until someone started it by
hand. A Traefik recreate also left client routes returning 504.
Reproduced on a v6.4.1 provider bundle with two clients.

The monitor now reattaches Traefik and the control plane to each active
client's network once at startup and on every pass, and recovers an
unhealthy client with a single restart instead of a stop. With the fix on
the same install, a control-plane recreate rejoined both networks within a
second, a Traefik-only recreate had its routes back on the next pass, and
no client was stopped.
2026-09-24 00:06:49 +01:00
rcourtman 15ffacab59 Merge remote-tracking branch 'origin/main' into claude/msp-portal-plan-panel
# Conflicts:
#	docs/release-control/v6/internal/subsystems/cloud-paid.md
#	docs/release-control/v6/internal/subsystems/deployment-installability.md
2026-09-23 23:47:42 +01:00
rcourtman edda116236 Show a provider-hosted platform its plan and let it buy one
The portal had no billing surface in provider-hosted mode, so a provider
on the free evaluation could not see when it expired, how many client
slots it had left, or any way to pay. Provider-hosted mode now shows the
billing section as Plan. It lists the evaluation or paid plan, its
expiry and the workspaces in use, and on an evaluation it offers the
plans above the current cap at the licence server's Stripe prices.

Owners and admins get Buy, Manage billing, and "Apply my purchase now";
read-only members are told who can buy. After Stripe returns to the
portal the panel keeps refreshing the licence until the purchase lands,
then polls until the restarted control plane serves the new plan,
without reloading the page.

Exercised on a fresh v6.4.1 provider bundle running this build against
a stand-in licence server: the tab, the evaluation expiry and slot
usage, monthly and annual pricing, Buy reaching checkout with the
platform's licence ID and portal return URL, the periodic refresh
signed with the lab's lease key, and a 390px layout with no horizontal
overflow.
2026-09-23 23:45:28 +01:00
rcourtman 205785b655 Merge pull request #2209 from rcourtman/claude/msp-hosted-install-token
Mint agent install tokens in hosted client workspaces
2026-09-23 23:44:20 +01:00
pulse-triage[bot] 08dfdad4d0 Merge pull request #2211 from rcourtman/maintainer/20260923T215018Z
Guard orphaned-backup opt-out and TrueNAS disk-write boundaries
2026-09-23 22:43:46 +00:00
rcourtman 9ff9387c59 Merge pull request #2210 from rcourtman/claude/msp-status-health
Judge client health from Docker when status runs out of band
2026-09-23 23:39:48 +01:00
rcourtman 185c6ac80b Let a provider-hosted platform buy and renew its own licence
A provider could stand the MSP bundle up and evaluate it without asking
anyone, but paying still meant emailing its public key to Pulse and
copying a licence file onto the host by hand. With the licence server's
self-serve purchase path (pulse-pro license-server/provider_msp_purchase),
the control plane can do the whole thing itself.

The control plane now signs a challenge with its lease signing key to
fetch the licence its subscription entitles, validates it exactly as
startup does, requires it to bind this platform's key, and keeps it in
the data directory, because the host licence is a read-only secret
mount. Startup prefers that renewed licence while it validates, so a
paying provider keeps starting after the self-issued evaluation on the
host expires. A changed licence restarts the control plane through the
existing graceful shutdown, since the plan version is read at load by
every workspace-limit, backup and status path; client workspaces keep
running. Preflight, proof, recovery and backup accept either signed
source.

The portal gains owner and admin routes for plan state, checkout, the
Stripe billing portal and an immediate licence refresh, and the plan list
comes from the licence server so it shows only what can be bought, at
Stripe's price. Adds the msp_solo plan: 3 client workspaces, the first
paid step above the 2-workspace evaluation.
2026-09-23 23:30:34 +01:00
rcourtman 05dfff8431 Merge remote-tracking branch 'origin/main' into claude/msp-hosted-install-token
# Conflicts:
#	docs/release-control/v6/internal/subsystems/agent-lifecycle.md
#	docs/release-control/v6/internal/subsystems/storage-recovery.md
2026-09-23 22:55:00 +01:00
pulse-triage[bot] 466a43707c Merge commit '1836341eaec489b889155e777891c0e835f52303'
Change-source: pulse-maintainer
2026-09-23 22:51:34 +01:00
rcourtman 1836341eae Merge pull request #2208 from rcourtman/claude/msp-org-owner-settings
Offer org owners the settings their own org's routes serve
2026-09-23 22:48:19 +01:00
rcourtman f338bd4765 Judge client health from Docker when status runs out of band
provider-msp status, which upgrade.sh and the install proof gate on,
runs in a one-off `docker compose run` container attached only to the
provider ingress network. Its health check dialled each client's
container on the client's isolated network, which that container cannot
reach, and an unreachable client counts as unhealthy. So on any install
with a real client, status failed with "unhealthy active workspaces" and
./upgrade.sh --dry-run exited 1: the backup-gated upgrade path refused to
run as soon as a provider onboarded anyone. CI proofs never saw it
because they only ever run against an empty install. Reproduced on a
fresh v6.4.1 provider bundle with one client whose container Docker
reported healthy.

The runtime image declares a HEALTHCHECK that probes the same
/api/health inside the container, and Docker records the result where
any caller with the socket can read it. Use that when it exists and keep
the HTTP probe for images without one. With the change the same install
reports healthy_tenants=1 and upgrade.sh --dry-run plans cleanly.
2026-09-23 22:46:47 +01:00
pulse-triage[bot] 70788d90f5 Merge orphaned-backup alert regression test
Change-source: pulse-maintainer
2026-09-23 22:37:53 +01:00
pulse-triage[bot] 1adfbb1f24 Merge monitoring target-boundary test
Change-source: pulse-maintainer
2026-09-23 22:37:47 +01:00
pulse-triage[bot] bb6a8be6f1 test(alerts): verify orphaned backup opt-out clears canonical alert
The existing regression only rejected legacy backup-age key prefixes, so it could pass while a canonical orphaned alert remained active. Assert a real orphan alert exists first, then disable the option and require every backup-age alert to clear. This guards the opt-out relevant to #1741 without changing runtime policy.

Change-source: pulse-maintainer
2026-09-23 22:31:02 +01:00
pulse-triage[bot] cc510b0675 test(monitoring): pin TrueNAS disk-write target boundary
Extend the existing same-hostname host-agent and TrueNAS fixture to the disk-write series reported in #1966. Assert connection-scoped agent targets, distinct source values, and that TrueNAS pool capacity writes are not disk-write samples. Keep cross-target equality explicitly synthetic pending reporter evidence.

Change-source: pulse-maintainer
2026-09-23 22:30:38 +01:00
rcourtman adf07a370a Mint agent install tokens in hosted client workspaces
Every provider MSP client workspace runs in hosted mode, where users sign
in through the control plane handoff. The install endpoints decided
whether to mint a token from the workspace's own config, which on a fresh
client has no local credential, API token, proxy secret or SSO provider.
So Settings > Infrastructure > Generate token answered 200 with an empty
token and the Proxmox flow built a command without one: a provider could
not install a single agent from the client workspace. Found on a fresh
v6.4.1 provider bundle.

The router's configTransferAuthenticationConfigured already counts hosted
mode as enforced authentication; the agent-lifecycle copy of the rule
never gained that term. Add it. Self-hosted runtimes with no auth keep
the token-less command.
2026-09-23 22:23:20 +01:00
rcourtman 4d47504331 Offer org owners the settings their own org's routes serve
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.
2026-09-23 22:11:03 +01:00
pulse-triage[bot] d272711c85 Merge pull request #2206 from rcourtman/maintainer/20260923T184316Z
Reduce resource-view read contention and verify TrueNAS metric targets
2026-09-23 19:30:49 +00:00
rcourtman 30bb1ed3ed Merge pull request #2204 from rcourtman/claude/stable-promotion-pin-drift
Let stable promotion carry test-only and installer pin changes
2026-09-23 20:15:25 +01:00
rcourtman 71ec1d875b Let stable promotion carry test-only and installer pin changes
Every stable cut re-pins CANONICAL_DEFAULT_PULSE_VERSION in
scripts/install-docker.sh from the RC to the stable version, and the
stable install-metadata test requires it. The drift allowlist omitted
that file, so no release candidate could be promoted without
hotfix_exception. The rule arrived on 2026-09-01, after v6.4.1, so no
stable promotion has run under it yet. v6.4.5 would be the first to fail.

The installer is shipped content, so the resolver accepts it only when
its diff against the candidate changes nothing but that pin line. Any
other installer change still counts as drift.

Go _test.go files are never compiled into a shipped artifact. A stable
cut can need test-only corrections, as v6.4.5 needs for the RC-derived
install-metadata contract, so they no longer count as unsoaked content.

Tests cover the allowed shapes, the refused near misses, and the pin
check against a real git diff.
2026-09-23 19:41:32 +01:00
pulse-triage[bot] 325fd10546 Merge reviewed candidate 20260923T182022Z-core-runtime
Change-source: pulse-maintainer
2026-09-23 19:41:27 +01:00
pulse-triage[bot] 94c7a8543c test(monitoring): cover distinct TrueNAS host metric targets
Exercise same-hostname host-agent and connection-scoped TrueNAS records through canonical resource resolution and unified metric routing. Keep the synthetic equality check explicit so it does not imply the reporter's live samples matched.

Change-source: pulse-maintainer
2026-09-23 19:29:09 +01:00
pulse-triage[bot] 5804f5b906 Merge pull request #2202 from rcourtman/maintainer/20260923T175815Z
Keep release and provider-MSP frontend builders on the updated Node 24 image
2026-09-23 18:27:52 +00:00
pulse-triage[bot] e054b0ef60 Merge #2199 cached-view optimization onto assigned head
Compose the exact optimization and benchmark source onto the current assigned source so correctness and paired costs can be measured without replacing the admitted Node digest candidate.

Change-source: pulse-maintainer
2026-09-23 19:01:58 +01:00
pulse-triage[bot] ffee736872 build: refresh Node 24 builder digest
Keep the canonical release and provider-MSP frontend builders on the proposed immutable amd64 Node 24 digest. Bind the same-commit change to the deployment contract, release-build metadata proof and provider-MSP rollout-control proof; hosted build and installed rollout remain separate evidence.

Change-source: pulse-maintainer
2026-09-23 18:46:18 +01:00
pulse-triage[bot] 469b2a0774 Merge #2199 cached-view optimization for proof
Compose the reviewed shared-lock change with the clean-read and dirty-cache comparison benchmarks so correctness and both cache states can be measured on the same candidate.

Change-source: pulse-maintainer
2026-09-23 18:16:47 +01:00
pulse-triage[bot] e01d6461ef test(unifiedresources): benchmark dirty view rebuilds
Separate full-cache rebuild cost after a one-resource invalidation from the clean cached-read benchmark for comparable lock-path evaluation.

Change-source: pulse-maintainer
2026-09-23 18:15:10 +01:00
pulse-triage[bot] d09d8d76e6 test(unifiedresources): benchmark cached view readers
Measure clean VM view-cache access under concurrent readers for a bounded before-and-after comparison.

Change-source: pulse-maintainer
2026-09-23 17:09:32 +01:00
pulse-triage[bot] 72a76ae06e Merge pull request #2177 from jamincollins/fix/disable-proxmox-peer-sensors
feat(agent): allow disabling Proxmox peer sensor collection
2026-09-23 16:35:41 +01:00
Jamin W. Collins 410134450d feat(agent): allow disabling Proxmox peer sensor collection 2026-09-23 08:18:44 -06:00
rcourtman a766cd4188 Merge pull request #2200 from rcourtman/claude/release-policy-train
Make releasing the default and define an achievable soak
2026-09-23 15:18:22 +01:00