feat(engine): admit a write target below a proved grafted write root - #1910
Conversation
The facade write guard now admits a create, an upload, a new version, a rename, a move and a delete below a grafted root when this session holds a proved write pass for it. A read grant, an unproved pass and a node the render does not hold keep their refusals. A grantee delete only unlinks the node. It writes no bin entry and re-keys nothing. The owner engine now captures an unlink at the root of an interior scope too, so the node goes to the owner bin. A move stays inside one received share. Restore, purge, version restore and version delete below a grafted root stay refused. A write at or below a scope root nested in the share is refused, because the grafted pass cannot seal there and owner capture cannot bin a scope root. The facade admits a write only below a root the last tick built a drain pass for. An op that a cut grant strands below a graft is charged and parked as a dead letter, so the queue behind it drains. A focus leg below a grafted root feeds no owner capture, so the sharer's departures do not fill the bounded set. The web client offers the in-share writes where the engine reports write permission. The staging writable-share profile runs again, and a local web-e2e spec covers the write grant in the PR gate.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository: FSM1/cipher-box/.coderabbit.yaml Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (15)
Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review. WalkthroughThe engine now admits writes inside proved writable received shares, restricts operations to the granted scope, and routes deletions to owner capture. The web UI exposes permitted in-share actions while withholding owner-only actions. Unit, integration, and end-to-end tests cover these behaviors. ChangesWritable received-share engine
Priority: ➖ Normal Estimated code review effort: 5 (Critical) | ~90 minutes Change: Feature · Severity of issue fixed: Medium Sequence Diagram(s)sequenceDiagram
participant RecipientUI
participant RecipientEngine
participant OwnerEngine
participant OwnerCapture
RecipientUI->>RecipientEngine: create or delete within writable share
RecipientEngine->>RecipientEngine: validate proved write home
RecipientEngine->>OwnerEngine: publish in-scope operation
OwnerEngine->>OwnerCapture: report received deletion
OwnerCapture->>OwnerEngine: create owner bin entry
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
@coderabbitai review |
|
|
Closes #1886.
Part of #1880.
What this changes
The facade write guard now admits a write below a grafted root when this session has proved a write pass for that root. The proof is: the last tick built a grafted drain pass for the root, and the owner-committed permission is still
writeand the write scope seed is still in memory. The drain proves its facts again on each tick, and the adoption gate still judges every record.This is the last slice of the writable-received-share build. The staging writable-share profile runs again.
The admitted and refused commands below a grafted root
ScopeExitRefusedScopeExitRefusedScopeExitRefusedScopeExitRefusedScopeExitRefusedScopeExitRefusedScopeExitRefusedreplacing, create inside)ScopeExitRefusedScopeExitRefusedScopeExitRefusedScopeExitRefusedScopeExitRefusedScopeExitRefusedScopeExitRefused(see the follow-up below)ScopeExitRefusedA node that the render does not hold keeps the verdict that the rebase gives it.
The delete of a grantee (owner decision of 2026-09-19)
to_bin = falsebelow a grafted root. A grafted drain pass only unlinks the node: it writes no bin entry, re-keys nothing and journals no reclamation.install_descendant_scopesnow reports those departures.Defects found and fixed
Web
SnapshotView.permissionreadswritefor a received share only when the write pass is proved. The file browser offers its write affordances onpermission, and it hides share, version restore and version delete inside a received share.tests/web-e2e/tests/write-grant.spec.ts(smoke slice, so the PR gate runs it): the recipient uploads, creates a folder and deletes inside the granted folder. The owner reads the writes back, and the deleted file appears in the owner bin and not in the recipient bin.tests/web-e2e/staging/writable-share.spec.ts: thetest.fixme()hold and its comment are removed.grantByCodeintests/web-e2e/sharing.ts.contact-grant.spec.tsuses it and now also asserts that a read grant offers no write.Durable queue
No queued op gets a new field. The delete op already carries
to_bin.Tests
WriteGranteeharness, real facade and real drain):a_write_grantee_authors_every_admitted_write_inside_the_granted_scope,a_write_grantees_delete_only_unlinks_the_node,a_write_grantee_is_refused_what_leaves_the_scope_or_reaches_the_owners_surfaces,a_read_grant_or_an_unproved_write_pass_admits_no_write,an_op_a_cut_grant_strands_parks_rather_than_stalling_the_queue.a_journal_target_outside_this_vaults_tree_is_refused(re-stated forwrite_home),a_grafted_relocation_stays_inside_one_share.a_write_grantees_delete_reaches_the_owners_bin_by_owner_captureincrates/engine/tests/owner_actions.rs. The owner grants write, the recipient engine accepts and deletes, and the owner engine bins the node.a_version_command_on_a_file_outside_this_vaults_tree_is_refused(re-stated: it also refuses a new version where no write pass is proved).a_grafted_pass_is_refused_every_vault_level_op_planno longer lists the hard delete. Focus:a_withheld_child_is_neither_relinked_nor_removednow asserts that a grafted leg feeds no capture.Local runs:
cargo fmt --all --check, clippy (workspace, and wasm32 for the engine and wasm crates),cargo test -p cipherbox-engine,pnpm -r typecheck,pnpm lint,pnpm lint:md,pnpm lint:tracker-refs, theapps/webvitest suite (761 tests). On the local web-e2e stack,write-grant.spec.ts,contact-grant.spec.ts,shared.spec.tsand the full-slicebin,sharing,invite,cross-client,write-pathandsave-pathspecs pass. The full local suite fails only on the login-button, device-approval and release-bundle specs, which need the Web3Auth build variables that this machine does not have.Reviews run before the draft
Movewithreplacingthat could remove a nested scope root; a journal-time proof narrower than the drain's; and an own-scope exclusion that missed minted and unproved roots.--agent --base-commit): 0 findings.Body checks / follow-ups filed
post-cutover,comp:engine, child of engine: the hardening track for post-review follow-ups #1702): a content read or version-history read below a grafted root opens under the vault root seed and fails with aTrustViolation. This is why version restore stays refused here.Note
Admit writes below a proved grafted write root in engine and web UI
SnapshotViewnow reportsPermission::Writefor a received scope only when the session holds a current proved write pass; otherwise it reportsRead. The webFileBrowserenables its write surface onwritepermission, andFileBrowserActionsexposes rename, move, and delete for write-granted received shares but omits sharing and version-history actions.install_descendant_scopesnow accepts an observation timestamp and returns unlinked-child records so owner capture can process departures from adopted scope roots.Engine::base_sequence_forand all mutation/upload arms now use role-aware write-home checks viaEngine::write_homeinstead of the old blanket outside-vault refusal. A write below a received scope is refused when an intervening folder's published IPNS name is not derived from the grantee's cached write seed. Session reset clears thegrafted_write_rootsstate.drain.rspublish_deleteskips the vault-surface refusal whento_binis false, allowing grafted hard deletes to proceed.Macroscope summarized 0f2b413.
Summary by CodeRabbit
New Features
Bug Fixes