Files
pxe-server/webapp/templates/_nic_status.html
cproudlock 606659bf07 webapp: fix review findings (imaging types, NIC status, iPXE gates)
- imaging: coerce client payload and stored session fields to str/int,
  drop lists/dicts; tiles template guards pctype/current_stage; POST
  rejects non-object bodies and non-string serials.
- nic_status: normalise every check-file entry; load nic.conf as-is with
  a [nic] fallback; split interface= lists; keep the check's binding while
  fresh, resolve wildcard sockets from the dnsmasq pin (never True for an
  excluded NIC); mark vanished NICs down; include role bridges; stale or
  future-dated files downgrade to warnings and drop evidence.
- Overview renders the network pill in its own try and shows
  'Network: unknown' when status fails.
- ipxe_update: read every Authenticode signature (all WIN_CERTIFICATE
  entries plus nested SPC_NESTED_SIGNATURE) with openssl; shim swap and
  install need both Microsoft UEFI CA 2011 and 2023; install re-reads
  each file (snponly ipxe.efi only); staged.json schema version, older
  records shown stale and refused; uhci counts as native USB.
- backups describe their files; risky rollbacks need a confirm flag.
- mac_folders: guarded listdir, cached describe, configured TFTP root,
  warning for a shim without ipxe.efi.
- evidence pack: years 2000..2100, 400 days inclusive.
- a11y role=group on quick ranges; progress bar stays full during 'shim'.
- tests/test_review_fixes.py: 29 unittest cases incl. both real shims.
2026-10-15 14:20:24 -04:00

51 lines
4.0 KiB
HTML

{# Overview network pill and its problem notice. Rendered on its own by
the dashboard view (part = 'pill' or 'notice') inside a try, so a broken
status file can never take the Overview down. #}
{% import '_ui.html' as ui %}
{% if part == 'pill' %}
{% set nic_dot = {'ok': 'var(--ok)', 'warn': 'var(--act)', 'bad': 'var(--fail)'}.get(nic.state, 'var(--off-edge)') %}
{% set role_name = {'imaging': 'Imaging', 'ge': 'GE network', 'other': 'Other'} %}
{% set verdict_chip = {'isolated': ('Isolated', 'ok'), 'ge': ('GE network', 'neutral'), 'foreign-dhcp': ('Other DHCP server', 'err'),
'no-link': ('No link', 'off'), 'error': ('Check failed', 'warn')} %}
<details class="more">
<summary class="fbtn" style="background: var(--surface); min-height: 36px">
<span class="dot" style="background: {{ nic_dot }}"></span>
{{ {'ok': 'Network OK', 'warn': 'Network: check', 'bad': 'Network: DANGER'}.get(nic.state, 'Network: unknown') }}
<span class="chev" aria-hidden="true">&#9662;</span>
</summary>
<div class="menu" style="width: min(460px, calc(100vw - 32px)); padding: 12px 14px; gap: 10px; font-size: 13px">
{% for i in nic.interfaces %}
{% set bad_here = (i.role == 'imaging' and i.verdict in ('ge', 'foreign-dhcp')) or (i.role != 'imaging' and i.dnsmasq_bound) %}
<div style="display: flex; flex-direction: column; gap: 4px">
<div style="display: flex; align-items: center; gap: 8px; flex-wrap: wrap">
<span class="dot" style="background: {{ 'var(--fail)' if bad_here else ('var(--ok)' if i.link == 'up' else 'var(--act)') }}"></span>
<strong>{{ role_name.get(i.role, i.role) }}</strong>
<span class="mono muted">{{ i.iface }}</span>
{% if i.verdict and i.verdict in verdict_chip %}{% set vc = verdict_chip[i.verdict] %}{{ ui.chip(vc[0], 'err' if bad_here else vc[1]) }}{% endif %}
</div>
<div class="muted" style="padding-left: 18px; white-space: normal">
{{ 'Up' if i.link == 'up' else 'No link' }}{% if i.speed_mbps is number and i.speed_mbps > 0 %}, {% if i.speed_mbps >= 1000 %}{{ (i.speed_mbps // 1000) if i.speed_mbps % 1000 == 0 else (i.speed_mbps / 1000) | round(1) }} Gb/s{% else %}{{ i.speed_mbps }} Mb/s{% endif %}{% endif %}
{% if i.addrs and i.addrs is not string %}<span class="mono">{{ i.addrs | join(', ') }}</span>{% endif %}
{% if i.dnsmasq_bound is not none %}<br>DHCP/PXE {{ 'served here' if i.dnsmasq_bound else 'not served here' }}{% endif %}
{% for e in (i.evidence if i.evidence is iterable and i.evidence is not string else []) %}<br>{{ e }}{% endfor %}{% for n in (i.notes if i.notes is iterable and i.notes is not string else []) %}<br><span class="sub">{{ n }}</span>{% endfor %}
</div>
</div>
{% else %}
<div class="muted">{{ 'Interfaces unknown.' if nic.source == 'error' else 'No network interfaces found.' }}</div>
{% endfor %}
<div class="sub" style="white-space: normal; border-top: 1px solid var(--line); padding-top: 8px">
{% if nic.source == 'check' and not nic.stale %}Checked {{ nic.checked_at | local_dt }} by pxe-nic-check.
{% elif nic.source == 'check' %}The network check is stale (last {{ nic.checked_at | local_dt }}): showing link and addresses only.
{% elif nic.source == 'error' %}The network status could not be read{% if nic.error %}: <span class="mono">{{ nic.error }}</span>{% endif %}. See the webapp log.
{% else %}Link and addresses only; pxe-nic-check (the GE-network detector) is not installed yet.{% endif %}
</div>
</div>
</details>
{% elif part == 'notice' %}
{% if nic and nic.problems %}
<div class="notice{{ ' bad' if nic.state == 'bad' else '' }}" role="{{ 'alert' if nic.state == 'bad' else 'status' }}">
<span>{% if nic.state == 'bad' %}<strong>Network danger.</strong> {% endif %}{% for level, text in nic.problems %}{{ text }}{% if not loop.last %} {% endif %}{% endfor %}</span>
</div>
{% endif %}
{% endif %}