Add endpoint monitor catalog and warn-only drift reconciler
Operators need to see when a machine's running services or processes fall outside the desired state defined by policy. This adds a reusable monitor catalog (shipped read-only rows plus user-built local rows), computes drift server-side on agent check-in, and surfaces a warning on the endpoint panels. Remediation stays manual for now; automation can follow once demand is proven. Includes migrations 0006-0008 and the monitors API client.
This commit is contained in:
@@ -486,26 +486,6 @@ class EndpointsPlugin(BasePlugin):
|
||||
# the installed-software inventory
|
||||
'group': 'software',
|
||||
},
|
||||
{
|
||||
# Installed-software (SBOM) inventory. Low-priority reference
|
||||
# data, not something looked at on every visit, so it starts
|
||||
# collapsed and sits near the bottom. Raw discovered list for
|
||||
# now: no managed-application linkage is surfaced yet.
|
||||
'id': 'endpoints-applications',
|
||||
'title': 'Installed software',
|
||||
'assettypes': ['computer'],
|
||||
'endpoint': '/api/endpoints/asset/{assetid}/applications',
|
||||
'render': 'table',
|
||||
'collapsible': True,
|
||||
'collapsedDefault': True,
|
||||
'columns': [
|
||||
{'key': 'displayname', 'label': 'Name'},
|
||||
{'key': 'displayversion', 'label': 'Version'},
|
||||
{'key': 'publisher', 'label': 'Publisher'},
|
||||
],
|
||||
'empty': 'No installed software reported.',
|
||||
'position': 30,
|
||||
},
|
||||
]
|
||||
|
||||
def get_dashboard_widgets(self) -> List[Dict]:
|
||||
@@ -822,6 +802,26 @@ class EndpointsPlugin(BasePlugin):
|
||||
|
||||
state.lastreportedat = datetime.utcnow()
|
||||
|
||||
# Warn-only reconciler: on this check-in, compare the monitors site
|
||||
# policy expects to be running against what the snapshot reports, and
|
||||
# cache the drift on the state in THIS transaction (same ledger commit as
|
||||
# servicesjson). No start/stop is issued - drift is surfaced for an
|
||||
# operator to act on. Reads the freshly reported services when present,
|
||||
# else the last-known snapshot, so a report that omits services still
|
||||
# reconciles against what we last saw. Fail-open: a reconciler error must
|
||||
# never fail an otherwise-good check-in, so drift is left unchanged.
|
||||
try:
|
||||
if 'services' in payload:
|
||||
reported_services = payload.get('services') or []
|
||||
else:
|
||||
reported_services = json.loads(state.servicesjson or '[]')
|
||||
from .services.reconciler import compute_drift
|
||||
state.driftjson = _as_json(compute_drift(assetid, reported_services))
|
||||
except Exception:
|
||||
logger.exception(
|
||||
'reconciler failed for asset %s; leaving drift unchanged',
|
||||
assetid)
|
||||
|
||||
# Log any keys the agent sent that the ingest path does not consume yet.
|
||||
# New agent telemetry (disks, bios, memory, ...) lands here first: it is
|
||||
# not persisted until the server grows columns for it, but logging the
|
||||
|
||||
Reference in New Issue
Block a user