package client import ( "sync" "crypto-miner-agent/deploy" "crypto-miner-agent/vulnprobe" ) var ( vulnScanMu sync.RWMutex lastVulnReport *vulnprobe.ScanReport ) func listeningPortMap(lp *ListenPortsReport) map[int]bool { m := make(map[int]bool) if lp == nil { return m } for _, p := range lp.Ports { m[p.Port] = true } return m } // vulnprobeProbeHost is overridden in tests to inject mocked probe output. var vulnprobeProbeHost = func(ports map[int]bool, osVersion string) vulnprobe.HostContext { return vulnprobe.ProbeHost(ports, osVersion) } // RunVulnLOTLProbe executes read-only LOTL vulnerability recon (authorized assessment). func RunVulnLOTLProbe() *vulnprobe.ScanReport { ports := collectListenPorts() ctx := vulnprobeProbeHost(listeningPortMap(ports), deploy.HostOSVersion()) if patch := collectPatchStatus(); patch != nil { if patch.LastPatchDays != nil { ctx.LastPatchDays = *patch.LastPatchDays } if patch.LastPatch != nil { ctx.LastPatch = *patch.LastPatch } } report := vulnprobe.Run(ctx) vulnScanMu.Lock() lastVulnReport = report vulnScanMu.Unlock() return report } // LastVulnScan returns the most recent cached vulnerability report. func LastVulnScan() *vulnprobe.ScanReport { vulnScanMu.RLock() defer vulnScanMu.RUnlock() if lastVulnReport == nil { return nil } dup := *lastVulnReport dup.Findings = append([]vulnprobe.VulnFinding(nil), lastVulnReport.Findings...) return &dup }