Files
pulse/internal/mutationregistry/runtime_surface_audit_test.go
T
2026-08-07 17:03:10 +01:00

268 lines
12 KiB
Go

package mutationregistry
import (
"fmt"
"os"
"path/filepath"
"regexp"
"sort"
"strings"
"testing"
)
type routeClassification struct {
MutationID string
}
var infrastructureRouteCatalog = map[string]routeClassification{
"POST /api/actions/plan": {MutationID: "action.api.plan"},
"POST /api/actions/{id}/refresh": {MutationID: "action.api.refresh"},
"GET /api/actions/pending": {},
"GET /api/actions": {},
"GET /api/actions/{id}": {},
"POST /api/actions/{id}/decision": {MutationID: "action.api.decision"},
"POST /api/actions/{id}/execute": {MutationID: "action.api.execute"},
"POST /api/actions/{id}/force-fail": {MutationID: "action.api.force-fail"},
"/api/agents/docker/report": {},
"/api/agents/docker/commands/": {},
"/api/agents/docker/runtimes/": {MutationID: "docker.api.runtime-stop"},
"/api/agents/docker/containers/update": {MutationID: "docker.api.update-container"},
"/api/updates/check": {},
"/api/updates/apply": {MutationID: "admin.pulse.self-update"},
"/api/updates/rollback": {MutationID: "admin.pulse.self-update"},
"/api/updates/status": {},
"/api/updates/stream": {},
"/api/updates/plan": {},
"/api/updates/history": {},
"/api/updates/history/entry": {},
"/api/updates/release-notes": {},
"/api/ai/run-command": {MutationID: "legacy.api.run-command"},
"/api/ai/remediation/plans": {},
"/api/ai/remediation/plan": {},
"/api/ai/remediation/approve": {MutationID: "legacy.enterprise.remediation-approve"},
"/api/ai/remediation/execute": {MutationID: "legacy.enterprise.remediation-execute"},
"/api/ai/remediation/rollback": {MutationID: "legacy.enterprise.remediation-rollback"},
}
// TestInfrastructureAPIRoutesResolveToRegistry scans the real router sources,
// not a duplicate ID inventory. Its scope is deliberately limited to the
// infrastructure mutation namespaces below; settings/metadata CRUD is outside
// M1 and is not claimed as infrastructure enumeration.
func TestInfrastructureAPIRoutesResolveToRegistry(t *testing.T) {
root := repoRoot(t)
files := []string{
"internal/api/router_routes_monitoring.go",
"internal/api/router_routes_registration.go",
"internal/api/router_routes_ai_relay.go",
}
routeRE := regexp.MustCompile(`"(?:(GET|POST|PUT|DELETE) )?(/api/[^"]+)"`)
found := map[string]bool{}
for _, relative := range files {
data, err := os.ReadFile(filepath.Join(root, relative))
if err != nil {
t.Fatal(err)
}
for _, match := range routeRE.FindAllStringSubmatch(string(data), -1) {
method, route := match[1], match[2]
if !auditedInfrastructurePrefix(route) {
continue
}
key := routeCatalogKey(method, route)
found[key] = true
classification, classified := infrastructureRouteCatalog[key]
if !classified {
t.Errorf("runtime infrastructure route %q is unclassified", key)
continue
}
if classification.MutationID != "" {
if err := AuditRuntimeCandidates([]RuntimeCandidate{{Surface: "http:" + key, MutationID: classification.MutationID}}); err != nil {
t.Error(err)
}
}
}
}
for key := range infrastructureRouteCatalog {
if !found[key] {
t.Errorf("classified route %q is no longer registered", key)
}
}
// The shared Docker gateway contains a second mutation sub-route.
dockerSource, _ := os.ReadFile(filepath.Join(root, "internal/api/docker_agents.go"))
if !strings.Contains(string(dockerSource), `"/update-all"`) {
t.Fatal("Docker update-all handler candidate not found")
}
if err := AuditRuntimeCandidates([]RuntimeCandidate{{Surface: "http:/api/agents/docker/runtimes/#update-all", MutationID: "docker.api.update-all"}}); err != nil {
t.Fatal(err)
}
}
func routeCatalogKey(method, route string) string {
if strings.TrimSpace(method) == "" {
return route
}
return method + " " + route
}
func auditedInfrastructurePrefix(route string) bool {
if route == "/api/actions" {
return true
}
for _, prefix := range []string{"/api/actions/", "/api/agents/docker/", "/api/updates/", "/api/ai/remediation/", "/api/ai/run-command"} {
if strings.HasPrefix(route, prefix) {
return true
}
}
return false
}
func TestActionRouteMethodAuthorityIsExactAndLookalikesFailClosed(t *testing.T) {
tests := []struct {
method, route, mutationID string
classified bool
}{
{method: "GET", route: "/api/actions/{id}", classified: true},
{method: "POST", route: "/api/actions/{id}/execute", mutationID: "action.api.execute", classified: true},
{method: "DELETE", route: "/api/actions/{id}"},
{method: "POST", route: "/api/actions/{id}"},
{method: "GET", route: "/api/actions/{id}/execute"},
{method: "POST", route: "/api/actions/{id}/execute-copy"},
}
for _, tt := range tests {
key := routeCatalogKey(tt.method, tt.route)
classification, ok := infrastructureRouteCatalog[key]
if ok != tt.classified {
t.Errorf("route %q classified=%v, want %v", key, ok, tt.classified)
continue
}
if ok && classification.MutationID != tt.mutationID {
t.Errorf("route %q mutation=%q, want %q", key, classification.MutationID, tt.mutationID)
}
}
}
type transportClassification struct {
Role TransportRole
MutationID string
DurableAuthorityID string
}
func TestTransportCommandCatalogsResolveToRegistry(t *testing.T) {
root := repoRoot(t)
docker := scanNamedStringConstants(t, filepath.Join(root, "internal/monitoring/docker_commands.go"), `DockerCommandType\w+`)
dockerCatalog := map[string]transportClassification{
"DockerCommandTypeStop": {Role: TransportRoleMutationRequest, MutationID: "transport.docker.runtime-stop"},
"DockerCommandTypeUpdateContainer": {Role: TransportRoleMutationRequest, MutationID: "transport.docker.update-container"},
"DockerCommandTypeUpdateAll": {Role: TransportRoleMutationRequest, MutationID: "transport.docker.update-all"},
"DockerCommandTypeCheckUpdates": {Role: TransportRoleProtocol},
}
auditConstantCatalog(t, docker, dockerCatalog)
agent := scanNamedStringConstants(t, filepath.Join(root, "internal/agentexec/types.go"), `MsgType\w+`)
agentCatalog := map[string]transportClassification{
"MsgTypeAgentRegister": {Role: TransportRoleProtocol}, "MsgTypeAgentPing": {Role: TransportRoleProtocol},
"MsgTypeCommandResult": {Role: TransportRoleOperationResult},
"MsgTypeHostStorageCleanupResult": {Role: TransportRoleOperationResult}, "MsgTypeHostUpdateResult": {Role: TransportRoleOperationResult},
"MsgTypeDockerContainerLifecycleResult": {Role: TransportRoleOperationResult},
"MsgTypeDockerContainerUpdateResult": {Role: TransportRoleOperationResult},
"MsgTypeOperationQueryResult": {Role: TransportRoleOperationReceipt},
"MsgTypeRegistered": {Role: TransportRoleProtocol}, "MsgTypePong": {Role: TransportRoleProtocol},
"MsgTypeExecuteCmd": {Role: TransportRoleMutationRequest, MutationID: "transport.agent.raw-command", DurableAuthorityID: "assistant.resource-action"},
"MsgTypeHostStorageCleanup": {Role: TransportRoleMutationRequest, MutationID: "transport.agent.host-package-cache-cleanup", DurableAuthorityID: "resource.host.package-cache-cleanup"},
"MsgTypeReadFile": {Role: TransportRoleProtocol},
"MsgTypeHostUpdate": {Role: TransportRoleMutationRequest, MutationID: "transport.agent.host-package-update", DurableAuthorityID: "resource.host.package-update"},
"MsgTypeDockerContainerLifecycle": {Role: TransportRoleMutationRequest, MutationID: "transport.agent.docker-container-lifecycle", DurableAuthorityID: "resource.docker.container-lifecycle"},
"MsgTypeDockerContainerUpdate": {Role: TransportRoleMutationRequest, MutationID: "transport.agent.docker-container-update", DurableAuthorityID: "resource.docker.container-update"},
"MsgTypeOperationQuery": {Role: TransportRoleOperationQuery},
"MsgTypeDeployPreflight": {Role: TransportRoleAdministrativeRequest, MutationID: "transport.agent.deploy-preflight"},
"MsgTypeDeployInstall": {Role: TransportRoleAdministrativeRequest, MutationID: "transport.agent.deploy-install"},
"MsgTypeDeployCancelJob": {Role: TransportRoleAdministrativeRequest, MutationID: "transport.agent.deploy-cancel"},
"MsgTypeDeployProgress": {Role: TransportRoleOperationResult},
}
auditConstantCatalog(t, agent, agentCatalog)
}
func TestNonAdmittingTransportMessagesCannotCarryDispatchAuthority(t *testing.T) {
for _, role := range []TransportRole{TransportRoleOperationQuery, TransportRoleOperationResult, TransportRoleOperationReceipt, TransportRoleProtocol} {
err := AuditTransportSurfaces([]TransportSurface{{
Name: "lookalike", WireValue: "docker_container_lifecycle_result_retry", Role: role,
MutationID: "transport.agent.docker-container-lifecycle", DurableAuthorityID: "resource.docker.container-lifecycle",
}})
if err == nil {
t.Errorf("non-admitting role %q accepted dispatch authority", role)
}
}
}
func TestUnknownTransportLookalikeFailsClosed(t *testing.T) {
actual := map[string]string{"MsgTypeDockerContainerLifecycle": "docker_container_lifecycle", "MsgTypeDockerContainerLifecycleRetry": "docker_container_lifecycle_retry"}
catalog := map[string]transportClassification{
"MsgTypeDockerContainerLifecycle": {Role: TransportRoleMutationRequest, MutationID: "transport.agent.docker-container-lifecycle", DurableAuthorityID: "resource.docker.container-lifecycle"},
}
if unknown := unclassifiedTransportConstants(actual, catalog); len(unknown) != 1 || unknown[0] != `MsgTypeDockerContainerLifecycleRetry="docker_container_lifecycle_retry"` {
t.Fatalf("unknown lookalike classification = %v", unknown)
}
}
func TestPatrolJobRegistrationResolvesToRegistry(t *testing.T) {
root := repoRoot(t)
router, _ := os.ReadFile(filepath.Join(root, "internal/api/router.go"))
broker, _ := os.ReadFile(filepath.Join(root, "internal/api/patrol_action_broker.go"))
if !strings.Contains(string(router), "SetActionBrokerFactory") || !strings.Contains(string(broker), "PlanWithOptions") {
t.Fatal("Patrol action job registration is no longer mechanically discoverable")
}
if err := AuditRuntimeCandidates([]RuntimeCandidate{{Surface: "job:patrol-action-broker", MutationID: "patrol.typed-action"}}); err != nil {
t.Fatal(err)
}
}
func scanNamedStringConstants(t *testing.T, path, namePattern string) map[string]string {
t.Helper()
data, err := os.ReadFile(path)
if err != nil {
t.Fatal(err)
}
re := regexp.MustCompile(`(?m)^\s*(` + namePattern + `)(?:\s+\w+)?\s*=\s*"([^"]+)"`)
out := map[string]string{}
for _, match := range re.FindAllStringSubmatch(string(data), -1) {
out[match[1]] = match[2]
}
return out
}
func auditConstantCatalog(t *testing.T, actual map[string]string, catalog map[string]transportClassification) {
t.Helper()
var surfaces []TransportSurface
for name, value := range actual {
classification, ok := catalog[name]
if !ok {
t.Errorf("transport command %s=%q is unclassified", name, value)
continue
}
surfaces = append(surfaces, TransportSurface{Name: name, WireValue: value, Role: classification.Role, MutationID: classification.MutationID, DurableAuthorityID: classification.DurableAuthorityID})
}
if err := AuditTransportSurfaces(surfaces); err != nil {
t.Error(err)
}
var stale []string
for name := range catalog {
if _, ok := actual[name]; !ok {
stale = append(stale, name)
}
}
sort.Strings(stale)
if len(stale) > 0 {
t.Errorf("classified transport constants no longer exist: %v", stale)
}
}
func unclassifiedTransportConstants(actual map[string]string, catalog map[string]transportClassification) []string {
var unknown []string
for name, value := range actual {
if _, ok := catalog[name]; !ok {
unknown = append(unknown, fmt.Sprintf(`%s=%q`, name, value))
}
}
sort.Strings(unknown)
return unknown
}