Files
skills/tests/test_hub_page.py
T
Kevin Veen-BirkenbachandClaude Opus 5.5 8ba45efd04 feat(hub): kvb-hub review hub with passkey-signed approvals
The kvb-hub is a local review hub in a container bound to 127.0.0.1: one page, JSON APIs and an MCP endpoint for the operator's inbox, asks, decisions, staged-commit reviews, the radio stream, the agent graph, the worktree tree, push-to-talk and read-aloud radio (Piper, whisper.cpp) and an optional LLM command line. The hub is only a relay. The host executors in hub/client (the runner user service, the PermissionRequest hook and the approval CLI the commit skills call) verify a WebAuthn passkey signature against keys pinned outside every sandbox, refuse replays and fail closed. scripts/hub.sh with make hub-install, hub-check, hub-pin, hub-runner and hub-hook installs and checks the hub; hub-hook writes ~/.claude/settings.json after a backup. make watch-check shows a stuck watch hook. The new kvb-git-diff skill and the commit skills route reviews through the hub; the test_hub_* suites replace test_hub.py.

Security review (kvb-think-criticize, three skeptics) fixed four holes: signed rules auto-approved chained shell commands; the client and LLM openers followed redirects, the LLM one with its bearer key; the worktree scan ran git fsmonitor and filter commands from agent-writable repos; compose set no memory, pids or health limits. Documented until core requirement 093, on the operator's word: the hub page is trusted while signing and pinning, local processes can forge the unsigned operator actions, and the container reads the host /tmp. Committed on the operator's word despite the gate: the passkey path is not yet verified live.

Accepted MEDUSA false positives (137 findings on 115 lines, rows in security-accepted.jsonl): EXA002 x17, MEDUSA-MM-SCAN-058 x12, B603 x8, MEDUSA-FTSC-SCAN-089 x7, MEDUSA-PRIV-SCAN-762 x6, AIC-EXFIL-005 x5, EXA006 x5, MEDUSA-FTSCAN-231 x5, WEB-SSRF x5, MEDUSA-INF-SCAN-2057 x3, RH005 x3, TC001 x3, LO002 x2, MEDUSA-AEXP-SCAN-096 x2, MEDUSA-CGS-SCAN-028 x2, MEDUSA-INF-SCAN-1350 x2, MEDUSA-INF-SCAN-2369 x2, MEDUSA-INF-SCAN-2440 x2, MEDUSA-INF-SCAN-2638 x2, MLSC-SERIAL-002 x2, PL002 x2, PQC005 x2, SAST-PATH-001 x2, TC004 x2, TC005 x2, TC006 x2, TC007 x2, AA-146, EXA007, FINE-050, GB-ENCODE-001, GB-ENCODE-003, MEDUSA-CGS-SCAN-029, MEDUSA-CGS-SCAN-103, MEDUSA-DP-SCAN-1034, MEDUSA-DP-SCAN-1916, MEDUSA-DP-SCAN-954, MEDUSA-EXF26-TOOL-004, MEDUSA-FT-TRIGGER-005, MEDUSA-INF-SCAN-2206, MEDUSA-INF-SCAN-2457, MEDUSA-INF-WEB-003, MEDUSA-INFRA-SCAN-030, MEDUSA-MP-SCAN-1135, MEDUSA-RLHF-POISON-002, MEDUSA-RT-SCAN-006, MM-ENCODE-001, MP-124, PQC001, PQC002, PQC006, RP001, TC009, TC010, WEB-FLASK-004.

🎯 Fix: 80 %
💥 Break: 4 %
💸 Cost: 129 %
⏱️ Time: –
🛡️ Security: 100 %
💰 Value: ?
🏆 Score: 60
🚦 Gate: ⛔ fix 80 % < 90; cost 129 % > 100: ask the operator before the commit

```
/home/kevinveenbirkenbach/Repositories/github.com/kevinveenbirkenbach/skills/.worktrees/feature/kvb-hub
```

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 18:46:40 +00:00

74 lines
3.8 KiB
Python

from __future__ import annotations
import json
import re
import subprocess
import time
import unittest
from hub_case import HubCase
from hub_support import AMBIENCE, SPACE, VOICE
from kvb_hub import exchange
class TestHubPage(HubCase):
def test_review_page_is_sandboxed_and_the_index_allows_only_its_own_inline_code(self):
review_id = self.request("feat: csp", "")
status, headers, _ = self.get(f"/reviews/{review_id}/page")
self.assertEqual(status, 200)
self.assertEqual(headers["content-security-policy"], "sandbox allow-scripts")
self.assertEqual(headers["x-content-type-options"], "nosniff")
status, headers, body = self.get("/")
csp = headers["content-security-policy"]
nonce = re.search(r"script-src 'nonce-([^']+)'", csp).group(1)
self.assertIn(f"style-src 'nonce-{nonce}'", csp)
self.assertNotIn("unsafe", csp)
self.assertIn("default-src 'none'", csp)
html = body.decode("utf-8")
tags = re.findall(r"<(script|style)\b([^>]*)>", html)
self.assertEqual(sorted({tag for tag, _ in tags}), ["script", "style"])
self.assertGreaterEqual(len(tags), 3)
for tag, attributes in tags:
with self.subTest(tag=tag, attributes=attributes):
self.assertIn(f'nonce="{nonce}"', attributes)
self.assertNotIn(nonce, self.get("/")[1]["content-security-policy"])
status, headers, _ = self.get(f"/reviews/{review_id}/files")
self.assertEqual((status, headers["content-type"]), (200, "application/json"))
self.assertEqual(headers["content-security-policy"], exchange.PLAIN_CSP)
def test_markup_from_agents_is_escaped(self):
self.request("<script>alert(1)</script>", "</pre><script>alert(2)</script>")
register = {"work/x": {"title": "<script>alert(3)</script>", "status": "running", "roles": {"<b>One</b>": "RA"}}}
news = {"ts": time.time(), "from": "<img src=x>", "to": [], "text": "<script>alert(4)</script>"}
self.write_council({"rasci.json": register, "news.jsonl": self.jsonl([news])})
html = self.index()
for n in range(1, 5):
with self.subTest(n=n):
self.assertNotIn(f"<script>alert({n})", html)
self.assertNotIn("<img src=x>", html)
self.assertNotIn("<b>One</b>", html)
embedded = re.search(r'<script nonce="[^"]+" id="state" type="application/json">(.*?)</script>', html, re.DOTALL).group(1)
state = json.loads(embedded)
self.assertEqual((state["reviews"][0]["title"], state["reviews"][0]["notes"]), ("<script>alert(1)</script>", "</pre><script>alert(2)</script>"))
self.assertEqual((state["register"][0]["title"], state["radio"][0]["from"]), ("<script>alert(3)</script>", "<img src=x>"))
def test_the_index_scripts_parse_and_embed_the_ambience_voice_and_space_modules(self):
html = self.index()
for module in (AMBIENCE, VOICE, SPACE):
with self.subTest(module=module.name):
self.assertIn(module.read_text(encoding="utf-8").strip(), html)
scripts = re.findall(r'<script nonce="[^"]+">(.*?)</script>', html, re.DOTALL)
self.assertEqual(len(scripts), 4)
page = self.state / "page.js"
page.write_text("\n;\n".join(scripts), encoding="utf-8")
done = subprocess.run(["node", "--check", str(page)], capture_output=True, text=True, timeout=60, check=False)
self.assertEqual(done.returncode, 0, done.stderr)
for module in (AMBIENCE, VOICE, SPACE):
with self.subTest(module=module.name):
done = subprocess.run(["node", "--check", str(module)], capture_output=True, text=True, timeout=60, check=False)
self.assertEqual(done.returncode, 0, done.stderr)
if __name__ == "__main__":
unittest.main()