Ctrl K
ComunidadGuías…

__tests__/admin.test.js

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
/**
 * 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' \}\)/);
  });
});