用 security-ownership-map 从 Git 历史画出安全责任拓扑

前言

很多团队都有 CODEOWNERS,也有人会临时跑一下 git blame。真正出事时,问题往往不是「文件写在谁名下」,而是:认证、加密、密钥相关代码到底还有没有人在维护?Bus Factor 是不是低到只剩一个人?纸面责任和提交历史是否已经脱节?

security-ownership-map 就是为这类「安全向所有权」问题准备的 Agent Skill。它基于 Git 历史构建人与文件的二部图,计算敏感代码的 Bus Factor,导出 CSV/JSON,并可导入 Neo4j、Gephi 做可视化。本文按官方 SKILL.md 与脚本说明,介绍它是什么、怎么装、怎么用。

这是什么

security-ownership-map 来自 OpenAI 的 Agent Skills 目录仓库 openai/skills 中的 curated 技能,路径为 skills/.curated/security-ownership-map。它遵循通用的 SKILL.md 格式,可在 Codex、Cursor、Claude Code 等支持 Agent Skills 标准的工具中使用。

官方对它的定位很明确:只在用户明确要做安全向所有权或 Bus Factor 分析时触发,例如孤儿敏感代码、安全维护者识别、对照 CODEOWNERS 做风险核对、敏感热点、所有权聚类等;不要拿它回答普通的「谁是维护者」类问题。

需要说明:openai/skills 仓库 README 已标注 deprecated,新的 Codex skill / plugin 示例转向 openai/plugins。当前仍可从原 curated 目录获取该 Skill 的 SKILL.md、脚本与参考文档。

核心功能与亮点

根据官方说明,主要能力包括:

  1. 人–文件二部图:从 Git 历史构建 people ↔ files 拓扑,刻画「谁碰过哪些文件」。
  2. 敏感代码与 Bus Factor:默认识别常见 auth / crypto / secrets 路径,计算所有权风险;summary.json 中会给出 bus_factor_hotspotsorphaned_sensitive_codehidden_owners 等安全向结论。
  3. 共变图(co-change):按共享提交的 Jaccard 相似度聚类「经常一起改动」的文件;默认忽略 lockfile、.github/*、编辑器配置等「胶水文件」,并默认排除 Dependabot 类提交,减少噪声。
  4. 社区检测:依赖 networkx,默认计算 community,并为每个社区给出 maintainers。
  5. 可查询、可导出:输出 CSV/JSON(可选 GraphML),再用 query_ownership.py 按需取小块 JSON,避免把整张图塞进模型上下文;需要持久化时可按 references/neo4j-import.md 导入 Neo4j。

依赖很简单:Python 3,以及:

pip install networkx

安装与启用

Codex

在 Codex 里可用内置的 $skill-installer 安装 curated 技能(默认对应 skills/.curated):

$skill-installer security-ownership-map

也可直接给出 GitHub 目录 URL。安装后需重启 Codex 以加载新 Skill。

Cursor / Claude Code 等

Skill 本体是一个目录,核心是 SKILL.md,并附带 scripts/references/ 等。按 Agent Skills / Cursor 文档,可把该目录放到工具会扫描的路径,例如:

工具 常见目录(项目级 / 用户级)
Cursor .cursor/skills/~/.cursor/skills/(也兼容 .agents/skills/ 等)
Claude Code .claude/skills/~/.claude/skills/
Codex .agents/skills/ / .codex/skills/ 等(以当前 Codex 文档为准)

手动获取示例:

git clone https://github.com/openai/skills.git
# 将 skills/.curated/security-ownership-map 复制到上述 skills 目录之一
# 目录名保持为 security-ownership-map,内含 SKILL.md

启用后,在 Agent 对话里明确提出「做安全所有权 / Bus Factor 分析」即可;在 Cursor 中也可通过 /security-ownership-map 一类方式显式调用(以当前客户端能力为准)。

典型用法

1. 生成所有权地图

在仓库根目录执行官方 Quick start(路径需按你本地 Skill 安装位置调整):

python skills/skills/security-ownership-map/scripts/run_ownership_map.py \
  --repo . \
  --out ownership-map-out \
  --since "12 months ago" \
  --emit-commits

默认使用 author 身份与 author date,并排除 merge commit。如需改用 committer、或包含 merge,可加 --identity committer--date-field committer--include-merges

输出目录 ownership-map-out/ 中常见产物包括:

  • people.csv / files.csv / edges.csv:人、文件、触摸边
  • cochange_edges.csv:文件共变边(可用 --no-cochange 关闭)
  • summary.json:安全所有权结论摘要
  • communities.jsoncochange.graph.json:社区与图结构
  • commits.jsonl:加了 --emit-commits 时才有
  • ownership.graphml / cochange.graphml:加了 --graphml 时才有

people.csv 还会根据提交时区偏移给出 primary_tz_offsetprimary_tz_minutestimezone_offsets 等字段。

2. 自定义敏感路径规则

默认会标记常见 auth / crypto / secret 路径。若要覆盖,可提供 CSV:

# pattern,tag,weight
**/auth/**,auth,1.0
**/crypto/**,crypto,1.0
**/*.pem,secrets,1.0

然后:

python .../run_ownership_map.py \
  --repo . \
  --out ownership-map-out \
  --sensitive-config path/to/sensitive.csv

3. 用查询脚本取「有界」结果

构建完成后,用 query_ownership.py 按问题切片,例如:

# 孤儿敏感代码(陈旧 + 低 Bus Factor)
python .../query_ownership.py --data-dir ownership-map-out summary --section orphaned_sensitive_code

# 隐性大户(hidden owners)
python .../query_ownership.py --data-dir ownership-map-out summary --section hidden_owners

# 低 Bus Factor 的敏感热点
python .../query_ownership.py --data-dir ownership-map-out summary --section bus_factor_hotspots

# auth / crypto 且 bus_factor <= 1
python .../query_ownership.py --data-dir ownership-map-out files --tag auth --bus-factor-max 1
python .../query_ownership.py --data-dir ownership-map-out files --tag crypto --bus-factor-max 1

# 谁最常碰敏感代码
python .../query_ownership.py --data-dir ownership-map-out people --sort sensitive_touches --limit 10

summary.json 中相关结构大致如下(字段可按需要扩展):

{
  "orphaned_sensitive_code": [
    {
      "path": "crypto/tls/handshake.rs",
      "last_security_touch": "2023-03-12T18:10:04+00:00",
      "bus_factor": 1
    }
  ],
  "hidden_owners": [
    {
      "person": "alice@corp",
      "controls": "63% of auth code"
    }
  ]
}

官方还提供 community_maintainers.py,可按月/季查看某个文件所在社区的维护者变化。

4. 导入图数据库(可选)

需要把 CSV 落到 Neo4j 时,按 Skill 内 references/neo4j-import.md:把 people.csvfiles.csvedges.csv(以及需要的 cochange_edges.csv)放到 Neo4j import 目录,建唯一约束后 LOAD CSV。Gephi 则可分别把人/文件当节点、边文件当边导入。可视化时可用 sensitivity_score > 0 过滤安全相关簇。

适用场景与注意事项

适合:

  • 企业安全 / AppSec 做「敏感路径还有没有人守」的盘点
  • 对照 CODEOWNERS,用提交现实核对所有权漂移
  • 识别 Bus Factor 过低的 auth、crypto 等热点
  • 需要导出 CSV/JSON,再进 Neo4j、Gephi 做复盘或汇报

注意:

  • Skill 描述要求显式安全所有权 / Bus Factor 意图才触发,避免当成通用 blame 工具。
  • git log 过大时用 --since / --until 收窄窗口;共变噪声可用 --cochange-exclude--cochange-max-files 等参数压制。
  • 触摸计数默认按「一次作者提交」计,不是按文件逐次;需要按文件计可用 --touch-mode file。也可用 --window-days--weight recency 等平滑 churn。
  • 分析结果是历史提交统计,不是权限系统真相;敏感路径规则要按仓库实际调整,并与 CODEOWNERS、值班表交叉验证。
  • 上游 openai/skills 已标注废弃,长期集成建议关注官方 Plugins 文档与迁移说明,同时可把 Skill 目录固定进自己的仓库,避免依赖目录仓库生命周期。

小结

security-ownership-map 把 Git 历史变成可查询的安全责任拓扑:建图、算 Bus Factor、标敏感孤儿与隐性大户,再按需导出或导入图库。对企业安全团队来说,它补的是「纸面归属」和「真实提交」之间的那一段空白。

官方地址:https://github.com/openai/skills/tree/main/skills/.curated/security-ownership-map

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜