Public: anyone can read this; the crew can change it.
Every app host answers GET /__forge/toolbar-<hash>.js with the forge pill's script #8285
Check · Review · Land · Live done — Landed and live in production.
Every app and preview host now answers `GET /__forge/toolbar-<hash>.js` with the pill's script. The new test and `test/apps-toolbar.test.ts` pass (35 tests), `tsc --noEmit` is clean and `scripts/gate.ts` ran without printing anything. I did not run the full suite; the forge's check does that on this push.
shipped production is serving it deploy 9e5d84b
Every app and preview host now answers GET /__forge/toolbar-<hash>.js with the pill's script. The new test and test/apps-toolbar.test.ts pass (35 tests), tsc --noEmit is clean and scripts/gate.ts ran without printing anything. I did not run the full suite; the forge's check does that on this push.
- Route: the check is in
src/apps/proxy.ts, ahead of the grant handling.
- The response is toolbarResponse(request), the same function that serves TOOLBAR_PATH, so the bytes and the immutable cache-control are the same. The content type is text/javascript; charset=utf-8.
- It goes through securityFloor, so x-content-type-options: nosniff and the referrer policy are set.
- Any other path under /__forge/toolbar answers 404 from the forge and never reaches the app. That covers a wrong hash, a missing hash and a suffixed or nested path.
- Only GET and HEAD are served; any other method on that path is also a 404.
- Exported path:
src/apps/toolbar.tsexportsTOOLBAR_ASSET_PATH, built from the samenamethatTOOLBAR_PATHuses, so the two cannot drift. It also exportsTOOLBAR_ASSET_PREFIX, the/__forge/toolbarprefix the proxy matches on. - Test:
test/apps-toolbar-asset.test.tsproxies an app and checks that the exact path returnstoolbarJswith the headers above, and that wrong or other paths return 404. A counter on the backend checks that none of these requests reaches the app. Without thesrcchange the test fails to load, because the new export does not exist.
Not done
- Nested hosts: the route is skipped on nested (guest-forge) hostnames, where
/__forge/*already belongs to the guest forge, as the grant route does. The issue says "every app and preview host", so say if you want nested hosts covered too. - Script tag: it still points at the forge origin. That is the next issue.
- Other tests: no existing test file is touched, including
render-media.test.ts.
To try it, request /__forge/toolbar-<hash>.js on any app host. The hash is in TOOLBAR_ASSET_PATH.
🤖 Generated with Claude Code
Approved. The route sits ahead of the app proxy and uses the same toolbarResponse as the forge origin. It runs through securityFloor and answers 404 for any other /__forge/toolbar path. The test proves the app is never reached. Wrong-hash path answers 404 on the preview. The change is small and single-purpose. No new dependency.
Two things I would do next:
- Point the script tag at /__forge/toolbar-<hash>.js, the stated next issue. Check on a 360px phone that the pill still paints with no layout shift under a strict script-src self.
- Decide nested (guest-forge) hosts explicitly. Skipping them is right today. Add a test that pins it, so a nested host still reaches the guest forge for /__forge/*, and add a HEAD and a POST case to the 404 and 200 tests.
Every app and preview host now answers
GET /__forge/toolbar-<hash>.jswith the pill's script. The new test andtest/apps-toolbar.test.tspass (35 tests),tsc --noEmitis clean andscripts/gate.tsran without printing anything. I did not run the full suite; the forge's check does that on this push.src/apps/proxy.ts, ahead of the grant handling.- The response is
toolbarResponse(request), the same function that servesTOOLBAR_PATH, so the bytes and the immutablecache-controlare the same. The content type istext/javascript; charset=utf-8. - It goes throughsecurityFloor, sox-content-type-options: nosniffand the referrer policy are set. - Any other path under/__forge/toolbaranswers 404 from the forge and never reaches the app. That covers a wrong hash, a missing hash and a suffixed or nested path. - Only GET and HEAD are served; any other method on that path is also a 404.src/apps/toolbar.tsexportsTOOLBAR_ASSET_PATH, built from the samenamethatTOOLBAR_PATHuses, so the two cannot drift. It also exportsTOOLBAR_ASSET_PREFIX, the/__forge/toolbarprefix the proxy matches on.test/apps-toolbar-asset.test.tsproxies an app and checks that the exact path returnstoolbarJswith the headers above, and that wrong or other paths return 404. A counter on the backend checks that none of these requests reaches the app. Without thesrcchange the test fails to load, because the new export does not exist.Not done
/__forge/*already belongs to the guest forge, as the grant route does. The issue says "every app and preview host", so say if you want nested hosts covered too.render-media.test.ts.To try it, request
/__forge/toolbar-<hash>.json any app host. The hash is inTOOLBAR_ASSET_PATH.🤖 Generated with Claude Code
Closes #8267