Completes Task #3 of httpclient dogfooding with 100% detection rate (7/7 violations). ## New Extractors - **OptionBoundsExtractor**: Detects Option<T> fields set to None (unbounded) - **OptionValueExtractor**: Extracts values from Some(n) for threshold checks Both extractors use context-aware pattern matching to understand Rust Option<T> semantics, which declarative extractors cannot handle. ## Implementation **Files Created**: - applications/aphoria/src/extractors/option_bounds.rs (257 lines) - applications/aphoria/src/extractors/option_value.rs (277 lines) - applications/aphoria/docs/examples/extractors/programmatic-option-semantics.md **Files Modified**: - applications/aphoria/src/extractors/mod.rs - Added module declarations - applications/aphoria/src/extractors/registry.rs - Registered extractors - applications/aphoria/dogfood/httpclient/.aphoria/claims.toml - Added 4 claims - applications/aphoria/dogfood/httpclient/TASK-1-SUMMARY.md - Task #3 completion ## Results | Metric | Value | |--------|-------| | Detection Rate | 100% (7/7 violations) | | Improvement | +29 percentage points (from 71%) | | New Violations | 2 (max_redirects, max_retries unbounded) | | Unit Tests | 13 (all passing) | ## Two-Claim Strategy For each bounded Option<T> field: 1. **configured** claim - Detects None (unbounded) 2. **max_value** claim - Validates Some(n) threshold Example: - `max_redirects: None` → CONFLICT (not configured) - `max_redirects: Some(20)` → CONFLICT (exceeds 10) - `max_redirects: Some(5)` → PASS ## Enterprise Quality ✓ Proper error handling (no unwrap/expect) ✓ Comprehensive tests (6+7 unit tests) ✓ Full documentation with examples ✓ Reusable for 10+ similar patterns ✓ Screening patterns for performance ## Cachewrap Dogfood Also includes complete cachewrap dogfood exercise: - 10 claims for Redis cache wrapper - Day 1-5 summaries - Full retrospective and evaluation - Declarative extractors for all patterns Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
191 lines
6.4 KiB
TOML
191 lines
6.4 KiB
TOML
# Aphoria Configuration for cachewrap Dogfood Project
|
|
# Purpose: Validate multi-domain flywheel (httpclient + dbpool + msgqueue → cache)
|
|
|
|
[project]
|
|
name = "cachewrap-dogfood"
|
|
version = "0.1.0"
|
|
|
|
[scan]
|
|
# Include all Rust source files
|
|
include = ["src/**/*.rs"]
|
|
|
|
# Exclude test files and build artifacts from scanning
|
|
exclude = ["tests/**/*.rs", "target/**"]
|
|
|
|
[episteme]
|
|
# CRITICAL: Use persistent mode (not ephemeral) for pattern learning
|
|
# This enables the flywheel - pattern aggregation across scans
|
|
mode = "persistent"
|
|
|
|
# Corpus database location (matches API's STEMEDB_CORPUS_DB_DIR)
|
|
corpus_db = "/home/jml/.aphoria/corpus-db"
|
|
|
|
[corpus]
|
|
# Enable pattern aggregation (flywheel mechanism)
|
|
aggregation_enabled = true
|
|
|
|
# Include corpus sources for pattern reuse
|
|
sources = [
|
|
"httpclient", # Async patterns: timeout, TLS, retry
|
|
"dbpool", # Connection patterns: max_connections, lifecycle
|
|
"msgqueue", # Messaging patterns: backpressure, metrics
|
|
]
|
|
|
|
# Include all corpus types
|
|
include_rfc = true # RFC normative statements
|
|
include_owasp = true # OWASP cheat sheets (security claims)
|
|
include_vendor = true # Vendor docs (Redis, AWS ElastiCache)
|
|
use_community = true # Community-learned patterns
|
|
|
|
# Cache directory for downloaded sources
|
|
cache_dir = "/home/jml/.aphoria/cache"
|
|
|
|
# ============================================================================
|
|
# EXTRACTORS CONFIGURATION
|
|
# ============================================================================
|
|
# By default, all 42 built-in extractors run (security patterns: TLS, secrets,
|
|
# injection, timeouts, etc.). Custom extractors will be created on Day 3 via
|
|
# /aphoria-custom-extractor-creator skill.
|
|
#
|
|
# Built-in extractors that may detect violations:
|
|
# - hardcoded_secrets: Detects violation 3 (plaintext password)
|
|
# - tls_config: Detects violation 2 (verify_tls = false)
|
|
# - timeout_config: May detect violation 8 (timeout = 0)
|
|
#
|
|
# Custom extractors needed (created on Day 3):
|
|
# - key_validation: Violation 1 (no validate_key call)
|
|
# - ttl_presence: Violation 4 (SET without EX/PX)
|
|
# - max_size_check: Violation 5 (max_size = None)
|
|
# - async_check: Violation 6 (blocking calls in async)
|
|
# - eviction_policy_check: Violation 7 (eviction_policy = None)
|
|
# - connection_pool_check: Violation 9 (no pooling)
|
|
# - metrics_check: Violation 10 (metrics_enabled = false)
|
|
# ============================================================================
|
|
|
|
[extractors]
|
|
|
|
[extractors.inline_markers]
|
|
# Enable @aphoria:claim comments
|
|
enabled = true
|
|
sync_to_pending = true
|
|
|
|
# ============================================================================
|
|
# CUSTOM DECLARATIVE EXTRACTORS (Day 3)
|
|
# ============================================================================
|
|
|
|
# Extractor 1: Detect missing key validation
|
|
[[extractors.declarative]]
|
|
name = "cache_key_validation_missing"
|
|
description = "Detects get() method accepting raw &str keys without validation (enables injection attacks)"
|
|
languages = ["rust"]
|
|
pattern = 'pub\s+async\s+fn\s+get\s*\(&self,\s*key:\s*&str\)'
|
|
claim.subject = "cache/key_validation"
|
|
claim.predicate = "required"
|
|
claim.value = false
|
|
confidence = 0.9
|
|
|
|
# Extractor 2: Detect TLS verification disabled
|
|
[[extractors.declarative]]
|
|
name = "tls_verification_disabled"
|
|
description = "Detects verify_tls: false in cache config (enables MITM attacks)"
|
|
languages = ["rust"]
|
|
pattern = 'verify_tls:\s*false'
|
|
claim.subject = "cache/tls/certificate_validation"
|
|
claim.predicate = "required"
|
|
claim.value = false
|
|
confidence = 0.95
|
|
|
|
# Extractor 3: Detect hardcoded passwords
|
|
[[extractors.declarative]]
|
|
name = "hardcoded_password"
|
|
description = "Detects hardcoded password strings in cache config"
|
|
languages = ["rust"]
|
|
pattern = 'password:\s*"[^"]+"\.to_string\(\)'
|
|
claim.subject = "cache/credentials/password"
|
|
claim.predicate = "hardcoded"
|
|
claim.value = true
|
|
confidence = 0.9
|
|
|
|
# Extractor 4: Detect missing TTL
|
|
[[extractors.declarative]]
|
|
name = "ttl_missing"
|
|
description = "Detects SET commands without TTL (causes memory leak)"
|
|
languages = ["rust"]
|
|
pattern = 'conn\.set::<[^>]+>\([^)]+\)\.await\?;'
|
|
claim.subject = "cache/ttl"
|
|
claim.predicate = "required"
|
|
claim.value = false
|
|
confidence = 0.85
|
|
|
|
# Extractor 5: Detect unbounded max_size
|
|
[[extractors.declarative]]
|
|
name = "max_size_unbounded"
|
|
description = "Detects max_size: None (unbounded cache allows OOM)"
|
|
languages = ["rust"]
|
|
pattern = 'max_size:\s*None'
|
|
claim.subject = "cache/max_size"
|
|
claim.predicate = "bounded"
|
|
claim.value = false
|
|
confidence = 0.95
|
|
|
|
# Extractor 6: Detect blocking in async
|
|
[[extractors.declarative]]
|
|
name = "async_blocking"
|
|
description = "Detects blocking get_connection() in async functions"
|
|
languages = ["rust"]
|
|
pattern = 'self\.client\.get_connection\(\)'
|
|
claim.subject = "cache/async/blocking_forbidden"
|
|
claim.predicate = "required"
|
|
claim.value = false
|
|
confidence = 0.9
|
|
|
|
# Extractor 7: Detect missing eviction policy
|
|
[[extractors.declarative]]
|
|
name = "eviction_policy_missing"
|
|
description = "Detects eviction_policy: None (undefined behavior when cache full)"
|
|
languages = ["rust"]
|
|
pattern = 'eviction_policy:\s*None'
|
|
claim.subject = "cache/eviction_policy"
|
|
claim.predicate = "required"
|
|
claim.value = false
|
|
confidence = 0.95
|
|
|
|
# Extractor 8: Detect zero timeout
|
|
[[extractors.declarative]]
|
|
name = "timeout_zero"
|
|
description = "Detects Duration::from_secs(0) timeout (indefinite blocking)"
|
|
languages = ["rust"]
|
|
pattern = 'timeout:\s*Duration::from_secs\(0\)'
|
|
claim.subject = "cache/timeout"
|
|
claim.predicate = "max_value"
|
|
claim.value_from_match = false
|
|
claim.value = 0.0
|
|
confidence = 1.0
|
|
|
|
# Extractor 9: Detect missing connection pooling
|
|
[[extractors.declarative]]
|
|
name = "connection_pool_missing"
|
|
description = "Detects get_multiplexed_async_connection() per request (resource exhaustion)"
|
|
languages = ["rust"]
|
|
pattern = 'let\s+mut\s+conn\s*=\s*self\.client\.get_multiplexed_async_connection\(\)\.await'
|
|
claim.subject = "cache/connection/max_connections"
|
|
claim.predicate = "bounded"
|
|
claim.value = false
|
|
confidence = 0.85
|
|
|
|
# Extractor 10: Detect metrics disabled
|
|
[[extractors.declarative]]
|
|
name = "metrics_disabled"
|
|
description = "Detects metrics_enabled: false (prevents production debugging)"
|
|
languages = ["rust"]
|
|
pattern = 'metrics_enabled:\s*false'
|
|
claim.subject = "cache/metrics/enabled"
|
|
claim.predicate = "required"
|
|
claim.value = false
|
|
confidence = 0.95
|
|
|
|
# Thresholds for conflict severity verdicts
|
|
[thresholds]
|
|
block_threshold = 0.7 # Conflict score >= 0.7 → BLOCK (critical violations)
|
|
flag_threshold = 0.5 # Conflict score >= 0.5 → FLAG (warnings)
|