tractatus/scripts/monitoring/ssl-monitor.sh
TheFlow 2af47035ac refactor: remove website code and fix critical startup crashes (Phase 8)
CRITICAL FIX: Server would CRASH ON STARTUP (multiple import errors)

REMOVED (2 scripts):
1. scripts/framework-watchdog.js
   - Monitored .claude/session-state.json (OUR Claude Code setup)
   - Monitored .claude/token-checkpoints.json (OUR file structure)
   - Implementers won't have our .claude/ directory

2. scripts/init-db.js
   - Created website collections: blog_posts, media_inquiries, case_submissions
   - Created website collections: resources, moderation_queue, users, citations
   - Created website collections: translations, koha_donations
   - Next steps referenced deleted scripts (npm run seed:admin)

REWRITTEN (2 files):

src/models/index.js (29 lines → 27 lines)
- REMOVED imports: Document, BlogPost, MediaInquiry, CaseSubmission, Resource
- REMOVED imports: ModerationQueue, User (all deleted in Phase 2)
- KEPT imports: AuditLog, DeliberationSession, GovernanceLog, GovernanceRule
- KEPT imports: Precedent, Project, SessionState, VariableValue, VerificationLog
- Result: Only framework models exported

src/server.js (284 lines → 163 lines, 43% reduction)
- REMOVED: Imports to deleted middleware (csrf-protection, response-sanitization)
- REMOVED: Stripe webhook handling (/api/koha/webhook)
- REMOVED: Static file caching (for deleted public/ directory)
- REMOVED: Static file serving (public/ deleted in Phase 6)
- REMOVED: CSRF token endpoint
- REMOVED: Website homepage with "auth, documents, blog, admin" references
- REMOVED: Instruction sync (scripts/sync-instructions-to-db.js reference)
- REMOVED: Hardcoded log path (${process.env.HOME}/var/log/tractatus/...)
- REMOVED: Website-specific security middleware
- KEPT: Security headers, rate limiting, CORS, body parsers
- KEPT: API routes, governance services, MongoDB connections
- RESULT: Clean framework-only server

RESULT: Repository can now start without crashes, all imports resolve

🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-21 22:17:02 +13:00

319 lines
7.7 KiB
Bash
Executable file

#!/bin/bash
#
# SSL Certificate Monitoring Script
# Monitors SSL certificate expiry and alerts before expiration
#
# Usage:
# ./ssl-monitor.sh # Check all domains
# ./ssl-monitor.sh --domain example.com # Check specific domain
# ./ssl-monitor.sh --test # Test mode (no alerts)
#
# Exit codes:
# 0 = OK
# 1 = Warning (expires soon)
# 2 = Critical (expires very soon)
# 3 = Expired or error
set -euo pipefail
# Configuration
ALERT_EMAIL="${ALERT_EMAIL:-}"
LOG_FILE="/var/log/tractatus/ssl-monitor.log"
WARN_DAYS=30 # Warn 30 days before expiry
CRITICAL_DAYS=7 # Critical alert 7 days before expiry
# Default domains to monitor
DOMAINS=(
"agenticgovernance.digital"
)
# Parse arguments
TEST_MODE=false
SPECIFIC_DOMAIN=""
while [[ $# -gt 0 ]]; do
case $1 in
--domain)
SPECIFIC_DOMAIN="$2"
shift 2
;;
--test)
TEST_MODE=true
shift
;;
*)
echo "Unknown option: $1"
exit 3
;;
esac
done
# Override domains if specific domain provided
if [[ -n "$SPECIFIC_DOMAIN" ]]; then
DOMAINS=("$SPECIFIC_DOMAIN")
fi
# Logging function
log() {
local level="$1"
shift
local message="$*"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$timestamp] [$level] $message"
if [[ -d "$(dirname "$LOG_FILE")" ]]; then
echo "[$timestamp] [$level] $message" >> "$LOG_FILE"
fi
}
# Send alert email
send_alert() {
local subject="$1"
local body="$2"
if [[ "$TEST_MODE" == "true" ]]; then
log "INFO" "TEST MODE: Would send alert: $subject"
return 0
fi
if [[ -z "$ALERT_EMAIL" ]]; then
log "WARN" "No alert email configured (ALERT_EMAIL not set)"
return 0
fi
if command -v mail &> /dev/null; then
echo "$body" | mail -s "$subject" "$ALERT_EMAIL"
log "INFO" "Alert email sent to $ALERT_EMAIL"
elif command -v sendmail &> /dev/null; then
{
echo "Subject: $subject"
echo "From: tractatus-monitoring@agenticgovernance.digital"
echo "To: $ALERT_EMAIL"
echo ""
echo "$body"
} | sendmail "$ALERT_EMAIL"
log "INFO" "Alert email sent via sendmail to $ALERT_EMAIL"
else
log "WARN" "No email command available"
fi
}
# Get SSL certificate expiry date
get_cert_expiry() {
local domain="$1"
# Use openssl to get certificate
local expiry_date
expiry_date=$(echo | openssl s_client -servername "$domain" -connect "$domain:443" 2>/dev/null | \
openssl x509 -noout -enddate 2>/dev/null | \
cut -d= -f2) || {
log "ERROR" "Failed to retrieve certificate for $domain"
return 1
}
echo "$expiry_date"
}
# Get days until expiry
get_days_until_expiry() {
local expiry_date="$1"
# Convert expiry date to seconds since epoch
local expiry_epoch
expiry_epoch=$(date -d "$expiry_date" +%s 2>/dev/null) || {
log "ERROR" "Failed to parse expiry date: $expiry_date"
return 1
}
# Get current time in seconds since epoch
local now_epoch=$(date +%s)
# Calculate days until expiry
local seconds_until_expiry=$((expiry_epoch - now_epoch))
local days_until_expiry=$((seconds_until_expiry / 86400))
echo "$days_until_expiry"
}
# Get certificate details
get_cert_details() {
local domain="$1"
echo | openssl s_client -servername "$domain" -connect "$domain:443" 2>/dev/null | \
openssl x509 -noout -subject -issuer -dates 2>/dev/null || {
echo "Failed to retrieve certificate details"
return 1
}
}
# Check single domain
check_domain() {
local domain="$1"
log "INFO" "Checking SSL certificate for $domain"
# Get expiry date
local expiry_date
expiry_date=$(get_cert_expiry "$domain") || {
log "ERROR" "Failed to check certificate for $domain"
return 3
}
# Calculate days until expiry
local days_until_expiry
days_until_expiry=$(get_days_until_expiry "$expiry_date") || {
log "ERROR" "Failed to calculate expiry for $domain"
return 3
}
# Check if expired
if [[ "$days_until_expiry" -lt 0 ]]; then
log "CRITICAL" "$domain: Certificate EXPIRED ${days_until_expiry#-} days ago!"
return 3
fi
# Check thresholds
if [[ "$days_until_expiry" -le "$CRITICAL_DAYS" ]]; then
log "CRITICAL" "$domain: Certificate expires in $days_until_expiry days (expires: $expiry_date)"
return 2
elif [[ "$days_until_expiry" -le "$WARN_DAYS" ]]; then
log "WARN" "$domain: Certificate expires in $days_until_expiry days (expires: $expiry_date)"
return 1
else
log "INFO" "$domain: Certificate valid for $days_until_expiry days (expires: $expiry_date)"
return 0
fi
}
# Main monitoring function
main() {
log "INFO" "Starting SSL certificate monitoring"
local max_severity=0
local expired_domains=()
local critical_domains=()
local warning_domains=()
# Check all domains
for domain in "${DOMAINS[@]}"; do
local exit_code=0
local expiry_date=$(get_cert_expiry "$domain" 2>/dev/null || echo "Unknown")
local days_until_expiry=$(get_days_until_expiry "$expiry_date" 2>/dev/null || echo "Unknown")
check_domain "$domain" || exit_code=$?
if [[ "$exit_code" -eq 3 ]]; then
max_severity=3
expired_domains+=("$domain (EXPIRED or ERROR)")
elif [[ "$exit_code" -eq 2 ]]; then
[[ "$max_severity" -lt 2 ]] && max_severity=2
critical_domains+=("$domain (expires in $days_until_expiry days)")
elif [[ "$exit_code" -eq 1 ]]; then
[[ "$max_severity" -lt 1 ]] && max_severity=1
warning_domains+=("$domain (expires in $days_until_expiry days)")
fi
done
# Send alerts based on severity
if [[ "$max_severity" -eq 3 ]]; then
local subject="[CRITICAL] SSL Certificate Expired or Error"
local body="CRITICAL: SSL certificate has expired or error occurred.
Expired/Error Domains:
$(printf -- "- %s\n" "${expired_domains[@]}")
"
# Add other alerts if any
if [[ "${#critical_domains[@]}" -gt 0 ]]; then
body+="
Critical Domains (<= $CRITICAL_DAYS days):
$(printf -- "- %s\n" "${critical_domains[@]}")
"
fi
if [[ "${#warning_domains[@]}" -gt 0 ]]; then
body+="
Warning Domains (<= $WARN_DAYS days):
$(printf -- "- %s\n" "${warning_domains[@]}")
"
fi
body+="
Time: $(date '+%Y-%m-%d %H:%M:%S %Z')
Host: $(hostname)
Action Required:
1. Renew SSL certificate immediately
2. Check Let's Encrypt auto-renewal:
sudo certbot renew --dry-run
Certificate details:
$(get_cert_details "${DOMAINS[0]}")
Renewal commands:
# Test renewal
sudo certbot renew --dry-run
# Force renewal
sudo certbot renew --force-renewal
# Check certificate status
sudo certbot certificates
"
send_alert "$subject" "$body"
log "CRITICAL" "SSL certificate alert sent"
elif [[ "$max_severity" -eq 2 ]]; then
local subject="[CRITICAL] SSL Certificate Expires Soon"
local body="CRITICAL: SSL certificate expires in $CRITICAL_DAYS days or less.
Critical Domains (<= $CRITICAL_DAYS days):
$(printf -- "- %s\n" "${critical_domains[@]}")
"
if [[ "${#warning_domains[@]}" -gt 0 ]]; then
body+="
Warning Domains (<= $WARN_DAYS days):
$(printf -- "- %s\n" "${warning_domains[@]}")
"
fi
body+="
Time: $(date '+%Y-%m-%d %H:%M:%S %Z')
Host: $(hostname)
Please renew certificates soon.
Check renewal:
sudo certbot renew --dry-run
"
send_alert "$subject" "$body"
log "CRITICAL" "SSL expiry alert sent"
elif [[ "$max_severity" -eq 1 ]]; then
local subject="[WARN] SSL Certificate Expires Soon"
local body="WARNING: SSL certificate expires in $WARN_DAYS days or less.
Warning Domains (<= $WARN_DAYS days):
$(printf -- "- %s\n" "${warning_domains[@]}")
Time: $(date '+%Y-%m-%d %H:%M:%S %Z')
Host: $(hostname)
Please plan certificate renewal.
"
send_alert "$subject" "$body"
log "WARN" "SSL expiry warning sent"
else
log "INFO" "All SSL certificates valid"
fi
exit $max_severity
}
# Run main function
main