--- # library/report.yml # # Included last in every playbook run by site.yml. Aggregates the # shared test_results[] list into a structured JSON compliance report. # # What it does: # 1. Assembles __report dict with meta, summary, by_category, # by_severity, failures, and the full results list # 2. Prints a boxed summary to the Ansible console # 3. Writes JSON to reports/-.json # (delegated to localhost so reports land on the control node) # # The JSON schema is documented in README.md § "JSON Output Schema". - name: "REPORT: Assemble compliance report" ansible.builtin.set_fact: __report: "{{ { 'meta': { 'standard': 'IEC 62443-3-3', 'security_level': 'SL2', 'target': inventory_hostname, 'timestamp': ansible_date_time.iso8601, 'executed_by': ansible_user_id }, 'summary': { 'total': test_results | length, 'passed': test_results | selectattr('passed', 'equalto', true) | list | length, 'failed': test_results | selectattr('passed', 'equalto', false) | list | length, 'skipped': test_results | selectattr('passed', 'equalto', 'skipped') | list | length }, 'by_category': test_results | groupby('category') | map( 'regex_replace', '^(.*)$', '\\1' ) | list, 'by_severity': { 'critical': test_results | selectattr('severity', 'equalto', 'critical') | list, 'high': test_results | selectattr('severity', 'equalto', 'high') | list, 'medium': test_results | selectattr('severity', 'equalto', 'medium') | list, 'low': test_results | selectattr('severity', 'equalto', 'low') | list }, 'failures': test_results | selectattr('passed', 'equalto', false) | list, 'results': test_results } }}" - name: "REPORT: Display summary to console" ansible.builtin.debug: msg: | ╔══════════════════════════════════════════════════════════════╗ ║ IEC 62443-3-3 SL2 Compliance Report — {{ inventory_hostname }} ╠══════════════════════════════════════════════════════════════╣ ║ Total: {{ __report.summary.total }} Passed: {{ __report.summary.passed }} Failed: {{ __report.summary.failed }} Skipped: {{ __report.summary.skipped }} ╚══════════════════════════════════════════════════════════════╝ {% for f in __report.failures %} ✗ {{ f.test_id }}: {{ f.description }} Expected: {{ f.expected }} Actual: {{ f.actual }} {% endfor %} - name: "REPORT: Write JSON to local file" ansible.builtin.copy: content: "{{ __report | to_nice_json(indent=2) }}" dest: "./reports/{{ inventory_hostname }}-{{ ansible_date_time.date }}.json" delegate_to: localhost run_once: true