Commit graph

93 commits

Author SHA1 Message Date
rcourtman
847cf98544 Fix activation fingerprint and license period status 2026-07-09 11:30:26 +01:00
rcourtman
e23505206d Carry the max_users grant claim into instance license limits
GrantClaims and Claims gain a MaxUsers seat limit mirroring MaxGuests:
the grant JWT claim is copied at the activation bridge and surfaced
through EffectiveLimits()["max_users"], which the already-shipped
user-limit enforcement (MaxUsersLimitFromLicense) reads unchanged.
Inert by default: no plan sets max_users yet, so absent claim = 0 =
unlimited for every existing license and grant. The self-hosted
commercial volume scrub strips only max_monitored_systems and
max_guests; tests now pin that max_users survives it from both the
named field and explicit limits, plus the end-to-end proof that a grant
carrying max_users=3 enforces 3 and a grant without it stays unlimited.
Contract shape recorded in cloud-paid Extension Point 26; the grant
wire contract list gains max_users against the relay-server reference
(pulse-pro 95a18bd).
2026-07-08 16:56:07 +01:00
rcourtman
fca5975c38 Add the dormant Business tier to the licensing core
TierBusiness: Pro's feature set, 365-day history retention, uncapped
core monitoring like every self-hosted tier, Business display name, and
a slot in the min-tier ordering. Differentiation is by max_users limit,
retention, and support rather than features (multi-user is already a Pro
capability via RBAC; see specs/pricing-segmentation.md binder findings).
Dormant until the license server issues business plan versions; no
checkout, pricing, or UI surface references it yet. Contract shape
recorded as cloud-paid Extension Point 26 and pinned by
TestBusinessTierContractShape.
2026-07-08 16:02:56 +01:00
rcourtman
8355335e08 Clarify v5 migration recovery states 2026-07-07 21:46:07 +01:00
rcourtman
ee8a24e14a backend and governance: MCP contract, agent capabilities, API, and release-control
Manifest-backed MCP tools, prompts, and resources with surface affordance contracts; agent capability manifest and governance projection; API contract tests and capability route projection; operations-loop and intelligence-funnel telemetry; release-control subsystem documentation, registry, and tooling; licensing and configuration.
2026-06-23 17:26:15 +01:00
rcourtman
7e26592f11 Fix CI SMART and grant refresh tests
Refs Build and Test failures on pulse/v6-release.
2026-06-11 16:26:21 +01:00
rcourtman
f9b10316b8 fix(licensing): surface unreadable persisted v5 licenses and retry failed startup exchanges
Two silent-downgrade paths in the v5→v6 migration are now visible and
self-healing:

License load/decrypt failure (was: one log line, no UI state): when
license.enc exists but cannot be read, getTenantComponents now persists
a terminal commercial_migration state with reason
persisted_license_unreadable, so the licence panel and global banner
tell the customer to re-enter their v5 key instead of leaving them to
discover missing Pro features.

Failed startup exchange (was: once per process, Community until manual
restart): exchange failures classified as pending — license-server
blips, DNS failures, rate limits — now schedule a background retry loop
with backoff (30s → 30m cap) that re-attempts the exchange until it
succeeds, hits a terminal classification, or the org's service activates
through another path. The loop stops cleanly on manual activation and
StopAllBackgroundLoops.

Registers the new files in the subsystem registry (cloud-paid
commercial-migration verification policy + shared ownership) and pins
both behaviors in the cloud-paid and api-contracts contracts.
2026-06-11 08:44:35 +01:00
rcourtman
cce1b3c783 fix(licensing): decrypt v5.0.0-era license.enc sealed with raw machine-id material
v5.0.0 derived the license.enc AES key as sha256("pulse-license-" +
material) where material was the raw /etc/machine-id file content —
trailing newline included — with hostname and a fixed dev fallback as
alternates. v6 trims machine-id before hashing and dropped both
fallbacks, so licenses activated on v5.0.0 (before .license-key shipped
in v5.0.1) could never be decrypted and the December 2025 lifetime
cohort silently booted as Community.

Collect the raw v5 key materials at construction and try them verbatim
as legacy sha256 candidates during decrypt, alongside the existing
trimmed HKDF/legacy derivations. The write path is unchanged: persistent
random key + HKDF only. Pins the cloud-paid persistence contract to the
full v5.0.x compatibility-loader material set.
2026-06-11 08:36:11 +01:00
rcourtman
6929c1c8fb fix(licensing): clear activation only on explicit revocation codes, not any 401
Go half of the licensing-policy client work from the v6 upgrade sweep
(license findings 5 and 6); the copy and docs landed in 3a51429a5 and
the license-server side lands in pulse-pro.

The grant refresh loop treated every HTTP 401 as revocation and wiped
the licence and activation file immediately, but the server returns 401
for token-not-found and token-expired as well as revocation, so a
single spurious 401 dropped a paying customer to Community until a
successful re-exchange. Activation state is now cleared only when the
401 carries an explicit revocation code (TOKEN_REVOKED,
INSTALLATION_REVOKED, LICENSE_REVOKED); any other 401 keeps the licence
and retries, letting the grant's 72h expiry plus the 7-day grace window
govern degradation. The bump_license_version immediate-refresh path in
the revocation poller had the same any-401 wipe and gets the same
guard.

ClassifyLegacyExchangeError now maps a 409 MAX_INSTALLATIONS exchange
error to failed/exchange_installation_limit with the
free_installation_slot action instead of the retryable
pending/exchange_conflict state, since retrying can never succeed until
a slot is freed server-side. Other 409s keep the pending conflict
semantics.

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-11 08:34:26 +01:00
rcourtman
3badd0a840 fix(licensing): honor activated licenses for dev-grant-excluded features in dev mode
In dev/demo builds HasFeature returned the implicit dev grant verdict
unconditionally, so features excluded from that grant (white_label,
multi_user, unlimited, env-gated multi_tenant) were denied even when an
explicitly activated, signature-verified license carried them - while
/api/license/status reported them active from the same claims. That
inconsistency made branded report rendering impossible to exercise in
dev builds. Excluded features now fall through to real entitlement
evaluation, so an activated license behaves the same in dev as in
release builds; the no-license dev posture is unchanged.
2026-06-10 17:09:00 +01:00
rcourtman
d25b99cbcc Make provider-MSP client runtimes verifiably licensed via chained entitlement leases
Provider-hosted MSP client workspaces previously sat at Community tier
forever: the runtime refreshed leases against the built-in Pulse Cloud URL
(hibernated, 522) instead of the provider control plane, and release-build
images verify leases only against the embedded Pulse key, which an
operator-generated CP_TRIAL_ACTIVATION_PRIVATE_KEY can never satisfy.

- Inject PULSE_PRO_TRIAL_SIGNUP_URL=CP_BASE_URL into client containers so
  lease refresh targets the provider control plane.
- Chain trust through the Pulse-signed provider MSP license: the license
  binds the provider's lease signing public key
  (entitlement_signing_public_key claim); the control plane embeds the
  license in every lease (provider_license claim); release-build runtimes
  verify embedded Pulse root -> provider license -> lease signature.
- Cap chain-verified leases at ProviderChainedLeaseCapabilities: MSP tier
  plus white_label (branded per-client reports), minus Pulse-service-backed
  relay/mobile_app/push_notifications, which otherwise loop doomed
  registrations against Pulse's relay.
- Fail fast at control-plane startup when the license does not bind the
  configured signing key, instead of provisioning silently unlicensed
  client workspaces.

Verified live on a Colima harness: release-tagged tenant image with test
embedded root, Traefik TLS, full provider-msp proof, tenant reports
valid=true plan_version=msp_growth with white_label and zero relay
failures.
2026-06-10 13:58:52 +01:00
rcourtman
9f722a442a Dedupe alerts PMG queue checks, vmware clones, licensing and proxmox client clones
Clears the dupl pairs outside internal/api:

- internal/alerts/pmg.go: the total/deferred/hold per-node queue checks
  share evaluatePMGNodeQueueAlert; the historical short-circuit (a
  below-threshold clear or invalid spec skips the node's remaining
  checks) is preserved via the helper's skip-node return.
- internal/vmware/provider.go: the cloneInventory* family rides generic
  cloneSliceWith / cloneShallowSlice helpers instead of fourteen copies
  of the same nil/make/loop scaffold.
- internal/vmware/client.go + client_signals.go: the byte-identical
  Automation and VI/JSON fetchers delegate to one getSessionScopedJSON.
- internal/vmware/fixtures.go: added to the dupl exclude list in
  .golangci.yml — literal mock fixture catalogs are the same category as
  the existing internal/mock/ exclusion.
- pkg/licensing/license_server_client.go: Activate and
  ExchangeLegacyLicense share postActivationRequest (idempotent POST +
  shared activation response decode).
- pkg/proxmox/client.go: LXC/VM RRD fetches share getGuestRRDData.
- pkg/pulsecli/actions.go is intentionally left for the api-contracts
  slice.

Full test suites pass for internal/alerts, internal/vmware,
pkg/licensing, pkg/proxmox.
2026-06-10 09:49:03 +01:00
rcourtman
faefe6edc8 Remove 198 unreachable Go functions
Dead-code sweep. Functions flagged unreachable by golang.org/x/tools/cmd/deadcode
and confirmed unused across pulse, pulse-enterprise, pulse-pro and pulse-mobile by
adversarial cross-repo verification. Cross-module reachability was checked
explicitly (only pkg/ exported symbols are importable by other modules; internal/
packages and _test.go files are not). go build, go vet and test-compile all pass.
2026-06-03 12:29:37 +01:00
rcourtman
d6964832a0 Add entitlement-gated report branding 2026-06-02 18:11:25 +01:00
rcourtman
914465e67f Tighten MSP workspace tier limits 2026-06-01 16:55:23 +01:00
rcourtman
da2537e4ab Add self-hosted commercial continuity proof 2026-05-13 16:44:26 +01:00
rcourtman
f16aa8a65c Parse stored subscription states for entitlement refresh 2026-05-12 15:17:53 +01:00
rcourtman
86244d8c13 Track runtime build in license activation 2026-05-06 23:45:37 +01:00
rcourtman
b84fc2301a Surface paid runtime mismatch in licensing 2026-05-06 17:18:35 +01:00
rcourtman
81b31e4d3b Remove monitored-system volume caps
Retire runtime/API/UI monitored-system volume enforcement now that infrastructure monitoring is no longer capped.

Keep only legacy metadata scrubbing and purchase-start compatibility for old max_monitored_systems references.

Rename the remaining preview surface to monitored-system impact and make previews explanatory rather than save-blocking.

Update subsystem contracts and RA7 evidence for the caps-retired invariant.
2026-05-05 12:59:59 +01:00
rcourtman
632f0af7f3 Keep uncapped continuity from writing raw caps 2026-05-05 09:33:44 +01:00
rcourtman
82c54cc39b Make self-hosted SSO Community-tier
Treat OIDC, SAML, and multi-provider SSO as included Community capabilities while retaining advanced_sso as a compatibility key. Remove SAML-specific paywalls and paid-upgrade copy from runtime, settings UI, entitlement snapshots, docs, journey proof, and subsystem contracts.

Refs #1449
2026-05-03 12:48:01 +01:00
rcourtman
1267a817c7 Gate cloud provisioning to hosted checkouts 2026-05-01 14:13:08 +01:00
rcourtman
c7164c2906 Clarify Relay mobile handoff paid copy 2026-04-30 13:18:04 +01:00
rcourtman
99129d0c09 Retire product upgrade metrics runtime
Remove local upgrade-metrics API registration, settings payload wiring, startup store migration, and backend conversion recorder hooks from the normal product runtime.

Delete the retired conversion/funnel and metering packages from compiled licensing code, and extend diagnostics boundary audits and governance contracts so maintainer commercial analytics cannot return through Settings or diagnostics.
2026-04-30 12:24:22 +01:00
rcourtman
48c8d26198 Add paid feature claim proof bundle 2026-04-29 14:18:43 +01:00
rcourtman
f060f261cd Present Relay as annual-first support tier 2026-04-29 12:49:20 +01:00
rcourtman
0dd3cd804e Hide MSP-only features from self-hosted Pro plans 2026-04-29 01:02:10 +01:00
rcourtman
5f0078b0d0 Keep synthetic modes out of entitlement payloads 2026-04-29 00:33:53 +01:00
rcourtman
08fef313eb Rename hosted capacity marker copy 2026-04-29 00:07:18 +01:00
rcourtman
c0ef2d44f3 Keep compatibility-only features out of upgrade URLs 2026-04-28 23:22:20 +01:00
rcourtman
937696508c Guard self-hosted feature metadata drift 2026-04-28 23:16:12 +01:00
rcourtman
a67845ada0 Retire self-hosted volume caps 2026-04-28 20:36:37 +01:00
rcourtman
c197f6a7a5 Move license test signers to testsupport 2026-04-28 19:12:21 +01:00
rcourtman
b29f398b9d Fix release-mode licensing test expectations 2026-04-28 18:58:35 +01:00
rcourtman
1d189d3343 Clarify hosted entitlement signing compatibility 2026-04-28 18:47:19 +01:00
rcourtman
2b1d82d965 Retire self-hosted trial posture prompts 2026-04-28 17:39:09 +01:00
rcourtman
7cc980ad1d Retire self-hosted trial signup control plane 2026-04-28 17:02:04 +01:00
rcourtman
ded190dcab Retire hosted AI quickstart runtime 2026-04-28 16:11:27 +01:00
rcourtman
b1e179479d Retire self-hosted AI quickstart surfaces 2026-04-28 15:49:18 +01:00
rcourtman
fab0e77800 Refine self-hosted Pro value copy 2026-04-28 09:56:03 +01:00
rcourtman
e0c4533fb4 Remove self-hosted monitoring upsell copy 2026-04-28 09:33:26 +01:00
rcourtman
430f0d3fa2 Clarify Pro Plus continuity feature contract 2026-04-26 21:08:15 +01:00
rcourtman
d36f465b7c Preserve uncapped self-hosted commercial continuity 2026-04-26 14:32:00 +01:00
rcourtman
b4692ef7f0 Encode canonical self-hosted feature metadata 2026-04-23 15:30:42 +01:00
rcourtman
a5687cd22e Formalize v6 paid-surface classification 2026-04-23 14:53:41 +01:00
rcourtman
74c2660f8d Expose infrastructure onboarding diagnostics 2026-04-22 15:37:56 +01:00
rcourtman
767a0dd5ba Instrument infrastructure onboarding funnel and harden onboarding proof 2026-04-22 15:04:33 +01:00
rcourtman
8a42bb432e Harden commercial callback and transport URL policy 2026-04-22 10:57:21 +01:00
rcourtman
de99fcb1f0 Restrict purchase return HTTP callbacks to loopback 2026-04-22 09:49:36 +01:00