mcp-gee-sweet 0.7.0.dev30__tar.gz → 0.7.0.dev32__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/PKG-INFO +1 -1
- mcp_gee_sweet-0.7.0.dev32/docs/qa/playwright_oauth.md +130 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/docs/qa/runs/v0.8.0.md +1 -1
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/docs/qa/setup.md +11 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/docs/qa/tests/docs.md +85 -85
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/docs/qa-checklist.md +170 -0
- mcp_gee_sweet-0.7.0.dev32/scripts/oauth_setup.py +115 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/src/mcp_gee_sweet/.env.template +7 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/.claude/commands/prep-for-pr.md +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/.dockerignore +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/.github/dependabot.yml +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/.github/workflows/ci.yml +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/.github/workflows/docs.yml +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/.github/workflows/publish-dev.yml +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/.github/workflows/release.yml +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/.gitignore +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/.pre-commit-config.yaml +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/.python-version +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/CLAUDE.md +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/CONTRIBUTING.md +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/Dockerfile +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/LICENSE +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/Makefile +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/README.md +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/SECURITY.md +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/TODO.md +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/docker-compose.yml +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/docs/auth.md +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/docs/client-setup.md +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/docs/configuration.md +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/docs/decisions/decision-chart-theming.md +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/docs/decisions/decision-composite-tools.md +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/docs/decisions/decision-docs-formatting.md +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/docs/decisions/decision-fork.md +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/docs/decisions/decision-publishing.md +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/docs/decisions/decision-testing.md +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/docs/decisions/index.md +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/docs/design/docs-ast-pipeline.md +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/docs/design/effectiveformat-spike.md +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/docs/design/index.md +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/docs/design/markdown-support.md +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/docs/design/phase3-theme-system.md +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/docs/design.md +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/docs/index.md +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/docs/known-limitations.md +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/docs/notes-read.md +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/docs/qa/README.md +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/docs/qa/fixtures/tc-d195-create-doc.md +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/docs/qa/fixtures/tc-d196-create-doc.html +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/docs/qa/fixtures/tc-d226-heading-table.md +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/docs/qa/fixtures.template.md +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/docs/qa/operations.yaml +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/docs/qa/results/.gitkeep +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/docs/qa/results/2026-06-02.md +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/docs/qa/results/2026-06-14.md +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/docs/qa/results/2026-06-17.md +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/docs/qa/results/2026-06-18.md +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/docs/qa/results/2026-06-21-drive-discovery.md +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/docs/qa/results/2026-06-21-sheets-delete-clear.md +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/docs/qa/run.md +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/docs/qa/runs/README.md +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/docs/qa/tests/calendar.md +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/docs/qa/tests/drive.md +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/docs/qa/tests/infra.md +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/docs/qa/tests/sheets_charts.md +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/docs/qa/tests/sheets_mgmt.md +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/docs/qa/tests/sheets_read.md +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/docs/qa/tests/sheets_write.md +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/docs/roadmap.md +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/docs/tools.md +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/mkdocs.yml +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/pyproject.toml +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/src/mcp_gee_sweet/__init__.py +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/src/mcp_gee_sweet/auth.py +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/src/mcp_gee_sweet/cache.py +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/src/mcp_gee_sweet/server.py +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/src/mcp_gee_sweet/tools/__init__.py +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/src/mcp_gee_sweet/tools/cache.py +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/src/mcp_gee_sweet/tools/calendar.py +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/src/mcp_gee_sweet/tools/docs/__init__.py +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/src/mcp_gee_sweet/tools/docs/ast.py +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/src/mcp_gee_sweet/tools/docs/emitter.py +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/src/mcp_gee_sweet/tools/docs/html_parser.py +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/src/mcp_gee_sweet/tools/drive/__init__.py +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/src/mcp_gee_sweet/tools/drive/activity.py +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/src/mcp_gee_sweet/tools/drive/files.py +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/src/mcp_gee_sweet/tools/drive/sharing.py +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/src/mcp_gee_sweet/tools/drive/transfer.py +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/src/mcp_gee_sweet/tools/sheets/__init__.py +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/src/mcp_gee_sweet/tools/sheets/data.py +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/src/mcp_gee_sweet/tools/sheets/helpers.py +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/src/mcp_gee_sweet/tools/sheets/structure.py +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/tests/__init__.py +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/tests/drive/__init__.py +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/tests/drive/test_activity.py +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/tests/drive/test_files.py +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/tests/drive/test_sharing.py +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/tests/drive/test_transfer.py +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/tests/sheets/__init__.py +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/tests/sheets/test_data.py +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/tests/sheets/test_helpers.py +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/tests/sheets/test_structure.py +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/tests/test_auth.py +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/tests/test_cache.py +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/tests/test_calendar.py +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/tests/test_docs.py +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/tests/test_server.py +0 -0
- {mcp_gee_sweet-0.7.0.dev30 → mcp_gee_sweet-0.7.0.dev32}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mcp-gee-sweet
|
|
3
|
-
Version: 0.7.0.
|
|
3
|
+
Version: 0.7.0.dev32
|
|
4
4
|
Summary: MCP server for Google Workspace — Sheets, Drive, Docs, and Calendar. 60+ tools for AI clients.
|
|
5
5
|
Project-URL: Homepage, https://github.com/khuisman/mcp-gee-sweet
|
|
6
6
|
Project-URL: Bug Tracker, https://github.com/khuisman/mcp-gee-sweet/issues
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# Playwright OAuth Automation
|
|
2
|
+
|
|
3
|
+
How to acquire or refresh an OAuth token for QA runs without manually clicking through Google's consent screen.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## When you need this
|
|
8
|
+
|
|
9
|
+
- Fresh environment with no `token.json`
|
|
10
|
+
- `token.json` expired and cannot be refreshed (e.g. revoked, scopes changed)
|
|
11
|
+
- Running `⚠️ requires-oauth` test cases in an automated QA session
|
|
12
|
+
|
|
13
|
+
If `token.json` already exists and is valid, you don't need any of this — the server refreshes the access token automatically.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Approach A — Playwright-assisted browser flow
|
|
18
|
+
|
|
19
|
+
Use `oauth_setup.py` to start the consent flow without auto-launching a browser, then let the Playwright MCP complete it.
|
|
20
|
+
|
|
21
|
+
### Prerequisites
|
|
22
|
+
|
|
23
|
+
Add to `src/mcp_gee_sweet/.env`:
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
GOOGLE_TEST_EMAIL=your-test-account@gmail.com
|
|
27
|
+
GOOGLE_TEST_PASSWORD=your-test-account-password
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
> **Security note:** these are used only by the Playwright step below and are never sent to the MCP server. Keep them in `.env` (gitignored).
|
|
31
|
+
|
|
32
|
+
### Step 1 — Start the OAuth server
|
|
33
|
+
|
|
34
|
+
In a terminal:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
uv run python scripts/oauth_setup.py
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The script prints an `OAUTH_URL: https://accounts.google.com/o/oauth2/auth?...` line and waits for the callback.
|
|
41
|
+
|
|
42
|
+
### Step 2 — Conductor prompt (Playwright MCP)
|
|
43
|
+
|
|
44
|
+
Paste this into a Claude Code session that has the Playwright MCP connected:
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
I need to complete a Google OAuth consent flow. Do the following:
|
|
48
|
+
|
|
49
|
+
1. Read GOOGLE_TEST_EMAIL and GOOGLE_TEST_PASSWORD from src/mcp_gee_sweet/.env
|
|
50
|
+
2. Navigate to the OAUTH_URL printed by the oauth_setup.py script (running in a terminal)
|
|
51
|
+
3. On the Google sign-in page, enter the email address and click Next
|
|
52
|
+
4. Enter the password and click Next
|
|
53
|
+
5. On the consent screen, click "Allow" (or "Continue") to grant all requested scopes
|
|
54
|
+
6. Wait for the "Authorization complete" message on the page
|
|
55
|
+
|
|
56
|
+
Report what you see at each step and flag immediately if Google shows a CAPTCHA or
|
|
57
|
+
"This browser or app may not be secure" warning — those require manual intervention.
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Step 3 — Verify
|
|
61
|
+
|
|
62
|
+
Once the script exits, confirm `token.json` was updated:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
python3 -c "import json; d=json.load(open('token.json')); print('refresh_token present:', bool(d.get('refresh_token')))"
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Known limitations
|
|
69
|
+
|
|
70
|
+
**Page load: ✅ confirmed working.** Google's sign-in page (`accounts.google.com/signin`) renders correctly in Playwright — the "Email or phone" field is present and accessible.
|
|
71
|
+
|
|
72
|
+
The remaining risk is at the credential-entry step. Google may apply bot detection after password entry:
|
|
73
|
+
|
|
74
|
+
| Symptom | Cause | Resolution |
|
|
75
|
+
|---|---|---|
|
|
76
|
+
| "This browser or app may not be secure" | Google flagged the automated browser post-login | Switch to Approach B (manual) then save refresh token |
|
|
77
|
+
| CAPTCHA or phone verification prompt | Account triggered fraud detection | Use a test-only Google account with 2FA disabled and a trusted browser profile |
|
|
78
|
+
| Redirect loop or 400 error | `redirect_uri` mismatch | Ensure `credentials.json` has `http://localhost` in authorized redirect URIs |
|
|
79
|
+
|
|
80
|
+
If Playwright is blocked after email/password entry, fall back to a one-time manual browser flow (paste the URL into Chrome) and then use Approach B for all future runs.
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Approach B — Refresh token injection (CI / headless)
|
|
85
|
+
|
|
86
|
+
Run the browser flow **once** (manually or via Playwright), then store the refresh token as an environment secret. All future runs reconstruct `token.json` without any browser.
|
|
87
|
+
|
|
88
|
+
### Step 1 — Extract the refresh token (one time)
|
|
89
|
+
|
|
90
|
+
After a successful OAuth flow:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
python3 -c "import json; d=json.load(open('token.json')); print(d['refresh_token'])"
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Store the output as:
|
|
97
|
+
- `GOOGLE_OAUTH_REFRESH_TOKEN` (secret)
|
|
98
|
+
- `GOOGLE_OAUTH_CLIENT_ID` (from `credentials.json → installed.client_id`)
|
|
99
|
+
- `GOOGLE_OAUTH_CLIENT_SECRET` (from `credentials.json → installed.client_secret`)
|
|
100
|
+
|
|
101
|
+
### Step 2 — Reconstruct token.json on each run
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
uv run python scripts/oauth_setup.py --from-refresh-token
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
This writes a minimal `token.json` with the refresh token. The MCP server exchanges it for a fresh access token on first use (same as a normal expired-token refresh — no browser needed).
|
|
108
|
+
|
|
109
|
+
### In CI (GitHub Actions example)
|
|
110
|
+
|
|
111
|
+
```yaml
|
|
112
|
+
- name: Restore OAuth token
|
|
113
|
+
env:
|
|
114
|
+
GOOGLE_OAUTH_REFRESH_TOKEN: ${{ secrets.GOOGLE_OAUTH_REFRESH_TOKEN }}
|
|
115
|
+
GOOGLE_OAUTH_CLIENT_ID: ${{ secrets.GOOGLE_OAUTH_CLIENT_ID }}
|
|
116
|
+
GOOGLE_OAUTH_CLIENT_SECRET: ${{ secrets.GOOGLE_OAUTH_CLIENT_SECRET }}
|
|
117
|
+
run: uv run python scripts/oauth_setup.py --from-refresh-token
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Which approach to use
|
|
123
|
+
|
|
124
|
+
| Scenario | Approach |
|
|
125
|
+
|---|---|
|
|
126
|
+
| First-ever token acquisition on a new machine | A (Playwright or manual) |
|
|
127
|
+
| QA run after token expiry — Playwright available | A |
|
|
128
|
+
| QA run after token expiry — no browser possible | B (if refresh token stored) |
|
|
129
|
+
| CI pipeline | B |
|
|
130
|
+
| Playwright blocked by Google | Manual browser + B for future |
|
|
@@ -27,7 +27,7 @@ Run each suite using the conductor prompt in `docs/qa/run.md`. Check off when th
|
|
|
27
27
|
- [ ] **Sheets Management** — `tests/sheets_mgmt.md` (TC-S01–TC-S24)
|
|
28
28
|
- [ ] **Sheets Charts** — `tests/sheets_charts.md` (TC-C01–TC-C12)
|
|
29
29
|
- [ ] **Drive + Docs** — `tests/drive.md` (TC-D01–TC-D166)
|
|
30
|
-
- [ ] **Docs Tools** — `tests/docs.md` (TC-
|
|
30
|
+
- [ ] **Docs Tools** — `tests/docs.md` (TC-DOC01–TC-DOC79)
|
|
31
31
|
- [ ] **Calendar** — `tests/calendar.md` (TC-CAL01–TC-CAL43)
|
|
32
32
|
|
|
33
33
|
---
|
|
@@ -118,6 +118,17 @@ Add the returned IDs to `.env` as `TEST_CALENDAR_ID` and `TEST_EVENT_ID`.
|
|
|
118
118
|
|
|
119
119
|
---
|
|
120
120
|
|
|
121
|
+
## OAuth token setup (for `⚠️ requires-oauth` tests)
|
|
122
|
+
|
|
123
|
+
Tests tagged `⚠️ requires-oauth` need a valid OAuth token (`token.json`). If you're running with a service account or ADC, these tests will be skipped or will fail — they require personal Drive access.
|
|
124
|
+
|
|
125
|
+
To acquire or refresh a token without manually clicking through Google's consent screen, see **[`docs/qa/playwright_oauth.md`](playwright_oauth.md)**. Two paths are documented:
|
|
126
|
+
|
|
127
|
+
- **Playwright-assisted**: run `scripts/oauth_setup.py`, let Claude Code + Playwright MCP complete the browser flow
|
|
128
|
+
- **Refresh token injection**: one-time manual flow, then store the refresh token as an env secret for all future runs (CI-friendly)
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
121
132
|
## Resetting fixtures
|
|
122
133
|
|
|
123
134
|
Re-run the Step 3 seed prompt against your existing IDs to restore known state. No need to create new files.
|