stemedb/applications/aphoria/dogfood/cachewrap/.aphoria/config.toml
jml e758f2ebfb feat(aphoria): implement programmatic extractors for Option<T> semantics
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>
2026-02-11 06:43:10 +00:00

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)