Design Spec: cloudflare-zone-waf-report
Parent: #111
Target: runwhen-contrib/rw-cli-codecollection
Spec
codebundle_name: "cloudflare-zone-waf-report"
target_collection: "runwhen-contrib/rw-cli-codecollection"
display_name: "Cloudflare Zone WAF & Security Events Report"
author: "rw-codebundle-agent"
purpose: |
Pulls Cloudflare WAF and security-adjacent firewall events for a zone, correlates them
by rule, action, client IP, geography, host, and path, and raises issues when volumes
exceed operator-defined thresholds. Intended for proactive abuse detection and tuning.
tasks:
- name: "Fetch Firewall and WAF Events for Zone `${CLOUDFLARE_ZONE_ID}`"
description: |
Queries the Cloudflare GraphQL Analytics API (firewall/security event datasets)
for the configured lookback window and persists normalized JSON for downstream tasks.
script_name: "fetch-cloudflare-firewall-events.sh"
expected_issue_severity: [1, 2]
access_level: "read-only"
data_type: "metrics"
- name: "Aggregate WAF Events by Rule, Action, and Service"
description: |
Groups events by rule ID, action (block, challenge, jschallenge, etc.), and
source service to show which protections are firing most often.
script_name: "aggregate-waf-by-rule.sh"
expected_issue_severity: [2, 2]
access_level: "read-only"
data_type: "metrics"
- name: "Correlate WAF Events by Source IP and Country"
description: |
Identifies top client IPs, ASNs, and countries to highlight concentrated attacks
versus distributed noise.
script_name: "correlate-waf-by-source.sh"
expected_issue_severity: [2, 3]
access_level: "read-only"
data_type: "metrics"
- name: "Break Down WAF Activity by Hostname and Request Path"
description: |
Surfaces which hosts and URL paths draw the most security actions for targeted
investigation and rule tuning.
script_name: "aggregate-waf-by-path.sh"
expected_issue_severity: [2, 2]
access_level: "read-only"
data_type: "metrics"
- name: "Evaluate WAF Volume and Spike Thresholds"
description: |
Compares totals and top-segment counts to configurable thresholds (absolute counts
and optional ratio versus prior window) and emits structured issues with expected vs
actual and remediation hints.
script_name: "evaluate-waf-thresholds.sh"
expected_issue_severity: [3, 4]
access_level: "read-only"
data_type: "metrics"
- name: "Produce Consolidated WAF Correlation Report"
description: |
Renders a single human-readable summary referencing the aggregations above and
attaches key metrics to the RunWhen report for on-call handoff.
script_name: "report-waf-correlation-summary.sh"
expected_issue_severity: [2, 3]
access_level: "read-only"
data_type: "metrics"
scope:
level: "Resource"
qualifiers:
- CLOUDFLARE_ZONE_ID
- CLOUDFLARE_ACCOUNT_ID
iteration_pattern: |
One SLX per Cloudflare zone. Operators supply CLOUDFLARE_ZONE_ID (and optionally
account context). Future generation rules may discover zones via the Accounts API
when an account-level token is available.
resource_types:
- "cloudflare_zone"
generation_strategy: |
Target resource type cloudflare_zone with qualifier zone identifier. Match RunWhen
resources representing monitored Cloudflare zones (manual registration or future
discovery from Cloudflare Accounts/Zones list APIs).
env_vars:
- name: CLOUDFLARE_ZONE_ID
description: "Cloudflare zone identifier (zone tag) to scope analytics queries"
required: true
- name: CLOUDFLARE_ACCOUNT_ID
description: "Cloudflare account identifier when required by GraphQL dataset filters"
required: false
- name: WAF_LOOKBACK_MINUTES
description: "Length of the primary analytics window in minutes"
required: false
default: "60"
- name: WAF_COMPARE_LOOKBACK_MINUTES
description: "Optional prior window for simple spike/baseline comparison (0 disables)"
required: false
default: "60"
- name: WAF_TOTAL_EVENTS_ISSUE_THRESHOLD
description: "Raise an issue when total WAF/security actions in the window exceed this count"
required: false
default: "500"
- name: WAF_TOP_ENTITY_ISSUE_THRESHOLD
description: "Raise when any single IP, rule ID, or path bucket exceeds this count"
required: false
default: "100"
- name: WAF_SPIKE_RATIO_THRESHOLD
description: "Optional ratio (e.g. 2.0) of primary window to prior window; issue if exceeded"
required: false
default: "0"
- name: WAF_REPORT_TOP_N
description: "Number of top entities to include in tables (IPs, rules, paths)"
required: false
default: "15"
secrets:
- name: cloudflare_api_token
description: "Cloudflare API token with Analytics read and Zone/WAF appropriate scopes"
format: |
Plain text token or RunWhen secret; HTTP Authorization Bearer to api.cloudflare.com
and the GraphQL Analytics endpoint. Minimum scopes: Zone Analytics read and Zone
Firewall Services read (exact names per Cloudflare token templates).
platform:
name: "cloudflare"
cli_tools:
- "curl"
- "jq"
auth_methods:
- "API Token (cloudflare_api_token Bearer auth)"
api_docs: "https://developers.cloudflare.com/analytics/graphql-api/"
related_bundles:
- name: "gcp-project-cost-health"
relationship: "complements"
notes: |
Establishes the same multi-task reporting + JSON issue pattern with configurable
thresholds; reuse bash+json issue emission and Robot task structure.
- name: "gcloud-log-inspection"
relationship: "complements"
notes: |
Similar log aggregation and “top N” correlation story on a different platform;
applicable for jq patterns and issue text quality.
- name: "vercel-project-health"
relationship: "overlaps"
notes: |
Edge traffic health on another provider; does not query Cloudflare WAF—different
data plane but adjacent operational concerns.
test_scenarios:
- name: "quiet_zone"
description: "Zone with no or minimal firewall events below all thresholds"
expected_issues: 0
- name: "concentrated_block_spike"
description: "Synthetic fixture with one rule ID and one IP exceeding top-entity threshold"
expected_issues: 2
expected_severities: [3, 3]
- name: "high_volume_distributed"
description: "Many low-volume sources that sum above total threshold"
expected_issues: 1
expected_severities: [3]
notes: |
Use the GraphQL Analytics API firewall/security event fields documented by Cloudflare;
dataset names and filters evolve—implementations should pin to the documented schema for
firewallEventsAdaptive / security event equivalents and degrade gracefully on empty
result sets. Prefer read-only Analytics and Zone APIs only; no configuration changes.
If GraphQL quota or sampling limits apply, document effective limits in the README.
Design Spec: cloudflare-zone-waf-report
Parent: #111
Target:
runwhen-contrib/rw-cli-codecollectionSpec