//! Default implementations for configuration types. use std::path::PathBuf; use super::types::{ AliasConfig, AutonomousConfig, CommunityConfig, CorpusConfig, DepVersionConfig, EntropyConfig, EpistemeConfig, ExtractorConfig, HostedConfig, LearningConfig, LlmConfig, OfflineFallback, PromotionConfig, ScanConfig, SyncMode, ThresholdConfig, TimeoutExtractorConfig, DEFAULT_LLM_MODEL, }; impl Default for EpistemeConfig { fn default() -> Self { Self { data_dir: dirs_default_data_dir(), url: None } } } impl Default for ThresholdConfig { fn default() -> Self { Self { block: 0.7, flag: 0.4 } } } impl Default for ExtractorConfig { fn default() -> Self { Self { enabled: vec![ "tls_verify".to_string(), "tls_version".to_string(), "jwt_config".to_string(), "hardcoded_secrets".to_string(), "timeout_config".to_string(), "dep_versions".to_string(), "cors_config".to_string(), "durability_config".to_string(), "rate_limit".to_string(), // Phase 2 extractors "weak_crypto".to_string(), "sql_injection".to_string(), "command_injection".to_string(), // Unreal Engine extractors "unreal_cpp".to_string(), "unreal_config".to_string(), "unreal_performance".to_string(), // Phase 8: Enterprise extractors (first batch) "high_entropy_secrets".to_string(), "auth_bypass".to_string(), "api_key_security".to_string(), "import_graph".to_string(), "derive_pattern".to_string(), "const_declarations".to_string(), "unsafe_atomic".to_string(), "circuit_breaker_config".to_string(), "insecure_cookies".to_string(), // Phase 8: Enterprise extractors (second batch) "path_traversal".to_string(), "unvalidated_redirects".to_string(), "weak_password".to_string(), "security_headers".to_string(), "insecure_deserialization".to_string(), "ssrf".to_string(), "orm_injection".to_string(), "xxe".to_string(), // Phase 8.3: Config deep parsing "config_security".to_string(), // Phase 8.2: Framework-specific security extractors "django_security".to_string(), "express_security".to_string(), "flask_security".to_string(), "fastapi_security".to_string(), "nestjs_security".to_string(), "nextjs_security".to_string(), "spring_security".to_string(), "laravel_security".to_string(), "rails_security".to_string(), "aspnet_security".to_string(), ], disabled: vec![], timeout_config: TimeoutExtractorConfig::default(), dep_versions: DepVersionConfig::default(), entropy: EntropyConfig::default(), declarative: vec![], } } } impl Default for TimeoutExtractorConfig { fn default() -> Self { Self { min_reasonable_ms: 1000, max_reasonable_ms: 300_000 } } } impl Default for DepVersionConfig { fn default() -> Self { Self { enabled: false, // OPT-IN: Disabled by default to reduce noise advisory_db: dirs_default_advisory_db(), } } } impl Default for EntropyConfig { fn default() -> Self { Self { min_entropy: 4.5, min_charset_variety: 0.4, min_length: 20, max_length: 200 } } } impl Default for ScanConfig { fn default() -> Self { Self { exclude: vec![ "target/".to_string(), "node_modules/".to_string(), ".git/".to_string(), "vendor/".to_string(), ], max_file_size: 1_048_576, // 1MB include_tests: false, } } } impl Default for AliasConfig { fn default() -> Self { Self { auto_suggest: true, auto_accept_tier0: true, auto_create_aliases: true } } } impl Default for CorpusConfig { fn default() -> Self { Self { cache_dir: dirs_default_cache_dir(), include_hardcoded: true, include_rfc: true, include_owasp: true, include_vendor: true, rfc_list: None, } } } impl Default for HostedConfig { fn default() -> Self { Self { url: None, project_id: None, team_id: None, sync_mode: SyncMode::default(), offline_fallback: OfflineFallback::default(), max_retries: 3, retry_delay_ms: 1000, api_key_env: "APHORIA_API_KEY".to_string(), } } } impl Default for CommunityConfig { fn default() -> Self { Self { enabled: false, // CRITICAL: Opt-in only anonymize: true, // CRITICAL: Privacy by default exclude: vec![], include: vec![], min_confidence: 0.8, } } } impl Default for LlmConfig { fn default() -> Self { Self { enabled: false, provider: "gemini".to_string(), model: DEFAULT_LLM_MODEL.to_string(), api_key_env: "GEMINI_API_KEY".to_string(), max_tokens_per_scan: 50000, max_tokens_per_file: 4000, cache_responses: true, timeout_secs: 60, high_value_only: true, min_confidence: 0.7, } } } impl Default for LearningConfig { fn default() -> Self { Self { enabled: false, store: "local".to_string(), min_confidence: 0.7, prune_after_days: 90, max_patterns: 10_000, promotion: PromotionConfig::default(), } } } impl Default for PromotionConfig { fn default() -> Self { Self { min_projects: 5, min_confidence: 0.8, auto_promote: false, output_dir: PathBuf::from(".aphoria/extractors/learned"), require_review: true, } } } impl Default for AutonomousConfig { fn default() -> Self { Self { // CRITICAL: Opt-in only - kill switch defaults to off enabled: false, // Stricter than standard promotion thresholds min_confidence: 0.95, min_projects: 10, // Require perfect validation by default require_zero_failures: true, require_zero_warnings: true, // Audit logging on by default for compliance audit_log: true, audit_dir: None, // Uses ~/.aphoria/audit/ via get_audit_dir() } } } /// Get the default Aphoria data directory. fn dirs_default_data_dir() -> PathBuf { if let Some(home) = dirs::home_dir() { home.join(".aphoria").join("db") } else { PathBuf::from(".aphoria/db") } } /// Get the default advisory database directory. fn dirs_default_advisory_db() -> PathBuf { if let Some(home) = dirs::home_dir() { home.join(".aphoria").join("advisory-db") } else { PathBuf::from(".aphoria/advisory-db") } } /// Get the default cache directory for corpus downloads. fn dirs_default_cache_dir() -> PathBuf { if let Some(cache) = dirs::cache_dir() { cache.join("aphoria") } else if let Some(home) = dirs::home_dir() { home.join(".cache").join("aphoria") } else { PathBuf::from(".aphoria/cache") } } /// Get the LLM response cache directory. /// /// Used to cache Claude API responses keyed by content hash + model. /// This avoids redundant API calls for the same file content. pub fn llm_cache_dir() -> PathBuf { if let Some(cache) = dirs::cache_dir() { cache.join("aphoria").join("llm-cache") } else if let Some(home) = dirs::home_dir() { home.join(".cache").join("aphoria").join("llm-cache") } else { PathBuf::from(".aphoria/llm-cache") } }