Files
Vyntral 3a4c230aa7 feat: v2.0 full rewrite — event-driven pipeline, AI + Nuclei + proxy
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.
2026-04-18 16:48:41 +02:00

152 lines
3.6 KiB
Go

package config
// View implements module.ConfigView over a *Config. Modules receive a View
// (not the raw Config pointer) to prevent them from mutating global scan
// state — reads only.
//
// The implementation is intentionally small: it exposes just the shape
// needed by the module package without pulling in a full generic key/value
// store. Module-specific settings live in ModuleSettings; typed options
// should be hoisted to first-class fields on Config when they are used
// across modules.
type View struct {
cfg *Config
}
// NewView wraps cfg as a ConfigView. cfg may be nil, in which case every
// accessor returns the fallback/zero value.
func NewView(cfg *Config) *View { return &View{cfg: cfg} }
// Profile returns the active profile name ("" when none).
func (v *View) Profile() string {
if v == nil || v.cfg == nil {
return ""
}
return v.cfg.Profile
}
// Bool reads a boolean config key by well-known name. Unknown keys return fb.
// Keys intentionally kept flat to avoid accidental namespacing bugs.
func (v *View) Bool(key string, fb bool) bool {
if v == nil || v.cfg == nil {
return fb
}
switch key {
case "ai.enabled":
return v.cfg.EnableAI
case "ai.cascade":
return v.cfg.AICascade
case "ai.deep":
return v.cfg.AIDeepAnalysis
case "ai.multi_agent":
return v.cfg.MultiAgent
case "ai.verbose":
return v.cfg.AIVerbose
case "ai.auto_pull":
return v.cfg.AutoPullModels
case "silent":
return v.cfg.Silent
case "verbose":
return v.cfg.Verbose
case "json":
return v.cfg.JsonOutput
case "no_brute":
return v.cfg.NoBrute
case "no_probe":
return v.cfg.NoProbe
case "no_ports":
return v.cfg.NoPorts
case "no_takeover":
return v.cfg.NoTakeover
case "only_active":
return v.cfg.OnlyActive
case "recursive":
return v.cfg.Recursive
case "cloud_scan":
return v.cfg.CloudScan
case "api_scan":
return v.cfg.APIScan
case "secrets_scan":
return v.cfg.SecretsScan
case "tech_scan":
return v.cfg.TechScan
case "asn_scan":
return v.cfg.ASNScan
case "vhost_scan":
return v.cfg.VHostScan
case "nuclei_scan":
return v.cfg.NucleiScan
case "nuclei_auto_download":
return v.cfg.NucleiAutoDownload
}
return fb
}
// Int reads an int key.
func (v *View) Int(key string, fb int) int {
if v == nil || v.cfg == nil {
return fb
}
switch key {
case "concurrency":
return v.cfg.Concurrency
case "timeout":
return v.cfg.Timeout
case "recursive.depth":
return v.cfg.RecursiveDepth
}
return fb
}
// String reads a string key.
func (v *View) String(key string, fb string) string {
if v == nil || v.cfg == nil {
return fb
}
switch key {
case "domain":
return v.cfg.Domain
case "wordlist":
return v.cfg.Wordlist
case "output":
return v.cfg.Output
case "format":
return v.cfg.Format
case "ports":
return v.cfg.Ports
case "resolvers":
return v.cfg.Resolvers
case "stealth":
return v.cfg.StealthMode
case "ai.url":
return v.cfg.AIUrl
case "ai.fast_model":
return v.cfg.AIFastModel
case "ai.deep_model":
return v.cfg.AIDeepModel
case "nuclei_templates":
return v.cfg.NucleiTemplates
}
return fb
}
// Strings reads a string-slice key. No multi-value keys are defined yet,
// but reserved for module-specific settings loaded from YAML.
func (v *View) Strings(key string) []string {
_ = key
return nil
}
// ModuleEnabled returns true when the config explicitly enabled the module
// by name (via ModuleSettings). It returns false otherwise; callers should
// fall back to the module's DefaultEnabled() when this returns false.
func (v *View) ModuleEnabled(name string) bool {
if v == nil || v.cfg == nil {
return false
}
if v.cfg.ModuleSettings == nil {
return false
}
return v.cfg.ModuleSettings[name]
}