webapp: technician to-do for the manual CMMC steps; count fallbacks as wiped
Technician To-Do (sidebar link with a count, and a banner on every page while anything is open) lists the playbook steps the server cannot do: 1. wipes still to tick on the Onsite Bin RITM (ENT-045/159) 2. monthly evidence packs to upload to Box (ENT-056/158), Mark uploaded 3. drives that failed to wipe, to destroy (COD recorded) 4. reports Blancco could not upload to the cloud (Resolved) Marks are stored in the Blancco state file; the counts are cached for 60s and refreshed on every mark, ServiceNow tick and cloud-status post. Results are now judged per drive. Blancco keeps every attempt in the report, so a NIST Purge that failed followed by a successful Clear fallback on the same drive appeared as two entries, and the Reports page rolled the whole report up to Failed. 20 such wipes since May showed as Failed; they were wiped (the work instruction counts the fallback as a success). The CSV marks those rows "Fallback: ... then erased with ...". One genuine failure remains: HNMD1V3, Seagate Z500R4KG, 2026-08-11.
This commit is contained in:
@@ -75,6 +75,13 @@
|
||||
<i class="bi bi-shield-check"></i> Blancco Reports
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if request.endpoint == 'blancco_todo' %}active{% endif %}"
|
||||
href="{{ url_for('blancco_todo') }}">
|
||||
<i class="bi bi-clipboard-check"></i> Technician To-Do
|
||||
{% if blancco_todo.total %}<span class="badge badge-warning ms-1">{{ blancco_todo.total }}</span>{% endif %}
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if request.endpoint == 'enrollment' %}active{% endif %}"
|
||||
href="{{ url_for('enrollment') }}">
|
||||
@@ -129,6 +136,20 @@
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
|
||||
{% if blancco_todo.total and request.endpoint not in ('blancco_todo', 'imaging_tiles') %}
|
||||
<div class="alert alert-warning d-flex flex-wrap align-items-center gap-2 py-2" role="alert">
|
||||
<i class="bi bi-clipboard-check"></i>
|
||||
<strong>Technician to-do:</strong>
|
||||
{% set parts = [] %}
|
||||
{% if blancco_todo.servicenow %}{% set _ = parts.append(blancco_todo.servicenow ~ ' wipe' ~ ('s' if blancco_todo.servicenow != 1) ~ ' to tick in ServiceNow') %}{% endif %}
|
||||
{% if blancco_todo.evidence %}{% set _ = parts.append(blancco_todo.evidence ~ ' evidence pack' ~ ('s' if blancco_todo.evidence != 1) ~ ' to upload to Box') %}{% endif %}
|
||||
{% if blancco_todo.failed %}{% set _ = parts.append(blancco_todo.failed ~ ' failed wipe' ~ ('s' if blancco_todo.failed != 1) ~ ' needing a Certificate of Destruction') %}{% endif %}
|
||||
{% if blancco_todo.not_in_cloud %}{% set _ = parts.append(blancco_todo.not_in_cloud ~ ' report' ~ ('s' if blancco_todo.not_in_cloud != 1) ~ ' not in the Blancco cloud') %}{% endif %}
|
||||
<span>{{ parts | join(' | ') }}</span>
|
||||
<a href="{{ url_for('blancco_todo') }}" class="ms-auto pxe-btn pxe-btn-secondary btn-row-action">Open to-do</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
|
||||
|
||||
120
webapp/templates/reports_todo.html
Normal file
120
webapp/templates/reports_todo.html
Normal file
@@ -0,0 +1,120 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Technician To-Do - PXE Server Manager{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="page-header">
|
||||
<h1><i class="bi bi-clipboard-check"></i> Technician To-Do</h1>
|
||||
<div class="header-actions">
|
||||
<span class="badge badge-{{ 'warning' if todo.total else 'success' }} badge-lg">{{ todo.total }} open</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-muted">
|
||||
Blancco wipes, reports, evidence packs and cloud uploads are automatic. These are the
|
||||
CMMC playbook steps that still need a technician ({{ site }}). Mark each one done here once finished.
|
||||
</p>
|
||||
|
||||
{# 1. ServiceNow #}
|
||||
<div class="section-card">
|
||||
<div class="section-title">1. Tick wipes on the Onsite Bin Management RITM (ENT-045 / ENT-159)</div>
|
||||
{% if todo.servicenow %}
|
||||
<p class="mb-2"><strong>{{ todo.servicenow }}</strong> wipe{{ 's' if todo.servicenow != 1 }} from the last 30 days still to tick in ServiceNow.</p>
|
||||
<a href="{{ url_for('blancco_servicenow') }}" class="pxe-btn pxe-btn-primary"><i class="bi bi-list-check"></i> Open the tick list</a>
|
||||
{% else %}
|
||||
<p class="text-muted mb-0">All caught up.</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{# 2. Evidence packs #}
|
||||
<div class="section-card">
|
||||
<div class="section-title">2. Upload the monthly evidence pack to Box (ENT-056 / ENT-158)</div>
|
||||
{% if todo.evidence %}
|
||||
<p class="mb-2">Saved automatically on the 1st. Download it, upload it to the site's ENT-056 / ENT-158 evidence folders in Box, then mark it uploaded.</p>
|
||||
<div class="table-container">
|
||||
<table class="data-table">
|
||||
<thead><tr><th>Month</th><th>File</th><th class="text-end">Actions</th></tr></thead>
|
||||
<tbody>
|
||||
{% for p in todo.evidence %}
|
||||
<tr>
|
||||
<td class="mono">{{ p.month }}</td>
|
||||
<td class="mono">{{ p.file }}</td>
|
||||
<td class="text-end text-nowrap">
|
||||
<a href="{{ url_for('blancco_evidence_file', filename=p.file) }}" class="pxe-btn pxe-btn-secondary btn-row-action"><i class="bi bi-download"></i> Download</a>
|
||||
<form method="post" action="{{ url_for('blancco_todo_mark', kind='evidence_uploaded', key=p.month) }}" style="display:inline;">
|
||||
<input type="hidden" name="_csrf_token" value="{{ csrf_token() }}">
|
||||
<button type="submit" class="pxe-btn pxe-btn-success btn-row-action">Mark uploaded</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="text-muted mb-0">No pack waiting. The next one is saved on the 1st of next month.</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{# 3. Failed wipes #}
|
||||
<div class="section-card">
|
||||
<div class="section-title">3. Destroy drives that failed to wipe (ENT-158 / ENT-159)</div>
|
||||
{% if todo.failed %}
|
||||
<p class="mb-2">Remove the drive, destroy it per site procedure, record the Certificate of Destruction and the destruction note on the RITM, then mark it here.</p>
|
||||
<div class="table-container">
|
||||
<table class="data-table">
|
||||
<thead><tr><th>Serial</th><th>Model</th><th>Wiped (UTC)</th><th>Failure</th><th class="text-end">Actions</th></tr></thead>
|
||||
<tbody>
|
||||
{% for it in todo.failed %}
|
||||
<tr title="{{ it.file }}">
|
||||
<td class="mono">{{ it.serial or '-' }}</td>
|
||||
<td>{{ it.model or '-' }}</td>
|
||||
<td class="mono text-nowrap">{{ it.when.strftime('%Y-%m-%d %H:%M') }}</td>
|
||||
<td class="small" style="max-width: 26rem;">{{ it.note }}</td>
|
||||
<td class="text-end text-nowrap">
|
||||
<a href="{{ url_for('blancco_view_report', filename=it.file) }}" class="pxe-btn pxe-btn-secondary btn-row-action"><i class="bi bi-eye"></i> Report</a>
|
||||
<form method="post" action="{{ url_for('blancco_todo_mark', kind='destroyed', key=it.document_id) }}" style="display:inline;">
|
||||
<input type="hidden" name="_csrf_token" value="{{ csrf_token() }}">
|
||||
<button type="submit" class="pxe-btn pxe-btn-success btn-row-action">COD recorded</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="text-muted mb-0">No failed wipes waiting for destruction.</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{# 4. Not in the cloud #}
|
||||
<div class="section-card">
|
||||
<div class="section-title">4. Reports that did not reach the Blancco cloud (ENT-056)</div>
|
||||
{% if todo.not_in_cloud %}
|
||||
<p class="mb-2">Auditors pull certificates from the Blancco Management Portal. Upload the report's XML there by hand, then mark it resolved.</p>
|
||||
<div class="table-container">
|
||||
<table class="data-table">
|
||||
<thead><tr><th>Serial</th><th>Model</th><th>Wiped (UTC)</th><th class="text-end">Actions</th></tr></thead>
|
||||
<tbody>
|
||||
{% for it in todo.not_in_cloud %}
|
||||
<tr title="{{ it.file }}">
|
||||
<td class="mono">{{ it.serial or '-' }}</td>
|
||||
<td>{{ it.model or '-' }}</td>
|
||||
<td class="mono text-nowrap">{{ it.when.strftime('%Y-%m-%d %H:%M') }}</td>
|
||||
<td class="text-end text-nowrap">
|
||||
<a href="{{ url_for('blancco_download_report', filename=it.file) }}" class="pxe-btn pxe-btn-secondary btn-row-action"><i class="bi bi-download"></i> XML</a>
|
||||
<form method="post" action="{{ url_for('blancco_todo_mark', kind='cloud_resolved', key=it.document_id) }}" style="display:inline;">
|
||||
<input type="hidden" name="_csrf_token" value="{{ csrf_token() }}">
|
||||
<button type="submit" class="pxe-btn pxe-btn-success btn-row-action">Resolved</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="text-muted mb-0">Every report with a known upload status reached the cloud.</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user