feat: surface loopback sidecar diagnostics#4612
Conversation
|
| Filename | Overview |
|---|---|
| api/extensions.py | Adds loopback sidecar parsing with two thorough sanitizers (origin and health path), warning-code-only rejection, and the sidecar list threaded through the existing diagnostics tuple. Early-break removal is intentional and bounded by the 64 KB manifest cap. |
| static/panels.js | Adds sidecar card rendering and browser-side health monitor; seq is captured at increment time in loadExtensionsPanel and threaded explicitly through _renderExtensionsPanel/_monitorExtensionSidecars/_checkExtensionSidecarHealth, with stale-check guards at the render boundary and post-fetch — the concern from the prior review is addressed. |
| static/style.css | Adds scoped sidecar list/row/badge CSS; responsive overrides included; no existing rules overridden. |
| tests/test_extension_status_endpoint.py | Adds 8 focused tests covering accepted sidecars (127.0.0.1, localhost, [::1]), disabled entry skipping, non-loopback rejection without raw value leakage, invalid health path rejection, unsupported type rejection, and truncation; existing tests updated for new tuple unpacking. |
| tests/test_extensions_settings_panel.py | Adds panel shape assertions (sidecar card, esc() usage, fetch options, seq threading, no response body reading) plus docs content assertions; good static verification of security-sensitive rendering patterns. |
| docs/EXTENSIONS.md | Documents sidecar declaration shape, sanitization rules, no-proxy/no-cookie boundary, and updated diagnostics field descriptions; multi-line bash example collapsed to single line (cosmetic). |
Reviews (4): Last reviewed commit: "feat: surface loopback sidecar diagnosti..." | Re-trigger Greptile
🎬 Cutter preview — PR #4612
|
b06cf40 to
16b7bc4
Compare
|
Rebased onto current New head: Verification after rebase:
Greptile's previous P2 seq-race finding was addressed before this rebase: the sidecar monitor seq is captured at |
16b7bc4 to
7080929
Compare
|
Heads-up @franksong2702 — this PR adds the loopback "sidecar" diagnostics surface to Settings → Extensions (manifest extensions declaring a |
The CSP-loopback-alignment fix added http(s)://[::1]:* to connect-src, but CSP host-source grammar can't express a port wildcard on a bracketed IPv6 literal — Chromium rejects '[::1]:*' as an invalid source, which browser-smoke flags as a console error (CI fail). Keep the valid https://127.0.0.1:*/localhost:* additions; drop the IPv6 wildcard entries. IPv6 [::1] sidecars are still accepted by the validator (displayed in the card); their browser health probe surfaces as 'blocked' under CSP unless an operator adds a specific-port [::1]:<port> via HERMES_WEBUI_CSP_CONNECT_EXTRA. Tests updated to match + assert [::1]:* absent.
|
Shipped in v0.51.564 🚀 — thank you @santastabber. The loopback sidecar diagnostics surface landed. Review applied three hardening fixes during the gate:
Review trail: Codex regression gate SAFE TO SHIP (after fixes), Opus advisor SAFE — ship (allowlist validation, rebuild-not-echo, no server SSRF, uniform escaping), full suite 9987 passed, browser-smoke green. Regression tests added for all three findings. |
…quena#4632) * stage nesquena#4612 (santastabber): surface loopback sidecar diagnostics + CHANGELOG Settings -> Extensions surfaces manifest-declared loopback sidecar companion services (type:loopback, http(s) on 127.0.0.1/localhost/::1 only, sanitized origin+health_path) as read-only health cards w/ a browser-side credentials-omitted health probe. Backend hard-whitelists scheme + loopback host, rejects userinfo/path/query/traversal, rebuilds output from parsed components (no echo of rejected input); frontend esc()'s every field, whitelists badge status, fetch never reads body. Purely additive to GET /api/extensions/status. Code applied byte-faithful from PR head 7080929. 33 own tests pass. Nathan concept-approved (loopback-companion direction). Co-authored-by: santastabber <santastabber@users.noreply.github.com> * fix nesquena#4612 Codex gate findings: reject encoded query/fragment in health_path + align CSP loopback allowlist Codex SHIP-WITH-FIXES (2 reproduced SILENT findings): 1. _normalize_sidecar_health_path percent-decoded AFTER the raw query/fragment ban, so /health%3Ftoken=abc -> ?token=abc survived into the probed URL. Now re-rejects decoded ? and # + regression test (%3F/%23 skipped with sidecar_health_path_rejected). 2. The origin validator accepts https:// and [::1], but CSP connect-src only listed http 127.0.0.1/localhost -> accepted https/IPv6 loopback sidecars would be CSP-blocked. Aligned _CSP_CONNECT_BASE (added https v4/localhost + http(s) [::1]) + updated the 4 exact-string CSP tests + a regression test asserting all loopback forms are allowed. Co-authored-by: santastabber <santastabber@users.noreply.github.com> * Release v0.51.564 — Release TW (loopback sidecar diagnostics; nesquena#4612) * fix(nesquena#4612): drop browser-invalid [::1]:* CSP source (browser-smoke fail) The CSP-loopback-alignment fix added http(s)://[::1]:* to connect-src, but CSP host-source grammar can't express a port wildcard on a bracketed IPv6 literal — Chromium rejects '[::1]:*' as an invalid source, which browser-smoke flags as a console error (CI fail). Keep the valid https://127.0.0.1:*/localhost:* additions; drop the IPv6 wildcard entries. IPv6 [::1] sidecars are still accepted by the validator (displayed in the card); their browser health probe surfaces as 'blocked' under CSP unless an operator adds a specific-port [::1]:<port> via HERMES_WEBUI_CSP_CONNECT_EXTRA. Tests updated to match + assert [::1]:* absent. --------- Co-authored-by: nesquena-hermes <agent@nesquena-hermes> Co-authored-by: santastabber <santastabber@users.noreply.github.com>

Thinking Path
What Changed
sidecardeclarations from enabled manifest extension entries:type: "loopback";http(s)origins on127.0.0.1,localhost, or[::1];health_pathto/healthand rejects unsafe explicit health paths.GET /api/extensions/status:sidecars[]withid,name,type,origin,health_path, andhealth_url;counts.sidecarsandmanifest.sidecar_count;fetch(health_url, { credentials: 'omit', cache: 'no-store' })and a short timeout.Why It Matters
Operators can now see whether sidecar-class extensions such as Desktop Companion declared a local companion service correctly and whether the local health endpoint is reachable, without WebUI becoming a sidecar proxy or forwarding authenticated WebUI cookies to local helper processes.
Verification
./scripts/test.sh tests/test_extension_status_endpoint.py tests/test_extensions_settings_panel.py -q33 passedpython3 -m py_compile api/extensions.py tests/test_extension_status_endpoint.py tests/test_extensions_settings_panel.pynode --check static/panels.jsgit diff --check origin/master...HEAD/healthreturned200;/api/extensions/statusreturned the accepted Desktop Companion sidecar with the expected health URL;sidecar_origin_rejected/manifest:sidecarsand no raw host/port/path leakage;healthy;Risks / Follow-ups
Contract Routing
Task type: extension diagnostics / trusted loopback sidecar visibility.
Touched areas:
Relevant public docs:
AGENTS.mdCONTRIBUTING.mddocs/CONTRACTS.mddocs/EXTENSIONS.mdScope boundaries:
Evidence needed before claiming done: