fix(buzz): the buzz CLI subprocess env leaks the launch profile's residue - #111985
Open
EloquentBrush0x wants to merge 1 commit into
Open
EloquentBrush0x wants to merge 1 commit into
EloquentBrush0x wants to merge 1 commit into
Conversation
…idue _exec_buzz (the sole spawn point for the external `buzz` CLI binary) built its child env with a bare os.environ.copy(). Under gateway.multiplex_profiles, one process serves several profiles and raw os.environ holds the LAUNCH profile's YAML-to-env bridge output plus its .env residue and bridged TERMINAL_* settings — a served secondary profile's buzz invocation inherited all of it, including a HERMES_HOME that pointed at the wrong profile's home. NousResearch#99427 (salvaging NousResearch#98748) already fixed the read side of this class for Buzz: BuzzAdapter's own config resolution (relay/channels/credentials/ allowed users) now goes through _scoped_platform_setting() so a secondary profile's PlatformConfig wins over stale env. But that PR's diff never touched _exec_buzz's env construction — the BUZZ_RELAY_URL/ BUZZ_PRIVATE_KEY/BUZZ_AUTH_TAG values it injects were already correctly scoped by the caller, so the leak was easy to miss: every OTHER ambient variable the launch profile's environment carries (HERMES_HOME foremost) still rode along unscoped. The same NousResearch#111617 multiplex retrofit that fixed 9 other subprocess/ background-thread spawn sites established served_profile_child_env() for exactly this shape (a2a's forward-to-profile subprocess, browser_tool's driver spawn, etc.) — this call site was missed. Switches _exec_buzz to served_profile_child_env(inherit_credentials=False), mirroring tools/browser_tool.py's identical external-CLI-driver pattern: the target profile's home is pinned and the launch profile's residue is dropped, while the buzz CLI's own credentials (relay_url/private_key/ auth_tag) keep arriving explicitly via the function's own parameters. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This branch has not been deployed
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.
Summary
_exec_buzz— the sole spawn point for the externalbuzzCLI binary — built its child env with a bareos.environ.copy(). Undergateway.multiplex_profiles, one process serves several profiles and rawos.environholds the launch profile's YAML-to-env bridge output plus its.envresidue and bridgedTERMINAL_*settings. A served secondary profile's buzz invocation inherited all of it, including aHERMES_HOMEthat pointed at the wrong profile's home.#99427 (salvaging #98748) already fixed the read side of this class for Buzz:
BuzzAdapter's own config resolution (relay/channels/credentials/allowed users) now goes through_scoped_platform_setting()so a secondary profile'sPlatformConfigwins over stale env. But that PR's diff never touched_exec_buzz's env construction (confirmed viagh pr diff— theenv = os.environ.copy()line is an unchanged context line in that PR) — theBUZZ_RELAY_URL/BUZZ_PRIVATE_KEY/BUZZ_AUTH_TAGvalues it injects were already correctly scoped by the caller, so the leak was easy to miss: every other ambient variable the launch profile's environment carries (HERMES_HOMEforemost) still rode along unscoped.The same #111617 multiplex retrofit that fixed 9 other subprocess/background-thread spawn sites this window established
served_profile_child_env()for exactly this shape (a2a's forward-to-profile subprocess,browser_tool's driver spawn, etc.) — this call site was missed.Fix
Switches
_exec_buzztoserved_profile_child_env(inherit_credentials=False), mirroringtools/browser_tool.py's identical external-CLI-driver pattern: the target profile's home is pinned and the launch profile's residue is dropped, while the buzz CLI's own credentials (relay_url/private_key/auth_tag) keep arriving explicitly via the function's own parameters, unchanged.Testing
TestExecBuzzChildEnv::test_served_profile_exec_drops_launch_profile_residue: sets up a launch home with aTERMINAL_ENVbridge var, arms multiplex + a served-profile home override, captures the env passed to a monkeypatchedasyncio.create_subprocess_exec, and assertsHERMES_HOMEis the served profile's home (not the launch profile's),TERMINAL_ENVresidue is absent, and the caller-suppliedBUZZ_RELAY_URL/BUZZ_PRIVATE_KEYstill win.HERMES_HOMEleaked the launch profile's path), restored the fix, confirmed the fulltests/gateway/test_buzz_adapter.pysuite passes (187/187).tests/agent/test_subprocess_env_guard.py(2/2) to confirm no regression in the sibling guard.🤖 Generated with Claude Code