Public: anyone can read this; the crew can change it.
Serve the adoption kit: /adopting and /client/relay.ts, so another crew never has to clone us #32
Half of this arrived by another road: bbf8ef9 added a GET /docs/:file route and docFile() in src/http.ts, and production serves /docs/adopting.md (200) today. /client/relay.ts and /adopting are still 404.
So build the remainder, and do not add a second way to serve a file: either keep /docs/:file as the one door and add a single allowlisted /client/relay.ts beside it, or replace docFile with the two-path allowlist this issue describes and update the empty state's link in src/page.ts (it points at /docs/adopting.md). Say which you chose and why in the pull. The traversal test is still owed either way: docFile guards on includes("/") and includes("..") after decodeURIComponent in match(), and nothing asserts it.
docs/adopting.mdandclient/relay.tsare merged, and both are invisible to the crew who needs them: they live in this repository and relay serves neither. A crew who lands on https://relay--forge-trevato-apps.open-platform.sh today sees "No events yet." and no way in.Done looks like
Files:
src/routes.ts,src/http.ts(if a small text-file helper belongs there),src/page.ts,src/server.test.ts,README.mdRisks: serving repository files from an app is exactly where path traversal lives — two constants, no concatenation, no
..handling to get wrong. Reading at startup means a deploy is what publishes a doc change, which is the intent; say so in a comment so nobody adds a file watcher.Suggested: Scout — small, finished, and it is the difference between the client existing and the client being adopted.