Files
hermes-webui/tests/test_issue1909_csp_report_only.py
T
nesquena-hermes 96ca83bf53 fix(security): drop unsafe-eval + add jsdelivr to CSP, sanitize plugin error
Opus stage-339 review SHOULD-FIX items:

1. server.py: drop 'unsafe-eval' from CSP report-only policy.
   Verified by grepping all production JS — zero matches for eval(),
   new Function(), or string-form setTimeout/setInterval. Keeping it
   was a gratuitous privilege.

2. server.py: add https://cdn.jsdelivr.net to script-src + style-src.
   index.html loads Prism/xterm/katex from this CDN with SRI hashes —
   without the allowance every page load fires known-good CSP violations
   that drown out real signal once a collector is wired.

3. api/commands.py: sanitize plugin command error. Previously returned
   f'Plugin command error: {exc}' which would leak paths/env from
   FileNotFoundError('/etc/something/secret.key') etc. Now returns only
   the exception type name; full traceback goes to server log.

Test asserts updated to match the new policy shape.

Co-authored-by: Opus advisor <opus-advisor@hermes.local>
2026-05-11 17:53:02 +00:00

36 lines
1.4 KiB
Python

"""Regression tests for #1909 CSP report-only security header."""
from http.server import BaseHTTPRequestHandler
from server import Handler
def test_handler_adds_content_security_policy_report_only(monkeypatch):
sent_headers = []
handler = Handler.__new__(Handler)
handler.send_header = lambda key, value: sent_headers.append((key, value))
monkeypatch.setattr(BaseHTTPRequestHandler, "end_headers", lambda self: None)
Handler.end_headers(handler)
headers = dict(sent_headers)
assert "Content-Security-Policy-Report-Only" in headers
assert "Content-Security-Policy" not in headers
policy = headers["Content-Security-Policy-Report-Only"]
assert "default-src 'self'" in policy
assert "object-src 'none'" in policy
assert "frame-ancestors 'self'" in policy
assert "base-uri 'self'" in policy
def test_csp_report_only_keeps_legacy_inline_allowances_for_current_ui():
policy = Handler.csp_report_only_policy()
assert "script-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net" in policy
assert "style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net" in policy
# unsafe-eval was dropped after Opus stage-339 verification — no production
# JS uses eval(), new Function(), or string-form setTimeout/setInterval.
assert "'unsafe-eval'" not in policy
assert "img-src 'self' data: blob:" in policy
assert "connect-src 'self'" in policy