← back to Govarbitrage

src/middleware.test.ts

99 lines

import { describe, expect, it, beforeEach, vi } from "vitest";
import { NextRequest } from "next/server";

// TK-11476 — verify TK-11466 FIX 2 (presentedAdminBasicAuth) actually holds:
// with the shared-password wall OFF (BASIC_AUTH=""), an anonymous caller on a
// protected path must fall through to /login (pages) / 401 JSON (APIs) and
// must NEVER be minted an ADMIN session. BASIC_AUTH is read as a top-level
// module constant, so each case resets modules and re-imports after setting
// the env var it needs to exercise.
async function loadMiddleware() {
  const mod = await import("./middleware");
  return mod.middleware;
}

function req(path: string, headers: Record<string, string> = {}) {
  return new NextRequest(new Request(`https://auctions.agentabrams.com${path}`, { headers }));
}

const basicHeader = (creds: string) => "Basic " + Buffer.from(creds).toString("base64");

beforeEach(() => {
  vi.resetModules();
  process.env.AUTH_SECRET = "test-secret-please-change";
  delete process.env.FLEET_SSO_SECRET;
  delete process.env.IMPORT_TOKEN;
});

describe("middleware — wall OFF (BASIC_AUTH empty)", () => {
  beforeEach(() => {
    process.env.BASIC_AUTH = "";
  });

  it("anon GET / redirects to /login and mints no session cookie", async () => {
    const middleware = await loadMiddleware();
    const res = await middleware(req("/"));
    expect(res.status).toBe(307);
    expect(res.headers.get("location")).toContain("/login");
    expect(res.cookies.get("ga_session")).toBeUndefined();
  });

  it("anon GET /api/credentials returns 401 JSON and mints no session cookie", async () => {
    const middleware = await loadMiddleware();
    const res = await middleware(req("/api/credentials"));
    expect(res.status).toBe(401);
    expect(res.cookies.get("ga_session")).toBeUndefined();
  });

  it("regression guard: a bogus Authorization header still does not mint ADMIN", async () => {
    const middleware = await loadMiddleware();
    const res = await middleware(req("/", { Authorization: basicHeader("anyone:anything") }));
    expect(res.status).toBe(307);
    expect(res.headers.get("location")).toContain("/login");
    expect(res.cookies.get("ga_session")).toBeUndefined();
  });

  it("regression guard: even the correct default creds do not mint ADMIN once the wall is off", async () => {
    // The exact TK-11466 bypass shape: basicAuthOk() would have been true
    // unconditionally with the wall off. presentedAdminBasicAuth() must stay
    // false regardless of what's presented when BASIC_AUTH itself is empty.
    const middleware = await loadMiddleware();
    const res = await middleware(req("/", { Authorization: basicHeader("admin:DW2024!") }));
    expect(res.status).toBe(307);
    expect(res.headers.get("location")).toContain("/login");
    expect(res.cookies.get("ga_session")).toBeUndefined();
  });

  it("public paths (e.g. /pricing) stay reachable anonymously", async () => {
    const middleware = await loadMiddleware();
    const res = await middleware(req("/pricing"));
    expect(res.status).toBe(200);
  });
});

describe("middleware — wall ON (BASIC_AUTH set, unchanged behavior)", () => {
  beforeEach(() => {
    process.env.BASIC_AUTH = "admin:DW2024!";
  });

  it("anon GET / (no credentials) is 401'd by the wall", async () => {
    const middleware = await loadMiddleware();
    const res = await middleware(req("/"));
    expect(res.status).toBe(401);
    expect(res.headers.get("www-authenticate")).toContain("Basic");
  });

  it("the real shared credential still auto-mints an ADMIN session", async () => {
    const middleware = await loadMiddleware();
    const res = await middleware(req("/", { Authorization: basicHeader("admin:DW2024!") }));
    expect(res.status).toBe(200);
    expect(res.cookies.get("ga_session")?.value).toBeTruthy();
  });

  it("a wrong credential is 401'd, not redirected", async () => {
    const middleware = await loadMiddleware();
    const res = await middleware(req("/", { Authorization: basicHeader("admin:wrong") }));
    expect(res.status).toBe(401);
  });
});