Analyze git repositories to build a security ownership topology (people-to-file), compute bus factor and sensitive-code ownership, and export CSV/JSON for graph databases and visualization. Trigger only when the user explicitly wants a security-oriented ownership or bus-factor analysis grounded in git history (for example: orphaned sensitive code, security maintainers, CODEOWNERS reality checks for risk, sensitive hotspots, or ownership clusters).
Add this skill
npx mdskills install openai/security-ownership-mapSecurity-focused git ownership analysis with bus factor, co-change clustering, and queryable artifacts
1---2name: "security-ownership-map"3description: "Analyze git repositories to build a security ownership topology (people-to-file), compute bus factor and sensitive-code ownership, and export CSV/JSON for graph databases and visualization. Trigger only when the user explicitly wants a security-oriented ownership or bus-factor analysis grounded in git history (for example: orphaned sensitive code, security maintainers, CODEOWNERS reality checks for risk, sensitive hotspots, or ownership clusters). Do not trigger for general maintainer lists or non-security ownership questions."4---56# Security Ownership Map78## Overview910Build a bipartite graph of people and files from git history, then compute ownership risk and export graph artifacts for Neo4j/Gephi. Also build a file co-change graph (Jaccard similarity on shared commits) to cluster files by how they move together while ignoring large, noisy commits.1112## Requirements1314- Python 315- `networkx` (required; community detection is enabled by default)1617Install with:1819```bash20pip install networkx21```2223## Workflow24251. Scope the repo and time window (optional `--since/--until`).262. Decide sensitivity rules (use defaults or provide a CSV config).273. Build the ownership map with `scripts/run_ownership_map.py` (co-change graph is on by default; use `--cochange-max-files` to ignore supernode commits).284. Communities are computed by default; graphml output is optional (`--graphml`).295. Query the outputs with `scripts/query_ownership.py` for bounded JSON slices.306. Persist and visualize (see `references/neo4j-import.md`).3132By default, the co-change graph ignores common “glue” files (lockfiles, `.github/*`, editor config) so clusters reflect actual code movement instead of shared infra edits. Override with `--cochange-exclude` or `--no-default-cochange-excludes`. Dependabot commits are excluded by default; override with `--no-default-author-excludes` or add patterns via `--author-exclude-regex`.3334If you want to exclude Linux build glue like `Kbuild` from co-change clustering, pass:3536```bash37python skills/skills/security-ownership-map/scripts/run_ownership_map.py \38 --repo /path/to/linux \39 --out ownership-map-out \40 --cochange-exclude "**/Kbuild"41```4243## Quick start4445Run from the repo root:4647```bash48python skills/skills/security-ownership-map/scripts/run_ownership_map.py \49 --repo . \50 --out ownership-map-out \51 --since "12 months ago" \52 --emit-commits53```5455Defaults: author identity, author date, and merge commits excluded. Use `--identity committer`, `--date-field committer`, or `--include-merges` if needed.5657Example (override co-change excludes):5859```bash60python skills/skills/security-ownership-map/scripts/run_ownership_map.py \61 --repo . \62 --out ownership-map-out \63 --cochange-exclude "**/Cargo.lock" \64 --cochange-exclude "**/.github/**" \65 --no-default-cochange-excludes66```6768Communities are computed by default. To disable:6970```bash71python skills/skills/security-ownership-map/scripts/run_ownership_map.py \72 --repo . \73 --out ownership-map-out \74 --no-communities75```7677## Sensitivity rules7879By default, the script flags common auth/crypto/secret paths. Override by providing a CSV file:8081```82# pattern,tag,weight83**/auth/**,auth,1.084**/crypto/**,crypto,1.085**/*.pem,secrets,1.086```8788Use it with `--sensitive-config path/to/sensitive.csv`.8990## Output artifacts9192`ownership-map-out/` contains:9394- `people.csv` (nodes: people)95- `files.csv` (nodes: files)96- `edges.csv` (edges: touches)97- `cochange_edges.csv` (file-to-file co-change edges with Jaccard weight; omitted with `--no-cochange`)98- `summary.json` (security ownership findings)99- `commits.jsonl` (optional, if `--emit-commits`)100- `communities.json` (computed by default from co-change edges when available; includes `maintainers` per community; disable with `--no-communities`)101- `cochange.graph.json` (NetworkX node-link JSON with `community_id` + `community_maintainers`; falls back to `ownership.graph.json` if no co-change edges)102- `ownership.graphml` / `cochange.graphml` (optional, if `--graphml`)103104`people.csv` includes timezone detection based on author commit offsets: `primary_tz_offset`, `primary_tz_minutes`, and `timezone_offsets`.105106## LLM query helper107108Use `scripts/query_ownership.py` to return small, JSON-bounded slices without loading the full graph into context.109110Examples:111112```bash113python skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out people --limit 10114python skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out files --tag auth --bus-factor-max 1115python skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out person --person alice@corp --limit 10116python skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out file --file crypto/tls117python skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out cochange --file crypto/tls --limit 10118python skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out summary --section orphaned_sensitive_code119python skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out community --id 3120```121122Use `--community-top-owners 5` (default) to control how many maintainers are stored per community.123124## Basic security queries125126Run these to answer common security ownership questions with bounded output:127128```bash129# Orphaned sensitive code (stale + low bus factor)130python skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out summary --section orphaned_sensitive_code131132# Hidden owners for sensitive tags133python skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out summary --section hidden_owners134135# Sensitive hotspots with low bus factor136python skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out summary --section bus_factor_hotspots137138# Auth/crypto files with bus factor <= 1139python skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out files --tag auth --bus-factor-max 1140python skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out files --tag crypto --bus-factor-max 1141142# Who is touching sensitive code the most143python skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out people --sort sensitive_touches --limit 10144145# Co-change neighbors (cluster hints for ownership drift)146python skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out cochange --file path/to/file --min-jaccard 0.05 --limit 20147148# Community maintainers (for a cluster)149python skills/skills/security-ownership-map/scripts/query_ownership.py --data-dir ownership-map-out community --id 3150151# Monthly maintainers for the community containing a file152python skills/skills/security-ownership-map/scripts/community_maintainers.py \153 --data-dir ownership-map-out \154 --file network/card.c \155 --since 2025-01-01 \156 --top 5157158# Quarterly buckets instead of monthly159python skills/skills/security-ownership-map/scripts/community_maintainers.py \160 --data-dir ownership-map-out \161 --file network/card.c \162 --since 2025-01-01 \163 --bucket quarter \164 --top 5165```166167Notes:168- Touches default to one authored commit (not per-file). Use `--touch-mode file` to count per-file touches.169- Use `--window-days 90` or `--weight recency --half-life-days 180` to smooth churn.170- Filter bots with `--ignore-author-regex '(bot|dependabot)'`.171- Use `--min-share 0.1` to show stable maintainers only.172- Use `--bucket quarter` for calendar quarter groupings.173- Use `--identity committer` or `--date-field committer` to switch from author attribution.174- Use `--include-merges` to include merge commits (excluded by default).175176### Summary format (default)177178Use this structure, add fields if needed:179180```json181{182 "orphaned_sensitive_code": [183 {184 "path": "crypto/tls/handshake.rs",185 "last_security_touch": "2023-03-12T18:10:04+00:00",186 "bus_factor": 1187 }188 ],189 "hidden_owners": [190 {191 "person": "alice@corp",192 "controls": "63% of auth code"193 }194 ]195}196```197198## Graph persistence199200Use `references/neo4j-import.md` when you need to load the CSVs into Neo4j. It includes constraints, import Cypher, and visualization tips.201202## Notes203204- `bus_factor_hotspots` in `summary.json` lists sensitive files with low bus factor; `orphaned_sensitive_code` is the stale subset.205- If `git log` is too large, narrow with `--since` or `--until`.206- Compare `summary.json` against CODEOWNERS to highlight ownership drift.207
Full transparency — inspect the skill content before installing.