关于 ghost-inspector-mcp
ghost-inspector-mcp 为 AI Agent 提供 Ghost Inspector 端到端浏览器测试的检查、诊断和管理工具,适合需要分析复杂测试账户并谨慎修改测试的团队。它整合失败归因、过期与空洞测试识别,并通过明确授权和多重保护限制写入及运行。
主要功能
- 01浏览账户中的文件夹、套件和测试
- 02区分过期失败与实际故障
- 03检查模块依赖及影响范围
- 04识别未验证有效行为的测试
- 05提出修复方案并预览测试执行
- 06在授权保护下更新、移动和运行测试
适用场景
- 01排查失败测试及其失败步骤
- 02评估修改共享模块的影响范围
- 03找出通过但缺少断言的测试
- 04在应用修改前验证测试定义
MCP 相关
该 MCP 服务通过 Ghost Inspector API 向客户端提供读取、诊断、验证、写入和运行测试的工具。写入和运行分别需要启用环境变量;删除操作不提供。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
npx -y ghost-inspector-mcpGHOST_INSPECTOR_API_KEY密钥Your personal Ghost Inspector key, from Account Settings then API Access. Read fresh on every call, never written to disk, never echoed back.GHOST_INSPECTOR_ORG_IDOrganization id. Needed only to execute a validation; read it from gi_whoami.GHOST_INSPECTOR_ALLOW_WRITESSet to exactly true to let the five write tools act. They are listed either way; anything else keeps the server read-only.GHOST_INSPECTOR_ALLOW_RUNSSet to "true" to let gi_run_test execute a stored test against a real environment, which can submit a real form. Deliberately not implied by GHOST_INSPECTOR_ALLOW_WRITES: an edit can be rolled back from the backup this server returns, a submission cannot. Defaults to false.GHOST_INSPECTOR_BACKUP_DIRWhere the write path saves the prior definition of every test it touches, credentials removed. Defaults to ~/.ghost-inspector-mcp/backups, created owner-only.本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
工具
22收录的工具列表 · 更新于 2 周前
此工具无需参数。
详细介绍
ghost-inspector-mcp
一个用于 Ghost Inspector API 的 MCP 服务,让你可以使用已有的任意 Agent(Claude、OpenAI、OpenCode,或自己的自动化工具)处理端到端浏览器测试,而无需在网页界面中逐个点击。
状态
共 20 个工具。其中 14 个仅供读取,5 个用于写入,另有 1 个会实际运行测试。所有工具始终都会列出——受限工具在未启用相应选项时会拒绝调用,而不是隐藏起来,因此不必根据工具是否缺失来推断情况。
下表概述了功能范围。每个工具自身的描述才是 Agent 实际读取的内容,详细信息和注意事项都在那里。
了解账户
| 工具 | 访问权限 | 功能 |
|---|---|---|
gi_whoami | 读取 | 验证 API 密钥,列出可访问的组织及其 ID,并报告哪些权限开关已启用。出现配置错误时,或 Agent 告诉你此服务无法执行任何修改时,请从这里开始。 |
gi_inventory | 读取 | 以“文件夹 → 套件”树状结构展示整个账户,并列出每个套件中通过、失败、模块和未运行测试的数量,以及失败测试的 ID 和名称。可按文件夹筛选,或仅查看失败的套件。 |
gi_find_tests | 读取 | 按名称、文件夹、套件或测试步骤的内容(命令、任意备用选择器、值)查找测试,并返回其他工具所需的 ID。 |
gi_module_usage | 读取 | execute 步骤的反向索引:针对每个导入的测试,列出直接导入它的测试及其完整的传递影响范围,并附上 ID。还会找出无人导入的模块、缺少仅供导入标记的已导入测试、无效引用和循环引用。可按文件夹或套件筛选列表;影响范围仍覆盖整个账户。每个测试发起一次请求。 |
gi_get_test | 读取 | 获取单个测试已存储的定义、身份信息和状态,包括 gi_update_test 需要用作并发令牌的 dateUpdated。编写任何编辑内容前都应调用此工具。一次最多获取 20 个测试;expandModules 会逐步内联运行时执行的内容,并标明其所属测试。 |
查找问题
| 工具 | 访问权限 | 功能 |
|---|---|---|
gi_stale_tests | 读取 | 通过比较整个 execute 链的 dateUpdated 与每个测试的上次运行时间,将失败测试区分为过时测试和确实损坏的测试。还会找出结果早于变更的通过测试。可按文件夹或套件筛选。每个测试发起一次请求。 |
gi_vacuous_tests | 读取 | 找出无法证明任何内容的通过测试,分为三类:运行零个步骤;运行了步骤,但完全没有断言;或最终断言是唯一断言,且在测试开始操作前就可能已为真。可按文件夹或套件筛选。 |
gi_test_result | 读取 | 说明单个测试失败的原因:失败步骤、错误信息、编写测试时使用的选择器(而不只是最终匹配成功的选择器),以及该步骤实际归属的测试或模块——根据当前位置与当前定义对应,绝不猜测。首先给出是否过时的判定,因为早于变更的运行结果不能作为证据。返回此次运行的截图、视频、URL 和控制台信息。一次最多获取 20 个。 |
gi_test_history | 读取 | 按时间倒序列出测试的运行记录,最多 500 条:每次运行的判定和失败步骤、最近一次通过记录,以及当前连续失败期间的首次失败记录。说明可追溯到多早的记录。 |
gi_failure_groups | 读取 | 按失败开始时间对失败测试分组,涵盖多个套件和文件夹,并列出共同错误和目标——数小时内出现的多个失败通常有共同原因。 |
修复问题
| 工具 | 访问权限 | 功能 |
|---|---|---|
gi_propose_repair | 读取 | 将诊断结果转化为具体方案:改写后的步骤、负责该步骤的测试,以及用于写入的令牌。不应用任何更改;如果诊断已过期或无法定位步骤,则会拒绝。 |
gi_plan_test | 读取 | 准确展示 gi_validate_test 将发送的内容——内联模块、解析 {{variables}},并应用全部三层提交保护——以及是否会被拒绝。不启动浏览器,也不需要组织 ID。 |
gi_validate_test | 读取¹ | 通过按需执行来运行定义,执行后丢弃,并报告每个步骤。复现测试套件的配置和变量,并通过三层保护防止提交(参见安全模型)。 |
gi_screenshot_status | 读取 | 测试的截图比较结果:生效的设置(测试未设置时继承自测试套件)、与阈值相比的测量差异、用于比较的图像,以及下次运行将使用的基准图像——接受新图像后,两者会有所不同。一次最多支持 20 项。 |
gi_screenshot_diff | 读取 | 截图发生变化的位置:将结果的全尺寸图像与基准图像逐像素比较,并返回变化区域以及最大的变化区域裁剪图(全尺寸,基准图在上,当前图在下)。 |
gi_update_test | 写入 | 在四项保护和并发令牌的约束下,替换测试步骤、重命名测试或更改其起始 URL。先前的定义会保存到仅所有者可访问的文件中。 |
gi_move_suite | 写入 | 将测试套件及其测试移至另一个文件夹。可撤销;会返回原文件夹,因此只需一次调用即可撤销。 |
gi_move_test | 写入 | 将一个测试移至另一个测试套件——也可用来停用测试。可撤销;会说明目标测试套件是否按计划运行,因为测试移入后便会开始运行。 |
gi_create_suite | 写入 | 创建一个空测试套件,也可指定将其放入某个文件夹。除非明确要求,否则如果存在同名同级项目,就会拒绝创建。 |
gi_duplicate_test | 写入 | 一次调用即可复制测试、将其放入测试套件、重命名,并可选择重新指定其起始 URL。获取新测试的唯一方式——Ghost Inspector 没有创建端点,因此必须提供源测试。默认会清除副本的计划设置。 |
gi_accept_screenshot | 写入 | 将最新截图设为新基准图像——仅当它是你查看过的结果、仍是最新结果且已完成,并且比较结果为失败时才会执行。会返回被替换的基准图像,因为 API 无法恢复它。 |
gi_run_test | 运行 | 严格按已保存的内容执行测试,并等待结果。它有独立于写入操作的门控。除非在本次调用中确认,否则如果测试会提交表单,就会被拒绝。 |
¹ gi_validate_test 不会保存任何内容,但会通过真实浏览器访问真实 URL,因此不会标记为只读。
六种写入工具仅当 GHOST_INSPECTOR_ALLOW_WRITES 的值恰好为 true 时才会执行;gi_run_test 仅当 GHOST_INSPECTOR_ALLOW_RUNS 的值为 true 时才会执行。遭拒时不会更改任何内容,并会指出需要设置的变量。gi_whoami 会报告这两个门控状态。
特意不包含。 任何形式的删除。DELETE /suites/{id}/ 会级联删除测试套件中的所有测试,且无法撤销;这种影响范围不应交由 Agent 操作。出于同样的原因,也不包含删除测试的功能,因为没有版本历史可供恢复。
无法从零创建测试。 Ghost Inspector 未提供创建端点——POST /tests/ 返回测试列表,组织和文件夹范围内的对应端点则返回 404;供应商文档只介绍更新、复制和删除,没有创建功能。gi_duplicate_test 是受支持的方式:复制现有测试、将其放置到目标位置并重命名。它的名称如实描述了功能,因为称之为“创建”会让人误以为无需提供源测试。
追溯回归问题到上一次通过的运行记录,可以使用 gi_test_history。旧结果会被清除,因此每个回答都会说明查询范围:向前追溯了多远,以及这是否是 Ghost Inspector 保留记录的范围尽头,还是仅仅到达了请求的范围。
你可以询问什么
你是向 Agent 提问,而不是向工具提问。服务就是为回答以下问题而构建的:
- “我的失败测试中,哪些确实坏了,哪些只是自从有人编辑它们后就没再运行过?” ——这是仪表板无法区分的情况,也是排查会话通常从这里开始的原因。
- “结账测试为什么显示失败?” ——失败的步骤、错误,以及归属该问题的测试或模块。
- “如果我修改这个共享模块,会有什么东西出问题?” ——直接导入者和完整的传递影响范围,后者通常大得多。
- “我的哪些通过测试实际上什么都没测?” ——测试可能在毫无证明作用的情况下通过,有三种不同情况。
- “修复那个选择器。” ——提出更改,先运行但不保存以检查是否能解决问题,在保护措施下应用更改,然后运行测试以确认。每个步骤都是独立的工具;凡是会更改或执行任何内容的步骤,都需要你先明确同意。
关于规模的说明。 对于积累了不少杂乱问题的账户,这个服务才能发挥价值:数百个测试、归属不明确的共享模块,或几个月没人排查的失败列表。对于规模较小且维护良好的账户——几十个测试、没有模块、全部通过——gi_stale_tests、gi_module_usage 和 gi_vacuous_tests 会正确地不返回任何结果,这时服务看起来几乎无事可做。这对该账户来说是实事求是的结果,并非故障。
为什么要开发此项目
Ghost Inspector 的 API 小巧且稳定,因此,简单地进行 1:1 封装并不会比 curl 多带来任何价值。这个服务专为 curl 无法提供的三件事而打造:
- API 未提供的聚合数据——将账户整理成文件夹 → 套件树并给出准确计数、反向索引哪些测试导入了各模块,以及将失败测试区分为确实损坏与仅仅过时。
- 写入路径上的防护措施——测试步骤没有版本历史记录,也没有回收站。覆盖后便永远无法恢复。
- 教会调用模型如何避免造成破坏的工具描述——将积累的注意事项随工具一起提供,让每个 Agent 都能免费受益,而不必付出高昂代价后才学会。
社区中还有其他封装此 API 的项目。区别在于这里的原则:除非你主动选择,否则不会写入或执行任何内容;无论选择何种级别,都不会删除内容;而且每次写入都有无法关闭的防护措施。
下面用两个实际示例说明第三点,因为这正是整个项目的核心主张。
将测试标记为 Import Only——Ghost Inspector 用来表示“这是一个模块,其他测试会导入它的步骤”——会删除其已存储的结果。因此,每个模块都会永久处于“从未执行”状态:没有结果,passing 不是布尔值,最后运行日期固定为 1970-01-01 这个纪元哨兵值。检测过时测试的直观做法是按最后运行日期排序,这会把账户中的每个模块都报告为最废弃、最损坏的内容,并建议删除所有线上测试共用的步骤。此服务了解这一点,并提供了能避免这种情况的判断条件。
而一个步骤仅包含对无步骤模块的 execute 调用的测试,运行零个步骤并且通过,因为没有任何内容可能失败。仪表板会将它显示为绿色,尽管它什么也没验证;这比显示红色更糟,因为没人会去调查绿色状态。清空一个共享模块,就会悄无声息地同时影响所有导入它的测试。
这是测试空洞的三种方式中最轻微的一种。在一个有几百个测试的真实账户中,gi_vacuous_tests 发现数量最多的远不止这一类,而是运行了所有步骤但完全没有断言的测试——只有在某个步骤出错时它们才会失败。第三类测试只在最后一个步骤进行断言,而该断言在测试执行任何操作之前很可能就已成立。它们全都显示为绿色。
安装
需要 Node 18+。无需提前安装任何内容——你的 MCP 客户端会通过以下命令启动此服务:
npx -y ghost-inspector-mcp
这始终会运行最新版本。要固定使用某个版本——团队共享设置时应该这样做——请指定版本:npx -y [email protected]。
这两个安装选项都会提示输入你的密钥,并将其存储在 VS Code 自带的机密输入中,而不是设置文件里。
要开发此服务本身,请克隆并构建:
git clone https://github.com/charliemtnez/ghost-inspector-mcp.git
cd ghost-inspector-mcp
npm install && npm run build
配置
获取你的个人 API 密钥:Ghost Inspector → 将鼠标悬停在你的姓名上(右上角)→ Account Settings → API Access。密钥按用户分配,重新生成密钥会立即禁用旧密钥。
| 变量 | 必填 | 用途 |
|---|---|---|
GHOST_INSPECTOR_API_KEY | 是 | 你的个人密钥 |
GHOST_INSPECTOR_ORG_ID | 执行验证时需要 | 组织 ID — 从 gi_whoami 中读取。gi_plan_test 不需要此项 |
GHOST_INSPECTOR_ALLOW_WRITES | 否(默认 false) | 设为 true 后,六个写入工具即可执行操作。无论如何设置,这些工具都会列出 |
GHOST_INSPECTOR_ALLOW_RUNS | 否(默认 false) | 设为 true 后,gi_run_test 即可执行。不会因 ALLOW_WRITES 而自动启用 — 编辑可以通过此服务返回的备份回滚,而已提交的表单则无法回滚 |
GHOST_INSPECTOR_BACKUP_DIR | 否(默认 ~/.ghost-inspector-mcp/backups) | 写入操作路径用于保存其涉及的每个测试的原始定义的位置。在 macOS 和 Linux 上创建的目录仅所有者可访问;在 Windows 上则继承用户配置文件的权限 |
配置仅使用环境变量。我们有意不支持 .env:此工具作为全局命令发布,没有自己的项目目录,而存放密钥的地方多一个,泄露密钥的地方也就多一个。每次调用都会重新读取密钥,因此轮换密钥无需重启即可生效。
Claude Code
claude mcp add ghost-inspector --scope user -- npx -y ghost-inspector-mcp
在原生 Windows(非 WSL)上,npx 是一个 .cmd 脚本,而不通过 shell 启动程序的客户端无法运行它。通过 cmd 执行即可兼容两种环境:
claude mcp add ghost-inspector --scope user -- cmd /c npx -y ghost-inspector-mcp
Claude Desktop、Cursor、Windsurf 以及其他使用 JSON 配置的客户端
{
"mcpServers": {
"ghost-inspector": {
"command": "npx",
"args": ["-y", "ghost-inspector-mcp"]
}
}
}
在原生 Windows 上,如果服务无法启动(spawn npx ENOENT 或 EINVAL),请使用 "command": "cmd" 和 "args": ["/c", "npx", "-y", "ghost-inspector-mcp"]。
无需设置 env 块:服务会继承启动客户端的进程环境,因此只需在 shell 配置文件中导出密钥即可,无需将密钥存放在配置文件中。只有在客户端无法继承环境变量时才添加该配置。
其他 MCP 客户端
通过 stdio 将其指向 npx -y ghost-inspector-mcp,或者在克隆的代码库中将其指向 node <path>/dist/index.js,并通过环境变量传递密钥。
如果工具已显示,但每次调用都提示缺少密钥
你的客户端很可能是通过桌面图标、Spotlight 或启动器启动的,而不是从终端启动。这些方式不会运行登录 shell,因此不会读取 ~/.zprofile 和 ~/.bash_profile,你的 export 命令也就没有执行 — 服务可以正常启动并注册工具,但随后会发现环境中没有密钥。
你可以从终端启动客户端,也可以让服务在启动时自行读取密钥:
claude mcp add ghost-inspector --scope user -- \
sh -c 'GHOST_INSPECTOR_API_KEY="$(cat ~/.gi-key)" exec npx -y ghost-inspector-mcp'
在 JSON 配置中使用 "command": "sh" 和 "args": ["-c", "..."] 也可以采用同样的包装方式。密钥保存在权限为 600 的文件中,只有你自己的用户可以读取,并且不会进入客户端配置。
Windows 上不会出现此问题:设置用户环境变量后,所有后续启动的程序(包括桌面快捷方式启动的程序)都能获取该变量。需要注意的是,已经运行的客户端会保留旧的环境变量 — 请完全退出客户端(包括从系统托盘退出),然后重新启动。
处理 API 密钥
Ghost Inspector 通过查询字符串中的 ?apiKey= 进行身份验证,因此除非你谨慎处理,否则凭据会出现在 shell 历史记录、代理日志和 AI 对话记录中。
# In a terminal you will close afterwards — the value never enters the
# command, so it never enters your history.
umask 077
read -rs 'GI?Ghost Inspector API key: '; printf '%s' "$GI" > ~/.gi-key; unset GI
# Then, in your shell profile:
export GHOST_INSPECTOR_API_KEY="$(cat ~/.gi-key)"
使用 printf 而不是 echo 很重要:末尾的换行符会破坏查询参数中的密钥。
在 Windows 上,请在 PowerShell 中将其存储为用户环境变量:
# Read-Host hides what you type, and PowerShell's history records only this
# line, never the key itself.
$k = Read-Host 'Ghost Inspector API key' -AsSecureString
[Environment]::SetEnvironmentVariable('GHOST_INSPECTOR_API_KEY', [Net.NetworkCredential]::new('', $k).Password, 'User')
Remove-Variable k
它会保存在你的用户帐户注册表设置中(HKCU\Environment),你和这台机器的管理员都可以读取——这与保存在主目录中权限为 600 的文件具有相同的信任级别。之后请重启 MCP 客户端。上表中的其他变量也以相同方式设置,例如 [Environment]::SetEnvironmentVariable('GHOST_INSPECTOR_ALLOW_WRITES', 'true', 'User')。
此服务绝不会:
- 通过工具调用向你索要密钥(那会让机密出现在对话记录中)
- 将密钥写入磁盘
- 在日志行、错误消息或工具响应中包含密钥
安全模型
除非你明确选择启用,否则不会写入或执行任何内容。 只有在 GHOST_INSPECTOR_ALLOW_WRITES=true 时,修改类工具才会执行操作;只有在 GHOST_INSPECTOR_ALLOW_RUNS=true 时,gi_run_test 才会执行操作。未启用时,无论 Agent 被要求做什么,都无法更改或运行任何内容——检查逻辑位于处理程序中,因此无论调用方发送什么内容,限制都会生效。每个工具还声明了 MCP 注解(readOnlyHint、destructiveHint),因此基于这些注解控制权限的客户端会看到与服务强制执行的安全策略一致的状态——其中包括 gi_validate_test 未标记为只读,因为即使不保存任何内容,驱动真实浏览器访问真实 URL 也会产生副作用。
受门控,但绝不隐藏。 无论门控是否开启,每个工具都会列出;权限检查会在调用工具时进行。未列出的工具与不存在的工具无法区分,因此 Agent 看到较短的列表后会认为缺少相应能力,并告诉你——而你无从纠正。这里,受门控的调用会被拒绝,不会触及任何内容,并会指出要设置的变量。
可见不代表有权限。两者有意分开:列表告知 Agent 此服务能做什么,门控则决定它当前可以做什么。
按设计,不提供套件删除功能。 DELETE /suites/{id}/ 会级联删除套件中的每个测试,且没有版本历史或回收站。此操作仍应由了解自己在做什么的人刻意使用 curl 执行。
失败的请求不会重试。 超时或连接中断会作为错误呈现,而不会再次尝试。这是有意为之,并非疏漏:execute 和写入端点都不是幂等的,重试可能会悄悄地让浏览器测试运行两次,或重新应用一次实际上已成功的写入;这种便利正是本服务旨在防止的意外。只读调用可以安全重试,因此 Agent 只需再次请求即可。
写入操作受到保护。 测试更新会按顺序执行以下四项,且任何一项都无法关闭:
- 对比整个
execute链中的dateUpdated与上次运行时的值:某个模块在上次运行之后才被编辑的红色测试,是过时而非故障;根据该失败诊断出的修复,依据的是一个已不存在的版本。导入最多嵌套十层,因此遍历有界且能检测循环。在一个真实账户上,这项检查拒绝了一个在仪表板上持续显示红色一年多的测试;该测试的定义是在上次运行几周后才编辑的; - 将完整的原始定义(即使拒绝写入也一样)保存到
GHOST_INSPECTOR_BACKUP_DIR下仅所有者可访问的文件中(目录权限为 700,文件权限为 600,已移除凭据),并在返回的摘要中附上文件路径。Ghost Inspector 不保留步骤的版本历史,因此该文件就是你的回滚依据。verbose: true也会在结果中内联返回该文件内容;如果文件无法写入,内容也会以内联形式返回; - 应用更改;
- 重新读取并进行两轮差异比较:确认发送的内容已原样写入——步骤及其各自的
sequence位置、名称和起始 URL;并确认所有未发送的字段均未更改。HTTP 200并不能证明这两点。
每个写入响应都会携带记录新的 dateUpdated,因此连续编辑时无需在中间重新读取。
存储的凭据永远不会传给你的 Agent。 测试和套件记录以明文形式存储 HTTP 基本身份验证的用户名和密码。每个工具结果返回前都会移除看起来像凭据的键,验证报告中的私有变量值也会被屏蔽。
写入还需要并发令牌。 你需要提供自己认为当前有效的 dateUpdated;如果记录此后已有变动,写入就会被拒绝。模型可能会被说服而绕过确认标记,但它无法猜出一个自己必须实际读取过的时间戳。gi_get_test 会连同定义一起返回该令牌,因此编辑时通常第一步就是读取记录,而非把读取当作障碍。
拒绝写入时会报告当前值,因为这有助于诊断真实冲突;同时会提示你重新读取并重新构建更改,而不是再次发送。重放基于已不再存储的定义构建的编辑,会覆盖后来替换它的内容。
该令牌只能缩小时间窗口,不能完全关闭窗口。Ghost Inspector 不支持比较并交换,因此检查是在客户端侧以先读后写的方式进行:如果两个写入者都在任一方写入前读取了记录,两者都会通过检查。它能捕获基于几分钟前或几天前读取的副本进行操作的情况——这是现实中更可能遇到的情形,而非真正的竞态。
所有四项防护都已在真实账户上通过验证:使用一个一次性克隆,创建后写入,再删除,最终账户的字节内容与之前完全一致。0.3.0 中新增的功能——更改起始 URL、存储步骤位置、备份文件以及接受截图——也以相同方式进行了验证。有一种行为只有在真实账户上才会显现:Ghost Inspector 写入时会规范化步骤,补齐调用者省略的字段,因此比较前会先规范化两侧内容。否则,即使写入完全成功,每次验证也都会报告存在差异。
运行已存储的测试有单独的门控。 gi_run_test 是唯一会严格按已保存内容执行测试的工具,不会截断任何内容——因此在大多数账户中,它会向生产环境提交请求。它要求设置 GHOST_INSPECTOR_ALLOW_RUNS=true;ALLOW_WRITES 并不意味着允许运行:编辑可以通过写入路径返回的备份恢复,而已提交的表单则完全无法撤回。此外,除非在该次调用中明确确认,否则会拒绝运行会提交内容的测试。检查会先内联展开模块,因为步骤全部是 execute 调用的测试可能会把提交操作藏在模块中;无法完整展开的调用链也会被视为会提交内容。
只有在存在后果时才会要求确认,这正是关键所在——如果每次调用都需要一个标志,所有调用方都会习惯性地设置它。对一批真实测试进行抽样统计后发现,大约四分之三的测试要求确认,其余则直接运行——那些要求确认的测试确实会点击提交控件。
验证不会提交任何内容。 gi_validate_test 使用按需执行来运行定义并将其丢弃,因此不会更改你账户中的任何内容。但它会通过真实浏览器访问真实 URL,运行方式与真实测试相同,并受到三层防护,且这些防护都无法关闭:
- 与真实测试相同。 首先会内联模块——如果某个测试的步骤只有
execute调用,那么其中的提交操作可能藏在模块里。{{variables}}会从你、测试套件和组织的变量中解析,因为按需执行会忽略自定义变量,并将未知变量作为空字符串运行;如果某个变量没有值,就会在发送任何内容前拒绝运行。测试套件的用户代理、区域、语言和延迟设置也会一并应用。 - (A) 静态防护。 运行会在首次点击外形类似提交控件的目标、按下 Enter 键,或遇到可能提交或发送数据的脚本或步骤条件时截断;该步骤会变成针对同一目标的断言——因此整条链都会得到验证,包括控件是否可访问,但不会触发它。
- (B) 浏览器内防护。 每次剩余的点击操作前,探针都会检查其解析到的元素;如果该元素是表单的提交控件、表单内的非字段控件,或根本无法解析,运行就会停止。表单中带有 aria 标签的提交按钮无法被任何选择器模式识别,但这里会捕获到它。
- (C) 触发器。 每个页面的每个步骤执行前,都会拦截并报告提交事件、
form.submit()、非 GET 的fetch和 XHR,以及sendBeacon。这不会中止运行。
仍有一些情况会如实记录,而非隐藏:在页面的第一个步骤运行前就已保存 window.fetch 或 form.submit 的脚本、WebSocket、子框架内发生的任何操作,以及通过 GET 发送的数据(像素或页面跳转)。防护倾向于停止运行:“Continue”按钮即使在表单内也会导致运行停止。没有任何选项可以让它执行提交;这仍需有意使用 curl。对于任何涉及生产环境的操作,请先使用 gi_plan_test:它会准确报告将要运行的内容,包括已内联、已解析和受防护的部分,且不会启动浏览器。
开发
npm ci
npm run typecheck
npm test # builds first, then runs the suite
263 项测试,不依赖任何测试依赖项——使用 Node 自带的运行器和 assert。这些测试按断言失败时会破坏什么来组织,而非按覆盖率组织,因此失败名称会告诉你破坏了什么:
| 文件 | 固定的行为 |
|---|---|
config.test.js | 只有精确的 true 才会打开写入门控,1 或 yes 均不会;每次调用都会重新读取密钥,因此轮换密钥可正常工作;redact 会移除查询参数和单独出现的字符串 |
detail.test.js | 并发令牌会传递给调用方;模块缺少判定结果时,不会被视为失败;返回的步骤不会展开,因此编辑操作会针对拥有这些步骤的测试 |
create.test.js | 除非调用方明确要求,否则会静默复制;任何非显式的 true 都会清除计划;在近似重复的套件名称创建之前就会拒绝它 |
client.test.js | 真值不等于 true;未知日期会被视为从未执行,因为反向处理会把仍在运行的模块错误地加入清理列表;卡住的正文下载无法超出请求超时时间 |
graph.test.js | 循环会终止;共享子树不再重复展开后,仍会报告一次循环;不会因某一层没有新增节点而增加深度;触及文档规定的嵌套上限时会报告,而不会冒充完整结果 |
inventory.test.js | 每个测试恰好归入一个类别;模块绝不会被计为失败;空套件仍会显示 |
modules.test.js | 传递影响范围会超过直接计数;循环会作为标记报告,而不会导致数字虚增;能够找到未执行任何操作的测试 |
diagnose.test.js | 即使保存模块时所有 sequence 都为 0,仍会将失败映射到失败的步骤;不会把从未运行的步骤指认为失败步骤;不会把已解析的选择器冒充为测试要查找的内容;模块中的失败步骤会指向该模块;已清除的运行不会被报告为从未运行的测试 |
vacuous.test.js | 无论模块看起来多么空,都不会将其称为空洞;从模块继承的断言也会计入;单独的最后一条断言会进入候选列表,而不会被判定为无效;无法读取的定义会被跳过,而不会被计为空 |
repair.test.js | 无论页面包含什么内容都成立的规则会被应用;脆弱的选择器会被指出,但绝不会被改写,因为凭空编造选择器只是在猜测 |
stale.test.js | 红色项目会拆分,且不会丢失任何内容;无法解析的日期会计为已更改;模块会被排除,而不是被评估 |
validate.test.js | 会捕获从模块继承的提交操作——按照原样对定义进行保护,经测试发现会导致 8 个真实测试中有 5 个提交线上表单;导入项的条件会约束其导入的每个步骤,而不会被丢弃;条件会以 {statement} 的形式传递;每个步骤都会受浏览器内保护机制约束,且注入的步骤绝不会改变报告所称的第 N 步;私有变量绝不会进入报告 |
run.test.js | 允许写入不代表允许运行;隐藏在模块中的提交操作仍然需要确认;无法完全展开的调用链会被视为提交操作 |
writes.test.js | 陈旧性保护中每种不确定情况的判定方向;不会将 Ghost Inspector 自身的步骤默认值报告为差异;只在写入后才出现的字段仍会被视为意外更改;每个步骤都会连同其位置一起保存;已存储的基本身份验证密码不会进入响应;备份文件仅所有者可读写 |
guard-script.test.js | 在模拟页面上执行的浏览器内探测、停止条件和触发器:会记录停止状态,并由后续步骤遵守;会阻止发送数据的操作,同时放行 GET 请求;被拒绝访问的 sessionStorage 不会导致未停止的运行被跳过 |
variables.test.js | 套件变量会传递到起始 URL;由较早步骤设置的变量会留给浏览器处理;在设置之前就使用的变量,或没有值的私有变量,会导致运行被拒绝 |
results.test.js | 跳过或未到达的步骤不会计为已执行;缺失的持续时间会重新构建,绝不会报告为 0;控制台输出会截断,绝不会被静默丢弃 |
find.test.js | 步骤搜索会匹配备用选择器;结果包含 ID |
history.test.js | 红色连败中首次失败的位置会跨页查找;未完成的遍历绝不会声称覆盖了全部历史记录;同时开始的失败会跨套件分组 |
screenshots.test.js | 从未有人查看的截图,或没有任何内容可供接受的截图,绝不会被接受 |
server.test.js | 服务会启动并使用协议通信;写入门控在端到端流程中有效;每个工具的注释都会说明代码实际执行的安全状态 |
server.test.js 会通过 stdio 启动真实服务器,这是发现注册或架构错误的唯一方法。整个测试套件中没有配置任何 API 密钥,因此不会有任何请求发送到 Ghost Inspector,可以在任何机器上安全运行测试。 |
CI 会在 Node 18、20、22 和 24 上运行所有测试——包括 engines 中的最低版本、两条 LTS 版本线和当前版本,因为 npx 会使用用户已有的 Node 版本运行。另一个任务会针对完整历史记录重新运行泄漏审计,而不是只检查工作树,因为即使后续提交清除了泄漏,泄漏内容仍然存在于历史记录中。
有一点值得说明。 此处记录的 API 行为是根据单个套餐上的单个账户进行实测验证的。每次检查结果都一致,但其他套餐的情况可能不同——如果你账户上的情况与此处记录的内容不符,欢迎提交 issue。
贡献
欢迎提交 issue 和 PR,但本项目以尽力维护为原则——它是为解决实际问题而构建的工具,并非受支持的产品。变更记录见 CHANGELOG.md;与安全相关的内容请通过 SECURITY.md 处理,而非公开 issue。
代码、测试、文档或示例中不得包含任何组织专属数据:包括 ID、主机名、文件夹或套件命名规范,以及测试数据身份信息。所有这些内容都应放在调用方的配置中。请使用 https://example.com 和 [email protected] 这类明显的占位符。
许可证
MIT。请参阅 LICENSE。
Ghost Inspector 是其各自所有者的商标。本项目与其无关。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。