diff --git a/zddc/internal/handler/auth_invariants_test.go b/zddc/internal/handler/auth_invariants_test.go index 9d06c06..7197824 100644 --- a/zddc/internal/handler/auth_invariants_test.go +++ b/zddc/internal/handler/auth_invariants_test.go @@ -459,8 +459,53 @@ func TestInvariant_UnelevatedAdminNoSilentBypass(t *testing.T) { func TestInvariant_ProfileAdminEndpointsHideFromNonAdmins(t *testing.T) { // These checks lock in the existence-hiding property: non-admins must - // see 404, never 403, so they can't probe which paths exist. - t.Skip("requires the profile handler dispatcher entry point; skip until the refactor confirms ServeProfile signature") + // see 404, never 403, so they can't probe which admin-only resources + // exist. ServeProfile is the dispatcher (the refactor this test waited + // on); its adminOnly wrapper denies with 404 before the sub-handler + // runs, so a nil ring/index is safe for the non-admin paths. + cfg, _ := invariantsFixture(t) + + adminEndpoints := []string{"/whoami", "/config", "/logs", "/effective-policy", "/reindex"} + + profileGet := func(sub, email string, elevated bool) *httptest.ResponseRecorder { + req := httptest.NewRequest(http.MethodGet, ProfilePathPrefix+sub, nil) + ctx := context.WithValue(req.Context(), EmailKey, email) + ctx = context.WithValue(ctx, ElevatedKey, elevated) + req = req.WithContext(ctx) + rec := httptest.NewRecorder() + ServeProfile(cfg, nil, nil, rec, req) + return rec + } + + // Non-admin (eve, project_team only) and anonymous callers must get + // 404 on every admin endpoint — never 403, never 200. + for _, who := range []struct { + email string + elevated bool + label string + }{ + {"eve@example.com", false, "non-admin"}, + {"", false, "anonymous"}, + {"admin@example.com", false, "un-elevated admin"}, // sudo-style: no authority until elevated + } { + for _, sub := range adminEndpoints { + rec := profileGet(sub, who.email, who.elevated) + if rec.Code != http.StatusNotFound { + t.Errorf("%s GET /.profile%s = %d, want 404 (existence-hiding)", who.label, sub, rec.Code) + } + } + } + + // Positive control: an elevated root admin must NOT get 404 on the + // gated routes that need no ring/index — proving the 404s above are + // the admin gate, not a missing route. (/whoami and /config don't + // touch the log ring or archive index.) + for _, sub := range []string{"/whoami", "/config"} { + rec := profileGet(sub, "admin@example.com", true) + if rec.Code == http.StatusNotFound { + t.Errorf("elevated admin GET /.profile%s = 404; the gate should admit admins", sub) + } + } } // dump prints the rec body when t.Logf would help debugging — used in