Files
codex-app-server/cloud/skills/browser-automation/SKILL.md
T
host 125b436ab3 browser: click-path allowlist, safe tenant script upgrade, allowlist activation plan
- click/click_ref: pre-click allowlist gate on resolvable anchor href
  (same check as navigate; miss refuses before the click executes);
  click/click_ref/click_at: post-click landing URL check.
  click_at has no pre-click gate by design (coordinates name no
  element); JS-driven navigation, evaluate, meta refresh and popups
  are documented as unintercepable with the Tinyproxy 403 backstop.
- Tenant script upgrade is now safe: only proven-unmodified scripts
  (manifest match, 2a569ac known-shipped SHA-256, missing, or
  current) auto-merge; tenant-modified scripts are never overwritten,
  are reported as skipped, and get one deduped audit record. The
  manifest never learns a tenant hash (else the next upgrade would
  mistake a modified file for untouched). Idempotent reruns.
- Activation candidate = deployed Tinyproxy programming set encoded
  with leading-dot entries (plain entries would regress
  docs.python.org); npmjs.org per the deployed filter, not npmjs.com.
  Host activation itself is NOT performed this round: only the plan,
  validation tests and rollback are delivered.
Tests: 28 new (click 13, upgrade 8, activation 7), all fake/no-network;
98 browser-related tests pass including prior suites.

(cherry picked from commit e4a93f5748ec815f163d0bc096ff4dc4b8c651f5)
2026-11-01 09:06:28 +00:00

125 lines
6.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: browser-automation
description: >
Use when a task needs a real browser: pages that render with
JavaScript, clicking through pagination or forms, filling and
submitting input, or taking a screenshot of what a page
actually looks like. For a plain static page or a quick fact,
use web_fetch / web_search first; open the browser only when
static fetch cannot see the content.
---
## 工具
`browser_navigate`(打开 URL,返回最终 URL 与标题)、
`browser_snapshot`(当前页标题、URL、正文,超 8000 字截断并标记)、
`browser_click`(按 CSS 选择器或 `text=...` 点击)、
`browser_fill`(按选择器填表)、
`browser_evaluate`(在页内跑 JS 表达式,返回字符串,限 4000 字)、
`browser_screenshot`(把当前页存成工作区内的 PNG,返回绝对路径与字节数)、
`browser_click_at`(按视口坐标点击,坐标系为 1280x800、原点左上角,
是 live 视图里用户点击的落点)、
`browser_live_shot`(把当前画面存成固定文件 browser-live.png,
附带 browser-live.json 状态:URL、标题、时间戳,供 watcher 轮询)、
`browser_close`(关闭浏览器,可重复调用)。
浏览器是单页的:一次 navigate,之后 snapshot / click / fill /
screenshot 都针对同一页;要换页再 navigate。
## live 视图(第一期)
有人在看浏览器时,每次 navigate / click / fill / click_at 之后
都要调一次 `browser_live_shot`,让 browser-live.png 保持最新;
不要只在最后截图一次。用户在 live 图上点的坐标会以 x/y 到达
`browser_click_at`,点完必须再 snapshot 一次确认变化,再调
`browser_live_shot` 刷新画面。
## 远控接管(第二期)
用户可以在控制台接管浏览器:接管期间(holder=user)你的
所有 browser_* 工具都会直接报错“user holds browser control”,
不要重试、不要 close 浏览器,停下来等用户交还;交还后
(holder 回到 agent)下一条继续消息会让你续跑,续跑前先
snapshot 一次看清用户改动到哪了。
新工具:`browser_snapshot_refs`(带 ref 的元素清单,点
`browser_click_ref` 比 CSS 选择器稳,页面重渲染后先重新
snapshot_refs 再点);`browser_mouse_move` / `browser_key_press` /
`browser_type_text`(键盘与鼠标,远控输入与 agent 工具同源)。
## 规则
1. 先 navigate,再 snapshot 看实际渲染结果;click / fill 后
必须再 snapshot 一次确认变化,不要凭猜测汇报。
2. 截图产出后用 shell / PIL 重新打开验证(格式、尺寸、非 0
字节)再交给用户;失败时贴出工具报错,不要换一张别的图顶替。
3. 网络走 egress 代理:不在 Tinyproxy 白名单里的域名会报
代理 403,这时如实说明,不要绕过白名单。
4. file:// URL 可用于打开工作区内已写好的测试页(验证 JS
执行、表单行为),是比外网更可靠的自测手段。
5. 不要用浏览器做静态抓取能做的事;不要用 evaluate 绕过
click / fill 的正常路径去改页面状态,除非 snapshot 已证明
正常路径走不通。
## 多页与域名白名单(本期新增)
多页工具:`browser_new_page`(开新页并切到它,每次
new_page 都是全新 Playwright context,cookie 与存储天然
隔离,适合同时登录两个账号或对照两个页面)、
`browser_list_pages`(列出全部页:index、URL、标题、
哪一页是当前页;浏览器未启动时不启动,只返回空列表)、
`browser_switch_page`(按 index 切到指定页,之后
navigate / snapshot / click / fill / screenshot 都针对该页;
切到不存在的 index 会明确报错,不会崩掉 MCP,当前页不变;
切换后旧页的 snapshot_refs 全部失效,要重新 snapshot_refs)、
`browser_close_page`(关一页,缺省关当前页;关当前页后
自动切到上一页;关最后一页会明确报错,改用
`browser_close` 关整个浏览器)。
域名白名单:环境变量 `BROWSER_ALLOWED_HOSTS`(逗号列表,
如 `example.com,.python.org`)。未设置时行为完全不变,
只靠 egress 代理白名单;设置后 navigate 在启动浏览器之前
就检查:`file://` 一律放行,`http(s)` 的 host 必须命中列表
(前导点条目做后缀匹配:`.python.org` 同时放行
`python.org` 与 `docs.python.org`,不放行
`notpython.org`;注意:不带前导点的 `python.org` 只精确
匹配自身,不放行 `docs.python.org`),大小写与端口不影响
匹配,未命中直接报错且不启动 Chromium。`localhost` /
`127.0.0.1` 没有特殊待遇:本地开发服务器要自己把它列进
变量,否则会被挡。
页内点击白名单(本轮补齐,与 navigate 同款检查):
`browser_click` / `browser_click_ref` 点到带 href 的链接时,
先解析 href(相对链接按当前页 URL 展开)再检查:未命中
直接报错、点击根本不执行;点到没有 href 的目标(按钮、
JS 处理函数)时事前无从得知目的地,只能在点击后检查落点
URL、命中 blocked host 时报错(此时点击已发生,只是事后
发现,不是事前拦截)。`browser_click_at` 是坐标点击,坐标
本身对应不了任何元素,所以没有事前检查,只有事后落点检查。
真正拦不住的路径(不要假装已拦):页内 JS 自行跳转
(`location.href`、表单提交、SPA 路由、回车提交)、
`browser_evaluate` 里跑的任意 JS、meta refresh、弹窗新页。
这些路径没有“点击前已知目的地”可供检查,只能靠 egress
代理 403 兜底——白名单与代理白名单取同一域名集合时,被挡
域名在代理层就加载失败,不会真的打开目标页;但 evaluate
与 shell 同权,白名单从来不是它的沙箱边界,不要把它当
成防绕过手段。
老租户脚本升级(本轮改动):播种器只对已证明未改动的
租户脚本自动合并新版(播种 manifest 命中,或命中
2a569ac 已发布版本的哈希,或文件缺失/已是最新);租户
改过的脚本绝不覆盖,原样不动、记一条审计
(租户 codex-home 里的 `playwright_scripts_audit.jsonl`),
留待人工处理——下次任务播种时它仍会被跳过,不会悄悄
被新版盖掉。
清理:`browser_close` 会关掉全部页,并尽力删除工作区里的
`browser-live.png` 与 `browser-live.json`(删不掉也不报错),
所以 close 之后不要再拿旧 live 文件当“当前画面”汇报;
单个截图(`browser_screenshot` 的 `shot-*.png`)不受影响。
不在本轨范围:下载没有落盘清单(下载仍只落工作区文件,
无统一清单可查);没有持久 profile(每次 MCP 进程结束
cookie 即丢);没有登录保险库(账号密码仍不进浏览器工具)。
需要这些时不要假装已有,先如实说明缺口。