Expand description
Folder-scoped write-permission gate (issue #1574).
omni-dev’s own local policy layer bounding drive create/upload/
edit, independent of and enforced in addition to whatever the OAuth
scope (crate::drive::auth::DriveGrantedScopes) would technically
allow. Google’s Drive scopes are all-or-nothing across a user’s whole
Drive — there is no Google-side way to say “this credential may only
write inside folder X” — so this module fills that gap.
Deliberately pure: zero DriveClient/network dependency, mirroring
crate::drive::visibility’s contract exactly. Fetching the ancestor
folder chain a target lives in is crate::drive::folder_ancestry’s job;
this module only classifies an already-resolved chain.
Named write_gate, not permission(s), to avoid any confusion with
crate::drive::permissions_api — Google’s own sharing/ACL wrapper,
a completely unrelated concept.
§The algorithm
A target (the --parent folder for create/upload, or a file’s
current parent folder(s) for edit/sheets write) is identified by
its ancestor chain: chain[0] is the target folder itself,
chain[1] its parent, chain[2] its grandparent, and so on up to
Drive’s root. resolve walks that chain looking for the closest
(lowest-depth) rule naming any folder in it — a non-recursive rule only
ever matches at depth 0, its own folder; a recursive rule matches at
any depth. Two tie-breaks, both security-relevant and each covered by a
dedicated test:
- Closest ancestor wins: a rule on a subfolder overrides a broader rule on its parent — the more specific grant/restriction is assumed the more deliberate one.
- Deny beats allow at equal depth: if two rules at the same depth disagree, the safe direction wins.
A rule may instead name a file id (issue #1612), which matches the
target itself at depth −1 — strictly closer than depth 0, so it
beats every folder rule in both directions: a file deny overrides a
recursive folder allow, and a file allow overrides a folder deny.
That is the same “closest wins” principle, not an exception to it. Two
consequences worth stating outright:
- Because nothing in any chain can beat a file rule, a decisive one
short-circuits the ancestor walk entirely — see
resolve_for_fileandcrate::drive::folder_ancestry::resolve_decision_for_file_target. This is what makes a file shared by link or email grantable at all:files.getreturns only the parents the caller can see, so such a file has none, and no folder rule could ever apply to it. combine_across_parents’ “deny wins” is a tie-break among peers — a target’s several legacy parents, all at the same level. A file rule is not a peer, so a fileallowstill beats a denying parent.
When no rule anywhere in the chain names op, DriveOperation::default_policy
decides it: Read defaults to Verdict::Allow, every write operation
defaults to Verdict::Deny. This is where “disabled by default” for
writes actually lives — there is deliberately no separate enabled/
disabled toggle; an absent or empty rule list already means “deny
everywhere” via this table alone.
Structs§
- Decided
ByLog Fields - The
(folder_id, file_id, depth)triplecrate::request_log::DriveMutationOutcome’sdecided_by_folder_id/decided_by_file_id/decided_by_depthfields expect. - Decision
- The outcome of
resolve: whether an operation is permitted, and which rule (if any) decided it. - Folder
Permission Rule - One configured permission rule, keyed on either a folder id or a
file id — exactly one of the two, enforced when the settings file is
deserialized (see the private
RawPermissionRulebelow).
Enums§
- Deciding
Rule - Which configured rule (if any) decided a
Decision. - Drive
Operation - A Drive operation this gate can permit or refuse. Reused directly as the
settings-file rule shape (
crate::utils::settings::WritePermissionsSettings) — no separate wire type. - Verdict
- The result of resolving a single operation against a rule set.
Functions§
- combine_
across_ parents - Combines per-parent
Decisions into one, for a target with more than one current parent (a legacy multi-parent file — Drive no longer permits creating new ones). - decided_
by_ log_ fields - Splits an optional
DecidingRuleinto the log’s flat fields. - decided_
rule_ requires_ lease - Whether the rule(s) that decided
decided_byrequire a Drive write lease (ADR-0080 §1/§13), in addition to this gate’s own verdict. - resolve
- Resolves whether
opis permitted againstchain(depth 0 = the target folder itself, then parent, grandparent, …) underrules. See the module doc for the full algorithm and its tie-breaks. - resolve_
file_ rule - The verdict from a rule naming
file_iditself, orNonewhen no configured rule names it. - resolve_
for_ file - Resolves
opfor a file target: a rule namingfile_idif one exists, elseresolveagainst the file’s ancestorchain.