#!/usr/bin/env bash # validate-audit-report.sh # Structural + semantic validation for CODEX audit reports. set -euo pipefail REPORT_PATH="${1:-CODEX-REPORT.md}" if [[ ! -f "$REPORT_PATH" ]]; then echo "[validate-audit-report] Missing report: $REPORT_PATH" exit 1 fi FAILURES=0 # --- Check 1: Required sections exist --- required_sections=( "## Requirements Mapping" "## Constitution Compliance Matrix" "## Evidence" "## Risks" ) for section in "${required_sections[@]}"; do if command -v rg >/dev/null 2>&1; then if ! rg -q "^${section//\//\\/}$" "$REPORT_PATH"; then echo "[validate-audit-report] Missing section: $section" FAILURES=$((FAILURES + 1)) fi else if ! grep -Eq "^${section//\//\\/}$" "$REPORT_PATH"; then echo "[validate-audit-report] Missing section: $section" FAILURES=$((FAILURES + 1)) fi fi done # --- Check 2: Reject forbidden placeholders --- forbidden_patterns=("TODO" "TBD" "UNMAPPED" "PLACEHOLDER" "FIXME") for pattern in "${forbidden_patterns[@]}"; do if command -v rg >/dev/null 2>&1; then count="$(rg -c "$pattern" "$REPORT_PATH" 2>/dev/null || echo 0)" else count="$(grep -c "$pattern" "$REPORT_PATH" 2>/dev/null || echo 0)" fi if [[ "$count" -gt 0 ]]; then echo "[validate-audit-report] Forbidden placeholder '$pattern' found ($count occurrences)" FAILURES=$((FAILURES + 1)) fi done # --- Check 3: Non-empty sections (at least 1 non-blank line after heading) --- for section in "${required_sections[@]}"; do # Extract content between this heading and the next ## heading (or EOF) section_escaped="${section//\//\\/}" content="" if command -v awk >/dev/null 2>&1; then content="$(awk "/^${section_escaped}\$/{found=1; next} found && /^## /{exit} found{print}" "$REPORT_PATH" | grep -v '^[[:space:]]*$' || true)" fi if [[ -z "$content" ]]; then echo "[validate-audit-report] Section is empty: $section" FAILURES=$((FAILURES + 1)) fi done # --- Check 4: Requirements mapping has entries (table rows or list items) --- req_entries="$(awk '/^## Requirements Mapping$/{found=1; next} found && /^## /{exit} found && /^\|[^-]/{print} found && /^- /{print}' "$REPORT_PATH" | wc -l | tr -d ' ')" if [[ "$req_entries" -lt 1 ]]; then echo "[validate-audit-report] Requirements Mapping has no entries (expected table rows or list items)" FAILURES=$((FAILURES + 1)) fi # --- Result --- if [[ $FAILURES -gt 0 ]]; then echo "[validate-audit-report] FAILED ($FAILURES issues)" exit 1 fi echo "[validate-audit-report] PASS ($REPORT_PATH)"