Skip to content

feat(drive): changes serve — receive Drive push notifications and trigger callbacks #689

@sebsnyk

Description

@sebsnyk

Motivation

gog drive changes watch already registers an HTTPS webhook channel against the Drive Changes API. The receiving side — the HTTPS endpoint Google posts to — is left as an exercise for the user. Meanwhile, the Gmail side ships a complete push handler at gog gmail watch serve (see internal/cmd/gmail_watch_server.go). The Drive equivalent is missing, which means anyone wanting real-time change events has to roll their own HTTPS receiver, deal with cert/tunnel setup, parse X-Goog-Channel-* headers, persist the pageToken between events, and renew the channel before its TTL expires.

This is the missing half of drive changes watch. With it, end-to-end automation ("fire a script every time something changes on this doc") works out of the box.

Pairs with

Together these four close the comment-driven edit loop: serve (or poll) detects the change, comments list --since enumerates what is new, comments locate resolves the anchor, and an existing surgical command (delete / format / insert-person etc.) acts on the resolved range.

Repro

# Today:
gog drive changes watch --token=... --webhook-url=https://my-server.example.com/hook
# Now the user has to:
#   1. Run an HTTPS server on https://my-server.example.com/hook
#   2. Parse X-Goog-Channel-ID, X-Goog-Channel-Token, X-Goog-Resource-State
#   3. Call `gog drive changes list --token=<saved>` on each notification
#   4. Persist the next pageToken
#   5. Re-call `gog drive changes watch` before the channel expires (max 7d)

Proposed surface

gog drive changes serve [flags]
  --listen=:8443                Local listen address
  --cert=PATH --key=PATH        TLS cert + key (Google requires HTTPS)
  --channel-token=STRING        Expected channel token (rejects mismatched POSTs)
  --state-file=PATH             Where to persist the next pageToken between notifications
  --on-change="<cmd>"           Shell command invoked per notification; JSON payload on stdin
  --filter-file=<id>            Only fire on-change when the change touches this file id
  --auto-renew                  Re-call changes.watch before the channel expires
  --renew-before=10m            How long before expiration to renew (default 10m)
  --drive=STRING                Shared-drive ID for shared-drive change logs
  --foreground                  Stay in the terminal (default; pair with systemd / launchd otherwise)

Payload format for --on-change:

{
  "channelId": "...",
  "resourceState": "change",
  "messageNumber": 17,
  "resourceUri": "...",
  "changes": [{"fileId":"...","time":"...","removed":false}]
}

Mirrors gog gmail watch serve structure: ServeHTTP authenticates by X-Goog-Channel-Token, calls changes.list, optionally invokes the user callback, persists the new token.

Acceptance criteria

  • Validates X-Goog-Channel-Token; returns 401 on mismatch.
  • Returns 200 on success (Google docs accept 200, 201, 202, 204, 102).
  • Persists the next pageToken atomically (no half-writes on crash).
  • --on-change is invoked once per notification with the JSON payload on stdin.
  • --auto-renew re-issues changes.watch at least --renew-before ahead of expiration and rolls over the channel id cleanly.
  • --filter-file=<id> short-circuits before calling on-change when the changes list does not include the target file.

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Normal priority bug or improvement with limited blast radius.clawsweeper:fix-shape-clearClawSweeper found a clear likely implementation shape for this issue.clawsweeper:needs-maintainer-reviewClawSweeper marked this issue as needing maintainer review before automation.clawsweeper:needs-product-decisionClawSweeper marked this issue as needing a product or behavior decision.clawsweeper:needs-security-reviewClawSweeper marked this issue as needing security-sensitive review.clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.impact:securityThis issue is about security boundaries, credentials, authz, sandboxing, or sensitive data.issue-rating: 🌊 off-meta tidepoolIssue quality rating does not apply to this item.

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions