fix(server-mode): close the gaps the review of workspace sharing found
- A Terminal tab a collaborator opens records them (dashboard_runs.started_by): its pane token acts as them — and only while still shared with them — never as the workspace owner (userFromPaneToken). - POST /api/run always starts the lane's AI tool: a collaborator gets ECOLLABSTART whatever the body says (shell: true no longer slips past). - A collaborator disabled since no longer locks the share list: kept on it (shown disabled) or taken off; only a new addition must be enabled. - The workspace home tells a collaborator to open an existing session and keeps Start disabled instead of failing on every submit.
This commit is contained in:
+4
-1
@@ -2111,7 +2111,10 @@ owner or an admin only (`403 ENOTOWNER`), same-origin, each change audited. Loca
|
||||
mode: `GET` answers an empty list, `PUT` `400 ELOCALMODE`. A user it is shared with
|
||||
sees and works in it like its owner, but `PATCH {title}`, `reset`/`remove`/`purge`,
|
||||
`DELETE` and `PUT …/shares` answer them `403 ENOTOWNER`, and a non-shell
|
||||
`POST /api/lanes/:id/start` or `POST /api/run` `403 ECOLLABSTART`. Users taken off
|
||||
`POST /api/lanes/:id/start` or any `POST /api/run` `403 ECOLLABSTART`. A Terminal
|
||||
tab they open (`start {shell: true}`) records them in `dashboard_runs.started_by`:
|
||||
its pane token acts as them, not the owner. A user disabled since stays on the
|
||||
list (`disabled: true`) and may be kept or removed; only a new one must be enabled. Users taken off
|
||||
get the WebSocket message `lane_access` `{laneId, userIds}` (sent to them only). See
|
||||
`docs/SERVER-MODE.md` → Sharing a workspace.
|
||||
|
||||
|
||||
+10
-2
@@ -257,9 +257,17 @@ decides the account. They can read everything in the owner's home (the owner's
|
||||
other workspaces, SSH keys, AI logins, the pane tokens of the owner's panes)
|
||||
and their commits carry the owner's git identity; only AgentHub's `audit_log`
|
||||
records who did what. The Share dialog says so. Share only with people you
|
||||
would hand your keyboard to.
|
||||
would hand your keyboard to. Two consequences follow and are accepted, not
|
||||
bugs: a collaborator can read the pane token of a pane the OWNER started (and
|
||||
so act as the owner through the CLI from it), and `ECOLLABSTART` is a
|
||||
dashboard rule, not a barrier — in a terminal they can run `claude` as the
|
||||
owner's account. A Terminal tab the collaborator opens records them as its
|
||||
starter (`dashboard_runs.started_by`), so its own pane token acts as THEM, and
|
||||
only while the workspace is still shared with them (`userFromPaneToken`).
|
||||
|
||||
Every share and unshare is audited (`share workspace <id>` /
|
||||
A user already on the list who was disabled since stays listed (marked
|
||||
disabled, granting nothing) and can be taken off; only a NEW addition must be
|
||||
enabled. Every share and unshare is audited (`share workspace <id>` /
|
||||
`unshare workspace <id>`). Taking it back sends the users taken off
|
||||
`lane_access` (their list re-reads) and closes their open terminals on it at
|
||||
the next attach re-check. Deleting the workspace, or the user, drops the rows;
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
# Workspace & session sharing — plan
|
||||
|
||||
Status: **phase 1 built 2026-11-06** (workspace sharing; R1 decided as option **(a)** — accept and warn hard). Phases 2–4 not built.
|
||||
An independent review of phase 1 found and got fixed: a collaborator's Terminal
|
||||
tab acted as the owner through its pane token (now `dashboard_runs.started_by`),
|
||||
`POST /api/run {shell:true}` bypassed `ECOLLABSTART`, a disabled collaborator
|
||||
locked the share list, and the home's prompt box let a collaborator type into a
|
||||
Start that always failed. Accepted under (a): the owner's own panes' tokens are
|
||||
readable by a collaborator, and `ECOLLABSTART` is advisory under S3.
|
||||
|
||||
Server mode only. In local mode there are no users, so there is nothing to share
|
||||
and every piece below is a no-op (`isServerMode()`).
|
||||
|
||||
Reference in New Issue
Block a user