__tests__/admin.test.js
Rama main · réplica de lectura del repositorio original.
/**
* Superadmin overview — the platform (my-app) superadmin's cross-tenant foundation. Each GB pod is one
* owner's isolated instance; the platform dashboard fans out to every pod's read-only /v1/admin/overview
* and stitches Users / Flows / Roles together. The endpoint must be READ-ONLY and gated by the SSO
* identity (email in SUPERADMIN_USERS) — never the console owner or a bearer key — so the view travels
* with the platform login. Token verification itself is covered by sso.test.js.
*/
import { describe, it, expect } from 'vitest';
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'url';
const src = fs.readFileSync(
path.join(path.dirname(fileURLToPath(import.meta.url)), '..', 'src', 'server.js'), 'utf8');
describe('superadmin overview endpoint', () => {
it('exposes a read-only GET /v1/admin/overview (no mutating verb on the admin surface)', () => {
expect(src).toMatch(/app\.get\(\s*['"]\/v1\/admin\/overview['"]/);
expect(src).not.toMatch(/app\.(post|put|delete)\(\s*['"]\/v1\/admin\//);
});
it('is gated by the SSO superadmin identity, not the console owner or an API key', () => {
expect(src).toContain('function superadminGate');
expect(src).toContain('SUPERADMIN_USERS');
expect(src).toContain('sso.verifyLeadflowToken');
expect(src).toMatch(/\/v1\/admin\/overview['"]\s*,\s*superadminGate/);
});
it('reports the owner, flows and created roles — the three superadmin pages', () => {
// the overview stitches into Users(owner) / Flows(workflows) / Roles(userRoles)
expect(src).toMatch(/owner:\s*acct/);
expect(src).toContain('workflows.all()');
expect(src).toContain('userRoles.all()');
});
it('provides a superadmin-gated aggregator that fans out to tenant pods', () => {
expect(src).toMatch(/app\.get\(\s*['"]\/v1\/admin\/tenants-overview['"]\s*,\s*superadminGate/);
expect(src).toContain('GB_TENANT_URLS');
// fans out to each tenant's own overview (server-side, sidestepping pod isolation + CORS)
expect(src).toMatch(/fetch\(base \+ ['"]\/v1\/admin\/overview['"]/);
});
});
describe('SSO isolation — one browser, one owner', () => {
it('the SSO route refuses a LeadFlow user who is neither the owner nor a superadmin', () => {
// a mismatched identity must be rejected, never logged in as the owner (which would share sessions);
// the real owner (same identity) and a superadmin are the only ones allowed through.
expect(src).toContain('const who = sso.ownerName(claims)');
expect(src).toContain('const sameOwner = String(who).toLowerCase() === String(rec.username).toLowerCase()');
expect(src).toContain('if (!sameOwner && !isSuper)');
expect(src).toMatch(/belongs to another account/);
expect(src).toMatch(/status\(403\)/);
});
});
/*
* THE RED 403 ON EVERY PAGE LOAD.
*
* The dashboard decided whether to show the Superadmin nav by CALLING /v1/admin/overview and
* catching the refusal. It worked, and it meant every ordinary sign-in printed a red 403 in the
* browser's console — noise that reads exactly like a broken page, and which twice sent the owner
* hunting a bug that was not there while a real one was in front of her.
*
* A question about who you are belongs on the route that answers who you are.
*/
describe('the console asks who it is, instead of being refused', () => {
const here = path.dirname(fileURLToPath(import.meta.url));
const read2 = (...p) => fs.readFileSync(path.join(here, '..', ...p), 'utf8');
const srv = read2('src', 'server.js');
const dash = read2('public', 'js', 'dashboard.js');
it('the sign-in state says whether this login is a superadmin', () => {
const at = srv.indexOf("app.get('/api/auth/state'");
expect(at).toBeGreaterThan(0);
expect(srv.slice(at, at + 1200)).toMatch(/superadmin: !!\(who && SUPERADMIN\.has\(String\(who\.username \|\| ''\)\.toLowerCase\(\)\)\)/);
});
it('and the nav reads that, rather than probing an endpoint it may not have', () => {
const at = dash.indexOf('Reveal the Superadmin nav');
const body = dash.slice(at, at + 800);
expect(body).toMatch(/api\('\/api\/auth\/state'\)/);
expect(body).toMatch(/if \(s\.superadmin && navAdmin\)/);
expect(body).not.toMatch(/api\('\/v1\/admin\/overview'\)/);
});
/* The gate itself is unchanged: knowing you are not one is not the same as being let in. */
it('while the admin routes are still gated exactly as before', () => {
expect(srv).toMatch(/app\.get\('\/v1\/admin\/overview', superadminGate/);
expect(srv).toMatch(/return res\.status\(403\)\.json\(\{ error: 'not a superadmin' \}\)/);
});
});