oh-my-openagent 的 omo-native 遥测范围保真审计:单一采集路径、隐私白名单与包体积预算的八项守门实践

发布时间:2026/9/19 11:19:34
oh-my-openagent 的 omo-native 遥测范围保真审计:单一采集路径、隐私白名单与包体积预算的八项守门实践
oh-my-openagent 的 omo-native 遥测范围保真审计单一采集路径、隐私白名单与包体积预算的八项守门实践【免费下载链接】oh-my-openagentOmO: Just type mass ulw keyword with your prompt. Now you are the master of graph engineering.项目地址: https://gitcode.com/gh_mirrors/oh/oh-my-openagentOmOoh-my-openagent在omo-senpi扩展中落地了一套全新的产品遥测omo-native telemetry而f4.md是这套功能合入前的**范围保真审计Scope-Fidelity Audit**记录它以只读方式逐条核对分支 diff 是否完全落在计划的 15 个实现 todo1–14含 13a/13b之内确认必须不包含Must NOT清单零违反、无解释不清的文件。读完本文你将掌握一条可复用的遥测合入守门方法论如何用源码扫描不变量单一采集路径、依赖与公共面 diff、隐私键白名单、包体积预算偏差审批来约束一次功能合入并能在本仓库的packages/omo-senpi与packages/telemetry-core中逐一验证这些结论。1. 审计对象与判据一份APPROVE结论从何而来f4.md针对的是feat/omo-native-telemetry分支相对origin/dev的 diff审计时点17 个提交、61 个被改动文件其依据是计划文档 .omo/plans/omo-native-telemetry.md 中的Must NOT have章节。审计者的角色被明确限定为只读范围审计不参与实现创作——这保证了结论的独立性。最终裁决为APPROVE背后是八项逐条检查全部通过外加一项已授权的偏差8 项必须检查single capture path、无新运行时依赖、相邻适配器零改动、旧语义不变、无可采集敏感数据、包体积预算、无 spill queue、GeoIP 禁用全部 PASS分支 diff 中的每个文件都能映射到 15 个 todo 之一、生成产物或 todo 所需证据无一个解释不清的文件唯一偏离 Must-NOT 清单的地方BUDGET_BYTES从 880,000 上调到精确的 900,000且源码中写有专门的 trim 尝试与 bundle 纯净性理由临时重建证明跟踪的扩展产物是最新的tracked 与磁盘 SHA-256 一致产物 891,384 字节两项 bundle 测试均通过。这套先定边界、再合入、最后逐项复核的做法对任何涉及用户数据上报的功能改造都有直接参考价值。2. 单一采集路径把 transport.capture 收敛到一个包装桥2.1 源码扫描不变量第一项检查的目标是整个 telemetry 目录里只有omo-native-component.ts可以触碰底层 transport 的capture方法其余所有事件生产者必须经过 telemetry-core 的captureEvent隐私包装。审计命令在仓库根目录执行如下files$(git diff --name-only origin/dev...HEAD -- packages/omo-senpi/src/components/telemetry/*.ts \ | grep -v ^packages/omo-senpi/src/components/telemetry/omo-native-component.ts$) if rg -n \.capture\s*\( $files; then echo FAIL exit 1 else echo PASS: no direct .capture( outside omo-native-component.ts telemetry-core wrapper transport bridge fi真实输出只命中两处均位于 omo-native-component.tspackages/omo-senpi/src/components/telemetry/omo-native-component.ts:112: transport.capture(message) packages/omo-senpi/src/components/telemetry/omo-native-component.ts:149: transport.capture(payload)对照当前源码这两处正是包装桥的两半sharedTransportFactory返回的包装 transport 在capture中先调用installCaptureFacade安装白名单投影 facade再forwardValidatedCapture(transport, message)放行omo-native-component.ts而forwardValidatedCapture的注释明确写道这是唯一的 native transport 边界到达这里的每条消息都已通过 telemetry-core captureEvent 隐私包装把原始 transport 调用保留在这里让源码扫描不变量精确并防止事件生产者绕过校验omo-native-component.ts。从源码结构看这个设计把隐私校验和网络出口拆成了两层上层各组件prompt、session、turns、tools 等只持有client.captureEvent下层只有一个函数能真正把消息交给 transport扫描器只需盯住这一处。2.2 交互路径上不允许网络与 await第二道防线是native 交互路径上不得出现 fetch/HTTP 请求或 await capture/flush。审计扫描\b(fetch|request|http|https)\s*\(|await .*capture|await .*flush|await .*shutdown|\.capture\s*\(后的真实输出显示packages/omo-senpi/src/components/telemetry/omo-native-session.ts:129: await activeClient?.shutdown() packages/omo-senpi/src/components/telemetry/omo-native-component.ts:112: transport.capture(message) packages/omo-senpi/src/components/telemetry/omo-native-component.ts:118: await transport.shutdown() packages/omo-senpi/src/components/telemetry/omo-native-component.ts:149: transport.capture(payload)唯一的await全部是 shutdown 相关session_shutdown事件里对 active client 的shutdown()omo-native-session.ts与包装 transport 的shutdownomo-native-component.ts。这意味着遥测采集永远不会阻塞用户交互路径——这是遥测不得影响主流程这一工程原则的源码级落实。3. 零新增依赖与相邻适配器不动公共面只增不改3.1 两个 package.json 零 diff审计对packages/omo-senpi/package.json与packages/telemetry-core/package.json执行 diff并单独抓取行中的依赖声明git diff origin/dev...HEAD -- packages/omo-senpi/package.json packages/telemetry-core/package.json git diff -U0 origin/dev...HEAD -- packages/omo-senpi/package.json packages/telemetry-core/package.json \ | grep -E ^\[^].*[^][[:space:]]*: || true真实输出三项均为空——两个清单都没变dependencies自然没有新增条目。从当前仓库看posthog-node是telemetry-core本就存在的传输依赖被复用而非新引入可对比 packages/telemetry-core/package.json 与 packages/telemetry-core/src/posthog-client.ts。3.2 公共面只增不改对packages/telemetry-core/src/index.ts、packages/telemetry-core/index.d.ts、packages/telemetry-core/src/types.ts做 diff 并过滤删除行if git diff -U0 origin/dev...HEAD -- \ packages/telemetry-core/src/index.ts packages/telemetry-core/index.d.ts packages/telemetry-core/src/types.ts \ | grep -E ^-[^-].*(export|readonly); then echo FAIL else echo PASS: shared telemetry-core public surface has additions only, no removed export/type field fi输出PASS共享包对外暴露面只有新增wrapper/批处理 API、onCapture回调、诊断类型等没有任何被移除的导出或类型字段。这种只增不改策略让下游消费者零风险升级。3.3 相邻适配器零改动 全局 DO_NOT_TRACK 例外对packages/omo-opencode与packages/omo-codex的 diff 结果为空——相邻适配器源码一个文件都没改。跨适配器相关的全部 diff 集中在packages/telemetry-core内部其中env.ts是唯一的行为变更新增全局DO_NOT_TRACK退出开关。对照当前 env.tsif (isDisableFlag(env[DO_NOT_TRACK])) { return true }shouldDisableTelemetry先查全局DO_NOT_TRACK再查各产品的OMO_*_DISABLE_POSTHOG与OMO_*_SEND_ANONYMOUS_TELEMETRY值归一化支持1/true/yes与0/false/no见 env.ts。配套测试覆盖了omo-opencode、omo-codex、omo-senpi三个产品在DO_NOT_TRACK1下全部禁用、0与未设置时保持启用以及带空格的大小写混合值归一化(pass) DO_NOT_TRACK global opt-out #given DO_NOT_TRACK is 1 #when evaluated for omo-senpi #then telemetry is disabled (pass) DO_NOT_TRACK global opt-out #given DO_NOT_TRACK is not an opt-out value #when the value is 0 #then telemetry remains enabled 22 pass / 0 fail / 22 expect() calls对应的测试文件为 packages/telemetry-core/src/env.test.ts。4. 旧遥测语义不变index.ts 只加 barrel 导出新功能引入时最常见的风险是顺手改坏旧行为。审计对packages/omo-senpi/src/components/telemetry/index.ts与packages/telemetry-core/src/record-daily-active.ts做了 diffindex.ts的 diff 只有一段追加export * from ./omo-native-*与export * from ./product-identity共 8 行 barrel 导出其遗留事件配置、payload 构造、machine-ID 前缀、状态目录与旧组件逐字节未变record-daily-active.ts的git diff --exit-code返回 0即零 diff——旧版每日活跃去重门与采集语义原封不动。关键设计是被放宽的采集门例如DO_NOT_TRACK或omo.json关闭时新旧两条链路都静默在新的 native session 组合层实现再调用未改动的旧 recorder。回归测试用--test-name-pattern native and legacy telemetry both emit nothing|legacy marker验证了三件事omo-native-session.test.ts(pass) #given DO_NOT_TRACK #when session_start fires #then native and legacy telemetry both emit nothing (pass) #given omo.json telemetry.enabled false #when session_start fires #then native and legacy telemetry both emit nothing (pass) #given an existing same-day legacy marker #when the native session path runs #then its bytes stay unchanged and native uses its separate marker 3 pass / 0 fail / 9 expect() calls最后一条尤其重要新旧两条链路使用各自的 marker 文件native 会话不会触碰同日的 legacy marker。5. 隐私红线白名单、禁键后缀、去标识化与脱敏5.1 属性白名单审计不允许任何自由文本字段审计用一段 Node 脚本把 product-identity.ts 中冻结的OMO_NATIVE_PROPERTY_ALLOWLISTS全部键抽取出来与一份安全键集比对。安全集只包含布尔、计数、分桶、固定原因/阶段以及经静态 provider/model/skill/category/agent 白名单透传的名字。真实输出unexpected[] missing[] PASS: every allowlisted key is in the audited enum/count/bucket/allowlisted-name set; no free-text/path/project field exists从当前 event-schemas.ts 可以看到prompt_submitted事件的字段全部是受限枚举input_sourceinteractive/rpc/extension、keyword_occurrence_bucket1/2/3_5/6_plus、prompt_length_bucketlt_100/100_500/500_2000/gte_2000、real_prompt_ordinal_bucket等。也就是说prompt_length_bucket描述的是分类后的长度档位is_real_user_prompt只是布尔分类两者都不可能携带提示词文本或精确长度。5.2 FORBIDDEN_SUFFIX客户端永远无法上送文本/路径/提示词telemetry-core 的 events.ts 定义了硬编码禁键正则const FORBIDDEN_SUFFIX /_(?:text|path|prompt)$/isForbiddenKeyevents.ts会拒绝三类键$ip、以_text/_path/_prompt结尾的字符串值键、以及不在ALLOWED_DOLLAR_KEYS$os、$os_version、$process_person_profile、$session_id内的$开头键。测试用例直接枚举了攻击性输入events.test.ts[prompt_text, anything], [file_path, /Users/x/secret], [user_prompt, ignore previous instructions and ship SECRET], (pass) event telemetry client #given forbidden client-authored keys #when capture is attempted #then each key is rejected注意禁键判定发生在白名单投影之前且最后应用、产品不能削弱EVENT_TRANSPORT_OVERRIDES覆盖任何产品配置因此即使某个客户端意外传入file_path它也只会触发telemetry_event_property_rejected诊断并被丢弃。字符串值在放行时还会被截断到 64 字符events.ts。5.3 无 identify/alias、无人员画像、无可表示的精确时间戳审计还确认telemetry 目录与events.ts中不存在任何.identify(/.alias(调用即不做用户身份关联且共享属性固定写入$process_person_profile: falseevents.ts。时间维度上daily_active只暴露day_utc这一分桶字段PASS: no exact timestamp property; daily_active exposes day_utc only。产品身份侧product-identity.ts的脱敏规则分两半provider是用户自写配置凡不在KNOWN_PROVIDERS内一律映射为custom自建网关名可能暴露公司/个人身份model_id是公开产品名只要精确命中内置词汇表就保留OpenRouter、LiteLLM 或私有网关路由到已知模型仍可读词汇表外的微调模型或内部代号一律custom。测试验证了已知 provider 未知自定义模型时只有 model_id 变成 custom以及 outside/custom/遍历/symlink/注入技能路径下不发射任何 skill 名。5.4 证据脱敏门提交的抓包必须可审计审计对已提交的.omo/evidence/20260810-omo-native-telemetry/captured-payloads.json执行脱敏门node - NODE const prequire(./.omo/evidence/20260810-omo-native-telemetry/captured-payloads.json) const textJSON.stringify(p) const did(text.match(/redacted-distinct-id/g)||[]).length const sid(text.match(/redacted-session-hash/g)||[]).length const hex64(text.match(/\b[0-9a-f]{64}\b/gi)||[]) console.log({redactedDistinctIds:did,redactedSessionHashes:sid,raw64HexValues:hex64}) NODE输出{ redactedDistinctIds: 16, redactedSessionHashes: 15, raw64HexValues: [] }且本机 hostname 在证据目录中不存在——16 个 distinct id 与 15 个会话哈希全部替换为占位符64 位十六进制原始值零残留。6. 包体积预算偏差一次有书面理由的 880,000 → 900,0006.1 精确预算与理由注释审计要求要么满足预算、要么有授权偏差。packages/omo-senpi/src/bundle-size.test.ts中恰好只有一处const BUDGET_BYTES 900_000其上方的注释就是完整理由bundle-size.test.ts// Raised 880,000 - 900,000 for plan omo-native-telemetry: the plan-scoped first-party feature code // is wired into the extension entry and grew the freshly rebuilt bundle to a measured 891,384 bytes. // No new third-party dependency was inlined; posthog-node was already present, and // bundle-purity.test.ts passes on the new build. A trim was attempted and rejected because reclaiming // the bytes would require a secondary chunk and loader-topology change. The round 900,000 ceiling // preserves explicit headroom instead of raising the budget to the failing value. const BUDGET_BYTES 900_000这份理由的信息量在于记录了新旧上限、实测字节数、未内联任何新第三方依赖posthog-node 本就存在、bundle-purity 结果、尝试过裁剪但被拒绝回收字节需要改动 loader 拓扑/次 chunk以及取整的 900,000 上限保留显式余量而不是把预算抬高到恰好等于失败值。6.2 新鲜构建、哈希、大小与纯净性为了避免触碰工作区审计直接调用顶层脚本导出的checkExtensionCurrent()——它在全新临时目录重建所有扩展入口比较源码/正文摘要与磁盘产物然后删除临时目录node --input-typemodule - NODE import { checkExtensionCurrent } from ./packages/omo-senpi/plugin/scripts/build-extension.mjs const result await checkExtensionCurrent() console.log(JSON.stringify(result)) if (!result.ok) process.exit(1) NODE git show HEAD:packages/omo-senpi/plugin/extensions/omo.js | shasum -a 256 shasum -a 256 packages/omo-senpi/plugin/extensions/omo.js bytes$(wc -c packages/omo-senpi/plugin/extensions/omo.js | tr -d )真实输出证明跟踪产物就是当前构建Bundled 781 modules in 29ms omo.js 0.89 MB (entry point) Bundled 279 modules in 11ms omo-member.js 117.61 KB (entry point) Bundled 61 modules in 5ms omo-memory-mcp.js 49.37 KB (entry point) {ok:true,output:.../packages/omo-senpi/plugin/extensions/omo.js,memberOutput:.../packages/omo-senpi/plugin/extensions/omo-member.js} 7d9731f575a7e79f2ba05046c0fce3267e285fd8e1c1edfa312194cee6e78a74 - 7d9731f575a7e79f2ba05046c0fce3267e285fd8e1c1edfa312194cee6e78a74 packages/omo-senpi/plugin/extensions/omo.js bytes891384 budget900000 PASS: artifact is within budgetgit 跟踪版本与磁盘版本的 SHA-256 完全一致7d9731f5...891,384 ≤ 900,000。随后的 bundle-size.test.ts 与 bundle-purity.test.ts 双双通过——后者确认静态导入中只有 senpi 同类包与 Node 内置模块保持 external共享构建常量钉住了全部 19 个 peer。7. 范围护栏无 spill queue、无 ulw_loop 枚举、一次通知7.1 延迟工作的排除Must-NOT 清单还包括两项不得提前夹带的工作spill/retry queue 与ulw_loop特性枚举。审计分别按文件名与按新增行扫描NO_SPILL_NAMED_FILES PASS: no spill/retry queue file NO_SPILL_ADDED_LINES PASS: no spill/retry queue added line NO_ULW_LOOP_TOKEN_IN_FEATURE_FUNCTION PASS从当前 omo-native-tools.ts 的featureForTool看特性枚举只有三项与ulw-loop无关function featureForTool(toolName: string): goal_tool | team_create | memory_tool | undefined { if (matchesToolName(toolName, create_goal)) return goal_tool if (matchesToolName(toolName, team_create)) return team_create if (matchesToolName(toolName, memory_apply_patch) || matchesToolName(toolName, memory)) return memory_tool return undefined }ulw-loop仅以内置技能名出现在技能白名单中见 event-schemas.ts 的BUILTIN_SKILL_NAMES这是技能 allowlisting 所必需的与feature_used枚举无关。7.2 配置隔离与 Ultrawork 只读分类文档确认telemetry配置块只控制 Senpi 的 omo-native 遥测telemetry.enabled是布尔值、默认true即开箱即用且与codegraph.telemetry完全隔离见 docs/reference/senpi-telemetry.md 中的原文引用。同时没有在生产路径添加任何 opt-in/consent 门。Ultrawork 分类保持只读omo-native-prompt.ts通过armingSnapshot(sessionId)取快照、classifyUltraworkInput({ text, source }, snapshot)做纯分类ultrawork/index.ts扩展来源被归类为extension_source抑制原因。45 个 ultrawork 测试244 次 expect证明相同快照重复分类结果一致、共享武装状态三次读取恒等、抑制路径下不发射任何消息且会话账本保持未武装。7.3 通知恰好一次不烦扰用户omo-native-notice.ts中的通知文案为const NOTICE omo-senpi sends anonymous usage telemetry (no prompts, no paths). Docs: ${DOCS_URL} - opt out: DO_NOT_TRACK1即匿名使用遥测不含提示词、不含路径退出方式DO_NOT_TRACK1。测试用并发与陈旧 marker 场景钉死了恰好一次语义omo-native-notice.test.ts(pass) #given enabled telemetry #when two consecutive session_start events fire #then the notice is sent exactly once (pass) #given a stale marker #when a later registration starts a session #then the notice stays suppressed (pass) #given two racing session_start events #when both attempt the first notice #then the marker admits only one notification 8 pass / 0 fail / 22 expect() calls8. GeoIP 与产品身份审计时点与当前仓库的演进审计时点的createOmoNativeProductConfig()显式固定disableGeoip: true、machineIdPrefix: omo-senpi:、cacheDirName: omo-native、eventName: daily_active、productEnvPrefix: OMO_SENPI配合$process_person_profile: false与零 identify/alias实现身份派生与地域禁用。需要说明的是后续仓库演进中GeoIP 策略已从 product config 迁移到 telemetry-core 的传输覆盖层——当前 events.ts 的EVENT_TRANSPORT_OVERRIDES中disableGeoip: false其注释解释了设计取舍关闭本地禁用、让 PostHog 服务端从传输源 IP 派生$geoip_country_code是回答按国家统计问题的唯一诚实方式设备时区不是国家且应用永远不会亲自写入$ip$ip仍是拒绝键、不存储 IP、保持$process_person_profile: false。审计文档所验证的隐私边界$ip拒绝、person profile 关闭、无 identify/alias在当前代码中依然成立变化的只是地域信息的派生位置。会话 id 依旧以持久化盐做 SHA-256 哈希session-id-salt见 product-identity.ts盐被删除或状态目录不可写时均有稳定的 fallback身份逻辑永远不会阻塞宿主。9. 结论与文件映射一份可复用的合入收尾清单f4.md的最终范围判定为Must-NOT 违反0解释不清的文件0相邻适配器源码改动0新运行时依赖0包装桥之外的直接 native transport 采集路径0夹带的 spill queue /ulw_loop特性工作0授权预算偏差880,000 → 900,000已核验证据按 todo 1–14 分散在.omo/evidence/20260810-omo-native-telemetry/下的task-1.md至task-14.md含 13a/13b配套captured-payloads.json脱敏抓包、cleanup-receipt.json清理证明与transcript.txt真实面交互记录自动化 QA 脚本为 script/qa/omo-native-telemetry-qa.mjs生成的文档 schema 块由 script/telemetry-schema-block.mjs 产出并写入 docs/reference/senpi-telemetry.md 与 docs/reference/omo-json.md。合入侧的核心源码清单均可继续深入组合与包装桥packages/omo-senpi/src/components/telemetry/omo-native-component.ts会话/每日活跃生命周期packages/omo-senpi/src/components/telemetry/omo-native-session.ts产品身份/脱敏/状态目录packages/omo-senpi/src/components/telemetry/product-identity.ts事件 schema 与属性白名单packages/omo-senpi/src/components/telemetry/event-schemas.ts隐私包装与传输覆盖packages/telemetry-core/src/events.ts、packages/telemetry-core/src/env.ts包体积门packages/omo-senpi/src/bundle-size.test.ts、packages/omo-senpi/src/bundle-purity.test.ts这套范围保真审计的通用动作值得沉淀为每次敏感功能合入的收尾清单先定 Must-NOT 边界 → diff 清单与 todo 一一映射 → 用源码扫描不变量守单一出口 → 用只增不改保护公共面 → 用键白名单与禁键后缀封死敏感数据 → 用书面理由审批预算偏差 → 用脱敏门保证证据可公开。八项检查全绿APPROVE 才成立。【免费下载链接】oh-my-openagentOmO: Just type mass ulw keyword with your prompt. Now you are the master of graph engineering.项目地址: https://gitcode.com/gh_mirrors/oh/oh-my-openagent创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考