Files
2026-04-21 09:25:56 -07:00

105 lines
3.1 KiB
Bash
Executable File

#!/usr/bin/env bash
#
# compare-logs.sh — Side-by-side comparison of minimal vs audit logs.
#
# The MCP server writes BOTH minimal.log and audit.log regardless of the
# --log-mode flag, so you can run any attack (SSRF, support_override, agent
# against a malicious ticket, etc.) and then diff the two files to see what
# a default-logging profile *misses* vs. what a real audit trail captures.
#
# Usage:
# scripts/compare-logs.sh # show both logs
# scripts/compare-logs.sh clear # truncate both log files
# scripts/compare-logs.sh minimal # show only minimal.log
# scripts/compare-logs.sh audit # show only audit.log (pretty)
# LOG_DIR=/var/log/mcp scripts/compare-logs.sh
#
set -euo pipefail
LOG_DIR="${LOG_DIR:-logs}"
MIN_LOG="${LOG_DIR}/minimal.log"
AUDIT_LOG="${LOG_DIR}/audit.log"
die() { echo "error: $*" >&2; exit 1; }
rule() { printf '%s\n' "----------------------------------------------------------------------"; }
have_jq() { command -v jq >/dev/null 2>&1; }
pretty_audit() {
local f="$1"
[[ -s "$f" ]] || { echo "(empty)"; return; }
if have_jq; then
jq -c '.' < "$f"
else
cat "$f"
fi
}
case "${1:-compare}" in
clear)
: > "$MIN_LOG" 2>/dev/null || die "cannot truncate $MIN_LOG"
: > "$AUDIT_LOG" 2>/dev/null || die "cannot truncate $AUDIT_LOG"
echo "cleared: $MIN_LOG"
echo "cleared: $AUDIT_LOG"
exit 0
;;
minimal)
[[ -r "$MIN_LOG" ]] || die "missing $MIN_LOG — is the server running with --log-dir $LOG_DIR ?"
cat "$MIN_LOG"
exit 0
;;
audit)
[[ -r "$AUDIT_LOG" ]] || die "missing $AUDIT_LOG — is the server running with --log-dir $LOG_DIR ?"
pretty_audit "$AUDIT_LOG"
exit 0
;;
compare|"")
[[ -r "$MIN_LOG" && -r "$AUDIT_LOG" ]] || die "logs not found in $LOG_DIR (start the server with --log-dir $LOG_DIR)"
rule
echo " MINIMAL LOG ($MIN_LOG)"
echo " default profile — 'just give me timestamps and tool names'"
rule
if [[ -s "$MIN_LOG" ]]; then
cat "$MIN_LOG"
else
echo "(empty — no tool calls yet)"
fi
echo
rule
echo " AUDIT LOG ($AUDIT_LOG)"
echo " structured JSON — session, client, role, outbound host, forward_auth,"
echo " target_user, record kind/id, response digest, policy decision"
rule
if [[ -s "$AUDIT_LOG" ]]; then
pretty_audit "$AUDIT_LOG"
else
echo "(empty — no tool calls yet)"
fi
echo
rule
echo " WHAT THE MINIMAL LOG CANNOT ANSWER"
rule
cat <<'EOF'
- Which URL did web_fetch hit? (internal metadata? customer API?)
- Did it forward the caller's bearer token downstream?
- Which customer record did db_lookup read?
- Who did support_override mint a token for, and with which role?
- Did env_debug leak SESSION_SIGNING_KEY or LOCAL_SUPPORT_MASTER_KEY?
- Was the request allowed or denied by policy?
- What was the size / digest of the response that left the server?
All of the above are in the audit log. None are in the minimal log.
EOF
;;
*)
die "usage: $0 [compare|clear|minimal|audit]"
;;
esac