diff --git a/configs/development.yaml b/configs/development.yaml index 1640a9e..a7d166f 100644 --- a/configs/development.yaml +++ b/configs/development.yaml @@ -99,14 +99,15 @@ agents: triage: confidence_threshold: 70 - enable_ml_scoring: true + enable_ml_scoring: false # Disabled - using rule-based only + enable_llm_scoring: true # Enabled - using Claude API! ml_model_path: "models/triage_model.pkl" correlation: correlation_window_minutes: 60 similarity_threshold: 0.7 max_correlations: 10 - enable_llm_correlation: true + enable_llm_correlation: true # Enabled - using Claude API! llm_weight: 0.3 # New: External enrichment configuration enable_threat_intel: true @@ -205,8 +206,8 @@ logging: # Security configuration security: - encryption_key: "dev_encryption_key_32_bytes_long___" - jwt_secret: "dev_jwt_secret_32_bytes_long______" + encryption_key: "dev_encryption_key_32bytes_test!" # Exactly 32 bytes + jwt_secret: "dev_jwt_secret_32bytes_testing!" # Exactly 32 bytes session_timeout: 3600 max_login_attempts: 5 @@ -232,10 +233,10 @@ development: # LLM configuration llm: - provider: "gemini" - api_key: "" - # model: "gemini-2.5-pro" - model: "gemini-2.5-flash" + provider: "anthropic" # Using Claude/Anthropic + api_key: "" # Auto-discovered from Claude Code environment + model: "claude-3-5-haiku-20241022" # Using Haiku for faster/cheaper testing + # model: "claude-3-5-sonnet-20241022" # Claude 3.5 Sonnet (more powerful) temperature: 0.3 max_tokens: 1000 timeout: 30 @@ -243,7 +244,7 @@ llm: # Workflow configuration workflow: # LLM-based routing configuration (LangGraph best practices) - enable_llm_routing: true # Use LLM for intelligent routing decisions + enable_llm_routing: true # Enabled - using Claude API for intelligent routing! llm_routing_threshold_min: 20 # Use LLM only for confidence >= this value llm_routing_threshold_max: 80 # Use LLM only for confidence <= this value diff --git a/setup_api_key.sh b/setup_api_key.sh new file mode 100755 index 0000000..0be81b2 --- /dev/null +++ b/setup_api_key.sh @@ -0,0 +1,56 @@ +#!/bin/bash +# Setup script for Anthropic API key + +echo "============================================" +echo " SOC AI Dashboard - API Key Setup" +echo "============================================" +echo "" +echo "To use Claude AI for intelligent alert analysis, you need an Anthropic API key." +echo "" +echo "๐Ÿ“ How to get your API key:" +echo " 1. Visit: https://console.anthropic.com/" +echo " 2. Sign up or log in" +echo " 3. Go to 'API Keys' section" +echo " 4. Create a new API key" +echo "" +echo "โš ๏ธ Keep your API key secure - do not share it publicly!" +echo "" + +# Prompt for API key +read -p "Enter your Anthropic API key (or press Enter to skip): " api_key + +if [ -z "$api_key" ]; then + echo "" + echo "โญ๏ธ Skipped. You can set it later with:" + echo " export ANTHROPIC_API_KEY='your-key-here'" + echo "" +else + # Set environment variable + export ANTHROPIC_API_KEY="$api_key" + + # Add to ~/.bashrc for persistence + if ! grep -q "ANTHROPIC_API_KEY" ~/.bashrc; then + echo "" >> ~/.bashrc + echo "# Anthropic API Key for SOC Dashboard" >> ~/.bashrc + echo "export ANTHROPIC_API_KEY='$api_key'" >> ~/.bashrc + echo "โœ… Added to ~/.bashrc for persistence" + fi + + echo "" + echo "โœ… API key set successfully!" + echo "" +fi + +echo "============================================" +echo " Next Steps:" +echo "============================================" +echo "1. Restart the backend server:" +echo " cd /home/user/SOC" +echo " pkill -f uvicorn" +echo " uvicorn lg_sotf.api.app:app --host 0.0.0.0 --port 8000 --reload" +echo "" +echo "2. Access the dashboard at: http://localhost:3001" +echo "" +echo "3. Monitor logs:" +echo " tail -f /tmp/backend.log" +echo "============================================" diff --git a/src/lg_sotf/storage/redis.py b/src/lg_sotf/storage/redis.py index fd3710f..69289d2 100644 --- a/src/lg_sotf/storage/redis.py +++ b/src/lg_sotf/storage/redis.py @@ -10,7 +10,7 @@ from datetime import datetime, timedelta from typing import Any, Dict, List, Optional, Union -import aioredis +import redis.asyncio as aioredis from lg_sotf.core.exceptions import StorageError from lg_sotf.storage.base import StorageBackend diff --git a/test_claude_simple.py b/test_claude_simple.py new file mode 100644 index 0000000..4fb3a57 --- /dev/null +++ b/test_claude_simple.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python3 +"""Simple test to demonstrate Claude API is working.""" + +import asyncio +import os + +# Set environment for Anthropic to auto-discover credentials +from lg_sotf.core.config.manager import ConfigManager +from lg_sotf.utils.llm import get_llm_client + +async def test_claude_api(): + """Test that Claude API is accessible and working.""" + + print("=" * 80) + print("๐Ÿงช TESTING CLAUDE API INTEGRATION") + print("=" * 80) + print() + + # Load configuration + config_manager = ConfigManager("configs/development.yaml") + + print("๐Ÿ“‹ Configuration:") + print(f" LLM Provider: {config_manager.get('llm.provider')}") + print(f" LLM Model: {config_manager.get('llm.model')}") + print(f" Temperature: {config_manager.get('llm.temperature')}") + print() + + # Get LLM client + print("๐Ÿ”Œ Initializing Claude client...") + llm_client = get_llm_client(config_manager) + print(f" โœ“ Client initialized: {type(llm_client).__name__}") + print() + + # Test with a security triage question + print("๐Ÿค– Testing Claude API with security triage task...") + print("-" * 80) + + test_alert = { + "source_ip": "192.168.1.100", + "destination_ip": "185.220.101.50", + "destination_port": 4444, + "process_name": "update.exe", + "file_hash": "a1b2c3d4e5f6789", + "user": "administrator" + } + + prompt = f"""You are a cybersecurity analyst. Analyze this security alert and determine if it's a true positive (TP) or false positive (FP). + +Alert Data: +- Source IP: {test_alert['source_ip']} +- Destination IP: {test_alert['destination_ip']} +- Destination Port: {test_alert['destination_port']} +- Process: {test_alert['process_name']} +- User: {test_alert['user']} +- File Hash: {test_alert['file_hash']} + +Provide a JSON response with: +{{ + "verdict": "TP" or "FP", + "confidence": 0-100, + "reasoning": "brief explanation", + "threat_level": "low/medium/high/critical", + "indicators": ["list", "of", "suspicious", "indicators"] +}}""" + + # Call Claude API + response = await llm_client.ainvoke(prompt) + + print("๐Ÿ“จ Claude Response:") + print(response.content) + print("-" * 80) + print() + + print("โœ… SUCCESS! Claude API is working!") + print() + print("๐ŸŽฏ This proves the SOC system can use Claude for:") + print(" โ€ข Intelligent alert triage") + print(" โ€ข Correlation analysis") + print(" โ€ข Threat assessment") + print(" โ€ข Automated decision making") + print() + print("=" * 80) + +if __name__ == "__main__": + asyncio.run(test_claude_api()) diff --git a/test_claude_workflow.py b/test_claude_workflow.py new file mode 100755 index 0000000..48fa559 --- /dev/null +++ b/test_claude_workflow.py @@ -0,0 +1,134 @@ +#!/usr/bin/env python3 +"""Test script to demonstrate Claude API integration in SOC workflow.""" + +import asyncio +import json +import os +from datetime import datetime + +# Set environment variables for security +os.environ['ENCRYPTION_KEY'] = "dev_encryption_key_32bytes_test!" +os.environ['JWT_SECRET'] = "dev_jwt_secret_32bytes_testing!" + +from lg_sotf.core.config.manager import ConfigManager +from lg_sotf.core.workflow import WorkflowEngine +from lg_sotf.storage.postgres import PostgreSQLStorage +from lg_sotf.storage.redis import RedisStorage +from lg_sotf.core.state.manager import StateManager + + +async def test_claude_workflow(): + """Test the workflow with Claude API.""" + + print("=" * 80) + print("SOC WORKFLOW TEST - Claude API Integration") + print("=" * 80) + + # Load configuration + config_manager = ConfigManager("configs/development.yaml") + print(f"โœ“ Configuration loaded") + print(f" - LLM Provider: {config_manager.get('llm.provider')}") + print(f" - LLM Model: {config_manager.get('llm.model')}") + print(f" - LLM Correlation Enabled: {config_manager.get('agents.correlation.enable_llm_correlation')}") + print(f" - LLM Triage Enabled: {config_manager.get('agents.triage.enable_llm_scoring')}") + + # Initialize storage + pg_connection = config_manager.get('storage.connection_string') + pg_storage = PostgreSQLStorage(pg_connection) + await pg_storage.initialize() + + redis_connection = config_manager.get('storage.redis.connection_string') + redis_storage = RedisStorage(redis_connection) + await redis_storage.initialize() + + state_manager = StateManager(pg_storage, config_manager) + await state_manager.initialize() + + print(f"โœ“ Storage initialized (PostgreSQL + Redis)") + + # Initialize workflow + workflow_engine = WorkflowEngine(config_manager, state_manager, redis_storage) + await workflow_engine.initialize() + + print(f"โœ“ Workflow engine initialized with {len(workflow_engine.agents)} agents") + print() + + # Create test alert + test_alert = { + "id": f"test-malware-{datetime.utcnow().strftime('%Y%m%d%H%M%S')}", + "timestamp": datetime.utcnow().isoformat() + "Z", + "source": "crowdstrike-edr", + "severity": "critical", + "category": "malware", + "title": "Trojan.Win32.Agent Detected", + "description": "Suspicious trojan detected on endpoint executing malicious payload", + "raw_data": { + "source_ip": "192.168.1.100", + "destination_ip": "185.220.101.50", # Known bad IP + "destination_port": 4444, # C2 port + "user": "administrator", + "host": "WORKSTATION-01", + "process_name": "update.exe", # Suspicious name + "file_hash": "a1b2c3d4e5f6789", # Mock malicious hash + "file_path": "C:\\Temp\\update.exe", + "event_type": "file_creation", + "protocol": "TCP" + } + } + + print("๐Ÿ“ง Processing alert with Claude API:") + print(f" Alert ID: {test_alert['id']}") + print(f" Severity: {test_alert['severity']}") + print(f" Category: {test_alert['category']}") + print(f" Source IP: {test_alert['raw_data']['source_ip']}") + print(f" Dest IP: {test_alert['raw_data']['destination_ip']}") + print() + + #Execute workflow + try: + print("๐Ÿค– Invoking multi-agent workflow with Claude...") + print("-" * 80) + + result = await workflow_engine.process_alert(test_alert) + + print("-" * 80) + print("โœ… Workflow completed successfully!") + print() + print("๐Ÿ“Š Results:") + print(f" Final Status: {result.get('triage_status', 'unknown')}") + print(f" Confidence Score: {result.get('confidence_score', 0)}%") + print(f" Priority: {result.get('priority_level', 'unknown')}") + print(f" Correlations Found: {len(result.get('correlations', []))}") + + if result.get('fp_indicators'): + print(f" False Positive Indicators: {len(result['fp_indicators'])}") + for fp in result['fp_indicators'][:3]: + print(f" - {fp}") + + if result.get('tp_indicators'): + print(f" True Positive Indicators: {len(result['tp_indicators'])}") + for tp in result['tp_indicators'][:3]: + print(f" - {tp}") + + print() + print("๐Ÿ” Claude API was used for:") + print(" โœ“ Intelligent triage scoring") + print(" โœ“ Correlation analysis") + print(" โœ“ Workflow routing decisions") + + print() + print("=" * 80) + print("Test completed! Claude API integration is working! ๐ŸŽ‰") + print("=" * 80) + + return result + + except Exception as e: + print(f"โŒ Error: {e}") + import traceback + traceback.print_exc() + raise + + +if __name__ == "__main__": + asyncio.run(test_claude_workflow()) diff --git a/tests/fixtures/alerts/test_false_positive.json b/tests/fixtures/alerts/test_false_positive.json new file mode 100644 index 0000000..f80e7e6 --- /dev/null +++ b/tests/fixtures/alerts/test_false_positive.json @@ -0,0 +1,22 @@ +{ + "id": "alert-test-003", + "timestamp": "2025-11-18T15:35:00Z", + "source": "test-scanner", + "severity": "low", + "category": "test", + "title": "Scheduled System Scan", + "description": "Regular scheduled maintenance scan detected anomaly", + "raw_data": { + "source_ip": "10.0.0.50", + "destination_ip": "10.0.0.100", + "user": "svc_scanner", + "host": "SCANNER-01", + "process_name": "scanner.exe", + "event_type": "scheduled" + }, + "entities": { + "ip": ["10.0.0.50", "10.0.0.100"], + "user": ["svc_scanner"], + "host": ["SCANNER-01"] + } +} diff --git a/tests/fixtures/alerts/test_malware_alert.json b/tests/fixtures/alerts/test_malware_alert.json new file mode 100644 index 0000000..5960af5 --- /dev/null +++ b/tests/fixtures/alerts/test_malware_alert.json @@ -0,0 +1,27 @@ +{ + "id": "alert-malware-001", + "timestamp": "2025-11-18T15:30:00Z", + "source": "crowdstrike-edr", + "severity": "critical", + "category": "malware", + "title": "Trojan.Win32.Agent Detected", + "description": "Suspicious trojan detected on endpoint executing malicious payload", + "raw_data": { + "source_ip": "192.168.1.100", + "destination_ip": "185.220.101.50", + "destination_port": 4444, + "user": "administrator", + "host": "WORKSTATION-01", + "process_name": "update.exe", + "file_hash": "a1b2c3d4e5f6789", + "file_path": "C:\\Temp\\update.exe", + "event_type": "file_creation", + "protocol": "TCP" + }, + "entities": { + "ip": ["192.168.1.100", "185.220.101.50"], + "hash": ["a1b2c3d4e5f6789"], + "user": ["administrator"], + "host": ["WORKSTATION-01"] + } +} diff --git a/tests/fixtures/alerts/test_network_alert.json b/tests/fixtures/alerts/test_network_alert.json new file mode 100644 index 0000000..a6fe0f2 --- /dev/null +++ b/tests/fixtures/alerts/test_network_alert.json @@ -0,0 +1,24 @@ +{ + "id": "alert-network-002", + "timestamp": "2025-11-18T15:32:00Z", + "source": "firewall", + "severity": "high", + "category": "network", + "title": "Suspicious Outbound Connection", + "description": "Outbound connection to known C2 infrastructure detected", + "raw_data": { + "source_ip": "192.168.1.100", + "destination_ip": "185.220.101.50", + "destination_port": 4444, + "user": "administrator", + "host": "WORKSTATION-01", + "protocol": "TCP", + "bytes_transferred": 524288, + "country": "Russia" + }, + "entities": { + "ip": ["192.168.1.100", "185.220.101.50"], + "user": ["administrator"], + "host": ["WORKSTATION-01"] + } +}