Files
coder/site
Michael Suchacz bca5d72c1c fix(site): prefer permitted organization for chat creation (#28078)
Fixes first-send 403s for multi-org users who lack `chat:create` in the
deployment default organization (CODAGT-892). Two frontend defects
combined to send chat creation to the wrong organization:

1. The Agents create form initialized its organization selection
permission-blind to the default org and only corrected it when the
`permittedOrganizations` authcheck result *transitioned*, so a fast
first send raced the check, and on warm-query-cache remounts the
correction never ran at all: the wrong org stayed selected permanently
while the org picker was hidden.
2. The permitted-organizations authcheck itself sent no `owner_id`, so
roles that grant `chat:create` at member (owner) scope, such as
`agents-access` (Coder Agents User, the exact role in the customer
report), were denied in every organization and the form always fell back
to the default org. This part was split out and already landed on main
via #28076; after rebasing, this PR relies on that fix and keeps its
stricter regression stories around it.

## Changes

- Derive the effective organization at render time: keep the user's
explicit pick only while it is still permitted, otherwise fall back to
the permitted default org, then the first permitted org, then the
dashboard default. Replaces the transition-based reconciliation, which
could not fire when the query cache was already warm on mount.
- Keep user-driven org cleanup (workspace selection, attachments) in the
picker/dialog event handlers; permission-driven changes are handled by
render-time state adjustments and the attachment hook's post-commit
adoption effect.
- Disable Send until the permitted-organizations check settles and the
attachment hook has adopted the effective org; hide the org picker and
disable the workspace picker until the check settles (their
pre-settlement options come from the unfiltered dashboard fallback, so a
pick could persist a foreign-org workspace).
- Scope persisted attachments to their organization in
`useFileAttachments`: restoration defers until a permitted org is known,
permission-driven org changes replace attachment state post-commit,
in-flight uploads are invalidated by an adoption epoch (including
A-to-B-to-A round trips), and no render exposes another org's file IDs,
including when authorization resolves to no org at all.
- Revalidate org-scoped state on permission refetches: a revoked
explicit selection clears instead of lying latent, a settled
effective-org change drops the stored workspace, and the org-change
confirmation dialog closes (and re-checks on confirm) when its pending
org is revoked.
- Rebase reconciliation with #28076: the stories use its
`permittedOrganizationsKey` helper and retain its
`MemberScopedPermissionsShowOrgPicker` regression story alongside this
PR's stricter member-scope stories.

The backend RBAC rejection was correct; this is frontend-only.

## Testing

- Red-green: every guard above was verified by reverting it and
confirming exactly its guarding story or unit test fails (whole-file
runs).
- `pnpm -C site check`, `pnpm -C site lint`, `pnpm -C site lint:types`,
full `AgentCreateForm.stories.tsx` (42 pass),
`useFileAttachments.test.tsx` (8 pass), re-run after the rebase onto
main.
- Dogfood UAT on a licensed multi-org dev deployment at this branch: a
restricted user with `agents-access` only in a non-default org sends
first and warm-remount messages successfully (201, payload carries the
permitted org, no 403); admin picker, workspace filtering, and
attachment org-change dialog verified. Round 2 of UAT caught the missing
`owner_id` (now landed via #28076); round 3 re-verified end to end.

> Mux created this PR on Mike's behalf.
2026-08-13 18:30:22 +02:00
..