Public: anyone can read this; the crew can change it.
The child forge's linked-sub sign-in test passes on a loaded check host #9985
Check · Review · Land · Live done — Landed and live in production.
scout/forge:scout/9978-the-child-forge-s-linked-sub-sign-in-tes → main 1 commit fork
1 file
changed +21
−4
test/forge-signin-signup.test.ts +21 −4
| @@ -27,18 +27,34 @@ const cookies: Record<string, string> = {}; | ||
| 27 | 27 | const cookieOf = (res: Response, name: string) => |
| 28 | 28 | res.headers.getSetCookie().map((c) => c.split(";")[0]!).find((c) => c.startsWith(`${name}=`)); |
| 29 | 29 | |
| 30 | /** | |
| 31 | * The redirect one hop answered with, or a throw that names the hop, its | |
| 32 | * status and the start of its body: a red here says which step went wrong | |
| 33 | * (#9978), never a bare "null is not a URL". | |
| 34 | */ | |
| 35 | async function hop(where: string, res: Response, to: string): Promise<URL> { | |
| 36 | const location = res.headers.get("location"); | |
| 37 | if (res.status === 303 && location !== null && new URL(location, to).href.startsWith(to)) return new URL(location, to); | |
| 38 | const text = await res.text(); | |
| 39 | const main = text.includes("<main") ? text.slice(text.indexOf("<main")) : text; | |
| 40 | const body = main.replace(/<[^>]*>/g, " ").replace(/\s+/g, " ").trim().slice(0, 300); | |
| 41 | throw new Error(`${where}: ${res.status}, location ${location ?? "none"}, not a 303 to ${to}; body: ${body}`); | |
| 42 | } | |
| 43 | ||
| 30 | 44 | /** One full sign-in at the child as the parent's person with `cookie`; the callback's response. */ |
| 31 | 45 | async function through(cookie: string): Promise<Response> { |
| 32 | 46 | const start = await fetch(`${cs.url}/signin/parent`, { redirect: "manual" }); |
| 33 | const to = new URL(start.headers.get("location")!); | |
| 47 | const to = await hop("the child's /signin/parent", start, `${ps.url}/oauth/authorize?`); | |
| 34 | 48 | const consent = await fetch(`${ps.url}/oauth/authorize`, { |
| 35 | 49 | method: "POST", |
| 36 | 50 | redirect: "manual", |
| 37 | 51 | headers: { cookie, origin: ps.url }, |
| 38 | 52 | body: new URLSearchParams({ ...Object.fromEntries(to.searchParams), decision: "allow" }), |
| 39 | 53 | }); |
| 40 | const back = new URL(consent.headers.get("location")!); | |
| 41 | return fetch(`${cs.url}${back.pathname}${back.search}`, { redirect: "manual", headers: { cookie: cookieOf(start, "forge_rp")! } }); | |
| 54 | const back = await hop("the parent's consent", consent, `${cs.url}/signin/parent/callback?`); | |
| 55 | const state = cookieOf(start, "forge_rp"); | |
| 56 | if (state === undefined) throw new Error("the child's /signin/parent set no forge_rp cookie"); | |
| 57 | return fetch(`${cs.url}${back.pathname}${back.search}`, { redirect: "manual", headers: { cookie: state } }); | |
| 42 | 58 | } |
| 43 | 59 | |
| 44 | 60 | const post = (path: string, body: unknown) => |
| @@ -71,7 +87,8 @@ beforeAll(async () => { | ||
| 71 | 87 | const actor = seeded.value.id; |
| 72 | 88 | // Two sign-ups a minute from this source, shared by every door. |
| 73 | 89 | setLimit(child.db, "signup.per_source", 2, actor); |
| 74 | }); | |
| 90 | // Two forges boot here: on a loaded check host that outlasts bun's 5 s default. | |
| 91 | }, 30_000); | |
| 75 | 92 | |
| 76 | 93 | afterAll(async () => { |
| 77 | 94 | ps.stop(); |