mirror of
https://github.com/Vyntral/god-eye.git
synced 2026-06-04 05:18:05 +02:00
3a4c230aa7
Complete architectural overhaul. Replaces the v0.1 monolithic scanner with an event-driven pipeline of auto-registered modules. Foundation (internal/): - eventbus: typed pub/sub, 20 event types, race-safe, drop counter - module: registry with phase-based selection - store: thread-safe host store with per-host locks + deep-copy reads - pipeline: coordinator with phase barriers + panic recovery - config: 5 scan profiles + 3 AI tiers + YAML loader + auto-discovery Modules (26 auto-registered across 6 phases): - Discovery: passive (26 sources), bruteforce, recursive, AXFR, GitHub dorks, CT streaming, permutation, reverse DNS, vhost, ASN, supply chain (npm + PyPI) - Enrichment: HTTP probe + tech fingerprint + TLS appliance ID, ports - Analysis: security checks, takeover (110+ sigs), cloud, JavaScript, GraphQL, JWT, headers (OWASP), HTTP smuggling, AI cascade, Nuclei - Reporting: TXT/JSON/CSV writer + AI scan brief AI layer (internal/ai/ + internal/modules/ai/): - Three profiles: lean (16 GB), balanced (32 GB MoE), heavy (64 GB) - Six event-driven handlers: CVE, JS file, HTTP response, secret filter, multi-agent vuln enrichment, anomaly + executive report - Content-hash cache dedups Ollama calls across hosts - Auto-pull of missing models via /api/pull with streaming progress - End-of-scan AI SCAN BRIEF in terminal with top chains + next actions Nuclei compat layer (internal/nucleitpl/): - Executes ~13k community templates (HTTP subset) - Auto-download of nuclei-templates ZIP to ~/.god-eye/nuclei-templates - Scope filter rejects off-host templates (eliminates OSINT FPs) Operations: - Interactive wizard (internal/wizard/) — zero-flag launch - LivePrinter (internal/tui/) — colorized event stream - Diff engine + scheduler (internal/diff, internal/scheduler) for continuous ASM monitoring with webhook alerts - Proxy support (internal/proxyconf/): http / https / socks5 / socks5h + basic auth Fixes #1 — native SOCKS5 / Tor compatibility via --proxy flag. 185 unit tests across 15 packages, all race-detector clean.
99 lines
2.6 KiB
Go
99 lines
2.6 KiB
Go
package config
|
|
|
|
import "testing"
|
|
|
|
func TestAIProfileByName(t *testing.T) {
|
|
cases := []struct {
|
|
in string
|
|
wantOK bool
|
|
wantTag string
|
|
}{
|
|
{"lean", true, "qwen3:1.7b"},
|
|
{"LEAN", true, "qwen3:1.7b"},
|
|
{"balanced", true, "qwen3:4b"},
|
|
{"balance", true, "qwen3:4b"},
|
|
{"mid", true, "qwen3:4b"},
|
|
{"heavy", true, "qwen3:8b"},
|
|
{"max", true, "qwen3:8b"},
|
|
{"power", true, "qwen3:8b"},
|
|
{"Heavy", true, "qwen3:8b"},
|
|
{"nope", false, ""},
|
|
{"", false, ""},
|
|
}
|
|
for _, c := range cases {
|
|
p, ok := AIProfileByName(c.in)
|
|
if ok != c.wantOK {
|
|
t.Errorf("AIProfileByName(%q) ok = %v, want %v", c.in, ok, c.wantOK)
|
|
continue
|
|
}
|
|
if ok && p.FastModel != c.wantTag {
|
|
t.Errorf("AIProfileByName(%q).FastModel = %q, want %q", c.in, p.FastModel, c.wantTag)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestBuiltinAIProfiles_Unique(t *testing.T) {
|
|
names := map[string]bool{}
|
|
for _, p := range BuiltinAIProfiles {
|
|
if p.Name == "" {
|
|
t.Error("profile with empty name")
|
|
}
|
|
if p.FastModel == "" || p.DeepModel == "" {
|
|
t.Errorf("profile %q missing models", p.Name)
|
|
}
|
|
if p.Description == "" {
|
|
t.Errorf("profile %q missing description", p.Name)
|
|
}
|
|
if names[p.Name] {
|
|
t.Errorf("duplicate profile name: %q", p.Name)
|
|
}
|
|
names[p.Name] = true
|
|
}
|
|
}
|
|
|
|
func TestApplyAIProfile_RespectsOverrides(t *testing.T) {
|
|
cfg := &Config{
|
|
AIFastModel: "user-chose-this:1b",
|
|
AIDeepModel: "user-chose-that:7b",
|
|
}
|
|
ApplyAIProfile(cfg, AIProfileHeavy, true, true)
|
|
if cfg.AIFastModel != "user-chose-this:1b" {
|
|
t.Errorf("overrideFast was ignored: %q", cfg.AIFastModel)
|
|
}
|
|
if cfg.AIDeepModel != "user-chose-that:7b" {
|
|
t.Errorf("overrideDeep was ignored: %q", cfg.AIDeepModel)
|
|
}
|
|
if cfg.AIProfile != "heavy" {
|
|
t.Errorf("AIProfile not set to heavy, got %q", cfg.AIProfile)
|
|
}
|
|
}
|
|
|
|
func TestApplyAIProfile_FillsUnsetFields(t *testing.T) {
|
|
cfg := &Config{}
|
|
ApplyAIProfile(cfg, AIProfileBalanced, false, false)
|
|
if cfg.AIFastModel != "qwen3:4b" {
|
|
t.Errorf("FastModel not applied: %q", cfg.AIFastModel)
|
|
}
|
|
if cfg.AIDeepModel != "qwen3-coder:30b" {
|
|
t.Errorf("DeepModel not applied: %q", cfg.AIDeepModel)
|
|
}
|
|
if cfg.AIProfile != "balanced" {
|
|
t.Errorf("AIProfile not set: %q", cfg.AIProfile)
|
|
}
|
|
}
|
|
|
|
func TestApplyAIProfile_NilConfigNoop(t *testing.T) {
|
|
ApplyAIProfile(nil, AIProfileLean, false, false) // must not panic
|
|
}
|
|
|
|
func TestApplyAIProfile_PartialOverride(t *testing.T) {
|
|
cfg := &Config{AIFastModel: "custom:1b"}
|
|
ApplyAIProfile(cfg, AIProfileHeavy, true, false)
|
|
if cfg.AIFastModel != "custom:1b" {
|
|
t.Errorf("FastModel overridden: %q", cfg.AIFastModel)
|
|
}
|
|
if cfg.AIDeepModel != "qwen3-coder:30b" {
|
|
t.Errorf("DeepModel not applied: %q", cfg.AIDeepModel)
|
|
}
|
|
}
|