Security Ownership Map
Analyze git history to build a bipartite ownership graph (people-to-files), compute security risk metrics (bus factor, sensitivity scores, ownership concentration), detect orphaned sensitive code and hidden owners, and export structured artifacts for Neo4j, Gephi, or downstream analysis.
Overview
This skill mines git repositories to answer security ownership questions:
- Who owns security-critical code? Map people to auth, crypto, secrets, and infrastructure files.
- What is the bus factor? Identify files where a single departure creates risk.
- Is ownership drifting? Compare CODEOWNERS declarations against actual commit patterns.
- Where are the orphaned hotspots? Find stale sensitive code with low bus factor.
- How do files cluster? Use co-change analysis (Jaccard similarity) and community detection to reveal logical coupling.
What it analyzes:
- Git commit history (author attribution, recency-weighted touches)
- File sensitivity (pattern-matched tags: auth, crypto, secrets, PII, infrastructure)
- Ownership concentration and bus factor per file
- Co-change coupling between files (Jaccard similarity on shared commits)
- Community structure (Louvain greedy modularity on co-change graph)
What it produces:
people.csv, files.csv, edges.csv — graph nodes and relationships
cochange_edges.csv — file-to-file coupling weights
summary.json — orphaned code, hidden owners, bus factor hotspots
communities.json — file clusters with top maintainers
cochange.graph.json / ownership.graph.json — NetworkX node-link format
- Optional:
commits.jsonl, GraphML exports
Analysis Checklist
Ownership Risk
Knowledge Distribution
Co-Change Coupling
CODEOWNERS Validation
Metrics
Bus Factor
| Metric |
Description |
Good |
Warning |
Critical |
| Bus factor |
Unique authors per sensitive file |
>= 3 |
2 |
1 |
| Ownership concentration |
Top contributor's share |
< 40% |
40-70% |
> 70% |
| Staleness |
Days since last security touch |
< 90 |
90-365 |
> 365 |
Co-Change Coupling
| Metric |
Description |
Strong |
Moderate |
Weak |
| Jaccard similarity |
Shared-commit overlap between files |
> 0.3 |
0.1-0.3 |
< 0.1 |
| Community bus factor |
Unique authors in a file cluster |
>= 5 |
3-4 |
1-2 |
Workflow
Step 1: Scope the repository
Choose the target repo and optional time window. Use --since / --until to narrow large histories.
Step 2: Configure sensitivity rules
Use built-in defaults (auth, crypto, secrets, SSO, IAM, TLS) or provide a custom CSV:
# pattern,tag,weight
**/auth/**,auth,1.0
**/crypto/**,crypto,1.0
**/*.pem,secrets,1.0
**/iam/**,auth,1.0
**/pii/**,pii,1.0
**/terraform/**,infrastructure,1.0
Step 3: Build the ownership map
python scripts/run_ownership_map.py \
--repo . \
--out ownership-map-out \
--since "12 months ago" \
--emit-commits
Key flags:
--cochange-max-files 50 — ignore supernode commits for co-change graph
--no-default-cochange-excludes — include lockfiles in co-change analysis
--cochange-exclude "**/Kbuild" — add custom exclusions
--identity committer — attribute to committer instead of author
--graphml — emit GraphML for Gephi import
--no-communities — skip community detection
--sensitive-config path/to/rules.csv — custom sensitivity rules
Step 4: Query results
Use scripts/query_ownership.py for bounded JSON slices without loading full datasets:
# Orphaned sensitive code
python scripts/query_ownership.py --data-dir ownership-map-out \
summary --section orphaned_sensitive_code
# Auth files with bus factor <= 1
python scripts/query_ownership.py --data-dir ownership-map-out \
files --tag auth --bus-factor-max 1
# Top sensitive-code contributors
python scripts/query_ownership.py --data-dir ownership-map-out \
people --sort sensitive_touches --limit 10
# Co-change neighbors for a file
python scripts/query_ownership.py --data-dir ownership-map-out \
cochange --file crypto/tls --min-jaccard 0.05
# Community maintainers
python scripts/query_ownership.py --data-dir ownership-map-out \
community --id 3
Step 5: Track maintainers over time
python scripts/community_maintainers.py \
--data-dir ownership-map-out \
--file network/card.c \
--since 2025-01-01 \
--top 5 \
--bucket quarter
Step 6: Persist and visualize
Load artifacts into Neo4j (see references/neo4j-import.md) or import CSVs into Gephi for network visualization. Filter by sensitivity_score > 0 to focus on security-relevant clusters.
Output Artifacts
| File |
Contents |
people.csv |
Person nodes with timezone, touch counts, sensitive touches |
files.csv |
File nodes with bus factor, sensitivity score, tags |
edges.csv |
Person-to-file edges with touches, recency weight, sensitive weight |
cochange_edges.csv |
File-to-file edges with co-change count and Jaccard similarity |
summary.json |
Orphaned sensitive code, hidden owners, bus factor hotspots, stats |
communities.json |
File clusters with top maintainers per community |
cochange.graph.json |
NetworkX node-link JSON with community IDs |
commits.jsonl |
Raw commit data (optional, with --emit-commits) |
*.graphml |
GraphML exports for Gephi (optional, with --graphml) |
Report Format
Summary
Security Ownership Map Report
==============================
Repository: /path/to/repo
Time window: 12 months
Generated: 2026-02-04T12:00:00Z
Stats:
Commits analyzed: 2,847
People: 42
Files: 1,203
Co-change pairs: 8,412
Key Findings:
- 7 sensitive files with bus factor = 1
- 3 orphaned auth files (stale > 365 days)
- 1 hidden owner controls 63% of crypto code
Security Queries
# Orphaned sensitive code (stale + low bus factor)
python scripts/query_ownership.py --data-dir ownership-map-out \
summary --section orphaned_sensitive_code
# Hidden owners by sensitivity tag
python scripts/query_ownership.py --data-dir ownership-map-out \
summary --section hidden_owners
# Bus factor hotspots
python scripts/query_ownership.py --data-dir ownership-map-out \
summary --section bus_factor_hotspots
Examples
Example 1: Quick security audit
User: Run a security ownership analysis on this repo for the last year.
Assistant: I'll build a security ownership map from your git history.
1. Running: python scripts/run_ownership_map.py --repo . --out ownership-map-out --since "12 months ago" --emit-commits
2. Querying orphaned sensitive code...
3. Checking bus factor hotspots...
Results:
- 1,203 files analyzed across 42 contributors
- 7 sensitive files with bus factor = 1 (critical)
- 3 orphaned auth files not touched in over a year
- alice@corp controls 63% of all crypto code (hidden owner)
Recommendations:
1. Pair-program on the 7 single-owner sensitive files to spread knowledge
2. Review the 3 orphaned auth files for deprecation or ownership transfer
3. Assign a secondary reviewer for all crypto changes
Example 2: Focused tag analysis
User: Which auth files have the lowest bus factor?
Assistant: Querying auth files sorted by bus factor...
python scripts/query_ownership.py --data-dir ownership-map-out files --tag auth --bus-factor-max 2
Found 4 auth files with bus factor <= 2:
- auth/oauth/handler.rs (bus_factor: 1, last touch: 2025-03-12)
- auth/session/store.rs (bus_factor: 1, last touch: 2025-08-01)
- auth/rbac/policy.rs (bus_factor: 2, last touch: 2025-11-20)
- auth/token/refresh.rs (bus_factor: 2, last touch: 2025-09-15)
Interpretation Guide
Score Meanings
| Bus Factor |
Risk Level |
Action |
| >= 3 |
Low |
Maintain current practices |
| 2 |
Moderate |
Plan knowledge transfer |
| 1 |
High |
Immediate pair programming needed |
| 0 (stale) |
Critical |
File may be abandoned; review for deprecation |
Sensitivity Tags
| Tag |
Matches |
Risk Context |
| auth |
Login, OAuth, RBAC, session, token, IAM, SSO |
Authentication and authorization logic |
| crypto |
Encryption, TLS, SSL, key derivation |
Cryptographic operations |
| secrets |
PEM files, key files, P12/PFX certificates |
Secret material and credentials |
| pii |
Personal data paths (custom config) |
Data privacy and compliance |
| infrastructure |
Terraform, K8s configs (custom config) |
Infrastructure-as-code security |
Requirements
- Python 3
networkx (required for community detection, enabled by default)
Install: pip install networkx
Notes
- Merge commits are excluded by default; use
--include-merges to include them.
- Dependabot commits are excluded by default; override with
--no-default-author-excludes.
- Co-change graph ignores lockfiles,
.github/*, and editor config by default.
- Compare
summary.json against CODEOWNERS to highlight ownership drift.
- If
git log is too large, narrow with --since or --until.
1---2name: security-ownership-map3description: Analyze git repositories to build a security ownership topology mapping people to files, compute bus factor and sensitive-code ownership metrics, detect orphaned security code and hidden owners, and export CSV/JSON artifacts for graph databases and visualization. Trigger when the user requests security-oriented ownership analysis, bus-factor audits, CODEOWNERS reality checks, sensitive hotspot identification, or ownership cluster analysis grounded in git history. Do not trigger for general contributor lists or non-security ownership queries.4---5
6# Security Ownership Map
7
8Analyze git history to build a bipartite ownership graph (people-to-files), compute security risk metrics (bus factor, sensitivity scores, ownership concentration), detect orphaned sensitive code and hidden owners, and export structured artifacts for Neo4j, Gephi, or downstream analysis.
9
10## Overview
11
12This skill mines git repositories to answer security ownership questions:
13
14- **Who owns security-critical code?** Map people to auth, crypto, secrets, and infrastructure files.
15- **What is the bus factor?** Identify files where a single departure creates risk.
16- **Is ownership drifting?** Compare CODEOWNERS declarations against actual commit patterns.
17- **Where are the orphaned hotspots?** Find stale sensitive code with low bus factor.
18- **How do files cluster?** Use co-change analysis (Jaccard similarity) and community detection to reveal logical coupling.
19
20**What it analyzes:**
21- Git commit history (author attribution, recency-weighted touches)
22- File sensitivity (pattern-matched tags: auth, crypto, secrets, PII, infrastructure)
23- Ownership concentration and bus factor per file
24- Co-change coupling between files (Jaccard similarity on shared commits)
25- Community structure (Louvain greedy modularity on co-change graph)
26
27**What it produces:**
28- `people.csv`, `files.csv`, `edges.csv` — graph nodes and relationships
29- `cochange_edges.csv` — file-to-file coupling weights
30- `summary.json` — orphaned code, hidden owners, bus factor hotspots
31- `communities.json` — file clusters with top maintainers
32- `cochange.graph.json` / `ownership.graph.json` — NetworkX node-link format
33- Optional: `commits.jsonl`, GraphML exports
34
35## Analysis Checklist
36
37### Ownership Risk
38
39- [ ] Identify all files matching sensitivity patterns (auth, crypto, secrets, PII, infrastructure)
40- [ ] Compute bus factor per sensitive file (threshold: 1 = danger, <3 = warning)
41- [ ] Flag orphaned sensitive code (stale + low bus factor)
42- [ ] Detect hidden owners (>50% of a sensitivity tag owned by one person)
43
44### Knowledge Distribution
45
46- [ ] Calculate ownership concentration per file (top contributor share)
47- [ ] Identify knowledge islands (single-developer files in security paths)
48- [ ] Track timezone distribution of contributors for global coverage gaps
49- [ ] Measure recency-weighted ownership to detect recent knowledge loss
50
51### Co-Change Coupling
52
53- [ ] Build co-change graph excluding lockfiles, config, and bot commits
54- [ ] Compute Jaccard similarity between file pairs
55- [ ] Run community detection (Louvain) on co-change graph
56- [ ] Identify cross-team clusters indicating architectural coupling risk
57
58### CODEOWNERS Validation
59
60- [ ] Compare declared CODEOWNERS against actual git history owners
61- [ ] Flag ghost owners (no commits in 180+ days)
62- [ ] Identify ownership gaps (sensitive files with no CODEOWNERS entry)
63
64## Metrics
65
66### Bus Factor
67
68| Metric | Description | Good | Warning | Critical |
69|--------|-------------|------|---------|----------|
70| Bus factor | Unique authors per sensitive file | >= 3 | 2 | 1 |
71| Ownership concentration | Top contributor's share | < 40% | 40-70% | > 70% |
72| Staleness | Days since last security touch | < 90 | 90-365 | > 365 |
73
74### Co-Change Coupling
75
76| Metric | Description | Strong | Moderate | Weak |
77|--------|-------------|--------|----------|------|
78| Jaccard similarity | Shared-commit overlap between files | > 0.3 | 0.1-0.3 | < 0.1 |
79| Community bus factor | Unique authors in a file cluster | >= 5 | 3-4 | 1-2 |
80
81## Workflow
82
83### Step 1: Scope the repository
84
85Choose the target repo and optional time window. Use `--since` / `--until` to narrow large histories.
86
87### Step 2: Configure sensitivity rules
88
89Use built-in defaults (auth, crypto, secrets, SSO, IAM, TLS) or provide a custom CSV:
90
91```
92# pattern,tag,weight
93**/auth/**,auth,1.0
94**/crypto/**,crypto,1.0
95**/*.pem,secrets,1.0
96**/iam/**,auth,1.0
97**/pii/**,pii,1.0
98**/terraform/**,infrastructure,1.0
99```
100
101### Step 3: Build the ownership map
102
103```bash
104python scripts/run_ownership_map.py \
105 --repo . \
106 --out ownership-map-out \
107 --since "12 months ago" \
108 --emit-commits
109```
110
111Key flags:
112- `--cochange-max-files 50` — ignore supernode commits for co-change graph
113- `--no-default-cochange-excludes` — include lockfiles in co-change analysis
114- `--cochange-exclude "**/Kbuild"` — add custom exclusions
115- `--identity committer` — attribute to committer instead of author
116- `--graphml` — emit GraphML for Gephi import
117- `--no-communities` — skip community detection
118- `--sensitive-config path/to/rules.csv` — custom sensitivity rules
119
120### Step 4: Query results
121
122Use `scripts/query_ownership.py` for bounded JSON slices without loading full datasets:
123
124```bash
125# Orphaned sensitive code
126python scripts/query_ownership.py --data-dir ownership-map-out \
127 summary --section orphaned_sensitive_code
128
129# Auth files with bus factor <= 1
130python scripts/query_ownership.py --data-dir ownership-map-out \
131 files --tag auth --bus-factor-max 1
132
133# Top sensitive-code contributors
134python scripts/query_ownership.py --data-dir ownership-map-out \
135 people --sort sensitive_touches --limit 10
136
137# Co-change neighbors for a file
138python scripts/query_ownership.py --data-dir ownership-map-out \
139 cochange --file crypto/tls --min-jaccard 0.05
140
141# Community maintainers
142python scripts/query_ownership.py --data-dir ownership-map-out \
143 community --id 3
144```
145
146### Step 5: Track maintainers over time
147
148```bash
149python scripts/community_maintainers.py \
150 --data-dir ownership-map-out \
151 --file network/card.c \
152 --since 2025-01-01 \
153 --top 5 \
154 --bucket quarter
155```
156
157### Step 6: Persist and visualize
158
159Load artifacts into Neo4j (see `references/neo4j-import.md`) or import CSVs into Gephi for network visualization. Filter by `sensitivity_score > 0` to focus on security-relevant clusters.
160
161## Output Artifacts
162
163| File | Contents |
164|------|----------|
165| `people.csv` | Person nodes with timezone, touch counts, sensitive touches |
166| `files.csv` | File nodes with bus factor, sensitivity score, tags |
167| `edges.csv` | Person-to-file edges with touches, recency weight, sensitive weight |
168| `cochange_edges.csv` | File-to-file edges with co-change count and Jaccard similarity |
169| `summary.json` | Orphaned sensitive code, hidden owners, bus factor hotspots, stats |
170| `communities.json` | File clusters with top maintainers per community |
171| `cochange.graph.json` | NetworkX node-link JSON with community IDs |
172| `commits.jsonl` | Raw commit data (optional, with `--emit-commits`) |
173| `*.graphml` | GraphML exports for Gephi (optional, with `--graphml`) |
174
175## Report Format
176
177### Summary
178
179```
180Security Ownership Map Report
181==============================
182Repository: /path/to/repo
183Time window: 12 months
184Generated: 2026-02-04T12:00:00Z
185
186Stats:
187 Commits analyzed: 2,847
188 People: 42
189 Files: 1,203
190 Co-change pairs: 8,412
191
192Key Findings:
193- 7 sensitive files with bus factor = 1
194- 3 orphaned auth files (stale > 365 days)
195- 1 hidden owner controls 63% of crypto code
196```
197
198### Security Queries
199
200```bash
201# Orphaned sensitive code (stale + low bus factor)
202python scripts/query_ownership.py --data-dir ownership-map-out \
203 summary --section orphaned_sensitive_code
204
205# Hidden owners by sensitivity tag
206python scripts/query_ownership.py --data-dir ownership-map-out \
207 summary --section hidden_owners
208
209# Bus factor hotspots
210python scripts/query_ownership.py --data-dir ownership-map-out \
211 summary --section bus_factor_hotspots
212```
213
214## Examples
215
216### Example 1: Quick security audit
217
218```
219User: Run a security ownership analysis on this repo for the last year.
220Assistant: I'll build a security ownership map from your git history.
221
2221. Running: python scripts/run_ownership_map.py --repo . --out ownership-map-out --since "12 months ago" --emit-commits
2232. Querying orphaned sensitive code...
2243. Checking bus factor hotspots...
225
226Results:
227- 1,203 files analyzed across 42 contributors
228- 7 sensitive files with bus factor = 1 (critical)
229- 3 orphaned auth files not touched in over a year
230- alice@corp controls 63% of all crypto code (hidden owner)
231
232Recommendations:
2331. Pair-program on the 7 single-owner sensitive files to spread knowledge
2342. Review the 3 orphaned auth files for deprecation or ownership transfer
2353. Assign a secondary reviewer for all crypto changes
236```
237
238### Example 2: Focused tag analysis
239
240```
241User: Which auth files have the lowest bus factor?
242Assistant: Querying auth files sorted by bus factor...
243
244python scripts/query_ownership.py --data-dir ownership-map-out files --tag auth --bus-factor-max 2
245
246Found 4 auth files with bus factor <= 2:
247- auth/oauth/handler.rs (bus_factor: 1, last touch: 2025-03-12)
248- auth/session/store.rs (bus_factor: 1, last touch: 2025-08-01)
249- auth/rbac/policy.rs (bus_factor: 2, last touch: 2025-11-20)
250- auth/token/refresh.rs (bus_factor: 2, last touch: 2025-09-15)
251```
252
253## Interpretation Guide
254
255### Score Meanings
256
257| Bus Factor | Risk Level | Action |
258|------------|------------|--------|
259| >= 3 | Low | Maintain current practices |
260| 2 | Moderate | Plan knowledge transfer |
261| 1 | High | Immediate pair programming needed |
262| 0 (stale) | Critical | File may be abandoned; review for deprecation |
263
264### Sensitivity Tags
265
266| Tag | Matches | Risk Context |
267|-----|---------|--------------|
268| auth | Login, OAuth, RBAC, session, token, IAM, SSO | Authentication and authorization logic |
269| crypto | Encryption, TLS, SSL, key derivation | Cryptographic operations |
270| secrets | PEM files, key files, P12/PFX certificates | Secret material and credentials |
271| pii | Personal data paths (custom config) | Data privacy and compliance |
272| infrastructure | Terraform, K8s configs (custom config) | Infrastructure-as-code security |
273
274## Requirements
275
276- Python 3
277- `networkx` (required for community detection, enabled by default)
278
279Install: `pip install networkx`
280
281## Notes
282
283- Merge commits are excluded by default; use `--include-merges` to include them.
284- Dependabot commits are excluded by default; override with `--no-default-author-excludes`.
285- Co-change graph ignores lockfiles, `.github/*`, and editor config by default.
286- Compare `summary.json` against CODEOWNERS to highlight ownership drift.
287- If `git log` is too large, narrow with `--since` or `--until`.