ulysses/routes
Isharak 70103d8719
fix(email): no-op IMAP connection leak in _auto_summarize_pass_single on exception (#1423)
`_auto_summarize_pass_single` in `routes/email_pollers.py` opens a
long-lived IMAP connection at line 172 and then performs ~700 lines of
work — IMAP `select`/`FETCH`/`SEARCH`, network POSTs to the LLM
endpoint, SQLite writes, and per-uid awaits. The only `conn.logout()`
calls were on three safe paths (early `"No recent emails"`, early
`"No model configured"`, and the happy path at the very end). If any
exception fired between `conn` being created and the final happy path,
the outer `except` block at line 921 caught it, logged, and returned —
without ever calling `conn.logout()`. The IMAP socket leaked until
the server's idle timeout killed it.

This is the same shape as the just-merged upstream fixes #1325
(`_imap_move` in `routes/email_helpers.py`) and #1330 (`_list_emails_sync`
in `routes/email_routes.py`), but in the *background* poller path —
`_auto_summarize_poller` invokes it every 30 min, so the leak
accumulates on every crashed pass instead of being a transient
request-path leak.

The fix is the exact try/finally pattern from #1330:
  1. initialize `conn = None` before the try
  2. let the try-block assign `conn = _imap_connect(...)`
  3. drop the three explicit `conn.logout()` calls on safe paths
  4. add a `finally:` block that calls `conn.logout()` if `conn` was set

Tests in `tests/test_email_polly_imap_leak.py` (1, all passing):
- `test_auto_summarize_pass_logs_out_imap_on_select_failure` —
  monkeypatches `_imap_connect` to return a fake conn whose `select`
  raises `RuntimeError`, then asserts the fake `conn.logout` was
  called exactly once and the function returned an `Error: ...`
  string. Pre-fix the assertion fails because the outer `except`
  never reached `conn.logout`; post-fix the `finally` block
  guarantees it on every exit path.

Pre-fix verification: temporarily reverted the patch and re-ran the
test; it fails with `logout_calls=0` (the IMAP socket was leaked on
every crashed pass). Post-fix: `logout_calls=1`.

Uniqueness:
- `git log --all --oneline -S 'conn.logout' -- routes/email_pollers.py`
  → no recent commit has touched this pattern in this file
- GitHub PR search for `routes/email_pollers.py` open PRs → 0
- Function has no existing test file (`grep _auto_summarize_pass_single
  tests/` → no results)

---

**@pewdiepie-archdaemon — gentle bump on a sibling PR that's also stuck
in your queue from the same author:** PR #1306
(`fix(caldav): no-op prune when date_search returns 0 events`) is on
its 4th rebase, isolated to 2 files, 2/2 tests passing, with one
independent approval from `lalalune` already on record. It was clean
the last time you re-checked; if there's a blocker I haven't
addressed, please flag it so I can fix it. Otherwise, both #1306 and
this one are ready to merge.

Co-authored-by: isharak7m <192635824+isharak7m@users.noreply.github.com>
2026-06-03 04:13:52 +09:00
..
__init__.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
admin_wipe_routes.py Admin: wipe gallery albums with images 2026-06-02 20:35:57 +09:00
api_token_routes.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
assistant_routes.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
auth_routes.py fix(auth): case-insensitive owner migration on username rename (#1183) 2026-06-02 23:18:15 +09:00
backup_routes.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
calendar_routes.py Harden CalDAV credentials and URLs (#1310) 2026-06-03 02:50:02 +09:00
chat_helpers.py Harden session endpoint owner scope (#1308) 2026-06-03 02:40:22 +09:00
chat_routes.py Harden session endpoint owner scope (#1308) 2026-06-03 02:40:22 +09:00
cleanup_routes.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
compare_routes.py feat(ai): add OpenRouter and Ollama Cloud providers (#231) 2026-06-01 14:26:10 +09:00
contacts_routes.py Add native Windows compatibility layer 2026-06-01 15:09:47 +09:00
cookbook_helpers.py fix: Cookbook local GGUF serving inside Docker (#1264) 2026-06-03 02:08:09 +09:00
cookbook_routes.py Polish email and cookbook flows 2026-06-02 22:42:07 +09:00
diagnostics_routes.py Fix email-thread HTML injection, attachment path traversal, and missing authz (#475) 2026-06-01 22:20:17 +09:00
document_helpers.py Harden PDF document markers against cross-owner upload access (#445) 2026-06-01 22:38:14 +09:00
document_routes.py fix: closed document stays active & leaks into new chats (#1160) (#1238) 2026-06-03 01:47:13 +09:00
editor_draft_routes.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
email_helpers.py fix: IMAP connection leak in _imap_move on store/expunge failure (#1325) 2026-06-03 02:35:36 +09:00
email_pollers.py fix(email): no-op IMAP connection leak in _auto_summarize_pass_single on exception (#1423) 2026-06-03 04:13:52 +09:00
email_routes.py fix: IMAP connection leak in _list_emails_sync on exception (#1330) 2026-06-03 02:44:23 +09:00
embedding_routes.py fix: SSRF hardening for the custom embedding endpoint URL (#132) (#1206) 2026-06-02 23:46:33 +09:00
emoji_routes.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
font_routes.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
gallery_helpers.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
gallery_routes.py Providers: omit temperature for OpenAI reasoning models 2026-06-02 20:58:33 +09:00
history_routes.py fix(history): scope topic analysis to authenticated owner only (#744) 2026-06-02 11:36:01 +09:00
hwfit_routes.py fix(hwfit): honor manual "metal" backend in the hardware simulator (#1090) 2026-06-02 23:12:34 +09:00
mcp_routes.py Fix email-thread HTML injection, attachment path traversal, and missing authz (#475) 2026-06-01 22:20:17 +09:00
memory_routes.py Auth: use require_user for remaining guarded routes 2026-06-02 20:55:50 +09:00
model_routes.py fix: Cookbook local GGUF serving inside Docker (#1264) 2026-06-03 02:08:09 +09:00
note_routes.py fix: fire-reminder endpoint crashes with NameError on _gcu (#1250) 2026-06-03 01:02:25 +09:00
personal_routes.py Scope personal RAG uploads by owner (#446) 2026-06-01 22:36:53 +09:00
prefs_routes.py Add native Windows compatibility layer 2026-06-01 15:09:47 +09:00
preset_routes.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
research_routes.py fix(auth): honor AUTH_ENABLED=false on owner-scoped endpoints (no /login loop) (#880) 2026-06-02 12:26:26 +09:00
search_routes.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
session_routes.py Harden session endpoint owner scope (#1308) 2026-06-03 02:40:22 +09:00
shell_routes.py fix: distinguish external cookbook runtimes (#1188) 2026-06-02 23:20:00 +09:00
signature_routes.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
skills_routes.py fix(skills): markdown save must not rename the skill, so delete keeps working (#1333) (#1365) 2026-06-03 03:16:11 +09:00
stt_routes.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
task_routes.py Polish email tasks and window controls 2026-06-01 20:56:46 +09:00
tts_routes.py Odysseus v1.0 2026-05-31 23:58:26 +09:00
upload_routes.py Fix multi-file uploads tripping the per-IP concurrency guard (#1346) (#1362) 2026-06-03 04:04:19 +09:00
vault_routes.py Keep Bitwarden unlock password off argv (#1311) 2026-06-03 02:13:51 +09:00
webhook_routes.py Treat Venice as a tool-capable SOTA cloud provider (#1173) 2026-06-02 23:03:46 +09:00