{# Defensive defaults block — placed before the render-mode gate per C.1 round-2 M1-2. Mirrors C.1 component_remediation_package.html. #} {% set remediation_summary = remediation_summary | default({}) %} {% if not remediation_summary is mapping %}{% set remediation_summary = {} %}{% endif %} {# Collection-level guards (round-2 PR multi-review M1-2): coerce non-list values to [] so selectattr / iteration doesn't break on upstream data drift. Also coerces non-iterable scalars (e.g. ints) that would otherwise blow up `| length` / `for row in ...`. #} {% set actions_df = actions_df | default([]) %} {% if actions_df is mapping or actions_df is string or actions_df is not iterable %}{% set actions_df = [] %}{% endif %} {% set suppressed_df = suppressed_df | default([]) %} {% if suppressed_df is mapping or suppressed_df is string or suppressed_df is not iterable %}{% set suppressed_df = [] %}{% endif %} {% set unresolvable_df = unresolvable_df | default([]) %} {% if unresolvable_df is mapping or unresolvable_df is string or unresolvable_df is not iterable %}{% set unresolvable_df = [] %}{% endif %} {% set project_agent_prompt = project_agent_prompt | default('') %} {% import "_console_macros.html" as fs with context %} {% if render_mode != 'fragment' %} {% if domain %}{% endif %} Remediation Package - Finite State Report {# No charts in this recipe (output.charts: []) — ECharts CDN is intentionally NOT included. marked.js + DOMPurify ARE included for AI-analysis markdown → HTML rendering (preserved from pre-migration). #} {% include "_design_system.html" %} {% include "_console_shell.html" %} {% endif %} {# Recipe-local styles — render in BOTH standalone and fragment modes so fragment_extractor (_STYLE_RE) collects them. #} {% if render_mode != 'fragment' %} {% endif %} {# Build topbar meta items conditionally. #} {% set rp_meta = [{"label": "Domain", "value": domain or "—"}] %} {% if scope_label %} {% set _ = rp_meta.append({"label": "Scope", "value": scope_label}) %} {% else %} {% set _ = rp_meta.append({"label": "Scope", "value": "All Projects"}) %} {% endif %} {% if project_name %} {% set _ = rp_meta.append({"label": "Project", "value": project_name}) %} {% endif %} {% if project_version %} {% set _ = rp_meta.append({"label": "Version", "value": project_version}) %} {% endif %} {% set _ = rp_meta.append({"label": "Generated", "value": generated_at or "—"}) %} {% if render_mode != 'fragment' %} {{ fs.topbar( crumbs=["Finite State", "Remediation Package"], meta=rp_meta, controls=[], ) }} {% endif %} {# Round-1 PR multi-review M1-10: comma-split scope_label into an exact CVE-ID list so the "expand-matched-CVE" check doesn't false-match `CVE-2024-1` inside `CVE-2024-10`. Hoisted here so it's computed once for the whole actions loop below. #} {% set _scope_cves = (scope_label or '').split(',') | map('trim') | list %}

Remediation Package

{% if scope_label %}
Scope: {{ scope_label }}
{% endif %}

{{ project_name }}{% if project_version %} · {{ project_version }}{% endif %}

{% if remediation_summary %}
{{ fs.kpi_cell("Components", remediation_summary.get('total_components', 0)) }} {{ fs.kpi_cell("CVEs Resolved", remediation_summary.get('total_cves_resolved', 0)) }} {{ fs.kpi_cell("Suppressed", remediation_summary.get('suppressed_count', 0)) }} {{ fs.kpi_cell( "No Fix", remediation_summary.get('unresolvable_count', 0), dot=("medium" if remediation_summary.get('unresolvable_count', 0) > 0 else None), ) }}
{% if remediation_summary.by_priority is mapping %} {# Per-band tints emitted as inline style so the CSS block doesn't carry `rp-pill-p{0..3}` class names — see