What happens to shares when an account is removed? (research + decision) #569
Labels
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: Cordy/Cairn#569
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Split out of #529's mockup review (2026-09-17). Nikola: "for now we have 'an admin can see them' in place, but the instinct to get a decision on this is right."
The question
When an account is removed — a local account deleted, or a directory account that stops existing — what happens to the shares that account created?
Once #529 gives
share.Storean addressee, every share has two identities that can disappear: the creator and the addressee. The failure modes are different and both need an answer:CreatedBydanglesThe addressee half is settled. This issue is about the creator half, which is not.
What Cairn does today
Nothing deliberate.
share.SharecarriesCreatedByas a string;Store.List(ctx, createdBy)filters by it. Removing the account does not touch the shares. So the shares keep working, owned by a name that no longer resolves, and the only way to find them is an admin listing.That is accidentally the fail-closed-ish answer, but it was never chosen, and it has a sharp edge worth naming: a public link created by a departed employee keeps serving their files. Nobody is notified, nothing expires, and the file is still readable by anyone holding the URL. For a product whose pitch is that the instance admin is accountable for what is on their own hardware, that is the wrong default to arrive at by omission.
There is a second-order problem specific to Cairn: after #529, a read goes through the owner's key scope. If the owner is gone, whose scope opens the file? The recovery identity presumably — but that path needs to be deliberate, not incidental, and it interacts with key custody (#528) and the retained-key rotation story.
Deep research task
Use Superpowers. Compare ownCloud, oCIS, Nextcloud and Seafile:
Then propose options with a recommendation, the way #529's crypto question was handled: state the constraint first, lay out the two or three real choices, recommend one, and name the consequence that has to be said out loud rather than buried.
Scope
Research and a recorded decision. Implementation is a follow-up once the decision exists — it may well be small (an admin listing plus a defined rule), but the rule has to be chosen before it is coded.
Blocked by nothing. Wants to be settled before the closed beta, since the first real user deletion will otherwise settle it by accident.
Research done — four products, two failure families, options + recommendation below
1. What each product actually does on user deletion
Nextcloud — deleting a user deletes their files and every share they created, public links included. The escape hatch is
occ files:transfer-ownership, run manually before deletion; it moves files plus outgoing shares into a subfolder of the target user. Trash is not transferred, incoming shares are not moved by default. There is no automatic step, no warning in the deletion flow, and admins who deleted first and read the manual second show up in the forums asking how to restore from backup.ownCloud classic — same model; the admin manual warns outright that deleting a user destroys everything they shared. There is a
cleanup-orphaned-sharesmaintenance command, which tells you orphans happen often enough to need a broom.oCIS — the opposite failure: deletion orphans content instead of destroying it. A deleted user's personal and project spaces keep existing (#4195), the admin cannot access or delete them (#4194, #4196), and removing a space's only Manager leaves the space unmanageable by anyone including admins (#4105, #7265). Undead data nobody controls — on the product whose whole redesign was supposed to fix this class.
Seafile — library-centric: deleting a library cancels all shares in it (restorable from admin trash); user deletion is handled by admins transferring libraries, with its own bug tail — ownership transfer drops assigned user/group permissions (forum 16706), transferring groups from a deleted user misbehaves (forum 14484).
2. The pitfalls they hit
The transfer tool is where Nextcloud bleeds: public shares silently deleted on transfer (#60223, root cause a cascade-delete via the
parentcolumn, fixed only in #64209 — this September); "share points at deleted file, skipping" losing shares mid-transfer (#25693); silent failure on insufficient target quota (#31868); files invisible in the web UI after transfer on object storage (#48463). Beyond the tool: deleting a shared file leaves orphaned link rows serving an error page (#46369), and NC18 once cascade-wiped the wholeoc_sharetable off one federated-share removal (forum).3. What users say
The recurring thread shape is "we migrated auth / offboarded someone / cleaned up accounts, and the shares vanished" — e.g. deleted users and shared links are gone, recover from backup? (local→AD migration deleted every share those users had made). Nobody is warned at deletion time; discovery is downstream, by the people the shares were serving.
4. What this means for Cairn
Two failure families to avoid: cascade surprise (Nextcloud/ownCloud — deletion silently destroys shares, sometimes other people's) and undead orphans (oCIS — content survives that nobody, admin included, can govern). Both stem from the same omission: no preview, no deliberate rule, no notification.
Cairn has one constraint none of them have, and it decides half the question for us: reads resolve through the owner's key scope. On
keycloak-profilecustody, a vanished directory account takes its key with it — a departed owner's grants and strong links cannot keep serving through the normal path, only through a deliberate recovery-identity code path. So "keep everything working like nothing happened" is not a lazy default available to us; it would have to be built on purpose. Good.Options
A — Freeze, surface, decide (recommended). When the creator no longer resolves — deleted locally or vanished from the directory — everything they created stops serving: grants stop resolving (already the fail-closed rule for addressees; apply it to creators symmetrically) and public links answer 404 exactly like an expired link. Nothing is mutated; files stay where they are. The admin gets a Departed owners listing (shares grouped by dangling
CreatedBy) with per-share revoke and, if the content must stay shared, the admin re-shares it from an account that exists — an explicit, audited act by an accountable person, not a silent transfer. Local deletion gets a confirmation dialog listing what will stop serving (the preview every competitor lacks).B — Cascade revoke on local deletion + freeze for directory accounts. Deliberate delete-time revocation (audited) for local accounts, freeze for IdP vanishing (which has no deletion event to hook). Two rules where A has one; the split invites the Nextcloud class of surprise on the local path, and the end state is the same bytes-wise. Only worth it if "deleted = record gone" matters more than a uniform rule.
C — Transfer-ownership tooling. The competitors' answer, with their documented bug tail, and in Cairn a transfer is a cross-scope move, which re-encrypts — colliding with holds (#138-class), versions (#541) and quota. Not for v0.7; if real demand appears, build it later on top of A, as an explicit admin action.
The consequence said out loud, per the brief: under A, the day someone leaves, their public links die. That is the point — a departed employee's files should not keep flowing outward under nobody's accountability — but it will surprise whoever was consuming the link, so the handbook states it and the Departed-owners panel makes the re-share one click for the admin. The alternative (links that keep serving via the recovery key) means the server routinely decrypts with the break-glass identity — a much worse sentence to have to write down.
Implementation size if A is chosen: small, as the issue hoped — a creator-liveness check where grants resolve and where
/s/serves (needs a "known principals" oracle: local store + seats seen-list + live IdP answer, fail-frozen on IdP outage so an outage doesn't mass-kill links — freeze is temporary and self-heals when the directory returns); the Departed-owners admin listing; the local-delete confirmation preview; audit verbs; handbook sentences. Interacts cleanly with #595 (same governance neighborhood) and gives #569's addressee half its mirror.Your call — A, B, or C (or A with amendments).
Decision (Nikola, 2026-09-18): Option A as the automatic rule, plus Option C built deliberately on top of it — from the start, not later.
Rationale, in his words: transfer tooling is already a market demand (every competitor's admins reach for it, and Nextcloud only just fixed its worst transfer bug); "showing up to a market with the solution in hand already is better than showing up with a marginally better solution."
So the shipped behaviour will be:
Cairn-specific design lines for the transfer, so we do not import Nextcloud's bug tail:
encrypt/group.go), already refuse under legal hold, already hit quota and audit. A transfer is "move/home/<gone>/…into/home/<target>/…" plus rewriting the affected share records — not a parallel copy machine.CreatedBybecomes the target admin-chosen owner, addressees untouched. Fail loudly on any record that cannot be re-pointed; never skip-and-continue (the "share points at deleted file, skipping" lesson).Implementation issue follows with the full brief; the Departed-owners panel and the transfer flow get a mockup before any UI is built.
Closing: this issue's scope (research + recorded decision) is complete — Option A (freeze + surface) with C (transfer) built on top, decided 2026-09-18 above — and the implementation shipped and closed as #597. Live UI verification of the departed-owner flow is pending as a dogfood exercise (delete one of the sharer1/sharer2 test accounts, confirm the frozen rows, Departed-owners listing, delete preview and transfer); any findings there get filed as fresh issues against the shipped behaviour.