fix(cron): migrate HERMES_CRON_SESSION from os.environ to ContextVar - #69766
Closed
im47cn wants to merge 1 commit into
Closed
fix(cron): migrate HERMES_CRON_SESSION from os.environ to ContextVar#69766im47cn wants to merge 1 commit into
im47cn wants to merge 1 commit into
Conversation
Collaborator
…earch#73195) Add tests/gateway/test_cron_session_contextvar.py covering: 1. is_cron_session() resolution order: ContextVar → os.environ fallback, truthy value handling 2. Producer isolation: ContextVar.not visible in other threads / copied contexts clear_session_vars() resets the flag 3. Defense-in-depth: set_session_vars() explicitly gates _CRON_SESSION_FLAG → '' Even a leaked os.environ var cannot miscategorize a gateway session 4. Bug scenario (NousResearch#73195): Feishu user replies to cron-delivered message is_cron_session() → False execute_code NOT blocked 5. Backward compat: Dedicated cron process (os.environ only) still blocks when cron_mode=deny Also add _CRON_SESSION_FLAG to clear_session_vars() explicit list and set it to '' in set_session_vars() for defense-in-depth.
im47cn
force-pushed
the
fix/cron-session-contextvar-migration
branch
from
July 23, 2026 02:53
b673cf6 to
8570a40
Compare
Author
|
Closing in favor of #58663 (earlier, more-reviewed ContextVar migration by @Adolanium). Two enhancement points submitted as review comments on #58663: (1) defense-in-depth via set_session_vars() gating, (2) Feishu reply-to-cron-message bug-scenario tests. |
19 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
When the cron scheduler runs inside a gateway process (
InProcessCronScheduler, the default),os.environ["HERMES_CRON_SESSION"] = "1"leaks into user-interactive sessions — permanently. Any user who replies to a cron-delivered message in a gateway platform inherits the flag.Concrete reproduction
Setup: Feishu gateway with 1 cron job (PR/branch monitor, delivers a daily report card to a group chat every 6 hours).
Steps to reproduce:
os.environ["HERMES_CRON_SESSION"] = "1"(line 2920)os.environ["HERMES_CRON_SESSION"]is still"1"execute_codeto run a multi-step script → BlockedActual error (from production logs, 2026-07-23 08:45 BJT):
{ "status": "error", "error": "BLOCKED: execute_code runs arbitrary local Python (including subprocess calls that bypass shell-string approval checks). Cron jobs run without a user present to approve it." }Actual impact: 3 consecutive
execute_codecalls blocked in a single session. The agent fell back toterminalfor each call individually, wasting tokens and slowing down response time.Process environment at the time of block (confirmed):
Why this keeps happening
The code comment itself acknowledged the design limitation:
This was written for a dedicated scheduler process. But the gateway co-locates the scheduler via
InProcessCronScheduler(default since the provider refactor). There is no cleanup — once set, the flag sticks until the gateway process restarts. Every user interaction handled by that process between cron ticks inherits the stale flag.Affected tools
Any tool gated on
check_execute_code_guardorcheck_all_command_guardsis affected whenapprovals.cron_modeisdeny(the default):execute_codeweb_requestrm -rf,chmod,mkfs,dd, etc.)Root Cause
os.environis process-global. The entire rest of the session state (HERMES_SESSION_PLATFORM,HERMES_SESSION_CHAT_ID, etc.) already migrated to ContextVars ingateway/session_context.py— butHERMES_CRON_SESSIONwas left behind.Fix
Migrate
HERMES_CRON_SESSIONto the existing ContextVar system:1.
gateway/session_context.py— new ContextVar + getter2.
cron/scheduler.py— ContextVar.set instead of os.environ assignmentNo manual cleanup needed — the existing
clear_session_vars()in thefinallyblock already resets all ContextVars (line 3626).3.
tools/approval.py— 4 call sites migratedThe 4 consumers are:
_is_gateway_approval_context()(line 241) — cron is never a gateway approval contextcheck_all_command_guards()(line 2717) — dangerous command blockingcheck_dangerous_command()(line 3245) — dangerous command detectioncheck_execute_code_guard()(line 3681) — script execution blockingWhy this is the right fix
HERMES_SESSION_*variableis_cron_session()falls back toos.environfor dedicated cron processes and CLI testsclear_session_vars()handles resetTests
All 1100 cron + approval tests pass. One pre-existing failure in
test_approval.py(detect_dangerous_command/tmp/path detection — unrelated to this change).