{# Defensive defaults — placed BEFORE the render-mode gate. #} {% set summary = summary | default({}) %} {% if summary is string or summary is not mapping %}{% set summary = {} %}{% endif %} {% set dossiers = dossiers | default([]) %} {% if dossiers is mapping or dossiers is string or dossiers is not iterable %}{% set dossiers = [] %}{% endif %} {% set mode = mode | default('summary') %} {% set main = main | default([]) %} {% import "_console_macros.html" as fs with context %} {% if render_mode != 'fragment' %} {% if domain %}{% endif %} CVE Impact — {{ recipe_name }} {# ECharts library — replaces Chart.js v4.4.1. The CDN script loads BEFORE _echarts_ready.html so the readiness wrapper can detect echarts.init. #} {% include "_echarts_ready.html" %} {% include "_design_system.html" %} {% include "_console_shell.html" %} {% endif %} {# Recipe-local styles — OUTSIDE the render-mode gate so fragment_extractor auto-scopes under .fs-section-cve-impact. All hex literals migrated to design tokens. #} {% if render_mode != 'fragment' %} {% endif %} {# Build topbar meta items. #} {% set ci_meta = [{"label": "Domain", "value": domain or "—"}] %} {% set _ = ci_meta.append({"label": "Mode", "value": (mode | capitalize) if mode else "Summary"}) %} {% if summary is mapping %} {% set _ = ci_meta.append({"label": "Unique CVEs", "value": (summary.get('total_cves', 0)) | string}) %} {% set _ = ci_meta.append({"label": "Projects", "value": (summary.get('total_projects', 0)) | string}) %} {% endif %} {% if metadata is mapping and metadata.get('start_date') and metadata.get('end_date') %} {% set _ = ci_meta.append({"label": "Period", "value": metadata.start_date ~ " → " ~ metadata.end_date}) %} {% endif %} {% set _ = ci_meta.append({"label": "Generated", "value": generated_at or "—"}) %} {% if render_mode != 'fragment' %} {{ fs.topbar( crumbs=["Finite State", "CVE Impact"], meta=ci_meta, controls=[], ) }} {% endif %}

CVE Impact

{% if mode == 'dossier' %} Per-CVE deep-dive across the portfolio {% else %} Portfolio-wide CVE distribution + top exposures {% endif %}

{% if summary is mapping and summary.get('total_cves', 0) > 0 %} {# KPI bar — conditional contents per mode. #}
{% if mode == 'dossier' %} {{ fs.kpi_cell("Severity", summary.get('worst_severity', '—') if summary is mapping else '—') }} {{ fs.kpi_cell("CVSS", summary.get('worst_cvss', 0) if summary is mapping else 0) }} {{ fs.kpi_cell("Projects", summary.get('total_projects', 0) if summary is mapping else 0) }} {{ fs.kpi_cell( "Reachable", summary.get('total_reachable', 0) if summary is mapping else 0, dot=("critical" if (summary is mapping and summary.get('total_reachable', 0) > 0) else None), ) }} {{ fs.kpi_cell( "Unreachable", summary.get('total_unreachable', 0) if summary is mapping else 0, dot=("low" if (summary is mapping and summary.get('total_unreachable', 0) > 0) else None), ) }} {{ fs.kpi_cell("Attack Vector", summary.get('worst_attack_vector', '—') if summary is mapping else '—') }} {% else %} {{ fs.kpi_cell("Unique CVEs", summary.get('total_cves', 0) if summary is mapping else 0) }} {{ fs.kpi_cell("Projects", summary.get('total_projects', 0) if summary is mapping else 0) }} {% set sevs = summary.get('severity_counts', {}) if summary is mapping else {} %} {{ fs.kpi_cell( "Critical", sevs.get('CRITICAL', 0), dot=("critical" if sevs.get('CRITICAL', 0) > 0 else None), ) }} {{ fs.kpi_cell( "High", sevs.get('HIGH', 0), dot=("high" if sevs.get('HIGH', 0) > 0 else None), ) }} {{ fs.kpi_cell( "Medium", sevs.get('MEDIUM', 0), dot=("medium" if sevs.get('MEDIUM', 0) > 0 else None), ) }} {{ fs.kpi_cell( "Low", sevs.get('LOW', 0), dot=("low" if sevs.get('LOW', 0) > 0 else None), ) }} {{ fs.kpi_cell( "Info / Unknown", (sevs.get('INFO', 0) + sevs.get('UNKNOWN', 0)), ) }} {% endif %}
{# Mode-branched body. #} {% if mode == 'summary' %} {# Portfolio summary mode: 2 ECharts + filterable table. #}

Severity Distribution

{% if render_mode == 'fragment' and not fragment_scripts_enabled %}
Chart unavailable in fragment view
{% else %}
{% endif %}

Top CVEs by Project Count

{% if render_mode == 'fragment' and not fragment_scripts_enabled %}
Chart unavailable in fragment view
{% else %}
{% endif %}

CVE Detail

{% if render_mode != 'fragment' %} {% endif %} {# The pre-migration template at cve_impact.html:216-247 iterates `table_data.rows` (NOT `main` directly) and accesses cells via row.get('CVE ID', '') etc. with the exact TITLE-CASE column names from _CSV_COLUMNS at cve_impact.py:374-394. The migrated template preserves that contract. #} {% if table_data and table_data.rows %} {% for row in table_data.rows %} {% endfor %}
CVE ID Severity CVSS Projects KEV EPSS Exploits Components
{{ row.get('CVE ID', '') }} {{ row.get('Severity', 'UNKNOWN') }} {{ "%.1f"|format(row.get('CVSS', 0)) }} {{ row.get('Affected Projects', 0) }} {% if row.get('KEV') %}KEV{% endif %} {{ "%.1f"|format(row.get('EPSS Percentile', 0) * 100) }}% {% if row.get('Exploits', 0) > 0 %}{{ row.get('Exploits', 0) }}{% endif %} {{ row.get('Components', '')[:60] }}{% if row.get('Components', '')|length > 60 %}…{% endif %}
{% else %}

No CVE data available.

{% endif %} {% else %} {# Dossier mode: per-CVE deep-dive blocks. Field names + DOM structure match the pre-migration template at cve_impact.html:251-420 — preserve all 11 sub-sections: header (NVD link + severity + CVSS + KEV/exploit chips), description, nvd_unavailable banner, meta items (CWE link + EPSS + first/last detected + attack vector + vuln_functions), known exploits table, AI prompt (--ai-prompts), AI remediation guidance dict (--ai), affected-projects table with entity-link deep-linking. project_details fields per cve_impact.py:706-719 (project_name, project_version, reachability_label, etc. — NOT project/version/reachability). #} {% for d in dossiers %} {% if d is mapping %}

{{ d.cve_id }}

{{ d.severity or 'UNKNOWN' }} CVSS {{ "%.1f"|format(d.cvss|default(0)) }} {% if d.kev %}CISA KEV{% endif %} {% if d.has_exploit %}Known Exploit{% endif %}
{# Description (full NVD description; falls back to title) #} {% if d.description %}

{{ d.description }}

{% elif d.title %}

{{ d.title }}

{% endif %} {# nvd_unavailable warning banner #} {% if d.nvd_unavailable %}

NVD data was unavailable for this CVE. Description and fix-version data may be incomplete. Check NVD directly.

{% endif %} {# Vulnerability metadata #}
{% if d.cwe %}
CWE: {% if d.cwe_url %}{{ d.cwe }}{% else %}{{ d.cwe }}{% endif %}
{% endif %}
EPSS: {{ "%.1f"|format(d.epss_percentile|default(0) * 100) }}th percentile
First Detected: {{ d.first_detected[:10] if d.first_detected else 'N/A' }}
Last Detected: {{ d.last_detected[:10] if d.last_detected else 'N/A' }}
{% if d.attack_vector and d.attack_vector != 'N/A' %}
Attack Vector: {{ d.attack_vector }}
{% endif %} {% if d.vuln_functions %}
Vulnerable Functions: {{ d.vuln_functions }}
{% endif %}
{# Known Exploits table #}

Known Exploits

{% if d.exploit_details and d.exploit_details | length > 0 %} {% for exp in d.exploit_details %} {% if exp is mapping %} {% endif %} {% endfor %}
SourceURLDescriptionMaturityType
{{ exp.source }} {% if exp.url %}{{ exp.url[:60] }}{% if exp.url|length > 60 %}…{% endif %}{% else %}—{% endif %} {{ exp.description[:150] if exp.description else '—' }}{% if exp.description and exp.description|length > 150 %}…{% endif %} {{ exp.maturity|default('—', true) }} {{ exp.type|default('—', true) }}
{% else %}

None known.

{% endif %}
{# AI Prompt (--ai-prompts) — raw prompt string in
 with Copy button #}
                {% if d.ai_prompt %}
                
AI Prompt (click to expand, copy & paste into any LLM)
{% if render_mode != 'fragment' %} {% endif %}
{{ d.ai_prompt }}
{% endif %} {# AI Remediation Guidance (--ai) — STRUCTURED DICT, NOT a string. Per cve_impact.py:998-1000 and pre-migration template at cve_impact.html:352-371, ai_guidance has keys: fix_version, guidance, workaround, code_search_hints, project_notes (optional), confidence. #} {% if d.ai_guidance %}

AI Remediation Guidance

{% if d.ai_guidance.project_notes and d.ai_guidance.project_notes != '—' %} {% endif %}
Fix Version{{ d.ai_guidance.fix_version|default('—', true) }}
Guidance{{ d.ai_guidance.guidance|default('—', true) }}
Workaround{{ d.ai_guidance.workaround|default('—', true) }}
Code Search{{ d.ai_guidance.code_search_hints|default('—', true) }}
Project Notes {{ d.ai_guidance.project_notes }}
Confidence{{ d.ai_guidance.confidence|default('—', true) }}
{% endif %} {# Affected Projects — preserve domain-based entity deep-links. project_details field names per cve_impact.py:706-719: project_name, project_id, project_version, project_version_id, component, component_id, finding_internal_id, reachability_label, triage_status, detected. #}

Affected Projects

Affects {{ d.affected_count }} project{{ 's' if d.affected_count != 1 else '' }}. {% if d.reachable_count > 0 %} Reachable in {{ d.reachable_count }}. {% endif %} {% if d.unreachable_count > 0 %} Unreachable in {{ d.unreachable_count }}. {% endif %} {% if d.unknown_count > 0 %} Inconclusive in {{ d.unknown_count }}. {% endif %}
{% if d.project_details and d.project_details | length > 0 %} {% for p in d.project_details %} {% if p is mapping %} {% endif %} {% endfor %}
Project Version Reachability Component Status Detected
{% if domain and p.project_id and p.project_version_id and p.finding_internal_id %}{{ p.project_name }}{% elif domain and p.project_id %}{{ p.project_name }}{% else %}{{ p.project_name }}{% endif %} {% if domain and p.project_id and p.project_version_id %}{{ p.project_version }}{% else %}{{ p.project_version }}{% endif %} {{ p.reachability_label }} {% if domain and p.project_id and p.project_version_id and p.component_id %}{{ p.component }}{% else %}{{ p.component }}{% endif %} {{ p.triage_status|default('—') if p.triage_status else '—' }} {{ p.detected[:10] if p.detected else '—' }}
{% endif %}
{% endif %} {% endfor %} {% endif %} {% else %}

No CVE data available for the selected filters.

{% endif %}
{% if render_mode != 'fragment' %} {{ fs.status_bar(items=[ "Recipe: CVE Impact", "Mode: " ~ (mode | capitalize), "CVEs: " ~ ((summary.get('total_cves', 0) if summary is mapping else 0) | string), generated_at | default(''), ], version='fs-report ' ~ (fs_report_version | default('dev'))) }} {% endif %} {% if render_mode != 'fragment' or fragment_scripts_enabled %} {% include '_action_buttons.html' %} {% endif %}