A read-only grant offers the full write menu under /shared (#529 2/3 follow-up) #588
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#588
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?
Found in the v0.6.213 live pass, signed in as the recipient of a
Can viewgrant.What happens
nikola-testgranted/home/nikola-test/moverinitonikola-test2with roleread. Asnikola-test2, opening#/shared/nikola-test/moverinishows the breadcrumb/ shared / nikola-test / moveriniwith a View only badge — correct — and the folder contents decrypt correctly, which is #570's overlay doing its job.The row menu on a file inside that folder offers, in order:
Open·Download·Share·Copy link·Send to peer·Copy to…·Move·Rename·Create space from selection·Add to favorites·Lock·Details·DeleteEverything in bold is either a write to someone else's file or a re-share of it. The toolbar above also still shows Upload file and New.
Why it matters
The backend is not the problem.
scope.Driver.Delegatedanswers "was this path reached through someone else's grant" and the re-share API refuses before writing anything — #575 landed that with a test asserting both the 403 and that the store stayed empty. Role enforcement on writes sits behind the same scope.So the failure is presentational, and that is exactly what makes it worth fixing rather than shrugging at: the UI invites a recipient to do eight things the server will refuse, two words away from a badge that says View only. The user learns the product is broken, when in fact the product is correct and the menu is lying.
Deleterendering in danger red on a file you do not own is the sharpest version of it.This is also the fourth failure in this slice with the same shape — correct logic, wrong surface. #580 (switch never reached the page), #582 (grant rendered as a link), #586 (save bar never appeared), now this.
What the fix needs to decide
Two separate gates, and they are not the same gate:
Share,Copy link,Send to peer,Create space from selection— should be absent wheneverDelegatedis true, at any role. A recipient withwritestill must not become a second grantor; that was decided in #571 and made structural in #575.Move,Rename,Delete,Lock, and the toolbar'sUpload file/New— should follow the grant's role: absent onread, present onwrite.AllowUploadgoverns upload specifically, and that role does not exist yet — see #589.Worth confirming while implementing: whether
Add to favoritesandDetailsare safe on a delegated read path (they look local-only, but check), and whetherCopy to…is a read of the source plus a write to the caller's own tree — if so it is legitimate onreadand should stay.Suggested test
The house pattern from
web/test/settings-load.test.jsfits: lift the row-menu builder, feed it a delegated read scope, and assert the built menu contains none of the forbidden verbs. Pure list-of-labels assertion, no DOM needed. Add thewriteand non-delegated cases so the gate cannot be satisfied by hiding everything.Reproduce
Can view.Fixed in #593, shipped as v0.6.214, live on both dogfoods.
Two gates, as the issue asked, kept distinct:
share(false anywhere under/shared— re-sharing and re-addressing never offered at any role) andmutate(false when the listing carries the #64readOnlyflag — Can-view recipients and read-only space members alike).Copy to…survives every role, as anticipated: it reads the source and writes only to the caller's own tree.Two findings from implementation worth the record:
applyReadOnly(#64) has disabled Upload/New on read-only listings all along — but the upload control is alabelwrapping the file input and nothing styled the disabled state, so it looked live (the #552 lesson, again). One.rodisclass fixes the look; behaviour was already correct.mutaterides the same server flag #64 already sets for read-only space members, they also stop being offered Move/Rename/Delete/Lock — a gap that predates #571 entirely.Coverage is the glue, not just the mapping:
web/test/row-menu.test.jsliftsopenRowMenuand builds the real menu against a fake DOM in four scenarios (delegated read, delegated write, owned, read-only space), plus a pure truth-table formenuGates. Red witnessed on all five before the splice.Remaining: an eyeball on the dogfood as the recipient — sessions are in-memory, so the v0.6.214 rollout needs a fresh login first. The
nikola-test → nikola-test2grant onmoveriniis still in place for exactly that.