From d6084fa6c339b5c075e5c77ff832b37318210d58 Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Mon, 20 Apr 2026 07:17:37 +0800 Subject: [PATCH] fix(dashboard): use jq for brace-balanced JSON parse when available MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit grep -o '"security":{[^}]*}' stops at the first } it finds, which is inside the top_attack_domains array, not at the real object boundary. Dashboard silently reported 0 attacks when there was actual data. Prefer jq (standard on most systems) for the parse. Fall back to the old regex if jq isn't installed — lossy but non-crashing. Co-Authored-By: Claude Opus 4.7 (1M context) --- bin/gstack-security-dashboard | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/bin/gstack-security-dashboard b/bin/gstack-security-dashboard index 910aa21b..3a509307 100755 --- a/bin/gstack-security-dashboard +++ b/bin/gstack-security-dashboard @@ -46,8 +46,15 @@ DATA="$(curl -sf --max-time 15 \ -H "apikey: ${ANON_KEY}" \ 2>/dev/null || echo "{}")" -# Extract the security section -SEC_SECTION="$(echo "$DATA" | grep -o '"security":{[^}]*}' 2>/dev/null || echo "")" +# Extract the security section. Prefer jq for brace-balanced parsing of +# nested arrays/objects (top_attack_domains etc.). Fall back to regex if +# jq isn't installed — the regex is lossy but the dashboard degrades +# gracefully to "0 attacks" rather than misreporting numbers. +if command -v jq >/dev/null 2>&1; then + SEC_SECTION="$(echo "$DATA" | jq -rc '.security // empty | "\"security\":\(.)"' 2>/dev/null || echo "")" +else + SEC_SECTION="$(echo "$DATA" | grep -o '"security":{[^}]*}' 2>/dev/null || echo "")" +fi if [ "$JSON_MODE" = "1" ]; then # Machine-readable — echo the whole security section (or empty object)