Skip to content

feat(api): add Discovery-backed method access#867

Merged
steipete merged 4 commits into
mainfrom
codex/discovery-api
Jun 22, 2026
Merged

feat(api): add Discovery-backed method access#867
steipete merged 4 commits into
mainfrom
codex/discovery-api

Conversation

@steipete

@steipete steipete commented Jun 22, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds a Discovery-backed escape hatch for Google APIs and methods that do not yet have first-class gog commands:

  • gog api list
  • gog api describe <api> <version> [method]
  • gog api call <api> <version> <method>

The implementation fetches Google's live Discovery document, resolves nested method IDs, validates path/query parameters, selects method-specific OAuth scope metadata, builds the REST request, and uses gog's existing account/client/token infrastructure.

Examples

gog api list
gog api describe gmail v1 gmail.users.labels.list
gog api call gmail v1 gmail.users.labels.list \
  --params '{"userId":"me","fields":"labels(id,name)"}'

gog api call gmail v1 gmail.users.labels.create \
  --params '{"userId":"me"}' \
  --body '{"name":"Example"}' \
  --allow-write --dry-run --json --no-input

Safety and contracts

  • GET/HEAD methods work by default.
  • Other HTTP methods require --allow-write and confirmation or --force.
  • --dry-run emits the resolved method, HTTP verb, URL, and body presence without obtaining credentials or calling the target API.
  • Gmail message/draft send methods honor root, config, and per-account no-send policies.
  • Discovery API-wide parameters such as fields and alt are merged with method parameters; unknown parameters fail instead of disappearing silently.
  • Discovery OAuth scopes are treated as alternatives. gog selects one narrow scope by default; --scope permits an explicit listed alternative.
  • JSON responses retain normal structured output and --wrap-untrusted behavior.
  • Non-JSON media is emitted byte-for-byte; textual media is wrapped when --wrap-untrusted is active.
  • Responses over 64 MiB fail explicitly before any partial output instead of being silently truncated.
  • Direct HTTP errors retain status metadata for gog's stable exit-code mapping.
  • Authenticated calls and redirects are restricted to HTTPS Google API hosts, preventing spoofed Discovery documents from forwarding OAuth tokens elsewhere.
  • Runtime command filters require an explicit api.<method-id> permission for each generic method; baked safety-profile binaries reject api call and retain their static command boundary.

api call intentionally grants a broader surface than narrow first-class commands. The README recommends first-class commands when available.

Validation

  • make ci
  • Discovery method traversal, required/common/unknown parameter, URL expansion, scope selection, write opt-in, Gmail no-send, raw media, and untrusted text tests
  • 699 generated command pages after rebasing on guided auth; docs site and coverage checks passed
  • live E2E on clawmac.local:
    • described gmail.users.labels.list from Google's live Discovery service
    • invoked that method through gog's authenticated generic caller: exit 0
    • resolved gmail.users.labels.create as POST and emitted a complete dry-run plan: exit 0; no label created
  • autoreview: clean after fixing trusted-host validation, redirect validation, command-policy enforcement, and JSON-shaped media preservation

Live-test safety

Only the Gmail labels list read was executed. The mutation example used --dry-run; no label or other Google data was created or changed.

@clawsweeper

clawsweeper Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed June 22, 2026, 1:08 PM ET / 17:08 UTC.

Summary
The PR adds Discovery-backed gog api list, gog api describe, and gog api call commands with dynamic method lookup, scoped OAuth client support, docs, and focused tests.

Reproducibility: not applicable. this is a feature PR rather than a bug report. The PR body reports make ci plus live Gmail labels-list and dry-run validation, and source inspection confirms focused unit coverage.

Review metrics: 3 noteworthy metrics.

  • Diff Footprint: 15 files changed, +1037/-1. The change spans command code, auth client plumbing, generated docs, README, changelog context, and tests.
  • Command Surface: 1 top-level command, 3 subcommands added. This is a new user-facing API surface rather than a narrow repair.
  • Focused Tests: 11 added test functions across 2 packages. The tests cover the high-risk write, host, redirect, policy, no-send, media, wrapping, scope-selection, and URL-building behavior.

Merge readiness
Overall: 🐚 platinum hermit
Proof: 🐚 platinum hermit
Patch quality: 🐚 platinum hermit
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • Obtain explicit maintainer acceptance of the generic Discovery caller and dynamic OAuth-scope boundary.

Risk before merge

  • [P1] gog api call intentionally lets authorized users invoke Discovery-described Google methods outside gog's first-class command implementations once OAuth, method policy, write opt-in, confirmation, and host checks pass.
  • [P1] Dynamic Discovery scope selection and NewHTTPClientForScopes broaden the auth path beyond the static service registry, including reauthorization behavior that ordinary CI cannot exhaustively prove across Google APIs.
  • [P1] VISION.md treats new API surfaces as discuss-first work, so the remaining blocker is maintainer product/security acceptance rather than a mechanical code repair.

Maintainer options:

  1. Accept the generic caller deliberately
    A maintainer can merge after explicitly accepting that gog api call reaches methods outside first-class command allowlists under write opt-in, confirmation, trusted-host checks, Gmail no-send, and command-policy safeguards.
  2. Narrow the first landing
    The branch can be reduced to read-only api list and api describe, or another smaller surface, if generic execution needs more design discussion.
  3. Pause the surface decision
    If the broad Discovery escape hatch is not yet in gog's direction, keep the PR paused or close it as a product decision rather than a patch-quality failure.

Next step before merge

  • [P2] Manual review is needed because the remaining blocker is product/security acceptance of a broad generic API execution and dynamic OAuth-scope boundary, not a narrow automated repair.

Security
Cleared: No concrete credential leak, supply-chain, or secret-handling defect was found; the intentionally broader API and OAuth boundary is captured as merge risk.

Review details

Best possible solution:

Keep the guarded implementation open for explicit maintainer acceptance of the generic Discovery caller and dynamic OAuth-scope model; if accepted, land it with the reported live Google proof and focused tests.

Do we have a high-confidence way to reproduce the issue?

Not applicable; this is a feature PR rather than a bug report. The PR body reports make ci plus live Gmail labels-list and dry-run validation, and source inspection confirms focused unit coverage.

Is this the best way to solve the issue?

Unclear as a product decision. The implementation is coherent for a guarded escape hatch, but VISION.md treats broad new API surfaces as discuss-first work.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 635f773788a8.

Label changes

Label justifications:

  • P2: This is a broad but bounded feature PR requiring normal maintainer review, not an urgent regression.
  • merge-risk: 🚨 auth-provider: The diff adds Discovery-selected OAuth scopes and a raw scoped HTTP client path outside the static service registry.
  • merge-risk: 🚨 security-boundary: The diff intentionally adds generic Google API method execution beyond existing first-class command allowlists.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🐚 platinum hermit and patch quality is 🐚 platinum hermit.
  • feature: ✨ showcase: ClawSweeper spotlight: unusually compelling feature idea for maintainer attention. A Discovery-backed escape hatch is unusually high-leverage for long-tail Google methods while keeping first-class commands preferred.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Not applicable: The external-contributor proof gate does not apply because this PR is collaborator-authored; the PR body still reports live Gmail read and dry-run validation.
Evidence reviewed

What I checked:

  • Repository policy read: AGENTS.md was present and read fully; it directs PR-link reviews through gh pr view and gh pr diff without switching branches, and the review kept the checkout clean. (AGENTS.md:37, 635f773788a8)
  • Maintainer notes check: No .agents/maintainer-notes/ files were present for this PR surface; only skill files were found under .agents/skills.
  • Current main lacks the command: The current-main CLI registry lists existing top-level commands through Photos, Config, Schema, and MCP with no api command entry. (internal/cmd/root.go:58, 635f773788a8)
  • Current main search: A current-main search found only a comparison-doc note about Discovery-backed coverage, not APICmd, APICallCmd, discoveryapi, or NewHTTPClientForScopes implementation symbols. (docs/gws-comparison.md:88, 635f773788a8)
  • Product-direction context: VISION.md says new API surfaces and broad command-structure changes are discuss-first, while also noting Discovery can be an explicit escape hatch if it preserves gog's curated safety-oriented surface. (VISION.md:20, 635f773788a8)
  • PR implementation path: At the PR head, APICallCmd.Run fetches a Discovery document, resolves a method, enforces method policy, validates parameters, gates writes, dry-runs before auth, validates Google targets, and calls through a scoped HTTP client. (internal/cmd/api.go:83, a618558d8712)

Likely related people:

  • steipete: Current-main blame/log history for the root command registry, raw Google HTTP client helper, and command-policy code points to Peter Steinberger, and the PR continues those same surfaces. (role: recent area contributor and feature-history owner; confidence: high; commits: 48db48b4f61f, a618558d8712; files: internal/cmd/root.go, internal/googleapi/client.go, internal/cmd/enabled_commands.go)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@clawsweeper clawsweeper Bot added rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. feature: ✨ showcase ClawSweeper spotlight: unusually compelling feature idea for maintainer attention. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. P2 Normal priority bug or improvement with limited blast radius. merge-risk: 🚨 auth-provider 🚨 Merging this PR could break OAuth, tokens, provider routing, model choice, or credentials. merge-risk: 🚨 security-boundary 🚨 Merging this PR could weaken sandboxing, authorization, credentials, or sensitive data. labels Jun 22, 2026
@steipete steipete force-pushed the codex/discovery-api branch from 6f6b5cf to a618558 Compare June 22, 2026 16:59
@steipete steipete marked this pull request as ready for review June 22, 2026 16:59

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a618558d87

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread internal/cmd/api.go
Comment on lines +226 to +233
best := available[0]
for _, scope := range available[1:] {
if discoveryScopeScore(scope) < discoveryScopeScore(best) {
best = scope
}
}

return []string{best}, nil

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Prefer granted Discovery scopes before narrow defaults

For accounts that already have one of the method's broader listed grants, this always requests the heuristically narrowest scope instead. For example, gog's default Gmail authorization stores gmail.modify, while a generic read such as gmail.users.labels.list will choose gmail.readonly; OAuth refreshes cannot add an ungranted scope string, so the call can fail even though the existing token has a valid listed scope. Please choose from the account's stored granted scopes when possible before falling back to the narrowest default.

Useful? React with 👍 / 👎.

Comment thread internal/cmd/api.go
Comment on lines +295 to +297
var value any
if err := json.Unmarshal(raw, &value); err != nil {
return fmt.Errorf("decode JSON response: %w", err)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve large JSON numbers in API responses

When a Discovery call returns JSON containing numeric IDs or counters above JavaScript's safe integer range, this default json.Unmarshal converts them to float64 before re-encoding, so the output can silently round or rewrite values. The existing JSON transform path uses UseNumber; this path should do the same (or avoid decoding when no transform/wrapping is needed) to keep API results byte-accurate.

Useful? React with 👍 / 👎.

@steipete steipete merged commit 0122f09 into main Jun 22, 2026
9 checks passed
@steipete steipete deleted the codex/discovery-api branch June 22, 2026 17:17
@steipete

Copy link
Copy Markdown
Collaborator Author

Landed as 0122f09d84e52aced2350d7969590c9045df04de.

Verification:

  • make ci — passed locally after the final hardening and lint fixes.
  • go test ./internal/cmd ./internal/discoveryapi — passed after each security fix.
  • Codex autoreview against current main — final run clean, no accepted/actionable findings.
  • GitHub CI — all 9 checks passed, including Linux, macOS CGO, Windows, worker, and Docker checks.
  • Existing live proof: authenticated Gmail label-list read succeeded; the mutation example remained dry-run only.

Landing fixes: restricted authenticated targets and redirects to HTTPS Google API hosts, enforced explicit per-method command policy under runtime filters, blocked generic calls in baked safety profiles, and preserved JSON-shaped media byte-for-byte.

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

Labels

feature: ✨ showcase ClawSweeper spotlight: unusually compelling feature idea for maintainer attention. merge-risk: 🚨 auth-provider 🚨 Merging this PR could break OAuth, tokens, provider routing, model choice, or credentials. merge-risk: 🚨 security-boundary 🚨 Merging this PR could weaken sandboxing, authorization, credentials, or sensitive data. P2 Normal priority bug or improvement with limited blast radius. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant