InsuranceBot / tools /install_crons.sh
rohitsar567's picture
Deploy v1 β€” single-Docker FastAPI + Next.js + RAG + voice + faithfulness
9c879c3 verified
Raw
History Blame Contribute Delete
6.75 kB
#!/usr/bin/env bash
# Install the four cron jobs as macOS LaunchAgents.
#
# Scripts go to ~/Library/Scripts/insurance-bot/ (TCC-safe location)
# Plists go to ~/Library/LaunchAgents/com.rohit.insurancebot.*.plist
# Logs go to ~/Library/Logs/insurance-bot/
#
# Schedule:
# daily-link-rot 03:00 β†’ check_link_rot.py
# weekly-pdf Sun 04:00 β†’ check_pdf_etags.py
# monthly-premium 1st 06:00 β†’ refresh_premiums.py
#
# Quarterly rebuild is manual: bash tools/quarterly_rebuild.sh
set -euo pipefail
PROJECT_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
SCRIPT_DIR="$HOME/Library/Scripts/insurance-bot"
PLIST_DIR="$HOME/Library/LaunchAgents"
LOG_DIR="$HOME/Library/Logs/insurance-bot"
# Prefer the project venv (httpx is installed there). Fall back to system python.
if [ -x "$PROJECT_ROOT/.venv/bin/python3" ]; then
PY="$PROJECT_ROOT/.venv/bin/python3"
else
PY="$(command -v python3)"
fi
echo "[install_crons] using python: $PY"
mkdir -p "$SCRIPT_DIR" "$PLIST_DIR" "$LOG_DIR"
# 1. Write wrapper scripts in ~/Library/Scripts/ that cd into the project and
# invoke python3 on the canonical tools/*.py. The wrappers MUST live here
# (not in ~/Documents/) because macOS TCC blocks launchd from reading
# ~/Documents/* without explicit Full Disk Access (see cache-sweeper
# incident 2026-05-12).
cat > "$SCRIPT_DIR/run_link_rot.sh" <<EOF
#!/usr/bin/env bash
cd "$PROJECT_ROOT"
"$PY" tools/check_link_rot.py >> "$LOG_DIR/link_rot.stdout.log" 2>> "$LOG_DIR/link_rot.stderr.log"
EOF
cat > "$SCRIPT_DIR/run_pdf_etags.sh" <<EOF
#!/usr/bin/env bash
cd "$PROJECT_ROOT"
"$PY" tools/check_pdf_etags.py >> "$LOG_DIR/pdf_etags.stdout.log" 2>> "$LOG_DIR/pdf_etags.stderr.log"
EOF
cat > "$SCRIPT_DIR/run_refresh_premiums.sh" <<EOF
#!/usr/bin/env bash
cd "$PROJECT_ROOT"
"$PY" tools/refresh_premiums.py >> "$LOG_DIR/premium_refresh.stdout.log" 2>> "$LOG_DIR/premium_refresh.stderr.log"
EOF
chmod +x "$SCRIPT_DIR"/*.sh
# 2. LaunchAgent plists
write_plist() {
local label="$1" script="$2" schedule_xml="$3"
cat > "$PLIST_DIR/$label.plist" <<PLIST
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>$label</string>
<key>ProgramArguments</key>
<array>
<string>/bin/bash</string>
<string>$SCRIPT_DIR/$script</string>
</array>
$schedule_xml
<key>RunAtLoad</key>
<false/>
<key>StandardOutPath</key>
<string>$LOG_DIR/$label.out.log</string>
<key>StandardErrorPath</key>
<string>$LOG_DIR/$label.err.log</string>
</dict>
</plist>
PLIST
}
# Daily 03:00
write_plist "com.rohit.insurancebot.linkrot" "run_link_rot.sh" " <key>StartCalendarInterval</key>
<dict>
<key>Hour</key>
<integer>3</integer>
<key>Minute</key>
<integer>0</integer>
</dict>"
# Weekly Sunday 04:00 (Weekday 0 = Sunday)
write_plist "com.rohit.insurancebot.pdfetags" "run_pdf_etags.sh" " <key>StartCalendarInterval</key>
<dict>
<key>Weekday</key>
<integer>0</integer>
<key>Hour</key>
<integer>4</integer>
<key>Minute</key>
<integer>0</integer>
</dict>"
# Monthly 1st 06:00
write_plist "com.rohit.insurancebot.premiums" "run_refresh_premiums.sh" " <key>StartCalendarInterval</key>
<dict>
<key>Day</key>
<integer>1</integer>
<key>Hour</key>
<integer>6</integer>
<key>Minute</key>
<integer>0</integer>
</dict>"
# 3. Load them (unload first to ensure idempotency)
for label in com.rohit.insurancebot.linkrot com.rohit.insurancebot.pdfetags com.rohit.insurancebot.premiums; do
launchctl unload "$PLIST_DIR/$label.plist" 2>/dev/null || true
launchctl load "$PLIST_DIR/$label.plist"
echo "[install_crons] loaded $label"
done
echo ""
echo "Installed LaunchAgents:"
launchctl list | grep com.rohit.insurancebot || echo "(none visible β€” check log dir)"
# ---- TCC self-test ----
# launchd-spawned processes cannot read ~/Documents/ unless the spawning binary
# (bash or python) has Full Disk Access. Test by running a tiny job and
# inspecting stderr for "Operation not permitted".
echo ""
echo "[install_crons] running TCC self-test..."
TEST_OUT="$(mktemp)"
launchctl start com.rohit.insurancebot.linkrot
sleep 6
if grep -q "Operation not permitted" "$LOG_DIR"/link_rot.stderr.log 2>/dev/null || \
grep -q "Operation not permitted" "$LOG_DIR"/com.rohit.insurancebot.linkrot.err.log 2>/dev/null; then
cat <<'WARN'
╔════════════════════════════════════════════════════════════════════════════╗
β•‘ TCC BLOCKING DETECTED β€” cron jobs cannot read ~/Documents/ β•‘
β•‘ β•‘
β•‘ macOS requires Full Disk Access to be granted to the binaries that β•‘
β•‘ launchd uses. Open System Settings β†’ Privacy & Security β†’ Full Disk β•‘
β•‘ Access, and add BOTH: β•‘
β•‘ β•‘
β•‘ 1. /bin/bash β•‘
β•‘ 2. The project's Python: β•‘
WARN
echo " $PY"
cat <<'WARN'
β•‘ β•‘
β•‘ After adding, click the toggle ON for each, then re-run: β•‘
β•‘ bash tools/install_crons.sh β•‘
β•‘ β•‘
β•‘ Opening Settings pane for you now... β•‘
β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
WARN
open "x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles" 2>/dev/null || true
exit 2
else
echo "[install_crons] TCC ok β€” jobs can read project files"
fi
rm -f "$TEST_OUT"
echo ""
echo "Logs land in: $LOG_DIR/"
echo "Scripts in: $SCRIPT_DIR/"
echo "Plists in: $PLIST_DIR/com.rohit.insurancebot.*.plist"
echo ""
echo "Manual trigger: bash tools/quarterly_rebuild.sh"
echo "Force a run: launchctl start com.rohit.insurancebot.linkrot"
echo "Disable: launchctl unload ~/Library/LaunchAgents/com.rohit.insurancebot.<x>.plist"