mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-07-05 15:29:01 +03:00
Initial commit - 611 cybersecurity skills across all subdomains
This commit is contained in:
@@ -0,0 +1,229 @@
|
||||
#!/usr/bin/env python3
|
||||
"""DefectDojo Vulnerability Dashboard Automation.
|
||||
|
||||
Manages products, engagements, scan imports, and metrics via the
|
||||
DefectDojo REST API v2.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
|
||||
import requests
|
||||
|
||||
DD_URL = os.environ.get("DD_URL", "http://localhost:8080/api/v2")
|
||||
DD_API_KEY = os.environ.get("DD_API_KEY", "")
|
||||
|
||||
|
||||
def get_headers():
|
||||
return {
|
||||
"Authorization": f"Token {DD_API_KEY}",
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
|
||||
|
||||
def create_product_type(name, description=""):
|
||||
resp = requests.post(
|
||||
f"{DD_URL}/product_types/",
|
||||
headers=get_headers(),
|
||||
json={"name": name, "description": description},
|
||||
timeout=30,
|
||||
)
|
||||
resp.raise_for_status()
|
||||
pt = resp.json()
|
||||
print(f"[+] Created product type: {name} (ID: {pt['id']})")
|
||||
return pt["id"]
|
||||
|
||||
|
||||
def create_product(name, product_type_id, description=""):
|
||||
resp = requests.post(
|
||||
f"{DD_URL}/products/",
|
||||
headers=get_headers(),
|
||||
json={
|
||||
"name": name,
|
||||
"description": description,
|
||||
"prod_type": product_type_id,
|
||||
},
|
||||
timeout=30,
|
||||
)
|
||||
resp.raise_for_status()
|
||||
product = resp.json()
|
||||
print(f"[+] Created product: {name} (ID: {product['id']})")
|
||||
return product["id"]
|
||||
|
||||
|
||||
def create_engagement(name, product_id, start_date=None, end_date=None):
|
||||
if not start_date:
|
||||
start_date = datetime.now(timezone.utc).strftime("%Y-%m-%d")
|
||||
if not end_date:
|
||||
end_date = "2025-12-31"
|
||||
resp = requests.post(
|
||||
f"{DD_URL}/engagements/",
|
||||
headers=get_headers(),
|
||||
json={
|
||||
"name": name,
|
||||
"product": product_id,
|
||||
"target_start": start_date,
|
||||
"target_end": end_date,
|
||||
"engagement_type": "CI/CD",
|
||||
"status": "In Progress",
|
||||
},
|
||||
timeout=30,
|
||||
)
|
||||
resp.raise_for_status()
|
||||
eng = resp.json()
|
||||
print(f"[+] Created engagement: {name} (ID: {eng['id']})")
|
||||
return eng["id"]
|
||||
|
||||
|
||||
def import_scan(scan_file, scan_type, product_name, engagement_name=None):
|
||||
"""Import or reimport scan results into DefectDojo."""
|
||||
data = {
|
||||
"scan_type": scan_type,
|
||||
"product_name": product_name,
|
||||
"auto_create_context": "true",
|
||||
"deduplication_on_engagement": "true",
|
||||
"close_old_findings": "true",
|
||||
}
|
||||
if engagement_name:
|
||||
data["engagement_name"] = engagement_name
|
||||
|
||||
with open(scan_file, "rb") as f:
|
||||
resp = requests.post(
|
||||
f"{DD_URL}/reimport-scan/",
|
||||
headers={"Authorization": f"Token {DD_API_KEY}"},
|
||||
data=data,
|
||||
files={"file": f},
|
||||
timeout=120,
|
||||
)
|
||||
|
||||
if resp.status_code in (200, 201):
|
||||
result = resp.json()
|
||||
test_id = result.get("test", 0)
|
||||
print(f"[+] Scan imported successfully (Test ID: {test_id})")
|
||||
print(f" New findings: {result.get('statistics', {}).get('created', 0)}")
|
||||
print(f" Closed findings: {result.get('statistics', {}).get('closed', 0)}")
|
||||
print(f" Reactivated: {result.get('statistics', {}).get('reactivated', 0)}")
|
||||
return result
|
||||
else:
|
||||
print(f"[-] Import failed: {resp.status_code} {resp.text}")
|
||||
return None
|
||||
|
||||
|
||||
def get_findings(product_id=None, severity=None, active=True, limit=100):
|
||||
"""Query findings with filters."""
|
||||
params = {"limit": limit, "active": str(active).lower()}
|
||||
if product_id:
|
||||
params["test__engagement__product"] = product_id
|
||||
if severity:
|
||||
params["severity"] = severity
|
||||
|
||||
resp = requests.get(f"{DD_URL}/findings/", headers=get_headers(), params=params, timeout=30)
|
||||
resp.raise_for_status()
|
||||
return resp.json()
|
||||
|
||||
|
||||
def get_metrics(product_id=None):
|
||||
"""Get vulnerability metrics for dashboard."""
|
||||
params = {"limit": 0}
|
||||
if product_id:
|
||||
params["test__engagement__product"] = product_id
|
||||
|
||||
metrics = {}
|
||||
for severity in ["Critical", "High", "Medium", "Low", "Info"]:
|
||||
resp = requests.get(
|
||||
f"{DD_URL}/findings/",
|
||||
headers=get_headers(),
|
||||
params={**params, "severity": severity, "active": "true"},
|
||||
timeout=30,
|
||||
)
|
||||
if resp.status_code == 200:
|
||||
metrics[severity] = resp.json().get("count", 0)
|
||||
|
||||
# SLA breached findings
|
||||
resp = requests.get(
|
||||
f"{DD_URL}/findings/",
|
||||
headers=get_headers(),
|
||||
params={**params, "active": "true", "is_mitigated": "false"},
|
||||
timeout=30,
|
||||
)
|
||||
if resp.status_code == 200:
|
||||
metrics["total_active"] = resp.json().get("count", 0)
|
||||
|
||||
return metrics
|
||||
|
||||
|
||||
def generate_dashboard_report(output_path, product_id=None):
|
||||
"""Generate dashboard metrics report."""
|
||||
metrics = get_metrics(product_id)
|
||||
report = {
|
||||
"generated_at": datetime.now(timezone.utc).isoformat(),
|
||||
"active_findings": metrics,
|
||||
"total_active": metrics.get("total_active", 0),
|
||||
}
|
||||
with open(output_path, "w", encoding="utf-8") as f:
|
||||
json.dump(report, f, indent=2)
|
||||
print(f"\n[+] Dashboard Report: {output_path}")
|
||||
print(f" Critical: {metrics.get('Critical', 0)}")
|
||||
print(f" High: {metrics.get('High', 0)}")
|
||||
print(f" Medium: {metrics.get('Medium', 0)}")
|
||||
print(f" Low: {metrics.get('Low', 0)}")
|
||||
print(f" Total Active: {metrics.get('total_active', 0)}")
|
||||
return report
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="DefectDojo Dashboard Automation")
|
||||
parser.add_argument("--url", default=DD_URL, help="DefectDojo API URL")
|
||||
parser.add_argument("--api-key", default=DD_API_KEY, help="API key")
|
||||
|
||||
sub = parser.add_subparsers(dest="command")
|
||||
|
||||
setup = sub.add_parser("setup", help="Create product type, product, engagement")
|
||||
setup.add_argument("--product-type", required=True)
|
||||
setup.add_argument("--product", required=True)
|
||||
setup.add_argument("--engagement", default="CI/CD")
|
||||
|
||||
imp = sub.add_parser("import", help="Import scan results")
|
||||
imp.add_argument("--file", required=True)
|
||||
imp.add_argument("--scan-type", required=True)
|
||||
imp.add_argument("--product", required=True)
|
||||
imp.add_argument("--engagement")
|
||||
|
||||
dash = sub.add_parser("dashboard", help="Generate dashboard report")
|
||||
dash.add_argument("--product-id", type=int)
|
||||
dash.add_argument("--output", default="defectdojo_dashboard.json")
|
||||
|
||||
findings = sub.add_parser("findings", help="List findings")
|
||||
findings.add_argument("--product-id", type=int)
|
||||
findings.add_argument("--severity")
|
||||
findings.add_argument("--limit", type=int, default=20)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
global DD_URL, DD_API_KEY
|
||||
DD_URL = args.url
|
||||
if args.api_key:
|
||||
DD_API_KEY = args.api_key
|
||||
|
||||
if args.command == "setup":
|
||||
pt_id = create_product_type(args.product_type)
|
||||
prod_id = create_product(args.product, pt_id)
|
||||
create_engagement(args.engagement, prod_id)
|
||||
elif args.command == "import":
|
||||
import_scan(args.file, args.scan_type, args.product, args.engagement)
|
||||
elif args.command == "dashboard":
|
||||
generate_dashboard_report(args.output, args.product_id)
|
||||
elif args.command == "findings":
|
||||
result = get_findings(args.product_id, args.severity, limit=args.limit)
|
||||
for f in result.get("results", []):
|
||||
print(f" [{f['severity']}] {f['title']} (ID: {f['id']})")
|
||||
else:
|
||||
parser.print_help()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user