← back to Dw Yolo Loop

scripts/promote-canary.sh

77 lines

#!/bin/bash
# promote-canary.sh — turn a built-but-unscheduled canary script into a launchd
# job. WRITES a plist to ~/Library/LaunchAgents/ and PRINTS the bootstrap command
# — it NEVER runs launchctl bootstrap itself (plist install is Steve-gated, and
# the auto-mode classifier blocks autonomous launchd bootstrap). Idempotent: a
# re-run overwrites the plist with the same content.
#
# Born from the 2026-06-16 Officer Council #2 pick (Canary Promotion Harness):
# the overnight loop built ~8 read-only canaries and scheduled NONE — the exact
# pattern that let the pg_dump backup die silent for 12 days. This closes the
# build→schedule gap with one reusable step.
#
# Usage:
#   bash scripts/promote-canary.sh <label> <abs-script-path> <cadence> [hour] [minute] [weekday]
#     <label>    e.g. dw-handle-freshness  (becomes com.steve.<label>)
#     <cadence>  daily | weekly
#     weekday    0-6 (Sun=0), only used for weekly
#   Example (nightly 3:10am):  bash scripts/promote-canary.sh dw-handle-freshness \
#       "$HOME/Projects/designerwallcoverings/scripts/handle-freshness/handle-freshness-canary.mjs" daily 3 10
#   Example (weekly Mon 4:00): ... tls-expiry ... weekly 4 0 1
#
# READ-ONLY w.r.t. prod. $0. The generated job just runs the (read-only) canary.
set -euo pipefail

LABEL="${1:?need label, e.g. dw-handle-freshness}"
SCRIPT="${2:?need absolute script path}"
CADENCE="${3:?need cadence: daily|weekly}"
HOUR="${4:-3}"
MIN="${5:-15}"
WEEKDAY="${6:-1}"   # Monday default for weekly

[ -f "$SCRIPT" ] || { echo "✗ script not found: $SCRIPT" >&2; exit 1; }

FULL="com.steve.${LABEL}"
PLIST="$HOME/Library/LaunchAgents/${FULL}.plist"

# choose runner by extension
case "$SCRIPT" in
  *.mjs|*.js) RUN="/usr/bin/env node \"$SCRIPT\"";;
  *.sh)       RUN="/bin/bash \"$SCRIPT\"";;
  *.py)       RUN="/usr/bin/env python3 \"$SCRIPT\"";;
  *)          RUN="\"$SCRIPT\"";;
esac

if [ "$CADENCE" = "weekly" ]; then
  CAL="<dict><key>Weekday</key><integer>${WEEKDAY}</integer><key>Hour</key><integer>${HOUR}</integer><key>Minute</key><integer>${MIN}</integer></dict>"
else
  CAL="<dict><key>Hour</key><integer>${HOUR}</integer><key>Minute</key><integer>${MIN}</integer></dict>"
fi

cat > "$PLIST" <<PLISTEOF
<?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>${FULL}</string>
  <key>ProgramArguments</key>
  <array>
    <string>/bin/bash</string><string>-lc</string>
    <string>${RUN} &gt;&gt; /tmp/${LABEL}.log 2&gt;&amp;1</string>
  </array>
  <key>StartCalendarInterval</key>${CAL}
  <key>RunAtLoad</key><false/>
  <key>StandardOutPath</key><string>/tmp/${LABEL}.launchd.out.log</string>
  <key>StandardErrorPath</key><string>/tmp/${LABEL}.launchd.err.log</string>
</dict>
</plist>
PLISTEOF

echo "✓ wrote $PLIST  (${CADENCE} ${HOUR}:$(printf '%02d' "$MIN")${CADENCE:+${WEEKDAY:+}})"
echo ""
echo "  → To ENABLE (Steve-gated — run this yourself):"
echo "      launchctl bootstrap gui/\$(id -u) \"$PLIST\""
echo "  → Verify:  launchctl list | grep ${FULL}"
echo "  → Run-now: launchctl kickstart -k gui/\$(id -u)/${FULL}"
echo "  → Disable: launchctl bootout gui/\$(id -u)/${FULL}"