fix(cli): quote .env values with internal whitespace in save_env_value - #66483
fix(cli): quote .env values with internal whitespace in save_env_value#66483pnascimento9596 wants to merge 1 commit into
Conversation
_quote_env_value previously left internal spaces unquoted (only #/"/' and leading/trailing whitespace triggered). Spaced macOS paths written via hermes setup SSH / Google Chat SA path / hermes config set produced lines that python-dotenv still parsed but shell `set -a; . file` word-split. Extend needs_quoting with any(c.isspace()); escaping dialect unchanged.
teknium1
left a comment
There was a problem hiding this comment.
Thanks for isolating the core serializer path. The premise is confirmed on current main: hermes_cli/config.py:7776-7785 does not quote internal whitespace, and standard setup paths call save_env_value for SSH and Google Chat filesystem paths (hermes_cli/setup.py:1416; plugins/platforms/google_chat/adapter.py:3484).
Problems
- The new shell round-trip tests invoke
envandshunconditionally (tests/hermes_cli/test_config.py:634and:668in this PR). Native Windows does not guarantee those executables. The existing POSIX file-mode tests in this class already guard Windows at current-maintests/hermes_cli/test_config.py:534and:548.
Suggested changes
- Gate the shell-source checks/tests on non-Windows platforms; keep the serializer,
dotenv_values, andload_env()assertions cross-platform.
Automated hermes-sweeper review.
| assert load_env()["TERMINAL_SSH_KEY"] == path | ||
|
|
||
| # Shell source must round-trip (this is what the bug broke). | ||
| r = subprocess.run( |
There was a problem hiding this comment.
Please gate this shell-source assertion (and the analogous tab test) on non-Windows platforms. Native Windows does not guarantee env or sh; retain the serializer/dotenv assertions cross-platform and make only the POSIX shell round-trip conditional.
|
Salvaged into #67192 (P2 config batch) with authorship preserved, rebased on current |
|
Thanks @OutThisLife, happy the whitespace fix and round-trip test held up. #67192 was a tidy way to land the batch. |
What / why
Fixes #66482.
_quote_env_value(used by everysave_env_valuewrite) quoted only for#/"/'/ leading-trailing whitespace. Internal spaces (e.g. macOSApplication Supportpaths forTERMINAL_SSH_KEYorGOOGLE_CHAT_SERVICE_ACCOUNT_JSON) were left unquoted:python-dotenv still reads that correctly; POSIX
set -a; . fileword-splits:One-condition fix: extend
needs_quotingwithany(c.isspace() for c in value). Escaping dialect unchanged (\\then\"then wrap — same dialect #57249 / sweeper already blessed for the installer writer).Does not touch
install.sh/install.ps1(#57249's surface). This is the core serializer sibling of accepted #57247.Residual write paths
This PR fixes the core serializer (
_quote_env_valueviasave_env_value) that all standard config/setup flows route through. The following sites still write rawKEY=valuelines outside_quote_env_valueand are enumerated for follow-up (verified still present on currentmain):hermes_cli/memory_setup.py—_write_env_varsplugins/memory/mem0/_setup.py—_write_envplugins/memory/hindsight/__init__.py— setup path that rewrites Hermes.envlines in placeplugins/memory/openviking/__init__.py—_write_env_varsThose provider/setup writers are intentionally out of scope here.
CI (at push time)
On head
d90bfdfdb(run29608254881): 23 SUCCESS / 9 SKIPPED / 0 FAILED. Numbers are the rollup at push time; re-check the checks tab for the current tip if the branch has moved.Churn analysis (Gate 4)
No mass-requote of existing user
.envfiles.save_env_valuerewrites the file but only re-serializes the key being written; other lines pass through_sanitize_env_lineswith their original text. A legacy unquoted spaced line stays unquoted until that key is saved again (one-time correction on re-save). Simple unquoted values stay unquoted (no rewrite churn). No caller depends on spaced values staying unquoted — shell source was already broken for them; dotenv load is unchanged for both quoted and unquoted forms.Tests
tests/hermes_cli/test_config.py(TestSaveEnvValueSecure):set -a; . fileround-tripdotenv_values) → re-save idempotent (setup path)load_envdialect round-trip\n/\rstripped before quote (single-line writer boundary)Counts:
TestSaveEnvValueSecure16 passed; fulltest_config.py163 passed. Footguns on changed files: 0.One logical change
Production: single extra disjunct in
needs_quoting. Tests: coverage + one pre-existing footgunencoding=in the same test file.Merge-tree vs #57249
Report in PR comment / sync after both dual-order checks (installer branch only touches install scripts; expected clean either order).
Type of Change