Render not-found for an org slug the session does not belong to - #1825
Merged
Conversation
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
executor-marketing | 0c63e6e | Commit Preview URL Branch Preview URL |
Aug 28 2026, 09:32 AM |
Contributor
Cloudflare previewTorn down — the PR is closed. |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
executor-cloud | 0c63e6e | Aug 28 2026, 09:33 AM |
@executor-js/cli
@executor-js/config
@executor-js/execution
@executor-js/sdk
@executor-js/codemode-core
@executor-js/runtime-quickjs
@executor-js/plugin-file-secrets
@executor-js/plugin-graphql
@executor-js/plugin-keychain
@executor-js/plugin-mcp
@executor-js/plugin-onepassword
@executor-js/plugin-openapi
executor
commit: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #1713
Opening
/<a-slug-you-do-not-own>/policiessometimes rendered the full authenticated console — sidebar, org switcher showing the user's OWN organization, page chrome — under an address naming an organization they cannot see, with a failing org-scoped query and a Retry button for a body.Cause
AuthGateonly reaches its not-found branch onceauth.organizationresolves tonull. Until/account/meanswers,useAuthseeds from the auth-hint cookie, and that cookie always names the organization the session last landed in — never the one in the URL. So the first paint answered a question about a different organization and built the whole shell out of it. Whether the user ever saw it came down to how fast the server replied, which is why it reproduced roughly one run in four on a loaded CI runner.Fix
AuthGatenow refuses to build the shell from an answer that does not name the organization the URL names:/account/meis scoped by the URL's slug, so once it resolves it can only agree or benull. A disagreement is therefore always an unresolved answer, never a verdict — hence blank rather than not-found, leaving the existingorganization == nullbranch as the only thing entitled to declare a wrong address. The URL is never rewritten.Cold-load speed is unchanged for the legitimate case: the hint names the slug already in the URL, so this matches on the very first paint and the shell renders with no round trip. Only a slug the hint does not name waits — a foreign one, and the single frame after an org switch, which now paints the organization the URL asked for instead of briefly showing the previous one. Bare and reserved console paths (
/policies,/integrations, …) are unaffected: every console root is a reserved slug, sopathnameOrgSlugisnullfor them and canonicalization still runs as before.OrgSlugGate's header comment is updated: the invariant it documents is now actually enforced by the host rather than assumed.Why not server-side
The console is SPA mode — one static prerendered shell serves every authenticated document request, and the document gate can only redirect or append cookies, not vary the body. A redirect is exactly what the issue rules out, and authorizing the URL's slug in the gate would put a live membership lookup on every slugged document request, which is the cold-load cost this change is meant to avoid. So the block is client-side and the shell simply never mounts.
Tests
The org-slug scenario's unknown-slug step previously only waited for "Page not found", so a run that flashed an entire workspace first still passed. It now installs a
MutationObserverbefore the page's own scripts run, records whether a console sidebar was ever attached, and asserts the landing state as a whole — pathname plus shell-ever-mounted. Both tenancy branches are pinned rather than one being skipped: multi-tenant hosts must 404 with no shell and the URL untouched, single-tenant hosts must canonicalize onto the instance org's shell.Verified end to end:
vitest run --project cloud scenarios/org-slug-routing.test.ts— passes; screenshot shows the not-found page with/zz-no-such-org/policiesstill in the address bar.shellEverMounted: true, deterministically. The assertion catches the flash it was written for.vitest run --project selfhost scenarios/org-slug-routing.test.ts— passes; the canonicalize branch holds.packages/react(363) andapps/cloud(344) unit suites, plus repo typecheck, lint, and format.