fix(cron): tighten worker-side broad-except in _run_cron_tracked (closes #1578)

Remove the try/except Exception wrapper around
cron_profile_context_for_home(...).__enter__() in _run_cron_tracked.
A silent fallback to ctx=None would leave the worker thread unpinned
against process-global HERMES_HOME, silently corrupting cross-profile
state — the same class of bug as #1573.

Add regression test to catch any future re-introduction.
This commit is contained in:
Frank Song
2026-05-04 16:28:33 +08:00
parent 9986d2fd30
commit cdcd6021cc
2 changed files with 33 additions and 7 deletions
+3 -7
View File
@@ -198,14 +198,10 @@ def _run_cron_tracked(job, profile_home=None):
# (threads have no TLS, so get_active_hermes_home() can't resolve).
ctx = None
if profile_home is not None:
try:
from api.profiles import cron_profile_context_for_home
from api.profiles import cron_profile_context_for_home
ctx = cron_profile_context_for_home(profile_home)
ctx.__enter__()
except Exception:
logger.exception("Failed to pin profile %s for cron run", profile_home)
ctx = None
ctx = cron_profile_context_for_home(profile_home)
ctx.__enter__()
try:
success, output, final_response, error = run_job(job)
@@ -197,3 +197,33 @@ def test_cron_run_does_not_silently_swallow_profile_resolution_errors():
"HERMES_HOME. Let the exception propagate (500 the request) rather "
"than corrupt cross-profile state silently."
)
def test_cron_worker_does_not_silently_fall_back_on_profile_context_failure():
"""_run_cron_tracked must NOT silently set ctx=None when
cron_profile_context_for_home(...).__enter__() raises.
A silent fallback in the worker thread would leave the job running
unpinned against process-global HERMES_HOME, silently corrupting
cross-profile state — the same class of bug as #1573. We'd rather
let the exception propagate and kill the worker thread than risk
that.
Source-level assertion to catch any future re-introduction of the
over-broad except clause around the context setup.
"""
from pathlib import Path
src = (Path(__file__).resolve().parent.parent / "api" / "routes.py").read_text(encoding="utf-8")
idx = src.find("def _run_cron_tracked(job, profile_home=None):")
assert idx != -1, "_run_cron_tracked not found"
body = src[idx : idx + 2000]
# The profile-context setup must NOT be wrapped in try/except that
# silently falls back to ctx=None.
assert "except Exception" not in body[:body.find("run_job(job)")], (
"_run_cron_tracked silently falls back to ctx=None when "
"cron_profile_context_for_home(...).__enter__() raises. That leaves "
"the worker thread unpinned against process-global HERMES_HOME. "
"Let the exception propagate rather than corrupt cross-profile state."
)