{# When the component search returns zero matching versions (or a legitimate search yields no findings and no zero-day actions), data_transformer exits early before the transform function runs, so the transform's _empty_result never populates `summary`/`actions`/`suppressed` in the template context. Default them here so the template renders a structurally valid page instead of blowing up on "'summary' is undefined". #} {% set summary = summary | default({}) %} {% if not summary is mapping %}{% set summary = {} %}{% endif %} {% set actions = actions | default([]) %} {% set suppressed = suppressed | default([]) %} {% set ai_prompts = ai_prompts | default([]) %} {% if render_mode != 'fragment' %} {% if domain %}{% endif %} Component Remediation Package — {{ summary.get('component_name', 'Unknown') }} {# No charts in this recipe (output.charts: []) — ECharts CDN is intentionally NOT included. Only design-system tokens + console shell chrome. #} {% 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, scopes under .fs-section-component-remediation-package, and re-emits at the top of the fragment. #} {% if render_mode != 'fragment' %} {% endif %} {% import "_console_macros.html" as fs with context %} {# Build topbar meta items conditionally. #} {% set crp_meta = [{"label": "Domain", "value": domain or "—"}] %} {% set _ = crp_meta.append({"label": "Scope", "value": scope_label or "All Projects"}) %} {% if summary.get('component_name') %} {% set _ = crp_meta.append({"label": "Component", "value": summary.component_name}) %} {% endif %} {% if summary.get('version_range') %} {% set _ = crp_meta.append({"label": "Version range", "value": summary.version_range}) %} {% endif %} {% set _ = crp_meta.append({"label": "Generated", "value": generated_at or "—"}) %} {% if render_mode != 'fragment' %} {{ fs.topbar( crumbs=["Finite State", "Component Remediation Package"], meta=crp_meta, controls=[], ) }} {% endif %}

Component Remediation Package

{{ summary.get('component_name', 'Unknown Component') }}{% if summary.get('version_range') %} · {{ summary.version_range }}{% endif %}

{# 5 KPI cells via fs.kpi_cell. #}
{{ fs.kpi_cell("Total Actions", summary.get('total_actions', 0)) }} {{ fs.kpi_cell( "Critical", summary.get('critical_actions', 0), dot=("critical" if summary.get('critical_actions', 0) > 0 else None), ) }} {{ fs.kpi_cell( "High", summary.get('high_actions', 0), dot=("high" if summary.get('high_actions', 0) > 0 else None), ) }} {{ fs.kpi_cell("Affected Projects", summary.get('affected_project_count', 0)) }} {{ fs.kpi_cell( "Zero-Day", summary.get('zero_day_actions', 0), ) }}
{% if actions %}
{{ fs.panel_head("Action cards", meta=((actions | length) | string) ~ " action" ~ ("s" if (actions | length) != 1 else "")) }}
{% for action in actions %} {% if action is mapping %} {% set sev = (action.get('max_severity', 'MEDIUM') | upper) %} {# Matches pre-migration default (round-1 M1-13) — actions with absent severity render as medium-styled, not unknown-styled. #} {% set sev_lc = sev | lower %}
{{ action.get('component_name', '') }} {{ action.get('component_version_name', '') }} {{ sev }}
{{ action.get('finding_count', 0) }} finding{{ 's' if action.get('finding_count', 0) != 1 }} {{ action.get('open_count', 0) }} open {{ (action.get('affected_projects', []) | length) }} project{{ 's' if (action.get('affected_projects', []) | length) != 1 }} Priority: {{ '%.1f' | format(action.get('priority_score', 0) | float) }}
{% if action.get('is_zero_day') %}
Zero-day — no CVE assigned
{% endif %} {% if action.get('cve_ids') %}
{% set chip_class = 'crp-cve-item-critical' if sev == 'CRITICAL' else ('crp-cve-item-high' if sev == 'HIGH' else '') %} {% for cve in action.cve_ids %} {{ cve }} {% endfor %}
{% endif %} {% if action.get('affected_projects') %}
Affected projects:
{% for proj in action.affected_projects %} {{ proj }} {% endfor %}
{% endif %} {% if action.get('upgrade_recommendation') %}
Upgrade recommendation: {{ action.upgrade_recommendation }}
{% endif %} {% if action.get('interim_mitigations') %}
Interim mitigations:
    {% for m in action.interim_mitigations %}
  • {{ m }}
  • {% endfor %}
{% endif %} {% if action.get('ai_guidance') %}
AI Remediation Guidance
{{ action.ai_guidance }}
{% endif %} {% if action.get('ai_prompt') %}
AI Prompt {% if action.ai_prompt.system %}
System: {{ action.ai_prompt.system }}
{% endif %} {% if action.ai_prompt.user %}
User: {{ action.ai_prompt.user }}
{% endif %} {% if action.ai_prompt.context %}
Context: {{ action.ai_prompt.context | tojson(indent=2) }}
{% endif %}
{% endif %}
{% endif %} {% endfor %}
{% endif %} {% if ai_prompts %}
{{ fs.panel_head("AI Prompts", meta=((ai_prompts | length) | string) ~ " prompt" ~ ("s" if (ai_prompts | length) != 1 else "")) }}
{% for prompt in ai_prompts %}
{{ prompt.get('id', 'Prompt ' ~ loop.index) }} {% if prompt.get('system') %}
System: {{ prompt.system }}
{% endif %} {% if prompt.get('user') %}
User: {{ prompt.user }}
{% endif %} {% if prompt.get('context') %}
Context: {{ prompt.context | tojson(indent=2) }}
{% endif %}
{% endfor %}
{% endif %} {% if suppressed %}
{{ fs.panel_head("Suppressed Findings", meta=((suppressed | length) | string) ~ " row" ~ ("s" if (suppressed | length) != 1 else "")) }}
Show suppressed findings {% for row in suppressed %} {% endfor %}
Component Version CVE Severity Status Project
{{ row.get('component_name', '') }} {{ row.get('component_version_name', '') }} {{ row.get('cve_id', '') }} {{ row.get('severity', '') }} {{ row.get('status', '') }} {{ row.get('project_name', '') }}
{% endif %}
{% if render_mode != 'fragment' %} {{ fs.status_bar(items=[ "Recipe: Component Remediation Package", "Actions: " ~ ((summary.get('total_actions', 0)) | string), "Affected projects: " ~ ((summary.get('affected_project_count', 0)) | string), generated_at | default(''), ], version='fs-report ' ~ (fs_report_version | default('dev'))) }} {% endif %} {% if render_mode != 'fragment' %} {% include '_action_buttons.html' %} {% endif %}