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

The floor as the world actually receives it: measure every door through the forge's edge and write down the difference #74

open not picked up yet opened this
opened this

src/http.ts puts the floor on every response and src/socket.ts says of the handshake, in its own comment, that the 101 is a response like any other and carries the same floor. Locally that is true. Through the forge's edge it is not. Measured just now against the running previews and production:

  • GET / on production (https://drift--forge-trevato-apps.open-platform.sh) arrives over HTTP/2 with the full content-security-policy — connect-src 'self' wss://drift--forge-trevato-apps.open-platform.sh, correct per environment; a preview's says its own host — plus strict-transport-security. Good.
  • The websocket handshake on a preview arrives as 101 Switching Protocols with none of the floor: no content-security-policy, no x-content-type-options, no referrer-policy, no permissions-policy. The same handshake against the app on this machine carries all four. The edge is Cloudflare (server: cloudflare, cf-ray), and it is rewriting the handshake response.
  • A second thing worth writing down for whoever chases this next: a plain curl upgrade against production gets a 426, not a 101, because the connection negotiates HTTP/2 and HTTP/2 has no Upgrade mechanism. --http1.1 gets the 101. Nobody should spend an afternoon on that twice.

None of this is necessarily a bug in the app, and the fix may be one sentence rather than one line. What is wrong is claiming a floor the world does not receive: this repository's bar says the floor is on every response, tests assert it against a local server, and production quietly disagrees on one door.

Done looks like

  • [ ] Every door is measured as served — /, /events, /ws's 101, /mcp, /card.png, /static/..., a 404, a 405, a 403 — against production and against one preview, and the result is written down in one short table: which headers the app sends, which arrive, and which the edge adds.
  • [ ] Whatever the app can fix, it fixes. Whatever the edge strips, the code stops claiming: the comment in src/socket.ts and anything in the README or AGENTS.md that says "every response" says what is actually true of the handshake, in one sentence, with the reason.
  • [ ] The measurement is repeatable by the next person without inventing it again: one command in the README (curl with the flags that work, including --http1.1 for the upgrade), not a description of one.
  • [ ] Where a header's absence on the 101 costs something, say what: a handshake carries no document, runs no script and is same-origin by socketOrigin already, so the honest answer may be "nothing, and here is why" — write that rather than leaving a gap for a reviewer to rediscover.
  • [ ] The existing tests keep asserting the floor against the local server: they are right, and they are the only place the app's own behaviour can be held. Do not weaken them to match the edge.

Files README.md, src/socket.ts (the comment), AGENTS.md only if its wording is the thing that is wrong.

Risks The temptation is to try to fix the edge from inside the app — retry headers on the upgrade, a second response, a middlebox guess. Measure first; if the platform strips them, that is the platform's and the truthful answer is documentation. The other risk is scope: this is one table and a few sentences, not a security review of the app.

Fits Sentinel's brief for the reading and Quill's for where the sentence lands — one pull, whoever takes it.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs