fix(chv-muse-round12): 移植 round-11 的 Page.aria_snapshot() 纠正到 CDP broker

Playwright 1.64.1 没有 page.accessibility(Puppeteer 的 API),
broker 的 snapshot 调它必走异常分支。改调 Page.aria_snapshot()
(字符串);guard 的 truncate_a11y 换成字符串版 truncate_aria
(179a86d 原样),detect_injection/detect_form_risk 加字符串
分支(dict 分支保留);两边 fake 与 P4 文档同步改。a11y-only
契约不变:不读原始 DOM、不走 JS eval。

测试:test_chv_muse_p2 + test_chv_muse_p4 114 OK;全量 2523 OK
(skipped=10)。
This commit is contained in:
host committed 2026-11-07 18:24:58 +00:00
1 parent 9da74c2a78
commit 114b444554
6 files changed
+209 -129

No files matched your search

+10 -10
View File
@@ -6,9 +6,9 @@ chv-browser.py(c61484a),P4 在此基础上重构——子代理不再直
Playwright/Chromium,Chromium 的所有权在单元外 CDP broker
(chv-cdp-broker.py)手里;本进程只是 broker 的客户端。
子代理只向单元返回页面无障碍树快照(Playwright
accessibility.snapshot,经 broker 取回),不见原始 DOM,不能
在页面上下文跑 JS,不暴露交互操作,不开 DevTools。
子代理只向单元返回页面无障碍快照(Playwright
Page.aria_snapshot() 的 ARIA 快照字符串,经 broker 取回),不见
原始 DOM,不能在页面上下文跑 JS,不暴露交互操作,不开 DevTools。
操作(Unix socket /run/chv-browser/browser.sock,JSON 行):
open {url} -> 经 broker 导航并返回 {title, url, a11y,
@@ -29,7 +29,7 @@ accessibility.snapshot,经 broker 取回),不见原始 DOM,不能
URL 校验、快照截断、错误消毒、禁用操作表都在
chv_browser_guard.py(纯函数模块,两脚本共用)。本层再做一次
validate_url 与 truncate_a11y(纵深防御),回包先过泄露检查。
validate_url 与 truncate_aria(纵深防御),回包先过泄露检查。
只用标准库。运行身份:系统用户 chv-browser,socket 0600
(broker 以 root 连,不受模式限制)。
@@ -129,10 +129,10 @@ class BrowserAgent:
if not ok:
return {"ok": False, "error": err}
resp = self._call({"op": "open", "url": url})
if resp.get("ok") and isinstance(resp.get("a11y"), dict):
tree, truncated = self._guard.truncate_a11y(resp["a11y"])
if resp.get("ok") and isinstance(resp.get("a11y"), str):
aria, truncated = self._guard.truncate_aria(resp["a11y"])
resp = dict(resp)
resp["a11y"] = tree
resp["a11y"] = aria
resp["truncated"] = bool(resp.get("truncated")
or truncated)
return self._sync_paused(resp)
@@ -141,10 +141,10 @@ class BrowserAgent:
if self._paused:
return self._blocked_while_paused()
resp = self._call({"op": "snapshot"})
if resp.get("ok") and isinstance(resp.get("a11y"), dict):
tree, truncated = self._guard.truncate_a11y(resp["a11y"])
if resp.get("ok") and isinstance(resp.get("a11y"), str):
aria, truncated = self._guard.truncate_aria(resp["a11y"])
resp = dict(resp)
resp["a11y"] = tree
resp["a11y"] = aria
resp["truncated"] = bool(resp.get("truncated")
or truncated)
return self._sync_paused(resp)