Skip to content

Add a folder-scoped Google Drive resource - #440

Open
ndisidore wants to merge 1 commit into
mainfrom
feat/gk-google-drive-folder
Open

Add a folder-scoped Google Drive resource#440
ndisidore wants to merge 1 commit into
mainfrom
feat/gk-google-drive-folder

Conversation

@ndisidore

@ndisidore ndisidore commented Sep 3, 2026

Copy link
Copy Markdown
Member

Adds a fourth Google Drive resource, scoped to one folder and everything currently
beneath it, read-only. It covers a folder in My Drive, including one someone else
shared with you, and an ordinary subfolder inside a shared drive; a shared drive's
own root stays with the existing Shared Drive resource. It requests the same three
read-only scopes as the account and exact-file resources rather than the wider
drive.readonly that Shared Drive needs.

Folder-derived Doc and Sheet sessions re-prove ancestry on every method call, not only
at open, so a file moved out of the subtree stops answering through a session that is
already open. Drive has no ancestry-plus-content transaction, so a move landing after
the final check still returns and the next read denies.

2026-09-03_18-59
Devin Review

@github-actions github-actions Bot added the gatekeeper Changes to a gatekeeper integration label Sep 3, 2026

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

3 flags not posted on this PR by your GitHub settings — view them in Devin Review. (Configure)

Devin Review

let folder = await readFolderRoot(scope.folderId, id => api.getFile(id));
return {
// The natural browser URL, not the internal `_resource` selector the grant is keyed on.
url: `https://drive.google.com/drive/folders/${encodeURIComponent(scope.folderId)}`,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Folder sharing requests wrong grant

describe() labels folder bindings with the shared-drive URL grammar. Collaborator setup then requests the wrong resource grant and broader permissions.

Prompt for agents
Folder bindings use an internal _resource URL as their grant identity, but GoogleDriveGatekeeperImpl.describe returns the natural /drive/folders/:id URL. The Workshop persists ResourceDescription.url and ObserverConfigModal resolves that URL against supported resource patterns when deciding which grant a collaborator needs. Because /drive/folders/:id is the shared-drive pattern, folder bindings are classified as shared drives and request drive.readonly. Preserve the natural browser URL for display while giving observer grant resolution an unambiguous folder resource identity. This likely requires carrying or using the original typeUrlPattern or creation resource URL rather than inferring the grant type from ResourceDescription.url.
Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Confines the existing read-only GoogleDriveSession API to one selected
folder's current descendant subtree, for both My Drive folders and
ordinary subfolders inside a shared drive. A shared drive's own root
stays with the Shared Drive resource.

Drive v3 offers no folder corpus, no folder-scoped token, and no
recursive ancestor predicate -- `'<id>' in parents` means direct
children only -- so membership is proved in the gatekeeper.
drive-folder-scope.ts walks each candidate's parent chain upward through
freshly batched files.get metadata, level by level, admitting only
acyclic same-domain chains of live folders that reach the root within
Drive's 101-hop nesting limit, then re-reads every node on the surviving
paths immediately before disclosure. Nothing is cached across the
operation that proved it: a hierarchy change rotates no credential and
bumps no cache generation.

The grant identity is an internal `/_resource/folder/:folderId` path
rather than the natural browser URL, because `/drive/folders/:driveId`
is already the shared drive's permanent identity and its pattern leaves
the query component wildcard -- a query-qualified variant would match
both resources and make resource selection order-dependent. describe()
still reports the natural URL for the UI.

Folder-derived Doc and Sheet children now revalidate: DriveSessionCore
.nativeRead() re-proves ancestry and the exact native MIME type before
the provider is contacted, re-checks the proved chain before any
approval, and discards the fetched value if either fails. Drive has no
ancestry-plus-content transaction, so a move landing after that final
check still returns; the next read denies, and the method says so.

CursorPager's authorize() now takes `exhausted` and its page budget is
maxProviderPagesPerCall: reaching the bound authorizes the empty
nonterminal page and returns [] rather than throwing, so a folder cursor
can filter a whole page without claiming there are no results. Only an
exhausted cursor reaches the empty-search path, which now fences
observer admission through ObserverTracker.prepareWithheld() -- a
withheld read registers no tracked set, so addObserver would otherwise
verify a candidate against nothing. The Drive observer denial no longer
names a file ID.
@ndisidore
ndisidore force-pushed the feat/gk-google-drive-folder branch from 24a03b3 to 7256fd6 Compare September 3, 2026 22:56
@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown

Preview: pr440-feat-gk-googl-62f8970b

https://pr440-feat-gk-googl-62f8970b-router.cloudflare-os-previews.workers.dev

Dashboard · deleted when this PR closes

@ask-bonk

ask-bonk Bot commented Sep 3, 2026

Copy link
Copy Markdown
  • High: drive-session.ts:470-472 returns unaudited empty pages after filtering. This leaks out-of-scope corpus page counts and enables search-term probing outside the bound folder.
  • Medium: drive-session.ts:419 revalidates only the root. A directParentId moved outside the subtree after cursor creation produces misleading empty results and can permanently latch observer admission closed. Revalidate it on every page.

github run

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gatekeeper Changes to a gatekeeper integration

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant