HERMES-GIELIE/api
nesquena-hermes 6c6444396d
fix(#3750): preserve LM Studio auth on reasoning probe (self-rebased #3837 + credential hardening) (#4202)
* fix(#3750): preserve LM Studio auth on reasoning probe

Rebased rodboev's #3837 onto current master (master reworked
resolve_model_reasoning_efforts via #3431 with a combined hermes_cli
import + _nested_route_reasoning_denied guard). Threaded the api_key
resolution + the _lmstudio_model_reasoning_options wrapper + the
HTTP-fallback probe into master's current structure; intent preserved
byte-identically (+164/-24, same as the original PR diff).

Co-authored-by: Rod Boev <rod.boev@gmail.com>

* fix(#3837): gate LM Studio probe credential to configured endpoint + no-redirect opener

Codex security review (CORE) on the rebased #3837: GET /api/reasoning accepts
a caller-supplied base_url, and the new probe attached the configured LM Studio
API key as a Bearer token; urllib also re-sends Authorization across redirects.
Together that could exfiltrate the stored credential to an attacker-controlled
host. (master only escalates here because master probed WITHOUT a key.)

Fixes:
1. Only forward the LM Studio credential when the probe target normalizes to
   the configured LM Studio base URL (reuses _normalize_base_url_for_match);
   a caller-supplied non-matching base_url is probed keyless.
2. _lmstudio_reasoning_probe_options_fallback uses a no-redirect opener
   (_NoRedirectHandler) so a 3xx can't forward the Authorization header onward.
3. Two regression tests: caller-supplied base_url drops the key; redirect is
   not followed (credential never reaches the redirect target).

Co-authored-by: Rod Boev <rod.boev@gmail.com>

* fix(#3837): route ALL credentialed LM Studio probes through the no-redirect probe

Codex re-gate caught that the first fix only hardened the built-in fallback;
in production hermes_cli IS importable, so the preferred path called
hermes_cli.models.lmstudio_model_reasoning_options(..., api_key=...) which uses
plain urlopen and still follows redirects with the credential.

Fix: _lmstudio_model_reasoning_options now short-circuits to the built-in
no-redirect probe whenever api_key is set; the hermes_cli path is used ONLY for
keyless probes (no credential to leak). Reworked tests accordingly:
- test_credentialed_probe_never_calls_hermes_cli: credentialed probe bypasses CLI
- test_keyless_probe_logs_signature_mismatch_before_fallback: keyless CLI degrade
- test_credentialed_probe_does_not_follow_redirects_end_to_end: E2E through
  resolve_model_reasoning_efforts with real hermes_cli; redirect target never hit

Verified both security tests fail without the guard and pass with it.

Co-authored-by: Rod Boev <rod.boev@gmail.com>

* chore(release): stamp v0.51.420 (Release OG) in CHANGELOG

---------

Co-authored-by: nesquena-hermes <agent@nesquena-hermes>
Co-authored-by: Rod Boev <rod.boev@gmail.com>
2026-06-14 15:46:35 -07:00
..
__init__.py
agent_health.py Release v0.51.260 — Release IB (stage-r8) (#3614) 2026-06-04 15:21:41 -07:00
agent_sessions.py fix(#3930): push source filters into agent session scans 2026-06-11 16:59:18 -04:00
auth.py harden(#4023): apply Opus security findings — verify-side name-pattern gate + require handler when auth enabled 2026-06-12 07:37:48 +00:00
background.py
background_process.py [HELD — independent review pending] Release v0.51.340 — bg_task agent wakeup (trio #2968+#2971+#2979) (#3867) 2026-06-08 22:36:18 -07:00
clarify.py feat: add distinct attention request sound 2026-05-30 19:40:40 +00:00
commands.py Merge #4112 (skill bundles in WebUI slash commands, #4087) onto master 2026-06-13 23:13:28 +00:00
compression_anchor.py fix(sidebar): keep newer continuation visible over older snapshot 2026-05-28 13:38:06 -06:00
config.py fix(#3750): preserve LM Studio auth on reasoning probe (self-rebased #3837 + credential hardening) (#4202) 2026-06-14 15:46:35 -07:00
dashboard_probe.py fix: preserve IPv6 dashboard link brackets 2026-05-19 21:35:10 -04:00
extensions.py
gateway_chat.py Apply Codex fix: gateway done-payload uses _session_payload_with_full_messages too (sibling of streaming done/error sites) + test 2026-06-14 20:38:43 +00:00
gateway_watcher.py Release v0.51.256 — Release HX (stage-r4) (#3596) 2026-06-04 12:28:06 -07:00
goals.py fix(i18n): localize /goal runtime status strings 2026-05-10 15:21:24 +08:00
helpers.py Merge #4028 (align profile cookie env var with HERMES_WEBUI_ prefix) onto master 2026-06-13 07:20:58 +00:00
kanban_bridge.py Release v0.51.348 — Release LL (Phase 0 hotfix: timeout regression + data-loss + leaks) (#3917) 2026-06-10 01:12:48 -07:00
metering.py
models.py fix: refresh stale zero-message snapshots 2026-06-14 08:26:59 +02:00
oauth.py Release v0.51.330 — Release KT (#3716 api docstring backfill, partial) (#3841) 2026-06-08 12:22:22 -07:00
onboarding.py Classify onboarding DNS probe failures consistently 2026-05-15 08:51:30 +08:00
passkeys.py Release v0.51.270 — Release IL (stage-u1 — un-hold batch: #3517 #3624 #3613) (#3674) 2026-06-05 11:35:26 -07:00
paths.py fix(profiles): avoid config import cycle 2026-06-01 05:05:16 +00:00
plugin_providers.py Release v0.51.270 — Release IL (stage-u1 — un-hold batch: #3517 #3624 #3613) (#3674) 2026-06-05 11:35:26 -07:00
plugins.py fix(#2622): plugin card UX — legible Open button, single badge, visible toggle + reject protocol-relative tab.path 2026-06-02 03:58:02 +00:00
profiles.py fix(profiles): scope the detached models-rebuild worker to the active profile (#3957) 2026-06-11 01:41:24 +00:00
providers.py fix(providers): claim probe workers under the pool lock (#3787) 2026-06-13 16:42:43 -04:00
request_diagnostics.py fix: add request wedge diagnostics 2026-05-08 15:37:08 +00:00
rollback.py
route_approvals.py fix(approval): extract _webui_mirror_token literal into named constant 2026-06-14 17:48:37 +00:00
routes.py Merge PR #3881: cache + single-flight /api/sessions payloads (#3791) 2026-06-14 18:53:57 +00:00
run_journal.py fix(streaming): tighten tool limit terminal guards 2026-06-12 10:03:31 +08:00
runner_client.py harden: runner client rejects non-http(s) base_url + no redirect-follow (#3073) 2026-05-31 17:49:26 +00:00
runtime_adapter.py Stage 398: PR #2696 — feat(runtime): add runner-local adapter selection (RuntimeAdapter slice 4c, feature-flagged) 2026-05-21 17:43:54 +00:00
session_discoverability.py Merge PR #3048 2026-05-28 17:47:33 +00:00
session_events.py perf(sidebar): cache and single-flight /api/sessions payloads (#3791) 2026-06-13 22:36:25 -04:00
session_lifecycle.py Release v0.51.256 — Release HX (stage-r4) (#3596) 2026-06-04 12:28:06 -07:00
session_ops.py Release v0.51.276 — Release IR (stage-p3e — preserve manually-named session titles #3542) (#3682) 2026-06-05 13:34:54 -07:00
session_recovery.py Release v0.51.329 — Release KS (#3814 O(n) index map + #3815 startup recovery skip) (#3840) 2026-06-08 11:49:26 -07:00
skill_usage.py fix: remove webui-side writer to avoid conflict with agent 2026-05-27 20:57:32 +08:00
startup.py
state_sync.py fix: use Optional[T] for default None parameters in state_sync.py 2026-06-01 17:20:17 +00:00
streaming.py fix: keep settled stream message counts consistent 2026-06-14 20:33:56 +00:00
system_health.py
terminal.py Release v0.51.304 — Release JT (stage-p2a — un-held terminal reaper + opt-in Docker GPU) (#3757) 2026-06-06 18:04:16 -07:00
todo_state.py Release v0.51.261 — Release IC (stage-r11) (#3616) 2026-06-04 16:46:20 -07:00
turn_journal.py Release v0.51.326 — Release KP (#3618 + #3802 + #3762 + #3810) (#3816) 2026-06-07 23:18:51 -07:00
updates.py fix(#4085): surface dirty install state in update-check payload 2026-06-13 06:05:06 +00:00
upload.py Release v0.51.326 — Release KP (#3618 + #3802 + #3762 + #3810) (#3816) 2026-06-07 23:18:51 -07:00
usage.py fix: display canonical cache hit percentage 2026-05-19 02:27:12 -06:00
webui_session_db.py Release v0.51.305 — Release JU (stage-p2b — dormant unified-SessionDB adapter) (#3759) 2026-06-06 18:16:07 -07:00
workspace.py Release v0.51.296 — stage-3731 (remote-workspace blocked-root security fix #3731) (#3744) 2026-06-06 13:49:59 -07:00
workspace_git.py Release v0.51.311 — Release KA (brick-wave: workspace Git RCE hardening #3769 + stale-snapshot sidebar visibility #3770) (#3776) 2026-06-07 08:05:30 -07:00
worktrees.py Harden worktree removal safeguards 2026-05-13 09:49:15 +08:00