fix(embed): read CLI profile config as UTF-8 - #3850
Conversation
Strix Security ReviewWarning This pull request has 1 commit after the last Strix review ( No security issues found. Updated for Reviewed by Strix |
Sanderhoff-alt
left a comment
There was a problem hiding this comment.
The read-side change is right, but the fix looks incomplete for the locale it targets: the matching write path and the template load are still locale-dependent, so on a non-UTF-8 default locale this can turn a previously-working default profile into an unreadable one. Details inline.
| # Load ONLY this profile's config, never fall back to default | ||
| if config_path.exists(): | ||
| with open(config_path) as f: | ||
| with open(config_path, encoding="utf-8") as f: |
There was a problem hiding this comment.
Pinning only the read side makes the default profile unreadable on a non-UTF-8 locale. hindsight-embed configure writes this exact file via CONFIG_FILE.write_text(render_config(...)) at hindsight-embed/hindsight_embed/cli.py:258 and :445, with no encoding=, so the text goes out in the process locale. render_config seeds from .env.example, which contains U+2014; both cp1252 (b'\x97') and gbk (b'\xa1\xaa') encode it happily. Before this change the write and read used the same codec and round-tripped; after it, the UTF-8 read raises UnicodeDecodeError on those bytes and startup fails. Please pin the writes too:
| with open(config_path, encoding="utf-8") as f: | |
| with open(config_path, encoding="utf-8") as f: |
(plus CONFIG_FILE.write_text(render_config(config_values), encoding="utf-8") at both write sites — profile_manager.py:419 already does this).
| @@ -104,7 +104,7 @@ def load_config_file(): | |||
|
|
|||
| # Load ONLY this profile's config, never fall back to default | |||
| if config_path.exists(): | |||
There was a problem hiding this comment.
The description says this fixes #3837, but the same failure remains on other paths reading the same file, so a GBK/cp1252 user still hits it:
hindsight-embed/hindsight_embed/env_template.py:24and:28—bundled.read_text()/candidate.read_text()with no encoding.env.exampledoes not decode as gbk ('gbk' codec can't decode byte 0x94 in position 639), soconfigureand profile creation raise before any config is written.hindsight-embed/hindsight_embed/cli.py:1219,:1271,:1316—config_path.read_text()with no encoding, in the config merge/set/unset commands.
Suggest pinning encoding="utf-8" on all of them in this PR so the contract holds for every reader and writer of the profile config.
|
Good catches — I pinned UTF-8 across the template reads, both default-profile writes, and the merge/set/remove readers in a0f4ef5. I also added a regression that requires the bundled template read to request UTF-8. Focused tests pass (22 passed; 3 unrelated daemon-command tests deselected), along with Ruff, format, and diff checks. |
Problem
load_config_file()opens the active profile.envwith the process locale. The generated template contains UTF-8 characters, so profile startup can fail on Windows locales such as GBK or cp1252.Fix
Fixes #3837.
Test
uv run pytest tests/test_profile_daemon_config.py -k load_config_file -q(2 passed)uvxfallbackuv run ruff check hindsight_embed/cli.pyuv run ruff check tests/test_profile_daemon_config.py --ignore F401(the module has three pre-existing unused imports)uv run ruff format --check hindsight_embed/cli.py tests/test_profile_daemon_config.pygit diff --checkRisk
Low. The profile files are generated and written as UTF-8 already; this makes the read path match that contract. No parsing or precedence behavior changes.