跳转至

Electron 文件页面观察

REA 可以附加到 Electron/Chromium CDP 端点,并检查现有的 file:// 渲染器页面,而无需评估 JavaScript 或调用 Electron API。请求直接提供端点;REA 仅接受字面端口回环 HTTP 端点。选择端点会暴露它服务的每个 Electron 目标,包括本地文件路径和页面元数据。

断开检查的页面会话可能会清除 Chromium 内部由调用方拥有的 navigator.platform 模拟。REA 无法恢复另一个客户端完整的 user-agent/client-hint 配置。请使用一次性目标,或让拥有该配置的客户端重新应用其配置;参见共享的 CDP 状态限制。

这种被动运行时表面与无目标的静态 analyze_javascript_application 工作流不同。静态分析读取本地 ASAR 或解压后的目录,而不执行应用程序代码。被动观察检查现有的 Electron 页面。结果保持静态推断和运行时观察的区分。打包的 fuse 状态是单独的静态读取:inspect_electron_fuses 报告此二进制文件是否会遵循 Inspector 标志、ELECTRON_RUN_AS_NODE、嵌入式 ASAR 完整性以及仅 app.asar 加载。当两组证据集都已存在时,请使用单独的 reconcile_javascript_runtime 工作流。

目标边界

请求提供字面端口回环端点,并针对检查提供目标 ID。REA 接受解析为常规文件的本地无主机 file:// URL,包括打包应用程序从 app.asar 内部提供的页面。对于这些 URL,路径中第一个作为常规文件的 .asar 路径组件即归档文件,其余部分必须在其标头中命名一个常规文件,报告路径为该归档规范路径与该成员拼接的结果。远程主机、路径名中的编码分隔符、ASAR 目录或链接以及不存在的路径都会被拒绝。端点会暴露每个符合条件的目标及其本地路径元数据。查询字符串和片段不参与文件系统路径准入,包括其中编码的分隔符文本。列出和检查证据都保留所观察到的浏览器产品/修订版本;主机平台和架构保持显式未知。

取消会在已启动的文件系统操作结束后停止进一步的文件授权。ASAR 描述符关闭失败仍属于带精确可重试所有者的类型化不完整清理;它们不会被视为缺失或未授权的页面。后续授权和提供程序关闭会在报告描述符释放前重试保留的描述符。失败的列出操作会保留其已授权的目标前缀,并在清理错误和精确所有者重试过程中明确剩余目标的不确定性。

工作流程

list_electron_targets 在一个内联数组中返回所提供端点服务的每个符合条件的目标。

对于 MCP 后续调用,将相同的字面回环端点和所选目标 ID 传递给 inspect_electron_page。REA 会在检查前重新发现目标,并针对活动端点验证该 ID。

rea list-electron-targets http://127.0.0.1:9223 --json
rea inspect-electron-page http://127.0.0.1:9223 TARGET_ID \
  --observation-ms 100 --json

脚本内容默认排除。在请求中设置 include_script_sources 会返回所选目标的脚本源:

rea inspect-electron-page http://127.0.0.1:9223 TARGET_ID \
  --include-script-sources \
  --json

规范化结果包含规范本地路径、框架和 DOM 结构、资源元数据、稳定的脚本/资源标识、显式完整性和内容寻址脚本工件。当资源大小被省略或无效时,其值未知;提供无效大小也会产生显式的完整性诊断。

DOM 节点索引保留其快照位置。无效行会连同完整性诊断一起被省略,因此 total_nodes 可能超过保留的节点计数,并且父索引可能引用已省略的源节点。

当 CDP 提供执行上下文框架 ID 时,脚本元数据会保留该 ID,并在 frame_scope 中单独记录准入。authorized 作用域指观察到的文档代次;unknown 保留已知框架 ID 但不声称授权,并使脚本覆盖率变为附加受限(attach-limited)。历史捕获可能省略此字段,从而使该准入事实未知。

来自其框架被本地文件策略显式排除的文档代次的脚本,会在读取脚本源之前被省略。框架身份可能来自脚本事件自身的辅助数据或其观察到的执行上下文;相互矛盾的标识不会被对齐。frame_claims.script_event_frame_id 和 frame_claims.execution_context_frame_id 保留来自这两个来源的实际观察声明。当它们存在分歧而使解析后的 frame_id 为 null、frame_scope 为 unknown 时,两者仍然可用。被省略的声明是未观察到,而非框架不存在的证明。框架描述当前清单;脚本观察可能保留已脱离的早期授权框架。

has_source_url 将 CDP 的 sourceURL 声明标志保留为 true、false 或 unknown(null,或在历史捕获中被省略)。脚本的规范 file_path 是被准入的本地文件 URL 或提供的 sourceURL 标签。它不验证运行时字节是否来自该磁盘文件;捕获的源字节有自己的摘要。reported_url 保留规范路径准入之前的原始 URL 或标签。标签与文件系统来源保持区分。捕获还会盘点 worker、service-worker 和 shared-worker 目标,并带有经过验证的 opener 目标和父框架 ID。Worker 发现使用被动目标元数据;REA 不会附加到这些目标,也不会在其中执行代码。脚本元数据对每种保留的表示形式使用共享的 8 MiB JSON 字节配额:传入草稿和规范化捕获元数据。准入会在保留它们或将元数据序列化为摘要之前,对转义字符串、框架声明和来源字段进行计数。配额耗尽会保留较早的记录,并报告计数为 resource_budget_exhausted 的脚本遗漏;之后较小的记录仍可能放入。此配额不增加脚本数量上限,并且独立于脚本源字节。脚本源收集在所有脚本中最多保留 32 MiB 的 UTF-8 文本,并共享 20 秒的收集截止时间。被省略的源会保留其脚本元数据和明确原因;在超大源被省略后,之后较小的源仍可能放入。单独的 64 MiB CDP 响应限制在保留准入之前约束单个线上消息,而不是总瞬态内存。源预算不增加脚本数量上限。与每个目标、框架、脚本和资源一样,worker URL 必须先解析为本地文件才能被保留。关系 ID 可以改进归因,但不能证明哪个静态模块启动了 worker,也不能证明其工作已完成。缺失 opener 和父级关系会使 worker 的所有权未知。此类目标会被扣留并带有 unattributed_target 排除项,workers 覆盖不可用,即使其 URL 指定的是本地文件也是如此。明确的外部关系仍为 out_of_target_scope;格式错误的所提供关系 ID 为 invalid_protocol_value。

检查不会保留 DOM 值、执行渲染器代码、导航、点击、调用 Electron IPC、关闭目标或终止应用程序。

主动 Electron 场景

场景请求提供 Electron 可执行文件和应用程序入口点,以及任何参数和操作。应用程序根目录默认为入口点的父目录,当应用使用不同的根目录时可以另行指定。REA 通过官方 Playwright Electron API 启动该可执行文件并拥有其生命周期。它接受点击/等待操作、窗口定向的渲染器重新加载/崩溃操作,以及合成的 open-url 或 second-instance 深链接递送。它记录捕获范围内的窗口和 WebContents 身份、进程指标,以及 IPC 通道和值形状元数据。负载值不会被保留。

window_index 在每个操作开始时从 Playwright 当前的 Page 列表中选择。REA 将该 Page 解析为其对应的 BrowserWindow 一次;操作的 target 使用 BrowserWindow 的捕获范围 window_id,与窗口清单匹配。选择后对任一枚举重新排序不会重新定向该操作。句柄清理失败会保留已完成的操作记录,并仍由提供者持有以进行清理重试。

使用操作员提供的 Electron 运行时运行真实的 fixture 验证器:

REA_ELECTRON_EXECUTABLE=/absolute/path/to/electron npm run verify:electron

此操作主动启动并与选定的目标交互。它不是被动的 CDP 观察。被拥有的进程保留正常的主机文件系统和网络权限,因此生命周期所有权不会使其成为沙箱。

CLI 和 MCP 接口接受相同的模式。对于 JSON 请求文件:

rea capture-electron-scenario scenario.json --json

结果按每个声明的操作记录一个状态和 target;在失败或已取消的操作之后的操作不会运行,并记录为 cancelled,带有未执行的错误。它还会记录相关联的应用/窗口/WebContents、预加载、会话、导航、shell、权限、弹出窗口、下载、协议、原生插件、进程和 IPC 时间线事件。IPC 通道和参数形状元数据保留其观察到的长度;负载值永远不会被保留。

渲染器崩溃/重启和深链接操作是合成的场景控制;它们的尝试和观察到结果会保留在时间线中。主动钩子会阻塞并记录下面列出的 shell 方法以及选定的导航、权限、下载、弹出窗口、更新器和操作系统集成 API。这些方法补丁不包含直接的文件系统、网络、原生插件或其他未打补丁的目标效果。

当附加在应用活动之后开始时,时间线明确是不完整的。启动(包括初始状态快照)有 60 秒的截止时间。操作会等待完成或请求取消;目标从未出现的点击,或在未打开任何窗口的应用中没有 window_index 的 wait,会保持待处理状态直到被取消。取消后,最终状态读取有 5 秒时间,之后 REA 改为保留初始快照;取消会保留调用方的原因,并在其诊断信息中记录该超时。

shell 策略由 scripts/electron-active-hook-boundaries.cjs 中的 blockedShellResults 拥有。其同步阻塞为:showItemInFolder 返回 undefined,writeShortcutLink 返回 false。它们的 shell-attempt 事件记录被阻塞的阶段和参数形状;这两个结果都不意味着所请求的主机操作已发生。现有的 openExternal、openPath 和 trashItem 阻塞会拒绝其 Promise。trashItem 阻塞会阻止该调用到达操作系统回收站操作;它不会拦截应用程序删除文件的其他方式。

CLI 的 SIGINT/SIGTERM 请求取消并等待被拥有进程的清理。窗口 ID、URL 和缓存的标题来自一个主进程 Electron 快照,因此崩溃的渲染器不需要成功的渲染器端标题查询。

窗口插桩使用 Electron 的 window-created 事件,包括具有只读 BrowserWindow 导出的运行时。预加载配置来自窗口的运行时元数据,包括当 web 偏好设置省略时 Electron 的可选内部预加载描述符。该描述符已在 Electron 44.7.0 上验证;未暴露任何一种表示的运行时保留不可用的路径。配置的路径或可用的 IPC 处理程序并不能证明预加载已执行。如果清理无法验证,错误会将收集到的观察结果保留在 details.partial_observation 中,并将其应用程序清理标记为 unverified。清理不确定性并不授权向无关进程发送信号。

在 Linux 上,基于 Chromium 的进程可以覆盖通过 /proc/<pid>/environ 暴露的初始环境内存。即使应用程序仍然通过 process.env 看到环境,环境也可能是可读的,而 REA_PROCESS_RUN_ID 却不存在。REA 会报告缺失的标记,并将谱系所有权和清理保留为未验证;PID、可执行文件或父进程关系不能替代该所有权证明。此限制可能影响原生 Linux 以及 WSL 上的被拥有的 Electron 捕获。这并不表明所有 Electron 版本或 Linux 环境的行为都相同。

主进程 IPC 记录保留 on 和 once 注册的原始函数移除,并只记录一次已触发的 once 回调。原生 Node.js 拥有 once 注册、触发和可调用分发以及移除顺序和遍历,包括由移除观察者注册的监听器;钩子在移除边界只翻译自己的记录包装器。包装器元数据使用弱键,不保留已移除的注册。包装器元数据操作、私有集合方法和遍历构造函数在目标启动前被捕获;之后替换其全局绑定不会改变监听器的注册或移除。

原生运行时在 once 是否咨询回调的 .call 或 .apply 方面有所不同。钩子观察实际回调入口,而不强加另一个运行时的属性读取或参数列表表示。由原生分发选择的应用方法保留其原始接收者和参数列表对象;当无法确定回调执行时,不透明的方法会产生 custom-call 或 custom-apply 观察间隙。

如果原生包装器创建或注册方法查找可能通过应用程序的 getter、setter 或 Proxy 暴露私有插桩,注册将保持原生且不包装。once-metadata 观测间隙标识出那次未被观测的注册尝试;它并不证明注册或传递已发生。原始回调、元数据写入和原生方法接收者均被保留,包括注册失败时也是如此。后续注册将恢复正常观测。当原生分发读取不可调用的 call/apply 属性时,会产生失败的观测间隙;回调条目并非虚构。

on 监听器的应用自定义 .apply 会原样接收原始参数列表对象。借用暴露的方法会保留其动态接收者。由于该方法负责参数解释且可能不会调用回调,钩子会记录一条有界的 ipc-observation-gap 时间线条目,包含注册的通道,而不是记录一次 IPC 调用。其空的 argument_shapes 表示参数未被观测,而非零参数回调;回调的执行和结果仍然未知。覆盖范围和保留策略均包含这些间隙,即使其中的单个记录被丢弃。正常的原生分发继续记录实际的调用帧。证据快照复制保留的数组和计数器,而不调用应用程序的迭代器或 Array species。

监听器链识别区分自有、非自有和未知的元数据。数据链接可能被继承;只有在完成有界的原型查找后才能确定其不存在。耗尽任一遍历、遇到 getter 或看到 Proxy 都会使归属保持未知。钩子保留原生注册而不添加另一个记录包装器,并在注册成功后保留一条 listener-chain 观测间隙。该间隙并不证明 IPC 传递已发生。现有的内部记录包装器仍可报告其实际调用;否则回调活动将保持未被观测。仅含 setter 的属性具有确定的 undefined 读取结果。数据描述符解析与移除归一化共用。

这并不建立完整的 JavaScript 函数自省等价性。调用者定义的 .listener 属性可以改变 listeners() 和元事件暴露的身份;包装器识别不会跟踪访问器和 Proxy 元数据。在另一个通道上重新注册原始记录包装器会保留原始注册的通道归属。在原始记录包装器上修改 .listener 也可能阻止通过绕过钩子移除方法的应用程序装饰器进行移除。当移除请求到达钩子的方法且其注册顺序已知时,私有回调归属会保留按原始函数进行的移除,并在公共元数据被更改或删除时保留最新匹配注册的移除。原生移除仍然决定 getter 的执行、异常和移除元事件。

如果注册或移除方法与钩子初始化时捕获的 Node 方法不同,钩子将使监听器回调保持不包装,并记录一条 listener-registration 观测间隙。应用程序保留其原始回调和接收者;回调执行保持未被观测。此比较假设 Node 的 EventEmitter 原型在钩子初始化之前本身未被全局装饰。提供程序在应用程序之前加载钩子,并从子环境中排除 NODE_OPTIONS。它保留选定的 DISPLAY、XAUTHORITY 和 WAYLAND_DISPLAY 值,包括调用者选择的 X11 授权文件路径。

不透明的后续监听器或不支持的发射器状态可能阻止证明移除顺序。钩子随后将移除委托给原生方法,并记录一条 listener-removal 间隙,而不是声称哪个注册被移除。这些间隙不同于被丢弃的记录,并不证明 IPC 传递或成功移除。

目标 fuse 前提条件

主动场景捕获要求目标 Electron 可执行文件支持 Node CLI 检查器标志(--inspect 或 --remote-debugging-port),以便 Playwright 能够建立其 DevTools 协议会话。当 Electron 可执行文件显式禁用 EnableNodeCliInspectArguments fuse(或移除该能力)时,capture-electron-scenario 会在进程启动前立即失败,抛出 AnalysisUnsupportedTargetError("unsupported_target"),而不是等待启动期限到期。对于禁用检查器 fuse 的目标,请通过 inspect_electron_page 使用被动 CDP 检查,或使用提取的 app.asar 针对不受限的开发二进制文件运行。

真实验证器在检查 IPC、渲染器崩溃/重载、实用程序/子进程、深链接和阻断效果夹具之前,会演练编译后的 CLI 和 stdio MCP 发现、页面/脚本检查、静态/运行时对账、主动观测以及 CLI SIGTERM 清理。即使保留的捕获包含有用的观测结果,清理错误也会使整个链路保持失败状态。

主动 Electron 证据也可以提供给 reconcile_javascript_runtime。该投影有意地仅针对目标且不完整:它将选定的应用程序路径和捕获结果绑定到静态图上,而帧、脚本、工作线程和执行声明仍不可用,直到单独的被动运行时捕获提供它们。

ASAR 观测通过一个打开的文件句柄读取头部,并对照归档大小验证其声明的长度。头部/索引准入使用与静态 ASAR 读取相同的预算:默认 16 MiB / 16777216 字节,或设置 REA_ASAR_MAX_HEADER_BYTES 时(最多 256 MiB)。过大的头部不会被解析;选择成员路径不会绕过准入,页面保持未授权状态。头部缓存另外跨八个归档最多保留那么多字节的已准入编码头部。驱逐该缓存不会提高准入上限。

本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 rea2/rea