32 lines
3.1 KiB
Python
32 lines
3.1 KiB
Python
import html
|
|
import json
|
|
from pathlib import Path
|
|
from samsara.analyzers.summary import summarize
|
|
|
|
MANUAL_STEPS = ["Confirm application and business owners and obtain retirement approval.",
|
|
"Review historical monitoring, DNS, load balancers, backups and firewall logs.",
|
|
"Validate service accounts, scheduled workloads and SMB/NFS/Samba consumers with owners.",
|
|
"Resolve failed or missing checks and verify rollback and retention requirements."]
|
|
|
|
def export_json(path, data, assessment):
|
|
Path(path).write_text(json.dumps({"inventory_result": data, "assessment": assessment}, indent=2), encoding="utf-8")
|
|
|
|
def export_html(path, data, assessment):
|
|
escape = lambda value: html.escape(str(value))
|
|
content = "<h1>Samsara assessment</h1><p>SYNTHETIC DEMO — no real collection performed.</p>" if data["synthetic"] else "<h1>Samsara assessment</h1><p>IMPORTED INVENTORY — source assertions not independently verified.</p>"
|
|
if not data['synthetic'] and data['server'].get('collection_source') == 'Local Linux read-only collection':
|
|
content = '<h1>Samsara assessment</h1><p>LOCAL LINUX INVENTORY — read-only snapshot of the execution host.</p>'
|
|
content += "<p>Heuristic requiring administrator review. This report does not authorize retirement.</p>"
|
|
summary = summarize(data, assessment)
|
|
content += f"<h2>Summary</h2><p>Retirement risk estimate: {escape(summary['risk_level'])} ({summary['risk_score']}/100). Higher scores mean more retirement concerns.</p>"
|
|
content += f"<p>OS type: {escape(summary['os_type'])}<br>Version: {escape(summary['version'])}<br>Incomplete or missing checks: {summary['incomplete']}</p>"
|
|
content += '<h3>Important software</h3><p>Workload name hints and application services; use unverified.</p><ul>'
|
|
content += ''.join(f"<li>{escape(row['name'])} — {escape(row['version'])}</li>" for row in summary['software']) or '<li>No workload name matches observed; review full inventory and missing checks.</li>'
|
|
content += '</ul><h3>Scheduled jobs and scripts</h3><p>Configured schedules do not confirm execution.</p><ul>'
|
|
content += ''.join(f"<li>{escape(row['name'])} — {escape(row['schedule'])}</li>" for row in summary['jobs']) or '<li>No enabled schedules observed; scheduler coverage may be incomplete.</li>'
|
|
content += '</ul>'
|
|
for title, value in [("Server overview", data["server"]), ("Collection timestamp", data["collected_at"]), ("Inventory", data["inventory"]), ("Dependencies and risk findings", assessment["findings"]), ("Collection checks / missing evidence", data["checks"])]:
|
|
content += f"<h2>{title}</h2><pre>{escape(json.dumps(value, indent=2))}</pre>"
|
|
content += "<h2>Recommended manual verification</h2><ul>" + "".join(f"<li>{escape(s)}</li>" for s in MANUAL_STEPS) + "</ul>"
|
|
Path(path).write_text('<!doctype html><html lang="en"><meta charset="utf-8"><title>Samsara</title><style>body{font:16px system-ui;max-width:1100px;margin:40px auto;padding:20px}pre{white-space:pre-wrap;background:#eee;padding:16px}</style>' + content + '</html>', encoding="utf-8")
|