Read-only space membership via <space>-ro IdP groups (#64) #67

Merged
Cordy merged 2 commits from feat/ro-spaces into main 2026-07-30 01:48:05 +00:00
Owner

Closes #64. The auditor/viewer persona from docs/PUBLIC-SECTOR.md, following the directory-is-the-source-of-truth philosophy — no parallel permission system.

  • Membership in <space>-ro (suffix configurable via auth.spaceReadOnlySuffix) grants read-only access to /spaces/<space>: reads, stats, and listings work; every mutation (write/delete/mkdir/rename-into-or-out/copy-into) returns the new storage.ErrReadOnly → 403 on REST. Copy OUT of a read-only space to one's home is allowed (it's a read).
  • Write membership wins when a user carries both groups. Non-members still get not-found — read-only membership reveals the space, nothing else changes.
  • The /spaces overlay lists an ro space under its real name (suffix stripped).
  • Upload-link bypass closed: public share uploads go through the unscoped store, so share creation now refuses allowUpload links from read-only members (scope.Driver.ReadOnly checked via optional interface).
  • Enforced in the scope overlay — web, REST, WebDAV, and TUS behave identically.

Note: WebDAV surfaces ErrReadOnly as a generic error rather than a mapped 403 for now — enforcement holds; status-code polish is a follow-up alongside the UI viewer-badge affordance.

Tests: read/list/stat allowed, all mutations rejected, spaces listing under real name, copy-in vs copy-out, dual-membership write wins, non-member invisibility, configurable suffix. Green on the runner.

Closes #64. The auditor/viewer persona from docs/PUBLIC-SECTOR.md, following the directory-is-the-source-of-truth philosophy — no parallel permission system. - Membership in `<space>-ro` (suffix configurable via `auth.spaceReadOnlySuffix`) grants **read-only** access to `/spaces/<space>`: reads, stats, and listings work; every mutation (write/delete/mkdir/rename-into-or-out/copy-into) returns the new `storage.ErrReadOnly` → 403 on REST. Copy OUT of a read-only space to one's home is allowed (it's a read). - Write membership wins when a user carries both groups. Non-members still get not-found — read-only membership reveals the space, nothing else changes. - The `/spaces` overlay lists an ro space under its real name (suffix stripped). - **Upload-link bypass closed**: public share uploads go through the unscoped store, so share creation now refuses `allowUpload` links from read-only members (`scope.Driver.ReadOnly` checked via optional interface). - Enforced in the scope overlay — web, REST, WebDAV, and TUS behave identically. Note: WebDAV surfaces ErrReadOnly as a generic error rather than a mapped 403 for now — enforcement holds; status-code polish is a follow-up alongside the UI viewer-badge affordance. Tests: read/list/stat allowed, all mutations rejected, spaces listing under real name, copy-in vs copy-out, dual-membership write wins, non-member invisibility, configurable suffix. Green on the runner.
Cordy merged commit e9f1b6c584 into main 2026-07-30 01:48:05 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: Cordy/Cairn#67
No description provided.