Skip to content

fix(browser): bound the real-profile auth backup so a locked source falls through to raw copy - #96659

Open
liuhao1024 wants to merge 1 commit into
NousResearch:mainfrom
liuhao1024:liuhao/cron-bugfix-96646
Open

liuhao1024 wants to merge 1 commit into
NousResearch:mainfrom
liuhao1024:liuhao/cron-bugfix-96646

Conversation

@liuhao1024

@liuhao1024 liuhao1024 commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Bounds the online-backup call in _copy_auth_file() so a locked auth DB can no longer hang the first consented real-profile session forever.

With browser.use_real_profile: true and the user's Chrome running, Chrome holds Login Data / Web Data with exclusive SQLite locks on POSIX too. The old code called source.backup(out) with no progress callback, and CPython's backup() retries SQLITE_BUSY in a loop with no total timeout and no exception — so the copy never returned, the except never fired, the raw-copy fallback was unreachable, and browser_exec died at the ~420 s tool timeout with no error (#96646). The timeout=5 on the source connection the old comment relied on only bounds statement-level busy waits, not backup() retries.

The fix reuses hermes_cli.backup._safe_copy_db — the deadline-bounded helper that already fixed this exact hazard class in the backup walker (#82042 / #92495 / #84475): read-only connect with timeout=0.0, a progress-callback deadline (_AUTH_BACKUP_TIMEOUT_SECONDS, 10 s, matching the walker's default), fail-closed False. On failure, control returns to the existing raw-copy fallback, which needs no SQLite cross-process locks on POSIX, so the launch proceeds instead of hanging.

Related Issue

Fixes #96646

Fixes #96661 (independent re-report of the same _copy_auth_file() hang, filed with its own per-DB probe data; same root cause and same fix path)

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)

Changes Made

  • hermes_cli/browser_connect.py_copy_auth_file()'s SQLite branch now calls hermes_cli.backup._safe_copy_db with a 10 s budget instead of an unbounded source.backup(out); added module constant _AUTH_BACKUP_TIMEOUT_SECONDS (monkeypatch-able for tests) and updated the docstring.
  • tests/tools/test_browser_real_profile.py — regression test_copy_auth_file_bounded_when_locked_falls_back_to_raw: holds an exclusive SQLite lock on a real Login Data DB (the way a running Chrome does), asserts _copy_auth_file returns well within 5 s and succeeds via the raw-copy fallback with the copied DB readable.

How to Test

  1. python -m pytest tests/tools/test_browser_real_profile.py -q — should pass (74 passed, including the new regression).
  2. python -m pytest tests/hermes_cli/test_backup_all_profiles.py tests/hermes_cli/test_backup_path_errors.py tests/hermes_cli/test_backup_stability.py -q — should pass (16 passed; the shared helper's own suite).
  3. Red/green observed locally: on the pre-fix code the new test's exact scenario hangs — a direct probe (BEGIN EXCLUSIVE on the source, then _copy_auth_file) was still blocked after 90 s and had to be killed; on this branch the same call returns in ~0.6 s with True and a readable snapshot DB.

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature (no unrelated commits)
  • I've run pytest tests/ -q and all tests pass (targeted: real-profile suite 74 passed; backup family 16 passed)
  • I've added tests for my changes (required for bug fixes, strongly encouraged for features)
  • I've tested on my platform: macOS 15.5 (arm64)

Documentation & Housekeeping

  • I've updated relevant documentation (README, docs/, docstrings) — N/A (docstring updated in place)
  • I've updated cli-config.yaml.example if I added/changed config keys — N/A
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — N/A
  • I've considered cross-platform impact (Windows, macOS) per the compatibility guide — on Windows the bounded backup fails fast and the fail-closed path behaves as before; no behavior change for unlocked DBs
  • I've updated tool descriptions/schemas if I changed tool behavior — N/A

…alls through to raw copy

_copy_auth_file() called sqlite3.Connection.backup() with no progress
callback, and CPython retries SQLITE_BUSY forever in that loop — while a
running Chrome holds Login Data / Web Data with exclusive SQLite locks on
POSIX too, the first consented session hung until the tool timed out
(~420 s) with no error, and the raw-copy fallback was unreachable (NousResearch#96646).
The connect(timeout=5) the old comment relied on does not bound backup()
retries.

Reuse the deadline-bounded family helper hermes_cli.backup._safe_copy_db
(same hazard already fixed there by NousResearch#82042/NousResearch#92495/NousResearch#84475): read-only
connect with timeout=0, progress-callback deadline of
_AUTH_BACKUP_TIMEOUT_SECONDS (10 s, matching the backup walker), and on
failure return control to the existing raw-copy fallback, which needs no
SQLite locks on POSIX.

Fixes NousResearch#96646
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/cli CLI entry point, hermes_cli/, setup wizard tool/browser Browser automation (CDP, Playwright) sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data labels Aug 27, 2026
teknium1 added a commit that referenced this pull request Sep 8, 2026
Preserve Ben Barclay's diagnosis and replace the staging-file approach with
SQLite-coordinated writes and a five-second backup callback deadline. A
main-file replacement can replay an abandoned destination WAL; immutable
source reads can miss committed source WAL. Neither raw copy nor replacement
is safe when the destination is locked.

Refuse unavailable auth databases without raw-copy fallback, retaining the
existing close-browser-and-retry flow. Keep two invariant tests for lock
refusal/recovery and source-versus-destination WAL contents. Convert existing
text masquerading as database fixtures into real SQLite fixtures.

Related: #105754
Related: #96659
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/cli CLI entry point, hermes_cli/, setup wizard P2 Medium — degraded but workaround exists sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data tool/browser Browser automation (CDP, Playwright) type/bug Something isn't working

Projects

None yet

2 participants