#!/usr/bin/env bash # Daily verification that KSTEENBB2025 (Birth Biologic) Datto SmartBadge config # still matches the EVO-X1 fleet reference. Posts a #bot-alerts heartbeat each run; # on drift also sends a coord message to Mike. Intended to run once/day for ~1 week # via the "ClaudeTools - KSTEEN SmartBadge Daily" scheduled task on GURU-5070. set -uo pipefail REPO_ROOT="${CLAUDETOOLS_ROOT:-/d/claudetools}" [ -d "$REPO_ROOT" ] || REPO_ROOT="$(git -C "$(dirname "$0")" rev-parse --show-toplevel 2>/dev/null)" VAULT="$REPO_ROOT/.claude/scripts/vault.sh" RMM="http://172.16.3.30:3001" # Coord API base — read from identity.json (per-machine override) and fall back # to the on-LAN default for backward compat. Same lookup pattern as sync.sh. IDENTITY_PATH="" for candidate in "$HOME/.claude/identity.json" "$REPO_ROOT/.claude/identity.json"; do if [ -f "$candidate" ]; then IDENTITY_PATH="$candidate" break fi done COORD_BASE="" if [ -n "$IDENTITY_PATH" ] && command -v jq >/dev/null 2>&1; then COORD_BASE=$(jq -r '.coord_api // empty' "$IDENTITY_PATH" 2>/dev/null) fi [ -z "$COORD_BASE" ] && COORD_BASE="http://172.16.3.30:8001" # default when identity.json doesn't define coord_api COORD="${COORD_BASE}/api/coord" KSTEEN="ee3c6aea-e9cc-4d2f-9e79-a38dd0eb129e" VERIFY_PS="$REPO_ROOT/.claude/scripts/ksteen-smartbadge-verify.ps1" LOG="$REPO_ROOT/.claude/logs/ksteen-smartbadge.log" mkdir -p "$(dirname "$LOG")" ts() { date '+%Y-%m-%d %H:%M:%S %Z'; } alert() { bash "$REPO_ROOT/.claude/scripts/post-bot-alert.sh" "$1" >/dev/null 2>&1; } fail_exit() { echo "$(ts) [ERROR] $1" >> "$LOG"; alert "[SMARTBADGE-WATCH] ERROR on KSTEENBB2025 check: $1"; exit 1; } EMAIL=$(bash "$VAULT" get-field infrastructure/gururmm-server.sops.yaml credentials.gururmm-api.admin-email 2>/dev/null) PASS=$(bash "$VAULT" get-field infrastructure/gururmm-server.sops.yaml credentials.gururmm-api.admin-password 2>/dev/null) [ -z "$EMAIL" ] && fail_exit "could not read RMM creds from vault" TOKEN=$(curl -s -X POST "$RMM/api/auth/login" -H "Content-Type: application/json" \ --data-binary "{\"email\":\"$EMAIL\",\"password\":\"$PASS\"}" | jq -r '.token // empty') [ -z "$TOKEN" ] && fail_exit "RMM login failed" # Is the agent connected? If offline, note and exit cleanly (will catch it tomorrow). ONLINE=$(curl -s "$RMM/api/agents" -H "Authorization: Bearer $TOKEN" | jq -r --arg id "$KSTEEN" '.[] | select(.id==$id) | .status') if [ "$ONLINE" != "online" ]; then echo "$(ts) [SKIP] agent offline ($ONLINE)" >> "$LOG" alert "[SMARTBADGE-WATCH] KSTEENBB2025 offline - SmartBadge check skipped, will retry next run" exit 0 fi PAYLOAD=$(jq -n --rawfile cmd "$VERIFY_PS" '{command_type:"powershell", command:$cmd, timeout_seconds:60}') CID=$(curl -s -X POST "$RMM/api/agents/$KSTEEN/command" -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" -d "$PAYLOAD" | jq -r '.command_id // empty') [ -z "$CID" ] && fail_exit "command dispatch failed" FINAL_ST="" for i in $(seq 1 30); do FINAL_ST=$(curl -s "$RMM/api/commands/$CID" -H "Authorization: Bearer $TOKEN" | jq -r '.status') case "$FINAL_ST" in completed|failed|cancelled|interrupted) break;; esac sleep 4 done CMD_JSON=$(curl -s "$RMM/api/commands/$CID" -H "Authorization: Bearer $TOKEN") OUT=$(printf '%s' "$CMD_JSON" | jq -r '.stdout // empty') ERR=$(printf '%s' "$CMD_JSON" | jq -r '.stderr // empty') EXIT_CODE=$(printf '%s' "$CMD_JSON" | jq -r '.exit_code // empty') # If the command never completed, treat as a transient infrastructure error (not drift) if [[ "$FINAL_ST" != "completed" && "$FINAL_ST" != "failed" ]]; then INFRA_REASON="command status=$FINAL_ST after poll window (exit_code=${EXIT_CODE:-?})" echo "$(ts) INFRA-ERROR | $INFRA_REASON" >> "$LOG" alert "[SMARTBADGE-WATCH] INFRA-ERROR KSTEENBB2025 | $INFRA_REASON - NOT counted as drift" exit 0 fi RESULT=$(printf '%s' "$OUT" | grep -m1 'RESULT:') if printf '%s' "$RESULT" | grep -q 'RESULT: PASS'; then echo "$(ts) PASS" >> "$LOG" alert "[SMARTBADGE-WATCH] KSTEENBB2025 PASS - Datto Workplace v10 + SmartBadge _CC add-in aligned" else REASON=$(printf '%s' "$RESULT" | sed 's/^RESULT: //') if [ -z "$REASON" ]; then # stdout was null/empty - use stderr or command status as diagnostic if [ -n "$ERR" ]; then REASON="no RESULT line; status=$FINAL_ST exit_code=${EXIT_CODE:-?}; stderr: ${ERR:0:300}" else REASON="no RESULT line; status=$FINAL_ST exit_code=${EXIT_CODE:-?}; stdout: ${OUT:0:200}" fi fi echo "$(ts) FAIL | $REASON" >> "$LOG" alert "[SMARTBADGE-WATCH] DRIFT KSTEENBB2025 FAIL | $REASON" curl -s -X POST "$COORD/messages" -H "Content-Type: application/json" --data-binary @- </dev/null 2>&1 {"from_session":"GURU-5070/smartbadge-watch","to_user":"mike","subject":"KSTEENBB2025 SmartBadge drift detected","body":"Daily watch found drift on Kristin Steen's machine: $REASON. Re-run the SmartBadge remediation (.claude/scripts/ksteen-smartbadge-verify.ps1 + ksteen-smartbadge-fix.ps1).","priority":"high"} JSON fi