Skip to content

fix(approval): use per-job ContextVar for cron-session flag instead of leaking env var (#56771) - #650

Open
hashbender wants to merge 1 commit into
mainfrom
mirror/pr-56796
Open

fix(approval): use per-job ContextVar for cron-session flag instead of leaking env var (#56771)#650
hashbender wants to merge 1 commit into
mainfrom
mirror/pr-56796

Conversation

@hashbender

Copy link
Copy Markdown
Owner

What

execute_code (and dangerous-command guards) were blocked in interactive gateway/CLI/TUI sessions whenever HERMES_CRON_SESSION=1 was present in the process environment — even though the user never ran a cron job in that session (NousResearch#56771).

Root cause

cron/scheduler.py set os.environ["HERMES_CRON_SESSION"] = "1" process-wide at job start and never cleared it. The approval system then gates on env_var_enabled("HERMES_CRON_SESSION") at 4 sites. When the gateway and scheduler share a process (the normal architecture), the env var leaks via inheritance into every concurrent interactive session, so the approval system treats user chats as cron and blocks execute_code / dangerous commands.

This was the only place in the codebase that set the var, and approval.py was the only consumer — so replacing the process-global set has no other side effects.

Fix

Replace the process-global env var with a task-local ContextVar so the cron flag cannot leak into concurrent interactive sessions:

  • gateway/session_context.py — add _CRON_SESSION ContextVar (mirroring the existing _UNSET sentinel pattern of the session vars) plus set_cron_session() / clear_cron_session() / is_cron_session() helpers. is_cron_session() checks the ContextVar first and falls back to the env var only for backward compat with tests / CLI cron paths that set it directly (in production the scheduler no longer sets it, so interactive sessions fall through to False).
  • cron/scheduler.py — replace the os.environ set with set_cron_session(True); add clear_cron_session() to the run_job() finally block. The flag is set before the scheduler's existing copy_context() (line 2861) that the agent thread runs inside (_cron_context.run(agent.run_conversation)), so real cron jobs still see True and cron_mode: deny keeps working.
  • tools/approval.py — add _is_cron_session() (contextvar-aware, lazy-imported like the existing get_session_env calls) and replace all 4 env_var_enabled("HERMES_CRON_SESSION") checks with it.

Why ContextVar and not env-var reordering

The scheduler sets the cron flag before spawning the agent in a worker thread via copy_context().run(...). ContextVars propagate downward through ctx.run, so the agent thread sees True; concurrent interactive sessions run in their own tasks/contexts where the var is _UNSET, so they resolve to False. By contrast os.environ is shared across all threads/process-children, which is precisely the leak this fixes. Competing approaches that merely reorder the gateway/cron precedence checks (or gate on interactive indicators) leave the env var leaking into spawned subprocesses and reverse the original design invariant that cron takes absolute priority over gateway approval.

How verified

  • 11 new regression tests (tests/tools/test_cron_session_leak.py): contextvar resolution, the core thread-isolation mechanism (scheduler thread sets the flag, concurrent gateway thread does not see it), env-var fallback for backward compat, contextvar-overrides-leaked-env, and the full check_execute_code_guard + _is_gateway_approval_context matrix (cron blocks, interactive allowed, interactive-after-scheduler-ran still allowed).
  • 325 existing approval/cron tests pass.
  • 612 scheduler tests pass.
  • Branch is exactly one focused commit ahead of main (0 1).

Closes NousResearch#56771.


Auto-published by Moonsong via Path B automated pipeline.


Mirror-of: NousResearch#56796
NousResearch#56796

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.

[Bug]: execute_code blocked in interactive Telegram gateway session because HERMES_CRON_SESSION env var leaks from cron scheduler into user's shell

1 participant