Add a complete Turkish locale to the WebUI and login page so users can
select Türkçe in Settings, with speech recognition via tr-TR.
Co-authored-by: Cursor <cursoragent@cursor.com>
6 test files had hardcoded locale counts/lists that broke when
the Italian locale block was added:
- test_issue1488_composer_voice_buttons.py: added 'it' to LOCALES,
replaced assert count == 9 with len(self.LOCALES)
- test_issue1560_password_env_var_lock.py: added 'it' to LOCALES
- test_1560_password_env_var_no_op.py: added 'it' to EXPECTED_LOCALES
- test_login_locale_parity.py: bumped floor from 9 to 10, added 'it'
- test_stage268_opus_followups.py: bumped floor from 9 to 10
(cherry picked from commit f5e42cec9bc77354c594321b20ba83055d2e3cf7)
CI failed across test_clarify_unblock + test_gateway_sync (~25 tests, all 401
Unauthorized) because two tests in this module write `password_hash` directly
to the shared TEST_STATE_DIR/settings.json (the path the integration server
reads):
- `test_post_set_password_settings_hash_unchanged_after_409` seeds a sentinel
hash to verify the 409 short-circuit doesn't overwrite it.
- `test_post_set_password_succeeds_when_env_var_unset` goes through
save_settings() with `_set_password`, persisting a real hash.
After this module ran, the integration server saw `is_auth_enabled() == True`
and rejected every subsequent request from test_clarify_unblock /
test_gateway_sync with 401.
Fix:
- Add `_restore_settings_file_after_test` autouse fixture that snapshots
cfg.SETTINGS_FILE before each test and restores it after, so password_hash
writes don't leak to later tests.
- Remove the misleading module-level `os.environ['HERMES_WEBUI_STATE_DIR']`
override — api.config.STATE_DIR resolves at import time (already done by
conftest.py before this module loads), so the override never reached the
in-process state path it claimed to redirect.
- Add `self.request = None` to FakeHandler so set_auth_cookie's
`getattr(handler.request, 'getpeercert', None)` probe doesn't AttributeError
on the success path of `_set_password` once settings are properly cleaned
between tests (the prior CI pass relied on stale state bouncing the request
with 401 before set_auth_cookie ran).
Verified locally: 85 tests pass across test_1560_*, test_issue1560_*,
test_clarify_unblock, test_gateway_sync (the previously-affected suites).
Settings password silently no-opped when HERMES_WEBUI_PASSWORD was set:
the env var takes precedence in api.auth.get_password_hash(), but the UI
happily POSTed _set_password and returned a green "Saved" toast while
every subsequent login still required the env-var password. Same for
Disable Auth (_clear_password=true).
Backend (api/routes.py):
- GET /api/settings now exposes password_env_var: bool so the UI knows
the field is shadowed.
- POST /api/settings refuses _set_password and _clear_password with HTTP
409 + a clear message naming HERMES_WEBUI_PASSWORD when the env var is
set. Short-circuits BEFORE save_settings() so settings.json is not
touched.
Frontend (static/index.html, static/panels.js, static/i18n.js):
- Added settingsPasswordEnvLock banner div in the System pane.
- panels.js reads settings.password_env_var, disables the password field,
swaps in a localized "locked" placeholder, reveals the banner, and
hides the Disable Auth button (its POST would 409 anyway).
- New i18n keys password_env_var_locked and password_env_var_locked_placeholder
added to all 9 locales (en, ja, ru, es, de, zh, zh-Hant, pt, ko).
Tests:
- tests/test_issue1560_password_env_var_lock.py: requirement-pinning
(handler exposes flag, 409 on set/clear, banner div, panels.js wiring,
i18n in all 9 locales, env var name in messages, live HTTP smoke when
env unset).
- tests/test_1560_password_env_var_no_op.py: behavioral via FakeHandler
(real status codes for env-set/unset/blank, settings.json hash unchanged
after 409, panels.js disable+banner+placeholder+disable-auth-hidden).
Both files run clean: 23 passed in 2.04s. test_issue1139_password_remote.py
unaffected (4/4 still pass).