HERMES-GIELIE/docs
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
..
architecture Release: Live Stream Anchor side-effects projection (#6204, @franksong2702) (#6348) 2026-07-20 04:56:51 +00:00
images feat(ui): show read ranges in collapsed tool labels 2026-07-15 20:37:02 +00:00
pr-assets
pr-media Release v0.51.238 — Release HF (stage-q9) (#3493) 2026-06-03 12:23:46 -07:00
rfcs docs(rfc): reconcile Live-to-Final assistant-reply contracts with shipped behavior (#6144) (#6147) 2026-07-16 08:19:43 -07:00
ui-ux docs: add desktop icon decision preview images 2026-06-28 08:04:53 +00:00
advanced-chat-setup.md docs(#5269): document gateway approval runs API opt-in 2026-07-04 13:37:39 -04:00
CONTRACTS.md docs(rfc): reconcile Live-to-Final assistant-reply contracts with shipped behavior (#6144) (#6147) 2026-07-16 08:19:43 -07:00
docker.md Release: terminal-error settlement timing/seal (#6323) + Docker experimental builds (#6329) (#6341) 2026-07-19 22:17:36 +00:00
EXTENSIONS.md feat(extensions): token-v1 proxy→sidecar authentication boundary (#6331) 2026-07-20 17:49:23 +00:00
GUIDELINES.md docs: fold in Rod's PR-review feedback into GUIDELINES + CONTRIBUTING (#6211) 2026-07-17 20:40:55 -07:00
ISSUES.md
onboarding-agent-checklist.md
onboarding.md docs(#2781): document proxy auth PWA update caveat 2026-07-06 04:41:45 -04:00
remote-access.md docs(readme): re-sequence IA — pull Features up, consolidate access, extract niche docs 2026-06-01 02:26:18 +00:00
supervisor.md fix: block duplicate webui start when launchd owns 8787 2026-05-31 23:02:23 +00:00
troubleshooting.md fix: reject stale runtime before chat mutation 2026-07-16 22:28:35 +08:00
UIUX-GUIDE.md [HELD — independent review pending] Release v0.51.294 — stage-3401 (live-to-final redesign #3401 + 4 deep-review fixes) (#3741) 2026-06-06 12:12:37 -07:00
why-hermes.md docs: move Hermes overview out of agent context root 2026-05-19 23:55:58 -07:00
workspace-git.md 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
wsl-autostart.md