← back to George Gmail
token-age-warn.sh
37 lines
#!/bin/bash
# token-age-warn run — probe George OAuth token ages; on a WORSENING transition, post a
# CNCP card + email Steve. READ-ONLY (probes Google's token endpoint, never writes creds).
set -uo pipefail
HERE="$(cd "$(dirname "$0")" && pwd)"; DATA="$HERE/data"; mkdir -p "$DATA"; LOG="$DATA/run.log"
log(){ echo "[$(date -Iseconds)] $1" | tee -a "$LOG"; }
START_TS=$(date +%s)
node "$HERE/token-age-warn.mjs" 2>&1 | tee -a "$LOG"
LATEST="$DATA/latest.json"; [ -f "$LATEST" ] || { log "no output"; exit 1; }
# Freshness guard: .mjs writes latest.json only on a completed run. If it crashed, the OLD
# latest.json remains — don't re-alert on stale data; exit non-zero so the heartbeat reflects it.
LATEST_MT=$(stat -f %m "$LATEST" 2>/dev/null || stat -c %Y "$LATEST" 2>/dev/null)
if [ -n "$LATEST_MT" ] && [ "$LATEST_MT" -lt "$START_TS" ]; then
log "no fresh output this run (latest.json stale) — not alerting"; exit 1
fi
ALERT=$(jq -r '.alert' "$LATEST")
log "token-age: worst=$(jq -r '.worst' "$LATEST") · $(jq -r '.warn' "$LATEST") WARN · $(jq -r '.crit' "$LATEST") CRIT · alert=$ALERT"
[ "$ALERT" != "true" ] && { log "no worsening transition — silent"; exit 0; }
CNCP="${CNCP_URL:-http://localhost:3333}"
note="[GEORGE TOKEN-AGE $(date +%Y-%m-%d)] $(jq -r '[.accounts[]|select(.worsened)|.label+" → "+.level+" ("+.detail+")"]|join(" · ")' "$LATEST") — re-consent at George /auth, or decide the durable migration (PLAN-OAUTH-DURABLE-TOKENS.md)."
curl -sS --max-time 10 "$CNCP/api/parking-lot" -H 'Content-Type: application/json' \
-d "$(jq -n --arg u "https://kamatera.tail79cb8e.ts.net:9850" --arg note "$note" '{url:$u,note:$note}')" >/dev/null 2>&1 \
&& log "CNCP posted" || log "CNCP post failed"
if [ -f "$HOME/.claude/skills/_shared/george-send.sh" ]; then
. "$HOME/.claude/skills/_shared/george-send.sh"
TO="${TOKEN_AGE_TO:-steve@designerwallcoverings.com}"
BODY=$(jq -r '"<div style=\"font-family:-apple-system,Helvetica,sans-serif;color:#222\"><h3 style=\"color:#b23b3b\">⚠ George OAuth token-age — worst="+.worst+"</h3><p style=\"font-size:13px;color:#444\">Testing-mode tokens die 7d after issuance. Re-consent at George /auth, or move to the durable path (service-account/DWD or Internal user-type — PLAN-OAUTH-DURABLE-TOKENS.md).</p>" + ([.accounts[]|"<div style=\"margin:6px 0;padding:8px 12px;border:1px solid #eee;border-radius:6px\"><b>"+.label+"</b> — "+.level+"<br><span style=\"font-size:12px;color:#666\">"+.detail+"</span></div>"]|join("")) + "</div>"' "$LATEST")
RESP="$(george_send steve-office "$TO" "⚠ George OAuth token-age — worst=$(jq -r '.worst' "$LATEST") — $(date +%Y-%m-%d)" "$BODY")"
echo "$RESP" > "$DATA/email-last.json"
echo "$RESP" | grep -q '"success":true' && log "alert emailed to $TO" || log "email failed"
else
log "george-send.sh not found — CNCP-only alert"
fi
log "surfaced worsening token-age transition"