// ACC-11: the hosted product has no shared password and no "Connect Azure model" form, and the // old /preview route is not in a production build. ACC-2: Try a fictional patient still works // with no account, on the fictional records only, with the local reader only. import { mkdtemp, readdir, readFile, rm } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { fileURLToPath } from "node:url"; import { build } from "vite"; import { afterEach, describe, expect, it, vi } from "vitest"; import { CASES } from "../server/cases"; import { createNetlifyHandler } from "../server/netlify-handler"; class MemoryBlobs { rows = new Map(); n = 0; async get(key: string) { return this.rows.get(key)?.value ?? null; } async getWithMetadata(key: string) { const row = this.rows.get(key); return row ? { data: row.value, etag: row.etag, metadata: {} } : null; } async setJSON(key: string, value: unknown, opts: { onlyIfNew?: boolean; onlyIfMatch?: string } = {}) { const row = this.rows.get(key); if ((opts.onlyIfNew && row) || (opts.onlyIfMatch && row?.etag !== opts.onlyIfMatch)) return { modified: false }; this.rows.set(key, { value, etag: `e${++this.n}` }); return { modified: true, etag: `e${this.n}` }; } async delete(key: string) { this.rows.delete(key); } async list() { return { blobs: [...this.rows.entries()].map(([key, row]) => ({ key, etag: row.etag })) }; } } const req = (path: string, body?: unknown, cookie?: string) => new Request("https://context.marmar.life/api/" + path, { method: body === undefined ? "GET" : "POST", headers: { Origin: "https://context.marmar.life", ...(body === undefined ? {} : { "Content-Type": "application/json" }), ...(cookie ? { Cookie: cookie } : {}) }, body: body === undefined ? undefined : JSON.stringify(body), }); describe("the hosted demo (CONTEXT_AUTH_MODE=demo)", () => { afterEach(() => vi.unstubAllEnvs()); it("runs a fictional patient with no account and no model", async () => { vi.stubEnv("CONTEXT_AUTH_MODE", "demo"); const handler = createNetlifyHandler(() => new MemoryBlobs() as never); const status = await handler(req("status")); expect(status.status).toBe(200); expect(await status.json()).toMatchObject({ modelConfigured: false, model: null, demo: true }); const cookie = status.headers.get("set-cookie")!; expect(cookie).toMatch(/^__Host-marmar-context-demo=[a-f0-9-]{36}; Secure; HttpOnly; SameSite=Strict/); const sources = CASES[0].sources; const draft = await handler(req("extract", { sources, syntheticOnly: true, useModel: false }, cookie.split(";")[0])); expect(draft.status).toBe(200); expect((await draft.json()).mode).toBe("local"); }); it("refuses the model, pasted or changed text, and has no password sign-in", async () => { vi.stubEnv("CONTEXT_AUTH_MODE", "demo"); const handler = createNetlifyHandler(() => new MemoryBlobs() as never); const sources = CASES[0].sources; expect((await handler(req("extract", { sources, syntheticOnly: true, useModel: true }))).status).toBe(403); const pasted = [{ ...sources[0], text: "Patient: a real person\nMedication: Warfarin 5 mg" }]; expect((await handler(req("extract", { sources: pasted, syntheticOnly: true, useModel: false }))).status).toBe(403); expect((await handler(req("auth", { password: "anything" }))).status).not.toBe(200); expect((await handler(req("model", {}))).status).toBe(403); }); it("still fails closed without Cloudflare Access outside the demo", async () => { vi.stubEnv("CONTEXT_AUTH_MODE", "password"); vi.stubEnv("CONTEXT_ACCESS_ISSUER", "https://marmar-test.cloudflareaccess.com"); vi.stubEnv("CONTEXT_ACCESS_AUD", "test-audience"); expect((await createNetlifyHandler(() => new MemoryBlobs() as never)(req("status"))).status).toBe(401); }); }); describe("the production build", () => { it("has no /preview route, no shared password and no model connection form", async () => { const outDir = await mkdtemp(join(tmpdir(), "context-build-")); // Vitest runs with NODE_ENV=test; a real build runs with production, which makes import.meta.env.DEV false. vi.stubEnv("NODE_ENV", "production"); try { await build({ root: fileURLToPath(new URL("..", import.meta.url)), logLevel: "silent", mode: "production", build: { outDir, emptyOutDir: true } }); const files = (await readdir(join(outDir, "assets"))).filter((f) => f.endsWith(".js")); const code = (await Promise.all(files.map((f) => readFile(join(outDir, "assets", f), "utf8")))).join("\n"); for (const banned of ['"/preview"', "Preview password", "preview-password", "Reviewer sign-in", "Connect your Azure model", "Save session connection", "Azure endpoint"]) expect(code.includes(banned), banned).toBe(false); // Try a fictional patient is still there. expect(code.includes('"/demo"')).toBe(true); expect(code.includes("Fictional demo")).toBe(true); } finally { vi.unstubAllEnvs(); await rm(outDir, { recursive: true, force: true }); } }, 60_000); });