Skip to main content
← Back to list
01Issue
BugShippedSwamp CLIPublic
Assigneesstack72

Relationships

#2504 dashboard: Schedules/Webhooks views are empty for non-admins -- the health stream needs admin on access:* and the 403 is swallowed

Opened by randybias · 9/24/2026· Shipped 9/28/2026

Problem

For any dashboard user who is not an administrator, the Schedules and Webhooks views, and the overview's health pill, are empty. The Schedules view says "No schedules configured" even when schedules are registered and firing.

Cause (read at ad0aa46, measured on 20260923.231117.0)

  • These views read the health object that f0() streams from /api/v1/health/stream (SSE).
  • That endpoint calls authenticateAdmin (src/cli/commands/serve.ts:4696), which requires admin on access:* (src/serve/admin_auth.ts:140-148).
  • A non-admin token gets HTTP 403 {"message":"Access denied: requires admin permission"}.
  • The dashboard's stream reader swallows the error (catch{}), and the views render their empty state.

Measured with two tokens against the same server:

token /api/v1/health/stream Schedules view
admin 200, text/event-stream, 3 events in 14 s, scheduling.schedules lists mircloud-sweep-cabling-drift 0 5 * * * shows it
operator (grants run, read, approve on workflow:*; read on model:*) 403 "No schedules configured"

GET /health (unauthenticated) returns the same scheduling block, so the data is not secret.

Why it matters

The only permission that unlocks the view is full admin on access:*, which also allows minting tokens and changing grants. An operator who can run and approve workflows cannot see when the next scheduled run fires, and the dashboard tells them nothing is scheduled. That is worse than an error.

Ask

  1. Gate the health stream (or at least its scheduling and webhooks parts) on read, not admin.
  2. When a view's data request is refused, show "access denied", never the empty state.
02Bog Flow
✓OPEN✓TRIAGED✓IN PROGRESS✓SHIPPED+ 1 MOREASSIGNED+ 11 MOREREVIEW+ 17 MOREPR_MERGED+ 2 MORESESSION_SUMMARIZED

Shipped

9/28/2026, 10:32:08 PM

Click a lifecycle step above to view its details.

03Sludge Pulse
stack72 assigned stack729/28/2026, 9:10:11 PM
Editable. Press Enter to edit.

stack72 commented 9/28/2026, 10:33:34 PM

Thanks @randybias for reporting this! We shipped: Let any valid token read the health snapshot and stream by splitting a token-only authenticateToken out of authenticateAdmin. Register each SSE health stream as a token session in the existing registry so revoke, rotate, expiry and principal deprovisioning end it through the same paths as WebSocket sessions, and cap open streams per token at 10 with a 429 above it. Make the dashboard health stream report denied and retry transient failures, and show Access denied or Loading rather than the empty state.. The fix has been merged and a release is on its way. We appreciate your contribution to swamp.

Sign in to post a ripple.