Add baseline reconciliation: accept audited drift with a reason
Implements the v0.9 roadmap item from the approved design spec. Operators accept a specific FIM/package/listener/SUID drift item with a mandatory reason; the ack suppresses that one alert only while the live state still matches the recorded fingerprint. Content kinds (fim/pkgfile) re-alert on further change; identity kinds (listener/suid) retire on TTL or revoke. - reconcile.py: ReconcileStore (mtime-cached, fails closed on missing/corrupt store), fingerprint builders, and the filter_alerts chokepoint. - CLI: baseline accept/revoke/list with --reason/--expires/--force/--stale/--json. - Wired at the daemon sweep + eBPF chokepoint, fim-check, and /api/integrity. - RECONCILE_V1 schema, config knob, COMMAND_REFERENCE/SCHEMAS/OPERATIONS/ROADMAP docs, and reconcile unit/CLI/integration tests. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
3d2047fde2
commit
dbbe35b3fc
18 changed files with 1155 additions and 28 deletions
|
|
@ -372,12 +372,14 @@ def integrity_report(cfg: Config, status: dict | None = None,
|
|||
),
|
||||
}
|
||||
keyring_present = pkgdb.keyring_present()
|
||||
reconciliation = _reconciliation_summary(cfg)
|
||||
checks = {
|
||||
"watchdog": "ok" if watchdog_ok else "review",
|
||||
"fim_baseline": fim_state["status"],
|
||||
"pkgdb_anchor": pkg_state["status"],
|
||||
"pacman_siglevel": "review" if sig_alert else "ok",
|
||||
"pacman_keyring": "ok" if keyring_present else "missing",
|
||||
"reconciliation": "review" if reconciliation["stale"] else "ok",
|
||||
}
|
||||
overall = "ok"
|
||||
if any(v in ("review", "missing", "unreadable") for v in checks.values()):
|
||||
|
|
@ -413,10 +415,30 @@ def integrity_report(cfg: Config, status: dict | None = None,
|
|||
"missing": len(watched) - present,
|
||||
"paths": watched,
|
||||
},
|
||||
"reconciliation": reconciliation,
|
||||
"read_only": True,
|
||||
}
|
||||
|
||||
|
||||
def _reconciliation_summary(cfg: Config) -> dict:
|
||||
"""Acknowledged-drift counts for the dashboard. Read-only: this evaluates
|
||||
TTL expiry and persisted status, but does not run live FIM/package scans
|
||||
from the web request path (consistent with the rest of integrity_report)."""
|
||||
from . import reconcile
|
||||
records = reconcile.ReconcileStore.load(cfg).list()
|
||||
stale = [r for r in records if r.status == "stale"]
|
||||
return {
|
||||
"total": len(records),
|
||||
"ok": len(records) - len(stale),
|
||||
"stale": len(stale),
|
||||
"stale_items": [
|
||||
{"kind": r.kind, "target": r.target, "reason": r.reason,
|
||||
"accepted_at": r.accepted_at, "expires_at": r.expires_at}
|
||||
for r in stale
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
# --- HTTP layer ------------------------------------------------------------
|
||||
|
||||
class _Handler(BaseHTTPRequestHandler):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue