Skip to content

feat: extend raw subcommand to gmail/calendar/people/contacts/tasks/forms#496

Open
karbassi wants to merge 17 commits intosteipete:mainfrom
karbassi:feat/raw-pr2
Open

feat: extend raw subcommand to gmail/calendar/people/contacts/tasks/forms#496
karbassi wants to merge 17 commits intosteipete:mainfrom
karbassi:feat/raw-pr2

Conversation

@karbassi
Copy link
Copy Markdown
Contributor

@karbassi karbassi commented Apr 8, 2026

Summary

Extends the raw subcommand pattern established in #495 to the remaining Google API command groups:

  • gog gmail raw <messageId>Users.Messages.Get, default format=full, --format full|metadata|minimal|raw
  • gog calendar raw <calendarId> <eventId>Events.Get, reuses resolveCalendarSelector so primary/emails/aliases work
  • gog people raw <userId>People.Get with a broad default personFields mask; --person-fields overrides
  • gog contacts raw <identifier> — same People.Get call, exposed under the contacts group
  • gog tasks raw <tasklistId> <taskId>Tasks.Get, reuses resolveTasklistID
  • gog forms raw <formId>Forms.Get

All six follow the conventions locked in by #495:

  • bare JSON struct output (no envelope)
  • compact by default, --pretty for indented
  • outfmt.WriteRaw helper, -j/-p silently no-op
  • unit tests per command (happy path + API error + not-found + empty-id)

Stacked on #495

This PR is stacked on #495 and currently shows PR #495's commits as well as this one's. When #495 merges to main, the diff will shrink to only this PR's commits. Please review #495 first.

Security audit

docs/raw-audit.md is extended with findings for all 6 new endpoints. None require redaction — risks are limited to data the caller already has access to, and none of the endpoints return credentials in the API contract. The gmail "raw" naming collision (subcommand name vs Gmail's format=raw) is explicitly documented.

Gmail naming collision

gog gmail raw defaults to format=full (structured parsed Message). Users who want Gmail's native format=raw (base64url RFC822 blob) can pass --format raw; the blob appears as the raw field inside the returned Message struct. Help text documents both senses.

Explicitly out of scope (from the plan)

  • appscript raw — existing get/content subcommands already cover the useful surface
  • chat raw / classroom raw — no natural single-resource Get endpoint
  • --jq / --filter flag — deferred

Test plan

  • gog gmail raw <id> | jq .payload.mimeType returns the MIME type
  • gog gmail raw <id> --format raw | jq .raw returns a base64url blob
  • gog calendar raw primary <eventId> returns the full Event struct
  • gog people raw people/<resourceName> returns full Person
  • gog contacts raw people/<resourceName> returns the same
  • gog tasks raw <listId> <taskId> returns the Task
  • gog forms raw <formId> returns the full Form tree

🤖 Generated with Claude Code

karbassi and others added 16 commits April 8, 2026 15:09
Emits a value as bare JSON (no envelope), compact by default with an
optional Pretty mode. HTML escaping disabled so URLs survive unchanged.
Backs the forthcoming `gog <group> raw` subcommands.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Records the security review performed before shipping `gog docs/sheets/
slides/drive raw`. Documents the redaction rule (redact only when
--fields is not user-specified) and per-endpoint findings.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Dumps the full Documents.Get response as JSON with no Fields
restriction, exposing the canonical Google Docs API tree (tables,
suggestions, per-run styling, list nesting, named ranges, inline
objects) that `docs info` strips. Compact by default, `--pretty` for
indented.

Tests cover happy path, API error, not-found, and empty-docId paths.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Dumps the full Spreadsheets.Get response as JSON. `--include-grid-data`
opts into cell-level data; off by default because grid payloads can be
multi-MB and formulas may embed API keys or tokens. Emits a stderr
warning when grid data is included or when developerMetadata is
present in the response.

Tests cover happy path (no grid), --include-grid-data propagation and
warning, API error, not-found, and empty-id paths.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Dumps the full Presentations.Get response. The Slides API has no field
mask so output is unconditionally lossless. Audit updated to ship
image/video URLs as-is (risk accepted): they are short-lived and
auth-gated, substantially lower risk than Drive's thumbnailLink, and
the lossless guarantee is valued more than marginal hardening. Same
rationale applied to Docs in the audit doc.

Tests cover happy path, API error, not-found, and empty-id paths.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Dumps Files.Get response as JSON. Defaults to fields=* and strips a
small set of capability-shaped fields (thumbnailLink, webContentLink,
exportLinks, resourceKey, appProperties, properties,
contentHints.thumbnail.image) when the user did not name fields
explicitly. When --fields is set the response is returned verbatim,
honoring exactly what the user asked for. Passing
--fields "id,name,thumbnailLink" returns thumbnailLink as requested.

Tests cover:
- default redaction strips every audited sensitive field
- explicit --fields honors user request (thumbnailLink preserved)
- API error, not-found, and empty-id paths

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…pete#486)

Both commands previously used a hard-coded Drive API field mask and
--select could only filter client-side. Adds a --fields flag that
passes directly to the Drive API fields parameter, letting users
request fields the defaults don't include (thumbnailLink,
imageMediaMetadata, videoMediaMetadata, contentHints, etc.).

Closes steipete#486.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…CHANGELOG

Adds a raw vs export/info comparison section to the docs/sheets/slides
command reference, example commands for each new `<group> raw`, and a
CHANGELOG entry under the unreleased section covering the raw feature
and the drive ls/get --fields expansion closing steipete#486.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
CI lint failed on wsl_v5 (missing blank lines before if/return
statements). Pure formatting fix — no behavior change. All tests
still pass.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds security review entries for gmail Users.Messages.Get, calendar
Events.Get, people People.Get (shared with contacts), tasks Tasks.Get,
and forms Forms.Get. None require redaction — risks are limited to
PII the caller already has access to, and none of the endpoints
return credentials in the API contract. Documents the gmail naming
collision ("raw" subcommand vs Gmail's format=raw) and the resolution.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Dumps the full Users.Messages.Get response as JSON. Defaults to
format=full (structured parsed Message); --format full|metadata|
minimal|raw exposes Gmail's native formats. The "raw" subcommand
name vs Gmail's format=raw value is a known collision; help text
documents both senses.

Tests cover default format, every --format value, invalid format,
API error, not-found, and empty-id paths.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… dump

Dumps the full Events.Get response as JSON. Uses the existing
resolveCalendarSelector helper so calendar IDs, 'primary', short
names, and email aliases all work the same as in \`calendar event\`.

Tests cover happy path, API error, not-found, and empty-eventId.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds PeopleRawCmd (gog people raw) and ContactsRawCmd (gog contacts
raw); both wrap the same People.Get call against the contacts service
and share implementation via runPeopleRaw. Defaults to a broad
personFields mask; --person-fields overrides.

Tests cover happy path for both commands, API error, and empty-id.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Dumps the full Tasks.Get response. Takes both tasklistId and taskId
as positional args, matching the existing \`tasks get\` signature.
Uses resolveTasklistID so short names work the same as elsewhere.

Tests cover happy path, API error, not-found, and empty-id paths.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Dumps the full Forms.Get response as JSON.

Tests cover happy path, API error, not-found, and empty-id paths.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ands

Adds example commands for gmail/calendar/people/contacts/tasks/forms
raw subcommands to the README reference and expands the CHANGELOG
entry to list the full set of raw commands now shipping under this
unreleased version.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds gmailFormatMinimal constant to the existing set in gmail_get.go
and reuses them in GmailRawCmd to satisfy goconst lint.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant