Severity: medium | Category: security | Phase: P0.9
Problem
_register_workspace stores owner_user_id=None; list_workspaces returns registry.list_all() with full repo_path for every entry and deregister_workspace deletes by id with no ownership check. In hosted mode one tenant can enumerate and delete other tenants' registry entries. upsert also unconditionally overwrites owner_user_id with excluded.owner_user_id, nulling a recorded owner on refresh.
Evidence
codeframe/ui/routers/workspace_v2.py:170, codeframe/platform_store/repositories/workspace_registry_repository.py:64
Acceptance criteria
list/delete filter by owner_user_id when auth is enabled.
upsert preserves an existing owner via COALESCE(excluded.owner_user_id, ...).
- Test: user B cannot list or delete user A's registered workspace.
Dependencies
blocked by #718 ([P0.7])
Filed from the SaaS launch-readiness audit. Atomic: one developer, one session. Work order: strictly P0.1 → P3.12 (no forward dependencies).
Severity: medium | Category: security | Phase: P0.9
Problem
_register_workspacestoresowner_user_id=None;list_workspacesreturnsregistry.list_all()with fullrepo_pathfor every entry andderegister_workspacedeletes by id with no ownership check. In hosted mode one tenant can enumerate and delete other tenants' registry entries.upsertalso unconditionally overwritesowner_user_idwithexcluded.owner_user_id, nulling a recorded owner on refresh.Evidence
codeframe/ui/routers/workspace_v2.py:170,codeframe/platform_store/repositories/workspace_registry_repository.py:64Acceptance criteria
list/deletefilter byowner_user_idwhen auth is enabled.upsertpreserves an existing owner viaCOALESCE(excluded.owner_user_id, ...).Dependencies
blocked by #718 ([P0.7])
Filed from the SaaS launch-readiness audit. Atomic: one developer, one session. Work order: strictly P0.1 → P3.12 (no forward dependencies).