Claude 24f816b6a3
Consolidate 22 sibling repos into layered organism structure
Place useful parts of the surrounding repos into sica-fondt by layer, per the
body model (Ada = membrane; brain/endocrine/capabilities/knowledge non-Ada):

- brain/        LLM reasoning + providers (dapr, hermes, MoMoA)
- capabilities/ REPRAG sidecars: hermes tools/skills, dapr tools, parallel
                dispatch, A51 channels, and the OSINT cluster
- knowledge/    LORAG corpus: 754 cyber-skills, agency personas, secure-coding,
                MITRE ATT&CK data
- reference/    defensive threat-reference (C3, shhbruh doc) + AdaYaml parser

License handling: AGPL sources (worldosint, advanced_evolution, mercury,
Reticulum) and GPL DeTTECT are SPEC-only clean-room/port descriptions — no
copyleft code copied. MIT/Apache/data parts copied as working trees.

Safety: shhbruh escape/persistence material and C3 covert-C2 kept as reference
only, not wired into the running organism. See CONSOLIDATION.md.

https://claude.ai/code/session_01UehUqEXXJJCsHoA4voCU5c
2026-06-10 06:53:01 +00:00

233 lines
8.6 KiB
Python

#!/usr/bin/env python3
"""Vulnerability remediation SLA tracking agent.
Tracks vulnerability remediation against defined SLA targets based on
severity. Ingests vulnerability data from scanners (JSON/CSV format),
calculates SLA compliance, identifies overdue items, and generates
remediation priority reports.
"""
import argparse
import csv
import json
import os
import sys
from datetime import datetime, timezone, timedelta
DEFAULT_SLA_DAYS = {
"CRITICAL": 7,
"HIGH": 30,
"MEDIUM": 90,
"LOW": 180,
}
def load_vulnerabilities(source_path):
"""Load vulnerabilities from a JSON or CSV file."""
ext = os.path.splitext(source_path)[1].lower()
if ext == ".json":
with open(source_path, "r") as f:
data = json.load(f)
if isinstance(data, list):
return data
return data.get("vulnerabilities", data.get("findings", data.get("results", [])))
elif ext == ".csv":
vulns = []
with open(source_path, "r", newline="") as f:
reader = csv.DictReader(f)
for row in reader:
vulns.append(row)
return vulns
else:
print(f"[!] Unsupported file format: {ext}", file=sys.stderr)
return []
def normalize_vulnerability(vuln):
"""Normalize vulnerability fields from various scanner formats."""
return {
"id": (vuln.get("id") or vuln.get("vulnerability_id") or
vuln.get("cve_id") or vuln.get("CVE") or vuln.get("plugin_id") or "unknown"),
"severity": (vuln.get("severity") or vuln.get("risk") or
vuln.get("Severity") or "MEDIUM").upper(),
"title": (vuln.get("title") or vuln.get("name") or
vuln.get("vulnerability_name") or vuln.get("Title") or "Unknown"),
"asset": (vuln.get("asset") or vuln.get("host") or
vuln.get("ip") or vuln.get("hostname") or "unknown"),
"discovered_date": (vuln.get("discovered_date") or vuln.get("first_found") or
vuln.get("discovered") or vuln.get("date_found") or
datetime.now(timezone.utc).isoformat()),
"status": (vuln.get("status") or vuln.get("state") or "open").lower(),
"remediation": (vuln.get("remediation") or vuln.get("fix") or
vuln.get("solution") or ""),
}
def calculate_sla_status(vulns, sla_days=None):
"""Calculate SLA compliance for each vulnerability."""
if sla_days is None:
sla_days = DEFAULT_SLA_DAYS
now = datetime.now(timezone.utc)
results = []
for vuln in vulns:
norm = normalize_vulnerability(vuln)
if norm["status"] not in ("open", "new", "active", "unresolved"):
norm["sla_status"] = "RESOLVED"
norm["sla_days_remaining"] = None
results.append(norm)
continue
severity = norm["severity"]
target_days = sla_days.get(severity, sla_days.get("MEDIUM", 90))
try:
disc_str = norm["discovered_date"]
if "T" in disc_str:
discovered = datetime.fromisoformat(disc_str.replace("Z", "+00:00"))
else:
discovered = datetime.strptime(disc_str[:10], "%Y-%m-%d").replace(tzinfo=timezone.utc)
except (ValueError, TypeError):
discovered = now
norm["parse_warning"] = "Could not parse discovered_date"
age_days = (now - discovered).days
sla_deadline = discovered + timedelta(days=target_days)
days_remaining = (sla_deadline - now).days
norm["age_days"] = age_days
norm["sla_target_days"] = target_days
norm["sla_deadline"] = sla_deadline.isoformat()
norm["sla_days_remaining"] = days_remaining
if days_remaining < 0:
norm["sla_status"] = "BREACHED"
norm["sla_overdue_days"] = abs(days_remaining)
elif days_remaining <= 7:
norm["sla_status"] = "AT_RISK"
else:
norm["sla_status"] = "ON_TRACK"
results.append(norm)
return results
def generate_metrics(results):
"""Generate SLA compliance metrics."""
open_vulns = [r for r in results if r.get("sla_status") != "RESOLVED"]
breached = [r for r in open_vulns if r.get("sla_status") == "BREACHED"]
at_risk = [r for r in open_vulns if r.get("sla_status") == "AT_RISK"]
on_track = [r for r in open_vulns if r.get("sla_status") == "ON_TRACK"]
compliance_rate = ((len(on_track) + len(at_risk)) / len(open_vulns) * 100) if open_vulns else 100.0
by_severity = {}
for r in open_vulns:
sev = r.get("severity", "MEDIUM")
by_severity.setdefault(sev, {"total": 0, "breached": 0, "at_risk": 0})
by_severity[sev]["total"] += 1
if r.get("sla_status") == "BREACHED":
by_severity[sev]["breached"] += 1
elif r.get("sla_status") == "AT_RISK":
by_severity[sev]["at_risk"] += 1
oldest_breach = None
if breached:
oldest = max(breached, key=lambda r: r.get("sla_overdue_days", 0))
oldest_breach = {
"id": oldest["id"],
"severity": oldest["severity"],
"overdue_days": oldest.get("sla_overdue_days", 0),
"asset": oldest["asset"],
}
return {
"total_open": len(open_vulns),
"breached": len(breached),
"at_risk": len(at_risk),
"on_track": len(on_track),
"resolved": len(results) - len(open_vulns),
"compliance_rate": round(compliance_rate, 1),
"by_severity": by_severity,
"oldest_breach": oldest_breach,
}
def format_summary(metrics, results):
"""Print SLA tracking summary."""
print(f"\n{'='*60}")
print(f" Vulnerability Remediation SLA Report")
print(f"{'='*60}")
print(f" Open Vulnerabilities : {metrics['total_open']}")
print(f" SLA Breached : {metrics['breached']}")
print(f" At Risk (<7 days) : {metrics['at_risk']}")
print(f" On Track : {metrics['on_track']}")
print(f" Resolved : {metrics['resolved']}")
print(f" Compliance Rate : {metrics['compliance_rate']}%")
print(f"\n By Severity:")
for sev in ["CRITICAL", "HIGH", "MEDIUM", "LOW"]:
data = metrics["by_severity"].get(sev, {})
if data.get("total", 0) > 0:
print(f" {sev:10s}: {data['total']} open, {data['breached']} breached, {data['at_risk']} at-risk")
breached = [r for r in results if r.get("sla_status") == "BREACHED"]
if breached:
print(f"\n SLA Breached ({len(breached)}):")
for r in sorted(breached, key=lambda x: -x.get("sla_overdue_days", 0))[:15]:
print(f" [{r['severity']:8s}] {r['id']:20s} | {r['asset']:20s} | "
f"{r.get('sla_overdue_days', 0)}d overdue | {r['title'][:30]}")
if metrics.get("oldest_breach"):
ob = metrics["oldest_breach"]
print(f"\n Worst Breach: {ob['id']} ({ob['severity']}) on {ob['asset']} - "
f"{ob['overdue_days']} days overdue")
def main():
parser = argparse.ArgumentParser(description="Vulnerability remediation SLA tracking agent")
parser.add_argument("--source", required=True, help="Vulnerability data file (JSON or CSV)")
parser.add_argument("--sla-critical", type=int, default=7, help="SLA days for CRITICAL (default: 7)")
parser.add_argument("--sla-high", type=int, default=30, help="SLA days for HIGH (default: 30)")
parser.add_argument("--sla-medium", type=int, default=90, help="SLA days for MEDIUM (default: 90)")
parser.add_argument("--sla-low", type=int, default=180, help="SLA days for LOW (default: 180)")
parser.add_argument("--output", "-o", help="Output JSON report")
parser.add_argument("--verbose", "-v", action="store_true")
args = parser.parse_args()
sla_days = {
"CRITICAL": args.sla_critical,
"HIGH": args.sla_high,
"MEDIUM": args.sla_medium,
"LOW": args.sla_low,
}
vulns = load_vulnerabilities(args.source)
print(f"[*] Loaded {len(vulns)} vulnerabilities from {args.source}")
results = calculate_sla_status(vulns, sla_days)
metrics = generate_metrics(results)
format_summary(metrics, results)
report = {
"timestamp": datetime.now(timezone.utc).isoformat(),
"tool": "Vulnerability SLA Tracker",
"source": args.source,
"sla_targets": sla_days,
"metrics": metrics,
"vulnerabilities": results,
}
if args.output:
with open(args.output, "w") as f:
json.dump(report, f, indent=2)
print(f"\n[+] Report saved to {args.output}")
elif args.verbose:
print(json.dumps(report, indent=2))
if __name__ == "__main__":
main()