mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-25 13:10:03 +00:00
Merge pull request #2219 from rcourtman/maintainer/20260924T005314Z
Honor shortened provider MSP paid-licence periods
This commit is contained in:
@@ -3449,8 +3449,11 @@ platform's key, and installs it at `ProviderMSPRenewedLicensePath`.
|
||||
`renewed_license`), so a paying provider keeps starting after the self-issued
|
||||
evaluation on the host expires. A changed licence restarts the control plane
|
||||
through the graceful shutdown path, because the plan version is read once at
|
||||
load. `msp_solo` (3 client workspaces) is the first paid step above the
|
||||
2-workspace evaluation.
|
||||
load. The comparison includes the signed expiry in both directions: a shorter
|
||||
paid period for the same licence ID and plan must replace the old licence and
|
||||
restart rather than retain a longer entitlement. An unchanged ID, plan and
|
||||
expiry must not trigger a restart. `msp_solo` (3 client workspaces) is the
|
||||
first paid step above the 2-workspace evaluation.
|
||||
|
||||
In the portal, provider-hosted mode shows the `billing` section as **Plan**
|
||||
(`internal/cloudcp/portal/frontend/src/provider_plan.ts`), never Pulse-hosted
|
||||
@@ -3470,7 +3473,8 @@ plan changed in the Stripe billing portal applies without a click. Regression
|
||||
coverage:
|
||||
`TestLoadConfig_ProviderHostedMSPPrefersRenewedLicense` in
|
||||
`internal/cloudcp/config_test.go`,
|
||||
`TestProviderMSPLicenseRefreshInstallsThePaidLicenceAndRestarts` and
|
||||
`TestProviderMSPLicenseRefreshInstallsThePaidLicenceAndRestarts`,
|
||||
`TestProviderMSPLicenseRefreshAppliesShorterPaidPeriod` and
|
||||
`TestProviderMSPPortalRoutesRelayToTheLicenceServer` in
|
||||
`internal/cloudcp/provider_msp_license_refresh_test.go`,
|
||||
`TestRegisterRoutes_ProviderMSPPurchaseRoutesRequireOwnerOrAdmin` in
|
||||
|
||||
@@ -250,7 +250,7 @@ func (r *ProviderMSPLicenseRefresher) Refresh(ctx context.Context) (ProviderMSPL
|
||||
}
|
||||
result.Changed = renewed.LicenseID != r.cfg.ProviderMSPLicenseID ||
|
||||
renewed.PlanVersion != r.cfg.ProviderMSPPlanVersion ||
|
||||
renewed.ExpiresAt.After(r.cfg.ProviderMSPLicenseExpiresAt.Add(time.Hour))
|
||||
!renewed.ExpiresAt.Equal(r.cfg.ProviderMSPLicenseExpiresAt)
|
||||
if !result.Changed {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
@@ -211,6 +211,39 @@ func TestProviderMSPLicenseRefreshInstallsThePaidLicenceAndRestarts(t *testing.T
|
||||
}
|
||||
}
|
||||
|
||||
func TestProviderMSPLicenseRefreshAppliesShorterPaidPeriod(t *testing.T) {
|
||||
issuer := newProviderMSPTestIssuer(t)
|
||||
fake := &fakeProviderMSPLicenseServer{t: t, currentStatus: http.StatusOK}
|
||||
server := httptest.NewServer(fake)
|
||||
defer server.Close()
|
||||
cfg := newProviderMSPRefreshTestConfig(t, server.URL)
|
||||
cfg.ProviderMSPLicenseID = "lic_msp_paid"
|
||||
cfg.ProviderMSPPlanVersion = "msp_solo"
|
||||
cfg.ProviderMSPLicenseExpiresAt = time.Now().Add(90 * 24 * time.Hour).Truncate(time.Second)
|
||||
|
||||
// A billing-cycle change can shorten the paid period without changing the
|
||||
// licence ID or plan. Retaining the old expiry would over-entitle it.
|
||||
shorterExpiry := time.Now().Add(30 * 24 * time.Hour).Truncate(time.Second)
|
||||
fake.currentLicense = issuer.sign(t, cfg.ProviderMSPLicenseID, cfg.ProviderMSPPlanVersion, shorterExpiry, trialSigningEnvPublicKey(t))
|
||||
refresher := NewProviderMSPLicenseRefresher(cfg)
|
||||
restarted := make(chan struct{}, 1)
|
||||
refresher.SetRestart(func() { restarted <- struct{}{} })
|
||||
|
||||
result, err := refresher.Refresh(context.Background())
|
||||
if err != nil || !result.Changed || !result.RestartScheduled || result.ExpiresAt != shorterExpiry.Format(time.RFC3339) {
|
||||
t.Fatalf("shorter paid-period refresh = %+v, %v", result, err)
|
||||
}
|
||||
installed, err := os.ReadFile(ProviderMSPRenewedLicensePath(cfg.DataDir))
|
||||
if err != nil || strings.TrimSpace(string(installed)) != fake.currentLicense {
|
||||
t.Fatalf("shorter paid-period licence not installed: %v", err)
|
||||
}
|
||||
select {
|
||||
case <-restarted:
|
||||
case <-time.After(5 * time.Second):
|
||||
t.Fatal("shorter paid-period licence did not restart the control plane")
|
||||
}
|
||||
}
|
||||
|
||||
func TestProviderMSPPortalRoutesRelayToTheLicenceServer(t *testing.T) {
|
||||
fake := &fakeProviderMSPLicenseServer{
|
||||
t: t,
|
||||
|
||||
Reference in New Issue
Block a user