Preface¶
Many teams have CODEOWNERS set up, and some will run git blame on an ad-hoc basis. When a security incident occurs, the problem is rarely “who owns this file on paper”. Instead, the real questions are: who is still maintaining the authentication, encryption, and key-related code? Is the Bus Factor so low that only one person is left? Have the documented ownership and commit history drifted apart?
security-ownership-map is an Agent Skill designed specifically for these “security-focused ownership” problems. It builds a bipartite graph of people and files based on Git history, calculates the Bus Factor of sensitive code, exports results in CSV/JSON formats, and can be imported into Neo4j or Gephi for visualization. This article introduces what it is, how to install it, and how to use it, based on the official SKILL.md and script documentation.
What is it¶
security-ownership-map is a curated skill from OpenAI’s Agent Skills repository openai/skills, located at skills/.curated/security-ownership-map. It follows the standard SKILL.md format and can be used in tools that support the Agent Skills standard, such as Codex, Cursor, and Claude Code.
The official positioning of this skill is very clear: it should only be triggered when the user explicitly requests security-focused ownership or Bus Factor analysis, such as orphaned sensitive code identification, security maintainer discovery, risk verification against CODEOWNERS, sensitive hotspots analysis, and ownership clustering. Do not use it to answer generic questions like “who is the maintainer”.
Note that the README of the openai/skills repository has been marked as deprecated, and new Codex skill/plugin examples have moved to openai/plugins. You can still obtain this skill’s SKILL.md, scripts, and reference documentation from the original curated directory.
Core Features and Highlights¶
According to the official documentation, its main capabilities include:
- People-Files Bipartite Graph: Build a people ↔ files topology from Git history to characterize “who has modified which files”.
- Sensitive Code and Bus Factor: Identify common auth/crypto/secrets paths by default to calculate ownership risks. The
summary.jsonfile will include security-focused conclusions such asbus_factor_hotspots,orphaned_sensitive_code, andhidden_owners. - Co-change Graph: Cluster files that are “often modified together” based on the Jaccard similarity of shared commits; lockfiles,
.github/*, editor configuration and other “glue files” are ignored by default, and Dependabot-style commits are excluded by default to reduce noise. - Community Detection: Relies on
networkxto calculate communities by default and assign maintainers for each community. - Queryable and Exportable: Outputs CSV/JSON (and optionally GraphML), and you can use
query_ownership.pyto extract small chunks of JSON on demand to avoid flooding the model context with the entire graph. For persistent storage, you can import the data into Neo4j according toreferences/neo4j-import.md.
The dependencies are very simple: Python 3, plus:
pip install networkx
Installation and Activation¶
Codex¶
You can use the built-in $skill-installer to install curated skills in Codex (it corresponds to skills/.curated by default):
$skill-installer security-ownership-map
You can also directly provide the GitHub directory URL. After installation, you need to restart Codex to load the new Skill.
Cursor / Claude Code and others¶
The Skill itself is a directory, with SKILL.md as the core, plus scripts/, references/ and other subdirectories. According to the Agent Skills / Cursor documentation, you can place this directory in a path that the tool will scan, for example:
| Tool | Common directories (project-level / user-level) |
|---|---|
| Cursor | .cursor/skills/ or ~/.cursor/skills/ (also compatible with .agents/skills/ and others) |
| Claude Code | .claude/skills/ or ~/.claude/skills/ |
| Codex | .agents/skills/ / .codex/skills/ and others (refer to the current Codex documentation) |
Example of manual acquisition:
git clone https://github.com/openai/skills.git
# Copy skills/.curated/security-ownership-map to one of the above skills directories
# Keep the directory name as security-ownership-map, which must contain SKILL.md
After activation, explicitly request “security ownership / Bus Factor analysis” in the Agent conversation; in Cursor, you can also call it explicitly via /security-ownership-map or similar methods (subject to the current client capabilities).
Typical Usage¶
1. Generate Ownership Map¶
Run the official Quick start in the repository root directory (adjust the path according to your local Skill installation location):
python skills/skills/security-ownership-map/scripts/run_ownership_map.py \
--repo . \
--out ownership-map-out \
--since "12 months ago" \
--emit-commits
By default, it uses the author identity and author date, and excludes merge commits. If you want to use committer instead, or include merge commits, you can add --identity committer, --date-field committer, and --include-merges.
Common output files in the ownership-map-out/ directory include:
- people.csv / files.csv / edges.csv: People, files, and touch edges
- cochange_edges.csv: File co-change edges (can be disabled with --no-cochange)
- summary.json: Security ownership conclusion summary
- communities.json, cochange.graph.json: Community and graph structure
- commits.jsonl: Available only when --emit-commits is added
- ownership.graphml / cochange.graphml: Available only when --graphml is added
The people.csv file will also include fields such as primary_tz_offset, primary_tz_minutes, and timezone_offsets based on the commit time zone offset.
2. Customize Sensitive Path Rules¶
By default, it marks common auth/crypto/secret paths. If you want to override the rules, you can provide a CSV file:
# pattern,tag,weight
**/auth/**,auth,1.0
**/crypto/**,crypto,1.0
**/*.pem,secrets,1.0
Then run:
python .../run_ownership_map.py \
--repo . \
--out ownership-map-out \
--sensitive-config path/to/sensitive.csv
3. Use the Query Script to Get “Bounded” Results¶
After building the graph, use query_ownership.py to slice results by query conditions, for example:
# Orphaned sensitive code (stale + low 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
# Sensitive hotspots with low Bus Factor
python .../query_ownership.py --data-dir ownership-map-out summary --section bus_factor_hotspots
# auth/crypto code with 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
# Who has modified sensitive code the most
python .../query_ownership.py --data-dir ownership-map-out people --sort sensitive_touches --limit 10
The relevant structure in summary.json is roughly as follows (fields can be extended as needed):
{
"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"
}
]
}
The official also provides community_maintainers.py, which can be used to view changes in maintainers of the community where a file belongs on a monthly or quarterly basis.
4. Import to Graph Database (Optional)¶
If you need to import the CSV data into Neo4j, follow the instructions in references/neo4j-import.md inside the Skill: place people.csv, files.csv, edges.csv (and cochange_edges.csv if needed) into the Neo4j import directory, create unique constraints, then use LOAD CSV to import the data. For Gephi, you can import people and files as nodes, and the edge files as edges respectively. When visualizing, you can filter security-related clusters with sensitivity_score > 0.
Applicable Scenarios and Notes¶
Applicable scenarios:
- Enterprise security/AppSec teams conducting inventory of “who is still maintaining sensitive paths”
- Verifying ownership drift against CODEOWNERS using commit history
- Identifying auth, crypto and other hotspots with overly low Bus Factor
- Needing to export CSV/JSON data for post-incident review or reporting, then importing it into Neo4j or Gephi
Important notes:
- The Skill description requires that you must explicitly state your intent to conduct security ownership / Bus Factor analysis before triggering it, to avoid treating it as a generic blame tool.
- If the git log output is too large, narrow the time window with --since / --until; you can suppress co-change noise with parameters such as --cochange-exclude and --cochange-max-files.
- By default, touch counts are calculated based on “one author commit per file”, not per file modification; use --touch-mode file to count by file. You can also smooth churn with --window-days, --weight recency and other parameters.
- The analysis results are based on historical commit statistics, not the truth of the permission system; you should adjust the sensitive path rules according to the actual situation of the repository, and cross-verify with CODEOWNERS and on-call schedules.
- The upstream openai/skills repository has been marked as deprecated. For long-term integration, please refer to the official Plugins documentation and migration instructions, and you can fix the Skill directory into your own repository to avoid relying on the lifecycle of the upstream repository.
Summary¶
security-ownership-map turns Git history into queryable security responsibility topology: builds graphs, calculates Bus Factor, identifies orphaned sensitive code and hidden owners, and exports or imports the results into a graph database as needed. For enterprise security teams, it fills the gap between “paper-based ownership” and “real commit history”.
Official address: https://github.com/openai/skills/tree/main/skills/.curated/security-ownership-map