Design: admins see everyone's home in "Personal" — scope admins by default, make backend access explicit? #177

Closed
opened 2026-08-10 00:50:00 +00:00 by Cordy · 2 comments
Owner

Dogfood note (Nikola): "as an admin, I can see the user home folder of other non-admin users. This shouldn't be that blatantly possible; an admin should only see his own user-home within his Personal space."

Current behavior is by design, and documented: admins are unscoped (scope.go: "Admins are NOT scoped: they address the whole backend directly"), so their "Personal" view IS the backend root — /home, /spaces, everything. The design rationale was operator simplicity (no per-file ACLs, the backend tree is the data model). The dogfood note says the presentation is wrong, and it is: an admin who wants their own files sees everyone's homes at eye level, and "Personal" lies about what it shows.

Proposal for discussion (needs Nikola's call before any code):

  • Admins get scoped like everyone else by default: their Personal = /home/<admin>, their Spaces = their groups. Day-to-day file use looks identical for admins and users.
  • Backend-wide access moves behind an explicit, visibly labeled "Backend" view in the sidebar (admin-only): same full access, but deliberately entered, visually distinct, and — with audit enabled — every read in it attributable. No capability is lost; the blast radius of casual browsing is.
  • Consequences to check before committing: admin-driven flows that rely on unscoped addressing (moving files between homes, hold paths, space repair, share revocation by actual path) must keep working from the Backend view; peering delivery and share serving already use the unscoped stack internally and are unaffected.

Questions for Nikola:

  1. Is the two-view model (scoped Personal + explicit Backend view) what you want, or do you want admins to have NO whole-backend file access at all (that would be a much deeper change and would break admin repair flows)?
  2. Should entering the Backend view require anything beyond being admin (e.g. a confirm click that gets audit-logged), or is the visual separation enough?
Dogfood note (Nikola): *"as an admin, I can see the user home folder of other non-admin users. This shouldn't be that blatantly possible; an admin should only see his own user-home within his Personal space."* **Current behavior is by design, and documented:** admins are unscoped (`scope.go`: "Admins are NOT scoped: they address the whole backend directly"), so their "Personal" view IS the backend root — `/home`, `/spaces`, everything. The design rationale was operator simplicity (no per-file ACLs, the backend tree is the data model). The dogfood note says the *presentation* is wrong, and it is: an admin who wants their own files sees everyone's homes at eye level, and "Personal" lies about what it shows. **Proposal for discussion (needs Nikola's call before any code):** - Admins get scoped like everyone else by default: their Personal = `/home/<admin>`, their Spaces = their groups. Day-to-day file use looks identical for admins and users. - Backend-wide access moves behind an **explicit, visibly labeled "Backend" view** in the sidebar (admin-only): same full access, but deliberately entered, visually distinct, and — with audit enabled — every read in it attributable. No capability is lost; the blast radius of casual browsing is. - Consequences to check before committing: admin-driven flows that rely on unscoped addressing (moving files between homes, hold paths, space repair, share revocation by actual path) must keep working from the Backend view; peering delivery and share serving already use the unscoped stack internally and are unaffected. **Questions for Nikola:** 1. Is the two-view model (scoped Personal + explicit Backend view) what you want, or do you want admins to have NO whole-backend file access at all (that would be a much deeper change and would break admin repair flows)? 2. Should entering the Backend view require anything beyond being admin (e.g. a confirm click that gets audit-logged), or is the visual separation enough?
Author
Owner

Dogfood evidence (Nikola, v0.6.8). As an admin, the Shares tab lists shares I created across other users' homes, addressed by raw backend path:

/home/nikola-test2
/home/nikola-test/testino

Two things this shows:

  1. Admin is unscoped by default — I could navigate into /home/nikola-test2 and /home/nikola-test/… and create share links for other users' files "this easily." That's exactly the concern here: admins operate on the whole backend as if it were their Personal space, with no explicit "I'm acting on the backend, not my own files" boundary.
  2. The Shares list shows the backend /home/… path, not the virtual path — same display leak as #192 (which fixed the share-created toast, but explicitly deferred the Shares-tab list/revoke strings). Whatever scoping decision lands here should also decide how these rows render (virtual path, or an explicit "backend:" prefix for admin-scoped views).

Feeds the design decision on this issue (scope admins by default; make backend-wide access an explicit mode).

Dogfood evidence (Nikola, v0.6.8). As an admin, the Shares tab lists shares I created across **other users' homes**, addressed by raw backend path: ``` /home/nikola-test2 /home/nikola-test/testino ``` Two things this shows: 1. **Admin is unscoped by default** — I could navigate into `/home/nikola-test2` and `/home/nikola-test/…` and create share links for other users' files "this easily." That's exactly the concern here: admins operate on the whole backend as if it were their Personal space, with no explicit "I'm acting on the backend, not my own files" boundary. 2. **The Shares list shows the backend `/home/…` path**, not the virtual path — same display leak as #192 (which fixed the share-*created* toast, but explicitly deferred the Shares-tab list/revoke strings). Whatever scoping decision lands here should also decide how these rows render (virtual path, or an explicit "backend:" prefix for admin-scoped views). Feeds the design decision on this issue (scope admins by default; make backend-wide access an explicit mode).
Author
Owner

Decision (Nikola): the strict model. Admins are scoped in the WebUI exactly like regular users — Personal = the admin's own /home/<admin>, Spaces = the admin's own groups. There is no native Cairn path to browse another user's home or a space the admin isn't a member of. An admin who genuinely needs another user's data reaches it out-of-band: directly at the storage backend, using the deployment recovery key (the recovery-custody age identity that can decrypt any user's files). That break-glass is deliberate, manual, and outside the UI. (Q2 — gating a Backend view — is moot; there is no Backend view.)

This is the "No backend file access" option, and it removes the whole-backend browser rather than hiding it behind a view.

Consequences to resolve during implementation (the unscoped admin path currently powers these — each needs a scoped answer or an explicit out-of-band story):

  1. Legal holds (#63/#185): today an admin sets a hold on any backend path. Scoped, an admin can only address their own tree in the UI. Options: keep a typed-path admin input for holds (no browser) so compliance holds on others' data still work, or move hold management out-of-band too. Needs a call — folded into #185.
  2. Admin "all shares" view: the moderation surface lists every share with its backend path. Either scope it (admin sees only their own shares) or keep an admin-only all-shares list that shows tokens without leaking /home/<other> paths.
  3. Cross-home move / space repair via UI: gone (was unscoped). Acceptable per this decision — those become out-of-band ops.

Peering delivery and public share serving use the unscoped stack internally (server-side, not the admin UI) and are unaffected. Implementation will center on scope.go (remove the admin exemption) + the nav/Shares surfaces; it's security-sensitive, so it lands with tests.

**Decision (Nikola): the strict model.** Admins are scoped in the WebUI exactly like regular users — Personal = the admin's own `/home/<admin>`, Spaces = the admin's own groups. There is **no native Cairn path** to browse another user's home or a space the admin isn't a member of. An admin who genuinely needs another user's data reaches it **out-of-band**: directly at the storage backend, using the deployment recovery key (the recovery-custody age identity that can decrypt any user's files). That break-glass is deliberate, manual, and outside the UI. (Q2 — gating a Backend view — is moot; there is no Backend view.) This is the "No backend file access" option, and it removes the whole-backend browser rather than hiding it behind a view. **Consequences to resolve during implementation** (the unscoped admin path currently powers these — each needs a scoped answer or an explicit out-of-band story): 1. **Legal holds (#63/#185):** today an admin sets a hold on any backend path. Scoped, an admin can only address their own tree in the UI. Options: keep a typed-path admin input for holds (no browser) so compliance holds on others' data still work, or move hold management out-of-band too. Needs a call — folded into #185. 2. **Admin "all shares" view:** the moderation surface lists every share with its backend path. Either scope it (admin sees only their own shares) or keep an admin-only all-shares list that shows tokens without leaking `/home/<other>` paths. 3. **Cross-home move / space repair via UI:** gone (was unscoped). Acceptable per this decision — those become out-of-band ops. Peering delivery and public share serving use the unscoped stack internally (server-side, not the admin UI) and are unaffected. Implementation will center on `scope.go` (remove the admin exemption) + the nav/Shares surfaces; it's security-sensitive, so it lands with tests.
Cordy closed this issue 2026-08-11 22:38:42 +00:00
Sign in to join this conversation.
No labels
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#177
No description provided.