Files
mukul975 c47eed6a64 Production hardening: security fixes, code quality, 724 skills complete
- Fix 25 shell=True subprocess calls with list-based commands
- Fix 49 verify=False in defensive skills (env-var override)
- Add timeout to 231 HTTP/subprocess/socket calls
- Fix 6 SQL injection patterns with whitelist validation
- Replace 8 __import__() with standard imports
- Remove 701 unused imports across 442 files
- Add authorized-testing disclaimers to all offensive skills
- Complete 11 incomplete skill directories
- Expand 10 stub SKILL.md files with full content
- Fix 2 YAML parse errors in frontmatter
- Fix 5 pre-existing syntax errors
- Convert 22 hardcoded paths/ports to environment variables
- Back up 21 redundant skill pairs to .bak
- Fix 2 global declaration errors
- 724/724 skills with full folder anatomy (SKILL.md + agent.py + api-reference.md + LICENSE)
- 0 compile errors across all 724 agent.py files
2026-03-19 13:26:49 +01:00

237 lines
9.8 KiB
Python

#!/usr/bin/env python3
"""Incident ticketing system agent supporting ServiceNow and TheHive."""
import json
import sys
import argparse
from datetime import datetime
try:
import requests
except ImportError:
print("Install requests: pip install requests")
sys.exit(1)
class ServiceNowClient:
"""Client for ServiceNow Incident Management REST API."""
def __init__(self, instance, username, password):
self.base_url = f"https://{instance}.service-now.com/api/now"
self.session = requests.Session()
self.session.auth = (username, password)
self.session.headers.update({"Accept": "application/json",
"Content-Type": "application/json"})
def create_incident(self, short_desc, description, urgency=2, impact=2, category="Security"):
"""Create a new security incident in ServiceNow."""
data = {"short_description": short_desc, "description": description,
"urgency": urgency, "impact": impact, "category": category,
"assignment_group": "Security Operations",
"contact_type": "Automated"}
resp = self.session.post(f"{self.base_url}/table/incident", json=data, timeout=30)
resp.raise_for_status()
result = resp.json().get("result", {})
return {"number": result.get("number"), "sys_id": result.get("sys_id"),
"state": result.get("state"), "priority": result.get("priority")}
def update_incident(self, sys_id, update_data):
"""Update an existing incident."""
resp = self.session.patch(f"{self.base_url}/table/incident/{sys_id}", json=update_data, timeout=30)
resp.raise_for_status()
return resp.json().get("result", {})
def get_incident(self, number):
"""Get incident details by number."""
resp = self.session.get(f"{self.base_url}/table/incident",
params={"sysparm_query": f"number={number}"}, timeout=30)
resp.raise_for_status()
results = resp.json().get("result", [])
return results[0] if results else None
def list_open_incidents(self, category="Security", limit=50):
"""List open security incidents."""
query = f"category={category}^state!=7^state!=8"
resp = self.session.get(f"{self.base_url}/table/incident",
params={"sysparm_query": query, "sysparm_limit": limit,
"sysparm_fields": "number,short_description,priority,state,"
"opened_at,assigned_to,urgency"}, timeout=30)
resp.raise_for_status()
return resp.json().get("result", [])
def add_work_note(self, sys_id, note):
"""Add a work note to an incident."""
return self.update_incident(sys_id, {"work_notes": note})
def close_incident(self, sys_id, close_notes, close_code="Solved (Permanently)"):
"""Close an incident with resolution notes."""
return self.update_incident(sys_id, {
"state": "7", "close_code": close_code,
"close_notes": close_notes})
class TheHiveClient:
"""Client for TheHive incident response platform API."""
def __init__(self, base_url, api_key):
self.base_url = base_url.rstrip("/")
self.session = requests.Session()
self.session.headers.update({"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"})
def create_case(self, title, description, severity=2, tlp=2, tags=None):
"""Create a new case in TheHive."""
data = {"title": title, "description": description,
"severity": severity, "tlp": tlp,
"tags": tags or ["security-incident"],
"flag": False, "status": "Open"}
resp = self.session.post(f"{self.base_url}/api/case", json=data, timeout=30)
resp.raise_for_status()
result = resp.json()
return {"id": result.get("_id"), "caseId": result.get("caseId"),
"title": result.get("title"), "status": result.get("status")}
def create_task(self, case_id, title, description="", group="default"):
"""Create a task within a case."""
data = {"title": title, "description": description, "group": group,
"status": "Waiting"}
resp = self.session.post(f"{self.base_url}/api/case/{case_id}/task", json=data, timeout=30)
resp.raise_for_status()
return resp.json()
def add_observable(self, case_id, data_type, data_value, tlp=2, message=""):
"""Add an observable (IOC) to a case."""
obs_data = {"dataType": data_type, "data": data_value, "tlp": tlp,
"message": message, "ioc": True}
resp = self.session.post(f"{self.base_url}/api/case/{case_id}/artifact", json=obs_data, timeout=30)
resp.raise_for_status()
return resp.json()
def list_cases(self, status="Open", limit=50):
"""List cases with optional status filter."""
query = {"query": {"_field": "status", "_value": status}}
resp = self.session.post(f"{self.base_url}/api/case/_search",
json=query, params={"range": f"0-{limit}"}, timeout=30)
resp.raise_for_status()
return resp.json()
def get_case(self, case_id):
"""Get case details."""
resp = self.session.get(f"{self.base_url}/api/case/{case_id}", timeout=30)
resp.raise_for_status()
return resp.json()
def close_case(self, case_id, summary, impact_status="NoImpact"):
"""Close a case with summary."""
data = {"status": "Resolved", "summary": summary,
"impactStatus": impact_status, "resolutionStatus": "TruePositive"}
resp = self.session.patch(f"{self.base_url}/api/case/{case_id}", json=data, timeout=30)
resp.raise_for_status()
return resp.json()
def calculate_sla_metrics(incidents):
"""Calculate SLA compliance metrics from incident data."""
sla_targets = {"1": 60, "2": 240, "3": 480, "4": 1440}
metrics = {"total": len(incidents), "within_sla": 0, "breached": 0,
"avg_response_min": 0, "by_priority": {}}
total_response = 0
for inc in incidents:
priority = str(inc.get("priority", "3"))
opened = inc.get("opened_at", "")
if priority not in metrics["by_priority"]:
metrics["by_priority"][priority] = {"total": 0, "within_sla": 0}
metrics["by_priority"][priority]["total"] += 1
metrics["sla_compliance_pct"] = round(
metrics["within_sla"] / max(metrics["total"], 1) * 100, 1)
return metrics
def run_ticketing_audit(snow_client=None, hive_client=None):
"""Run ticketing system audit."""
print(f"\n{'='*60}")
print(f" INCIDENT TICKETING SYSTEM AUDIT")
print(f" Generated: {datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')} UTC")
print(f"{'='*60}\n")
report = {}
if snow_client:
incidents = snow_client.list_open_incidents()
print(f"--- SERVICENOW INCIDENTS ({len(incidents)} open) ---")
for inc in incidents[:10]:
print(f" [{inc.get('priority', 'N/A')}] {inc.get('number')}: "
f"{inc.get('short_description', '')[:50]}")
metrics = calculate_sla_metrics(incidents)
print(f"\n--- SLA METRICS ---")
print(f" Total open: {metrics['total']}")
print(f" SLA compliance: {metrics['sla_compliance_pct']}%")
report["servicenow"] = {"open": len(incidents), "metrics": metrics}
if hive_client:
cases = hive_client.list_cases()
print(f"\n--- THEHIVE CASES ({len(cases)} open) ---")
for case in cases[:10]:
print(f" [Sev:{case.get('severity', 'N/A')}] #{case.get('caseId')}: "
f"{case.get('title', '')[:50]}")
report["thehive"] = {"open_cases": len(cases)}
print(f"\n{'='*60}\n")
return report
def main():
parser = argparse.ArgumentParser(description="Incident Ticketing System Agent")
sub = parser.add_subparsers(dest="platform")
snow = sub.add_parser("servicenow")
snow.add_argument("--instance", required=True, help="ServiceNow instance name")
snow.add_argument("--username", required=True)
snow.add_argument("--password", required=True)
snow.add_argument("--audit", action="store_true")
snow.add_argument("--create", nargs=2, metavar=("TITLE", "DESC"), help="Create incident")
hive = sub.add_parser("thehive")
hive.add_argument("--url", required=True, help="TheHive URL")
hive.add_argument("--api-key", required=True)
hive.add_argument("--audit", action="store_true")
hive.add_argument("--create", nargs=2, metavar=("TITLE", "DESC"), help="Create case")
parser.add_argument("--output", help="Save report to JSON")
args = parser.parse_args()
if args.platform == "servicenow":
client = ServiceNowClient(args.instance, args.username, args.password)
if args.audit:
report = run_ticketing_audit(snow_client=client)
elif args.create:
result = client.create_incident(args.create[0], args.create[1])
print(json.dumps(result, indent=2))
return
else:
parser.print_help()
return
elif args.platform == "thehive":
client = TheHiveClient(args.url, args.api_key)
if args.audit:
report = run_ticketing_audit(hive_client=client)
elif args.create:
result = client.create_case(args.create[0], args.create[1])
print(json.dumps(result, indent=2))
return
else:
parser.print_help()
return
else:
parser.print_help()
return
if args.output:
with open(args.output, "w") as f:
json.dump(report, f, indent=2, default=str)
print(f"[+] Report saved to {args.output}")
if __name__ == "__main__":
main()