From 7c1d0dc5683caf664e4ba98bf6685c306f61e9bc Mon Sep 17 00:00:00 2001 From: Emil Date: Mon, 3 Aug 2026 01:34:22 +0300 Subject: [PATCH] Tell non-admins why the console is off-limits instead of bouncing them to the dashboard --- coordinator/internal/transport/http/ui_admin.go | 8 +++++--- .../internal/transport/http/ui_admin_internal_test.go | 6 +++--- install.ps1 | 2 +- install.sh | 2 +- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/coordinator/internal/transport/http/ui_admin.go b/coordinator/internal/transport/http/ui_admin.go index 29d2f14..0234bd1 100644 --- a/coordinator/internal/transport/http/ui_admin.go +++ b/coordinator/internal/transport/http/ui_admin.go @@ -26,12 +26,14 @@ var adminUserActions = map[string]bool{ } // requireAdmin gates a route on the session caller being an admin. It runs -// inside withUISession, which has already stamped the requester. A non-admin is -// sent back to the dashboard rather than shown the panel. +// inside withUISession, which has already stamped the requester. A signed-in +// non-admin is told why (and bounced to the login with the message); an +// unauthenticated caller never gets here — the gate has already sent them to +// the login page with the intended destination. func requireAdmin(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if req, ok := authctx.From(r.Context()); !ok || !req.IsAdmin() { - http.Redirect(w, r, "/ui", http.StatusSeeOther) + http.Redirect(w, r, "/ui/login?error=admin+role+required", http.StatusSeeOther) return } next.ServeHTTP(w, r) diff --git a/coordinator/internal/transport/http/ui_admin_internal_test.go b/coordinator/internal/transport/http/ui_admin_internal_test.go index 92f3c27..d55bb1d 100644 --- a/coordinator/internal/transport/http/ui_admin_internal_test.go +++ b/coordinator/internal/transport/http/ui_admin_internal_test.go @@ -30,15 +30,15 @@ func TestRequireAdminAllowsAdminOnly(t *testing.T) { t.Error("admin must reach the handler") } - // Plain user is redirected to the dashboard. + // Plain user is redirected to the login with the reason. reached = false rec := httptest.NewRecorder() h.ServeHTTP(rec, adminReq(t, "user")) if reached { t.Error("non-admin must not reach the handler") } - if rec.Code != http.StatusSeeOther || rec.Header().Get("Location") != "/ui" { - t.Errorf("non-admin got %d -> %q, want 303 -> /ui", rec.Code, rec.Header().Get("Location")) + if rec.Code != http.StatusSeeOther || rec.Header().Get("Location") != "/ui/login?error=admin+role+required" { + t.Errorf("non-admin got %d -> %q, want 303 -> login with the admin-required error", rec.Code, rec.Header().Get("Location")) } } diff --git a/install.ps1 b/install.ps1 index 41fbd51..12d2d65 100644 --- a/install.ps1 +++ b/install.ps1 @@ -65,7 +65,7 @@ Write-Host "SciMesh $Component installed: $Target" Write-Host "" if ($Component -eq "coordinator") { if ($AutoStart -eq "1") { - Write-Host "Starting the platform and opening the control room in your browser..." + Write-Host "Starting the platform and opening the admin console in your browser..." Write-Host "(stop it with Ctrl-C; it keeps your data in ~\.scimesh)" Write-Host "" & $Target serve --open diff --git a/install.sh b/install.sh index 9b658b0..697b997 100644 --- a/install.sh +++ b/install.sh @@ -78,7 +78,7 @@ fi if [ "$COMPONENT" = "coordinator" ]; then if [ "$AUTO_START" = "1" ]; then echo - echo "Starting the platform and opening the control room in your browser..." + echo "Starting the platform and opening the admin console in your browser..." echo "(stop it with Ctrl-C; it keeps your data in ~/.scimesh)" echo exec "$TARGET" serve --open