Skip to content
File

Blob: tests/worker/routes/auth-and-validation.test.ts

typescript120 lines
1import { describe, expect, it } from "vitest";
2 
3import { authHeaders, fetchJson, mintCookieAuth, seedUser } from "../../helpers/runtime";
4import { registerWorkerRuntimeHooks } from "../../helpers/worker-hooks";
5 
6describe("worker routes", () => {
7 registerWorkerRuntimeHooks();
8 
9 describe("auth and request validation", () => {
10 it("reports app encryption configuration health on the public config route", async () => {
11 const result = await fetchJson("/api/public/app-config");
12 
13 expect(result.status).toBe(200);
14 expect(result.body).toEqual({});
15 });
16 
17 it("rejects private routes without a valid session", async () => {
18 const result = await fetchJson("/api/private/me");
19 
20 expect(result.status).toBe(403);
21 expect(result.body).toMatchObject({
22 error: {
23 code: "missing_session",
24 },
25 });
26 });
27 
28 it("rejects unsafe private routes without same-origin evidence", async () => {
29 const user = await seedUser({
30 email: "routes-missing-origin@example.com",
31 slug: "routes-missing-origin",
32 });
33 
34 const { sessionId } = await mintCookieAuth(user.id);
35 const headers = authHeaders(sessionId, {
36 "content-type": "application/json; charset=utf-8",
37 });
38 headers.delete("origin");
39 
40 const createdProject = await fetchJson("/api/private/projects", {
41 method: "POST",
42 headers,
43 body: JSON.stringify({
44 projectSlug: "missing-origin",
45 name: "Missing Origin",
46 repoUrl: "https://github.com/example/missing-origin",
47 defaultBranch: "main",
48 configPath: ".anvil.yml",
49 }),
50 });
51 
52 expect(createdProject.status).toBe(403);
53 expect(createdProject.body).toMatchObject({
54 error: {
55 code: "cross_origin_blocked",
56 },
57 });
58 });
59 
60 it("returns structured codec issues for branded request validation failures", async () => {
61 const user = await seedUser({
62 email: "routes-invalid@example.com",
63 slug: "routes-invalid-user",
64 });
65 
66 const { sessionId } = await mintCookieAuth(user.id);
67 
68 const createdProject = await fetchJson("/api/private/projects", {
69 method: "POST",
70 headers: authHeaders(sessionId, {
71 "content-type": "application/json; charset=utf-8",
72 }),
73 body: JSON.stringify({
74 projectSlug: "api-tests",
75 name: "API Tests",
76 repoUrl: "https://github.com/example/api-tests",
77 defaultBranch: "",
78 configPath: ".anvil.yml",
79 }),
80 });
81 
82 expect(createdProject.status).toBe(400);
83 expect(createdProject.body).toMatchObject({
84 error: {
85 code: "invalid_request",
86 details: {
87 issues: [
88 {
89 path: "defaultBranch",
90 expected: "BranchName",
91 message: null,
92 },
93 ],
94 },
95 },
96 });
97 });
98 
99 it("treats invalid project ids as project not found on private project routes", async () => {
100 const user = await seedUser({
101 email: "routes-invalid-project-id@example.com",
102 slug: "routes-invalid-project-id",
103 });
104 
105 const { sessionId } = await mintCookieAuth(user.id);
106 
107 const result = await fetchJson("/api/private/projects/not-a-project-id", {
108 headers: authHeaders(sessionId),
109 });
110 
111 expect(result.status).toBe(404);
112 expect(result.body).toMatchObject({
113 error: {
114 code: "project_not_found",
115 },
116 });
117 });
118 });
119});