mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-09-10 18:45:53 +00:00
54a312bebd
Six of the eight Pro-exclusive features had no telemetry field at all, so there was no way to answer whether RBAC, audit logging, scheduled reporting, agent profiles, alert-triggered AI, or Kubernetes AI were being used by the installs paying for them. Schema v6 adds nine content-free adoption signals: alert_ai_enabled AIConfig.IsAlertTriggeredAnalysisEnabled() rbac_custom_roles non-built-in roles, per org rbac_user_assignments user-to-role assignments, per org audit_logging_persistent a persistent audit store is active, not console audit_events_30d audit events retained inside the window report_schedules configured scheduled reports report_schedules_enabled scheduled reports switched on report_schedules_run_30d schedules whose last run falls inside the window agent_profiles configured agent profiles Counts only. Role names, permissions, usernames, schedule names, delivery recipients, report scope, profile names, and every audit event field stay on the install. kubernetes_ai needs no field of its own: it is derivable at read time from alert_ai_enabled combined with the existing kubernetes_clusters count, and a dedicated field would be redundant. Config-sourced signals are read through applyLicensedFeatureConfigSnapshot; RBAC and audit live behind the router and are read through Router.ApplyLicensedFeatureTelemetrySnapshot. The RBAC read goes through a new TenantRBACProvider.PeekManager so a background telemetry read can never provision an RBAC store for an org that has never used RBAC. Also removes pulse_intelligence_patrol_autofixes_30d and the AutoFixCount field behind it. patrol_run.go hardcoded AutoFixCount to 0 and no increment site existed anywhere in the tree, so the counter was zero in all 233,364 retained production pings. That was a wiring bug, not evidence that nobody uses Patrol fixes; governed fixes are delivered through the approved-action pipeline, which is already instrumented. The field was plumbed through run records, history persistence, the Assistant handoff, and telemetry while being structurally incapable of holding a non-zero value. Verified end to end against a running install rather than only in unit tests, which is precisely the check the autofix counter never had: seeding three report schedules (two enabled, one last run inside the window) and two agent profiles produced report_schedules 3, report_schedules_enabled 2, report_schedules_run_30d 1, agent_profiles 2 in the Settings telemetry preview, and signing in moved audit_events_30d to 1. The private receiver landed first in pulse-pro 78ff7dd so the new fields are accepted on arrival.
70 lines
2.7 KiB
Go
70 lines
2.7 KiB
Go
package server
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/rcourtman/pulse-go-rewrite/internal/config"
|
|
"github.com/rcourtman/pulse-go-rewrite/internal/models"
|
|
"github.com/rcourtman/pulse-go-rewrite/internal/telemetry"
|
|
)
|
|
|
|
func TestApplyLicensedFeatureConfigSnapshot_CountsScheduledReportingAndProfiles(t *testing.T) {
|
|
now := time.Date(2026, 8, 5, 12, 0, 0, 0, time.UTC)
|
|
recent := now.Add(-48 * time.Hour)
|
|
old := now.Add(-(telemetry.PulseIntelligenceTelemetryWindow + time.Hour))
|
|
|
|
persistence := config.NewConfigPersistence(t.TempDir())
|
|
if err := persistence.SaveReportScheduleStore(config.ReportScheduleStore{
|
|
Schedules: []config.ReportSchedule{
|
|
{ID: "a", Name: "weekly-capacity", Enabled: true, LastRunAt: &recent},
|
|
{ID: "b", Name: "monthly-uptime", Enabled: true, LastRunAt: &old},
|
|
{ID: "c", Name: "paused", Enabled: false, LastRunAt: &recent},
|
|
{ID: "d", Name: "never-run", Enabled: true},
|
|
},
|
|
}); err != nil {
|
|
t.Fatalf("SaveReportScheduleStore: %v", err)
|
|
}
|
|
if err := persistence.SaveAgentProfiles([]models.AgentProfile{
|
|
{ID: "profile-1", Name: "edge"},
|
|
{ID: "profile-2", Name: "core"},
|
|
}); err != nil {
|
|
t.Fatalf("SaveAgentProfiles: %v", err)
|
|
}
|
|
|
|
var snap telemetry.Snapshot
|
|
applyLicensedFeatureConfigSnapshot(&snap, persistence, now)
|
|
|
|
if snap.ReportSchedules != 4 {
|
|
t.Fatalf("report schedules = %d, want 4", snap.ReportSchedules)
|
|
}
|
|
if snap.ReportSchedulesEnabled != 3 {
|
|
t.Fatalf("enabled report schedules = %d, want 3", snap.ReportSchedulesEnabled)
|
|
}
|
|
// Only the two schedules whose last run falls inside the window count, and
|
|
// a disabled schedule that still ran recently is one of them.
|
|
if snap.ReportSchedulesRun30d != 2 {
|
|
t.Fatalf("report schedules run in window = %d, want 2", snap.ReportSchedulesRun30d)
|
|
}
|
|
if snap.AgentProfiles != 2 {
|
|
t.Fatalf("agent profiles = %d, want 2", snap.AgentProfiles)
|
|
}
|
|
}
|
|
|
|
func TestApplyLicensedFeatureConfigSnapshot_LeavesCountsZeroWhenNothingConfigured(t *testing.T) {
|
|
var snap telemetry.Snapshot
|
|
applyLicensedFeatureConfigSnapshot(&snap, config.NewConfigPersistence(t.TempDir()), time.Now().UTC())
|
|
|
|
if snap.ReportSchedules != 0 || snap.ReportSchedulesEnabled != 0 || snap.ReportSchedulesRun30d != 0 || snap.AgentProfiles != 0 {
|
|
t.Fatalf("unconfigured install must report zeroes: %#v", snap)
|
|
}
|
|
}
|
|
|
|
// A nil persistence must not panic: the telemetry snapshot runs on a timer and
|
|
// a failed persistence init cannot be allowed to take the process down.
|
|
func TestApplyLicensedFeatureConfigSnapshot_ToleratesNilInputs(t *testing.T) {
|
|
var snap telemetry.Snapshot
|
|
applyLicensedFeatureConfigSnapshot(&snap, nil, time.Now().UTC())
|
|
applyLicensedFeatureConfigSnapshot(nil, config.NewConfigPersistence(t.TempDir()), time.Now().UTC())
|
|
}
|