gomcp/internal/domain/soc/genai_monitor.go

140 lines
3.8 KiB
Go

package soc
// GenAI Process Monitoring & Detection
//
// Defines GenAI-specific process names, credential files, LLM DNS endpoints,
// and auto-response actions for GenAI EDR (SDD-001).
// GenAIProcessNames is the canonical list of GenAI IDE agent process names.
// Used by IMMUNE eBPF hooks and GoMCP SOC correlation rules.
var GenAIProcessNames = []string{
"claude",
"cursor",
"Cursor Helper",
"Cursor Helper (Plugin)",
"copilot",
"copilot-agent",
"windsurf",
"gemini",
"aider",
"continue",
"cline",
"codex",
"codex-cli",
}
// CredentialFiles is the list of sensitive files monitored for GenAI access.
// Access by a GenAI process or its descendants triggers CRITICAL alert.
var CredentialFiles = []string{
"credentials.db",
"Cookies",
"Login Data",
"logins.json",
"key3.db",
"key4.db",
"cert9.db",
".ssh/id_rsa",
".ssh/id_ed25519",
".aws/credentials",
".env",
".netrc",
}
// LLMDNSEndpoints is the list of known LLM API endpoints for DNS monitoring.
// Shield DNS monitor emits events when these domains are resolved.
var LLMDNSEndpoints = []string{
"api.anthropic.com",
"api.openai.com",
"chatgpt.com",
"claude.ai",
"generativelanguage.googleapis.com",
"gemini.googleapis.com",
"api.deepseek.com",
"api.together.xyz",
"api.groq.com",
"api.mistral.ai",
"api.cohere.com",
}
// GenAI event categories for the SOC event bus.
const (
CategoryGenAIChildProcess = "genai_child_process"
CategoryGenAISensitiveFile = "genai_sensitive_file_access"
CategoryGenAIUnusualDomain = "genai_unusual_domain"
CategoryGenAICredentialAccess = "genai_credential_access"
CategoryGenAIPersistence = "genai_persistence"
CategoryGenAIConfigModification = "genai_config_modification"
)
// AutoAction defines an automated response for GenAI EDR rules.
type AutoAction struct {
Type string `json:"type"` // "kill_process", "notify", "quarantine"
Target string `json:"target"` // Process ID, file path, etc.
Reason string `json:"reason"` // Human-readable justification
}
// IsGenAIProcess returns true if the process name matches a known GenAI agent.
func IsGenAIProcess(processName string) bool {
for _, name := range GenAIProcessNames {
if processName == name {
return true
}
}
return false
}
// IsCredentialFile returns true if the file path matches a known credential file.
func IsCredentialFile(filePath string) bool {
for _, cred := range CredentialFiles {
// Check if the file path ends with the credential file name
if len(filePath) >= len(cred) && filePath[len(filePath)-len(cred):] == cred {
return true
}
}
return false
}
// IsLLMEndpoint returns true if the domain matches a known LLM API endpoint.
func IsLLMEndpoint(domain string) bool {
for _, endpoint := range LLMDNSEndpoints {
if domain == endpoint {
return true
}
}
return false
}
// ProcessAncestry represents the process tree for Entity ID Intersection.
type ProcessAncestry struct {
PID int `json:"pid"`
Name string `json:"name"`
Executable string `json:"executable"`
Args []string `json:"args,omitempty"`
ParentPID int `json:"parent_pid"`
ParentName string `json:"parent_name"`
Ancestry []string `json:"ancestry"` // Full ancestry chain (oldest first)
EntityID string `json:"entity_id"`
}
// HasGenAIAncestor returns true if any process in the ancestry chain is a GenAI agent.
func (p *ProcessAncestry) HasGenAIAncestor() bool {
for _, ancestor := range p.Ancestry {
if IsGenAIProcess(ancestor) {
return true
}
}
return IsGenAIProcess(p.ParentName)
}
// GenAIAncestorName returns the name of the GenAI ancestor, or empty string if none.
func (p *ProcessAncestry) GenAIAncestorName() string {
if IsGenAIProcess(p.ParentName) {
return p.ParentName
}
for _, ancestor := range p.Ancestry {
if IsGenAIProcess(ancestor) {
return ancestor
}
}
return ""
}