Files
rcourtman 186ce504c8 Retire disconnected incident recording and preserve archives
The fleet sampler and coordinator had no production alert trigger and could
repeat cached values as fresh incident evidence. Preserve saved recordings
through explicit read-only lookups, propagate read failures and report the
former live incident count as unmeasured. Keep historical status and duration
units explicit without rewriting archived observations.

Integrate main's alert dispatch wording and startup replay qualification.
Canonical incident listing and real-model outcome qualification remain open.
2026-09-06 17:42:24 +01:00

2860 lines
105 KiB
Go

package unifiedresources
// Unified Resources Architecture — Code Standards Enforcement
//
// END STATE (State Read Consolidation — SRC):
//
// The Unified Resources Registry is the PRIMARY read surface for all
// internal business logic. StateSnapshot is the write/ingest buffer and
// frontend wire DTO only.
//
// Architecture:
//
// 1. StateSnapshot (models.StateSnapshot)
// WRITE-ONLY ingest buffer. Monitoring/polling populates typed arrays.
// The registry reads from it via IngestSnapshot(). Frontend reads via
// ToFrontend()/WebSocket. Internal business logic MUST NOT read from
// StateSnapshot directly — use the ReadState interface instead.
//
// 2. Unified Resources Registry (unifiedresources.ResourceRegistry)
// The canonical read model. Provides cross-source identity resolution,
// deduplication, typed views, and a normalized resource model.
// Implements the ReadState interface with typed accessor methods
// (VMs(), Containers(), Nodes(), etc.) backed by cached per-type
// indexes that are O(1) to read and invalidated per ingest cycle.
//
// Consumer package policy:
//
// - internal/ai/*, internal/api/*, internal/infradiscovery/,
// internal/servicediscovery/: MUST use ReadState. Direct state reads
// are banned for all migrated resource types.
//
// - internal/monitoring/, internal/mock/, internal/models/,
// internal/websocket/: Exempt (producer/wire-format packages).
// Monitoring remains a producer package, but snapshot-shaped export
// helpers are progressively derived from ReadState-backed canonical data
// rather than treated as state-owned truth. Workload export helpers
// (VMsSnapshot/ContainersSnapshot) now also derive from ReadState-backed
// canonical data instead of from StateSnapshot-owned guest arrays. PBS
// instance export helpers now follow the same rule via
// ReadState.PBSInstances(). Backup-alert guest lookup assembly now also
// derives VM/container identity from ReadState workload views instead of
// from snapshot-owned guest arrays. Backup polling and recovery ingest
// guest-context assembly now also derive workload node/name/type data from
// ReadState instead of from snapshot-owned guest arrays. Storage-backup
// preservation now also derives node/storage membership from
// ReadState.StoragePools() instead of from snapshot-owned storage arrays.
// Physical-disk refresh/merge paths now also derive disk, node, and linked
// host context from ReadState instead of from snapshot-owned physical-disk
// arrays.
//
// - All state.* field access patterns and GetState() calls are
// enforced as hard bans (SRC-04b). Migration is complete — zero
// direct state access remains in consumer packages.
//
// See: docs/architecture/state-read-consolidation-plan-2026-02.md
// Progress: docs/architecture/state-read-consolidation-progress-2026-02.md
//
// The tests below enforce these rules by scanning consumer packages for
// banned direct-state access patterns.
import (
"encoding/json"
"os"
"path/filepath"
"reflect"
"regexp"
"strings"
"testing"
"time"
"github.com/rcourtman/pulse-go-rewrite/internal/models"
"github.com/rcourtman/pulse-go-rewrite/pkg/proxmox"
)
func TestMetricValueAlwaysCarriesNumericValueWhenObjectExists(t *testing.T) {
payload, err := json.Marshal(MetricValue{Unit: "bytes/s", Source: SourceProxmox})
if err != nil {
t.Fatal(err)
}
var decoded map[string]any
if err := json.Unmarshal(payload, &decoded); err != nil {
t.Fatal(err)
}
value, ok := decoded["value"].(float64)
if !ok || value != 0 {
t.Fatalf("MetricValue JSON must contain numeric zero, got %s", payload)
}
}
func TestProviderNeutralVirtualMachineJSONContract(t *testing.T) {
payload, err := json.Marshal(Resource{
Type: ResourceTypeVM,
VirtualMachine: &VirtualMachineData{
RuntimeState: "running",
Hypervisor: "libvirt",
VCPUs: 4,
},
})
if err != nil {
t.Fatal(err)
}
var decoded map[string]any
if err := json.Unmarshal(payload, &decoded); err != nil {
t.Fatal(err)
}
facet, ok := decoded["virtualMachine"].(map[string]any)
if !ok ||
facet["runtimeState"] != "running" ||
facet["hypervisor"] != "libvirt" ||
facet["vcpus"] != float64(4) {
t.Fatalf("provider-neutral VM facet = %#v in %s", facet, payload)
}
if _, exists := decoded["proxmox"]; exists {
t.Fatalf("provider-neutral VM facet fabricated Proxmox metadata: %s", payload)
}
}
func TestActionTruthTypesStayUnifiedResourceOwned(t *testing.T) {
repoRoot := filepath.Join("..", "..")
roots := []string{"internal/api", "internal/ai", "internal/agentexec", "internal/hostagent", "internal/dockeragent", "internal/relay", "internal/workflow", "internal/workflows"}
forbidden := []*regexp.Regexp{
regexp.MustCompile(`(?m)^type\s+ActionExecutionStatus\b`),
regexp.MustCompile(`(?m)^type\s+ActionVerificationStatus\b`),
regexp.MustCompile(`(?m)^type\s+ActionEvidenceClass\b`),
regexp.MustCompile(`(?m)^type\s+ActionCompensationStatus\b`),
regexp.MustCompile(`(?m)^type\s+ActionResultV2\b`),
}
for _, root := range roots {
path := filepath.Join(repoRoot, root)
if _, err := os.Stat(path); os.IsNotExist(err) {
continue
}
err := filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() || filepath.Ext(path) != ".go" || strings.HasSuffix(path, "_test.go") {
return nil
}
source, err := os.ReadFile(path)
if err != nil {
return err
}
for _, pattern := range forbidden {
if pattern.Match(source) {
t.Errorf("%s declares workflow-local action truth; use unifiedresources.ActionResultV2", filepath.ToSlash(path))
}
}
return nil
})
if err != nil {
t.Fatalf("scan %s: %v", path, err)
}
}
}
func TestOperationReceiptProtocolRemainsInternalToIngestAndRuntime(t *testing.T) {
repoRoot := filepath.Join("..", "..")
for _, path := range []string{
"internal/models/models_frontend.go",
"internal/unifiedresources/types.go",
} {
source, err := os.ReadFile(filepath.Join(repoRoot, path))
if err != nil {
t.Fatal(err)
}
if path == "internal/models/models_frontend.go" && strings.Contains(string(source), "OperationReceiptVersion") {
t.Fatalf("%s exposes the raw receipt protocol in a frontend DTO", path)
}
if path == "internal/unifiedresources/types.go" {
field := regexp.MustCompile(`OperationReceiptVersion\s+int\s+` + "`json:\"-\"`")
if !field.Match(source) {
t.Fatalf("%s must keep receipt metadata internal-only", path)
}
}
}
err := filepath.Walk(filepath.Join(repoRoot, "frontend-modern", "src"), func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() || (filepath.Ext(path) != ".ts" && filepath.Ext(path) != ".tsx") {
return nil
}
source, err := os.ReadFile(path)
if err != nil {
return err
}
if strings.Contains(string(source), "OperationReceiptVersion") || strings.Contains(string(source), "operationReceiptVersion") {
t.Errorf("%s learned the internal receipt protocol", filepath.ToSlash(path))
}
return nil
})
if err != nil {
t.Fatal(err)
}
for _, path := range []string{"internal/actionlifecycle", "internal/workflow", "internal/workflows"} {
root := filepath.Join(repoRoot, path)
if _, err := os.Stat(root); os.IsNotExist(err) {
continue
}
err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() || filepath.Ext(path) != ".go" || strings.HasSuffix(path, "_test.go") {
return nil
}
source, err := os.ReadFile(path)
if err != nil {
return err
}
if regexp.MustCompile(`(?m)^\s*OperationReceiptVersion\s+`).Match(source) {
t.Errorf("%s declares workflow-local receipt protocol truth", filepath.ToSlash(path))
}
return nil
})
if err != nil {
t.Fatal(err)
}
}
}
func TestDockerOOMEvidenceRemainsAuthoritativeAcrossCanonicalIngest(t *testing.T) {
monitorSource, err := os.ReadFile(filepath.Join("..", "monitoring", "monitor_agents.go"))
if err != nil {
t.Fatal(err)
}
if !regexp.MustCompile(`OOMKilled:\s+cloneReportBoolPtr\(payload\.OOMKilled\)`).Match(monitorSource) {
t.Fatal("Docker report ingest must preserve and clone nullable runtime OOM evidence")
}
oomKilled := false
resource, _ := resourceFromDockerContainer(models.DockerContainer{
ID: "container-oom-contract",
Name: "contract-container",
State: "exited",
ExitCode: 137,
OOMKilled: &oomKilled,
}, models.DockerHost{ID: "docker-host-contract"})
if resource.Docker == nil || resource.Docker.OOMKilled == nil || *resource.Docker.OOMKilled {
t.Fatalf("canonical DockerData lost explicit non-OOM evidence: %+v", resource.Docker)
}
oomKilled = true
viewEvidence := NewDockerContainerView(&resource).OOMKilled()
if viewEvidence == nil || *viewEvidence {
t.Fatalf("typed Docker view aliased its source evidence: %v", viewEvidence)
}
*viewEvidence = true
if got := NewDockerContainerView(&resource).OOMKilled(); got == nil || *got {
t.Fatalf("typed Docker view must return an independent OOM evidence value: %v", got)
}
}
func TestProductionActionLifecycleDoesNotUseRecordActionAuditAsUpsert(t *testing.T) {
paths := []string{"../actionlifecycle/service.go", "../ai/tools/action_audit.go", "../api/patrol_action_broker.go"}
for _, path := range paths {
src, err := os.ReadFile(path)
if err != nil {
t.Fatalf("read %s: %v", path, err)
}
if strings.Contains(string(src), ".RecordActionAudit(") {
t.Errorf("%s must use CreateActionAudit or a typed CAS transition", path)
}
}
}
func TestActionPolicyDecisionProvenanceHasOneOwnerAndNoPublicAuthorityField(t *testing.T) {
declaration := regexp.MustCompile(`(?m)^type\s+ActionPolicyDecisionProvenance\b`)
found := []string{}
for _, root := range []string{"..", "../../pkg"} {
err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() || filepath.Ext(path) != ".go" || strings.HasSuffix(path, "_test.go") {
return nil
}
source, err := os.ReadFile(path)
if err != nil {
return err
}
if declaration.Match(source) {
found = append(found, filepath.ToSlash(path))
}
return nil
})
if err != nil {
t.Fatal(err)
}
}
if len(found) != 1 || !strings.HasSuffix(found[0], "unifiedresources/action_policy_provenance.go") {
t.Fatalf("policy decision provenance owners=%v", found)
}
apiSource, err := os.ReadFile("../api/actions.go")
if err != nil {
t.Fatal(err)
}
requestStart := strings.Index(string(apiSource), "type publicActionPlanRequest struct")
if requestStart < 0 {
t.Fatal("public action planning request type is missing")
}
requestEnd := strings.Index(string(apiSource)[requestStart:], "\n}")
if requestEnd < 0 || strings.Contains(string(apiSource)[requestStart:requestStart+requestEnd], "PolicyDecision") {
t.Fatal("public action planning request must not accept policy provenance")
}
lifecycleSource, err := os.ReadFile("../actionlifecycle/service.go")
if err != nil {
t.Fatal(err)
}
if !strings.Contains(string(lifecycleSource), "PolicyFactors []unified.ActionPolicyAuthorityFactor") {
t.Fatal("trusted broker policy provenance must enter only through PlanOptions")
}
}
func TestCanonicalActionPlanConstructionCannotBypassPolicyProvenancePlanner(t *testing.T) {
allowed := map[string]bool{
"../actionplanner/planner.go": true,
// Boundary-only compatibility conversions and retired command-shaped
// audit history remain readable but are not canonical action producers.
"../api/router_routes_ai_relay.go": true,
"../ai/tools/action_audit.go": true,
// Graph-owned mock records are immutable presentation fixtures. They do
// not admit, approve, or dispatch executable actions.
"../mock/action_fixtures.go": true,
}
pattern := regexp.MustCompile(`(?s)\bActionPlan\s*\{\s*[A-Za-z_][A-Za-z0-9_]*\s*:`)
err := filepath.Walk("..", func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() || filepath.Ext(path) != ".go" || strings.HasSuffix(path, "_test.go") {
return nil
}
source, err := os.ReadFile(path)
if err != nil {
return err
}
if pattern.Match(source) && !allowed[filepath.ToSlash(path)] {
t.Errorf("%s constructs ActionPlan outside the canonical planner or named compatibility boundary", filepath.ToSlash(path))
}
return nil
})
if err != nil {
t.Fatal(err)
}
for path := range allowed {
source, err := os.ReadFile(path)
if err != nil {
t.Fatal(err)
}
if !pattern.Match(source) {
t.Fatalf("expected ActionPlan construction in %s", path)
}
}
}
// readConsumerGoFiles returns the contents of all non-test .go files in the
// specified directory (relative to the repo internal/ root).
func readConsumerGoFiles(t *testing.T, relDir string) map[string]string {
t.Helper()
// Walk up from unifiedresources/ to internal/
internalDir := filepath.Join("..", relDir)
files := make(map[string]string)
err := filepath.Walk(internalDir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() {
return nil
}
if filepath.Ext(path) != ".go" || strings.HasSuffix(path, "_test.go") {
return nil
}
data, readErr := os.ReadFile(path)
if readErr != nil {
t.Fatalf("failed to read %s: %v", path, readErr)
}
files[path] = string(data)
return nil
})
if err != nil {
t.Fatalf("failed to walk %s: %v", relDir, err)
}
return files
}
// bannedPattern defines a state access pattern that should not appear in
// consumer code because the resource type has been migrated to the registry.
type bannedPattern struct {
re *regexp.Regexp
message string
}
var migratedResourcePatterns = []bannedPattern{
{
re: regexp.MustCompile(`state\.PhysicalDisks\b`),
message: "use unified resources registry (GetByType/ListByType with ResourceTypePhysicalDisk) instead of state.PhysicalDisks",
},
{
re: regexp.MustCompile(`state\.CephClusters\b`),
message: "use unified resources registry (GetByType/ListByType with ResourceTypeCeph) instead of state.CephClusters",
},
{
re: regexp.MustCompile(`GetCephClusters\(\)`),
message: "GetCephClusters() was removed — use unified resources registry instead",
},
{
re: regexp.MustCompile(`StorageProvider\b`),
message: "StorageProvider was removed — storage pools are accessed via unified resources registry",
},
// SRC-04b hard bans: state.* field access patterns and GetState() calls.
// Converted from ratchet ceilings (all reached 0) to hard bans on 2026-03-01.
// Consumer packages must use ReadState typed accessors exclusively.
{
re: regexp.MustCompile(`state\.VMs\b`),
message: "use ReadState.VMs() instead of state.VMs — direct state access banned (SRC-04b)",
},
{
re: regexp.MustCompile(`state\.Containers\b`),
message: "use ReadState.Containers() instead of state.Containers — direct state access banned (SRC-04b)",
},
{
re: regexp.MustCompile(`state\.Nodes\b`),
message: "use ReadState.Nodes() instead of state.Nodes — direct state access banned (SRC-04b)",
},
{
re: regexp.MustCompile(`state\.DockerHosts\b`),
message: "use ReadState.DockerHosts() instead of state.DockerHosts — direct state access banned (SRC-04b)",
},
{
re: regexp.MustCompile(`state\.Hosts\b`),
message: "use ReadState.Hosts() instead of state.Hosts — direct state access banned (SRC-04b)",
},
{
re: regexp.MustCompile(`state\.Storage\b`),
message: "use ReadState.StoragePools() instead of state.Storage — direct state access banned (SRC-04b)",
},
{
re: regexp.MustCompile(`state\.KubernetesClusters\b`),
message: "use ReadState.K8sClusters() instead of state.KubernetesClusters — direct state access banned (SRC-04b)",
},
{
re: regexp.MustCompile(`state\.PBSInstances\b`),
message: "use ReadState.PBSInstances() instead of state.PBSInstances — direct state access banned (SRC-04b)",
},
{
re: regexp.MustCompile(`state\.PMGInstances\b`),
message: "use ReadState.PMGInstances() instead of state.PMGInstances — direct state access banned (SRC-04b)",
},
{
re: regexp.MustCompile(`\.GetState\(\)`),
message: "use ReadState interface instead of GetState() — direct state access banned (SRC-04b)",
},
}
// consumerPackage defines a package directory to scan and any files that are
// exempt from the banned patterns (e.g., adapters that bridge between layers).
type consumerPackage struct {
dir string
exemptFiles map[string]bool
}
var consumerPackages = []consumerPackage{
{dir: "ai/tools", exemptFiles: nil},
{dir: "ai/chat", exemptFiles: nil},
{dir: "ai", exemptFiles: nil},
{dir: "api", exemptFiles: nil},
{dir: "servicediscovery", exemptFiles: nil},
}
// TestNoDirectStateAccessForMigratedResources ensures that consumer packages
// do not directly access state.* fields, call GetState(), or use removed
// provider interfaces. All resource types have been migrated to the unified
// resources registry and ReadState interface (SRC-04b).
func TestNoDirectStateAccessForMigratedResources(t *testing.T) {
// Collect all consumer file contents, deduplicating across overlapping
// package entries (e.g., "ai" walks into "ai/tools" and "ai/chat").
// Track exempt files so per-package exemptions are preserved.
allFiles := make(map[string]string)
exemptFiles := make(map[string]bool)
for _, pkg := range consumerPackages {
for path, content := range readConsumerGoFiles(t, pkg.dir) {
allFiles[path] = content
if pkg.exemptFiles[filepath.Base(path)] {
exemptFiles[path] = true
}
}
}
for path, content := range allFiles {
if exemptFiles[path] {
continue
}
for _, bp := range migratedResourcePatterns {
if matches := bp.re.FindAllStringIndex(content, -1); len(matches) > 0 {
for _, m := range matches {
line := 1 + strings.Count(content[:m[0]], "\n")
t.Errorf("%s:%d: %s", path, line, bp.message)
}
}
}
}
}
func TestCloneResourceClonesDockerSecurityPosture(t *testing.T) {
original := Resource{
ID: "app-container:docker-host-1:web",
Type: ResourceTypeAppContainer,
Docker: &DockerData{
HostSourceID: "docker-host-1",
Runtime: "docker",
Security: &models.DockerHostSecurity{
AuthorizationPlugins: []string{"opa"},
MutatingCommandsBlocked: true,
MutatingCommandsBlockedReason: "authorization plugin configured",
},
},
}
cloned := cloneResource(&original)
if cloned.Docker == nil || cloned.Docker.Security == nil {
t.Fatalf("clone lost docker security posture: %#v", cloned.Docker)
}
if !reflect.DeepEqual(cloned.Docker.Security, original.Docker.Security) {
t.Fatalf("docker security posture clone = %#v, want %#v", cloned.Docker.Security, original.Docker.Security)
}
cloned.Docker.Security.AuthorizationPlugins[0] = "changed"
if got := original.Docker.Security.AuthorizationPlugins[0]; got != "opa" {
t.Fatalf("docker security posture was aliased through clone, original plugin = %q", got)
}
}
func TestCloneResourceClonesDockerIdentityConflict(t *testing.T) {
original := Resource{
ID: "agent:docker-host-1",
Type: ResourceTypeAgent,
Docker: &DockerData{
HostSourceID: "docker-host-1",
Runtime: "docker",
IdentityConflict: &models.DockerHostIdentityConflict{
Hostnames: []string{"clone-a", "clone-b"},
MachineIDs: []string{"machine-shared"},
},
},
}
cloned := cloneResource(&original)
if cloned.Docker == nil || cloned.Docker.IdentityConflict == nil {
t.Fatalf("clone lost docker identity conflict evidence: %#v", cloned.Docker)
}
if !reflect.DeepEqual(cloned.Docker.IdentityConflict, original.Docker.IdentityConflict) {
t.Fatalf("identity conflict clone = %#v, want %#v",
cloned.Docker.IdentityConflict, original.Docker.IdentityConflict)
}
cloned.Docker.IdentityConflict.Hostnames[0] = "changed"
if got := original.Docker.IdentityConflict.Hostnames[0]; got != "clone-a" {
t.Fatalf("identity conflict was aliased through clone, original hostname = %q", got)
}
}
func TestCloneResourceClonesHostAgentIdentityConflict(t *testing.T) {
original := Resource{
ID: "agent:host-1",
Type: ResourceTypeAgent,
Agent: &AgentData{
AgentID: "host-1",
IdentityConflict: &models.HostIdentityConflict{
Hostnames: []string{"pve01"},
ReportIPs: []string{"192.168.1.10", "10.0.0.10"},
},
},
}
cloned := cloneResource(&original)
if cloned.Agent == nil || cloned.Agent.IdentityConflict == nil {
t.Fatalf("clone lost host agent identity conflict evidence: %#v", cloned.Agent)
}
if !reflect.DeepEqual(cloned.Agent.IdentityConflict, original.Agent.IdentityConflict) {
t.Fatalf("identity conflict clone = %#v, want %#v",
cloned.Agent.IdentityConflict, original.Agent.IdentityConflict)
}
cloned.Agent.IdentityConflict.ReportIPs[0] = "changed"
if got := original.Agent.IdentityConflict.ReportIPs[0]; got != "192.168.1.10" {
t.Fatalf("identity conflict was aliased through clone, original report IP = %q", got)
}
}
func TestCloneResourcePreservesDockerCPUCapacityMetadata(t *testing.T) {
original := Resource{
ID: "app-container:docker-host-1:web",
Type: ResourceTypeAppContainer,
Docker: &DockerData{
HostSourceID: "docker-host-1",
ContainerID: "web",
CPURawPercent: 240,
CPUCapacityPercent: 60,
CPUCapacityCores: 4,
},
}
cloned := cloneResource(&original)
if cloned.Docker == nil {
t.Fatal("clone lost Docker metadata")
}
if cloned.Docker.CPURawPercent != 240 ||
cloned.Docker.CPUCapacityPercent != 60 ||
cloned.Docker.CPUCapacityCores != 4 {
t.Fatalf("docker CPU capacity metadata clone = %+v, want raw 240 normalized 60 cores 4", cloned.Docker)
}
}
func TestCloneResourceCopiesHostThermalState(t *testing.T) {
warningLevel := 1
resource := Resource{
ID: "agent:mac-host",
Type: ResourceTypeAgent,
Agent: &AgentData{
Sensors: &HostSensorMeta{
ThermalState: &HostThermalState{
Source: "pmset",
Pressure: "constrained",
ThermalWarningLevel: &warningLevel,
LimitsPercent: map[string]int{"cpu_speed_limit": 72},
},
},
},
}
clone := cloneResource(&resource)
clone.Agent.Sensors.ThermalState.LimitsPercent["cpu_speed_limit"] = 95
*clone.Agent.Sensors.ThermalState.ThermalWarningLevel = 2
originalState := resource.Agent.Sensors.ThermalState
if got := originalState.LimitsPercent["cpu_speed_limit"]; got != 72 {
t.Fatalf("original thermal limit = %d, want 72 after clone mutation", got)
}
if originalState.ThermalWarningLevel == nil || *originalState.ThermalWarningLevel != 1 {
t.Fatalf("original thermal warning level = %+v, want 1 after clone mutation", originalState.ThermalWarningLevel)
}
}
func TestProxmoxWorkloadActionTargetsStayBackendAuthored(t *testing.T) {
apiSource, err := os.ReadFile(filepath.Join("..", "api", "resourceapi", "resources.go"))
if err != nil {
t.Fatalf("read api resources source: %v", err)
}
api := string(apiSource)
if !strings.Contains(api, "hostID := proxmoxLinkedAgentID(resource.Proxmox)") {
t.Fatal("Proxmox workload discovery targets must use the linked node agent ID")
}
if strings.Contains(api, "hostID := strings.TrimSpace(resource.Proxmox.NodeName)") {
t.Fatal("Proxmox workload discovery targets must not use node display names as agent IDs")
}
frontendSource, err := os.ReadFile(filepath.Join("..", "..", "frontend-modern", "src", "utils", "workloads.ts"))
if err != nil {
t.Fatalf("read frontend workload source: %v", err)
}
frontend := string(frontendSource)
if strings.Contains(frontend, "const agentId = (guest.node || '').trim();") &&
strings.Contains(frontend, "const resourceId = String(guest.vmid);") {
t.Fatal("frontend workload mapping must not infer Proxmox action targets from node plus VMID")
}
}
func TestDockerSwarmEvidenceGuardStaysInAdapter(t *testing.T) {
data, err := os.ReadFile("adapters.go")
if err != nil {
t.Fatalf("failed to read adapters.go: %v", err)
}
source := string(data)
requiredSnippets := []string{
"func hasReportableDockerSwarmInfo(info *models.DockerSwarmInfo) bool",
`state == "inactive"`,
"func convertSwarm(info *models.DockerSwarmInfo) *DockerSwarmInfo",
"if !hasReportableDockerSwarmInfo(info) {",
"return nil",
}
for _, snippet := range requiredSnippets {
if !strings.Contains(source, snippet) {
t.Fatalf("adapters.go must contain %q", snippet)
}
}
}
func TestAPIResourcesKeepsOwnedSupplementalGapFillAndVMwareAlias(t *testing.T) {
data, err := os.ReadFile(filepath.Join("..", "api", "resourceapi", "resources.go"))
if err != nil {
t.Fatalf("failed to read ../api/resourceapi/resources.go: %v", err)
}
source := string(data)
requiredSnippets := []string{
"seedSources := unifiedSeedSources(seed.resources)",
"!sourceOwnedBySupplementalProvider(source, ownedSources)",
"(source != unified.SourceAvailability && unifiedSeedIncludesSource(seedSources, source))",
`case "vmware", "vmware-vsphere":`,
}
for _, snippet := range requiredSnippets {
if !strings.Contains(source, snippet) {
t.Fatalf("../api/resourceapi/resources.go must contain %q", snippet)
}
}
}
func TestResourceAPIUsesCanonicalTenantUnifiedSeed(t *testing.T) {
data, err := os.ReadFile(filepath.Join("..", "api", "resourceapi", "resources.go"))
if err != nil {
t.Fatalf("failed to read resources.go: %v", err)
}
source := string(data)
if strings.Contains(source, "GetStateForTenant(") {
t.Fatalf("internal/api/resourceapi/resources.go must not fall back to tenant StateSnapshot seeding")
}
if !strings.Contains(source, "UnifiedResourceSnapshotForTenant(orgID)") {
t.Fatalf("internal/api/resourceapi/resources.go must use tenant unified resource snapshots as the canonical seed")
}
}
func TestAgentlessAvailabilityTargetKindStaysCanonical(t *testing.T) {
requiredSnippets := map[string][]string{
filepath.Join("..", "config", "availability.go"): {
"AvailabilityTargetMachine AvailabilityTargetKind = \"machine\"",
"AvailabilityTargetService AvailabilityTargetKind = \"service\"",
"AvailabilityTargetDevice AvailabilityTargetKind = \"device\"",
"TargetKind AvailabilityTargetKind `json:\"targetKind,omitempty\"`",
"target.TargetKind = AvailabilityTargetKind(strings.ToLower(strings.TrimSpace(string(target.TargetKind))))",
"LinkedResourceID string `json:\"linkedResourceId,omitempty\"`",
},
filepath.Join("..", "monitoring", "availability_poller.go"): {
"TargetKind",
"string",
"`json:\"targetKind,omitempty\"`",
"TargetKind: string(target.TargetKind),",
"TargetKind: string(target.TargetKind),",
"tags = append(tags, string(target.TargetKind))",
"LinkedResourceID: strings.TrimSpace(target.LinkedResourceID),",
},
"types.go": {
"Availability *AvailabilityData `json:\"availability,omitempty\"`",
"TargetKind",
"string",
"`json:\"targetKind,omitempty\"`",
"LinkedResourceID string `json:\"linkedResourceId,omitempty\"`",
"LastChecked *time.Time `json:\"lastChecked,omitempty\"`",
"LastSuccess *time.Time `json:\"lastSuccess,omitempty\"`",
},
filepath.Join("..", "..", "frontend-modern", "src", "api", "availabilityTargets.ts"): {
"export type AvailabilityTargetKind = 'machine' | 'service' | 'device';",
"targetKind?: AvailabilityTargetKind;",
},
// standalonePageModel.ts no longer references targetKind: commit
// 1e16cf34f intentionally narrowed the Machines surface to Pulse
// Agent resources only, so agentless availability targets are no
// longer classified by kind for the Machines list. The server
// contract (config/availability.go, monitoring/availability_poller.go,
// types.go, frontend-modern/src/api/availabilityTargets.ts) still
// preserves targetKind for any future UI that wants to consume it.
}
for path, snippets := range requiredSnippets {
data, err := os.ReadFile(path)
if err != nil {
t.Fatalf("failed to read %s: %v", path, err)
}
source := string(data)
for _, snippet := range snippets {
if !strings.Contains(source, snippet) {
t.Fatalf("%s must keep agentless availability target kind contract via %q", path, snippet)
}
}
}
}
func TestCanonicalStorageMetadataPreservesBackingPoolField(t *testing.T) {
requiredSnippets := map[string][]string{
"types.go": {
"Pool string `json:\"pool,omitempty\"`",
},
"adapters.go": {
"Pool: storage.Pool,",
},
"views.go": {
"func (v StoragePoolView) Pool() string {",
"return v.r.Storage.Pool",
},
filepath.Join("..", "..", "frontend-modern", "src", "types", "resource.ts"): {
"pool?: string;",
},
filepath.Join("..", "..", "frontend-modern", "src", "hooks", "useUnifiedResources.ts"): {
"pool?: string;",
},
}
for path, snippets := range requiredSnippets {
data, err := os.ReadFile(path)
if err != nil {
t.Fatalf("failed to read %s: %v", path, err)
}
source := string(data)
for _, snippet := range snippets {
if !strings.Contains(source, snippet) {
t.Fatalf("%s must contain %q", path, snippet)
}
}
}
}
func TestCanonicalStorageMetadataCarriesFullZFSPoolReport(t *testing.T) {
requiredSnippets := map[string][]string{
"types.go": {
"ZFSPool *models.ZFSPool `json:\"zfsPool,omitempty\"`",
},
"adapters.go": {
"normalized := storage.ZFSPool.NormalizeCollections()",
"ZFSPool: zfsPool,",
},
filepath.Join("..", "monitoring", "monitor.go"): {
"payload[\"zfsPool\"] = storage.ZFSPool",
},
filepath.Join("..", "..", "frontend-modern", "src", "types", "resource.ts"): {
"zfsPool?: ZFSPool;",
},
filepath.Join("..", "..", "frontend-modern", "src", "hooks", "useUnifiedResources.ts"): {
"zfsPool?: unknown;",
},
filepath.Join("..", "..", "frontend-modern", "src", "features", "storageBackups", "storageAdapters.ts"): {
"zfsPool: storageMeta?.zfsPool ?? platformData.zfsPool,",
},
}
for path, snippets := range requiredSnippets {
data, err := os.ReadFile(path)
if err != nil {
t.Fatalf("failed to read %s: %v", path, err)
}
source := string(data)
for _, snippet := range snippets {
if !strings.Contains(source, snippet) {
t.Fatalf("%s must contain %q", path, snippet)
}
}
}
}
func TestCephPoolsProjectThroughCanonicalStoragePath(t *testing.T) {
requiredSnippets := map[string][]string{
filepath.Join("..", "models", "models.go"): {
"func CephPoolStorageID(instanceName, poolName string) string",
"func StorageFromCephPool(cluster CephCluster, pool CephPool) Storage",
`Type: "ceph",`,
"ID: CephPoolStorageID(cluster.Instance, name),",
},
"registry.go": {
"models.CephPoolStorage(cluster)",
"rr.ingestStorage(storage)",
},
filepath.Join("..", "monitoring", "ceph.go"): {
"m.checkCephPoolStorage(cluster)",
"models.CephPoolStorage(cluster)",
`m.metricsStore.Write("storage", storage.ID, "usage", storage.Usage, timestamp)`,
"m.alertManager.CheckStorageWithCapacityTrend(storage, m.storageCapacityTrend(storage, timestamp))",
},
}
for path, snippets := range requiredSnippets {
data, err := os.ReadFile(path)
if err != nil {
t.Fatalf("failed to read %s: %v", path, err)
}
source := string(data)
for _, snippet := range snippets {
if !strings.Contains(source, snippet) {
t.Fatalf("%s must keep Ceph pool storage on canonical storage identity via %q", path, snippet)
}
}
}
}
func TestResourceAPIExposesDedicatedFacetReads(t *testing.T) {
requiredSnippets := map[string][]string{
filepath.Join("..", "api", "resourceapi", "resources.go"): {
"HandleGetResourceFacets",
"HandleGetResourceTimeline",
"HandleListResourceTimeline",
"unified.ParseResourceChangeFilters(r.URL.Query()[\"kind\"], r.URL.Query()[\"sourceType\"], r.URL.Query()[\"sourceAdapter\"])",
"filters.IncludeRelated = true",
"GetRecentChangesFiltered(resourceID, since, limit, filters)",
"CountRecentChangesFiltered(resourceID, since, filters)",
"CountRecentChangesByKindFiltered(resourceID, since, filters)",
"CountRecentChangesBySourceTypeFiltered(resourceID, since, filters)",
"sourceAdapter",
`strings.TrimSuffix(r.URL.Path, "/") == "/api/resources/timeline"`,
"strings.HasSuffix(r.URL.Path, \"/facets\")",
"strings.HasSuffix(r.URL.Path, \"/timeline\")",
},
filepath.Join("..", "..", "frontend-modern", "src", "api", "resources.ts"): {
"static async getGlobalTimeline(",
"`/api/resources/timeline${buildTimelineQuery(options)}`",
"static async getTimeline(",
"static async getFacetBundle(",
},
}
for name, snippets := range requiredSnippets {
data, err := os.ReadFile(name)
if err != nil {
t.Fatalf("failed to read %s: %v", name, err)
}
source := string(data)
for _, snippet := range snippets {
if !strings.Contains(source, snippet) {
t.Fatalf("%s must expose canonical resource timeline/facet snippet %q", name, snippet)
}
}
}
}
func TestActionExecutionContractStaysAPIOwned(t *testing.T) {
requiredSnippets := map[string][]string{
// Single map entry per file: Go map literals silently drop
// duplicate keys, so two entries for the same file would
// erase the first. Keeping all actions.go pins together
// guarantees every snippet actually runs.
filepath.Join(".", "actions.go"): {
"func BeginActionExecution(record ActionAuditRecord, actor string, now time.Time)",
"func CompleteActionExecution(record ActionAuditRecord, result *ExecutionResult, actor string, now time.Time)",
"func ValidateActionExecutionStart(record ActionAuditRecord, now time.Time) error",
// ErrActionPlanDrift is the canonical error returned when the
// payload at execute time does not match the PlanHash recorded
// at approval time. Pinning it here keeps the broker contract
// honest: drift refusal cannot silently turn into another error
// kind that callers fail to detect.
"ErrActionPlanDrift = errors.New(",
// ErrResourceRemediationLocked is the canonical error returned
// when the operator has set NeverAutoRemediate=true on the
// target resource. Pin it here so the broker contract stays
// honest: per-resource lock refusal cannot silently turn into
// another error kind that callers fail to detect.
"ErrResourceRemediationLocked",
"type ActionPolicyAuthorizationLease struct",
"func BeginPolicyActionExecution(",
// ActionVerificationResult is the canonical post-execution
// read-after-write outcome carrier. The broker writes it onto
// ExecutionResult.Verification; pinning the type here keeps the
// shape stable across refactors so frontend audit surfaces and
// any other consumers can rely on it.
"type ActionVerificationResult struct",
"Verification *ActionVerificationResult `json:\"verification,omitempty\"`",
},
filepath.Join(".", "store.go"): {
"RecordActionExecutionStart(record ActionAuditRecord, event ActionLifecycleEvent) error",
"RecordActionPolicyExecutionStart(record ActionAuditRecord, approvalEvent, executionEvent ActionLifecycleEvent) error",
"RecordActionExecutionResult(record ActionAuditRecord, event ActionLifecycleEvent) error",
"func (s *SQLiteResourceStore) RecordActionExecutionStart(record ActionAuditRecord, event ActionLifecycleEvent) error",
"func (s *SQLiteResourceStore) RecordActionPolicyExecutionStart(record ActionAuditRecord, approvalEvent, executionEvent ActionLifecycleEvent) error",
"func (s *SQLiteResourceStore) RecordActionExecutionResult(record ActionAuditRecord, event ActionLifecycleEvent) error",
// Audit-log secret redaction must run at every persistence
// boundary so operator-authored reasons and command output do
// not leak credentials into the plaintext SQL audit history.
// Pin the call sites in store.go to keep redaction wired even
// across future refactors.
"record = RedactAuditRecord(normalized)",
"normalizedRecord = RedactAuditRecord(normalizedRecord)",
// SQLite audit reads must also pass through the shared
// redaction boundary so legacy rows cannot expose verification
// command/output/note details after read-time normalization.
"func redactActionAuditRecordFromStore(record ActionAuditRecord) ActionAuditRecord",
"return redactActionAuditRecordFromStore(record), nil",
"func (s *SQLiteResourceStore) migrateActionAuditRedaction() error",
},
filepath.Join(".", "audit_redaction.go"): {
"func RedactAuditText(s string) string",
"func RedactAuditRecord(record ActionAuditRecord) ActionAuditRecord",
"func redactActionExecutionResult(result *ExecutionResult) *ExecutionResult",
},
filepath.Join(".", "capabilities.go"): {
"type ResourceCapability struct",
"type ResourceActionReadiness struct",
"ReasonCode string `json:\"reasonCode,omitempty\"`",
},
filepath.Join(".", "types.go"): {
"ActionReadiness []ResourceActionReadiness `json:\"actionReadiness,omitempty\"`",
},
filepath.Join("..", "actionlifecycle", "service.go"): {
// The transport-independent lifecycle service is the only
// sanctioned path from a typed action request to execution.
// REST handlers and in-process brokers must both route
// through it; pin its execution-boundary invariants here.
"type Executor interface",
"type AvailabilityChecker interface",
"CheckActionAvailable(ctx context.Context, req unified.ActionRequest, resource unified.Resource) unified.ResourceActionReadiness",
"func (s *Service) ValidatePlanFresh(orgID string, record unified.ActionAuditRecord) error",
"func (s *Service) ValidateExecutionAvailable(ctx context.Context, orgID string, record unified.ActionAuditRecord) error",
"ErrActionExecutionUnavailable",
"func (s *Service) ExecuteUnderPolicy(",
"func RecordRefusedExecution(store Store, record unified.ActionAuditRecord",
"func (s *Service) publishCompleted(record unified.ActionAuditRecord)",
// The persisted-state transition hook is org-scoped so
// multi-tenant reconcilers (e.g. Patrol finding outcomes)
// can never apply a transition to the wrong tenant, and it
// publishes only after the corresponding store write.
"OnActionTransition func(orgID string, record unified.ActionAuditRecord)",
"func (s *Service) publishTransition(orgID string, record unified.ActionAuditRecord)",
"store.RecordActionExecutionAdmission(started, startEvent, attempt)",
"store.MarkActionDispatchStarted(attempt.ID, owner, s.now())",
"s.Executor.ExecuteAction(withDispatchAttempt(ctx, attempt), record)",
"store.RecordActionDispatchCompletion(receipt, completed, doneEvent)",
},
filepath.Join("..", "api", "actions.go"): {
// The REST layer is a thin adapter over the shared lifecycle
// service; it owns only decode, actor resolution, and error
// code mapping.
"type ActionExecutor = actionlifecycle.Executor",
"type ActionAvailabilityChecker = actionlifecycle.AvailabilityChecker",
"func (h *ResourceHandlers) ActionLifecycle() *actionlifecycle.Service",
"func (h *ResourceHandlers) HandleExecuteAction(w http.ResponseWriter, r *http.Request)",
"agentcapabilities.AgentErrCodeActionExecutionUnavailable",
"agentcapabilities.AgentErrCodeActionPlanDrift",
"agentcapabilities.AgentErrCodeActionExecutorUnavailable",
},
filepath.Join("..", "api", "resources_compat.go"): {
"actionExecutor ActionExecutor",
"actionCompleted func(unified.ActionAuditRecord)",
"actionTransition func(orgID string, record unified.ActionAuditRecord)",
"func (h *ResourceHandlers) SetActionExecutor(executor ActionExecutor)",
"func (h *ResourceHandlers) SetActionCompletedPublisher(",
"func (h *ResourceHandlers) SetActionTransitionPublisher(",
"policyAdmission *actionlifecycle.PolicyAdmissionCoordinator",
},
filepath.Join("..", "api", "resourceapi", "resources.go"): {
"actionAvailability actionlifecycle.AvailabilityChecker",
"func (h *QueryService) applyActionAvailability(ctx context.Context, resources []unified.Resource)",
"resources[i].ActionReadiness = readinesses",
},
filepath.Join("..", "api", "agent_events.go"): {
"func (b *AgentEventBroadcaster) PublishActionCompletedRecord(record unifiedresources.ActionAuditRecord)",
"payload := AgentEventActionCompletedPayload{",
"b.PublishActionCompleted(payload)",
},
filepath.Join("..", "api", "router.go"): {
"r.resourceHandlers.SetActionCompletedPublisher(r.agentEventBroadcaster.PublishActionCompletedRecord)",
"SetActionEmergencyStopChecker",
},
filepath.Join("..", "api", "router_routes_monitoring.go"): {
`"POST /api/actions/{id}/execute"`,
"requireActionCapability(r.config, r.authorizer, auth.ActionExecute",
"r.resourceHandlers.HandleExecuteAction",
},
}
for name, snippets := range requiredSnippets {
data, err := os.ReadFile(name)
if err != nil {
t.Fatalf("failed to read %s: %v", name, err)
}
source := string(data)
for _, snippet := range snippets {
if !strings.Contains(source, snippet) {
t.Fatalf("%s must contain %q", name, snippet)
}
}
}
}
func TestResourcePolicySummaryContractOmitsRawSignals(t *testing.T) {
policy := ResourcePolicy{
Sensitivity: ResourceSensitivityRestricted,
Routing: ResourceRoutingPolicy{
Scope: ResourceRoutingScopeLocalOnly,
Redact: []ResourceRedactionHint{
ResourceRedactionHostname,
},
},
}
summary := strings.Join(ResourcePolicySummaryLines(&policy), "\n")
if strings.Contains(summary, "Raw Signals") || strings.Contains(summary, "allowCloudRawSignals") || strings.Contains(summary, "cloud_summary=") {
t.Fatalf("resource policy summary leaked raw-signals wording: %q", summary)
}
}
func TestResourceChangeFilterParsingIsOwnedByUnifiedResources(t *testing.T) {
requiredSnippets := map[string][]string{
filepath.Join(".", "change_filters.go"): {
"func ParseResourceChangeFilters(kinds, sourceTypes, sourceAdapters []string) (ResourceChangeFilters, error)",
"func parseResourceChangeKinds(values []string) ([]ChangeKind, error)",
"func parseResourceChangeSourceTypes(values []string) ([]ChangeSourceType, error)",
"func parseResourceChangeSourceAdapters(values []string) ([]ChangeSourceAdapter, error)",
},
filepath.Join("..", "api", "resourceapi", "resources.go"): {
"unified.ParseResourceChangeFilters(r.URL.Query()[\"kind\"], r.URL.Query()[\"sourceType\"], r.URL.Query()[\"sourceAdapter\"])",
},
}
for name, snippets := range requiredSnippets {
data, err := os.ReadFile(name)
if err != nil {
t.Fatalf("failed to read %s: %v", name, err)
}
for _, snippet := range snippets {
if !strings.Contains(string(data), snippet) {
t.Fatalf("%s must contain %q", name, snippet)
}
}
}
}
func TestPlatformActivityTimelineContractStaysCanonical(t *testing.T) {
requiredSnippets := map[string][]string{
filepath.Join(".", "changes.go"): {
`ChangeActivity ChangeKind = "activity"`,
`AdapterVMware ChangeSourceAdapter = "vmware_adapter"`,
},
filepath.Join(".", "activity_changes.go"): {
"type PlatformActivityChange struct {",
"func BuildPlatformActivityChange(resourceID string, activity PlatformActivityChange) *ResourceChange {",
"Kind: ChangeActivity,",
"SourceType: SourcePlatformEvent,",
"func platformActivityChangeID(resourceID string, sourceAdapter ChangeSourceAdapter, activityType, nativeID string, occurredAt time.Time, title, message string) string {",
},
filepath.Join(".", "change_filters.go"): {
"case string(ChangeActivity):",
"case string(AdapterVMware):",
},
filepath.Join(".", "change_presentation.go"): {
"case ChangeActivity:",
},
filepath.Join(".", "store.go"): {
"ON CONFLICT(id) DO NOTHING",
"if existing.ID == change.ID && change.ID != \"\" {",
},
filepath.Join("..", "monitoring", "monitor.go"): {
"type MonitorSupplementalChangesProvider interface {",
"recordSupplementalResourceChanges(store, supplementalChanges)",
"func recordSupplementalResourceChanges(store ResourceStoreInterface, changes []unifiedresources.ResourceChange) {",
},
filepath.Join("..", "monitoring", "vmware_poller.go"): {
"cachedChangesByOrg map[string]map[string][]unifiedresources.ResourceChange",
"p.cachedChangesByOrg[entry.orgID][entry.connectionID] = changes",
"func (p *VMwarePoller) SupplementalChanges(_ *Monitor, orgID string) []unifiedresources.ResourceChange {",
},
filepath.Join("..", "vmware", "activity_changes.go"): {
"func (p *Provider) ActivityChanges() []unifiedresources.ResourceChange {",
`ActivityType: "vmware_task",`,
`ActivityType: "vmware_event",`,
},
filepath.Join("..", "..", "frontend-modern", "src", "types", "resource.ts"): {
"| 'activity'",
"| 'vmware_adapter'",
},
filepath.Join("..", "..", "frontend-modern", "src", "utils", "resourceChangePresentation.ts"): {
"activity: {",
"vmware_adapter: {",
"case 'activity':",
},
}
for name, snippets := range requiredSnippets {
data, err := os.ReadFile(name)
if err != nil {
t.Fatalf("failed to read %s: %v", name, err)
}
for _, snippet := range snippets {
if !strings.Contains(string(data), snippet) {
t.Fatalf("%s must contain %q", name, snippet)
}
}
}
}
func TestResourcePolicyPresentationUsesCanonicalLabels(t *testing.T) {
data, err := os.ReadFile(filepath.Join(".", "policy_presentation.go"))
if err != nil {
t.Fatalf("failed to read policy_presentation.go: %v", err)
}
source := string(data)
requiredSnippets := []string{
"ResourceSensitivityOrder",
"ResourceRoutingScopeOrder",
"ResourceRedactionHintOrder",
"ResourceSensitivityLabel(",
"ResourceRoutingScopeLabel(",
"ResourceRedactionHintLabel(",
"ResourcePolicyRedactionLabels(",
"ResourcePolicyRedactionLabelsFromCounts(",
"ResourcePolicySensitivitySummaryFromCounts(",
"ResourcePolicyRoutingSummaryFromCounts(",
"ResourcePolicySummaryLines(",
"ResourcePolicyRedacts(",
"ResourcePolicyUsesAISafeSummary(",
}
for _, snippet := range requiredSnippets {
if !strings.Contains(source, snippet) {
t.Fatalf("policy_presentation.go must contain %q", snippet)
}
}
}
func TestResourcePolicyCloneHelperUsedByAIConsumers(t *testing.T) {
requiredFiles := []string{
filepath.Join("..", "ai", "chat", "context_prefetch.go"),
filepath.Join("..", "ai", "tools", "tools_query.go"),
filepath.Join(".", "policy_metadata.go"),
}
requiredSnippets := map[string]string{
filepath.Join("..", "ai", "chat", "context_prefetch.go"): "unifiedresources.CanonicalGovernanceMetadata(resource)",
filepath.Join("..", "ai", "tools", "tools_query.go"): "unifiedresources.CanonicalGovernanceMetadata(resource)",
filepath.Join(".", "policy_metadata.go"): "func CanonicalGovernanceMetadata(resource *Resource) (*ResourcePolicy, string)",
}
for _, name := range requiredFiles {
data, err := os.ReadFile(name)
if err != nil {
t.Fatalf("failed to read %s: %v", name, err)
}
snippet := requiredSnippets[name]
if !strings.Contains(string(data), snippet) {
t.Fatalf("%s must contain %q", name, snippet)
}
}
}
func TestAISafeSummarySuffixHelperIsOwnedByUnifiedResources(t *testing.T) {
data, err := os.ReadFile(filepath.Join(".", "policy_metadata.go"))
if err != nil {
t.Fatalf("failed to read policy_metadata.go: %v", err)
}
source := string(data)
requiredSnippets := []string{
"func resourceAISafeSummaryPolicySuffix(sensitivity ResourceSensitivity) string",
"return \"redacted for cloud summary\"",
"return \"local-only context\"",
}
for _, snippet := range requiredSnippets {
if !strings.Contains(source, snippet) {
t.Fatalf("policy_metadata.go must contain %q", snippet)
}
}
}
func TestCanonicalMetadataRefreshHelperUsedByConsumers(t *testing.T) {
requiredSnippets := map[string][]string{
filepath.Join(".", "policy_metadata.go"): {
"func RefreshCanonicalMetadata(resource *Resource)",
"func RefreshCanonicalMetadataSlice(resources []Resource) []Resource",
},
filepath.Join(".", "clone.go"): {
"RefreshCanonicalMetadata(&out)",
},
filepath.Join("..", "api", "resourceapi", "resources.go"): {
"unified.RefreshCanonicalMetadata(&resourceCopy)",
"unified.RefreshCanonicalMetadataSlice(paged)",
"unified.RefreshCanonicalMetadataSlice(children)",
},
filepath.Join("..", "ai", "resource_context.go"): {
"unifiedresources.RefreshCanonicalMetadataSlice(urp.GetInfrastructure())",
"unifiedresources.RefreshCanonicalMetadataSlice(urp.GetWorkloads())",
"unifiedresources.RefreshCanonicalMetadataSlice(urp.GetAll())",
},
filepath.Join("..", "ai", "intelligence.go"): {
"unifiedresources.RefreshCanonicalMetadataSlice(unifiedResourceProvider.GetAll())",
},
}
for name, snippets := range requiredSnippets {
data, err := os.ReadFile(name)
if err != nil {
t.Fatalf("failed to read %s: %v", name, err)
}
for _, snippet := range snippets {
if !strings.Contains(string(data), snippet) {
t.Fatalf("%s must contain %q", name, snippet)
}
}
}
}
func TestResourcePolicyLabelHelpersUsedByAIConsumers(t *testing.T) {
requiredSnippets := map[string][]string{
filepath.Join("..", "ai", "intelligence.go"): {
"func (i *Intelligence) HasCorrelationsSource() bool",
"func (i *Intelligence) GetCorrelations(resourceID string) []*correlation.Correlation",
"func (i *Intelligence) FormatCorrelationsContext(resourceID string) string",
},
filepath.Join("..", "ai", "service.go"): {
"intel.FormatCorrelationsContext(resourceID)",
},
filepath.Join("..", "ai", "patrol_ai.go"): {
"intelFacade.GetCorrelations(\"\")",
},
filepath.Join("..", "api", "ai_intelligence_handlers.go"): {
"intel.HasCorrelationsSource()",
"intel.GetCorrelations(resourceID)",
},
filepath.Join("..", "ai", "chat", "knowledge_extractor.go"): {
"unifiedresources.ResourcePolicyLabel(",
"unifiedresources.ResourcePolicyRedactedValue(",
},
filepath.Join("..", "ai", "chat", "context_prefetch.go"): {
"tools.CanonicalDiscoveryResourceType(",
"tools.DiscoveryProviderResourceType(",
"tools.CanonicalDiscoveryTargetID(",
"unifiedresources.ResourcePolicyRequiresGovernedSummary(mention.Policy)",
"unifiedresources.FormatResourcePolicyGovernedSummary(mention.AISafeSummary, mention.Policy)",
},
filepath.Join("..", "ai", "tools", "tools_discovery.go"): {
"func CanonicalDiscoveryResourceType(raw string) string",
"func DiscoveryProviderResourceType(canonical string) string",
"func CanonicalDiscoveryTargetID(discovery *ResourceDiscoveryInfo, fallbackTargetID string) string",
},
filepath.Join("..", "ai", "resource_export.go"): {
"unifiedresources.ResourceRedactionLabelsFromHints(redactionHints)",
},
filepath.Join("..", "ai", "resource_context.go"): {
"unifiedresources.ResourcePolicyLabel(",
"unifiedresources.ResourcePolicyRedactedText(",
"unifiedresources.ResourceDisplayName(",
"unifiedresources.ResourceClusterName(",
"unifiedresources.ResourceIPSummary(",
},
filepath.Join("..", "ai", "chat", "service.go"): {
"unifiedresources.ResourcePolicyRedactedTextWithReferences(",
"unifiedresources.ResourcePolicyReference(",
},
filepath.Join("..", "unifiedresources", "unified_ai_adapter.go"): {
"ResourceDisplayName(results[i])",
"ResourceDisplayName(results[j])",
},
filepath.Join(".", "policy_presentation.go"): {
"func ResourcePolicyLabel(name, aiSafeSummary string, policy *ResourcePolicy) string",
"if ResourcePolicyRequiresGovernedSummary(policy) {",
"return ResourcePolicyRedactedLabel",
"return ResourcePolicyRequiresGovernedSummary(policy)",
"Policy: sensitivity=%s, routing=%s",
"func ResourcePolicyRedactedValue(value string, policy *ResourcePolicy, hints ...ResourceRedactionHint) string",
"func ResourcePolicyRedactedText(value string, resource Resource) string",
"func ResourcePolicyRedactedTextWithReferences(value string, resource Resource, references ...ResourcePolicyRedactionReference) string",
"func ResourcePolicyReference(value string, hints ...ResourceRedactionHint) ResourcePolicyRedactionReference",
"const ResourcePolicyRedactedLabel = \"redacted by policy\"",
"func ResourceRedactionLabelsFromHints(hints []ResourceRedactionHint) []string",
"func ResourceClusterName(resource Resource) string",
"func ResourceIPSummary(resource Resource, limit int) string",
"func ResourcePolicyRequiresGovernedSummary(policy *ResourcePolicy) bool",
"func ResourcePolicyGovernedSummaryPreamble() string",
"func ResourcePolicyGovernedSummaryFooter() string",
"func FormatResourcePolicyGovernedSummary(summary string, policy *ResourcePolicy) string",
"func ResourceDisplayName(resource Resource) string",
},
}
for name, snippets := range requiredSnippets {
data, err := os.ReadFile(name)
if err != nil {
t.Fatalf("failed to read %s: %v", name, err)
}
for _, snippet := range snippets {
if !strings.Contains(string(data), snippet) {
t.Fatalf("%s must contain %q", name, snippet)
}
}
}
}
func TestPolicyPostureSummaryIsOwnedByUnifiedResources(t *testing.T) {
requiredSnippets := map[string][]string{
filepath.Join(".", "policy_posture.go"): {
"type PolicyPostureSummary struct {",
"func SummarizePolicyPosture(resources []Resource) *PolicyPostureSummary",
"type ResourcePolicyPostureSummary struct {",
"func ResourcePolicyPostureContract(summary *PolicyPostureSummary) *ResourcePolicyPostureSummary",
},
filepath.Join("..", "ai", "intelligence.go"): {
"unifiedresources.PolicyPostureSummary",
"unifiedresources.SummarizePolicyPosture(",
},
filepath.Join("..", "ai", "resource_context.go"): {
"unifiedresources.SummarizePolicyPosture(allResources)",
},
filepath.Join("..", "api", "resourceapi", "resources.go"): {
"resourcePolicyPostureAggregation(allResources)",
"unified.ResourcePolicyPostureContract(unified.SummarizePolicyPosture(canonicalResources))",
},
}
for name, snippets := range requiredSnippets {
data, err := os.ReadFile(name)
if err != nil {
t.Fatalf("failed to read %s: %v", name, err)
}
for _, snippet := range snippets {
if !strings.Contains(string(data), snippet) {
t.Fatalf("%s must contain %q", name, snippet)
}
}
}
}
func TestExportDecisionHelpersUsedByAIConsumers(t *testing.T) {
data, err := os.ReadFile(filepath.Join("..", "ai", "resource_export.go"))
if err != nil {
t.Fatalf("failed to read resource_export.go: %v", err)
}
source := string(data)
requiredSnippets := []string{
"unifiedresources.ExportSensitivityFloor(sensitivityCounts)",
"unifiedresources.ExportDecisionForContext(sensitivityFloor, localOnlyCount, len(redactions))",
}
for _, snippet := range requiredSnippets {
if !strings.Contains(source, snippet) {
t.Fatalf("internal/ai/resource_export.go must pin canonical export decision snippet %q", snippet)
}
}
}
func TestExportDecisionHelpersCanonicalInUnifiedResources(t *testing.T) {
data, err := os.ReadFile(filepath.Join("privacy.go"))
if err != nil {
t.Fatalf("failed to read privacy.go: %v", err)
}
source := string(data)
requiredSnippets := []string{
"func ExportSensitivityFloor(counts map[ResourceSensitivity]int) DataSensitivity",
"func ExportDecisionForContext(sensitivityFloor DataSensitivity, localOnlyCount int, redactionCount int) (ExportDecision, string)",
}
for _, snippet := range requiredSnippets {
if !strings.Contains(source, snippet) {
t.Fatalf("internal/unifiedresources/privacy.go must pin canonical export helper snippet %q", snippet)
}
}
}
func TestRootCauseEngineUsesCanonicalRelationshipModel(t *testing.T) {
data, err := os.ReadFile(filepath.Join("..", "ai", "correlation", "rootcause.go"))
if err != nil {
t.Fatalf("failed to read rootcause.go: %v", err)
}
source := string(data)
requiredSnippets := []string{
"type RelationshipType = unifiedresources.RelationshipType",
"type ResourceRelationship = unifiedresources.ResourceRelationship",
"GetRelationships(resourceID string) []ResourceRelationship",
"score += relationshipScore(rel.Type)",
"func relationshipScore(t RelationshipType) float64",
}
for _, snippet := range requiredSnippets {
if !strings.Contains(source, snippet) {
t.Fatalf("internal/ai/correlation/rootcause.go must pin canonical relationship snippet %q", snippet)
}
}
}
func TestResourceDisplayNameUsedByInfrastructureConsumers(t *testing.T) {
requiredSnippets := map[string][]string{
filepath.Join("..", "monitoring", "connected_infrastructure.go"): {
"unifiedresources.ResourceDisplayName(resource)",
},
filepath.Join(".", "monitored_systems.go"): {
"if name := ResourceDisplayName(*resource); name != \"\" {",
},
}
for name, snippets := range requiredSnippets {
data, err := os.ReadFile(name)
if err != nil {
t.Fatalf("failed to read %s: %v", name, err)
}
for _, snippet := range snippets {
if !strings.Contains(string(data), snippet) {
t.Fatalf("%s must contain %q", name, snippet)
}
}
}
}
func TestTopLevelSystemResolverPinsCanonicalInfrastructureCounting(t *testing.T) {
requiredSnippets := map[string][]string{
filepath.Join(".", "monitored_systems.go"): {
"resolveMonitoredSystemTopLevelSystems(rs).Count()",
"ResolveTopLevelSystems(resources)",
},
filepath.Join(".", "top_level_systems.go"): {
"ResolveTopLevelSystems(resources []Resource) TopLevelSystemResolver",
"match.Confidence < HighConfidenceThreshold",
"topLevelSystemGroupingExplanation(",
"monitoredSystemCandidateAllowsHostAttachment(candidate)",
"isNonUniqueIP(normalizedIP)",
"When adding a new top-level monitored-system source, update:",
},
}
for name, snippets := range requiredSnippets {
data, err := os.ReadFile(name)
if err != nil {
t.Fatalf("failed to read %s: %v", name, err)
}
source := string(data)
for _, snippet := range snippets {
if !strings.Contains(source, snippet) {
t.Fatalf("%s must contain %q", name, snippet)
}
}
}
}
func TestResourceTimelineStoreIndexesSupportFilteredReads(t *testing.T) {
data, err := os.ReadFile(filepath.Join("store.go"))
if err != nil {
t.Fatalf("failed to read store.go: %v", err)
}
source := string(data)
requiredSnippets := []string{
"idx_resource_changes_kind_time",
"idx_resource_changes_source_type_time",
"idx_resource_changes_source_adapter_time",
"ensureResourceChangesIndexes",
}
for _, snippet := range requiredSnippets {
if !strings.Contains(source, snippet) {
t.Fatalf("internal/unifiedresources/store.go must pin filtered timeline index snippet %q", snippet)
}
}
}
func TestResourceChangeEmissionCoversRelationshipAndCapabilityChanges(t *testing.T) {
data, err := os.ReadFile(filepath.Join("change_emission.go"))
if err != nil {
t.Fatalf("failed to read change_emission.go: %v", err)
}
source := string(data)
requiredSnippets := []string{
"change.RelatedResources = relatedResourceIDs(change.ResourceID, before, after)",
"case resourceRestartChanged(before, after):",
"case resourceIncidentChanged(before, after):",
"if !relationshipsEquivalent(before.Relationships, after.Relationships) {",
"changed = append(changed, \"relationships\")",
"func relationshipsEquivalent(a, b []ResourceRelationship) bool {",
"if resourceIncidentChanged(before, after) {",
"changed = append(changed, \"incidents\")",
"if dockerRestartChanged(before, after) {",
"changed = append(changed, \"docker.restartCount\", \"docker.uptimeSeconds\")",
"if kubernetesRestartChanged(before, after) {",
"changed = append(changed, \"kubernetes.restarts\", \"kubernetes.uptimeSeconds\")",
"if !reflect.DeepEqual(before.Capabilities, after.Capabilities) {",
"changed = append(changed, \"capabilities\")",
}
for _, snippet := range requiredSnippets {
if !strings.Contains(source, snippet) {
t.Fatalf("internal/unifiedresources/change_emission.go must pin canonical relationship/capability change detection snippet %q", snippet)
}
}
}
func TestResourceChangePresentationUsesCanonicalLabels(t *testing.T) {
data, err := os.ReadFile(filepath.Join("change_presentation.go"))
if err != nil {
t.Fatalf("failed to read change_presentation.go: %v", err)
}
source := string(data)
requiredSnippets := []string{
"func ChangeKindLabel(kind ChangeKind) string",
"func DescribeChange(change ResourceChange) ChangePresentation",
"func FormatResourceChangeSummary(change ResourceChange) string",
"func resourceRelationshipSummary(relationships []ResourceRelationship) string",
"resourceStateSummary(resource Resource) string",
"resourceRestartSummary(resource Resource) string",
"resourceIncidentSummary(resource Resource) string",
"resourceIncidentSummaryFromSlice(incidents []ResourceIncident) string",
"resourceIncidentLabel(incident ResourceIncident) string",
"resourceConfigSummary(resource Resource) string",
"KindLabel: ChangeKindLabel(change.Kind)",
"presentation.SourceType = strings.TrimSpace(string(change.SourceType))",
"presentation.SourceAdapter = strings.TrimSpace(string(change.SourceAdapter))",
}
for _, snippet := range requiredSnippets {
if !strings.Contains(source, snippet) {
t.Fatalf("internal/unifiedresources/change_presentation.go must pin canonical change presentation snippet %q", snippet)
}
}
}
func TestAlertSnoozeChangeKindsRemainCanonical(t *testing.T) {
filters, err := ParseResourceChangeFilters([]string{"alert_snoozed,alert_unsnoozed"}, nil, nil)
if err != nil {
t.Fatal(err)
}
want := []ChangeKind{ChangeAlertSnoozed, ChangeAlertUnsnoozed}
if !reflect.DeepEqual(filters.Kinds, want) {
t.Fatalf("snooze filters = %#v, want %#v", filters.Kinds, want)
}
if ChangeKindLabel(ChangeAlertSnoozed) != "Alert snoozed" || ChangeKindLabel(ChangeAlertUnsnoozed) != "Alert resumed" {
t.Fatalf("snooze labels = %q, %q", ChangeKindLabel(ChangeAlertSnoozed), ChangeKindLabel(ChangeAlertUnsnoozed))
}
}
func TestResourceRelationshipContextUsesCanonicalRelationshipPresentation(t *testing.T) {
data, err := os.ReadFile(filepath.Join("..", "ai", "service.go"))
if err != nil {
t.Fatalf("failed to read service.go: %v", err)
}
source := string(data)
requiredSnippets := []string{
"func (s *Service) buildResourceRelationshipContext(resourceID string) string",
"if relationshipContext := s.buildResourceRelationshipContext(resourceID); relationshipContext != \"\" {",
"Get canonical relationship context from unified resources.",
"unifiedresources.FormatResourceRelationshipContext(resource, 3)",
"unifiedresources.FormatResourceRecentChangesContext(changes, false, \"###\")",
"type canonicalResourceGetter interface {",
"intel.FormatCorrelationsContext(resourceID)",
}
for _, snippet := range requiredSnippets {
if !strings.Contains(source, snippet) {
t.Fatalf("internal/ai/service.go must pin canonical relationship presentation snippet %q", snippet)
}
}
}
func TestResourceRelationshipModelUsesCanonicalEdgeComment(t *testing.T) {
data, err := os.ReadFile(filepath.Join("relationships.go"))
if err != nil {
t.Fatalf("failed to read relationships.go: %v", err)
}
source := string(data)
requiredSnippets := []string{
"// ResourceRelationship represents a typed relationship edge between two unified resources.",
"type ResourceRelationship struct {",
"const parentRelationshipDiscoverer = \"resource_registry\"",
"func ResourceRelationshipsWithCanonicalParent(resource Resource) []ResourceRelationship",
"relationshipType := parentRelationshipType(resource.Type)",
"Metadata: map[string]any{",
"func parentRelationshipType(resourceType ResourceType) RelationshipType",
}
for _, snippet := range requiredSnippets {
if !strings.Contains(source, snippet) {
t.Fatalf("internal/unifiedresources/relationships.go must pin canonical relationship edge snippet %q", snippet)
}
}
}
func TestPatrolSeedCorrelationContextUsesCanonicalSummaryFormatter(t *testing.T) {
data, err := os.ReadFile(filepath.Join("..", "ai", "patrol_ai.go"))
if err != nil {
t.Fatalf("failed to read patrol_ai.go: %v", err)
}
source := string(data)
requiredSnippets := []string{
"# Known Resource Correlations",
"correlation.FormatCorrelationSummary(c)",
"memory.ChangeFromUnifiedResourceChange(change)",
}
for _, snippet := range requiredSnippets {
if !strings.Contains(source, snippet) {
t.Fatalf("internal/ai/patrol_ai.go must pin canonical correlation presentation snippet %q", snippet)
}
}
}
func TestIntelligenceRecentChangesUseCanonicalSummaryFormatter(t *testing.T) {
data, err := os.ReadFile(filepath.Join("..", "ai", "intelligence.go"))
if err != nil {
t.Fatalf("failed to read intelligence.go: %v", err)
}
source := string(data)
requiredSnippets := []string{
"func (i *Intelligence) GetRecentChanges(since time.Time, limit int) []unifiedresources.ResourceChange",
"func (i *Intelligence) DescribeResource(resourceID string) (string, string)",
"func (i *Intelligence) HasRecentChangesSource() bool",
"unifiedresources.FormatResourceRecentChangesContext(recent, includeResourcePrefix, \"##\")",
}
for _, snippet := range requiredSnippets {
if !strings.Contains(source, snippet) {
t.Fatalf("internal/ai/intelligence.go must pin canonical recent-change snippet %q", snippet)
}
}
}
func TestMemoryChangeConversionHelpersAreSharedAcrossAIConsumers(t *testing.T) {
requiredFiles := map[string][]string{
filepath.Join("..", "ai", "patrol_ai.go"): {
"memory.ChangeFromUnifiedResourceChange(change)",
},
filepath.Join("..", "ai", "intelligence.go"): {
"memory.ResourceChangeFromMemoryChange(change)",
},
filepath.Join("..", "ai", "memory", "presentation.go"): {
"func ChangeFromUnifiedResourceChange(change unifiedresources.ResourceChange) Change",
"func ResourceChangeFromMemoryChange(change Change) unifiedresources.ResourceChange",
},
}
for path, snippets := range requiredFiles {
data, err := os.ReadFile(path)
if err != nil {
t.Fatalf("failed to read %s: %v", path, err)
}
source := string(data)
for _, snippet := range snippets {
if !strings.Contains(source, snippet) {
t.Fatalf("%s must pin canonical memory conversion snippet %q", path, snippet)
}
}
}
}
func TestAIRecentChangesHandlerUsesCanonicalIntelligencePath(t *testing.T) {
data, err := os.ReadFile(filepath.Join("..", "api", "ai_intelligence_handlers.go"))
if err != nil {
t.Fatalf("failed to read ai_intelligence_handlers.go: %v", err)
}
source := string(data)
requiredSnippets := []string{
"intel := patrol.GetIntelligence()",
"intel.HasRecentChangesSource()",
"intel.GetRecentChanges(since, 100)",
"intel.DescribeResource(change.ResourceID)",
"unifiedresources.FormatResourceChangeSummary(change)",
"Recent changes not initialized",
}
for _, snippet := range requiredSnippets {
if !strings.Contains(source, snippet) {
t.Fatalf("internal/api/ai_intelligence_handlers.go must pin canonical recent-changes snippet %q", snippet)
}
}
}
func TestResourcePresentationsUseSharedDurationHelper(t *testing.T) {
requiredFiles := []string{
"change_presentation.go",
"relationship_presentation.go",
}
for _, name := range requiredFiles {
data, err := os.ReadFile(filepath.Join(name))
if err != nil {
t.Fatalf("failed to read %s: %v", name, err)
}
if !strings.Contains(string(data), "utils.FormatDurationAgo(") {
t.Fatalf("%s must use the shared utils.FormatDurationAgo helper", name)
}
}
}
func TestResourceFacetCountsAreCanonicalResourceFields(t *testing.T) {
typesData, err := os.ReadFile(filepath.Join("types.go"))
if err != nil {
t.Fatalf("failed to read types.go: %v", err)
}
typesSource := string(typesData)
if !strings.Contains(typesSource, "FacetCounts ResourceFacetCounts") {
t.Fatalf("internal/unifiedresources/types.go must expose Resource.FacetCounts on the canonical resource model")
}
if !strings.Contains(typesSource, "json:\"facetCounts,omitempty\"") {
t.Fatalf("internal/unifiedresources/types.go must keep the facetCounts JSON contract")
}
if !strings.Contains(typesSource, "RecentChangeKinds map[ChangeKind]int") {
t.Fatalf("internal/unifiedresources/types.go must expose grouped timeline counts on the canonical facet model")
}
if !strings.Contains(typesSource, "RecentChangeSourceTypes map[ChangeSourceType]int") {
t.Fatalf("internal/unifiedresources/types.go must expose grouped timeline source-type counts on the canonical facet model")
}
if !strings.Contains(typesSource, "RecentChangeSourceAdapters map[ChangeSourceAdapter]int") {
t.Fatalf("internal/unifiedresources/types.go must expose grouped timeline source-adapter counts on the canonical facet model")
}
cloneData, err := os.ReadFile(filepath.Join("clone.go"))
if err != nil {
t.Fatalf("failed to read clone.go: %v", err)
}
cloneSource := string(cloneData)
requiredSnippets := []string{
"out.FacetCounts = resourceFacetCounts(out)",
"func resourceFacetCounts(resource Resource) ResourceFacetCounts",
}
for _, snippet := range requiredSnippets {
if !strings.Contains(cloneSource, snippet) {
t.Fatalf("internal/unifiedresources/clone.go must derive canonical facet counts via %q", snippet)
}
}
}
func TestCanonicalIdentityIsCanonicalResourceField(t *testing.T) {
typesData, err := os.ReadFile(filepath.Join("types.go"))
if err != nil {
t.Fatalf("failed to read types.go: %v", err)
}
typesSource := string(typesData)
requiredSnippets := []string{
"json:\"canonicalIdentity,omitempty\"",
"type CanonicalIdentity struct {",
"DisplayName string `json:\"displayName,omitempty\"`",
"Aliases []string `json:\"aliases,omitempty\"`",
"SupersededIDs []string `json:\"supersededIds,omitempty\"`",
}
for _, snippet := range requiredSnippets {
if !strings.Contains(typesSource, snippet) {
t.Fatalf("internal/unifiedresources/types.go must keep the canonical identity contract snippet %q", snippet)
}
}
cloneData, err := os.ReadFile(filepath.Join("clone.go"))
if err != nil {
t.Fatalf("failed to read clone.go: %v", err)
}
cloneSource := string(cloneData)
requiredCloneSnippets := []string{
"RefreshCanonicalMetadata(&out)",
}
for _, snippet := range requiredCloneSnippets {
if !strings.Contains(cloneSource, snippet) {
t.Fatalf("internal/unifiedresources/clone.go must preserve canonical identity via %q", snippet)
}
}
}
// TestNoLegacyHostResourceTypeSymbol prevents reintroducing the removed
// ResourceTypeHost symbol. v6 code must use ResourceTypeAgent and
// CanonicalResourceType() for legacy normalization.
func TestNoLegacyHostResourceTypeSymbol(t *testing.T) {
internalDir := filepath.Join("..")
err := filepath.Walk(internalDir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() {
return nil
}
if filepath.Ext(path) != ".go" || strings.HasSuffix(path, "_test.go") {
return nil
}
data, readErr := os.ReadFile(path)
if readErr != nil {
return readErr
}
content := string(data)
if !strings.Contains(content, "ResourceTypeHost") {
return nil
}
normalizedPath := filepath.ToSlash(path)
t.Errorf("%s: legacy ResourceTypeHost symbol detected; use ResourceTypeAgent instead", normalizedPath)
return nil
})
if err != nil {
t.Fatalf("failed to scan internal packages: %v", err)
}
}
func TestResourceParentBySourceStateRemainsInternal(t *testing.T) {
resourceType := reflect.TypeOf(Resource{})
parentIDField, ok := resourceType.FieldByName("ParentID")
if !ok {
t.Fatalf("expected Resource.ParentID field")
}
if got := parentIDField.Tag.Get("json"); got != "parentId,omitempty" {
t.Fatalf("Resource.ParentID json tag = %q, want %q", got, "parentId,omitempty")
}
parentBySourceField, ok := resourceType.FieldByName("parentBySource")
if !ok {
t.Fatalf("expected Resource.parentBySource field")
}
if parentBySourceField.IsExported() {
t.Fatalf("expected Resource.parentBySource to remain internal-only")
}
if got := parentBySourceField.Tag.Get("json"); got != "" {
t.Fatalf("expected Resource.parentBySource to have no JSON contract, got %q", got)
}
}
func TestHostMaintenancePostureRemainsAgentScoped(t *testing.T) {
agentType := reflect.TypeOf(AgentData{})
field, ok := agentType.FieldByName("PackageUpdates")
if !ok {
t.Fatal("expected AgentData.PackageUpdates field")
}
if got := field.Tag.Get("json"); got != "packageUpdates,omitempty" {
t.Fatalf("expected package-update posture to use the agent-scoped wire key, got %q", got)
}
if field.Type != reflect.TypeOf((*AgentPackageUpdateMeta)(nil)) {
t.Fatalf("expected typed package-update metadata, got %v", field.Type)
}
cleanupField, ok := agentType.FieldByName("StorageCleanup")
if !ok {
t.Fatal("expected AgentData.StorageCleanup field")
}
if got := cleanupField.Tag.Get("json"); got != "storageCleanup,omitempty" {
t.Fatalf("expected storage-cleanup posture to use the agent-scoped wire key, got %q", got)
}
if cleanupField.Type != reflect.TypeOf((*AgentStorageCleanupMeta)(nil)) {
t.Fatalf("expected typed storage-cleanup metadata, got %v", cleanupField.Type)
}
for _, tc := range []struct {
name string
typeOf reflect.Type
}{
{name: "package updates", typeOf: reflect.TypeOf(AgentPackageUpdateMeta{})},
{name: "storage cleanup", typeOf: reflect.TypeOf(AgentStorageCleanupMeta{})},
} {
checkedAt, ok := tc.typeOf.FieldByName("CheckedAt")
if !ok || checkedAt.Type != reflect.TypeOf(time.Time{}) || checkedAt.Tag.Get("json") != "checkedAt,omitempty" {
t.Fatalf("%s CheckedAt contract = %#v", tc.name, checkedAt)
}
observedAt, ok := tc.typeOf.FieldByName("ObservedAt")
if !ok || observedAt.Type != reflect.TypeOf(time.Time{}) || observedAt.Tag.Get("json") != "observedAt,omitempty" {
t.Fatalf("%s ObservedAt contract = %#v", tc.name, observedAt)
}
}
resourceType := reflect.TypeOf(Resource{})
if _, ok := resourceType.FieldByName("PackageUpdates"); ok {
t.Fatal("package-update posture must not become an unscoped top-level Resource field")
}
if _, ok := resourceType.FieldByName("StorageCleanup"); ok {
t.Fatal("storage-cleanup posture must not become an unscoped top-level Resource field")
}
}
func TestHostAPTTelemetryTruthStaysUnifiedResourceOwned(t *testing.T) {
ownerSource, err := os.ReadFile("host_apt_telemetry.go")
if err != nil {
t.Fatalf("read canonical host APT telemetry owner: %v", err)
}
for _, required := range []string{
"func ValidHostAPTDigest(value string) bool",
"func HostPackageUpdateTelemetryFresh(status *AgentPackageUpdateMeta, now time.Time) bool",
"func HostStorageCleanupTelemetryFresh(status *AgentStorageCleanupMeta, now time.Time) bool",
} {
if !strings.Contains(string(ownerSource), required) {
t.Fatalf("unifiedresources must own host APT telemetry truth: missing %q", required)
}
}
workflowFiles := []string{
filepath.Join("..", "ai", "findings_apt_workflows.go"),
filepath.Join("..", "api", "host_update_action_executor.go"),
filepath.Join("..", "api", "host_storage_cleanup_action_executor.go"),
}
forbiddenDeclarations := []*regexp.Regexp{
regexp.MustCompile(`(?m)^type\s+AgentPackageUpdateMeta\b`),
regexp.MustCompile(`(?m)^type\s+AgentStorageCleanupMeta\b`),
regexp.MustCompile(`(?m)^func\s+\w*(?:TelemetryFresh|APTDigest)\b`),
}
for _, path := range workflowFiles {
source, err := os.ReadFile(path)
if err != nil {
t.Fatalf("read host APT workflow %s: %v", path, err)
}
for _, forbidden := range forbiddenDeclarations {
if forbidden.Match(source) {
t.Fatalf("host APT workflow %s duplicates unified-resource telemetry truth with %s", path, forbidden)
}
}
}
findingSource, err := os.ReadFile(filepath.Join("..", "ai", "findings_apt_workflows.go"))
if err != nil {
t.Fatalf("read host APT finding producer: %v", err)
}
for _, required := range []string{
"unifiedresources.ValidHostAPTDigest",
"unifiedresources.HostPackageUpdateTelemetryFresh",
"unifiedresources.HostStorageCleanupTelemetryFresh",
} {
if !strings.Contains(string(findingSource), required) {
t.Fatalf("host APT finding producer must consume canonical telemetry truth: missing %q", required)
}
}
}
// TestNoLegacyMigrationHintsInRuntimeCode prevents reintroducing runtime
// messages that point removed aliases at the wrong token guidance.
func TestNoLegacyMigrationHintsInRuntimeCode(t *testing.T) {
bannedPhrases := []string{
`no longer supported; use "agent"`,
`no longer supported; use "agent:*"`,
`app_container is no longer supported; use container`,
}
internalDir := filepath.Join("..")
err := filepath.Walk(internalDir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() {
return nil
}
if filepath.Ext(path) != ".go" || strings.HasSuffix(path, "_test.go") {
return nil
}
data, readErr := os.ReadFile(path)
if readErr != nil {
return readErr
}
content := string(data)
normalizedPath := filepath.ToSlash(path)
for _, phrase := range bannedPhrases {
if !strings.Contains(content, phrase) {
continue
}
t.Errorf("%s: banned legacy migration hint detected: %q", normalizedPath, phrase)
}
return nil
})
if err != nil {
t.Fatalf("failed to scan internal packages: %v", err)
}
}
// TestV6AgentRegistrationArtifactsStayCanonical prevents the release-facing
// agent registration journey and eval instructions from drifting back to
// legacy /api/state.hosts or legacy agent.type="host" assumptions.
func TestV6AgentRegistrationArtifactsStayCanonical(t *testing.T) {
repoRoot := filepath.Join("..", "..")
integrationRoots := []string{
filepath.Join(repoRoot, "tests", "integration", "tests"),
filepath.Join(repoRoot, "tests", "integration", "evals"),
}
globalBannedPatterns := []*regexp.Regexp{
regexp.MustCompile(`state\.hosts\b`),
regexp.MustCompile(`hosts array`),
regexp.MustCompile(`agent\.type\s*=\s*"host"`),
regexp.MustCompile(`type:\s*'host'`),
regexp.MustCompile(`"type"\s*:\s*"host"`),
regexp.MustCompile(`resourceType"\s*:\s*"host"`),
regexp.MustCompile(`resourceType:\s*'host'`),
regexp.MustCompile(`/api/resources\?type=host`),
}
for _, root := range integrationRoots {
err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() {
return nil
}
switch filepath.Ext(path) {
case ".ts", ".tsx", ".md":
default:
return nil
}
data, readErr := os.ReadFile(path)
if readErr != nil {
return readErr
}
content := string(data)
normalizedPath := filepath.ToSlash(path)
for _, pattern := range globalBannedPatterns {
matches := pattern.FindAllStringIndex(content, -1)
for _, match := range matches {
line := 1 + strings.Count(content[:match[0]], "\n")
t.Errorf("%s:%d: banned legacy integration/eval pattern %q", normalizedPath, line, pattern.String())
}
}
return nil
})
if err != nil {
t.Fatalf("failed to scan %s: %v", root, err)
}
}
artifacts := []struct {
path string
requiredSnippets []string
requiredPatterns []*regexp.Regexp
bannedPatterns []*regexp.Regexp
}{
{
path: filepath.Join(
repoRoot,
"tests",
"integration",
"tests",
"journeys",
"04-agent-install-registration.spec.ts",
),
requiredSnippets: []string{
"state.resources",
},
requiredPatterns: []*regexp.Regexp{
regexp.MustCompile(`type:\s*['"]unified['"]`),
},
bannedPatterns: []*regexp.Regexp{
regexp.MustCompile(`state\.hosts\b`),
regexp.MustCompile(`hosts array`),
regexp.MustCompile(`type:\s*'host'`),
regexp.MustCompile(`"type"\s*:\s*"host"`),
},
},
{
path: filepath.Join(
repoRoot,
"tests",
"integration",
"evals",
"tasks",
"agent-registration.md",
),
requiredSnippets: []string{
"resources[]",
`agent.type = "unified"`,
},
bannedPatterns: []*regexp.Regexp{
regexp.MustCompile("`hosts` array"),
regexp.MustCompile(`agent\.type\s*=\s*"host"`),
},
},
}
for _, artifact := range artifacts {
data, err := os.ReadFile(artifact.path)
if err != nil {
t.Fatalf("failed to read %s: %v", artifact.path, err)
}
content := string(data)
normalizedPath := filepath.ToSlash(artifact.path)
for _, snippet := range artifact.requiredSnippets {
if !strings.Contains(content, snippet) {
t.Errorf("%s: missing required canonical v6 snippet %q", normalizedPath, snippet)
}
}
for _, pattern := range artifact.requiredPatterns {
if !pattern.MatchString(content) {
t.Errorf("%s: missing required canonical v6 pattern %q", normalizedPath, pattern.String())
}
}
for _, pattern := range artifact.bannedPatterns {
matches := pattern.FindAllStringIndex(content, -1)
for _, match := range matches {
line := 1 + strings.Count(content[:match[0]], "\n")
t.Errorf(
"%s:%d: banned legacy agent registration artifact pattern %q",
normalizedPath,
line,
pattern.String(),
)
}
}
}
}
// TestV6AIEvalPromptsStayCanonical prevents internal AI eval scenarios from
// teaching legacy pulse_query list types after the v6 canonicalization.
func TestV6AIEvalPromptsStayCanonical(t *testing.T) {
repoRoot := filepath.Join("..", "..")
path := filepath.Join(repoRoot, "internal", "ai", "eval", "scenarios.go")
data, err := os.ReadFile(path)
if err != nil {
t.Fatalf("failed to read %s: %v", path, err)
}
content := string(data)
normalizedPath := filepath.ToSlash(path)
requiredSnippets := []string{
`type=system-containers`,
`type=app-containers`,
}
for _, snippet := range requiredSnippets {
if !strings.Contains(content, snippet) {
t.Errorf("%s: missing required canonical AI eval snippet %q", normalizedPath, snippet)
}
}
bannedSnippets := []string{
`type=containers`,
`type=docker`,
}
for _, snippet := range bannedSnippets {
if !strings.Contains(content, snippet) {
continue
}
t.Errorf("%s: banned legacy AI eval snippet %q", normalizedPath, snippet)
}
}
// TestV6AlertConfigAliasesStayStripped keeps alert-config compatibility tests
// pinned on dropping removed legacy resource-type aliases and host-era keys.
func TestV6AlertConfigAliasesStayStripped(t *testing.T) {
repoRoot := filepath.Join("..", "..")
path := filepath.Join(repoRoot, "internal", "alerts", "config_aliases_test.go")
data, err := os.ReadFile(path)
if err != nil {
t.Fatalf("failed to read %s: %v", path, err)
}
content := string(data)
normalizedPath := filepath.ToSlash(path)
requiredSnippets := []string{
`TestAlertConfigUnmarshal_LegacyHostAliasesIgnored`,
`expected legacy timeThresholds.host to be removed`,
`expected legacy timeThresholds.docker to be removed`,
`expected legacy timeThresholds.k8s to be removed`,
`expected legacy metricTimeThresholds.host to be removed`,
`expected legacy metricTimeThresholds.dockerhost to be removed`,
`expected legacy metricTimeThresholds.kubernetes-cluster to be removed`,
`TestAlertConfigUnmarshal_CanonicalKeysTakePrecedence`,
`did not expect legacy metricTimeThresholds.docker to remain`,
`TestAlertConfigMarshal_UsesCanonicalAgentKeys`,
`did not expect legacy hostDefaults in output`,
`did not expect legacy disableAllHosts in output`,
}
for _, snippet := range requiredSnippets {
if !strings.Contains(content, snippet) {
t.Errorf("%s: missing required alert-config alias stripping snippet %q", normalizedPath, snippet)
}
}
}
// TestV6BroadLegacyAliasCoverage keeps the broader removed alias set pinned in
// central API, AI, and alerts tests so coverage does not regress back to host-only.
func TestV6BroadLegacyAliasCoverage(t *testing.T) {
repoRoot := filepath.Join("..", "..")
artifacts := []struct {
path string
requiredSnippets []string
}{
{
path: filepath.Join(repoRoot, "internal", "api", "ai_handlers_test.go"),
requiredSnippets: []string{
`legacy guest rejected`,
`legacy docker rejected`,
`legacy container rejected`,
`legacy k8s alias rejected`,
},
},
{
path: filepath.Join(repoRoot, "internal", "ai", "alert_adapter_test.go"),
requiredSnippets: []string{
`vm qemu rejected`,
`system container lxc rejected`,
`legacy system_container alias rejected`,
`legacy docker_container alias rejected`,
`legacy docker_service alias rejected`,
`legacy kubernetes_cluster alias rejected`,
},
},
{
path: filepath.Join(repoRoot, "internal", "ai", "patrol_run_test.go"),
requiredSnippets: []string{
`expected legacy 'qemu' alias to be rejected`,
`expected legacy 'container' alias to be rejected`,
`expected legacy 'system_container' alias to be rejected`,
`expected legacy 'docker_container' alias to be rejected`,
`expected legacy 'kubernetes_cluster' alias to be rejected`,
`expected legacy 'app_container' alias to be rejected`,
},
},
{
path: filepath.Join(repoRoot, "internal", "ai", "tools", "tools_metrics_alerts_test.go"),
requiredSnippets: []string{
`expected error for legacy system_container resource_type`,
`expected error for legacy container resource_type`,
`expected error for legacy app_container resource_type`,
`expected error for legacy docker resource_type`,
},
},
{
path: filepath.Join(repoRoot, "internal", "alerts", "utility_test.go"),
requiredSnippets: []string{
`legacy host alias type key is dropped`,
`legacy docker alias type key is dropped`,
},
},
}
for _, artifact := range artifacts {
data, err := os.ReadFile(artifact.path)
if err != nil {
t.Fatalf("failed to read %s: %v", artifact.path, err)
}
content := string(data)
normalizedPath := filepath.ToSlash(artifact.path)
for _, snippet := range artifact.requiredSnippets {
if !strings.Contains(content, snippet) {
t.Errorf("%s: missing required broad legacy-alias coverage snippet %q", normalizedPath, snippet)
}
}
}
}
// TestV6ReleaseFacingAPITestsCoverLegacyHostRejection keeps release-facing API
// contract tests pinned on strict v6 behavior for removed host aliases.
func TestV6ReleaseFacingAPITestsCoverLegacyHostRejection(t *testing.T) {
repoRoot := filepath.Join("..", "..")
artifacts := []struct {
path string
requiredSnippets []string
}{
{
path: filepath.Join(repoRoot, "internal", "api", "ai_handler_test.go"),
requiredSnippets: []string{
`canonicalizeChatMentionType("host")`,
},
},
{
path: filepath.Join(repoRoot, "internal", "api", "ai_handlers_test.go"),
requiredSnippets: []string{
`"target_type":"host"`,
`unsupported resource_type "host"`,
},
},
{
path: filepath.Join(repoRoot, "internal", "api", "org_handlers_test.go"),
requiredSnippets: []string{
`"resourceType":"host"`,
},
},
{
path: filepath.Join(repoRoot, "internal", "api", "resourceapi", "resources_test.go"),
requiredSnippets: []string{
`/api/resources?type=host`,
`unsupported type filter token(s): host`,
},
},
{
path: filepath.Join(repoRoot, "internal", "api", "discovery_handlers_info_test.go"),
requiredSnippets: []string{
`/api/discovery/info/host`,
`unsupported resource type "host"`,
},
},
{
path: filepath.Join(repoRoot, "internal", "api", "discovery_handlers_test.go"),
requiredSnippets: []string{
`/api/discovery/type/host`,
`/api/discovery/host/host-1/host-1`,
`unsupported resource type "host"`,
},
},
{
path: filepath.Join(repoRoot, "internal", "api", "docker_agents_routes_more_test.go"),
requiredSnippets: []string{
`legacy hosts alias status = %d, want 400`,
},
},
{
path: filepath.Join(repoRoot, "internal", "api", "reporting_handlers_test.go"),
requiredSnippets: []string{
`/api/reporting?format=pdf&resourceType=host&resourceId=h-1`,
},
},
{
path: filepath.Join(repoRoot, "internal", "api", "router_version_tenant_metrics_test.go"),
requiredSnippets: []string{
`/api/metrics-store/history?resourceType=host&resourceId=agent-1&metric=cpu&range=1h`,
`unsupported resourceType "host"`,
},
},
}
for _, artifact := range artifacts {
data, err := os.ReadFile(artifact.path)
if err != nil {
t.Fatalf("failed to read %s: %v", artifact.path, err)
}
content := string(data)
normalizedPath := filepath.ToSlash(artifact.path)
for _, snippet := range artifact.requiredSnippets {
if !strings.Contains(content, snippet) {
t.Errorf("%s: missing required legacy-host rejection snippet %q", normalizedPath, snippet)
}
}
}
}
// TestV6DirectHostAliasValidatorCoverage keeps direct validator-level tests in
// place for the highest-risk host-alias rejection paths.
func TestV6DirectHostAliasValidatorCoverage(t *testing.T) {
repoRoot := filepath.Join("..", "..")
artifacts := []struct {
path string
requiredSnippets []string
}{
{
path: filepath.Join(repoRoot, "internal", "api", "ai_handlers_test.go"),
requiredSnippets: []string{
`TestNormalizeAndValidateAIExecuteTargetType_StrictCanonicalV6`,
`legacy host rejected", in: "host"`,
`TestNormalizeInvestigateAlertTargetType_StrictCanonicalV6`,
},
},
{
path: filepath.Join(repoRoot, "internal", "api", "org_handlers_test.go"),
requiredSnippets: []string{
`TestIsUnsupportedOrganizationShareResourceType`,
`host unsupported`,
},
},
{
path: filepath.Join(repoRoot, "internal", "api", "discovery_handlers_test.go"),
requiredSnippets: []string{
`TestParseDiscoveryResourceType_RejectsLegacyHostAlias`,
`legacy host rejected`,
},
},
{
path: filepath.Join(repoRoot, "internal", "ai", "resource_type_legacy_test.go"),
requiredSnippets: []string{
`TestIsUnsupportedLegacyAIResourceTypeToken`,
`legacy host rejected`,
},
},
{
path: filepath.Join(repoRoot, "internal", "ai", "tools", "tools_patrol_test.go"),
requiredSnippets: []string{
`TestHandlePatrolReportFinding_RejectsLegacyResourceTypeAliases`,
`TestHandlePatrolReportFinding_AcceptsPhysicalDiskResourceType`,
`"resource_type"] = "physical_disk"`,
`[]string{"host", "container", "docker"`,
},
},
{
path: filepath.Join(repoRoot, "internal", "ai", "tools", "tools_discovery_test.go"),
requiredSnippets: []string{
`TestIsUnsupportedDiscoveryLegacyResourceTypeToken`,
`"host", "lxc"`,
`TestExecuteListDiscoveries_RejectsLegacyTypeAlias`,
},
},
{
path: filepath.Join(repoRoot, "internal", "ai", "tools", "tools_query_test.go"),
requiredSnippets: []string{
`TestExecuteGetTopology_RejectsLegacyDockerIncludeAlias`,
`expected error for legacy include alias`,
`invalid include`,
`"type": "host"`,
`invalid type: host`,
`"resource_type": "host"`,
`invalid resource_type: host`,
`[]string{"lxc", "host"}`,
`TestExecuteGetGuestConfig_RejectsLegacyResourceTypes`,
},
},
{
path: filepath.Join(repoRoot, "internal", "ai", "alert_adapter_test.go"),
requiredSnippets: []string{
`with_metadata_host_legacy_ignored`,
`agent host alias rejected`,
`input: "host"`,
},
},
{
path: filepath.Join(repoRoot, "internal", "ai", "findings_resource_type_test.go"),
requiredSnippets: []string{
`{in: "host", want: ""}`,
`TestNormalizeFindingResourceTypes_RejectsLegacyAndInfers`,
},
},
{
path: filepath.Join(repoRoot, "internal", "ai", "patrol_triggers_test.go"),
requiredSnippets: []string{
`AnomalyDetectedPatrolScope("res-host", "host", "cpu", 95, 50)`,
},
},
{
path: filepath.Join(repoRoot, "internal", "ai", "patrol_run_test.go"),
requiredSnippets: []string{
`expected legacy 'host' alias to be rejected`,
`expected non-canonical 'docker' alias to be rejected`,
`expected non-canonical 'agent_raid' alias to be rejected`,
},
},
{
path: filepath.Join(repoRoot, "internal", "ai", "patrol_triage_test.go"),
requiredSnippets: []string{
`triageResourceType("host", "qemu/100")`,
},
},
{
path: filepath.Join(repoRoot, "internal", "ai", "adapters", "adapters_additional_test.go"),
requiredSnippets: []string{
`expected unsupported host resource ID to be rejected`,
`expected unsupported host query alias to be rejected`,
},
},
{
path: filepath.Join(repoRoot, "internal", "ai", "knowledge", "store_extended_test.go"),
requiredSnippets: []string{
`expected unsupported host guest ID to be rejected`,
`expected unsupported host guest ID query to be rejected`,
`expected unsupported host guest type to be rejected`,
`expected unsupported host file to remain unchanged`,
},
},
{
path: filepath.Join(repoRoot, "internal", "ai", "approval", "store_test.go"),
requiredSnippets: []string{
`expected unsupported host target type to be rejected`,
`expected error for unsupported host target type input`,
},
},
{
path: filepath.Join(repoRoot, "internal", "ai", "metadata_provider_test.go"),
requiredSnippets: []string{
`[]string{"host", "guest", "docker", "container", "lxc", "qemu", "docker_container", "docker_service"}`,
},
},
{
path: filepath.Join(repoRoot, "internal", "ai", "tools", "tools_metrics_alerts_test.go"),
requiredSnippets: []string{
`expected error for legacy host resource_type`,
},
},
{
path: filepath.Join(repoRoot, "internal", "ai", "tools", "tools_read_test.go"),
requiredSnippets: []string{
`TestPulseToolExecutor_ExecuteReadRejectsLegacyAppContainerArg`,
`app_container is no longer supported; use app-container`,
},
},
{
path: filepath.Join(repoRoot, "internal", "ai", "tools", "tools_file_test.go"),
requiredSnippets: []string{
`Legacy AppContainer Rejected`,
`app_container is no longer supported; use app-container`,
},
},
{
path: filepath.Join(repoRoot, "internal", "ai", "chat", "context_prefetch_additional_test.go"),
requiredSnippets: []string{
`expected legacy host mention to be ignored`,
},
},
{
path: filepath.Join(repoRoot, "internal", "alerts", "utility_test.go"),
requiredSnippets: []string{
`legacy host alias rejected`,
`legacy container alias rejected`,
`legacy docker alias rejected`,
`legacy k8s alias rejected`,
},
},
{
path: filepath.Join(repoRoot, "internal", "api", "resourceapi", "resources_test.go"),
requiredSnippets: []string{
`/api/resources?type=host`,
`unsupported type filter token(s): host`,
},
},
{
path: filepath.Join(repoRoot, "internal", "api", "resourceapi", "resources_frontend_types_test.go"),
requiredSnippets: []string{
`unsupported host ignored by parser`,
`TestUnsupportedResourceTypeFilterTokensRejectsLegacyAliases`,
},
},
{
path: filepath.Join(repoRoot, "internal", "api", "router_helpers_additional_test.go"),
requiredSnippets: []string{
`metadata legacy resource type ignored`,
`Metadata: map[string]interface{}{"resourceType": "host"}`,
},
},
{
path: filepath.Join(repoRoot, "internal", "api", "reporting_handlers_test.go"),
requiredSnippets: []string{
`TestNormalizeReportResourceType_RejectsLegacyAliases`,
`{"host", "container"}`,
},
},
{
path: filepath.Join(repoRoot, "internal", "api", "router_misc_additional_test.go"),
requiredSnippets: []string{
`TestNormalizeMetricsHistoryResourceType_RejectsLegacyAliases`,
`[]string{"host", "guest", "docker", "dockerhost", "dockercontainer", "system_container"}`,
},
},
}
for _, artifact := range artifacts {
data, err := os.ReadFile(artifact.path)
if err != nil {
t.Fatalf("failed to read %s: %v", artifact.path, err)
}
content := string(data)
normalizedPath := filepath.ToSlash(artifact.path)
for _, snippet := range artifact.requiredSnippets {
if !strings.Contains(content, snippet) {
t.Errorf("%s: missing required direct host-alias validator snippet %q", normalizedPath, snippet)
}
}
}
}
// SRC-04b: Ratchet-to-hard-ban conversion completed 2026-03-01.
//
// All state.* field access patterns and GetState() calls in consumer packages
// reached ceiling 0 through SRC-03a → SRC-04g migration work. They are now
// enforced as hard bans via migratedResourcePatterns above (per-file, per-line
// error reporting). The legacy ratchet infrastructure (legacyStateRatchet type,
// legacyStateRatchets slice, TestLegacyStateAccessRatchet) has been removed.
//
// Migration changelog preserved in git history (see commits SRC-03f → SRC-04g).
func TestResourceAPIHotPathUsesSharedPresentationSnapshot(t *testing.T) {
repoRoot := filepath.Join("..", "..")
path := filepath.Join(repoRoot, "internal", "api", "resourceapi", "resources.go")
data, err := os.ReadFile(path)
if err != nil {
t.Fatalf("failed to read %s: %v", path, err)
}
source := string(data)
normalizedPath := filepath.ToSlash(path)
if strings.Count(source, "sharedPresentationResources(orgID)") != 2 {
t.Fatalf("%s: expected HandleListResources and HandleStats to share the cached presentation snapshot for the registry generation", normalizedPath)
}
if !strings.Contains(source, "allResources := flatCopyResources(sharedResources)") {
t.Fatalf("%s: expected HandleListResources to copy the shared presentation slice before request-local decoration", normalizedPath)
}
if strings.Count(source, "computeResourceContractStats(allResources)") != 2 {
t.Fatalf("%s: expected canonical aggregations to reuse the shared presentation snapshot in both handlers", normalizedPath)
}
if strings.Contains(source, "allResources := registry.List()") {
t.Fatalf("%s: direct registry.List() hot-path aggregation detected", normalizedPath)
}
if strings.Contains(source, "computeResourceContractByType(registry.List())") {
t.Fatalf("%s: duplicate registry.List() hot-path aggregation detected", normalizedPath)
}
}
func TestCanonicalResourceOrderingContractsStayShared(t *testing.T) {
repoRoot := filepath.Join("..", "..")
resourcesPath := filepath.Join(repoRoot, "internal", "api", "resourceapi", "resources.go")
registryPath := filepath.Join(repoRoot, "internal", "unifiedresources", "registry.go")
resourcesSource, err := os.ReadFile(resourcesPath)
if err != nil {
t.Fatalf("failed to read %s: %v", resourcesPath, err)
}
registrySource, err := os.ReadFile(registryPath)
if err != nil {
t.Fatalf("failed to read %s: %v", registryPath, err)
}
if !strings.Contains(string(resourcesSource), "unified.CompareResourcesByCanonicalName") {
t.Fatalf("%s: /api/resources must route deterministic list ordering through unified.CompareResourcesByCanonicalName", filepath.ToSlash(resourcesPath))
}
if !strings.Contains(string(registrySource), "sortResourcesByName(out)") {
t.Fatalf("%s: ResourceRegistry.List() must normalize map iteration through sortResourcesByName(out)", filepath.ToSlash(registryPath))
}
if !strings.Contains(string(registrySource), "sortNamedResourceViewsByName(rr.cachedStorage)") {
t.Fatalf("%s: cached unified resource views must share the canonical deterministic name ordering helper", filepath.ToSlash(registryPath))
}
}
func TestBroadcastStateUsesSharedCanonicalResourceContract(t *testing.T) {
repoRoot := filepath.Join("..", "..")
typesPath := filepath.Join(repoRoot, "internal", "unifiedresources", "types.go")
resourcesPath := filepath.Join(repoRoot, "internal", "api", "resourceapi", "resources.go")
monitorPath := filepath.Join(repoRoot, "internal", "monitoring", "monitor.go")
typesSource, err := os.ReadFile(typesPath)
if err != nil {
t.Fatalf("failed to read %s: %v", typesPath, err)
}
resourcesSource, err := os.ReadFile(resourcesPath)
if err != nil {
t.Fatalf("failed to read %s: %v", resourcesPath, err)
}
monitorSource, err := os.ReadFile(monitorPath)
if err != nil {
t.Fatalf("failed to read %s: %v", monitorPath, err)
}
if !strings.Contains(string(typesSource), "func ContractResourceType(resource Resource) ResourceType {") {
t.Fatalf("%s: unified resource contract type helper must remain canonical", filepath.ToSlash(typesPath))
}
if !strings.Contains(string(resourcesSource), "return unified.ContractResourceType(r)") {
t.Fatalf("%s: /api/resources must derive external resource types from unified.ContractResourceType", filepath.ToSlash(resourcesPath))
}
requiredMonitorSnippets := []string{
"unifiedView := m.currentUnifiedStateView()",
"return string(unifiedresources.ContractResourceType(resource))",
"unifiedresources.ResourceDisplayName(resource)",
"unifiedresources.ResourceClusterName(resource)",
}
for _, snippet := range requiredMonitorSnippets {
if !strings.Contains(string(monitorSource), snippet) {
t.Fatalf("%s: websocket/state broadcast must contain %q", filepath.ToSlash(monitorPath), snippet)
}
}
}
func TestCloneHostSensorMetaKeepsGPUSensorsIsolated(t *testing.T) {
temperature := 63.0
utilization := 42.0
usedBytes := int64(4 * 1024 * 1024 * 1024)
totalBytes := int64(16 * 1024 * 1024 * 1024)
source := &HostSensorMeta{
GPU: []HostGPUSensor{
{
ID: "0",
Name: "NVIDIA RTX A6000",
TemperatureCelsius: &temperature,
UtilizationPercent: &utilization,
MemoryUsedBytes: &usedBytes,
MemoryTotalBytes: &totalBytes,
},
},
}
clone := cloneHostSensorMeta(source)
if clone == nil || len(clone.GPU) != 1 {
t.Fatalf("GPU clone = %+v, want one sensor", clone)
}
temperature = 10
utilization = 1
usedBytes = 1
totalBytes = 2
source.GPU[0].Name = "mutated"
gpu := clone.GPU[0]
if gpu.Name != "NVIDIA RTX A6000" {
t.Fatalf("GPU name clone = %q, want original name", gpu.Name)
}
if gpu.TemperatureCelsius == nil || *gpu.TemperatureCelsius != 63 {
t.Fatalf("GPU temperature clone = %#v, want 63", gpu.TemperatureCelsius)
}
if gpu.UtilizationPercent == nil || *gpu.UtilizationPercent != 42 {
t.Fatalf("GPU utilization clone = %#v, want 42", gpu.UtilizationPercent)
}
if gpu.MemoryUsedBytes == nil || *gpu.MemoryUsedBytes != int64(4*1024*1024*1024) {
t.Fatalf("GPU used memory clone = %#v, want 4 GiB", gpu.MemoryUsedBytes)
}
if gpu.MemoryTotalBytes == nil || *gpu.MemoryTotalBytes != int64(16*1024*1024*1024) {
t.Fatalf("GPU total memory clone = %#v, want 16 GiB", gpu.MemoryTotalBytes)
}
}
func TestCloneHostSensorMetaKeepsPowerSensorsIsolated(t *testing.T) {
source := &HostSensorMeta{
PowerWatts: map[string]float64{
"cpu_package": 82.4,
"dram": 13.2,
},
}
clone := cloneHostSensorMeta(source)
if clone == nil {
t.Fatal("expected host sensor clone")
}
source.PowerWatts["cpu_package"] = 1
if got := clone.PowerWatts["cpu_package"]; got != 82.4 {
t.Fatalf("power sensor clone = %.1f, want 82.4", got)
}
}
func TestCloneVMwareDataKeepsNestedRuntimeDetailsIsolated(t *testing.T) {
repoRoot := filepath.Join("..", "..")
clonePath := filepath.Join(repoRoot, "internal", "unifiedresources", "clone.go")
cloneSource, err := os.ReadFile(clonePath)
if err != nil {
t.Fatalf("failed to read %s: %v", clonePath, err)
}
source := string(cloneSource)
requiredSnippets := []string{
"out.SnapshotTree = cloneVMwareSnapshotDataSlice(in.SnapshotTree)",
"out.NetworkAdapters = cloneVMwareNetworkAdapterDataSlice(in.NetworkAdapters)",
"out.VirtualDisks = cloneVMwareVirtualDiskDataSlice(in.VirtualDisks)",
"out.ClusterHAEnabled = cloneBoolPtr(in.ClusterHAEnabled)",
"out.ClusterDRSEnabled = cloneBoolPtr(in.ClusterDRSEnabled)",
"out.NetworkHostNames = cloneStringSlice(in.NetworkHostNames)",
"out.NetworkVMNames = cloneStringSlice(in.NetworkVMNames)",
"out.Tools = cloneVMwareToolsData(in.Tools)",
"out.Hardware = cloneVMwareVMHardwareData(in.Hardware)",
"out[i].CreatedAt = cloneTimePtr(in[i].CreatedAt)",
"out[i].Children = cloneVMwareSnapshotDataSlice(in[i].Children)",
"out[i].PCISlotNumber = cloneInt64Ptr(in[i].PCISlotNumber)",
"out[i].CapacityBytes = cloneInt64Ptr(in[i].CapacityBytes)",
"out.GuestRebootComponents = cloneStringSlice(in.GuestRebootComponents)",
"out.BootDevices = cloneVMwareBootDeviceDataSlice(in.BootDevices)",
"out[i].Disks = cloneStringSlice(in[i].Disks)",
}
for _, snippet := range requiredSnippets {
if !strings.Contains(source, snippet) {
t.Fatalf("%s: VMware clone isolation must include %q", filepath.ToSlash(clonePath), snippet)
}
}
}
func TestGuestRRDPointCarriesOnlyRecordedGuestColumns(t *testing.T) {
// Issue #1634: GuestRRDPoint once declared memused/memavailable columns
// that real PVE guest rrddata responses never contain — they exist only
// in node RRD — so every consumer branch reading them was dead and guest
// memory silently fell through. The struct must not regrow columns that
// are absent from the recorded fixtures in pkg/proxmox/testdata/rrd/.
allowed := map[string]bool{"time": true, "maxmem": true}
typ := reflect.TypeOf(proxmox.GuestRRDPoint{})
for i := 0; i < typ.NumField(); i++ {
tag := typ.Field(i).Tag.Get("json")
if comma := strings.IndexByte(tag, ','); comma >= 0 {
tag = tag[:comma]
}
if !allowed[tag] {
t.Errorf("GuestRRDPoint field %s (json %q) is not a recorded guest rrddata column; add fixture evidence under pkg/proxmox/testdata/rrd before parsing it (#1634)", typ.Field(i).Name, tag)
}
}
}
// A per-tenant cache of SQLite resource stores must have a release path, and
// tenant teardown must use it.
//
// ResourceHandlers.getStore opens a handle per org and caches it for the
// process lifetime. Without an explicit release, offboarding a tenant leaves
// its handle, file descriptors, and -wal/-shm sidecars alive and its directory
// unremovable. This is a source-shape guard because the leak is invisible at
// runtime until a tenant is deleted or a data directory is torn down.
func TestCachedResourceStoresHaveATenantReleasePath(t *testing.T) {
resources, err := os.ReadFile("../api/resourceapi/resources.go")
if err != nil {
t.Fatalf("read resources.go: %v", err)
}
for _, fragment := range []string{
"func (h *QueryService) CloseTenantStore(orgID string) error",
"func (h *QueryService) CloseStores() error",
} {
if !strings.Contains(string(resources), fragment) {
t.Errorf("internal/api/resourceapi/resources.go must expose %q so cached per-tenant stores can be released", fragment)
}
}
router, err := os.ReadFile("../api/router.go")
if err != nil {
t.Fatalf("read router.go: %v", err)
}
if !strings.Contains(string(router), "r.resourceHandlers.CloseTenantStore(orgID)") {
t.Error("Router.CleanupTenant must release the offboarded tenant's resource store")
}
if !strings.Contains(string(router), "func (r *Router) ShutdownResourceStores()") {
t.Error("Router must expose ShutdownResourceStores so every cached store can be released on shutdown")
}
}