"""Actionable reports from privacy-minimized evidence, without raw sidecars.""" import hashlib import html import json from pathlib import Path from samsara.core.privacy import minimize_inventory from samsara.core.storage import write_private from samsara.analyzers.assessment import assess from samsara.analyzers.summary import summarize MANUAL_STEPS = ['Confirm application and business owners and obtain administrator retirement approval.', 'Validate historical usage across a representative business cycle, including infrequent and offline jobs.', 'Review DNS, load balancers, monitoring, backups, firewall logs and service-account consumers.', 'Verify custom tasks and share consumers; resolve incomplete checks and confirm rollback/retention requirements.'] def private_assessment(data, assessment): # Never trust a marker or cached finding to authorize raw data disclosure. source=data.get('server',{}).get('collection_source') clean=minimize_inventory(data, trusted_source=source) policy=assessment.get('scoring',{}).get('policy') if isinstance(assessment,dict) else None if policy is not None: import copy policy=copy.deepcopy(policy) policy['name']='Deployment scoring policy' return clean, assess(clean, policy=policy) def export_json(path, data, assessment): data, assessment=private_assessment(data, assessment) write_private(path,json.dumps({'inventory_result':data,'assessment':assessment},indent=2)) def inventory_artifact(path, data): """Explicit minimized inventory export; never writes a raw sidecar.""" data=minimize_inventory(data) payload=(json.dumps(data,indent=2,ensure_ascii=True)+'\n').encode('utf-8') destination=Path(path).with_suffix('.inventory.json') write_private(destination,payload) return destination, hashlib.sha256(payload).hexdigest() def table(headers, rows): escape = lambda value: html.escape(str(value)) if not rows: return '

None identified in collected evidence. Review missing evidence before drawing conclusions.

' return '
' + ''.join('' for h in headers) + '' + ''.join(''+''.join('' for v in row)+'' for row in rows) + '
'+escape(h)+'
'+escape(v)+'
' def export_html(path, data, assessment): escape = lambda value: html.escape(str(value)) data, assessment = private_assessment(data, assessment) source = 'SYNTHETIC DEMO — no real collection performed.' if data['synthetic'] else 'IMPORTED INVENTORY — source assertions not independently verified.' for platform in ('Linux','Windows'): if not data['synthetic'] and data['server'].get('collection_source') == f'Local {platform} read-only collection': source = f'LOCAL {platform.upper()} INVENTORY — read-only snapshot of the execution host.' summary = summarize(data,assessment) scoring = assessment['scoring'] content = '

Samsara assessment

'+escape(source)+'

' content += '

Summary

' content += '

'+escape(data['server']['hostname'])+' · '+escape(data['collected_at'])+'

' content += f"
Retirement risk estimate: {escape(assessment['level']).title()} · {assessment['score']}/100

{escape(scoring['explanation'])}

" content += f"

Evidence coverage: {summary['coverage_percent']}% · Evidence confidence: {escape(summary['confidence'])} · {summary['incomplete']} checks need review.

" content += '

Coverage and uncertainty are separate from risk. A zero or low score is not retirement clearance. Historical usage validation and administrator approval are always required.

' content += f"

OS type: {escape(summary['os_type'])}
Version: {escape(summary['version'])}

" actionable = [row for row in assessment['findings'] if row['points']>0] content += '

Actionable workload findings

' content += table(['Workload','Classification','Workload score','Evidence','Why this affects scoring'],[(row['category'],row['classification'],row['points'],row['evidence'],row['scoring_reason']) for row in actionable]) content += '

How the score was calculated

'+escape(scoring['formula'])+'

' content += table(['Workload','Selected rule','Score','Determines final score','Evidence observations'],[(row['title'],row['selected_rule'],row['score'],'Yes (co-leading)' if row['determines_final_score'] else 'No; below the maximum',row['evidence_count']) for row in scoring['breakdown']]) content += '
Policy weights, thresholds and audit identity

Policy SHA-256: '+escape(scoring['policy_id'])+'

'+escape(json.dumps(scoring['policy'],indent=2))+'
' content += '

Important software

Inventory name hints only; installed software does not establish active use.

' content += table(['Software','Version','Evidence'],[(r['name'],r['version'],r['evidence']) for r in summary['software'][:12]]) content += '

Scheduled jobs and scripts

Nonroutine enabled schedules; configuration does not confirm execution. All tasks remain in the inventory.

' content += table(['Job','Schedule','State'],[(r['name'],r['schedule'],r['status']) for r in summary['jobs'][:12]]) context = [r for r in assessment['findings'] if r['points']==0 and r['id'] not in ('coverage','observation-limits')] content += '

Unscored context and review items

Routine services, administrative shares, client traffic and unknown observations do not receive workload points.

' content += table(['Category','Classification','Context'],[(r['category'],r['classification'],r['evidence']) for r in context]) directions = {} for row in assessment['network_observations']: directions[row['direction']] = directions.get(row['direction'],0)+1 content += '

Network interpretation

Direction inferred from listener/PID or ephemeral-port patterns is a heuristic, not a captured initiating handshake. Confirmed workload findings describe attributed observed transport activity, not verified business ownership.

' content += table(['Direction / activity','Observations'],list(sorted(directions.items()))) content += '

Collection checks / missing evidence

Failed and partial checks reduce confidence; they never add workload risk points.

' checks = [] for name in sorted(set(data['checks']) | set(assessment['scoring']['policy']['coverage_weights'])): row = data['checks'].get(name,{'status':'not_collected','message':'No status supplied.'}) errors = '; '.join(f"{e['code']}: {e['message']}" for e in row.get('errors',[])) checks.append((name,row['status'],row.get('started_at','Not supplied'),row.get('completed_at','Not supplied'),row['message'],errors,'; '.join(row.get('permission_limitations',[])),'; '.join(row.get('limitations',[])))) content += table(['Check','Status','started_at (UTC)','completed_at (UTC)','Result','Errors','permission_limitations','Scope limitations'],checks) content += '

Recommended manual verification

' content += '

Privacy and omitted evidence

Identifying names, accounts, task commands, certificate identities and unapproved paths are omitted. No raw inventory sidecar is generated. JSON export contains the same minimized evidence. Numeric IP addresses remain confidential infrastructure metadata. This report does not establish PHI-free operation or HIPAA compliance.

' content += table(['Inventory section','Rows'],[(name,len(rows)) for name,rows in data['inventory'].items()]) css = 'body{font:15px system-ui;max-width:1180px;margin:32px auto;padding:20px;color:#233044;line-height:1.55}h1,h2{color:#173c60}.muted{color:#667}.source,.card,details{background:#eef3f8;padding:16px;border-radius:7px}.table{overflow-x:auto}table{border-collapse:collapse;width:100%;margin:12px 0}th,td{border:1px solid #d9e0e8;text-align:left;vertical-align:top;padding:9px;white-space:pre-wrap;overflow-wrap:anywhere}th{background:#eef3f8}pre{white-space:pre-wrap;overflow-wrap:anywhere}a{color:#1263a3}' write_private(path,'Samsara'+content+'')