Audit wrangler config with dual-mode: Resource Discovery (default) finds unused/dangling resources, --validate verifies against production metrics
Audits Cloudflare wrangler configs with resource discovery and live production validation.
/plugin marketplace add littlebearapps/cloudflare-engineer/plugin install cloudflare-engineer@littlebearapps-cloudflare[wrangler-path] [--category=security|performance|cost|resilience|resources|all] [--validate] [--discover]Comprehensive audit of your wrangler configuration with dual-mode operation:
--validate): Verify findings against live production metricsArguments: "$ARGUMENTS"
| Mode | Description | MCP Tools |
|---|---|---|
| Discovery (default) | Find unused resources + static config analysis | bindings (optional) |
Validate (--validate) | Verify findings against live production data | observability, bindings |
Discover (--discover) | Resource discovery only (explicit mode) | bindings |
/cf-audit # Resource discovery + config audit (default)
/cf-audit workers/wrangler.jsonc # Specific file
/cf-audit --category=security # Security-only audit
/cf-audit --category=resources # Resource discovery only
/cf-audit --discover # Explicit resource discovery mode
/cf-audit --validate # Verify findings with live production data
/cf-audit --validate --category=perf # Live-validated performance audit
Parse $ARGUMENTS for:
--validate: Enable live data validation--discover: Explicit resource discovery mode--category=X: Filter to specific category (now includes resources)[path]: Explicit wrangler config pathNEW in v1.2.0: By default, /cf-audit now performs resource discovery before config analysis.
| Resource Type | Discovery Check | Provenance |
|---|---|---|
| KV Namespaces | List all → compare to wrangler bindings | [STATIC] or [LIVE-VALIDATED] |
| R2 Buckets | List all → check for references in code | [STATIC] or [LIVE-VALIDATED] |
| D1 Databases | List all → compare to active bindings | [STATIC] or [LIVE-VALIDATED] |
| DNS Records | List dangling CNAME/A records | [LIVE-VALIDATED] only |
| Queues | List all → check consumer bindings | [STATIC] or [LIVE-VALIDATED] |
| Workers | List all → check for orphaned workers | [LIVE-VALIDATED] only |
// Step 1: Inventory account resources (if MCP available)
mcp__cloudflare-bindings__kv_namespaces_list()
mcp__cloudflare-bindings__r2_buckets_list()
mcp__cloudflare-bindings__d1_databases_list()
mcp__cloudflare-bindings__queues_list()
mcp__cloudflare-bindings__workers_list()
// Step 2: Parse all wrangler configs in project
// Find all wrangler.toml/wrangler.jsonc files
// Extract all bindings: kv_namespaces, r2_buckets, d1_databases, queues
// Step 3: Compare and identify
// - Unused: In account but not in any wrangler config
// - Dangling: In wrangler config but not in account
// - Orphaned: Workers with no recent requests (via observability)
## Resource Discovery Results
### Unused Resources (Cleanup Candidates)
| Type | Name/ID | Last Activity | Action |
|------|---------|---------------|--------|
| KV | `old-cache-namespace` | 90+ days | Consider deletion |
| R2 | `staging-uploads-2024` | No recent ops | Verify and delete |
| D1 | `test-db-backup` | Never queried | Archive or delete |
### Dangling References
| Type | Binding | Issue | Fix |
|------|---------|-------|-----|
| KV | `LEGACY_CACHE` | Namespace doesn't exist | Remove binding or create namespace |
| Queue | `OLD_QUEUE` | Queue deleted | Remove consumer config |
### Orphaned Workers
| Worker | Last Request | Recommendation |
|--------|--------------|----------------|
| `api-v1-deprecated` | 180 days ago | Delete if unused |
Before using MCP tools, verify availability:
// Lightweight probe to test MCP connectivity
mcp__cloudflare-bindings__workers_list()
Expected outcomes:
[STATIC]# If no path provided, search for wrangler config
find . -maxdepth 3 -name "wrangler.toml" -o -name "wrangler.jsonc"
Read the wrangler config and check against rules:
Security Checks:
Performance Checks:
Cost Checks:
Resilience Checks:
If D1 bindings exist, scan migration files for:
Verify static findings against live data. Reference @skills/probes/SKILL.md for query patterns.
// Check for actual error rates (may indicate attack patterns)
mcp__cloudflare-observability__query_worker_observability({
view: "calculations",
parameters: {
calculations: [
{ operator: "count", as: "total" },
{ operator: "countIf", as: "errors",
condition: { field: "$metadata.outcome", operator: "eq", value: "exception" }}
],
groupBys: [{ type: "string", value: "$metadata.path" }]
},
timeframe: { reference: "now", offset: "-7d" }
})
// EXPLAIN QUERY PLAN for detected queries
mcp__cloudflare-bindings__d1_database_query({
database_id: "...",
sql: "EXPLAIN QUERY PLAN SELECT * FROM users WHERE email = ?"
})
Interpretation:
SCAN TABLE → [LIVE-VALIDATED] PERF002 confirmedSEARCH USING INDEX → [LIVE-REFUTED] Index exists but not in migrations// Check latency percentiles
mcp__cloudflare-observability__query_worker_observability({
view: "calculations",
parameters: {
calculations: [
{ operator: "p50", field: "$metadata.duration", as: "p50_ms" },
{ operator: "p99", field: "$metadata.duration", as: "p99_ms" }
]
},
timeframe: { reference: "now", offset: "-24h" }
})
// Check actual error rates and patterns
// High error rate may indicate resilience issues
Output score and findings:
# Audit Report
**Score**: XX/100 (Grade)
**File**: path/to/wrangler.jsonc
**Mode**: [Static | Live Validated]
**Validation Status**: [Full | Partial | Static Only]
## Summary Table
| Category | Critical | High | Medium | Low | Validated |
|----------|----------|------|--------|-----|-----------|
| Security | X | X | X | X | [Y/N] |
| Performance | X | X | X | X | [Y/N] |
| Cost | X | X | X | X | [Y/N] |
| Resilience | X | X | X | X | [Y/N] |
## Critical Issues
### [STATIC] SEC001: Secrets in plaintext vars
- **Location**: `vars.API_KEY` (line 15)
- **Issue**: Plaintext secret detected
- **Fix**: Move to `secrets` or use encrypted vars
### [LIVE-VALIDATED] PERF002: D1 missing indexes
- **Location**: `migrations/0001_init.sql`
- **Static Finding**: No index on `users.email`
- **Live Evidence**: `EXPLAIN QUERY PLAN` shows `SCAN TABLE users`
- **Fix**: Add index: `CREATE INDEX idx_users_email ON users(email);`
## High Priority
### [LIVE-REFUTED] RES001: Missing dead letter queue
- **Location**: `queues.consumers[0]` (harvest-queue)
- **Static Finding**: No DLQ configured
- **Live Evidence**: Queue has 0 failed messages in 30 days
- **Recommendation**: Still add DLQ for future resilience
## Medium Priority
### [INCOMPLETE] COST003: AI without caching
- **Location**: AI Gateway binding
- **Static Finding**: No cache configuration detected
- **Note**: Could not verify - AI Gateway MCP unavailable
## Recommendations
[Prioritized action items with provenance tags]
---
**Finding Tags:**
- `[STATIC]` - Inferred from code/config analysis
- `[LIVE-VALIDATED]` - Confirmed by observability (--validate mode)
- `[LIVE-REFUTED]` - Code smell not observed in production
- `[INCOMPLETE]` - Some MCP tools unavailable
--category=resources)Focus on:
Live Validation Adds:
--category=security)Focus on:
Live Validation Adds:
--category=performance)Focus on:
Live Validation Adds:
--category=cost)Focus on:
Live Validation Adds:
--category=resilience)Focus on:
Live Validation Adds:
Score = 100 - (critical × 25) - (high × 15) - (medium × 5) - (low × 2)
Grades:
A (90-100): Production ready
B (80-89): Minor issues
C (70-79): Address before deploy
D (60-69): Significant issues
F (<60): Critical problems
Use in CI/CD:
# Block deployment if score < 80
/cf-audit --min-score=80
# Block if any CRITICAL issues
/cf-audit --fail-on-critical
For --validate mode, these MCP servers should be configured:
cloudflare-observability - Error rates, latency metricscloudflare-bindings - D1 EXPLAIN QUERY PLANIf any MCP server is unavailable, the command will:
[INCOMPLETE]--validate for pre-production verification[LIVE-REFUTED] findings may still be worth fixing proactively