Pulse/internal/unifiedresources/code_standards_test.go

1808 lines
64 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 (
"os"
"path/filepath"
"reflect"
"regexp"
"strings"
"testing"
)
// 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 TestAPIResourcesKeepsOwnedSupplementalGapFillAndVMwareAlias(t *testing.T) {
data, err := os.ReadFile(filepath.Join("..", "api", "resources.go"))
if err != nil {
t.Fatalf("failed to read ../api/resources.go: %v", err)
}
source := string(data)
requiredSnippets := []string{
"seedSources := unifiedSeedSources(seed.resources)",
"!sourceOwnedBySupplementalProvider(source, ownedSources) || unifiedSeedIncludesSource(seedSources, source)",
`case "vmware", "vmware-vsphere":`,
}
for _, snippet := range requiredSnippets {
if !strings.Contains(source, snippet) {
t.Fatalf("../api/resources.go must contain %q", snippet)
}
}
}
func TestResourceAPIUsesCanonicalTenantUnifiedSeed(t *testing.T) {
data, err := os.ReadFile(filepath.Join("..", "api", "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/resources.go must not fall back to tenant StateSnapshot seeding")
}
if !strings.Contains(source, "UnifiedResourceSnapshotForTenant(orgID)") {
t.Fatalf("internal/api/resources.go must use tenant unified resource snapshots as the canonical seed")
}
}
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 TestResourceAPIExposesDedicatedFacetReads(t *testing.T) {
data, err := os.ReadFile(filepath.Join("..", "api", "resources.go"))
if err != nil {
t.Fatalf("failed to read resources.go: %v", err)
}
source := string(data)
requiredSnippets := []string{
"HandleGetResourceFacets",
"HandleGetResourceTimeline",
"unified.ParseResourceChangeFilters(r.URL.Query()[\"kind\"], r.URL.Query()[\"sourceType\"], r.URL.Query()[\"sourceAdapter\"])",
"GetRecentChangesFiltered(resourceID, since, limit, filters)",
"CountRecentChangesFiltered(resourceID, since, filters)",
"CountRecentChangesByKindFiltered(resourceID, since, filters)",
"CountRecentChangesBySourceTypeFiltered(resourceID, since, filters)",
"sourceAdapter",
"strings.HasSuffix(r.URL.Path, \"/facets\")",
"strings.HasSuffix(r.URL.Path, \"/timeline\")",
}
for _, snippet := range requiredSnippets {
if !strings.Contains(source, snippet) {
t.Fatalf("internal/api/resources.go must expose canonical facet read snippet %q", 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", "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", "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.ResourceDisplayName(",
"unifiedresources.ResourceClusterName(",
"unifiedresources.ResourceIPSummary(",
},
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",
"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",
},
filepath.Join("..", "ai", "intelligence.go"): {
"unifiedresources.PolicyPostureSummary",
"unifiedresources.SummarizePolicyPosture(",
},
filepath.Join("..", "ai", "resource_context.go"): {
"unifiedresources.SummarizePolicyPosture(allResources)",
},
}
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)",
"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 !reflect.DeepEqual(before.Relationships, after.Relationships) {",
"changed = append(changed, \"relationships\")",
"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 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 {",
}
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\"`",
}
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)
}
}
// 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
bannedPatterns []*regexp.Regexp
}{
{
path: filepath.Join(
repoRoot,
"tests",
"integration",
"tests",
"journeys",
"04-agent-install-registration.spec.ts",
),
requiredSnippets: []string{
"state.resources",
"type: '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.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", "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`,
`host target type rejected`,
},
},
{
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", "incident_coordinator_additional_test.go"),
requiredSnippets: []string{
`TestIncidentCoordinator_OnAnomalyDetected_CanonicalizesLegacyHostAlias`,
`expected anomaly recording resource type to be canonicalized to agent`,
},
},
{
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", "metrics", "incident_recorder_test.go"),
requiredSnippets: []string{
`TestStartRecordingCanonicalizesLegacyHostAlias`,
`expected legacy host alias to canonicalize to agent`,
},
},
{
path: filepath.Join(repoRoot, "internal", "api", "resources_test.go"),
requiredSnippets: []string{
`/api/resources?type=host`,
`unsupported type filter token(s): host`,
},
},
{
path: filepath.Join(repoRoot, "internal", "api", "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 TestResourceAPIHotPathUsesSingleRegistryListSnapshot(t *testing.T) {
repoRoot := filepath.Join("..", "..")
path := filepath.Join(repoRoot, "internal", "api", "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, "allResources := registry.List()") != 2 {
t.Fatalf("%s: expected HandleListResources and HandleStats to each seed exactly one registry list snapshot", normalizedPath)
}
if strings.Count(source, "computeResourceContractByType(allResources)") != 2 {
t.Fatalf("%s: expected canonical by-type aggregations to reuse the seeded registry snapshot in both handlers", 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", "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", "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)
}
}
}