From f18fb88cdcd59e245a3aaf96d5dc3cef57f195d5 Mon Sep 17 00:00:00 2001 From: rcourtman Date: Sun, 7 Jun 2026 20:54:46 +0100 Subject: [PATCH] Make discovery a fast surface scan, not a deep scan MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Discovery is the index, not the encyclopedia: it needs to quickly answer 'what is this and how do I reach it', then the Assistant supplies standard-service knowledge and runs commands on demand for specifics. Trim the guest command sets to surface identity signals only (OS, hostname, running services, listening ports, top processes for LXC/VM; OS, processes, ports, env for Docker). Drop the deep enumeration — installed_packages, config_files, docker_mounts, hardware/GPU, disk, cron, nested docker_check — which bloated the evidence payload (and the AI analysis) for no benefit the Assistant can't get live. Remove the now-unused dockerMountsCommand const and retire its test; add TestGuestCommandSetsAreSurfaceOnly to pin the surface intent (verified live: HA LXC went from 13 commands to 5). Note: full speed also needs a fast identification path (the configured reasoning model still exceeds the 45s analysis timeout on its own) — that's the follow-up. --- internal/servicediscovery/commands.go | 114 +++------------------ internal/servicediscovery/commands_test.go | 48 +++++---- 2 files changed, 35 insertions(+), 127 deletions(-) diff --git a/internal/servicediscovery/commands.go b/internal/servicediscovery/commands.go index 781fca2e5..51053808c 100644 --- a/internal/servicediscovery/commands.go +++ b/internal/servicediscovery/commands.go @@ -43,10 +43,6 @@ type DiscoveryCommand struct { Optional bool `json:"optional"` // If true, don't fail if command fails } -// dockerMountsCommand collects Docker mount metadata without relying on extra -// text utilities (sed/grep), which may be missing in minimal guest images. -const dockerMountsCommand = `sh -c 'docker ps -q 2>/dev/null | head -15 | while read -r id; do name=$(docker inspect --format "{{.Name}}" "$id" 2>/dev/null); name=${name#/}; [ -n "$name" ] || name="$id"; echo "CONTAINER:$name"; docker inspect --format "{{range .Mounts}}{{.Source}}|{{.Destination}}|{{.Type}}{{println}}{{end}}" "$id" 2>/dev/null || true; done; echo docker_mounts_done'` - // GetCommandsForResource returns the commands to run for a given resource type. func GetCommandsForResource(resourceType ResourceType) []DiscoveryCommand { switch resourceType { @@ -105,62 +101,12 @@ func getSystemContainerCommands() []DiscoveryCommand { Categories: []string{"service"}, Optional: true, }, - { - Name: "disk_usage", - Command: "df -h 2>/dev/null | head -15", - Description: "Disk usage and mount points", - Categories: []string{"storage"}, - Optional: true, - }, - { - Name: "docker_check", - Command: "docker ps --format '{{.Names}}: {{.Image}} ({{.Status}})' 2>/dev/null | head -20 || echo 'no_docker'", - Description: "Docker containers if running", - Categories: []string{"service", "container"}, - Optional: true, - }, - { - Name: "docker_mounts", - Command: dockerMountsCommand, - Description: "Docker container bind mounts (source -> destination)", - Categories: []string{"config", "storage"}, - Optional: true, - }, - { - Name: "installed_packages", - Command: "dpkg -l 2>/dev/null | grep -E '^ii' | awk '{print $2}' | head -50 || rpm -qa 2>/dev/null | head -50 || apk list --installed 2>/dev/null | head -50", - Description: "Installed packages", - Categories: []string{"version", "service"}, - Optional: true, - }, - { - Name: "config_files", - Command: "find /etc -name '*.conf' -o -name '*.yml' -o -name '*.yaml' -o -name '*.json' 2>/dev/null | head -30", - Description: "Configuration files", - Categories: []string{"config"}, - Optional: true, - }, - { - Name: "cron_jobs", - Command: "crontab -l 2>/dev/null | grep -v '^#' | head -10 || ls -la /etc/cron.d/ 2>/dev/null | head -10", - Description: "Scheduled jobs", - Categories: []string{"service"}, - Optional: true, - }, - { - Name: "hardware_info", - Command: "lspci 2>/dev/null | head -20 || echo 'no_lspci'", - Description: "Hardware devices (e.g., Coral TPU)", - Categories: []string{"hardware"}, - Optional: true, - }, - { - Name: "gpu_devices", - Command: "ls -la /dev/dri/ 2>/dev/null; ls -la /dev/apex* 2>/dev/null; nvidia-smi -L 2>/dev/null || echo 'no_gpu'", - Description: "GPU and TPU devices", - Categories: []string{"hardware"}, - Optional: true, - }, + // Surface discovery only: identity + how-to-reach. Deep enumeration + // (installed packages, config-file trees, hardware/GPU, bind mounts, + // disk, cron) is intentionally omitted — it bloats the evidence payload + // and slows AI analysis, and it re-derives what the Assistant already + // knows about standard services. Specifics are fetched on demand via + // agent commands when actually needed. See discovery-assistant-goal. } } @@ -202,41 +148,10 @@ func getVMCommands() []DiscoveryCommand { Categories: []string{"service"}, Optional: true, }, - { - Name: "disk_usage", - Command: "df -h 2>/dev/null | head -15", - Description: "Disk usage and mount points", - Categories: []string{"storage"}, - Optional: true, - }, - { - Name: "docker_check", - Command: "docker ps --format '{{.Names}}: {{.Image}} ({{.Status}})' 2>/dev/null | head -20 || echo 'no_docker'", - Description: "Docker containers if running", - Categories: []string{"service", "container"}, - Optional: true, - }, - { - Name: "docker_mounts", - Command: dockerMountsCommand, - Description: "Docker container bind mounts (source -> destination)", - Categories: []string{"config", "storage"}, - Optional: true, - }, - { - Name: "hardware_info", - Command: "lspci 2>/dev/null | head -20", - Description: "PCI hardware devices", - Categories: []string{"hardware"}, - Optional: true, - }, - { - Name: "gpu_devices", - Command: "ls -la /dev/dri/ 2>/dev/null; nvidia-smi -L 2>/dev/null || echo 'no_gpu'", - Description: "GPU devices", - Categories: []string{"hardware"}, - Optional: true, - }, + // Surface discovery only — identity + how-to-reach. Deep enumeration + // (disk, nested docker + bind mounts, hardware/GPU) is omitted and + // fetched on demand via agent commands when needed. See + // getSystemContainerCommands / discovery-assistant-goal. } } @@ -272,13 +187,8 @@ func getDockerCommands() []DiscoveryCommand { Categories: []string{"config"}, Optional: true, }, - { - Name: "config_files", - Command: "find /config /data /app /etc -maxdepth 2 -name '*.conf' -o -name '*.yml' -o -name '*.yaml' -o -name '*.json' 2>/dev/null | head -20", - Description: "Configuration files", - Categories: []string{"config"}, - Optional: true, - }, + // Surface discovery only — config-file enumeration omitted; the + // Assistant fetches specifics on demand. See discovery-assistant-goal. } } diff --git a/internal/servicediscovery/commands_test.go b/internal/servicediscovery/commands_test.go index 6742f16a0..d2e0bda54 100644 --- a/internal/servicediscovery/commands_test.go +++ b/internal/servicediscovery/commands_test.go @@ -80,33 +80,31 @@ func TestCommandsAndTemplates(t *testing.T) { } } -func TestDockerMountsCommandAvoidsExtraTextUtilities(t *testing.T) { - lxcCmds := GetCommandsForResource(ResourceTypeSystemContainer) - vmCmds := GetCommandsForResource(ResourceTypeVM) - - findByName := func(cmds []DiscoveryCommand, name string) string { - for _, cmd := range cmds { - if cmd.Name == name { - return cmd.Command +func TestGuestCommandSetsAreSurfaceOnly(t *testing.T) { + // Discovery is a fast surface index (identity + how-to-reach), not a deep + // scan. Guest command sets must stay light and must NOT include the deep + // enumeration commands — the Assistant knows standard service layouts and + // fetches specifics on demand. See discovery-assistant-goal. + deep := map[string]bool{ + "installed_packages": true, + "config_files": true, + "docker_mounts": true, + "hardware_info": true, + "gpu_devices": true, + "disk_usage": true, + "cron_jobs": true, + "docker_check": true, + } + for _, rt := range []ResourceType{ResourceTypeSystemContainer, ResourceTypeVM, ResourceTypeDocker} { + cmds := GetCommandsForResource(rt) + if len(cmds) == 0 || len(cmds) > 6 { + t.Errorf("%s surface command set should be small (1-6 commands), got %d", rt, len(cmds)) + } + for _, c := range cmds { + if deep[c.Name] { + t.Errorf("%s should not run deep command %q in a surface scan", rt, c.Name) } } - return "" - } - - lxcMounts := findByName(lxcCmds, "docker_mounts") - vmMounts := findByName(vmCmds, "docker_mounts") - - if lxcMounts == "" || vmMounts == "" { - t.Fatalf("expected docker_mounts command for both LXC and VM") - } - if lxcMounts != vmMounts { - t.Fatalf("expected shared docker_mounts command, got lxc=%q vm=%q", lxcMounts, vmMounts) - } - if strings.Contains(lxcMounts, "sed ") || strings.Contains(lxcMounts, "grep ") { - t.Fatalf("docker_mounts should not depend on sed/grep: %s", lxcMounts) - } - if !strings.Contains(lxcMounts, "name=${name#/}") { - t.Fatalf("expected shell-native container name trimming, got: %s", lxcMounts) } }