Files
paperclip/server/src/__tests__/board-mutation-guard.test.ts
Forgotten e1f2be7ecf feat(server): integrate Better Auth, access control, and deployment mode startup
Wire up Better Auth for session-based authentication. Add actor middleware
that resolves local_trusted mode to an implicit board actor and authenticated
mode to Better Auth sessions. Add access service with membership, permission,
invite, and join-request management. Register access routes for member/invite/
join-request CRUD. Update health endpoint to report deployment mode and
bootstrap status. Enforce tasks:assign and agents:create permissions in issue
and agent routes. Add deployment mode validation at startup with guardrails
(loopback-only for local_trusted, auth config required for authenticated).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 14:40:32 -06:00

69 lines
2.2 KiB
TypeScript

import { describe, expect, it } from "vitest";
import express from "express";
import request from "supertest";
import { boardMutationGuard } from "../middleware/board-mutation-guard.js";
function createApp(actorType: "board" | "agent", boardSource: "session" | "local_implicit" = "session") {
const app = express();
app.use(express.json());
app.use((req, _res, next) => {
req.actor = actorType === "board"
? { type: "board", userId: "board", source: boardSource }
: { type: "agent", agentId: "agent-1" };
next();
});
app.use(boardMutationGuard());
app.post("/mutate", (_req, res) => {
res.status(204).end();
});
app.get("/read", (_req, res) => {
res.status(204).end();
});
return app;
}
describe("boardMutationGuard", () => {
it("allows safe methods for board actor", async () => {
const app = createApp("board");
const res = await request(app).get("/read");
expect(res.status).toBe(204);
});
it("blocks board mutations without trusted origin", async () => {
const app = createApp("board");
const res = await request(app).post("/mutate").send({ ok: true });
expect(res.status).toBe(403);
expect(res.body).toEqual({ error: "Board mutation requires trusted browser origin" });
});
it("allows local implicit board mutations without origin", async () => {
const app = createApp("board", "local_implicit");
const res = await request(app).post("/mutate").send({ ok: true });
expect(res.status).toBe(204);
});
it("allows board mutations from trusted origin", async () => {
const app = createApp("board");
const res = await request(app)
.post("/mutate")
.set("Origin", "http://localhost:5173")
.send({ ok: true });
expect(res.status).toBe(204);
});
it("allows board mutations from trusted referer origin", async () => {
const app = createApp("board");
const res = await request(app)
.post("/mutate")
.set("Referer", "http://localhost:5173/issues/abc")
.send({ ok: true });
expect(res.status).toBe(204);
});
it("does not block authenticated agent mutations", async () => {
const app = createApp("agent");
const res = await request(app).post("/mutate").send({ ok: true });
expect(res.status).toBe(204);
});
});