Files
gh-cskiro-claudex/skills/analysis/codebase-auditor/scripts/remediation_planner.py
2025-11-29 18:16:40 +08:00

242 lines
8.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
Remediation Planner
Generates prioritized action plans based on audit findings.
Uses severity, impact, frequency, and effort to prioritize issues.
"""
from typing import Dict, List
from datetime import datetime, timedelta
def generate_remediation_plan(findings: Dict[str, List[Dict]], metadata: Dict) -> str:
"""
Generate a prioritized remediation plan.
Args:
findings: All findings organized by category
metadata: Project metadata
Returns:
Markdown-formatted remediation plan
"""
plan = []
# Header
plan.append("# Codebase Remediation Plan")
plan.append(f"\n**Generated**: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
plan.append(f"**Codebase**: `{metadata.get('path', 'Unknown')}`")
plan.append("\n---\n")
# Flatten and prioritize all findings
all_findings = []
for category, category_findings in findings.items():
for finding in category_findings:
finding['category'] = category
all_findings.append(finding)
# Calculate priority scores
for finding in all_findings:
finding['priority_score'] = calculate_priority_score(finding)
# Sort by priority score (highest first)
all_findings.sort(key=lambda x: x['priority_score'], reverse=True)
# Group by priority level
p0_issues = [f for f in all_findings if f['severity'] == 'critical']
p1_issues = [f for f in all_findings if f['severity'] == 'high']
p2_issues = [f for f in all_findings if f['severity'] == 'medium']
p3_issues = [f for f in all_findings if f['severity'] == 'low']
# Priority 0: Critical Issues (Fix Immediately)
if p0_issues:
plan.append("## Priority 0: Critical Issues (Fix Immediately ⚡)")
plan.append("\n**Timeline**: Within 24 hours")
plan.append("**Impact**: Security vulnerabilities, production-breaking bugs, data loss risks\n")
for i, finding in enumerate(p0_issues, 1):
plan.append(f"### {i}. {finding.get('title', 'Untitled')}")
plan.append(f"**Category**: {finding.get('category', 'Unknown').replace('_', ' ').title()}")
plan.append(f"**Location**: `{finding.get('file', 'Unknown')}`")
plan.append(f"**Effort**: {finding.get('effort', 'unknown').upper()}")
plan.append(f"\n**Issue**: {finding.get('description', 'No description')}")
plan.append(f"\n**Impact**: {finding.get('impact', 'Unknown impact')}")
plan.append(f"\n**Action**: {finding.get('remediation', 'No remediation suggested')}\n")
plan.append("---\n")
# Priority 1: High Issues (Fix This Sprint)
if p1_issues:
plan.append("## Priority 1: High Issues (Fix This Sprint 📅)")
plan.append("\n**Timeline**: Within current sprint (2 weeks)")
plan.append("**Impact**: Significant quality, security, or user experience issues\n")
for i, finding in enumerate(p1_issues[:10], 1): # Top 10
plan.append(f"### {i}. {finding.get('title', 'Untitled')}")
plan.append(f"**Category**: {finding.get('category', 'Unknown').replace('_', ' ').title()}")
plan.append(f"**Effort**: {finding.get('effort', 'unknown').upper()}")
plan.append(f"\n**Action**: {finding.get('remediation', 'No remediation suggested')}\n")
if len(p1_issues) > 10:
plan.append(f"\n*...and {len(p1_issues) - 10} more high-priority issues*\n")
plan.append("---\n")
# Priority 2: Medium Issues (Fix Next Quarter)
if p2_issues:
plan.append("## Priority 2: Medium Issues (Fix Next Quarter 📆)")
plan.append("\n**Timeline**: Within 3 months")
plan.append("**Impact**: Code maintainability, developer productivity\n")
plan.append(f"**Total Issues**: {len(p2_issues)}\n")
# Group by subcategory
subcategories = {}
for finding in p2_issues:
subcat = finding.get('subcategory', 'Other')
if subcat not in subcategories:
subcategories[subcat] = []
subcategories[subcat].append(finding)
plan.append("**Grouped by Type**:\n")
for subcat, subcat_findings in subcategories.items():
plan.append(f"- {subcat.replace('_', ' ').title()}: {len(subcat_findings)} issues")
plan.append("\n---\n")
# Priority 3: Low Issues (Backlog)
if p3_issues:
plan.append("## Priority 3: Low Issues (Backlog 📋)")
plan.append("\n**Timeline**: When time permits")
plan.append("**Impact**: Minor improvements, stylistic issues\n")
plan.append(f"**Total Issues**: {len(p3_issues)}\n")
plan.append("*Address during dedicated tech debt sprints or slow periods*\n")
plan.append("---\n")
# Implementation Timeline
plan.append("## Suggested Timeline\n")
today = datetime.now()
if p0_issues:
deadline = today + timedelta(days=1)
plan.append(f"- **{deadline.strftime('%Y-%m-%d')}**: All P0 issues resolved")
if p1_issues:
deadline = today + timedelta(weeks=2)
plan.append(f"- **{deadline.strftime('%Y-%m-%d')}**: P1 issues addressed (end of sprint)")
if p2_issues:
deadline = today + timedelta(weeks=12)
plan.append(f"- **{deadline.strftime('%Y-%m-%d')}**: P2 issues resolved (end of quarter)")
# Effort Summary
plan.append("\n## Effort Summary\n")
effort_estimates = calculate_effort_summary(all_findings)
plan.append(f"**Total Estimated Effort**: {effort_estimates['total']} person-days")
plan.append(f"- Critical/High: {effort_estimates['critical_high']} days")
plan.append(f"- Medium: {effort_estimates['medium']} days")
plan.append(f"- Low: {effort_estimates['low']} days")
# Team Assignment Suggestions
plan.append("\n## Team Assignment Suggestions\n")
plan.append("- **Security Team**: All P0 security issues, P1 vulnerabilities")
plan.append("- **QA/Testing**: Test coverage improvements, test quality issues")
plan.append("- **Infrastructure**: CI/CD improvements, build performance")
plan.append("- **Development Team**: Code quality refactoring, complexity reduction")
# Footer
plan.append("\n---\n")
plan.append("*Remediation plan generated by Codebase Auditor Skill*")
plan.append("\n*Priority scoring based on: Impact × 10 + Frequency × 5 - Effort × 2*")
return '\n'.join(plan)
def calculate_priority_score(finding: Dict) -> int:
"""
Calculate priority score for a finding.
Formula: (Impact × 10) + (Frequency × 5) - (Effort × 2)
Args:
finding: Individual finding
Returns:
Priority score (higher = more urgent)
"""
# Map severity to impact (1-10)
severity_impact = {
'critical': 10,
'high': 7,
'medium': 4,
'low': 2,
}
impact = severity_impact.get(finding.get('severity', 'low'), 1)
# Estimate frequency (1-10) based on category
# Security/testing issues affect everything
category = finding.get('category', '')
if category in ['security', 'testing']:
frequency = 10
elif category in ['quality', 'performance']:
frequency = 6
else:
frequency = 3
# Map effort to numeric value (1-10)
effort_values = {
'low': 2,
'medium': 5,
'high': 8,
}
effort = effort_values.get(finding.get('effort', 'medium'), 5)
# Calculate score
score = (impact * 10) + (frequency * 5) - (effort * 2)
return max(0, score) # Never negative
def calculate_effort_summary(findings: List[Dict]) -> Dict[str, int]:
"""
Calculate total effort estimates.
Args:
findings: All findings
Returns:
Dictionary with effort estimates in person-days
"""
# Map effort levels to days
effort_days = {
'low': 0.5,
'medium': 2,
'high': 5,
}
critical_high_days = sum(
effort_days.get(f.get('effort', 'medium'), 2)
for f in findings
if f.get('severity') in ['critical', 'high']
)
medium_days = sum(
effort_days.get(f.get('effort', 'medium'), 2)
for f in findings
if f.get('severity') == 'medium'
)
low_days = sum(
effort_days.get(f.get('effort', 'medium'), 2)
for f in findings
if f.get('severity') == 'low'
)
return {
'critical_high': round(critical_high_days, 1),
'medium': round(medium_days, 1),
'low': round(low_days, 1),
'total': round(critical_high_days + medium_days + low_days, 1),
}