Pro Security Ownership Map
Production-ready skill that handles analyze, repositories, build, security. Includes structured workflows, validation checks, and reusable patterns for security.
Pro Security Ownership Map
Build security ownership maps by analyzing git history to create a bipartite graph of people and files, computing ownership risk scores, and identifying code with no active maintainer. This skill covers git log analysis, ownership metrics, bus factor calculation, and security-relevant code identification.
When to Use This Skill
Choose Pro Security Ownership Map when you need to:
- Identify who owns security-critical code areas and whether they're actively maintained
- Calculate bus factor (how many people need to leave before code is unmaintained)
- Map security-sensitive files to their most recent contributors for incident response
- Generate ownership reports for security audits and compliance requirements
Consider alternatives when:
- You need code quality analysis (use SonarQube or CodeClimate)
- You need dependency vulnerability scanning (use Snyk or npm audit)
- You need active security testing (use penetration testing skills)
Quick Start
import subprocess import json from collections import defaultdict, Counter from datetime import datetime, timedelta from pathlib import Path class SecurityOwnershipMap: """Analyze git history to build code ownership maps.""" def __init__(self, repo_path='.', lookback_days=365): self.repo_path = repo_path self.lookback_days = lookback_days self.ownership = defaultdict(lambda: defaultdict(int)) # file → author → commits self.last_touched = {} # file → last commit date def analyze(self): """Parse git log to build ownership data.""" since_date = (datetime.now() - timedelta(days=self.lookback_days)).strftime('%Y-%m-%d') cmd = [ 'git', 'log', f'--since={since_date}', '--format=%H|%ae|%aI', '--name-only', '--no-merges' ] result = subprocess.run(cmd, capture_output=True, text=True, cwd=self.repo_path) current_author = None current_date = None for line in result.stdout.split('\n'): if '|' in line and line.count('|') == 2: _, current_author, current_date = line.split('|') elif line.strip() and current_author: filepath = line.strip() self.ownership[filepath][current_author] += 1 if filepath not in self.last_touched or current_date > self.last_touched[filepath]: self.last_touched[filepath] = current_date def bus_factor(self, filepath): """Calculate bus factor for a file.""" authors = self.ownership.get(filepath, {}) if not authors: return 0 total = sum(authors.values()) sorted_authors = sorted(authors.items(), key=lambda x: x[1], reverse=True) cumulative = 0 for i, (_, commits) in enumerate(sorted_authors, 1): cumulative += commits if cumulative >= total * 0.8: # 80% of commits return i return len(sorted_authors) def security_critical_files(self, patterns=None): """Identify security-sensitive files and their ownership.""" if patterns is None: patterns = [ '**/auth*', '**/login*', '**/password*', '**/crypto*', '**/security*', '**/permission*', '**/middleware*', '**/token*', '**/.env*', '**/secret*', ] critical = [] all_files = set(self.ownership.keys()) for filepath in all_files: for pattern in patterns: if Path(filepath).match(pattern.replace('**/', '')): owners = self.ownership[filepath] primary = max(owners, key=owners.get) if owners else "NONE" critical.append({ 'file': filepath, 'primary_owner': primary, 'contributors': len(owners), 'bus_factor': self.bus_factor(filepath), 'last_touched': self.last_touched.get(filepath, 'unknown'), }) break return sorted(critical, key=lambda x: x['bus_factor']) def report(self): """Generate ownership risk report.""" print("=== SECURITY OWNERSHIP REPORT ===\n") # Overall stats all_files = set(self.ownership.keys()) all_authors = set() for authors in self.ownership.values(): all_authors.update(authors.keys()) print(f"Files analyzed: {len(all_files)}") print(f"Active contributors: {len(all_authors)}") # Security-critical files critical = self.security_critical_files() if critical: print(f"\nSECURITY-CRITICAL FILES ({len(critical)}):") for f in critical: risk = "HIGH" if f['bus_factor'] <= 1 else "MEDIUM" if f['bus_factor'] <= 2 else "LOW" print(f" [{risk}] {f['file']}") print(f" Owner: {f['primary_owner']}, " f"Bus factor: {f['bus_factor']}, " f"Contributors: {f['contributors']}") # Orphaned files (no commits in lookback period) current_files = subprocess.run( ['git', 'ls-files'], capture_output=True, text=True, cwd=self.repo_path ).stdout.strip().split('\n') orphaned = [f for f in current_files if f not in all_files] if orphaned: print(f"\nORPHANED FILES (no commits in {self.lookback_days} days): {len(orphaned)}") # mapper = SecurityOwnershipMap(lookback_days=180) # mapper.analyze() # mapper.report()
Core Concepts
Ownership Risk Metrics
| Metric | Description | Risk Threshold |
|---|---|---|
| Bus factor | People needed to leave before code is unmaintained | ≤ 1 = HIGH risk |
| Last touched | Days since last commit to the file | > 180 days = stale |
| Contributor count | Unique authors in lookback period | 1 = single point of failure |
| Ownership concentration | % of commits by top contributor | > 90% = concentrated |
| Security sensitivity | Whether file handles auth, crypto, or permissions | Pattern-matched |
| Orphan status | No commits in lookback period | Unmaintained |
Configuration
| Parameter | Description | Default |
|---|---|---|
lookback_days | Days of git history to analyze | 365 |
security_patterns | Glob patterns for security-sensitive files | Auth, crypto, permission patterns |
bus_factor_threshold | Bus factor below which to flag risk | 2 |
stale_threshold_days | Days without commits to mark as stale | 180 |
exclude_paths | Paths to exclude from analysis | ["vendor/", "node_modules/"] |
output_format | Report format (text, json, csv) | "text" |
include_orphans | Report files with no recent activity | true |
ownership_threshold | Commit percentage to qualify as owner | 0.8 |
Best Practices
-
Run ownership analysis quarterly and before major releases — Code ownership shifts as team members join, leave, or change focus. Quarterly analysis catches emerging risks. Before major releases, verify that security-critical code has active, knowledgeable maintainers.
-
Focus on security-critical files with bus factor of 1 — A single-owner authentication module is a critical risk. If that person leaves, no one understands the security controls. Prioritize cross-training and code review for these files.
-
Combine ownership data with vulnerability scan results — Map discovered vulnerabilities to code owners for efficient remediation routing. The person who wrote and maintains the code can fix vulnerabilities faster than someone unfamiliar with the codebase.
-
Use ownership maps for incident response routing — When a security incident involves specific code or systems, the ownership map immediately identifies who to contact. This reduces incident response time from hours (searching for the right person) to minutes.
-
Track orphaned security-critical code as a risk item — Files with no recent commits aren't necessarily secure — they may contain unpatched vulnerabilities that no one is monitoring. Flag orphaned security files for review and assign a new owner.
Common Issues
Git history includes bot/CI commits that skew ownership — Filter out commits from CI/CD bots, automated formatters, and dependency update bots. Use author email filtering: exclude *@noreply.github.com patterns and known bot accounts to get accurate human ownership data.
Large monorepo analysis is slow — Git log parsing on repositories with millions of commits takes time. Use --since to limit the time range, -- path/to/directory to scope to specific directories, and cache results between runs. Incremental analysis (only new commits since last run) improves performance.
Ownership doesn't reflect actual expertise — Commit count doesn't equal understanding. Someone who made 50 formatting changes doesn't own the code like someone who made 5 architectural changes. Weight commits by change size (lines added/removed) or classify commits by type for more accurate ownership.
Reviews
No reviews yet. Be the first to review this template!
Similar Templates
Full-Stack Code Reviewer
Comprehensive code review skill that checks for security vulnerabilities, performance issues, accessibility, and best practices across frontend and backend code.
Test Suite Generator
Generates comprehensive test suites with unit tests, integration tests, and edge cases. Supports Jest, Vitest, Pytest, and Go testing.
Pro Architecture Workspace
Battle-tested skill for architectural, decision, making, framework. Includes structured workflows, validation checks, and reusable patterns for development.