Stale enforcement reports judge both clocks

This commit is contained in:
2026-08-13 09:54:05 -04:00
parent 5dcc7e30af
commit 3abf724ae6
3 changed files with 70 additions and 6 deletions

View File

@@ -1116,9 +1116,20 @@ def list_reports():
latest_cache[key] = _current_published_version(*key)
latest = latest_cache[key]
known = facts.get((report.hostname or '').lower(), {})
isstale = (stalecutoff is not None
and (report.receivedat is None
or report.receivedat < stalecutoff))
# Two separate ways to have gone quiet, and the table has a column for
# each. receivedat is the SERVER's record of the last report it got;
# lastcheckin is the client's own claim about when it last ran. A PC can
# fail either way round - silent to the server, or still posting while
# its own cycle has stopped advancing - so both count.
#
# They are checked independently rather than by taking the newer of the
# two: lastcheckin is client-asserted, so a wrong or future value there
# must not be able to mask real silence on receivedat.
isstale = stalecutoff is not None and (
report.receivedat is None
or report.receivedat < stalecutoff
or (report.lastcheckin is not None
and report.lastcheckin < stalecutoff))
data.append({
'reportid': report.reportid,
'hostname': report.hostname,

View File

@@ -192,9 +192,11 @@ function statusClass(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}".`
const received = report.receivedat ? formatDate(report.receivedat) : 'never'
const checkin = report.lastcheckin ? formatDate(report.lastcheckin) : 'not reported'
return `Nothing heard for over ${report.staleafterminutes} minutes.`
+ ` Last report received ${received}, PC last checked in ${checkin},`
+ ` reporting "${report.status}".`
}
function actionClass(action) {
return { installed: 'badge-info', skipped: 'badge-success', failed: 'badge-danger',