perUserHomes: home directory not materialized at login — fresh users fail the peering residency check #146
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#146
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?
Fourth live find of the #106 dogfood. A brand-new local-auth user (
Niko-teston the beta instance) logged in successfully, appeared in the receivers allowlist, peer names matched — and inbound transfers still failedSTATUS_UNKNOWN_RECIPIENT.Cause:
peerRecipients.Existsimplements "allow-listed AND resident here" with residency =Stat("/home/<recipient>")succeeding. But logging in does not create the home directory — it is materialized lazily by the first write. A user who has authenticated but never uploaded anything is invisible to peering (and their own Personal view 404s until first write, visible in the request log as aGET /api/v1/files 404loop).Intent vs implementation: residency-by-login is the design's evident intent; residency-by-first-upload is what's implemented. The gap only shows for fresh users, which is exactly the "new colleague receives their first file via peering" scenario the feature is for.
Fix options:
/home/<user>at successful login (all auth modes). Small, matches intent, also fixes the 404 loop on a fresh user's Personal view. Recommended.MkdirAllimplicitly — rejected: it would make the residency check meaningless (any allow-listed name becomes "resident").Found because the beta instance uses local auth where users only exist after
/setup; on the OIDC dogfood every user had long since uploaded something.Live confirmation plus a sharpening: the recipient on the beta instance is an admin, and admins are deliberately unscoped (scope.go: "Admins are NOT scoped: they address the whole backend directly"). So an admin's uploads land at the backend root and never materialize
/home/<user>— for admin recipients the lazy-materialization gap isn't just "hasn't uploaded yet," it's permanent: no amount of normal usage ever creates their home. The workaround used in the dogfood was manually creatinghome/<user>from the admin's root view.This strengthens option 1: materialize
/home/<user>at successful login for every authenticated user, admin or not — login is the one event both scoped and unscoped users share. It also means the fix must not route through the scoped store (admins bypass it); do the MkdirAll against the unscoped store at the auth layer.Shipped in v0.4.12 (PR #149), live on the dogfood. Option 1 as recommended:
auth.WithHomeEnsure— a Provider decorator with the inner Provider embedded (soChallengeand any future interface methods forward untouched; onlyAuthenticateis intercepted). On first successful authentication per username it materializes/home/<username>through a callback wired to the unscoped store (Mkdir /homethenMkdir /home/<user>, errors ignored — the same lazy-ensure semantics as scope). Gated onHomesEnabled(); sits at the top of the provider chain so every auth mode (local, OIDC, LDAP, Basic/WebDAV) and both scoped and unscoped users pass through it. Fresh users are peering-visible from their first login; admins are no longer permanently invisible. Unit-tested: fires exactly once per user, never for unauthenticated requests.