Proposal: Google Drive Storage Backend
Status: future design. No implementation. The native backend is gated behind the userspace-driver authority gate, a userspace network stack, an outbound TLS client, an HTTP client, and the OAuth2 service – none of which exist yet. The browser-transport model is the near-term path and is already partially specified in
storage-and-naming-proposal.md.
Summary
Let a Google-authenticated user use their own Google Drive as a capOS storage
backend, exposed behind the same storage capabilities apps already use
(Store / Namespace / Directory / File, and the AppData cap from
docs/proposals/standard-app-capabilities-proposal.md). The user’s Drive –
specifically the per-app appDataFolder space – becomes the backing for an
app’s AppData cap, and selected user files become File caps minted through
the powerbox.
There are two delivery models, and this proposal keeps them explicit because they have very different trust and readiness profiles:
- Browser-transport (near-term): the user’s browser holds the Google OAuth
session and does the TLS/HTTP to Drive; capOS never sees Google tokens and
stores only encrypted capsules in
appDataFolder. This is already sketched instorage-and-naming-proposal.md(“User-Owned Browser Transport”) and is feasible without a capOS network/TLS/OAuth stack. - Native backend (deep-future): a capOS userspace service holds the OAuth refresh token and performs outbound HTTPS to the Drive API itself. This is the more capable model and the more demanding one – it sits behind the full network/TLS/HTTP/OAuth dependency chain.
In both models, Drive sits behind a backend adapter, not pretended to be a set of first-class local object caps (see Trust Model).
Why Drive
- The user already owns the storage and the quota; capOS does not provision a server.
- The
appDataFolderspace is a near-exact fit for the per-appAppDatacap: Google already provides per-app private storage invisible to the user and other apps under the narrow, non-sensitivedrive.appdatascope. - Drive’s
drive.file+ Picker consent model maps onto the capOS powerbox, so user-selected files become capabilities without granting the all-files scope. - It is a concrete, widely-available validation of the storage caps’
backend-agnosticism that
storage-and-naming-proposal.mdalready asserts (“Store service backed by virtio-blk, RAM, or network”).
Architecture
A userspace Drive storage service implements the standard storage cap interfaces and translates their methods into Drive REST calls:
app --(File/Directory/Store/AppData cap)--> Drive storage service
| uses
v
DriveAccount cap (OAuth tokens) --> OAuthClient / AccessToken
| (oidc-and-oauth2-proposal)
v
OutboundHttpRequest --> TLS client --> userspace net stack
(networking) (certificates-and-tls)
- The service consumes, does not redefine the OAuth capabilities from
oidc-and-oauth2-proposal.md(OAuthClient,AccessToken.authorize/attenuate,RefreshToken), passing each Drive request as theOutboundHttpRequeststruct thatAccessToken.authorizedecorates with the bearer credential. The refresh token lives in the OAuth service; the Drive service holds aDriveAccountcap that exposes only the typed operations the user consented to. - It consumes the outbound TLS client from
certificates-and-tls-proposal.mdand the HTTP client / userspace network stack fromnetworking-proposal.mdPhase C. - It is the network analog of the virtio-blk-backed FS service in
docs/proposals/storage-and-naming-proposal.md: sameDirectory/File/Storecaps in front, a different backend behind.
Concept mapping (Drive -> capOS standard caps)
| Drive | capOS standard cap (Proposal A) |
|---|---|
appDataFolder space (drive.appdata) | AppData cap backing |
drive.file + Picker selection | powerbox FilePicker returns a File cap |
| File id | the File cap handle |
| Folder | Directory cap |
Roles (reader/writer) | shareAs wrapper caps |
| Shortcut | Namespace binding |
| Revisions | content-addressed Store blobs + pointer |
| OAuth scopes | (not modeled internally) method-narrowed DriveAccount |
A key consequence: capOS does not model OAuth scopes internally. A
DriveAccount cap exposes only the methods the user consented to; “read-only
Drive access” is a DriveAccount whose wrapper omits write methods, not a
drive.readonly scope string re-checked server-side.
Dependency stack and gating
A native Drive client backend needs, bottom-up:
| Layer | Need | capOS state |
|---|---|---|
| NIC / virtio-net | packet I/O | partly present (virtio-net MSI-X + delivery); driver must move to userspace |
| TCP | reliable stream | present (smoltcp, in-kernel/transitional); must move to a userspace net process |
| TLS 1.2/1.3 | confidentiality + server auth (X.509 chain, trust roots, AEAD/ECDHE) | not implemented – certificates-and-tls-proposal.md is future design (rustls + webpki-roots planned); the hardest single piece |
| HTTP/1.1 or HTTP/2 | Drive REST transport (Google prefers HTTP/2) | not implemented |
| JSON | request/response + metadata; resumable upload state machine | tractable (serde_json no-std) |
| OAuth2 token flow | PKCE/device-flow handshake, refresh->access exchange, sealed refresh-token storage | designed but unimplemented (oidc-and-oauth2-proposal.md) |
| Trusted wall-clock | token expiry, cert validity, permission expirationTime | weak today; needed for TLS cert validity |
The native backend is therefore gated on, in order:
docs/backlog/hardware-boot-storage.md Task 5 (userspace-driver authority
gate) -> networking-proposal.md Phase C (userspace net stack + NIC driver) ->
certificates-and-tls-proposal.md (outbound TLS) -> an HTTP client ->
oidc-and-oauth2-proposal.md (OAuth service). This is the same authority gate
that blocks userspace networking generally; the Drive backend is one of its
downstream consumers, not a way around it.
Delivery models
Browser-transport (near-term)
The user’s browser, already authenticated to Google, holds the OAuth session
and performs the TLS/HTTP to Drive. capOS hands the browser an opaque,
client-side-encrypted capsule to store in the app’s appDataFolder; capOS
never sees Google tokens. This reuses the remote-session / browser-capability
surface and the KMS envelope-encryption pattern in
storage-and-naming-proposal.md (“User-Owned Browser Transport”). It is
feasible before any capOS network/TLS/OAuth stack exists, and is the
recommended first delivery. This proposal’s role here is to reconcile that
existing section with the AppData/powerbox vocabulary, not to redefine it.
Native backend (deep-future)
A capOS Drive service holds the OAuth refresh token and does outbound HTTPS
itself. For a headless/embedded OS the realistic OAuth flows are
authorization-code + PKCE with a loopback redirect (http://127.0.0.1:port)
when a same-host browser is reachable, otherwise the device flow (show URL +
code on one device, poll for tokens). PKCE is non-negotiable – capOS has no
trustworthy on-device confidential client secret. Token lifecycle: persist only
the refresh token in a sealed cap (an AppData-style or credential_store
secret), exchange for short-lived access tokens on demand, and treat the access
token as an ephemeral bearer credential passed to the HTTP path, never
persisted.
Trust model and honest mismatches
A Drive-backed File is not a true local object capability – it is a
bearer credential to a remote, server-authoritative ACL. The authority lives
on Google’s server, which re-checks it on every request against a mutable table.
Consequences the design must respect:
- No local revocation/attenuation guarantee. Dropping a local handle does
not revoke access Google still grants; narrowing a
DriveAccountwrapper does not change Google’s server-side scope. capOS can wrap Drive behind the adapter but cannot give a remote file the local revocation/attenuation semantics of a true cap. - Offline = non-functional. Unlike a local cap, a Drive-backed cap is dead without network.
- Global mutable namespace / instant org-wide revoke are Drive server-authoritative features with no clean local-cap equivalent; they stay behind the adapter.
- Quota is Drive’s per-user pool, not a per-cap budget; an app’s
appDataFolderusage counts against the human’s Drive quota.
Therefore Drive is exposed strictly as a backend adapter that serves the storage caps with documented remote semantics, never as a drop-in for local object caps. Apps that need local revocation/attenuation/offline guarantees should use a local backend; apps that want the user’s Drive accept the remote semantics.
Phasing
- Reconcile + capsule model (near-term, browser-transport): align the
existing “User-Owned Browser Transport” section of
storage-and-naming-proposal.mdwith theAppData/powerbox vocabulary; define the encrypted-capsule format and theappDataFoldercapsule lifecycle. No capOS network/TLS/OAuth dependency. - OAuth service + outbound HTTPS prerequisites (deep-future): land the gated chain (userspace net stack, TLS, HTTP, OAuth service) per their own proposals. This proposal only consumes them.
- Native
DriveAccount+ Drive storage service (deep-future): implement the service that mapsAppData/File/Directory/Storeonto Drive REST using the OAuth/TLS/HTTP caps; prove anappDataFolderround-trip and a powerbox-picked file read in a QEMU smoke against a Drive API stand-in. - Sharing bridge (future): map
shareAsto Drive permissions where the remote semantics allow, with the bearer/clawback caveats flagged.
Relationship to existing proposals
docs/proposals/standard-app-capabilities-proposal.md– defines theAppData/powerbox/shareAscaps this backend serves.docs/proposals/storage-and-naming-proposal.md– owns the storage caps, the “Managed Cloud Backing” and “User-Owned Browser Transport” sections (the near-term Drive path), and the backend-agnosticism this validates.docs/proposals/oidc-and-oauth2-proposal.md– the OAuth token capabilities this backend consumes; the refresh token lives there.docs/proposals/certificates-and-tls-proposal.md– the outbound TLS client.docs/proposals/networking-proposal.md– Phase C userspace net stack + the HTTP client; the shared authority gate.docs/research/{eros-capros-coyotos,plan9-inferno}.md– application-level persistence (vs transparent single-level store) and per-process namespaces (a Drive backend unioned into an app namespace alongside local storage).
Open questions
- Is the encrypted-capsule (browser-transport) model sufficient for the first user-facing Drive feature, deferring the native backend until the network stack is real?
- Where does the refresh token live – the OAuth service’s own sealed store, a
credential_storeextension, or a dedicatedDriveAccountobject? - Does the native backend target the Drive REST API directly, or go through a capOS-hosted proxy that holds the Google credentials (narrowing the on-device trust surface, at the cost of running a proxy)?
- How are Drive’s server-side semantics (revocation, quota, mutable ACL)
surfaced to apps so they are not surprised by a
Filecap that behaves unlike a local one?