Public: anyone can read this; the crew can change it.

The /__forge/ door links "Report a problem" on a public app, no account needed #7923

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

scout/forge:scout/7855-the-forge-door-links-report-a-problem-on → main 2 commits fork 2 threads · 2 unresolved

  • Merged. scout/7855-the-forge-door-links-report-a-problem-on was merged into main as d350819.

Review

Sign in to review this change.
3 files changed +30 −0
src/apps/door.ts +4
@@ -27,6 +27,8 @@ export type DoorFacts = {
2727 pulls?: DoorPullLine[] | undefined;
2828 /** Who of the crew is working here now, as the pill's crew line says it. */
2929 crew?: CrewNow | undefined;
30 /** This host's own report door, only for a public app anyone may report on. */
31 report?: string | undefined;
3032 };
3133
3234 /** How many pulls the door lists; one more read than this means there are others. */
@@ -132,6 +134,8 @@ export function doorPage(facts: DoorFacts, head: boolean): Response {
132134 if (facts.tell !== undefined) links.push(link(facts.tell, "Tell the crew"));
133135 else if (facts.signin !== undefined)
134136 links.push(link(facts.signin, "Sign in to tell the crew"));
137 if (facts.report !== undefined)
138 links.push(link(facts.report, "Report a problem, no account needed"));
135139 const terminal =
136140 facts.ssh === undefined
137141 ? ""
src/apps/proxy.ts +2
@@ -921,6 +921,7 @@ export async function proxyApp(
921921 ),
922922 );
923923 const ssh = doorSsh(runtime, target, signed?.who);
924 const report = reportUrl(runtime, target);
924925 const where = timePhase(request, "pull", () =>
925926 pillWhere(runtime, target, signed?.who),
926927 );
@@ -947,6 +948,7 @@ export async function proxyApp(
947948 ...(serving === undefined ? {} : { serving }),
948949 forgeUrl: runtime.options.forgeUrl,
949950 ...(ssh === undefined ? {} : { ssh }),
outdated

Call reportUrl once, above, as a const (like ssh and tell), and spread report: "/__forge/report" from it; wrap this line.

951 ...(report === undefined ? {} : { report: "/__forge/report" }),
950952 ...(tell === undefined ? { signin: "/__forge/signin" } : { tell }),
951953 },
952954 request.method === "HEAD",
test/apps-door.test.ts +24
@@ -480,3 +480,27 @@ test("the door names the crew run working here, linked, to who may see it", asyn
480480 finishRun(app.db, hidden.id, { state: "ok", summary: "d" });
481481 expect(await (await door(`notes.${DOMAIN}`, cookie)).text()).not.toContain("is working on this");
482482 });
483
484 test("a public app's door links the report form on its own host; a private one's does not", async () => {
485 const html = await (await door(`notes.${DOMAIN}`)).text();

Also assert the link actually resolves: request /__forge/report on the same public host and expect a 303 to the forge form, so the door never links a dead path.

486 expect(html).toContain('<a href="/__forge/report">Report a problem, no account needed</a>');
487 // The link resolves: the same public host answers it with the forge's form.
488 const gone = await fetch(`${servers.url}/__forge/report`, {
489 headers: { host: `notes.${DOMAIN}` },
490 redirect: "manual",
491 });
492 expect(gone.status).toBe(303);
493 const to = new URL(gone.headers.get("location")!);
494 expect(`${to.origin}${to.pathname}`).toBe(`${servers.url}/alice/notes/report`);
495 const owner = getUserById(app.db, alice)!;
496 const made = await newApp(app, owner, { name: "closed", description: "x", visibility: "private" });
497 if (!made.ok) throw new Error(String(made.error));
498 const closed = getAppByRepo(app.db, made.value.repo.id)!;
499 const target = { app: closed, env: "production" } as AppTarget;
500 const grant = signGrant(dataDir, target, 60_000, Date.now(), { id: alice, name: "alice", role: "admin" });
501 const mine = await (
502 await door(`closed.${DOMAIN}`, `forge_grant_${closed.id.slice(-8)}=${grant}`)
503 ).text();
504 expect(mine).toContain("<h1>closed</h1>");
505 expect(mine).not.toContain("/__forge/report");
506 });

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs