Repository navigation
feat(ui-evidence): add source-bound real-browser verification - #113
Merged
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
摘要
ui-evidence.v1:将 Run/Mission/Session/Workspace、commit、dirty/index/worktree digest、build/start recipe、固定浏览器身份、loopback route、fixture/seed、呈现矩阵、交互步骤、失败策略和不可变 Artifact 绑定为一份可审计清单。command-runtime.v2启动当前源码的应用,拒绝预先存在的 listener;从固定受信位置重新验证 Edge 版本、publisher 与 executable SHA-256,以 disposable Profile、受限 CDP、Safe Web/WFP 和创建时 Job Object 完成真实导航、交互、断言及采集。passed。run-verify从 1.0.0 精确归档后升级为 1.1.0。Closes #102.
协议、源码绑定与状态语义
ui-evidence.v1的 manifest 在运行前一次性持久化,随后不可变。它同时绑定:command-runtime.v2配方,包括固定 executable/argv、Workspace 相对 cwd、environment digest、timeout、network=disabled与credentials=none;restricted-cdp-ui-evidence.v1、headless 和 temporary-profile 声明;127.0.0.1origin、route、readiness、viewport/DPR、locale/theme/reduced-motion、fixture/seed/page state digest;Application 在 build 前、应用 readiness 后、浏览器断言后及 owned application/browser tree 清理完成后重新捕获 source checkpoint。tracked、未忽略的 untracked、index、commit、branch 或 root 任一漂移都会 fail closed;最后一次复核刻意位于 cleanup 之后,避免应用在最后断言与 terminal receipt 之间改写源码。
Attempt 只允许
not_run|running|passed|failed|cancelled|timed_out|interrupted。passed是唯一绿色状态;not_run、build 成功、mock render、缺少强制产物或清理未证实都保持非通过。失败阶段固定为build|launch|readiness|navigation|selector|assertion|console|network|capture|cleanup,CLI、OpenAPI、Desktop 和 Skill 使用同一字段与语义。运行所有权、浏览器与网络边界
Desktop 默认只读。启动 UI evidence 必须同时具备当前 running Run、Code/Local/Deliver/root、active execution lease、
full_access、permission control、danger-full-access、Run execution、restricted browser CDP 和显式--enable-ui-evidence;启动 flag 只打开进程内 capability,不创建 permission、approval 或 lease。readiness 端口在任何启动前探测;已有 listener 返回
launch/preexisting_service,不会被收养、停止或用作当前提交的证据。应用由 Run-owned command runtime 管理;浏览器从固定安装位置重新验证身份,以新的 Profile 启动。每次 start/read/wait 都重查当前 lease。取消、timeout、撤权或 Desktop shutdown 后,cleanup-only binding 只携带本 Attempt 的 durable Job/operation/Run/lease identity,只能回收精确 owner 的进程树,不能恢复启动权、收养历史 PID/端口/Profile 或影响其他 Job。Profile 仅在浏览器树、network guard 和端口回收完成后进入 exact-owner quarantine;Windows 短暂 sharing lock 使用 5 秒有界重试,超限仍是
cleanupfailure。启动 reconciliation 只把遗留runningAttempt 收敛为interrupted,不会从 SQLite 历史恢复进程 authority。浏览器只允许精确 literal loopback origin,所有 request/redirect 重新经过 TargetScope。UI 专用 CDP allowlist 不包含
Runtime.evaluate、cookie API、response body、request mutation/replay 或Fetch.fulfillRequest。越界 URL 只持久化[blocked-url];不读取 request headers、cookie 或 body。普通 command runtime 的network=disabled是宿主执行策略,不被描述成通用 packet-level OS containment;真正浏览器流量由 UI-evidence Safe Web/WFP 路径独立约束。Windows 托管 Edge 根因与生产修复
托管 Windows 首轮失败不是 Edge 安装、publisher、Profile ACL、Job Object、standard-user token、RemoteDebuggingAllowed policy 或进程存活问题。有限诊断证明主进程与 Job 持续存活、Profile 正常初始化;同一临时标准用户使用等价参数直接启动可以发布 DevTools endpoint,只有生产 adapter 的旧环境块失败。
根因是旧实现把
USERPROFILE、APPDATA、LOCALAPPDATA全部改写为浏览器 Profile 下的任意子目录。Chromium 的 Windows PathService 因此无法从实际 launch token 解析 Local AppData,把远程调试使用的 user-data directory 视为未知/默认目录并主动拒绝。最终修复先取得并验证启动 authority,再通过 WindowsCreateEnvironmentBlock的 Go 封装从该 token 创建全新环境,且明确不继承调用者进程环境;随后只保留固定 structural allowlist,要求三个 known-folder 值均为绝对路径,并覆盖COMSPEC、PATH、PATHEXT、SystemRoot/WINDIR。HOME、TEMP、TMP与--user-data-dir仍指向 disposable Profile,调用者 secret 与任意 PATH 不会进入浏览器。Edge 还会先创建零字节
DevToolsActivePort,再写入两行 endpoint。读取器现在只把“owned Profile 内、direct、regular、非 reparse、大小恰为 0”的短暂窗口视为 pending,并继续受 45 秒 deadline 与进程存活约束;indirection、oversize、非空 malformed payload 仍立即 fail closed。CI 同时改为临时标准用户、随机密码、唯一 direct temp root、受限 ACL、production process adapter,并在 finally 中按 SID 清除 Profile、ACL、账户和临时目录。证据、脱敏、限额与清理
V1 每次执行必须同时采集 PNG screenshot、DOM、accessibility tree、console/page diagnostics、network/HTTP metadata 和 performance metrics;
video字段保留但当前必须为false,因此不会以像素快照单独替代行为、可访问性或运行时健康验证。每个 Artifact 绑定 kind、MIME、bytes、SHA-256、source commit、Run/Attempt、source step、capture time、viewport、screenshot dimensions、redaction、
retention_policy=run_history与untrusted=true。截图像素面和 PNG dimensions 在 domain、SQLite trigger 与 React parser 三层绑定到viewport × DPR;在完整 PNG 解码/分配前先检查 header dimensions。上限为单 Artifact 32 MiB、单 Attempt 128 MiB、仓库 2 GiB,CI 上传副本保留 5 天。文本产物统一修复 UTF-8、去控制字符并做 Secret redaction。Network 仅保留再次通过 scope 的脱敏 URL、method、resource type、status、MIME 和失败摘要。动态或可能含敏感数据的 screenshot 区域必须显式列入 mask;任一 mask selector 未匹配即失败。下载响应使用
no-store、ETag、内容 SHA-256 与 untrusted header;React 在创建 Blob 前复核 MIME/长度/hash,CLI 在0600独占创建输出文件前完成同样复核。HTTP、CLI、Desktop 与 Skill
认证 HTTP/OpenAPI 新增:
GET/download 使用 read bearer;start/cancel 使用独立 control bearer、严格 JSON、有界 body、Run URL ownership 和
confirm=true。相同operation_key+ request fingerprint 幂等返回原 Attempt,不同载荷复用 key 冲突。CLI 有意只提供
list|show|artifact,不复制执行 authority;artifact export 是 exclusive create + hash verify。Desktop Run workspace 新增双语 UI evidence 页签,capability 关闭后仍能只读查看历史;启动要求编辑完整 JSON 并显式勾选审阅确认,只有passed使用成功样式,not_run保持中性。React 还独立复核 Attempt/step/artifact chronology、尺寸和下载内容。内置
run-verify@1.1.0将 manifest/receipt、focused-checks与 PR Verification 字段对齐;原 1.0.0 的SKILL.md和 manifest 逐字节归档,升级不会改写历史 Skill 身份。生成后的 OpenAPI 为 128 paths / 143 operations / 350 schemas;OpenAPI SHA-256 为
016a7de607badbc240c35d0ebeb33d576ed89f4d17a26f27a6a273db44a42ffc,TypeScript binding SHA-256 为652a5fbc747b0ad1910b1fc6a12cc1bba4ddbc63a90fbc6d97cb0a0e02259808。主线兼容性
本分支已 rebase 到包含 PR #112 / Issue #103 的当前
main9fc824c。上游批次交付已经使用 schema v118 与 ADR 0119,因此本 PR 顺延为 schema v119 与 ADR 0120,不改写迁移历史。command-runtime.v2、execution lease、permission、browser runtime、Safe Web/WFP、Job Object、Workspace identity 与 Artifact 约束,不建立第二套进程或浏览器 authority。run-verify精确归档 1.0.0 并升级 1.1.0;旧 Skill 身份、既有 command runtime、batch delivery、workspace checkpoints 与 Desktop compatibility identifiers 保持兼容。验收条件对应
false,不会伪报已采集。not_run不显示为通过。本地验证
go test -count=1 -timeout 25m ./...:在最终分支 commit4a80cd7b93a212c2b8ab83539b29fe33e18279b5全仓通过;internal/application645.479s、internal/httpapi220.330s、internal/store完整 v1→v119 migration/recovery 1377.572s。go test -race -count=1 -timeout 15m -run '(UIEvidence|SchemaV11(8|9)|CleanupOnly)' ./internal/application ./internal/browserruntime ./internal/httpapi ./internal/store ./internal/uievidence ./internal/desktop:定向 race 全通过。cmd/cyberagent-desktop的 ordinary/secure-tag 定向回归通过;Windows Desktop 使用完整desktop,wv2runtime.errortags。go vet ./...、go mod verify、go mod tidy -diff、Linux amd64/CGO-offgo build ./...。staticcheck -checks='SA*,S1*,QF*'覆盖全部受影响 Go 包及 Desktop tags,无新增 finding。npm run check:api和连续生成无漂移;OpenAPI/TypeScript hash 如上。npm run typecheck、完整npm test(62 files / 266 tests)、npm run build。npm audit --audit-level=high:0 vulnerabilities。cargo fmt --check、cargo test --locked(7 + 2 tests)、cargo clippy --locked --all-targets -- -D warnings。git diff --check、本机绝对路径/身份、凭据形态和构建产物扫描。./scripts/build-desktop.ps1 -SkipFrontend -VerifyReproducible在最终分支 commit4a80cd7b93a212c2b8ab83539b29fe33e18279b5完成双构建;EXE SHA-256ebffbb8ff33061623bfd6616ab60be4bd669afb450eb79915690ca32f01fd6be,reproducible=true、release_ready=false、无 installer/registry writes,Profile control 默认关闭。全仓 staticcheck 仍有 5 项与本 PR 无关的既存 finding:
internal/fileeditSA9003、internal/projectconfigSA4005,以及internal/sandbox的 SA1019/SA4011/S1023;受影响包扫描为绿色,未把仓库既存债务描述成零 finding。govulncheck ./...在本机 Go 1.26.5 如实报告 5 项可达标准库问题:GO-2026-6218、GO-2026-6090、GO-2026-6089、GO-2026-5972、GO-2026-5026,均由 Go 1.26.6 修复;另有 imported/required 但未调用的 advisory。本 PR 未新增模块依赖,不能把该本机扫描写成 zero finding;远端固定 Go 1.25 当前补丁版的结果由 CI 给出。最终真实 Edge 收据
最终 clean 分支 commit
4a80cd7b93a212c2b8ab83539b29fe33e18279b5上运行:ui-evidence-ci-smoke.v18a19544bbf17725574efaf949209b33b796c472d5078917f7b81ba0bc1d9cddfe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855;clean_checkout=true486c0e70f7c66a3288f3b00acf25452b69e08c2cb1f361937d8f6e720ee01ecedesktop-light-en.png:1440×900,14,000 bytes,SHA-256f215d70b144e3116838e3bc6fb579e42385927d03ac316cee19d2522ac3be337mobile-dark-zh-reduced.png:390×844 @2x → 780×1688,31,269 bytes,SHA-256deb11ce9f55258066d7902bd7857d873007e484380454bb3332231b186c9fbf3regression-detected.png:1440×900,13,467 bytes,SHA-256d8e58eac08a8dc1e81e8799721e29f462b2137d67b54e1990186268bb1d5723dregression_caught=true;browser_tree_reaped=true;browser_port_released=true;profile_removed=true;fixture_server_reaped=true;CI retention 5 days。同一固定 fixture 连续运行的三张 PNG 逐字节一致。首次真实运行暴露的 Windows Profile database sharing-lock 已通过 exact-owner、5 秒有界 quarantine cleanup 修复并由重跑验证。
远端 CI
Publish verified GitHub Release按 PR/Draft 规则跳过,没有发布未审阅产物。托管真实 Edge 作业在 GitHub 的 synthetic merge checkout
6f1da0fe2b1b702909198bedaf01b80f13b27ac4上生成并上传ui-evidence-edge-smoke(Artifact ID9389521356,retention 5 days):c1ebac20fa6bdd90d3aebcd26aab5bffb8b5a6957675728622e93b2b833ec21aclean_checkout=true;dirty digeste3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855b573f5254db288cd586e3a7afa8a6ef93e749c7a08f5f8fb862c3a75f5065902;adapterwindows_browser_job.v267131360b3c35696d81a5f4166cd42a4b55baf40246b048c45d24b705fa24763c3ea2d16a1bebaeb015242fea237212ba0d0e4579d0bb89a38667fdf42728e5ff39395f1b378cf2bf0406db0949899510e5a6c86e5a66ae3ef0e741fb894afdcregression_caught=true、browser_tree_reaped=true、browser_port_released=true、profile_removed=true、fixture_server_reaped=truePR 继续保持 Draft,留给维护者完成人工 Desktop UX 审阅。
安全审计
9fc824c...4a80cd7的 62/62 个 source inventory 项,9 个高风险 surface 全部no_issue_found,无 exclusion、deferred 或 open question,0 candidate / 0 reportable finding。审查包含最终 token environment allowlist、standard-user launch、zero-byte endpoint publication、production-adapter hosted smoke 和 cleanup delta;报告已 sealed,scan ID35c14640-fa37-47ee-81f2-4479635fc664。not_runfalse-success。安全扫描的动态限制如实保留:真实运行证据来自 Windows;宿主 command runtime 的 stripped/offline policy 不是 packet-level sandbox;安全结论只覆盖本 PR diff,不把不可信浏览器产物当作源码外安全属性的证明。
非目标与仍需人工证据
video=false;当前强制证据是 PNG + DOM + accessibility + console/page + network/HTTP + performance。GIF/video 属于可选后续能力,不会伪报已采集。not_run中性展示、step timeline、Artifact 下载验证及失败说明。尚未取得的人工交互证据不会写成已完成。Audit