The community security dashboard fails OPEN on a security-signaling surface: a
backend error, an unreachable backend, or a host without `jq` all render a
reassuring "Attacks detected last 7 days: 0 / Good news" that is
indistinguishable from a genuine zero. A user glances at the shield and
concludes there is no prompt-injection activity when the real state is unknown.
This is the same fail-open class the project's "4 security guards failing open"
wave (9cc41b71) corrected elsewhere.
Two layers fixed so the surface fails CLOSED:
- community-pulse edge function: the catch block returned all-zero aggregates
with HTTP 200. It now tags the body with an explicit `error: true` flag (top
level and inside `security`) so consumers can tell an internal failure apart
from a real zero. Status stays 200 so existing `curl -sf` clients still get
the body and can read the flag.
- gstack-security-dashboard: now captures curl's exit code and detects the
degraded states (unreachable backend, `error: true` flag, missing security
section, or `jq` absent) up front. In any degraded state it renders
"Attacks detected last 7 days: unknown (Degraded: <reason>...)" in human mode
and `{"error":"security_data_unavailable","security":null}` in --json mode,
instead of a fake all-zero payload. A genuine zero still reads as
"0 / Good news". The attack count is now read via an exact `jq` path
(`.security.attacks_last_7_days`) rather than a two-stage grep that also
mis-matched the "7" inside "last_7_days".
The latent telemetry `error_message` redaction concern noted in the issue is a
separate subsystem and left for a follow-up.
Adds test/security-dashboard.test.ts (5 tests, proven to fail on main):
unreachable, explicit-error, --json degraded, genuine-zero, and healthy non-zero.
Fixes#1947
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>