chore: pre-migration snapshot
Layer0, MCP servers, Terraform consolidation
This commit is contained in:
393
scripts/waf-and-plan-invariants.sh
Normal file
393
scripts/waf-and-plan-invariants.sh
Normal file
@@ -0,0 +1,393 @@
|
||||
#!/usr/bin/env bash
|
||||
# ============================================================================
|
||||
# WAF + PLAN INVARIANTS CHECKER
|
||||
# ============================================================================
|
||||
# Enforces security+plan gating invariants for VaultMesh Cloudflare IaC.
|
||||
# Run from repo root: bash scripts/waf-and-plan-invariants.sh
|
||||
#
|
||||
# Exit codes:
|
||||
# 0 = All invariants pass
|
||||
# 1 = One or more invariants violated
|
||||
#
|
||||
# Governed by: RED-BOOK.md
|
||||
# ============================================================================
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
cd "$REPO_ROOT"
|
||||
|
||||
# Colors
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
NC='\033[0m'
|
||||
|
||||
echo "============================================"
|
||||
echo " VaultMesh WAF + Plan Invariants Check"
|
||||
echo "============================================"
|
||||
echo ""
|
||||
|
||||
FAILED=0
|
||||
|
||||
echo "── 0. Toolchain Versions ──"
|
||||
terraform version || true
|
||||
python3 --version || true
|
||||
python3 -m pip --version || true
|
||||
python3 -m pytest --version || true
|
||||
python3 -m mcp.waf_intelligence --version || true
|
||||
|
||||
echo ""
|
||||
|
||||
echo "── 1. WAF Intel Analyzer Regression ──"
|
||||
if python3 -m pytest -q tests/test_waf_intelligence_analyzer.py; then
|
||||
echo -e "${GREEN}✓${NC} 1.1 Analyzer regression test passed"
|
||||
else
|
||||
echo -e "${RED}✗${NC} 1.1 Analyzer regression test failed"
|
||||
FAILED=1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "── 2. WAF Intel CLI Contract ──"
|
||||
|
||||
TMP_DIR="${TMPDIR:-/tmp}"
|
||||
WAF_JSON_FILE="$(mktemp -p "$TMP_DIR" waf-intel.XXXXXX.json)"
|
||||
if python3 -m mcp.waf_intelligence --file terraform/waf.tf --format json --limit 5 >"$WAF_JSON_FILE"; then
|
||||
if python3 - "$WAF_JSON_FILE" <<'PY'
|
||||
import json
|
||||
import sys
|
||||
|
||||
path = sys.argv[1]
|
||||
with open(path, "r", encoding="utf-8") as f:
|
||||
payload = json.load(f)
|
||||
|
||||
insights = payload.get("insights")
|
||||
if not isinstance(insights, list):
|
||||
raise SystemExit("waf_intel: insights is not a list")
|
||||
|
||||
if insights:
|
||||
raise SystemExit(f"waf_intel: expected 0 insights, got {len(insights)}")
|
||||
|
||||
print("ok")
|
||||
PY
|
||||
then
|
||||
echo -e "${GREEN}✓${NC} 2.1 WAF Intel JSON parses and insights are empty"
|
||||
else
|
||||
echo -e "${RED}✗${NC} 2.1 WAF Intel JSON contract violated"
|
||||
cat "$WAF_JSON_FILE"
|
||||
FAILED=1
|
||||
fi
|
||||
else
|
||||
echo -e "${RED}✗${NC} 2.1 WAF Intel CLI failed"
|
||||
FAILED=1
|
||||
fi
|
||||
rm -f "$WAF_JSON_FILE"
|
||||
|
||||
echo ""
|
||||
echo "── 3. Terraform Format + Validate + Plan Gates ──"
|
||||
|
||||
cd terraform
|
||||
|
||||
if terraform fmt -check -recursive >/dev/null 2>&1; then
|
||||
echo -e "${GREEN}✓${NC} 3.1 Terraform formatting OK"
|
||||
else
|
||||
echo -e "${RED}✗${NC} 3.1 Terraform formatting required"
|
||||
echo " Run: cd terraform && terraform fmt -recursive"
|
||||
FAILED=1
|
||||
fi
|
||||
|
||||
terraform init -backend=false -input=false >/dev/null 2>&1
|
||||
if terraform validate -no-color >/dev/null 2>&1; then
|
||||
echo -e "${GREEN}✓${NC} 3.2 Terraform validate OK"
|
||||
else
|
||||
echo -e "${RED}✗${NC} 3.2 Terraform validate failed"
|
||||
terraform validate -no-color
|
||||
FAILED=1
|
||||
fi
|
||||
|
||||
PLAN_FREE_OUT="$(mktemp -p "$TMP_DIR" tf-plan-free.XXXXXX.out)"
|
||||
PLAN_PRO_OUT="$(mktemp -p "$TMP_DIR" tf-plan-pro.XXXXXX.out)"
|
||||
PLAN_FREE_JSON="$(mktemp -p "$TMP_DIR" tf-plan-free.XXXXXX.json)"
|
||||
PLAN_PRO_JSON="$(mktemp -p "$TMP_DIR" tf-plan-pro.XXXXXX.json)"
|
||||
rm -f "$PLAN_FREE_OUT" "$PLAN_PRO_OUT"
|
||||
|
||||
if terraform plan -no-color -input=false -lock=false -refresh=false -out="$PLAN_FREE_OUT" -var-file=assurance_free.tfvars >/dev/null; then
|
||||
if terraform show -json "$PLAN_FREE_OUT" >"$PLAN_FREE_JSON"; then
|
||||
if output="$(
|
||||
python3 - "$PLAN_FREE_JSON" <<'PY'
|
||||
import json
|
||||
import sys
|
||||
|
||||
path = sys.argv[1]
|
||||
try:
|
||||
with open(path, "r", encoding="utf-8") as f:
|
||||
payload = json.load(f)
|
||||
except json.JSONDecodeError as e:
|
||||
print(f"json parse error: {e}")
|
||||
raise SystemExit(2)
|
||||
|
||||
resource_changes = payload.get("resource_changes")
|
||||
planned_values = payload.get("planned_values")
|
||||
|
||||
if not isinstance(resource_changes, list) or not isinstance(planned_values, dict):
|
||||
print("invalid plan json: missing resource_changes[] and/or planned_values{}")
|
||||
raise SystemExit(2)
|
||||
|
||||
addresses = [
|
||||
rc.get("address", "")
|
||||
for rc in resource_changes
|
||||
if isinstance(rc, dict) and isinstance(rc.get("address"), str)
|
||||
]
|
||||
|
||||
managed_waf = sum(1 for a in addresses if a.startswith("cloudflare_ruleset.managed_waf["))
|
||||
bot_mgmt = sum(1 for a in addresses if a.startswith("cloudflare_bot_management.domains["))
|
||||
|
||||
if managed_waf != 0 or bot_mgmt != 0:
|
||||
print(f"expected managed_waf=0 bot_management=0, got managed_waf={managed_waf} bot_management={bot_mgmt}")
|
||||
for addr in sorted(
|
||||
a
|
||||
for a in addresses
|
||||
if a.startswith("cloudflare_ruleset.managed_waf[") or a.startswith("cloudflare_bot_management.domains[")
|
||||
):
|
||||
print(f"- {addr}")
|
||||
raise SystemExit(2)
|
||||
PY
|
||||
)"; then
|
||||
echo -e "${GREEN}✓${NC} 3.3 Free-plan gate OK (managed_waf=0 bot_management=0)"
|
||||
else
|
||||
echo -e "${RED}✗${NC} 3.3 Free-plan gate violated"
|
||||
if [[ -n "${output:-}" ]]; then
|
||||
echo "$output" | sed 's/^/ /'
|
||||
fi
|
||||
FAILED=1
|
||||
fi
|
||||
else
|
||||
echo -e "${RED}✗${NC} 3.3 terraform show -json failed (free)"
|
||||
FAILED=1
|
||||
fi
|
||||
else
|
||||
echo -e "${RED}✗${NC} 3.3 Terraform plan failed (free)"
|
||||
terraform show -no-color "$PLAN_FREE_OUT" 2>/dev/null || true
|
||||
FAILED=1
|
||||
fi
|
||||
|
||||
if terraform plan -no-color -input=false -lock=false -refresh=false -out="$PLAN_PRO_OUT" -var-file=assurance_pro.tfvars >/dev/null; then
|
||||
if terraform show -json "$PLAN_PRO_OUT" >"$PLAN_PRO_JSON"; then
|
||||
if output="$(
|
||||
python3 - "$PLAN_PRO_JSON" <<'PY'
|
||||
import json
|
||||
import sys
|
||||
|
||||
path = sys.argv[1]
|
||||
try:
|
||||
with open(path, "r", encoding="utf-8") as f:
|
||||
payload = json.load(f)
|
||||
except json.JSONDecodeError as e:
|
||||
print(f"json parse error: {e}")
|
||||
raise SystemExit(2)
|
||||
|
||||
resource_changes = payload.get("resource_changes")
|
||||
planned_values = payload.get("planned_values")
|
||||
|
||||
if not isinstance(resource_changes, list) or not isinstance(planned_values, dict):
|
||||
print("invalid plan json: missing resource_changes[] and/or planned_values{}")
|
||||
raise SystemExit(2)
|
||||
|
||||
addresses = [
|
||||
rc.get("address", "")
|
||||
for rc in resource_changes
|
||||
if isinstance(rc, dict) and isinstance(rc.get("address"), str)
|
||||
]
|
||||
|
||||
managed_waf = sum(1 for a in addresses if a.startswith("cloudflare_ruleset.managed_waf["))
|
||||
bot_mgmt = sum(1 for a in addresses if a.startswith("cloudflare_bot_management.domains["))
|
||||
|
||||
if managed_waf != 1 or bot_mgmt != 1:
|
||||
print("expected managed_waf=1 bot_management=1")
|
||||
print(f"got managed_waf={managed_waf} bot_management={bot_mgmt}")
|
||||
print("observed:")
|
||||
for addr in sorted(
|
||||
a
|
||||
for a in addresses
|
||||
if a.startswith("cloudflare_ruleset.managed_waf[") or a.startswith("cloudflare_bot_management.domains[")
|
||||
):
|
||||
print(f"- {addr}")
|
||||
raise SystemExit(2)
|
||||
PY
|
||||
)"; then
|
||||
echo -e "${GREEN}✓${NC} 3.4 Paid-plan gate OK (managed_waf=1 bot_management=1)"
|
||||
else
|
||||
echo -e "${RED}✗${NC} 3.4 Paid-plan gate violated"
|
||||
if [[ -n "${output:-}" ]]; then
|
||||
echo "$output" | sed 's/^/ /'
|
||||
fi
|
||||
FAILED=1
|
||||
fi
|
||||
else
|
||||
echo -e "${RED}✗${NC} 3.4 terraform show -json failed (pro)"
|
||||
FAILED=1
|
||||
fi
|
||||
else
|
||||
echo -e "${RED}✗${NC} 3.4 Terraform plan failed (pro)"
|
||||
terraform show -no-color "$PLAN_PRO_OUT" 2>/dev/null || true
|
||||
FAILED=1
|
||||
fi
|
||||
|
||||
PLAN_NEG_FREE_OUT="$(mktemp -p "$TMP_DIR" tf-plan-neg-free.XXXXXX.out)"
|
||||
PLAN_NEG_PRO_OUT="$(mktemp -p "$TMP_DIR" tf-plan-neg-pro.XXXXXX.out)"
|
||||
PLAN_NEG_FREE_JSON="$(mktemp -p "$TMP_DIR" tf-plan-neg-free.XXXXXX.json)"
|
||||
PLAN_NEG_PRO_JSON="$(mktemp -p "$TMP_DIR" tf-plan-neg-pro.XXXXXX.json)"
|
||||
rm -f "$PLAN_NEG_FREE_OUT" "$PLAN_NEG_PRO_OUT"
|
||||
|
||||
echo ""
|
||||
echo "── 4. Negative Controls (Prove the gate bites) ──"
|
||||
|
||||
if terraform plan -no-color -input=false -lock=false -refresh=false -out="$PLAN_NEG_FREE_OUT" -var-file=assurance_negative_free_should_fail.tfvars >/dev/null; then
|
||||
if terraform show -json "$PLAN_NEG_FREE_OUT" >"$PLAN_NEG_FREE_JSON"; then
|
||||
if output="$(
|
||||
python3 - "$PLAN_NEG_FREE_JSON" <<'PY'
|
||||
import json
|
||||
import sys
|
||||
|
||||
path = sys.argv[1]
|
||||
try:
|
||||
with open(path, "r", encoding="utf-8") as f:
|
||||
payload = json.load(f)
|
||||
except json.JSONDecodeError as e:
|
||||
print(f"json parse error: {e}")
|
||||
raise SystemExit(2)
|
||||
|
||||
resource_changes = payload.get("resource_changes")
|
||||
planned_values = payload.get("planned_values")
|
||||
|
||||
if not isinstance(resource_changes, list) or not isinstance(planned_values, dict):
|
||||
print("invalid plan json: missing resource_changes[] and/or planned_values{}")
|
||||
raise SystemExit(2)
|
||||
|
||||
addresses = [
|
||||
rc.get("address", "")
|
||||
for rc in resource_changes
|
||||
if isinstance(rc, dict) and isinstance(rc.get("address"), str)
|
||||
]
|
||||
|
||||
managed_waf = sum(1 for a in addresses if a.startswith("cloudflare_ruleset.managed_waf["))
|
||||
bot_mgmt = sum(1 for a in addresses if a.startswith("cloudflare_bot_management.domains["))
|
||||
|
||||
if managed_waf != 0 or bot_mgmt != 0:
|
||||
print(f"expected managed_waf=0 bot_management=0, got managed_waf={managed_waf} bot_management={bot_mgmt}")
|
||||
for addr in sorted(
|
||||
a
|
||||
for a in addresses
|
||||
if a.startswith("cloudflare_ruleset.managed_waf[") or a.startswith("cloudflare_bot_management.domains[")
|
||||
):
|
||||
print(f"- {addr}")
|
||||
raise SystemExit(2)
|
||||
|
||||
print("ok")
|
||||
PY
|
||||
)"; then
|
||||
echo -e "${RED}✗${NC} 4.1 Negative free-plan control unexpectedly passed"
|
||||
FAILED=1
|
||||
else
|
||||
if [[ "${output:-}" == *"expected managed_waf=0 bot_management=0"* ]]; then
|
||||
echo -e "${GREEN}✓${NC} 4.1 Negative free-plan control failed as expected"
|
||||
else
|
||||
echo -e "${RED}✗${NC} 4.1 Negative free-plan control failed (unexpected error)"
|
||||
if [[ -n "${output:-}" ]]; then
|
||||
echo "$output" | sed 's/^/ /'
|
||||
fi
|
||||
FAILED=1
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo -e "${RED}✗${NC} 4.1 terraform show -json failed (negative free)"
|
||||
FAILED=1
|
||||
fi
|
||||
else
|
||||
echo -e "${RED}✗${NC} 4.1 Terraform plan failed (negative free)"
|
||||
FAILED=1
|
||||
fi
|
||||
|
||||
if terraform plan -no-color -input=false -lock=false -refresh=false -out="$PLAN_NEG_PRO_OUT" -var-file=assurance_negative_pro_should_fail.tfvars >/dev/null; then
|
||||
if terraform show -json "$PLAN_NEG_PRO_OUT" >"$PLAN_NEG_PRO_JSON"; then
|
||||
if output="$(
|
||||
python3 - "$PLAN_NEG_PRO_JSON" <<'PY'
|
||||
import json
|
||||
import sys
|
||||
|
||||
path = sys.argv[1]
|
||||
try:
|
||||
with open(path, "r", encoding="utf-8") as f:
|
||||
payload = json.load(f)
|
||||
except json.JSONDecodeError as e:
|
||||
print(f"json parse error: {e}")
|
||||
raise SystemExit(2)
|
||||
|
||||
resource_changes = payload.get("resource_changes")
|
||||
planned_values = payload.get("planned_values")
|
||||
|
||||
if not isinstance(resource_changes, list) or not isinstance(planned_values, dict):
|
||||
print("invalid plan json: missing resource_changes[] and/or planned_values{}")
|
||||
raise SystemExit(2)
|
||||
|
||||
addresses = [
|
||||
rc.get("address", "")
|
||||
for rc in resource_changes
|
||||
if isinstance(rc, dict) and isinstance(rc.get("address"), str)
|
||||
]
|
||||
|
||||
managed_waf = sum(1 for a in addresses if a.startswith("cloudflare_ruleset.managed_waf["))
|
||||
bot_mgmt = sum(1 for a in addresses if a.startswith("cloudflare_bot_management.domains["))
|
||||
|
||||
if managed_waf != 1 or bot_mgmt != 1:
|
||||
print("expected managed_waf=1 bot_management=1")
|
||||
print(f"got managed_waf={managed_waf} bot_management={bot_mgmt}")
|
||||
print("observed:")
|
||||
for addr in sorted(
|
||||
a
|
||||
for a in addresses
|
||||
if a.startswith("cloudflare_ruleset.managed_waf[") or a.startswith("cloudflare_bot_management.domains[")
|
||||
):
|
||||
print(f"- {addr}")
|
||||
raise SystemExit(2)
|
||||
|
||||
print("ok")
|
||||
PY
|
||||
)"; then
|
||||
echo -e "${RED}✗${NC} 4.2 Negative paid-plan control unexpectedly passed"
|
||||
FAILED=1
|
||||
else
|
||||
if [[ "${output:-}" == *"expected managed_waf=1 bot_management=1"* ]]; then
|
||||
echo -e "${GREEN}✓${NC} 4.2 Negative paid-plan control failed as expected"
|
||||
else
|
||||
echo -e "${RED}✗${NC} 4.2 Negative paid-plan control failed (unexpected error)"
|
||||
if [[ -n "${output:-}" ]]; then
|
||||
echo "$output" | sed 's/^/ /'
|
||||
fi
|
||||
FAILED=1
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo -e "${RED}✗${NC} 4.2 terraform show -json failed (negative pro)"
|
||||
FAILED=1
|
||||
fi
|
||||
else
|
||||
echo -e "${RED}✗${NC} 4.2 Terraform plan failed (negative pro)"
|
||||
FAILED=1
|
||||
fi
|
||||
|
||||
rm -f "$PLAN_FREE_OUT" "$PLAN_PRO_OUT" "$PLAN_FREE_JSON" "$PLAN_PRO_JSON" "$PLAN_NEG_FREE_OUT" "$PLAN_NEG_PRO_OUT" "$PLAN_NEG_FREE_JSON" "$PLAN_NEG_PRO_JSON"
|
||||
|
||||
cd "$REPO_ROOT"
|
||||
|
||||
echo ""
|
||||
echo "============================================"
|
||||
echo " Summary"
|
||||
echo "============================================"
|
||||
|
||||
if [[ $FAILED -gt 0 ]]; then
|
||||
echo -e "${RED}WAF + plan invariants violated. Fix before merging.${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}All WAF + plan invariants pass. ✓${NC}"
|
||||
exit 0
|
||||
Reference in New Issue
Block a user