# 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
  in `storage-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 `appDataFolder` space is a near-exact fit for the per-app `AppData` cap:
  Google already provides per-app private storage invisible to the user and
  other apps under the narrow, non-sensitive `drive.appdata` scope.
- 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.md` already 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:

```text
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 the
  `OutboundHttpRequest` struct that `AccessToken.authorize` decorates with the
  bearer credential. The refresh token lives in the OAuth service; the Drive
  service holds a `DriveAccount` cap that exposes only the typed operations the
  user consented to.
- It consumes the outbound TLS client from `certificates-and-tls-proposal.md`
  and the HTTP client / userspace network stack from `networking-proposal.md`
  Phase C.
- It is the network analog of the virtio-blk-backed FS service in
  `docs/proposals/storage-and-naming-proposal.md`: same `Directory`/`File`/`Store` caps 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 `DriveAccount` wrapper 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
  `appDataFolder` usage 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

1. **Reconcile + capsule model (near-term, browser-transport)**: align the
   existing "User-Owned Browser Transport" section of
   `storage-and-naming-proposal.md` with the `AppData`/powerbox vocabulary;
   define the encrypted-capsule format and the `appDataFolder` capsule lifecycle.
   No capOS network/TLS/OAuth dependency.
2. **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.
3. **Native `DriveAccount` + Drive storage service (deep-future)**: implement
   the service that maps `AppData`/`File`/`Directory`/`Store` onto Drive REST
   using the OAuth/TLS/HTTP caps; prove an `appDataFolder` round-trip and a
   powerbox-picked file read in a QEMU smoke against a Drive API stand-in.
4. **Sharing bridge (future)**: map `shareAs` to 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 the
  `AppData`/powerbox/`shareAs` caps 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_store` extension, or a dedicated `DriveAccount` object?
- 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 `File` cap that behaves
  unlike a local one?
