- workspace: capmetro-monitor, github-notifications, model-selector - workspace-security: vt-monitor, monitor-unauthorized - workspace-home: cron-manager, monitor-unauthorized - extensions: vt-sentinel (VT-Sentinel plugin) Includes sync.sh for pull/push, README, AGENTS.md, .gitignore.
130 lines
4.5 KiB
Bash
Executable File
130 lines
4.5 KiB
Bash
Executable File
#!/bin/bash
|
|
# Unauthorized connection monitor — cron wrapper
|
|
# Orchestrates: log-splitter → check → formatted output with agent instructions
|
|
#
|
|
# Output is structured for the OpenClaw agent to parse and act on.
|
|
# The agent reads SKILL.md for detailed instructions on thread management.
|
|
#
|
|
# Flow:
|
|
# 1. Run log-splitter to extract new unauthorized entries from gateway log
|
|
# 2. Check thread index status (does the agent need to refresh it?)
|
|
# 3. Run check to categorize IPs as new or returning
|
|
# 4. Format output with ACTION markers the agent will parse
|
|
#
|
|
# Exit: always 0. Empty output = nothing to do (agent replies NO_REPLY)
|
|
set -e
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
|
|
# --- Step 1: Split unauthorized entries from gateway log ---
|
|
SPLIT_RESULT=$("$SCRIPT_DIR/log-splitter.sh" 2>/dev/null) || true
|
|
|
|
# --- Step 2: Check thread index ---
|
|
INDEX_STATUS=$("$SCRIPT_DIR/index-threads.sh" needs-refresh 2>/dev/null) || INDEX_STATUS="missing"
|
|
|
|
# --- Step 3: Check for new/returning unauthorized connections ---
|
|
CHECK_RESULT=$("$SCRIPT_DIR/check.sh" 2>/dev/null) || CHECK_RESULT='{}'
|
|
|
|
NEW_COUNT=$(echo "$CHECK_RESULT" | jq '.new_ips | length' 2>/dev/null || echo 0)
|
|
RETURNING_COUNT=$(echo "$CHECK_RESULT" | jq '.returning_ips | length' 2>/dev/null || echo 0)
|
|
TOTAL=$(echo "$CHECK_RESULT" | jq '.total_events' 2>/dev/null || echo 0)
|
|
|
|
# Nothing to report
|
|
if [ "$NEW_COUNT" -eq 0 ] && [ "$RETURNING_COUNT" -eq 0 ] && [ "$INDEX_STATUS" = "fresh" ]; then
|
|
exit 0
|
|
fi
|
|
|
|
OUTPUT=""
|
|
|
|
# --- Thread index refresh needed ---
|
|
if [ "$INDEX_STATUS" != "fresh" ]; then
|
|
OUTPUT+="ACTION:INDEX_THREADS
|
|
The thread index is ${INDEX_STATUS}. Before processing connections, refresh the thread index.
|
|
See SKILL.md section \"Thread Index Management\" for instructions.
|
|
---END_ACTION---
|
|
"
|
|
fi
|
|
|
|
# --- New IPs: agent should create threads ---
|
|
if [ "$NEW_COUNT" -gt 0 ]; then
|
|
OUTPUT+="
|
|
🚨 UNAUTHORIZED CONNECTIONS — ${NEW_COUNT} NEW IP(s) DETECTED
|
|
============================================================
|
|
"
|
|
# Emit each new IP as an ACTION block
|
|
for i in $(seq 0 $((NEW_COUNT - 1))); do
|
|
IP=$(echo "$CHECK_RESULT" | jq -r ".new_ips[$i].ip")
|
|
FIRST_SEEN=$(echo "$CHECK_RESULT" | jq -r ".new_ips[$i].first_seen")
|
|
ATTEMPTS=$(echo "$CHECK_RESULT" | jq -r ".new_ips[$i].attempts")
|
|
REASON=$(echo "$CHECK_RESULT" | jq -r ".new_ips[$i].reason")
|
|
ORIGIN=$(echo "$CHECK_RESULT" | jq -r ".new_ips[$i].origin")
|
|
UA=$(echo "$CHECK_RESULT" | jq -r ".new_ips[$i].user_agent")
|
|
REMOTE=$(echo "$CHECK_RESULT" | jq -r ".new_ips[$i].remote")
|
|
|
|
OUTPUT+="
|
|
ACTION:NEW_THREAD
|
|
IP:${IP}
|
|
---
|
|
🚨 **NEW UNAUTHORIZED CONNECTION**
|
|
|
|
**IP:** \`${IP}\`
|
|
**First Seen:** ${FIRST_SEEN}
|
|
**Attempts:** ${ATTEMPTS}
|
|
**Reason:** ${REASON}
|
|
**Origin:** ${ORIGIN}
|
|
**User Agent:** ${UA}
|
|
**Remote (proxy):** ${REMOTE}
|
|
|
|
_New IP — thread created by security monitor._
|
|
---END_ACTION---
|
|
"
|
|
done
|
|
fi
|
|
|
|
# --- Returning IPs: agent should update existing threads ---
|
|
if [ "$RETURNING_COUNT" -gt 0 ]; then
|
|
OUTPUT+="
|
|
⚠️ RETURNING CONNECTIONS — ${RETURNING_COUNT} KNOWN IP(s)
|
|
==========================================================
|
|
"
|
|
for i in $(seq 0 $((RETURNING_COUNT - 1))); do
|
|
IP=$(echo "$CHECK_RESULT" | jq -r ".returning_ips[$i].ip")
|
|
LATEST=$(echo "$CHECK_RESULT" | jq -r ".returning_ips[$i].latest")
|
|
NEW_ATTEMPTS=$(echo "$CHECK_RESULT" | jq -r ".returning_ips[$i].new_attempts")
|
|
TOTAL_ATTEMPTS=$(echo "$CHECK_RESULT" | jq -r ".returning_ips[$i].total_attempts")
|
|
REASON=$(echo "$CHECK_RESULT" | jq -r ".returning_ips[$i].reason")
|
|
ORIGIN=$(echo "$CHECK_RESULT" | jq -r ".returning_ips[$i].origin")
|
|
UA=$(echo "$CHECK_RESULT" | jq -r ".returning_ips[$i].user_agent")
|
|
REMOTE=$(echo "$CHECK_RESULT" | jq -r ".returning_ips[$i].remote")
|
|
|
|
# Look up existing thread
|
|
THREAD_INFO=$("$SCRIPT_DIR/index-threads.sh" lookup "$IP" 2>/dev/null) || THREAD_INFO=""
|
|
SESSION_KEY=""
|
|
if [ -n "$THREAD_INFO" ]; then
|
|
SESSION_KEY=$(echo "$THREAD_INFO" | jq -r '.session_key // empty')
|
|
fi
|
|
|
|
OUTPUT+="
|
|
ACTION:UPDATE_THREAD
|
|
IP:${IP}
|
|
SESSION_KEY:${SESSION_KEY}
|
|
---
|
|
⚠️ **RETURNING UNAUTHORIZED CONNECTION**
|
|
|
|
**IP:** \`${IP}\`
|
|
**Latest Attempt:** ${LATEST}
|
|
**New Attempts (this period):** ${NEW_ATTEMPTS}
|
|
**Total Attempts (all time):** ${TOTAL_ATTEMPTS}
|
|
**Reason:** ${REASON}
|
|
**Origin:** ${ORIGIN}
|
|
**User Agent:** ${UA}
|
|
**Remote (proxy):** ${REMOTE}
|
|
|
|
_Recurring access attempt — updated by security monitor._
|
|
---END_ACTION---
|
|
"
|
|
done
|
|
fi
|
|
|
|
echo -e "$OUTPUT"
|