- Update dbis_core, cross-chain-pmm-lps, explorer-monorepo, metamask-integration, pr-workspace/chains - Omit embedded publish git dirs and empty placeholders from index Made-with: Cursor
231 lines
7.1 KiB
Bash
231 lines
7.1 KiB
Bash
#!/usr/bin/env bash
|
|
# Generate a markdown remediation plan for current public 502 and DNS gaps.
|
|
# Uses config/public-surface-remediation-map.json plus the latest public E2E run by default.
|
|
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
|
EVIDENCE_DIR="$PROJECT_ROOT/docs/04-configuration/verification-evidence"
|
|
MAP_FILE_DEFAULT="$PROJECT_ROOT/config/public-surface-remediation-map.json"
|
|
|
|
usage() {
|
|
cat <<'EOF'
|
|
Usage: bash scripts/verify/generate-public-surface-remediation-plan.sh [--e2e-json PATH] [--map PATH] [--output PATH] [--print]
|
|
|
|
Defaults:
|
|
--e2e-json Latest docs/04-configuration/verification-evidence/e2e-verification-*/all_e2e_results.json
|
|
--map config/public-surface-remediation-map.json
|
|
--output docs/04-configuration/verification-evidence/public-surface-remediation-YYYYMMDD_HHMMSS.md
|
|
EOF
|
|
}
|
|
|
|
find_latest_e2e_json() {
|
|
local latest_dir
|
|
latest_dir="$(ls -1dt "$EVIDENCE_DIR"/e2e-verification-* 2>/dev/null | head -n1 || true)"
|
|
if [[ -z "$latest_dir" ]]; then
|
|
return 1
|
|
fi
|
|
printf '%s\n' "$latest_dir/all_e2e_results.json"
|
|
}
|
|
|
|
dns_resolution() {
|
|
local domain="$1"
|
|
local results=""
|
|
if command -v getent >/dev/null 2>&1; then
|
|
results="$(getent ahosts "$domain" 2>/dev/null | awk '{print $1}' | sort -u | paste -sd ',' -)"
|
|
fi
|
|
if [[ -z "$results" ]] && command -v dig >/dev/null 2>&1; then
|
|
results="$(dig +short "$domain" 2>/dev/null | grep -E '^[0-9a-fA-F:.]+$' | sort -u | paste -sd ',' -)"
|
|
fi
|
|
printf '%s\n' "$results"
|
|
}
|
|
|
|
E2E_JSON=""
|
|
MAP_FILE="$MAP_FILE_DEFAULT"
|
|
OUTPUT=""
|
|
PRINT_REPORT=0
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--e2e-json)
|
|
E2E_JSON="$2"
|
|
shift 2
|
|
;;
|
|
--map)
|
|
MAP_FILE="$2"
|
|
shift 2
|
|
;;
|
|
--output)
|
|
OUTPUT="$2"
|
|
shift 2
|
|
;;
|
|
--print)
|
|
PRINT_REPORT=1
|
|
shift
|
|
;;
|
|
-h|--help)
|
|
usage
|
|
exit 0
|
|
;;
|
|
*)
|
|
echo "Unknown argument: $1" >&2
|
|
usage >&2
|
|
exit 2
|
|
;;
|
|
esac
|
|
done
|
|
|
|
if [[ -z "$E2E_JSON" ]]; then
|
|
E2E_JSON="$(find_latest_e2e_json || true)"
|
|
fi
|
|
|
|
if [[ -z "$E2E_JSON" || ! -f "$E2E_JSON" ]]; then
|
|
echo "Could not locate an E2E JSON report. Pass --e2e-json explicitly." >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [[ ! -f "$MAP_FILE" ]]; then
|
|
echo "Remediation map not found: $MAP_FILE" >&2
|
|
exit 1
|
|
fi
|
|
|
|
TIMESTAMP="$(date +%Y%m%d_%H%M%S)"
|
|
if [[ -z "$OUTPUT" ]]; then
|
|
OUTPUT="$EVIDENCE_DIR/public-surface-remediation-$TIMESTAMP.md"
|
|
fi
|
|
|
|
mkdir -p "$(dirname "$OUTPUT")"
|
|
|
|
TMP_REPORT="$(mktemp)"
|
|
SUMMARY_FILE="$(mktemp)"
|
|
DETAILS_FILE="$(mktemp)"
|
|
trap 'rm -f "$TMP_REPORT" "$SUMMARY_FILE" "$DETAILS_FILE"' EXIT
|
|
|
|
{
|
|
echo "# Public surface remediation plan"
|
|
echo ""
|
|
echo "- Generated: $(date -Iseconds)"
|
|
echo "- E2E source: \`$E2E_JSON\`"
|
|
echo "- Remediation map: \`$MAP_FILE\`"
|
|
echo ""
|
|
echo "## Summary"
|
|
echo ""
|
|
echo "| Surface | Domains | Live observation | Classification | Upstream | Primary fix |"
|
|
echo "|---------|---------|------------------|----------------|----------|-------------|"
|
|
} > "$TMP_REPORT"
|
|
|
|
surface_count="$(jq '.surfaces | length' "$MAP_FILE")"
|
|
active_count=0
|
|
|
|
for idx in $(seq 0 $((surface_count - 1))); do
|
|
surface_json="$(jq ".surfaces[$idx]" "$MAP_FILE")"
|
|
id="$(printf '%s\n' "$surface_json" | jq -r '.id')"
|
|
classification="$(printf '%s\n' "$surface_json" | jq -r '.classification')"
|
|
expected_service="$(printf '%s\n' "$surface_json" | jq -r '.expectedService')"
|
|
status_policy="$(printf '%s\n' "$surface_json" | jq -r '.statusPolicy')"
|
|
repo_solution="$(printf '%s\n' "$surface_json" | jq -r '.repoSolution')"
|
|
upstream_desc="$(printf '%s\n' "$surface_json" | jq -r '.upstream | "\(.vmid) @ \(.host) -> \(.ip):\(.port)"')"
|
|
domains_csv="$(printf '%s\n' "$surface_json" | jq -r '.domains | join(", ")')"
|
|
|
|
observations=()
|
|
active_issue=0
|
|
effective_solution="$repo_solution"
|
|
optional_surface=0
|
|
all_domains_unpublished=1
|
|
if [[ "$status_policy" == "keep_optional_until_real_service_deployed" ]]; then
|
|
optional_surface=1
|
|
fi
|
|
|
|
while IFS= read -r domain; do
|
|
[[ -z "$domain" ]] && continue
|
|
dns_ips="$(dns_resolution "$domain")"
|
|
e2e_http_code="$(jq -r --arg domain "$domain" 'map(select(.domain == $domain))[0].tests.https.http_code // empty' "$E2E_JSON")"
|
|
e2e_https_status="$(jq -r --arg domain "$domain" 'map(select(.domain == $domain))[0].tests.https.status // empty' "$E2E_JSON")"
|
|
|
|
if [[ -z "$dns_ips" ]]; then
|
|
observations+=("$domain: no public DNS answer")
|
|
if [[ $optional_surface -ne 1 ]]; then
|
|
active_issue=1
|
|
fi
|
|
continue
|
|
fi
|
|
all_domains_unpublished=0
|
|
|
|
if [[ -n "$e2e_http_code" ]]; then
|
|
if [[ "$e2e_http_code" == "502" ]]; then
|
|
observations+=("$domain: HTTPS 502, DNS $dns_ips")
|
|
active_issue=1
|
|
else
|
|
observations+=("$domain: HTTPS ${e2e_http_code} (${e2e_https_status:-ok}), DNS $dns_ips")
|
|
fi
|
|
else
|
|
observations+=("$domain: DNS $dns_ips, not in current E2E inventory")
|
|
fi
|
|
done < <(printf '%s\n' "$surface_json" | jq -r '.domains[]')
|
|
|
|
observation_text="$(printf '%s\n' "${observations[@]}" | awk 'NR==1{printf "%s",$0; next}{printf "; %s",$0}')"
|
|
if [[ $active_issue -eq 0 ]]; then
|
|
if [[ "$classification" == "public_502_backend" ]]; then
|
|
effective_solution="Currently healthy. Keep the upstream, proxy rows, and public E2E verifier aligned so any future regression is caught quickly."
|
|
elif [[ "$classification" == "public_edge_ok" ]]; then
|
|
effective_solution="Currently healthy. Keep the documented upstream, proxy rows, and verification checks aligned."
|
|
elif [[ "$classification" == "placeholder_surface" && $optional_surface -eq 1 && $all_domains_unpublished -eq 1 ]]; then
|
|
effective_solution="Currently unpublished as intended. Only publish these hostnames after the real service is deployed and verified."
|
|
fi
|
|
fi
|
|
if [[ $active_issue -eq 1 ]]; then
|
|
active_count=$((active_count + 1))
|
|
fi
|
|
|
|
printf '| `%s` | `%s` | %s | `%s` | `%s` | %s |\n' \
|
|
"$id" \
|
|
"$domains_csv" \
|
|
"$observation_text" \
|
|
"$classification" \
|
|
"$upstream_desc" \
|
|
"$effective_solution" >> "$SUMMARY_FILE"
|
|
|
|
{
|
|
echo ""
|
|
echo "## $id"
|
|
echo ""
|
|
echo "- Expected service: $expected_service"
|
|
echo "- Status policy: \`$status_policy\`"
|
|
echo "- Upstream: \`$upstream_desc\`"
|
|
echo "- Live observation: $observation_text"
|
|
echo "- Repo solution: $effective_solution"
|
|
echo "- Scripts:"
|
|
printf '%s\n' "$surface_json" | jq -r '.scripts[]' | while IFS= read -r path; do
|
|
echo " - \`$path\`"
|
|
done
|
|
echo "- Commands:"
|
|
printf '%s\n' "$surface_json" | jq -r '.commands[]' | while IFS= read -r cmd; do
|
|
echo " - \`$cmd\`"
|
|
done
|
|
echo "- Docs:"
|
|
printf '%s\n' "$surface_json" | jq -r '.docs[]' | while IFS= read -r path; do
|
|
echo " - \`$path\`"
|
|
done
|
|
} >> "$DETAILS_FILE"
|
|
done
|
|
|
|
{
|
|
cat "$SUMMARY_FILE"
|
|
cat "$DETAILS_FILE"
|
|
echo ""
|
|
echo "## Totals"
|
|
echo ""
|
|
echo "- Active issue groups in this report: $active_count"
|
|
echo "- Total mapped surfaces: $surface_count"
|
|
} >> "$TMP_REPORT"
|
|
|
|
mv "$TMP_REPORT" "$OUTPUT"
|
|
trap - EXIT
|
|
|
|
echo "Wrote remediation plan: $OUTPUT"
|
|
|
|
if [[ "$PRINT_REPORT" -eq 1 ]]; then
|
|
cat "$OUTPUT"
|
|
fi
|