Extend MSP install proof for portal rollups

This commit is contained in:
rcourtman
2026-07-07 20:49:55 +01:00
parent 4382919447
commit 4043c466f6
8 changed files with 422 additions and 89 deletions
@@ -65,6 +65,8 @@ type providerMSPInstallProofReport struct {
SetupFactsTokenUseVisible bool
AgentReportIngestVerified bool
TokenRotationVerified bool
ReportScheduleVisible bool
ActiveAlertRollupVisible bool
RotatedOutTokenRejectionVerified bool
NonProofTenantCountPreserved bool
InitialStatusTotalTenants int
@@ -495,6 +497,8 @@ func populateProviderMSPInstallProofProof(report *providerMSPInstallProofReport,
report.SetupFactsTokenUseVisible = proof.SetupFactsTokenUseVisible
report.AgentReportIngestVerified = proof.AgentReportIngestVerified
report.TokenRotationVerified = proof.TokenRotationVerified
report.ReportScheduleVisible = proof.ReportScheduleVisible
report.ActiveAlertRollupVisible = proof.ActiveAlertRollupVisible
report.TenantIsolationVerified = proof.InstallTokenBoundaryOK
report.DefaultRuntimeIsolationVerified = proof.AgentReportIngestVerified
report.RotatedOutTokenRejectionVerified = providerMSPInstallProofAllRotatedOutTokensRejected(proof.Workspaces)
@@ -596,6 +600,8 @@ func printProviderMSPInstallProofReport(report *providerMSPInstallProofReport) {
fmt.Printf("setup_facts_token_use_visible=%t\n", report.SetupFactsTokenUseVisible)
fmt.Printf("agent_report_ingest_verified=%t\n", report.AgentReportIngestVerified)
fmt.Printf("token_rotation_verified=%t\n", report.TokenRotationVerified)
fmt.Printf("report_schedule_visible=%t\n", report.ReportScheduleVisible)
fmt.Printf("active_alert_rollup_visible=%t\n", report.ActiveAlertRollupVisible)
fmt.Printf("rotated_out_token_rejection_verified=%t\n", report.RotatedOutTokenRejectionVerified)
fmt.Printf("non_proof_tenant_count_preserved=%t\n", report.NonProofTenantCountPreserved)
fmt.Printf("initial_status_total_tenants=%d\n", report.InitialStatusTotalTenants)
@@ -605,7 +611,7 @@ func printProviderMSPInstallProofReport(report *providerMSPInstallProofReport) {
fmt.Printf("final_status_unhealthy_tenants=%d\n", report.FinalStatusUnhealthyTenants)
fmt.Printf("final_status_stuck_provisioning_tenants=%d\n", report.FinalStatusStuckProvisioningTenants)
for _, workspace := range report.Workspaces {
fmt.Printf("workspace=%s display_name=%q state=%s plan_version=%s container_id=%s public_url=%s install_type=%s install_token_id=%s install_command_generated=%t agent_token_auth_verified=%t setup_facts_token_use_visible=%t agent_report_ingest_verified=%t agent_report_agent_id=%s agent_report_hostname=%s token_rotation_verified=%t rotated_install_token_id=%s old_install_token_rejected=%t rotated_agent_report_verified=%t handoff_exchange_verified=%t handoff_target_path=%s entitlement_lease_checked=%t entitlement_lease_verified=%t entitlement_white_label=%t entitlement_skipped_reason=%s\n",
fmt.Printf("workspace=%s display_name=%q state=%s plan_version=%s container_id=%s public_url=%s install_type=%s install_token_id=%s install_command_generated=%t agent_token_auth_verified=%t setup_facts_token_use_visible=%t agent_report_ingest_verified=%t agent_report_agent_id=%s agent_report_hostname=%s token_rotation_verified=%t rotated_install_token_id=%s old_install_token_rejected=%t rotated_agent_report_verified=%t handoff_exchange_verified=%t handoff_target_path=%s entitlement_lease_checked=%t entitlement_lease_verified=%t entitlement_white_label=%t entitlement_skipped_reason=%s report_schedule_created=%t report_schedule_id=%s report_schedule_visible=%t report_schedule_count=%d disabled_report_schedule_count=%d active_alert_persisted=%t active_alert_rollup_visible=%t critical_alert_count=%d warning_alert_count=%d\n",
workspace.TenantID,
workspace.DisplayName,
workspace.State,
@@ -630,6 +636,15 @@ func printProviderMSPInstallProofReport(report *providerMSPInstallProofReport) {
workspace.EntitlementLeaseVerified,
workspace.EntitlementWhiteLabel,
workspace.EntitlementSkippedReason,
workspace.ReportScheduleCreated,
workspace.ReportScheduleID,
workspace.ReportScheduleVisible,
workspace.ReportScheduleCount,
workspace.DisabledReportScheduleCount,
workspace.ActiveAlertPersisted,
workspace.ActiveAlertRollupVisible,
workspace.CriticalAlertCount,
workspace.WarningAlertCount,
)
}
for _, failure := range report.Failures {
@@ -159,7 +159,7 @@ func TestProviderMSPInstallProofRunsFreshInstallSequence(t *testing.T) {
if report.WorkspaceCount != 2 || len(report.Workspaces) != 2 {
t.Fatalf("workspace proof count = %d len=%d", report.WorkspaceCount, len(report.Workspaces))
}
if !report.TenantIsolationVerified || !report.DefaultRuntimeIsolationVerified || !report.TokenRotationVerified || !report.RotatedOutTokenRejectionVerified {
if !report.TenantIsolationVerified || !report.DefaultRuntimeIsolationVerified || !report.TokenRotationVerified || !report.RotatedOutTokenRejectionVerified || !report.ReportScheduleVisible || !report.ActiveAlertRollupVisible {
t.Fatalf("isolation/token proof missing: %#v", report)
}
if !report.NonProofTenantCountPreserved {
@@ -336,6 +336,8 @@ func healthyProviderMSPInstallProofProofReport() *providerMSPProofReport {
SetupFactsTokenUseVisible: true,
AgentReportIngestVerified: true,
TokenRotationVerified: true,
ReportScheduleVisible: true,
ActiveAlertRollupVisible: true,
Workspaces: []providerMSPProofWorkspace{
healthyProviderMSPInstallProofWorkspace("ws-proof-01", "Provider MSP Proof 01"),
healthyProviderMSPInstallProofWorkspace("ws-proof-02", "Provider MSP Proof 02"),
@@ -345,26 +347,35 @@ func healthyProviderMSPInstallProofProofReport() *providerMSPProofReport {
func healthyProviderMSPInstallProofWorkspace(tenantID, displayName string) providerMSPProofWorkspace {
return providerMSPProofWorkspace{
TenantID: tenantID,
DisplayName: displayName,
State: "active",
PlanVersion: "msp_growth",
ContainerID: "ctr-" + tenantID,
PublicURL: "https://" + tenantID + ".msp.example.com",
InstallType: "pve",
InstallTokenID: "tok-" + tenantID,
InstallCommandGenerated: true,
AgentTokenAuthVerified: true,
SetupFactsTokenUseVisible: true,
AgentReportIngestVerified: true,
AgentReportAgentID: "agent-" + tenantID,
AgentReportHostname: "pve1",
TokenRotationVerified: true,
RotatedInstallTokenID: "tok-rotated-" + tenantID,
OldInstallTokenRejected: true,
RotatedAgentReportVerified: true,
HandoffExchangeVerified: true,
HandoffTargetPath: "/settings/infrastructure?add=linux-host",
TenantID: tenantID,
DisplayName: displayName,
State: "active",
PlanVersion: "msp_growth",
ContainerID: "ctr-" + tenantID,
PublicURL: "https://" + tenantID + ".msp.example.com",
InstallType: "pve",
InstallTokenID: "tok-" + tenantID,
InstallCommandGenerated: true,
AgentTokenAuthVerified: true,
SetupFactsTokenUseVisible: true,
AgentReportIngestVerified: true,
AgentReportAgentID: "agent-" + tenantID,
AgentReportHostname: "pve1",
TokenRotationVerified: true,
RotatedInstallTokenID: "tok-rotated-" + tenantID,
OldInstallTokenRejected: true,
RotatedAgentReportVerified: true,
HandoffExchangeVerified: true,
HandoffTargetPath: "/settings/infrastructure?add=linux-host",
ReportScheduleCreated: true,
ReportScheduleID: "sched-" + tenantID,
ReportScheduleVisible: true,
ReportScheduleCount: 1,
DisabledReportScheduleCount: 0,
ActiveAlertPersisted: true,
ActiveAlertRollupVisible: true,
CriticalAlertCount: 1,
WarningAlertCount: 1,
}
}
+284 -53
View File
@@ -14,6 +14,7 @@ import (
"strings"
"time"
"github.com/rcourtman/pulse-go-rewrite/internal/alerts"
"github.com/rcourtman/pulse-go-rewrite/internal/api"
"github.com/rcourtman/pulse-go-rewrite/internal/cloudcp"
"github.com/rcourtman/pulse-go-rewrite/internal/cloudcp/account"
@@ -55,32 +56,41 @@ type providerMSPProofRuntime struct {
}
type providerMSPProofWorkspace struct {
TenantID string
DisplayName string
State string
PlanVersion string
ContainerID string
PublicURL string
InstallType string
InstallToken string
InstallTokenID string
InstallCommandGenerated bool
AgentTokenAuthVerified bool
SetupFactsTokenUseVisible bool
AgentReportIngestVerified bool
AgentReportAgentID string
AgentReportHostname string
TokenRotationVerified bool
RotatedInstallToken string
RotatedInstallTokenID string
OldInstallTokenRejected bool
RotatedAgentReportVerified bool
HandoffExchangeVerified bool
HandoffTargetPath string
EntitlementLeaseChecked bool
EntitlementLeaseVerified bool
EntitlementWhiteLabel bool
EntitlementSkippedReason string
TenantID string
DisplayName string
State string
PlanVersion string
ContainerID string
PublicURL string
InstallType string
InstallToken string
InstallTokenID string
InstallCommandGenerated bool
AgentTokenAuthVerified bool
SetupFactsTokenUseVisible bool
AgentReportIngestVerified bool
AgentReportAgentID string
AgentReportHostname string
TokenRotationVerified bool
RotatedInstallToken string
RotatedInstallTokenID string
OldInstallTokenRejected bool
RotatedAgentReportVerified bool
HandoffExchangeVerified bool
HandoffTargetPath string
EntitlementLeaseChecked bool
EntitlementLeaseVerified bool
EntitlementWhiteLabel bool
EntitlementSkippedReason string
ReportScheduleCreated bool
ReportScheduleID string
ReportScheduleVisible bool
ReportScheduleCount int
DisabledReportScheduleCount int
ActiveAlertPersisted bool
ActiveAlertRollupVisible bool
CriticalAlertCount int
WarningAlertCount int
}
type providerMSPProofReport struct {
@@ -102,6 +112,8 @@ type providerMSPProofReport struct {
SetupFactsTokenUseVisible bool
AgentReportIngestVerified bool
TokenRotationVerified bool
ReportScheduleVisible bool
ActiveAlertRollupVisible bool
Cleanup bool
}
@@ -268,6 +280,8 @@ func (rt *providerMSPProofRuntime) runProviderMSPProof(ctx context.Context, opts
SetupFactsTokenUseVisible: true,
AgentReportIngestVerified: true,
TokenRotationVerified: true,
ReportScheduleVisible: true,
ActiveAlertRollupVisible: true,
Cleanup: opts.Cleanup,
}
@@ -299,6 +313,12 @@ func (rt *providerMSPProofRuntime) runProviderMSPProof(ctx context.Context, opts
if !workspace.TokenRotationVerified {
report.TokenRotationVerified = false
}
if !workspace.ReportScheduleVisible {
report.ReportScheduleVisible = false
}
if !workspace.ActiveAlertRollupVisible {
report.ActiveAlertRollupVisible = false
}
report.Workspaces = append(report.Workspaces, workspace)
}
@@ -461,36 +481,236 @@ func (rt *providerMSPProofRuntime) proveProviderMSPWorkspace(ctx context.Context
return providerMSPProofWorkspace{}, err
}
portalRollup, err := rt.verifyProviderMSPProofPortalRollup(ctx, tenant, tenantDataDir, agentReport)
if err != nil {
return providerMSPProofWorkspace{}, err
}
return providerMSPProofWorkspace{
TenantID: tenant.ID,
DisplayName: tenant.DisplayName,
State: string(tenant.State),
PlanVersion: tenant.PlanVersion,
ContainerID: tenant.ContainerID,
PublicURL: publicURL,
InstallType: install.InstallType,
InstallToken: install.Token,
InstallTokenID: install.TokenID,
InstallCommandGenerated: true,
AgentTokenAuthVerified: tokenAuthVerified,
SetupFactsTokenUseVisible: setupFactsVisible,
AgentReportIngestVerified: agentReport.Verified,
AgentReportAgentID: agentReport.AgentID,
AgentReportHostname: agentReport.Hostname,
TokenRotationVerified: rotation.Verified,
RotatedInstallToken: rotation.RotatedToken,
RotatedInstallTokenID: rotation.RotatedTokenID,
OldInstallTokenRejected: rotation.OldTokenRejected,
RotatedAgentReportVerified: rotation.RotatedAgentReportVerified,
HandoffExchangeVerified: exchangedTargetPath == targetPath,
HandoffTargetPath: exchangedTargetPath,
EntitlementLeaseChecked: entitlement.Checked,
EntitlementLeaseVerified: entitlement.Verified,
EntitlementWhiteLabel: entitlement.WhiteLabel,
EntitlementSkippedReason: entitlement.SkippedReason,
TenantID: tenant.ID,
DisplayName: tenant.DisplayName,
State: string(tenant.State),
PlanVersion: tenant.PlanVersion,
ContainerID: tenant.ContainerID,
PublicURL: publicURL,
InstallType: install.InstallType,
InstallToken: install.Token,
InstallTokenID: install.TokenID,
InstallCommandGenerated: true,
AgentTokenAuthVerified: tokenAuthVerified,
SetupFactsTokenUseVisible: setupFactsVisible,
AgentReportIngestVerified: agentReport.Verified,
AgentReportAgentID: agentReport.AgentID,
AgentReportHostname: agentReport.Hostname,
TokenRotationVerified: rotation.Verified,
RotatedInstallToken: rotation.RotatedToken,
RotatedInstallTokenID: rotation.RotatedTokenID,
OldInstallTokenRejected: rotation.OldTokenRejected,
RotatedAgentReportVerified: rotation.RotatedAgentReportVerified,
HandoffExchangeVerified: exchangedTargetPath == targetPath,
HandoffTargetPath: exchangedTargetPath,
EntitlementLeaseChecked: entitlement.Checked,
EntitlementLeaseVerified: entitlement.Verified,
EntitlementWhiteLabel: entitlement.WhiteLabel,
EntitlementSkippedReason: entitlement.SkippedReason,
ReportScheduleCreated: portalRollup.ReportScheduleCreated,
ReportScheduleID: portalRollup.ReportScheduleID,
ReportScheduleVisible: portalRollup.ReportScheduleVisible,
ReportScheduleCount: portalRollup.ReportScheduleCount,
DisabledReportScheduleCount: portalRollup.DisabledReportScheduleCount,
ActiveAlertPersisted: portalRollup.ActiveAlertPersisted,
ActiveAlertRollupVisible: portalRollup.ActiveAlertRollupVisible,
CriticalAlertCount: portalRollup.CriticalAlertCount,
WarningAlertCount: portalRollup.WarningAlertCount,
}, nil
}
type providerMSPProofPortalRollup struct {
ReportScheduleCreated bool
ReportScheduleID string
ReportScheduleVisible bool
ReportScheduleCount int
DisabledReportScheduleCount int
ActiveAlertPersisted bool
ActiveAlertRollupVisible bool
CriticalAlertCount int
WarningAlertCount int
}
func (rt *providerMSPProofRuntime) verifyProviderMSPProofPortalRollup(ctx context.Context, tenant *registry.Tenant, tenantDataDir string, agentReport providerMSPProofAgentReportIngest) (providerMSPProofPortalRollup, error) {
result := providerMSPProofPortalRollup{}
if tenant == nil {
return result, fmt.Errorf("tenant is required")
}
tenantID := strings.TrimSpace(tenant.ID)
if tenantID == "" {
return result, fmt.Errorf("tenant id is required")
}
if strings.TrimSpace(agentReport.AgentID) == "" {
return result, fmt.Errorf("tenant %s agent report id is required before portal rollup proof", tenantID)
}
scheduleID, err := rt.createProviderMSPProofReportSchedule(ctx, tenant, tenantDataDir, agentReport.AgentID, agentReport.Hostname)
if err != nil {
return result, err
}
result.ReportScheduleCreated = true
result.ReportScheduleID = scheduleID
orgDir := filepath.Join(tenantDataDir, "orgs", tenantID)
if err := writeProviderMSPProofActiveAlerts(orgDir, agentReport.AgentID, agentReport.Hostname); err != nil {
return result, fmt.Errorf("write provider MSP proof active alerts for tenant %s: %w", tenantID, err)
}
result.ActiveAlertPersisted = true
facts := portal.NewTenantDirWorkspaceSetupFactReader(rt.cfg.TenantsDir()).FactsForWorkspace(tenantID)
result.ReportScheduleCount = providerMSPProofFactInt(facts.ReportScheduleCount)
result.DisabledReportScheduleCount = providerMSPProofFactInt(facts.DisabledReportScheduleCount)
result.CriticalAlertCount = providerMSPProofFactInt(facts.ActiveCriticalAlertCount)
result.WarningAlertCount = providerMSPProofFactInt(facts.ActiveWarningAlertCount)
result.ReportScheduleVisible = result.ReportScheduleCount == 1 && result.DisabledReportScheduleCount == 0
result.ActiveAlertRollupVisible = result.CriticalAlertCount == 1 && result.WarningAlertCount == 1 && facts.ActiveAlertsUpdatedAt != nil
if !result.ReportScheduleVisible {
return result, fmt.Errorf("portal setup facts for tenant %s report schedules = enabled:%d disabled:%d, want enabled:1 disabled:0", tenantID, result.ReportScheduleCount, result.DisabledReportScheduleCount)
}
if !result.ActiveAlertRollupVisible {
return result, fmt.Errorf("portal setup facts for tenant %s active alerts = critical:%d warning:%d updated:%t, want critical:1 warning:1 updated:true", tenantID, result.CriticalAlertCount, result.WarningAlertCount, facts.ActiveAlertsUpdatedAt != nil)
}
return result, nil
}
func (rt *providerMSPProofRuntime) createProviderMSPProofReportSchedule(ctx context.Context, tenant *registry.Tenant, tenantDataDir, resourceID, resourceName string) (string, error) {
if tenant == nil {
return "", fmt.Errorf("tenant is required")
}
tenantID := strings.TrimSpace(tenant.ID)
if tenantID == "" {
return "", fmt.Errorf("tenant id is required")
}
if strings.TrimSpace(resourceName) == "" {
resourceName = strings.TrimSpace(resourceID)
}
tenantCfg := &runtimeconfig.Config{
DataPath: tenantDataDir,
ConfigPath: tenantDataDir,
PublicURL: rt.providerMSPProofTenantPublicURL(tenantID),
}
tenantPersistence := runtimeconfig.NewMultiTenantPersistence(tenantDataDir)
if !tenantPersistence.OrgExists(tenantID) {
return "", fmt.Errorf("tenant %s organization metadata is missing before report schedule proof", tenantID)
}
tenantMonitor := monitoring.NewMultiTenantMonitor(tenantCfg, tenantPersistence, nil)
defer tenantMonitor.Stop()
handler := api.NewReportingHandlers(tenantMonitor, nil)
payload := runtimeconfig.ReportSchedule{
Name: "Provider MSP proof monthly report",
Enabled: true,
Cadence: runtimeconfig.ReportScheduleCadence{
Type: runtimeconfig.ReportScheduleCadenceMonthly,
DayOfMonth: 1,
Time: "09:00",
Timezone: "UTC",
},
Scope: runtimeconfig.ReportScheduleScope{
Resources: []runtimeconfig.ReportScheduleResource{
{
ResourceType: "agent",
ResourceID: strings.TrimSpace(resourceID),
Name: strings.TrimSpace(resourceName),
},
},
},
Format: runtimeconfig.ReportScheduleFormatPDF,
Delivery: runtimeconfig.ReportScheduleDelivery{
Method: runtimeconfig.ReportScheduleDeliveryDisk,
Attach: true,
SaveToDisk: true,
},
}
body, err := json.Marshal(payload)
if err != nil {
return "", fmt.Errorf("marshal provider MSP proof report schedule: %w", err)
}
req := httptest.NewRequest(http.MethodPost, "/api/reports/schedules", bytes.NewReader(body))
req = req.WithContext(context.WithValue(ctx, api.OrgIDContextKey, tenantID))
req.Header.Set("Content-Type", "application/json")
rec := httptest.NewRecorder()
handler.HandleCreateReportSchedule(rec, req)
if rec.Code != http.StatusCreated {
return "", fmt.Errorf("tenant %s report schedule create status=%d body=%s", tenantID, rec.Code, strings.TrimSpace(rec.Body.String()))
}
var created runtimeconfig.ReportSchedule
if err := json.Unmarshal(rec.Body.Bytes(), &created); err != nil {
return "", fmt.Errorf("decode provider MSP proof report schedule: %w", err)
}
if strings.TrimSpace(created.ID) == "" {
return "", fmt.Errorf("tenant %s report schedule create response missing id", tenantID)
}
return created.ID, nil
}
func writeProviderMSPProofActiveAlerts(orgDir, resourceID, resourceName string) error {
if strings.TrimSpace(orgDir) == "" {
return fmt.Errorf("org dir is required")
}
if strings.TrimSpace(resourceName) == "" {
resourceName = strings.TrimSpace(resourceID)
}
now := time.Now().UTC()
active := []alerts.Alert{
{
ID: "provider-msp-proof-critical",
Type: "cpu",
Level: alerts.AlertLevelCritical,
ResourceID: strings.TrimSpace(resourceID),
ResourceName: strings.TrimSpace(resourceName),
Node: strings.TrimSpace(resourceName),
Instance: "provider-msp-proof",
Message: "Provider MSP proof critical alert",
Value: 96,
Threshold: 80,
StartTime: now,
LastSeen: now,
},
{
ID: "provider-msp-proof-warning",
Type: "memory",
Level: alerts.AlertLevelWarning,
ResourceID: strings.TrimSpace(resourceID),
ResourceName: strings.TrimSpace(resourceName),
Node: strings.TrimSpace(resourceName),
Instance: "provider-msp-proof",
Message: "Provider MSP proof warning alert",
Value: 88,
Threshold: 85,
StartTime: now,
LastSeen: now,
},
}
data, err := json.Marshal(active)
if err != nil {
return fmt.Errorf("marshal active alerts: %w", err)
}
alertsDir := filepath.Join(orgDir, "alerts")
if err := os.MkdirAll(alertsDir, 0o700); err != nil {
return fmt.Errorf("create active alerts dir: %w", err)
}
path := filepath.Join(alertsDir, "active-alerts.json")
if err := os.WriteFile(path, data, 0o600); err != nil {
return fmt.Errorf("write active alerts file: %w", err)
}
return nil
}
func providerMSPProofFactInt(value *int) int {
if value == nil {
return 0
}
return *value
}
type providerMSPProofEntitlementLease struct {
Checked bool
Verified bool
@@ -1101,9 +1321,11 @@ func printProviderMSPProofReport(report *providerMSPProofReport) {
fmt.Printf("setup_facts_token_use_visible=%t\n", report.SetupFactsTokenUseVisible)
fmt.Printf("agent_report_ingest_verified=%t\n", report.AgentReportIngestVerified)
fmt.Printf("token_rotation_verified=%t\n", report.TokenRotationVerified)
fmt.Printf("report_schedule_visible=%t\n", report.ReportScheduleVisible)
fmt.Printf("active_alert_rollup_visible=%t\n", report.ActiveAlertRollupVisible)
fmt.Printf("cleanup=%t\n", report.Cleanup)
for _, workspace := range report.Workspaces {
fmt.Printf("workspace=%s display_name=%q state=%s plan_version=%s container_id=%s public_url=%s install_type=%s install_token_id=%s install_command_generated=%t agent_token_auth_verified=%t setup_facts_token_use_visible=%t agent_report_ingest_verified=%t agent_report_agent_id=%s agent_report_hostname=%s token_rotation_verified=%t rotated_install_token_id=%s old_install_token_rejected=%t rotated_agent_report_verified=%t handoff_exchange_verified=%t handoff_target_path=%s entitlement_lease_checked=%t entitlement_lease_verified=%t entitlement_white_label=%t entitlement_skipped_reason=%s\n",
fmt.Printf("workspace=%s display_name=%q state=%s plan_version=%s container_id=%s public_url=%s install_type=%s install_token_id=%s install_command_generated=%t agent_token_auth_verified=%t setup_facts_token_use_visible=%t agent_report_ingest_verified=%t agent_report_agent_id=%s agent_report_hostname=%s token_rotation_verified=%t rotated_install_token_id=%s old_install_token_rejected=%t rotated_agent_report_verified=%t handoff_exchange_verified=%t handoff_target_path=%s entitlement_lease_checked=%t entitlement_lease_verified=%t entitlement_white_label=%t entitlement_skipped_reason=%s report_schedule_created=%t report_schedule_id=%s report_schedule_visible=%t report_schedule_count=%d disabled_report_schedule_count=%d active_alert_persisted=%t active_alert_rollup_visible=%t critical_alert_count=%d warning_alert_count=%d\n",
workspace.TenantID,
workspace.DisplayName,
workspace.State,
@@ -1128,6 +1350,15 @@ func printProviderMSPProofReport(report *providerMSPProofReport) {
workspace.EntitlementLeaseVerified,
workspace.EntitlementWhiteLabel,
workspace.EntitlementSkippedReason,
workspace.ReportScheduleCreated,
workspace.ReportScheduleID,
workspace.ReportScheduleVisible,
workspace.ReportScheduleCount,
workspace.DisabledReportScheduleCount,
workspace.ActiveAlertPersisted,
workspace.ActiveAlertRollupVisible,
workspace.CriticalAlertCount,
workspace.WarningAlertCount,
)
}
}
@@ -141,6 +141,12 @@ func TestProviderMSPProofExercisesWorkspaceInstallHandoffAndIsolation(t *testing
if !report.TokenRotationVerified {
t.Fatal("token rotation was not verified")
}
if !report.ReportScheduleVisible {
t.Fatal("report schedule portal fact was not verified")
}
if !report.ActiveAlertRollupVisible {
t.Fatal("active alert portal rollup was not verified")
}
seenTenants := map[string]struct{}{}
for _, workspace := range report.Workspaces {
@@ -202,6 +208,18 @@ func TestProviderMSPProofExercisesWorkspaceInstallHandoffAndIsolation(t *testing
if !workspace.EntitlementWhiteLabel {
t.Fatalf("entitlement lease for %s is missing white_label", workspace.TenantID)
}
if !workspace.ReportScheduleCreated || workspace.ReportScheduleID == "" || !workspace.ReportScheduleVisible {
t.Fatalf("report schedule portal proof incomplete for %s: %#v", workspace.TenantID, workspace)
}
if workspace.ReportScheduleCount != 1 || workspace.DisabledReportScheduleCount != 0 {
t.Fatalf("report schedule facts for %s = enabled:%d disabled:%d, want enabled:1 disabled:0", workspace.TenantID, workspace.ReportScheduleCount, workspace.DisabledReportScheduleCount)
}
if !workspace.ActiveAlertPersisted || !workspace.ActiveAlertRollupVisible {
t.Fatalf("active alert portal rollup proof incomplete for %s: %#v", workspace.TenantID, workspace)
}
if workspace.CriticalAlertCount != 1 || workspace.WarningAlertCount != 1 {
t.Fatalf("active alert facts for %s = critical:%d warning:%d, want critical:1 warning:1", workspace.TenantID, workspace.CriticalAlertCount, workspace.WarningAlertCount)
}
}
}
@@ -254,7 +272,7 @@ func TestProviderMSPProofLoadsSignedLicenseFilePlan(t *testing.T) {
if report.LicenseEmail != "provider@example.com" {
t.Fatalf("LicenseEmail = %q, want provider@example.com", report.LicenseEmail)
}
if !report.AgentReportIngestVerified || !report.InstallTokenBoundaryOK || !report.TokenRotationVerified || !report.HandoffExchangeVerified {
if !report.AgentReportIngestVerified || !report.InstallTokenBoundaryOK || !report.TokenRotationVerified || !report.HandoffExchangeVerified || !report.ReportScheduleVisible || !report.ActiveAlertRollupVisible {
t.Fatalf("provider MSP proof did not complete core runtime checks: %#v", report)
}
}
@@ -679,6 +679,11 @@ or other self-hosted uncapped continuity plans.
age labels from read-only setup facts so providers can prioritize the
workspace list, but it must not become an alert console or expose alert
bodies, remediation state, acknowledgements, or cross-client alert streams.
Those setup facts must read report schedule counts from the client runtime's
org-scoped `report_schedules.json` store and active-alert counts from the
org-scoped `alerts/active-alerts.json` runtime file before falling back to a
legacy tenant-root active-alert file, because tenant monitors own
org-scoped runtime persistence.
Pulse Account also owns the provider-facing setup progression for client
workspaces: after workspace creation the portal should select the created
workspace, reveal the setup job, and preserve workspace/target context in
@@ -165,9 +165,11 @@ TLS floor in the dynamic config.
`pulse-control-plane provider-msp proof` must exercise the first-client
onboarding path through workspace creation, client-bound install token
generation, tenant-local unified-agent report ingest, tenant-bound install
token rotation, rotated-out token rejection, handoff exchange, and
duplicate-hostname isolation before provider-hosted MSP installability is
treated as proven. The proof is license-backed by default: `license_file` must be the
token rotation, rotated-out token rejection, handoff exchange,
tenant-runtime report schedule creation, portal-visible active-alert rollup
facts, and duplicate-hostname isolation before provider-hosted MSP
installability is treated as proven. The proof is license-backed by default:
`license_file` must be the
resolved provider MSP plan source unless the operator explicitly opts into
the local-development `--allow-env-plan` escape hatch.
The same proof surface must also keep adversarial client-boundary probes in
+37 -10
View File
@@ -66,7 +66,7 @@ func readWorkspaceSetupFacts(tenantID, tenantDataDir, orgDir string) WorkspaceSe
facts.AgentCount, facts.AgentTokenCount, facts.UnusedAgentTokenCount, facts.LastAgentSeenAt = readAgentSetupFacts(tenantID, tenantDataDir, orgDir)
facts.AlertRouteCount, facts.DisabledAlertRouteCount = readAlertRouteFacts(orgDir)
facts.ActiveCriticalAlertCount, facts.ActiveWarningAlertCount, facts.ActiveAlertsUpdatedAt = readActiveAlertFacts(tenantDataDir)
facts.ActiveCriticalAlertCount, facts.ActiveWarningAlertCount, facts.ActiveAlertsUpdatedAt = readActiveAlertFacts(tenantDataDir, orgDir)
facts.ReportScheduleCount, facts.DisabledReportScheduleCount = readReportScheduleFacts(orgDir)
return facts
}
@@ -219,26 +219,53 @@ func nonBlankCount(values []string) int {
return count
}
func readActiveAlertFacts(tenantDataDir string) (*int, *int, *time.Time) {
path, ok := safeConfigLeafPath(tenantDataDir, filepath.Join("alerts", "active-alerts.json"))
func readActiveAlertFacts(tenantDataDir, orgDir string) (*int, *int, *time.Time) {
for _, dir := range uniqueActiveAlertFactDirs(orgDir, tenantDataDir) {
critical, warning, updatedAt, ok := readActiveAlertFactsFromDir(dir)
if ok {
return critical, warning, updatedAt
}
}
return nil, nil, nil
}
func uniqueActiveAlertFactDirs(values ...string) []string {
dirs := make([]string, 0, len(values))
seen := map[string]struct{}{}
for _, value := range values {
value = strings.TrimSpace(value)
if value == "" {
continue
}
if _, exists := seen[value]; exists {
continue
}
seen[value] = struct{}{}
dirs = append(dirs, value)
}
return dirs
}
func readActiveAlertFactsFromDir(configDir string) (*int, *int, *time.Time, bool) {
path, ok := safeConfigLeafPath(configDir, filepath.Join("alerts", "active-alerts.json"))
if !ok {
return nil, nil, nil
return nil, nil, nil, false
}
data, err := os.ReadFile(path)
if err != nil {
if !errors.Is(err, os.ErrNotExist) {
log.Warn().Err(err).Str("tenant_data_dir", tenantDataDir).Msg("cloudcp.portal.setup_facts: read active alerts")
log.Warn().Err(err).Str("config_dir", configDir).Msg("cloudcp.portal.setup_facts: read active alerts")
}
return nil, nil, nil
return nil, nil, nil, false
}
if len(strings.TrimSpace(string(data))) == 0 {
return nil, nil, nil
return nil, nil, nil, true
}
var active []alerts.Alert
if err := json.Unmarshal(data, &active); err != nil {
log.Warn().Err(err).Str("tenant_data_dir", tenantDataDir).Msg("cloudcp.portal.setup_facts: parse active alerts")
return nil, nil, nil
log.Warn().Err(err).Str("config_dir", configDir).Msg("cloudcp.portal.setup_facts: parse active alerts")
return nil, nil, nil, true
}
criticalCount := 0
@@ -257,7 +284,7 @@ func readActiveAlertFacts(tenantDataDir string) (*int, *int, *time.Time) {
ts := info.ModTime().UTC()
updatedAt = &ts
}
return intPtr(criticalCount), intPtr(warningCount), updatedAt
return intPtr(criticalCount), intPtr(warningCount), updatedAt, true
}
func readReportScheduleFacts(orgDir string) (*int, *int) {
@@ -264,6 +264,30 @@ func TestTenantDirWorkspaceSetupFactReaderTreatsCorruptActiveAlertFileAsUnknown(
}
}
func TestTenantDirWorkspaceSetupFactReaderPrefersRuntimeOrgActiveAlerts(t *testing.T) {
tenantsDir := t.TempDir()
tenantDir := filepath.Join(tenantsDir, "ws_runtime_alerts")
orgDir := filepath.Join(tenantDir, "orgs", "ws_runtime_alerts")
if err := os.MkdirAll(orgDir, 0o755); err != nil {
t.Fatal(err)
}
writeSetupFactJSON(t, tenantDir, filepath.Join("alerts", "active-alerts.json"), []alerts.Alert{
{ID: "legacy-warning", Level: alerts.AlertLevelWarning},
})
writeSetupFactJSON(t, orgDir, filepath.Join("alerts", "active-alerts.json"), []alerts.Alert{
{ID: "runtime-critical", Level: alerts.AlertLevelCritical},
{ID: "runtime-warning", Level: alerts.AlertLevelWarning},
})
facts := NewTenantDirWorkspaceSetupFactReader(tenantsDir).FactsForWorkspace("ws_runtime_alerts")
if facts.ActiveCriticalAlertCount == nil || *facts.ActiveCriticalAlertCount != 1 {
t.Fatalf("ActiveCriticalAlertCount = %v, want 1", facts.ActiveCriticalAlertCount)
}
if facts.ActiveWarningAlertCount == nil || *facts.ActiveWarningAlertCount != 1 {
t.Fatalf("ActiveWarningAlertCount = %v, want 1", facts.ActiveWarningAlertCount)
}
}
func TestTenantDirWorkspaceSetupFactReaderCountsRuntimePersistedReportSchedules(t *testing.T) {
tenantsDir := t.TempDir()
orgDir := filepath.Join(tenantsDir, "ws_runtime", "orgs", "ws_runtime")