HERMES-GIELIE/static
nesquena-hermes c414c39f10
feat(extensions): token-v1 proxy→sidecar authentication boundary (#6331)
* feat(extensions): token-v1 proxy->sidecar auth boundary

Mint a per-extension secret core injects (X-Hermes-Sidecar-Token) on every
proxied request; sidecars validate it. Closes the hole where a loopback sidecar
port is reachable by any local process and cannot distinguish a proxied request
from a direct one.

- api/extension_sidecar_auth.py: per-extension token lifecycle (atomic mint,
  re-read-verified so an unpersisted token is never injected, per-request
  mtime-cached read for live rotation, path-escape-safe)
- manifest proxy_auth negotiation: absent=legacy, token-v1=enforce, unknown=fail-closed
- proxy: inject token, strip inbound + response x-hermes-*, auth-off posture
  (loopback-only local_unprotected, else 503), fail-closed when token unavailable
- consent-time auth_required in status payload; mint-on-consent
- docs/EXTENSIONS.md proxy_auth section
- 7 new tests (26/26 green)

* fix(extensions): address Codex+Fable gate on token-v1 (6 findings)

- align token-module extension-id grammar with core _EXTENSION_ID_RE (was
  narrower -> legally-named ext consented then 503'd forever)
- resolve token dir dynamically (mirror _extension_state_dir) -> real test
  isolation, no import-time STATE_DIR cache
- cross-process mint: O_CREAT|O_EXCL no-clobber claim (was os.replace clobber)
- rotation cache keyed on full fingerprint (ino/dev/mtime/ctime/size) +
  re-fingerprint after read -> same-size/mtime replacement no longer stale
- validate token format on read (url-safe, 16-256) -> malformed file can't
  leak via a ValueError echoed in a 502
- consent fails 503 when token can't be provisioned (was silent-swallow ->
  persisted consent then 503 forever)
- rename status auth_required -> posture enum (protected|local_unprotected):
  nothing is blocked for loopback, so 'required' was misleading
- panels.js: render local_unprotected warning on the consent row (+ CSS)
- docs: token-path resolution order, 401-vs-503, explicit 'legacy' acceptance
- tests: route-level token-injection+response-strip test; fix illusory isolation
  in token-module test; 27/27 green

* fix(extensions): close 2 token-mint races (Codex re-gate round 2)

- mint via temp-file + atomic os.replace (not O_CREAT|O_EXCL) so the final
  path is never observed empty/half-written — a concurrent loser can no longer
  read an empty token file and 503
- single _stable_read helper (fingerprint-read-refingerprint, bounded retry on
  mid-read change) used by BOTH ensure_token and current_token — a token that
  changes during the read is never returned or cached stale
- stress-verified: 20 concurrent first-mints converge on 1 persisted token; 27/27

* fix(extensions): atomic no-clobber token publish via os.link (Codex re-gate round 3)

os.replace fixed empty-file exposure but still clobbered cross-process: two
processes could both write+replace and a reader between them got a token no
longer on disk -> 401. Switch to the repo's TOCTOU-safe os.link create-or-fail
idiom (session_recovery.py:627): write temp -> link into place (fails if a
winner already published) -> loser drops its temp and reads the winner via
_stable_read. Proven: 16 concurrent PROCESSES converge on 1 persisted token,
all matching disk. 27/27 tests green.

* fix(extensions): resolve Frank+Greptile #6331 review — token-v1 fail-closed when auth off (consent+resolution), token-v1-only proxy_auth/posture status fields, fullmatch ext-id validator

* fix(extensions): finish Frank and Greptile sidecar review

---------

Co-authored-by: nesquena-hermes <nesquena-hermes@users.noreply.github.com>
Co-authored-by: nesquena-hermes <agent@nesquena-hermes>
2026-07-20 17:49:23 +00:00
..
vendor fix: protect pipes inside backtick code spans in renderMd tables 2026-06-25 08:25:58 +00:00
__init__.py Release: pip-installable packaging metadata (#6337, @rodboev) (#6344) 2026-07-20 02:17:52 +00:00
apple-touch-icon.png Swap brand to new cyan caduceus: favicon family, titlebar + empty-state logo (theme-safe navy badge), remove per-skin titlebar fill overrides 2026-06-28 07:44:16 +00:00
assistant_turn_anchors.js Release: Live Stream Anchor side-effects projection (#6204, @franksong2702) (#6348) 2026-07-20 04:56:51 +00:00
boot.js fix(#6099): make transparent stream activity timestamps optional (#6130) 2026-07-18 20:56:44 -07:00
commands.js fix(sessions): guard all auto-mint paths + strict config/body parsing (gate review) 2026-07-14 04:35:06 +00:00
extension_settings.js fix(extensions): prune malformed browser overrides (#5094) 2026-06-28 18:31:43 -04:00
favicon-32.png Swap brand to new cyan caduceus: favicon family, titlebar + empty-state logo (theme-safe navy badge), remove per-skin titlebar fill overrides 2026-06-28 07:44:16 +00:00
favicon-192.png Swap brand to new cyan caduceus: favicon family, titlebar + empty-state logo (theme-safe navy badge), remove per-skin titlebar fill overrides 2026-06-28 07:44:16 +00:00
favicon-512.png Swap brand to new cyan caduceus: favicon family, titlebar + empty-state logo (theme-safe navy badge), remove per-skin titlebar fill overrides 2026-06-28 07:44:16 +00:00
favicon-512.svg Swap brand to new cyan caduceus: favicon family, titlebar + empty-state logo (theme-safe navy badge), remove per-skin titlebar fill overrides 2026-06-28 07:44:16 +00:00
favicon.ico Swap brand to new cyan caduceus: favicon family, titlebar + empty-state logo (theme-safe navy badge), remove per-skin titlebar fill overrides 2026-06-28 07:44:16 +00:00
favicon.svg Swap brand to new cyan caduceus: favicon family, titlebar + empty-state logo (theme-safe navy badge), remove per-skin titlebar fill overrides 2026-06-28 07:44:16 +00:00
i18n.js fix(#6099): make transparent stream activity timestamps optional (#6130) 2026-07-18 20:56:44 -07:00
icons.js stage #4581 onto master (v0.51.556) — surface escape-target symlinks as display-only workspace rows 2026-06-21 09:15:22 +00:00
index.html fix(#6099): make transparent stream activity timestamps optional (#6130) 2026-07-18 20:56:44 -07:00
login.js Fix login connectivity retry cleanup: clearInterval not clearTimeout 2026-07-09 03:41:42 +00:00
manifest.json
messages.js Release: Live Stream Anchor side-effects projection (#6204, @franksong2702) (#6348) 2026-07-20 04:56:51 +00:00
onboarding.js fix(webui): give the onboarding password inputs a form owner too 2026-07-15 10:41:16 +02:00
outline.js Release: msg_limit ceiling + row-loss-safe pagination (#6152 + #6154, @rh-id) (#6213) 2026-07-17 20:15:40 -07:00
panels.js feat(extensions): token-v1 proxy→sidecar authentication boundary (#6331) 2026-07-20 17:49:23 +00:00
pwa-startup.js
sessions.js Release: Artifacts filename-first + session-own-streaming + reduced-motion msg-row (#6161, #6165, #6166, @webtecnica) (#6282) 2026-07-18 17:53:57 -07:00
share.html Rebase #5337 (public read-only conversation sharing) onto master 2026-07-11 01:39:42 +00:00
share.js Rebase #5337 (public read-only conversation sharing) onto master 2026-07-11 01:39:42 +00:00
style.css feat(extensions): token-v1 proxy→sidecar authentication boundary (#6331) 2026-07-20 17:49:23 +00:00
sw.js fix: focus the existing chat tab when a notification is clicked instead of opening a new tab 2026-06-13 14:42:41 -07:00
terminal.js Handle terminal output EventSource transport errors 2026-07-09 02:26:20 +00:00
ui.js fix(#6099): make transparent stream activity timestamps optional (#6130) 2026-07-18 20:56:44 -07:00
workspace.js Release: Artifacts filename-first + session-own-streaming + reduced-motion msg-row (#6161, #6165, #6166, @webtecnica) (#6282) 2026-07-18 17:53:57 -07:00