P

Pro Security Ownership Map

Production-ready skill that handles analyze, repositories, build, security. Includes structured workflows, validation checks, and reusable patterns for security.

SkillClipticssecurityv1.0.0MIT
0 views0 copies

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

MetricDescriptionRisk Threshold
Bus factorPeople needed to leave before code is unmaintained≤ 1 = HIGH risk
Last touchedDays since last commit to the file> 180 days = stale
Contributor countUnique authors in lookback period1 = single point of failure
Ownership concentration% of commits by top contributor> 90% = concentrated
Security sensitivityWhether file handles auth, crypto, or permissionsPattern-matched
Orphan statusNo commits in lookback periodUnmaintained

Configuration

ParameterDescriptionDefault
lookback_daysDays of git history to analyze365
security_patternsGlob patterns for security-sensitive filesAuth, crypto, permission patterns
bus_factor_thresholdBus factor below which to flag risk2
stale_threshold_daysDays without commits to mark as stale180
exclude_pathsPaths to exclude from analysis["vendor/", "node_modules/"]
output_formatReport format (text, json, csv)"text"
include_orphansReport files with no recent activitytrue
ownership_thresholdCommit percentage to qualify as owner0.8

Best Practices

  1. 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.

  2. 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.

  3. 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.

  4. 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.

  5. 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.

Community

Reviews

Write a review

No reviews yet. Be the first to review this template!

Similar Templates