{% comment %} _includes/attack-flow.html ────────────────────────────────────────────────────────────────────── SVG swimlane attack-flow diagram, driven entirely from page.stages[]. Each stage may declare these optional fields (in addition to label/id): mitre_tactic – string, e.g. "TA0001" mitre_techniques – array of {id, name} detection_status – "blocked" | "detected" | "exploited" | "unknown" attacker_action – short string shown inside the stage box systems – short string shown in the detection row detection_signals – array of strings (used in the hover tooltip) Requires: assets/js/attack-flow.js, .af-* rules in style.css {% endcomment %} {% if page.stages %} {%- comment -%} ── Layout constants ──────────────────────────────── {%- endcomment -%} {% assign _n = page.stages | size %} {% assign _box_w = 160 %} {% assign _gap_px = 50 %} {% assign _col_w = 210 %} {%- comment -%} = box_w + gap_px {%- endcomment -%} {% assign _half_bw = 80 %} {%- comment -%} = box_w / 2 {%- endcomment -%} {% assign _box_h = 68 %} {% assign _left_w = 74 %} {%- comment -%} swimlane label column width {%- endcomment -%} {% assign _right_p = 16 %} {% assign _svg_h = 284 %} {%- comment -%} svg_w = left_w + n*box_w + (n-1)*gap + right_p {%- endcomment -%} {% assign _n_minus_1 = _n | minus: 1 %} {% assign _stages_w = _n | times: _box_w %} {% assign _gaps_w = _n_minus_1 | times: _gap_px %} {% assign _svg_w = _stages_w | plus: _gaps_w | plus: _left_w | plus: _right_p %} {%- comment -%} ── Swimlane Y boundaries ─────────────────────────── {%- endcomment -%} {%- comment -%} Lane 1 (Attacker): y=0 → 107 (box at y=14, h=68) {%- endcomment -%} {%- comment -%} Lane 2 (ATT&CK): y=107 → 188 {%- endcomment -%} {%- comment -%} Lane 3 (Detection): y=188 → 284 {%- endcomment -%}
{{ page.title }} - attack flow diagram Attack chain with {{ _n }} stages: {% for s in page.stages %}{{ s.label }}{% unless forloop.last %}, {% endunless %}{% endfor %}. Stages are color-coded by detection posture: red = exploited (gap), yellow = detected (opportunity), green = blocked (control active). {%- comment -%} ── Arrow-head marker defs (one per status color) ──────── {%- endcomment -%} {%- comment -%} ── Swimlane background bands ──────────────────────────── {%- endcomment -%} {%- comment -%} ── Swimlane labels (rotated, centered in each band) ─────── {%- endcomment -%} ATTACKER ATT&CK DETECTION {%- comment -%} ── Swimlane divider lines ────────────────────────────── {%- endcomment -%} {%- comment -%} ── Stage groups ─────────────────────────────────────── {%- endcomment -%} {% for stage in page.stages %} {%- comment -%} Position calculations {%- endcomment -%} {% assign _ix = forloop.index0 %} {% assign _bx = _ix | times: _col_w | plus: _left_w %} {% assign _cx = _half_bw | plus: _bx %} {% assign _status = stage.detection_status | default: 'unknown' %} {%- comment -%} Build pipe-delimited technique string for data attribute {%- endcomment -%} {% capture _tech_str %}{% for _t in stage.mitre_techniques %}{% unless forloop.first %}||{% endunless %}{{ _t.id }} - {{ _t.name }}{% endfor %}{% endcapture %} {%- comment -%} Build pipe-delimited signals string {%- endcomment -%} {% assign _sig_str = stage.detection_signals | join: "||" %} {%- comment -%} Human-readable status label {%- endcomment -%} {% if _status == 'exploited' %}{% assign _status_label = 'Exploited - Detection Gap' %} {% elsif _status == 'detected' %}{% assign _status_label = 'Detected - Opportunity' %} {% elsif _status == 'blocked' %}{% assign _status_label = 'Blocked - Control Active' %} {% else %}{% assign _status_label = 'Unknown' %} {% endif %} {%- comment -%} ── Lane 1: Stage box ──────────────────────────── {%- endcomment -%} {%- comment -%} Stage label {%- endcomment -%} {{ stage.label }} {%- comment -%} Tactic ID badge {%- endcomment -%} {% if stage.mitre_tactic %} {{ stage.mitre_tactic }} {% endif %} {%- comment -%} Attacker action text {%- endcomment -%} {% if stage.attacker_action %} {{ stage.attacker_action | truncate: 26, "" }} {% endif %} {%- comment -%} ── Lane 2: ATT&CK technique IDs ──────────────── {%- endcomment -%} {% if stage.mitre_techniques %} {% for _tech in stage.mitre_techniques limit:3 %} {% assign _ty = forloop.index | times: 20 | plus: 114 %} {{ _tech.id }} {% endfor %} {% endif %} {%- comment -%} ── Lane 3: Detection status indicator ─────────── {%- endcomment -%} {%- comment -%} Icon inside dot {%- endcomment -%} {% if _status == 'blocked' %} ✓ {% elsif _status == 'detected' %} ◎ {% elsif _status == 'exploited' %} ✕ {% else %} ? {% endif %} {%- comment -%} Status label text {%- endcomment -%} {% if _status == 'exploited' %}EXPLOITED{% elsif _status == 'detected' %}DETECTED{% elsif _status == 'blocked' %}BLOCKED{% else %}UNKNOWN{% endif %} {%- comment -%} Systems context (small, below status label) {%- endcomment -%} {% if stage.systems %} {{ stage.systems | truncate: 22, "" }} {% endif %} {%- comment -%} ── Arrow to next stage (drawn within this stage's group) {%- endcomment -%} {% unless forloop.last %} {% assign _ax1 = _bx | plus: _box_w %} {% assign _ax2 = forloop.index | times: _col_w | plus: _left_w %} {% assign _arrow_y = 48 %} {% endunless %} {% endfor %}
{%- comment -%} Tooltip element (positioned + populated by attack-flow.js) {%- endcomment -%} {% endif %}