你们团队负责认证模块的那个人如果明天离职,你知道哪些文件会变成孤儿吗?大多数团队的回答是”不太确定”。CODEOWNERS 文件写了名义归属,但 git log 讲的才是真话。OpenAI 内部安全团队最近释出的 Security Ownership Map,干的事情就是把这两者之间的差距量化出来。
它的思路不复杂:扫一遍 git 历史,提取每个人碰了哪些文件。然后做两件传统安全扫描器不干的事,算 bus factor 和标记孤儿敏感代码,顺便把人和代码之间的”隐藏所有权”也翻出来。这不是另一个”装一下就出报告”的扫描器。它做的是更底层的事,把人、代码、风险三者拉成一张可以查询的图。
从 Smithery 页面来看,这个工具的安装量还不高,只有两位数。但这跟它的价值判断没有直接关系,它面向的是安全工程师和平台团队的日常刚需,而不是大众开发者的尝鲜场景。说真的,这篇文章想把这些能力拆开讲清楚,从安装配到跑完第一份报告,再到那些 JSON 字段到底在说什么。
环境准备
这个工具对依赖的要求轻到让人意外。只需要 Python 3 和 networkx 一个库,没有数据库、没有向量存储、没有需要配置 Token 的后端服务,纯本地跑。OpenAI 把它放在 Smithery 上发布,但实际执行完全不依赖云端。
pip install networkx
安装后从你的项目根目录执行 run_ownership_map.py,指定仓库路径、输出目录和时间窗口就能跑。如果没报 git 相关的错,环境就就绪了。工具内部用 GitPython 或 subprocess 直接调 git 命令,所以你本机的 git 必须可用。
python skills/skills/security-ownership-map/scripts/run_ownership_map.py \
--repo . \
--out ownership-map-out \
--since "12 months ago" \
--emit-commits
第一次跑最可能卡在两个地方。一是仓库太大,git log 跑十几分钟没反应,这时候必须用 –since 把时间窗收窄,或者用 –until 截断。二是 Dependabot 提交太多把共变图撑炸了,工具默认已经排除 Dependabot 和常见 bot,但如果内部 CI 机器人也在高频提交,记得加 –author-exclude-regex 过滤掉。这两个参数决定了你第一次跑下来是顺利还是一头雾水。

操作流程
建图这一步是整个工具的骨架。run_ownership_map.py 遍历 git log,对每次提交提取作者、文件列表、时间戳。它不只看”谁写了哪一行”,还看”哪些文件总是在同一个提交里一起被改”,用 Jaccard 系数算文件间的共变强度。这一步的输出是三张核心 CSV,people.csv 存贡献者节点(附带时区检测信息),files.csv 存文件节点,edges.csv 存人碰了哪个文件的边。
第二步是打标签。工具内置了一套默认的敏感路径规则,auth、crypto、secrets 相关路径自动标记。如果你有自定义的敏感代码定义,传一个 CSV 配置文件就能覆盖,每条规则带一个 weight 字段用来加权计算敏感接触的严重程度。这比简单的关键字匹配靠谱,因为你可以把密钥文件权重设到 1.0,把普通配置文件压到 0.2,让最终的风险排序更贴近真实威胁面。
第三步是算风险,也是最有实战价值的一步。工具自动算三个指标:bus factor(每个文件有多少个”够格”的维护者)、orphaned sensitive code(敏感文件但维护者不足,且最近一次安全相关提交太久)、hidden owners(某些人对某类敏感代码的控制权远超预期)。这些数据存在 summary.json 里。
python skills/skills/security-ownership-map/scripts/query_ownership.py \
--data-dir ownership-map-out \
summary --section orphaned_sensitive_code
第四步是社区检测。工具默认在共变图上跑社区发现算法,把”经常一起被改”的文件聚成一组,给每个社区标上主要维护者。如果需要把整张图导入 Neo4j 或 Gephi 做可视化,传 –graphml 就能导出标准格式。整个流程跑下来,输出目录里是一整套可以持续复用的分析产物,和跑一次就丢的扫描器完全不同。

关键设计
这个工具最聪明的设计,不是它的算法,是它的输出格式决策。每个分析结果都有两种消费方式:直接用 query_ownership.py 查,或者导出到外部图数据库。
query_ownership.py 这个 LLM 查询助手值得单独说。你可以用自然语言级别的命令查出”auth 标签且 bus factor 小于等于 1 的文件”,输出是一个精悍的 JSON 切片,不会把几十 MB 的全量图塞进上下文。这个设计显然是为 AI Agent 的使用场景准备的,团队在选方案时可以把这个能力也放到决策清单里。
另一个值得拆的点是共变图。传统安全分析只看谁碰了哪个文件,这能回答”这个人知道太多”的问题。但共变图回答的是另一个维度:哪些文件在物理上耦合在一起。如果一个攻击者控制了某个开发者,共变图能告诉你随之可能被波及的文件范围。从纵深防御的角度看,这种”文件级攻击面可视化”是一个很有价值的补充视角。
敏感规则的 weight 系统是一个好起点,但潜力没有被完全挖透。当前 weight 只影响 sensitive_touches 的加权计数,如果把 weight 也应用到 bus factor 的分母计算里,高权重敏感文件的 bus factor 阈值自动收紧,产出的风险排序会更符合实际威胁模型。这是一个锦上添花的改进方向,现有能力在大多数场景下已经够用了。

使用场景
这个工具最直接的应用是安全审计。假设你在做 SOC2 或 ISO 27001 认证,审计师会问一个经典问题:”如果有特权访问的人离开,哪些系统会受影响?”传统做法是翻 Confluence 和 CODEOWNERS 文件,然后祈祷文档没过期。用这个工具跑一遍,输出 orphaned_sensitive_code 和 bus_factor_hotspots 两个字段,答案就在那里,而且可复现。
第二种场景更日常,代码审查的上下文判断。当 PR 涉及一个你不熟悉的模块,你想快速知道谁是这段代码的实际维护者。query_ownership.py 传入文件路径就能查到所有触碰过的人、最近触碰时间、触碰频次。这比 git blame 的信息维度高一个层次,因为它考虑了所有权的时间衰减和共变关联。
还有一个容易被忽视的场景是团队调整时的风险预判。如果有人要转岗或休长假,提前跑一遍 ownership map,找出 bus factor = 1 的文件,赶在交接窗口内安排知识传递。这不是”等出事了再排查”,而是把安全前置到组织决策的节奏里。工具默认排除合并提交,这使得分析结果更准确,因为合并提交的作者和实际写代码的人往往不是同一个。
洞察与反思
看过这个工具之后,我个人的判断有三层。
第一,安全风险可视化正在从”找漏洞”转向”找脆弱结构”。传统工具告诉你有未修复的 CVE,Security Ownership Map 告诉你这里只有一个人能修。后者的优先级其实更高,因为漏洞可以排期,单点故障是系统性的,等发现了往往已经来不及。
第二,OpenAI 把这个工具放在 Smithery 上而不是 GitHub Release,这个选择本身有信号意义。它是面向 AI Agent 生态设计的,query_ownership.py 的 bounded JSON 输出就是证据。未来安全审计的一部分流程会被 Agent 自动化,而这个工具的输出格式恰好可以直接嵌入 Agent 的思考循环里,不需要额外做格式转换。
第三,这个工具的局限也很明显。它完全依赖 git 历史,如果你新接手一个仓库、团队刚重组、或者历史记录不干净,分析结果的参考价值会打折扣。另外,它没有把文件重要性纳入风险模型,一个 README 和一个处理用户支付密码的模块在 bus factor 计算里的权重是一样的。这是下一个大版本应该解决的问题,也是它从”有用”到”不可或缺”之间需要跨过的距离。
资源地址
| 资源 | 地址 |
|---|---|
| 官网 | https://smithery.ai/skills/openai/security-ownership-map |
| 作者 | OpenAI |
总结
Security Ownership Map 做的事情本质上不复杂:把 git log 里的人和文件关系拉成一张图,然后在上面跑风险分析。但”不复杂”恰好是它最好的部分。不需要部署任何服务,不需要申请 API Key,不需要学新的查询语言,一条命令出结果。
如果你的团队还没系统做过代码所有权审计,从这个工具开始是最低成本的选择。先从过去 12 个月的主分支跑一次,导出 summary.json,盯着 bus_factor_hotspots 和 orphaned_sensitive_code 两个字段看。大概率你会看到一些让你后背发凉的数字,然后把它加到 CI 里定期跑。安全不是一次性的检查,是一张需要持续更新的地图。
