Files
CompanySite/.github/workflows/uptime-monitor.yml
T
Clintchiz d402256547
Deploy to Production / Build & Verify (push) Failing after 5m56s
Ping Search Engines / Notify Search Engines (push) Successful in 2s
Deploy to Production / Pre-Deploy Tests (push) Has been skipped
Deploy to Production / Deploy to Railway (push) Has been skipped
Deploy to Production / Deploy to Render (push) Has been skipped
Deploy to Production / Deploy to VPS (PM2) (push) Has been skipped
Deploy to Production / Deploy to Fly.io (push) Has been skipped
Deploy to Production / Post-Deploy Verification (push) Has been skipped
Deploy to Production / Notify on Failure (push) Successful in 2s
E2E Test Suite / Critical User Journeys (push) Has been skipped
E2E Test Suite / API Integration Tests (push) Has been skipped
E2E Test Suite / Smoke Tests (P0) (push) Failing after 11m26s
E2E Test Suite / Form Interaction Tests (push) Failing after 11m42s
E2E Test Suite / Destructive & Chaos Tests (push) Failing after 12m2s
E2E Test Suite / Cross-Browser Regression (chromium) (push) Failing after 16m14s
E2E Test Suite / Cross-Browser Regression (webkit) (push) Failing after 17m45s
E2E Test Suite / Cross-Browser Regression (firefox) (push) Failing after 25m23s
E2E Test Suite / Security Header Tests (push) Failing after 7m55s
E2E Test Suite / Test Report Summary (push) Failing after 20s
E2E Test Suite / Mobile Device Tests (push) Failing after 2h49m9s
Uptime Monitor / Health & Response Time (push) Failing after 2s
Uptime Monitor / SSL Certificate (push) Successful in 2s
Uptime Monitor / Send Alerts (push) Failing after 3s
Uptime Monitor / Record Uptime Success (push) Has been skipped
First Init
2026-03-21 16:46:46 +05:30

295 lines
11 KiB
YAML

name: Uptime Monitor
on:
schedule:
# Run every 5 minutes
- cron: '*/5 * * * *'
workflow_dispatch:
inputs:
verbose:
description: 'Verbose output'
required: false
default: false
type: boolean
# Prevent concurrent monitoring runs
concurrency:
group: uptime-monitor
cancel-in-progress: true
env:
BASE_URL: https://workroot.in
RESPONSE_TIME_THRESHOLD_MS: 3000
# SSL check: days before expiry to alert
SSL_ALERT_DAYS: 14
jobs:
# ============================================================
# Job 1: Health & Response Time Check
# ============================================================
health-check:
name: Health & Response Time
runs-on: ubuntu-latest
timeout-minutes: 5
outputs:
health-status: ${{ steps.health.outputs.status }}
response-time: ${{ steps.health.outputs.response_time }}
is-slow: ${{ steps.health.outputs.is_slow }}
steps:
- name: Check health endpoint
id: health
run: |
START=$(date +%s%3N)
HTTP_RESPONSE=$(curl \
--silent \
--max-time 10 \
--write-out "\n%{http_code}" \
"${{ env.BASE_URL }}/api/health.json" \
)
END=$(date +%s%3N)
RESPONSE_TIME=$((END - START))
HTTP_BODY=$(echo "$HTTP_RESPONSE" | head -n -1)
HTTP_CODE=$(echo "$HTTP_RESPONSE" | tail -n 1)
echo "HTTP status: $HTTP_CODE"
echo "Response time: ${RESPONSE_TIME}ms"
echo "Body: $HTTP_BODY"
# Outputs
echo "response_time=${RESPONSE_TIME}" >> $GITHUB_OUTPUT
if [ "$HTTP_CODE" = "200" ]; then
STATUS=$(echo "$HTTP_BODY" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('status','unknown'))" 2>/dev/null || echo "parse-error")
echo "status=${STATUS}" >> $GITHUB_OUTPUT
else
echo "status=down-${HTTP_CODE}" >> $GITHUB_OUTPUT
fi
# Slow response check
if [ "$RESPONSE_TIME" -gt "${{ env.RESPONSE_TIME_THRESHOLD_MS }}" ]; then
echo "is_slow=true" >> $GITHUB_OUTPUT
echo "WARNING: Response time ${RESPONSE_TIME}ms exceeds threshold ${{ env.RESPONSE_TIME_THRESHOLD_MS }}ms"
else
echo "is_slow=false" >> $GITHUB_OUTPUT
fi
- name: Check critical pages
id: pages
run: |
FAILED_PAGES=""
PAGES="/ /services /portfolio /contact /about"
for PAGE in $PAGES; do
START=$(date +%s%3N)
HTTP_CODE=$(curl --silent --max-time 10 -o /dev/null -w "%{http_code}" "${{ env.BASE_URL }}${PAGE}")
END=$(date +%s%3N)
RT=$((END - START))
if [ "$HTTP_CODE" != "200" ]; then
FAILED_PAGES="${FAILED_PAGES} ${PAGE}(${HTTP_CODE})"
echo "FAIL: ${PAGE} → HTTP $HTTP_CODE"
else
echo "OK: ${PAGE} → HTTP $HTTP_CODE (${RT}ms)"
fi
done
if [ -n "$FAILED_PAGES" ]; then
echo "Failed pages:${FAILED_PAGES}"
exit 1
fi
- name: Check sitemap and robots.txt
run: |
for RESOURCE in "/sitemap.xml" "/robots.txt"; do
HTTP_CODE=$(curl --silent --max-time 10 -o /dev/null -w "%{http_code}" "${{ env.BASE_URL }}${RESOURCE}")
if [ "$HTTP_CODE" != "200" ]; then
echo "FAIL: ${RESOURCE} returned HTTP $HTTP_CODE"
exit 1
fi
echo "OK: ${RESOURCE} → HTTP $HTTP_CODE"
done
# ============================================================
# Job 2: SSL Certificate Check
# ============================================================
ssl-check:
name: SSL Certificate
runs-on: ubuntu-latest
timeout-minutes: 5
outputs:
days-until-expiry: ${{ steps.ssl.outputs.days_until_expiry }}
ssl-valid: ${{ steps.ssl.outputs.ssl_valid }}
steps:
- name: Check SSL certificate
id: ssl
run: |
DOMAIN="workroot.in"
# Get certificate expiry date
EXPIRY=$(echo | openssl s_client -servername "$DOMAIN" -connect "${DOMAIN}:443" 2>/dev/null \
| openssl x509 -noout -enddate 2>/dev/null \
| cut -d= -f2)
if [ -z "$EXPIRY" ]; then
echo "ssl_valid=false" >> $GITHUB_OUTPUT
echo "days_until_expiry=0" >> $GITHUB_OUTPUT
echo "ERROR: Could not retrieve SSL certificate"
exit 1
fi
EXPIRY_EPOCH=$(date -d "$EXPIRY" +%s 2>/dev/null || date -j -f "%b %d %H:%M:%S %Y %Z" "$EXPIRY" +%s 2>/dev/null)
NOW_EPOCH=$(date +%s)
DAYS_LEFT=$(( (EXPIRY_EPOCH - NOW_EPOCH) / 86400 ))
echo "ssl_valid=true" >> $GITHUB_OUTPUT
echo "days_until_expiry=${DAYS_LEFT}" >> $GITHUB_OUTPUT
echo "SSL certificate expires: $EXPIRY"
echo "Days until expiry: $DAYS_LEFT"
if [ "$DAYS_LEFT" -le "${{ env.SSL_ALERT_DAYS }}" ]; then
echo "WARNING: SSL certificate expires in $DAYS_LEFT days!"
exit 1
fi
echo "SSL OK: $DAYS_LEFT days remaining"
# ============================================================
# Job 3: Alert on Downtime or Issues
# ============================================================
alert:
name: Send Alerts
runs-on: ubuntu-latest
timeout-minutes: 5
needs: [health-check, ssl-check]
if: |
always() &&
(
needs.health-check.result == 'failure' ||
needs.ssl-check.result == 'failure' ||
needs.health-check.outputs.health-status != 'ok' ||
needs.health-check.outputs.is-slow == 'true'
)
steps:
- name: Build alert summary
id: alert-content
run: |
HEALTH_STATUS="${{ needs.health-check.outputs.health-status }}"
RESPONSE_TIME="${{ needs.health-check.outputs.response-time }}"
IS_SLOW="${{ needs.health-check.outputs.is-slow }}"
SSL_DAYS="${{ needs.ssl-check.outputs.days-until-expiry }}"
SSL_VALID="${{ needs.ssl-check.outputs.ssl-valid }}"
# Determine alert type
if [ "${{ needs.health-check.result }}" = "failure" ]; then
ALERT_TYPE="DOWNTIME"
SEVERITY="critical"
elif [ "$IS_SLOW" = "true" ]; then
ALERT_TYPE="SLOW_RESPONSE"
SEVERITY="warning"
elif [ "${{ needs.ssl-check.result }}" = "failure" ]; then
ALERT_TYPE="SSL_EXPIRY"
SEVERITY="warning"
else
ALERT_TYPE="DEGRADED"
SEVERITY="warning"
fi
echo "alert_type=${ALERT_TYPE}" >> $GITHUB_OUTPUT
echo "severity=${SEVERITY}" >> $GITHUB_OUTPUT
# GitHub Step Summary
echo "## Alert: ${ALERT_TYPE} [${SEVERITY^^}]" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Check | Status |" >> $GITHUB_STEP_SUMMARY
echo "|-------|--------|" >> $GITHUB_STEP_SUMMARY
echo "| Health Status | ${HEALTH_STATUS} |" >> $GITHUB_STEP_SUMMARY
echo "| Response Time | ${RESPONSE_TIME}ms |" >> $GITHUB_STEP_SUMMARY
echo "| Response Slow | ${IS_SLOW} |" >> $GITHUB_STEP_SUMMARY
echo "| SSL Valid | ${SSL_VALID} |" >> $GITHUB_STEP_SUMMARY
echo "| SSL Days Left | ${SSL_DAYS} |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Time:** $(date -u '+%Y-%m-%d %H:%M:%S UTC')" >> $GITHUB_STEP_SUMMARY
echo "**Site:** ${{ env.BASE_URL }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "[View Health Endpoint](${{ env.BASE_URL }}/api/health.json)" >> $GITHUB_STEP_SUMMARY
# ── Slack notification (enable by adding SLACK_WEBHOOK_URL secret) ──
# - name: Notify Slack
# if: secrets.SLACK_WEBHOOK_URL != ''
# run: |
# ALERT_TYPE="${{ steps.alert-content.outputs.alert_type }}"
# SEVERITY="${{ steps.alert-content.outputs.severity }}"
# COLOR=$([ "$SEVERITY" = "critical" ] && echo "danger" || echo "warning")
# EMOJI=$([ "$SEVERITY" = "critical" ] && echo ":red_circle:" || echo ":warning:")
#
# curl -s -X POST "${{ secrets.SLACK_WEBHOOK_URL }}" \
# -H 'Content-type: application/json' \
# --data "{
# \"text\": \"${EMOJI} WorkRoot Alert: ${ALERT_TYPE}\",
# \"attachments\": [{
# \"color\": \"${COLOR}\",
# \"fields\": [
# {\"title\": \"Alert\", \"value\": \"${ALERT_TYPE}\", \"short\": true},
# {\"title\": \"Site\", \"value\": \"${{ env.BASE_URL }}\", \"short\": true},
# {\"title\": \"Response Time\", \"value\": \"${{ needs.health-check.outputs.response-time }}ms\", \"short\": true},
# {\"title\": \"SSL Days Left\", \"value\": \"${{ needs.ssl-check.outputs.days-until-expiry }}\", \"short\": true}
# ],
# \"footer\": \"WorkRoot Monitor | $(date -u '+%Y-%m-%d %H:%M UTC')\"
# }]
# }"
# ── Email/PagerDuty notification (via webhook) ──
# - name: Notify via webhook
# if: secrets.ALERT_WEBHOOK_URL != ''
# run: |
# curl -s -X POST "${{ secrets.ALERT_WEBHOOK_URL }}" \
# -H 'Content-type: application/json' \
# --data '{
# "event": "${{ steps.alert-content.outputs.alert_type }}",
# "severity": "${{ steps.alert-content.outputs.severity }}",
# "site": "${{ env.BASE_URL }}",
# "health_status": "${{ needs.health-check.outputs.health-status }}",
# "response_time_ms": "${{ needs.health-check.outputs.response-time }}",
# "ssl_days_left": "${{ needs.ssl-check.outputs.days-until-expiry }}",
# "timestamp": "'"$(date -u +%Y-%m-%dT%H:%M:%SZ)"'"
# }'
- name: Fail workflow to make alert visible
run: |
echo "Alert triggered: ${{ steps.alert-content.outputs.alert_type }}"
echo "Severity: ${{ steps.alert-content.outputs.severity }}"
exit 1
# ============================================================
# Job 4: Record Success (for uptime tracking)
# ============================================================
record-success:
name: Record Uptime Success
runs-on: ubuntu-latest
timeout-minutes: 2
needs: [health-check, ssl-check]
if: |
always() &&
needs.health-check.result == 'success' &&
needs.ssl-check.result == 'success'
steps:
- name: Log success
run: |
echo "## Uptime Check Passed" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Check | Result |" >> $GITHUB_STEP_SUMMARY
echo "|-------|--------|" >> $GITHUB_STEP_SUMMARY
echo "| Health | ${{ needs.health-check.outputs.health-status }} |" >> $GITHUB_STEP_SUMMARY
echo "| Response Time | ${{ needs.health-check.outputs.response-time }}ms |" >> $GITHUB_STEP_SUMMARY
echo "| SSL Days Left | ${{ needs.ssl-check.outputs.days-until-expiry }} |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Checked at:** $(date -u '+%Y-%m-%d %H:%M:%S UTC')" >> $GITHUB_STEP_SUMMARY