Skip to content

fix(auth): a corrupt cookie store is not a network problem (#796) - #1096

Merged
ffroliva merged 4 commits into
developfrom
bugfix/796-corrupt-cookie-store
Oct 25, 2026
Merged

ffroliva merged 4 commits into
developfrom
bugfix/796-corrupt-cookie-store

Conversation

@ffroliva

Copy link
Copy Markdown
Owner

Summary

Part of #796. A corrupt Chrome cookie database was reported as a network problem: gflow auth status said "Check network connectivity and retry", and the MCP gflow_auth_status tool returned verification_error (HTTP 503, retryable: true), which tells an agent to retry. This is the "adjacent finding" recorded on #796 when #797 landed: same wrong advice, different trigger.

Root cause

browser_cookie3.chrome() raises sqlite3.DatabaseError("file is not a database") for a cookie file that is not a valid SQLite database. Its connection check only catches OperationalError. _get_chrome_cookies3 (src/gflow_cli/auth/cookies.py) only turns decryption errors into PermissionError for the Playwright fallback, so the DatabaseError reached the catch-all except Exception in verify_flow_profile (src/gflow_cli/auth/verification.py) and became VERIFICATION_ERROR. I checked this by running the real browser_cookie3 on a garbage file, which raised sqlite3.DatabaseError.

Fix

  • A new FlowSessionOutcome.COOKIE_STORE_UNREADABLE. verify_flow_profile catches sqlite3.DatabaseError (which also covers OperationalError) before the catch-all and returns this outcome.
  • It does not go into the Playwright fallback the way PermissionError does. That would launch Chrome on a corrupt file during a read-only status probe, where Chrome may discard (raze) the database. On a profile with no marker it would also stop at the marker gate and give the wrong advice.
  • CLI gflow auth status says: "This profile's cookie store is corrupt or unreadable. Close any Chrome window using this profile, then re-run gflow auth login --profile ."
  • MCP twin: cookie_store_unreadable, HTTP 409, retryable: false. This matches the existing profile_marker_missing envelope (a local-state fault, neither 503 nor 401). retryable: false is measured, not guessed: two back-to-back live runs gave the same outcome 2/2, because a retry reads the same broken file again.
  • Login strategies: UNVERIFIED_MESSAGE / UNVERIFIED_HINT get the new outcome, so a login that verifies into it gets a clean message and not a KeyError.
  • Docs: the gflow_auth_status entry in docs/MCP.md, plus the regenerated website mirror. CHANGELOG [Unreleased] ### Fixed.

Evidence

TDD: three new tests failed for the right reason before the fix. The log showed auth_flow_session_probe_error error=DatabaseError, and the CLI output contained "check network connectivity".

  • tests/auth/test_verification.py::...::test_corrupt_cookie_store_is_not_reported_as_a_network_fault: a real corrupt file in tmp_path and the real browser_cookie3. It asserts the new outcome and that Playwright is never launched.
  • tests/cli/test_auth_status.py::test_corrupt_cookie_store_is_not_blamed_on_the_network: end to end through the real probe. verify_flow_profile and browser_cookie3 are not mocked.
  • tests/mcp/test_auth_status_tool.py::test_an_unreadable_cookie_store_is_not_retryable_and_not_a_network_fault

Live, $0, no browser launched. A real profile's marker files, Local State and cookie DB were copied into a temporary GFLOW_CLI_HOME. The copied Cookies was then overwritten with random bytes. The original profile was not modified, and the copy has since been deleted.

develop 624992d9:

{"source": "status", "error": "DatabaseError", "event": "auth_flow_session_probe_error", ...}
Could not verify the Flow session. Check network connectivity and retry;
re-login is only needed if the session is actually dead.
EXIT=1
MCP: {"outcome": "verification_error", "status": 503, "retryable": true, "remediation_hint": "...Check connectivity and retry..."}

this branch:

{"source": "status", "error": "DatabaseError", "event": "auth_cookie_store_unreadable", ...}
This profile's cookie store is corrupt or unreadable. Close any Chrome window
using this profile, then re-run gflow auth login --profile corrupt796.
EXIT=1   (2/2 runs)
MCP: {"status": "cookie_store_unreadable", "error": {"status": 409, "retryable": false, "remediation_hint": "This profile's Chrome cookie database is corrupt or unreadable. Close any Chrome window using this profile, then re-run `gflow auth login` for it.", ...}}

E2E scope: this does not touch a Flow surface. The fault is a local file, and the path fails before any network call or browser launch. The live run above goes through the real CLI and MCP entry points.

Verification status

  • Repo hygiene, doc links, website PII, website mirror --check, council memory: all exit 0
  • ruff check clean, ruff format --check clean
  • uv run pyright src: 0 errors, 0 warnings
  • pytest tests/auth tests/cli tests/mcp -n 8 -m "not live and not e2e and not smoke": 1161 passed
  • Live CLI + MCP before/after on a corrupted copy of a real profile
  • Re-login on a profile with a corrupt cookie DB really recovers it. The hint assumes Chrome rebuilds the database on launch. Not exercised here.

What remains on #796 (not in this PR)

Not touched here: the marker rollback after a failed verification (real_chrome.py), which permanently demotes a chrome profile, and the GOOGLE_SESSION_ONLY re-login loop. The macOS Keychain leg is also still unverified (no Mac here). Hence Refs, not Closes.

Refs #796

browser_cookie3 raises sqlite3.DatabaseError for a cookie file that is
not a database. It fell through to VERIFICATION_ERROR, so auth status
said "check network connectivity" and the MCP twin answered 503
retryable. It is now its own outcome, COOKIE_STORE_UNREADABLE: the CLI
says to close Chrome and re-login, and MCP returns 409, not retryable.
It is not routed into the Playwright fallback, which would launch Chrome
on the corrupt file during a read-only probe.

Refs #796
@coderabbitai

coderabbitai Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Caution

Review failed

The pull request is closed.

Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

…atabaseError test

On Linux/macOS browser_cookie3 asks the keyring for the key before opening
the DB; CI has no keyring, so it falls back before reaching the corrupt file.
The portable test injects the same sqlite3.DatabaseError where
browser_cookie3 raises it.
# Conflicts:
#	CHANGELOG.md
#	docs/MCP.md
#	website/docs/MCP.md
@ffroliva
ffroliva marked this pull request as ready for review October 25, 2026 11:26
@ffroliva
ffroliva merged commit 3f202b8 into develop Oct 25, 2026
18 checks passed
@ffroliva
ffroliva deleted the bugfix/796-corrupt-cookie-store branch October 28, 2026 11:22
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