geenforce: a PC that has gone quiet stops reading as healthy

A report records how ONE cycle went. Nothing ages it, so a PC that stops
reporting keeps the status of its last good cycle: switch a machine off after a
clean run and it shows 'ok' indefinitely. One had been offline more than a day
and still read 'ok'.

Silence is a different fact from the last cycle's outcome, so it is computed
separately rather than by rewriting the stored status. receivedat - the server's
own clock, not anything a client asserts - is compared against
geenforce_reportstaleminutes, default 30, which is roughly two missed cycles at
the usual cadence. Set it to 0 to turn the check off.

In the table 'stale' takes the badge, because a status from a machine that has
not spoken since is not evidence of anything. What it last reported stays in the
tooltip with the time it was heard. The stored status is untouched: it is still
a true record of that cycle, just not proof the PC is alive.

A site whose scope enforces less often than the threshold will read stale while
healthy, which is what the setting is for.
This commit is contained in:
cproudlock
2026-08-13 09:28:37 -04:00
parent 20a95013ad
commit 962979d483
4 changed files with 169 additions and 2 deletions

View File

@@ -88,7 +88,14 @@
</span>
</td>
<td class="muted">{{ report.appliedversion ?? '-' }} / {{ report.latestversion ?? '-' }}</td>
<td><span class="badge" :class="statusClass(report.status)">{{ report.status }}</span></td>
<!-- A PC that stops reporting keeps the status of its last good
cycle, so silence has to outrank it: 'stale' shows instead,
with what it last reported kept in the tooltip. -->
<td>
<span v-if="report.isstale" class="badge badge-warning"
:title="staleTitle(report)">stale</span>
<span v-else class="badge" :class="statusClass(report.status)">{{ report.status }}</span>
</td>
<td>{{ report.installed }}</td>
<td class="muted">{{ report.skipped }}</td>
<td :class="{ 'fail-count': report.failed }">{{ report.failed }}</td>
@@ -183,6 +190,12 @@ async function openDetail(reportid) {
function statusClass(status) {
return { ok: 'badge-success', selfhealed: 'badge-info', failed: 'badge-danger' }[status] || ''
}
function staleTitle(report) {
const last = report.receivedat ? formatDate(report.receivedat) : 'never'
return `No report for over ${report.staleafterminutes} minutes.`
+ ` Last heard ${last}, reporting "${report.status}".`
}
function actionClass(action) {
return { installed: 'badge-info', skipped: 'badge-success', failed: 'badge-danger',
filtered: '' }[action] || ''