Skip to content

refactor(P2-1): Extract pure Google OAuth helpers for web-wizard reuse#20

Merged
hyoshi merged 2 commits intomainfrom
feat/web-auth-wizard
Apr 19, 2026
Merged

refactor(P2-1): Extract pure Google OAuth helpers for web-wizard reuse#20
hyoshi merged 2 commits intomainfrom
feat/web-auth-wizard

Conversation

@hyoshi
Copy link
Copy Markdown
Collaborator

@hyoshi hyoshi commented Apr 19, 2026

Summary

First of 4 PRs implementing Phase 2 (web-based OAuth wizard so non-technical users never touch a terminal). This PR is prep-only — no user-facing behavior change. Extracts the Google OAuth dance in auth_setup.py into small pure building blocks so the upcoming web wizard and the existing interactive CLI share the same scopes / client-config / token-exchange path.

What changes

New public helpers in mureo/auth_setup.py

  • build_google_client_config(client_id, client_secret) -> dict
  • build_google_flow(client_id, client_secret, redirect_uri=None) — returns InstalledAppFlow when redirect_uri=None (current CLI path); returns plain Flow otherwise (web-wizard path).
  • google_auth_url(flow) -> (auth_url, state) — forces access_type=offline + prompt=consent so refresh_token is guaranteed on every authorization, not just first grant.
  • exchange_google_code(flow, code) -> OAuthResult — raises RuntimeError if the response lacks refresh_token.

Existing run_google_oauth refactored to use build_google_flow

Public signature and return type unchanged. The three existing monkey-patches in tests/test_auth_setup.py continue to work because they patch the outer function.

Test plan

  • 12 new tests in tests/test_auth_oauth_helpers.py: client-config shape, Flow vs InstalledAppFlow selection by redirect_uri, scope coverage (ads + webmasters), auth URL shape, refresh_token guarantee, and a regression lock on run_google_oauth.
  • Full suite: 1672 passed. mypy (CI config --ignore-missing-imports), ruff, and black all clean.
  • CI green after push.

Roadmap

  • P2-1 (this PR) — extract helpers
  • P2-2 — web wizard HTTP server + Google Ads flow + mureo auth setup --web flag
  • P2-3 — Meta Ads flow in web wizard
  • P2-4 — README polish + deep links to Google Cloud / Meta Developers

hyoshi added 2 commits April 19, 2026 11:48
Prep work for the web-based auth wizard (Phase 2). Splits the Google
OAuth dance in auth_setup.py into small pure building blocks so the
interactive CLI (InstalledAppFlow + run_local_server) and the
forthcoming web wizard (plain Flow + our own HTTP server) both go
through the same scopes / client-config / token-exchange path without
drift.

New public functions (all sync, no I/O beyond the Flow itself):
- build_google_client_config(client_id, client_secret) -> dict
- build_google_flow(client_id, client_secret, redirect_uri) -> Flow
  (returns InstalledAppFlow when redirect_uri is None)
- google_auth_url(flow) -> (auth_url, state)
  forces access_type=offline + prompt=consent so refresh_token is
  guaranteed on every authorization
- exchange_google_code(flow, code) -> OAuthResult

run_google_oauth now delegates to build_google_flow internally. Its
public signature and return type are unchanged so the three places in
test_auth_setup.py that monkey-patch it continue to work.

12 new tests in tests/test_auth_oauth_helpers.py covering: config
shape, Flow vs InstalledAppFlow selection, scope coverage (Google
Ads + Search Console), auth URL shape, refresh_token guarantee,
missing-refresh fallback, and run_google_oauth regression.

Full suite: 1672 passed, mypy (with --ignore-missing-imports per CI)
/ ruff / black clean. No behavior change for existing users.
- HIGH: _validate_local_redirect_uri() rejects non-localhost URIs in
  build_google_flow so a caller cannot redirect OAuth grants to a
  remote host. Enforces scheme=http + hostname in {127.0.0.1,
  localhost}. 9 parametrized tests cover rejections and acceptances.
- HIGH: Add a comment on google_auth_url documenting the
  prompt=consent injection-point asymmetry with run_google_oauth
  (which injects via run_local_server).
- MEDIUM: Type build_google_flow return as Flow (was Any); same for
  google_auth_url and exchange_google_code parameters. Top-level
  import of Flow (was function-local, inconsistent with
  InstalledAppFlow).
- MEDIUM: exchange_google_code RuntimeError now explains the fix
  (re-run with prompt=consent + access_type=offline, or revoke at
  https://myaccount.google.com/permissions).
- LOW: 3 new tests — fetch_token propagates unexpected errors,
  error message is actionable (mentions both prompt/offline),
  client_config dict is independent across calls (not shared state).

Full suite: 1684 passed, mypy / ruff / black clean.
@hyoshi hyoshi merged commit 8cb20c5 into main Apr 19, 2026
4 checks passed
@hyoshi hyoshi deleted the feat/web-auth-wizard branch April 19, 2026 03:23
hyoshi added a commit that referenced this pull request May 1, 2026
…e EVERY commit (#76)

Codifies the rule reinforced after PR #20 (OAuth helper, 2 HIGH issues found post-hoc) and PR #75 fixup (review-response commit pushed without re-review). Fixup, lint, and review-response commits all require their own review pass — a previous review on the same branch does NOT exempt follow-up commits.

Exceptions (visual review only): docs/README/CHANGELOG, version bumps, Dependabot Actions bumps, typo fixes in comments.
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