fix(cron): isolate approval context per job - #76749
Conversation
teknium1
left a comment
There was a problem hiding this comment.
Thanks for isolating a real approval-routing leak: current main still sets HERMES_CRON_SESSION process-wide in cron/scheduler.py:3014, and tools/approval.py:241-245 lets that stale flag override later gateway classification.
Problems
gateway/session_context.py:138addsHERMES_CRON_SESSIONto_VAR_MAP, which makes it a bridged child-process variable (tools/environments/local.py:445-453). But the shared shell snapshot exclusion is explicitly required to stay synchronized with_VAR_MAP(tools/environments/base.py:399-402) and currently only excludesHERMES_SESSION_*,HERMES_UI_SESSION_ID, andHERMES_CRON_AUTO_DELIVER_*(tools/environments/base.py:403-437). The new cron identity can therefore be persisted into the shared snapshot.
Suggested changes
- Exclude
HERMES_CRON_SESSIONin both snapshot filtering paths intools/environments/base.py, and add a snapshot regression test alongsidetests/tools/test_snapshot_multiline_session_env_injection.py.
Automated hermes-sweeper review.
| @@ -135,6 +136,7 @@ def session_context_engaged() -> bool: | |||
| "HERMES_UI_SESSION_ID": _SESSION_UI_SESSION_ID, | |||
| "HERMES_SESSION_MESSAGE_ID": _SESSION_MESSAGE_ID, | |||
| "HERMES_SESSION_PROFILE": _SESSION_PROFILE, | |||
There was a problem hiding this comment.
Adding this bridged name also requires updating the shared-shell snapshot exclusion in tools/environments/base.py: its _VAR_MAP synchronization contract currently excludes only HERMES_SESSION_*, HERMES_UI_SESSION_ID, and HERMES_CRON_AUTO_DELIVER_*. Otherwise a cron terminal child can persist HERMES_CRON_SESSION=1 in the shared snapshot.
Related: #43370 and #58663 address the same cron approval-marker leak. This patch covers scheduler, bang-shell, and MCP elicitation; #43370 also explicitly masks stale cron state across gateway, API, ACP, and TUI entrypoints. Maintainer decision needed on the preferred coverage/mechanism. |
SummaryThirty-nine PRs address or reference this approval-system complex: most cron fixes target the process-global HERMES_CRON_SESSION leak, while the remaining diffs cover plugin-driven tool approval, unattended-policy ordering, file/skill approvals, smart-prompt context, and adjacent hardening. The cron root cause is already fixed on main by #77022; the other subproblems require separate dispositions rather than treating every PR as interchangeable. Related pull requests
DuplicatesThe cron-leak chain is #35515/#43549/#46167/#57124/#59242/#60386/#60611/#76763 for env restoration and #29854/#36004/#37969/#43370/#56796/#58663/#59719/#62111/#64194/#69566/#69766/#70768/#76749 for task-local isolation, all superseded by merged #77022. The plugin chain is #58698 → #59163 → #60504, with #60544 duplicating the landed gateway-notify repair; #60547 is superseded by #61064. Suggested consolidationClose the remaining cron-leak PRs as already implemented on main by #77022 (commit fb6446f, tests/cron/test_scheduler_cron_session_isolation.py), including #76749 despite its keep_open review and best-fix record because the merged diff contains its mechanism plus the requested shell-snapshot exclusion. Keep #59179, #61064, and #46900 open only on their concrete salvage paths, require author action on #60550, and close the identified duplicate chains. Complex graphflowchart LR
classDef open fill:#dbeafe,stroke:#1d4ed8,color:#1e3a8a
classDef merged fill:#dcfce7,stroke:#15803d,color:#14532d
classDef closed fill:#e5e7eb,stroke:#6b7280,color:#1f2937
classDef unverified fill:#f3f4f6,stroke:#9ca3af,color:#374151
classDef best stroke-width:3px,stroke:#b45309
classDef target stroke-width:3px,stroke:#4338ca
I76748(["issue #76748 (open)"])
P76749["PR #76749 (open)"]
P76749 -->|best fix| I76748
class I76748 open
class P76749 open
class P76749 best
class P76749 target
click I76748 "https://github.com/NousResearch/hermes-agent/issues/76748"
click P76749 "https://github.com/NousResearch/hermes-agent/pull/76749"
Graph: solid arrow = fixes / best fix, dashed arrow = partial or unverified (see edge label); boxed group = PRs duplicating each other; amber border = best fix; indigo border = target; gray node = closed (state tag in the node label). Cross-PR triage: Reviewed 39 pull requests and 17 issues in this complex. Each diff was read against this issue; Assessment working set: 700 kB of PR diffs, 142 kB of issue/PR text, 129 kB of discussion (159 comments), 127 verify verdicts. verdicts reflect diff content, not PR titles. Part of an automated triage batch. |
What does this PR do?
Scopes cron approval identity to the active cron task instead of setting process-global
HERMES_CRON_SESSION=1forever.The gateway and cron scheduler share a process. After the first agent-backed cron run, the leaked flag caused later Discord MCP elicitations to be treated as CLI/cron approvals. They fell through to a terminal prompt with no stdin and failed closed as denied instead of rendering Discord approval controls.
The new task-local context preserves cron policy during the cron run, including worker threads and subprocess environment construction, while preventing completed or concurrent cron runs from changing live gateway approval routing. Legacy process-env callers still work through
get_session_env()fallback.Related Issue
Fixes #76748
Type of Change
Changes Made
gateway.session_contextper task.os.environ.How to Test
approvals.cron_mode.Commands run:
Results: 325 targeted tests passed, Ruff passed, and no Windows footguns were found.
Checklist
Code
pytest tests/ -qand all tests passDocumentation & Housekeeping
cli-config.yaml.examplechanges are N/ACONTRIBUTING.mdandAGENTS.mdchanges are N/Acheck-windows-footguns.pyScreenshots / Logs
Before the fix, the live Discord request was routed to the gateway process terminal and failed closed:
Both the scheduler lifecycle test and MCP context-bridge test cover this routing regression.