Conversation
Nested hermes chat --source tool from a Kanban worker inherited HERMES_KANBAN_TASK and could kanban_complete the parent card. Strip lifecycle ownership from subprocess env and drop it at chat startup unless the process is the dispatcher worker.
Map shermanlye@Shermans-MacBook-Pro.local to ming0627 so the transplanted authorship commit passes contributor attribution CI.
|
Local verification on a fresh clone of current
GitHub Actions on this fork PR is sitting in This is the same class as #70809. Distinct from still-open #70898 (ContextVar gating, failed CI) and #81843 (spawn-path strip only). |
Reviewed What's good
Suggestions
Strong security fix for a real destructive race (child completing the parent card deletes the live workspace); #1 is the one thing I'd harden before merge. |
|
Bound to the expanded ambient process-authority class under #83565 and the governing control-plane architecture in #91911. This PR supplies the deny-side reference edge: a dispatcher-owned Kanban worker may own its task lifecycle, but an arbitrary nested Keep the board-routing pins and explicit real-worker launch contract; strip lifecycle mutation authority at the child boundary and retain the startup-side proof so a polluted environment cannot re-mint ownership. This is the complement of #92309, which carries bounded authority across one explicitly authorized worker → Architecture extension: #91911 (comment) |
|
Independent follow-up completed for the explicit native-worker launch contract. PR against this branch: ming0627#1 The follow-up removes human query text from authority and uses a fresh one-shot nonce in both the native spawn env and hidden CLI argument. Startup requires exact source/task/nonce agreement, consumes the env nonce immediately, rejects reconstruction from the public task ID, and fails closed on validator import failure while retaining board/DB routing. Evidence: 39/39 final relevant tests, repository-wide ownership-key scan 7/7 covered, Ruff/compileall/diff-check clean. Parent is exact head Scope note: this prevents accidental/passive lifecycle inheritance; it is not claimed as cryptographic isolation from a malicious same-user process. |
|
Current-main refresh of the machine launch contract requested in review, kept separate from every other Kanban fix.
The issue still reproduced on that base. The refreshed patch removes human query text from authority: the native dispatcher creates a fresh one-shot nonce, passes it through both the worker environment and a hidden CLI argument, requires exact source/task/nonce agreement, and consumes the environment proof at startup. Ordinary child chats retain only board/DB routing pins and lose lifecycle mutation authority. Verification on the exact commit: the two regression files failed with 21 tests before the source patch; afterward those 21 passed. The 11-file Kanban startup/environment matrix passed with 112 passed and 0 failed. Ruff, compileall, and This supersedes my older author-branch follow-up |
Bug Description
A dispatcher-owned Kanban worker that shells out to
hermes chat(for examplehermes chat -Q … --source toolfor Browser Use) inheritedHERMES_KANBAN_TASK/RUN_ID/WORKSPACE/CLAIM_LOCK. The child process is a new interpreter, so in-process ContextVars cannot help:is_dispatcher_owned_worker_context()defaults True, and the child cankanban_completethe parent card, which then deletes the scratch workspace while the real worker is still running.Fixes #70809
Related (open, not landed, different or incomplete approaches): #70898, #81843.
Root Cause
os.environand only fully scrubbed Kanban identity insidedelegate_task/ in-process cron contexts.hermes chatis a new process, so ContextVar isolation from delegate_task children inherit HERMES_KANBAN_TASK and can complete/block the parent's kanban card #56647 / fix(kanban): isolate delegate_task children from the parent's Kanban task #69837 / cron isolation does not apply.Fix
Defense in depth, transplanted from locally tested commit
2abc0a841onto currentorigin/main:_make_run_env,_sanitize_subprocess_env, andhermes_subprocess_envdrop lifecycle ownership keys (TASK,RUN_ID,WORKSPACE,WORKSPACES_ROOT,CLAIM_LOCK). Board routing pins (BOARD/DB) stay sohermes kanbanshell-outs remain on the same board ([Bug]: harness kanban CLI invoked from agent session ignores active-board pin, races current file with concurrent boards switch #20074).build_subprocess_env(scrub_secrets=True)inherits this via_sanitize_subprocess_env.cmd_chatdrops the same keys unless this process is the explicit dispatcher worker (HERMES_SESSION_SOURCE=kanbanAND querywork kanban task <id>).--query-fileis checked after the prompt is loaded._default_spawnstill injects ownership into the real worker.Authorship of the functional commit is preserved (
Sherman Lye). A follow-up mapping commit attributes the local author email toming0627for contributor-check CI.How to Verify
LocalEnvironment.execute/_make_run_envhas noHERMES_KANBAN_TASKwhileHERMES_KANBAN_BOARD/ provider-style keys remain.cmd_chat --source tooldrops inherited ownership, a mismatchedwork kanban taskprompt drops it, and an explicit board-worker launch keeps it.kanban_completefrom that child env errors and the parent task staysrunningwith its workspace intact.Test Plan
test_terminal_child_cannot_complete_parent_and_parent_stays_runningVerified on this PR branch (fresh clone of current
origin/main+ transplant), not the live checkout:Result: 11 files, 100 tests passed, 0 failed.
Risk Assessment
Low / Medium — blast radius is env inheritance for subprocesses launched from a Kanban worker and
cmd_chatstartup. Board pins and Browser Use / provider-key passthrough (inherit_credentials,_BROWSER_PASSTHROUGH_KEYS) are unchanged. Dispatcher workers keep ownership via the explicit argv/env contract.This is not claiming a local-only commit as landed upstream. Merge to
NousResearch/hermes-agentmain is the durable landing.