{# Extended Threat Modeling dashboard: coverage, a portfolio-total STRIDE x asset-class matrix plus one per project, threat disposition (tested vs. untested mitigations), accepted threats reconciled with recorded human owners, models needing rework, recurring threat archetypes, model-depth mix, post-build misses, and falsified assumptions. See web/threat_modeling_dashboard.py for what's real vs. approximated. #} {% macro stride_table(matrix) %}
| Asset class | {% for letter in ["S", "T", "R", "I", "D", "E"] %}{{ letter }} | {% endfor %}
|---|---|
| {{ row.asset_class }} | {% for letter in ["S", "T", "R", "I", "D", "E"] %} {% set n = row.cells[letter] %}{{ n if n else "—" }} | {% endfor %}
Empty cells are the signal — a blank column means that category was never exercised, not that it's safe from it.
Portfolio total (every modeled project, summed)By project — a blank cell here is a real gap on that specific system; the total above can't say which project it came from.
Every threat marked Accepted, reconciled with who actually signed off — secfoo accept create is how "not recorded" turns into a real name.
| Threat | Project | Accepted by |
|---|---|---|
| {{ item.threat }} | {{ item.project }} | {% if item.accepted_by %}{{ item.accepted_by }} {% else %}Not recorded{% endif %} |
No accepted threats yet.
{% endif %}| Project | State | Last modeled |
|---|---|---|
| {{ p.project_display_name }} | {% if p.state == "never_reviewed" %}Never modeled {% elif p.state == "boundary_changed" %}Trust boundary changed {% else %}Stale ({{ p.days_since_review }}d){% endif %} | {{ (p.last_reviewed_at | fmt_time) if p.last_reviewed_at else "Never" }} |
None recorded yet — see secfoo miss.
No falsified assumptions recorded yet.
{% endif %}