#!/bin/bash # identity-audit-check.sh - Check VM identity audit for drift # # Lives on bl (/home/super/Projects/NetVM/bin/). Reads a bl-local cached # copy of the VM's identity audit JSON and reports drift. # # Why a cache: bl cannot SSH to the VM (VM only accepts the operator # container's key). The VM's hourly audit cron (/srv/board/bin/identity-audit.py) # should scp /srv/board/data/identity-audit.json to bl at: # /home/super/Projects/NetVM/var/identity-audit.json # after each run. Until that push is wired, the cache is refreshed manually # or by the identity-audit-watch cron. # # Called by: # - the identity-audit-watch cron (replaces inline SSH one-liner) # - box-ctl.py `identity-audit` action # # Exit codes: # 0 - clean (no drift; warnings are expected and silent) # 1 - drift detected (items printed to stdout, one per line) # 2 - audit cache missing/unreadable (needs attention) # # Output on drift: one drift item per line, prefixed with "DRIFT: " set -u CACHE_PATH="/home/super/Projects/NetVM/var/identity-audit.json" # Allow override for testing if [ $# -ge 1 ] && [ -f "$1" ]; then CACHE_PATH="$1" fi if [ ! -f "$CACHE_PATH" ]; then echo "ERROR: identity audit cache missing: $CACHE_PATH" >&2 echo "The VM hourly audit should push /srv/board/data/identity-audit.json here after each run." >&2 exit 2 fi audit_json=$(cat "$CACHE_PATH" 2>/dev/null) if [ -z "$audit_json" ]; then echo "ERROR: identity audit cache unreadable: $CACHE_PATH" >&2 exit 2 fi # Parse with python3 drift_output=$(printf '%s' "$audit_json" | python3 -c " import json, sys try: data = json.load(sys.stdin) except Exception as e: print('ERROR: invalid JSON in audit cache: %s' % e, file=sys.stderr) sys.exit(2) for item in data.get('drift', []): print('DRIFT: ' + str(item)) " 2>&1) parse_rc=$? if [ $parse_rc -eq 2 ]; then echo "$drift_output" >&2 exit 2 fi if [ -n "$drift_output" ]; then echo "$drift_output" exit 1 fi # Clean: no drift. Warnings are expected (agents not dialed in) — stay silent. exit 0