stemedb/applications/aphoria/src/config/defaults.rs
2026-02-07 19:51:05 -07:00

271 lines
8.2 KiB
Rust

//! 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")
}
}