diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 000000000..c75b3d7fe --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,2 @@ +# Public status configuration, workflows, and incident process +* @masterfung diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index 651c5a1c7..000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve -title: '' -labels: 'bug' -assignees: 'AnandChowdhary' - ---- - - - -**Describe the bug** -A clear and concise description of what the bug is. - -**To Reproduce** -Steps to reproduce the behavior: -1. Go to '...' -2. Click on '....' -3. Scroll down to '....' -4. See error - -**Expected behavior** -A clear and concise description of what you expected to happen. - -**Screenshots** -If applicable, add screenshots to help explain your problem. - -**Desktop (please complete the following information):** - - OS: [e.g. iOS] - - Browser [e.g. chrome, safari] - - Version [e.g. 22] - -**Smartphone (please complete the following information):** - - Device: [e.g. iPhone6] - - OS: [e.g. iOS8.1] - - Browser [e.g. stock browser, safari] - - Version [e.g. 22] - -**Additional context** -Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index a07d0253b..a1055d683 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,8 +1,11 @@ -blank_issues_enabled: true +blank_issues_enabled: false contact_links: - - name: Feature requests and ideas - url: https://github.com/orgs/upptime/discussions/new?category=ideas - about: Suggest an idea for this project - - name: Questions - url: https://github.com/orgs/upptime/discussions/new?category=q-a - about: Please ask and answer questions here + - name: Report a Mighty service problem + url: mailto:hi@trymighty.ai + about: Contact Mighty support if a problem is not already shown on the status page. + - name: Report a security vulnerability privately + url: https://github.com/TryMightyAI/status/security/advisories/new + about: Do not disclose security vulnerabilities in a public status issue. + - name: Upptime project support + url: https://github.com/upptime/upptime/issues + about: Report bugs in the upstream status-page software to Upptime. diff --git a/.github/ISSUE_TEMPLATE/maintainance-event.md b/.github/ISSUE_TEMPLATE/maintainance-event.md deleted file mode 100644 index 7abcd2532..000000000 --- a/.github/ISSUE_TEMPLATE/maintainance-event.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -name: Maintenance Event -about: Schedule a work window -title: "[Scheduled Maintenance] Site down for Maintenance" -labels: maintenance -assignees: '' - ---- - - - -**Additional context** -Who/what/when/where/why is this maintenance happening diff --git a/.github/ISSUE_TEMPLATE/scheduled-maintenance.md b/.github/ISSUE_TEMPLATE/scheduled-maintenance.md new file mode 100644 index 000000000..3fba39844 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/scheduled-maintenance.md @@ -0,0 +1,41 @@ +--- +name: Scheduled maintenance +about: Announce customer-impacting maintenance or a risky production push +title: "[Scheduled Maintenance] " +labels: maintenance +assignees: "" +--- + +> **Required:** Replace both 2000 timestamps with the approved UTC start/end. +> List only genuinely affected slugs after `expectedDown` or +> `expectedDegraded`; leave the value empty when that impact is not expected. + + + +Valid component slugs: `website`, `api`, `scan-gateway`. + +## Summary + +What work is happening, and why is a public notice appropriate? + +## Expected customer impact + +Describe affected capabilities, regions if relevant, and whether interruption +or degraded performance is expected. Do not include sensitive implementation +details. + +## Update plan + +State where and when the next update will appear. + +## Operator checklist + +- [ ] Approved start/end times are in UTC and replace the 2000 placeholders. +- [ ] Affected component slugs are accurate. +- [ ] Change/rollback owner and approval exist in the private change record. +- [ ] Security/privacy/legal review is complete if the notice needs it. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..4a7b9e7ee --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,13 @@ +## Summary + +## Status-page risk + +- [ ] This change does not make a new SLA, compliance, or availability claim. +- [ ] Public text contains no customer data, secrets, or exploitable details. +- [ ] Monitor/component changes were tested from outside the Mighty stack. +- [ ] Workflow actions remain pinned to full commit SHAs. +- [ ] `ruby scripts/validate.rb` passes. + +## Deployment and rollback + +Describe how the static page will be verified and how this change can be reverted. diff --git a/.github/workflows/graphs.yml b/.github/workflows/graphs.yml deleted file mode 100644 index fa78f349f..000000000 --- a/.github/workflows/graphs.yml +++ /dev/null @@ -1,46 +0,0 @@ -# -# =============================== -# Do not edit this file directly! -# =============================== -# -# Your changes will be overwritten when the Upptime template updates (by default, weekly) -# Instead, change .upptimerc.yml configuration and the workflows will be generated accordingly. -# -# 🔼 Upptime @v1.43.13 -# GitHub-powered open-source uptime monitor and status page by Anand Chowdhary - -# * Source: https://github.com/upptime/upptime -# * Docs and more: https://upptime.js.org -# * More by Anand Chowdhary: https://anandchowdhary.com - - -name: Graphs CI -on: - schedule: - - cron: "0 0 * * *" - repository_dispatch: - types: [graphs] - workflow_dispatch: -concurrency: - group: ${{ github.repository }}-${{ github.head_ref || github.ref_name }}-upptime - cancel-in-progress: false -jobs: - release: - name: Generate graphs - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v6 - with: - ref: ${{ github.head_ref || github.ref_name }} - token: ${{ secrets.GH_PAT || github.token }} - - name: Setup Node.js for graphs - uses: actions/setup-node@v6 - with: - node-version: "20" - - name: Generate graphs - uses: upptime/uptime-monitor@v1.43.13 - with: - command: "graphs" - env: - GH_PAT: ${{ secrets.GH_PAT || github.token }} diff --git a/.github/workflows/response-time.yml b/.github/workflows/response-time.yml index 5304230dc..3df63bff6 100644 --- a/.github/workflows/response-time.yml +++ b/.github/workflows/response-time.yml @@ -1,44 +1,38 @@ -# -# =============================== -# Do not edit this file directly! -# =============================== -# -# Your changes will be overwritten when the Upptime template updates (by default, weekly) -# Instead, change .upptimerc.yml configuration and the workflows will be generated accordingly. -# -# 🔼 Upptime @v1.43.13 -# GitHub-powered open-source uptime monitor and status page by Anand Chowdhary - -# * Source: https://github.com/upptime/upptime -# * Docs and more: https://upptime.js.org -# * More by Anand Chowdhary: https://anandchowdhary.com - - +# Hardened from Upptime v1.43.13. Review upgrades through UPSTREAM.md; +# never replace full commit SHAs with moving tags or branches. name: Response Time CI + on: schedule: - - cron: "0 23 * * *" - repository_dispatch: - types: [response_time] + - cron: "43 23 * * *" workflow_dispatch: + +permissions: + contents: read + concurrency: - group: ${{ github.repository }}-${{ github.head_ref || github.ref_name }}-upptime + group: ${{ github.repository }}-upptime-main-writer cancel-in-progress: false + jobs: release: - name: Check status + permissions: + contents: write + issues: write + name: Record response time + if: github.ref == 'refs/heads/main' && vars.STATUS_AUTOMATION_ENABLED == 'true' runs-on: ubuntu-latest + timeout-minutes: 10 steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 with: - ref: ${{ github.head_ref || github.ref_name }} - token: ${{ secrets.GH_PAT || github.token }} - - name: Update response time - uses: upptime/uptime-monitor@v1.43.13 + ref: main + token: ${{ github.token }} + - name: Record response time + uses: upptime/uptime-monitor@4fec88256b5917a2ed07a088df6e205869b424d6 # v1.43.13 with: - command: "response-time" + command: response-time env: - GH_PAT: ${{ secrets.GH_PAT || github.token }} - # Configure the secret allowlist in .upptimerc.yml; do not edit this workflow directly. - SECRETS_CONTEXT: '{"DYNAMIC_STRING_LENGTH":${{ toJson(secrets.DYNAMIC_STRING_LENGTH) }},"GLOBALPING_TOKEN":${{ toJson(secrets.GLOBALPING_TOKEN) }},"NOTIFICATIONS_DOWN_MESSAGE":${{ toJson(secrets.NOTIFICATIONS_DOWN_MESSAGE) }},"NOTIFICATIONS_UP_MESSAGE":${{ toJson(secrets.NOTIFICATIONS_UP_MESSAGE) }},"NOTIFICATION_CUSTOM_WEBHOOK":${{ toJson(secrets.NOTIFICATION_CUSTOM_WEBHOOK) }},"NOTIFICATION_CUSTOM_WEBHOOK_URL":${{ toJson(secrets.NOTIFICATION_CUSTOM_WEBHOOK_URL) }},"NOTIFICATION_DISCORD_WEBHOOK_URL":${{ toJson(secrets.NOTIFICATION_DISCORD_WEBHOOK_URL) }},"NOTIFICATION_EMAIL":${{ toJson(secrets.NOTIFICATION_EMAIL) }},"NOTIFICATION_EMAIL_FROM":${{ toJson(secrets.NOTIFICATION_EMAIL_FROM) }},"NOTIFICATION_EMAIL_MAILGUN":${{ toJson(secrets.NOTIFICATION_EMAIL_MAILGUN) }},"NOTIFICATION_EMAIL_MAILGUN_API_KEY":${{ toJson(secrets.NOTIFICATION_EMAIL_MAILGUN_API_KEY) }},"NOTIFICATION_EMAIL_MAILGUN_DOMAIN_NAME":${{ toJson(secrets.NOTIFICATION_EMAIL_MAILGUN_DOMAIN_NAME) }},"NOTIFICATION_EMAIL_SENDGRID":${{ toJson(secrets.NOTIFICATION_EMAIL_SENDGRID) }},"NOTIFICATION_EMAIL_SENDGRID_API_KEY":${{ toJson(secrets.NOTIFICATION_EMAIL_SENDGRID_API_KEY) }},"NOTIFICATION_EMAIL_SES":${{ toJson(secrets.NOTIFICATION_EMAIL_SES) }},"NOTIFICATION_EMAIL_SES_ACCESS_KEY_ID":${{ toJson(secrets.NOTIFICATION_EMAIL_SES_ACCESS_KEY_ID) }},"NOTIFICATION_EMAIL_SES_REGION":${{ toJson(secrets.NOTIFICATION_EMAIL_SES_REGION) }},"NOTIFICATION_EMAIL_SES_SECRET_ACCESS_KEY":${{ toJson(secrets.NOTIFICATION_EMAIL_SES_SECRET_ACCESS_KEY) }},"NOTIFICATION_EMAIL_SES_SESSION_TOKEN":${{ toJson(secrets.NOTIFICATION_EMAIL_SES_SESSION_TOKEN) }},"NOTIFICATION_EMAIL_SMTP":${{ toJson(secrets.NOTIFICATION_EMAIL_SMTP) }},"NOTIFICATION_EMAIL_SMTP_HOST":${{ toJson(secrets.NOTIFICATION_EMAIL_SMTP_HOST) }},"NOTIFICATION_EMAIL_SMTP_PASSWORD":${{ toJson(secrets.NOTIFICATION_EMAIL_SMTP_PASSWORD) }},"NOTIFICATION_EMAIL_SMTP_PORT":${{ toJson(secrets.NOTIFICATION_EMAIL_SMTP_PORT) }},"NOTIFICATION_EMAIL_SMTP_USERNAME":${{ toJson(secrets.NOTIFICATION_EMAIL_SMTP_USERNAME) }},"NOTIFICATION_EMAIL_SPARKPOST":${{ toJson(secrets.NOTIFICATION_EMAIL_SPARKPOST) }},"NOTIFICATION_EMAIL_SPARKPOST_API_KEY":${{ toJson(secrets.NOTIFICATION_EMAIL_SPARKPOST_API_KEY) }},"NOTIFICATION_EMAIL_STRATEGY":${{ toJson(secrets.NOTIFICATION_EMAIL_STRATEGY) }},"NOTIFICATION_EMAIL_TO":${{ toJson(secrets.NOTIFICATION_EMAIL_TO) }},"NOTIFICATION_GOOGLE_CHAT_WEBHOOK_URL":${{ toJson(secrets.NOTIFICATION_GOOGLE_CHAT_WEBHOOK_URL) }},"NOTIFICATION_GOTIFY":${{ toJson(secrets.NOTIFICATION_GOTIFY) }},"NOTIFICATION_GOTIFY_PRIORITY":${{ toJson(secrets.NOTIFICATION_GOTIFY_PRIORITY) }},"NOTIFICATION_GOTIFY_TITLE":${{ toJson(secrets.NOTIFICATION_GOTIFY_TITLE) }},"NOTIFICATION_GOTIFY_TOKEN":${{ toJson(secrets.NOTIFICATION_GOTIFY_TOKEN) }},"NOTIFICATION_GOTIFY_URL":${{ toJson(secrets.NOTIFICATION_GOTIFY_URL) }},"NOTIFICATION_LARK":${{ toJson(secrets.NOTIFICATION_LARK) }},"NOTIFICATION_LARK_BOT_WEBHOOK":${{ toJson(secrets.NOTIFICATION_LARK_BOT_WEBHOOK) }},"NOTIFICATION_MASTODON":${{ toJson(secrets.NOTIFICATION_MASTODON) }},"NOTIFICATION_MASTODON_API_KEY":${{ toJson(secrets.NOTIFICATION_MASTODON_API_KEY) }},"NOTIFICATION_MASTODON_INSTANCE_URL":${{ toJson(secrets.NOTIFICATION_MASTODON_INSTANCE_URL) }},"NOTIFICATION_MASTODON_TOOT_VISIBILITY":${{ toJson(secrets.NOTIFICATION_MASTODON_TOOT_VISIBILITY) }},"NOTIFICATION_MISSKEY":${{ toJson(secrets.NOTIFICATION_MISSKEY) }},"NOTIFICATION_MISSKEY_API_KEY":${{ toJson(secrets.NOTIFICATION_MISSKEY_API_KEY) }},"NOTIFICATION_MISSKEY_CHAT":${{ toJson(secrets.NOTIFICATION_MISSKEY_CHAT) }},"NOTIFICATION_MISSKEY_CHAT_USER_ID":${{ toJson(secrets.NOTIFICATION_MISSKEY_CHAT_USER_ID) }},"NOTIFICATION_MISSKEY_INSTANCE_URL":${{ toJson(secrets.NOTIFICATION_MISSKEY_INSTANCE_URL) }},"NOTIFICATION_MISSKEY_NOTE":${{ toJson(secrets.NOTIFICATION_MISSKEY_NOTE) }},"NOTIFICATION_MISSKEY_NOTE_VISIBILITY":${{ toJson(secrets.NOTIFICATION_MISSKEY_NOTE_VISIBILITY) }},"NOTIFICATION_MISSKEY_NOTE_VISIBLE_USER_IDS":${{ toJson(secrets.NOTIFICATION_MISSKEY_NOTE_VISIBLE_USER_IDS) }},"NOTIFICATION_SLACK":${{ toJson(secrets.NOTIFICATION_SLACK) }},"NOTIFICATION_SLACK_STRATEGY":${{ toJson(secrets.NOTIFICATION_SLACK_STRATEGY) }},"NOTIFICATION_SLACK_WEBHOOK_URL":${{ toJson(secrets.NOTIFICATION_SLACK_WEBHOOK_URL) }},"NOTIFICATION_SMS_46ELKS":${{ toJson(secrets.NOTIFICATION_SMS_46ELKS) }},"NOTIFICATION_SMS_46ELKS_API_PASSWORD":${{ toJson(secrets.NOTIFICATION_SMS_46ELKS_API_PASSWORD) }},"NOTIFICATION_SMS_46ELKS_API_USERNAME":${{ toJson(secrets.NOTIFICATION_SMS_46ELKS_API_USERNAME) }},"NOTIFICATION_SMS_CALLR":${{ toJson(secrets.NOTIFICATION_SMS_CALLR) }},"NOTIFICATION_SMS_CALLR_LOGIN":${{ toJson(secrets.NOTIFICATION_SMS_CALLR_LOGIN) }},"NOTIFICATION_SMS_CALLR_PASSWORD":${{ toJson(secrets.NOTIFICATION_SMS_CALLR_PASSWORD) }},"NOTIFICATION_SMS_CLICKATELL":${{ toJson(secrets.NOTIFICATION_SMS_CLICKATELL) }},"NOTIFICATION_SMS_CLICKATELL_API_KEY":${{ toJson(secrets.NOTIFICATION_SMS_CLICKATELL_API_KEY) }},"NOTIFICATION_SMS_FROM":${{ toJson(secrets.NOTIFICATION_SMS_FROM) }},"NOTIFICATION_SMS_INFOBIP":${{ toJson(secrets.NOTIFICATION_SMS_INFOBIP) }},"NOTIFICATION_SMS_INFOBIP_PASSWORD":${{ toJson(secrets.NOTIFICATION_SMS_INFOBIP_PASSWORD) }},"NOTIFICATION_SMS_INFOBIP_USERNAME":${{ toJson(secrets.NOTIFICATION_SMS_INFOBIP_USERNAME) }},"NOTIFICATION_SMS_NEXMO":${{ toJson(secrets.NOTIFICATION_SMS_NEXMO) }},"NOTIFICATION_SMS_NEXMO_API_KEY":${{ toJson(secrets.NOTIFICATION_SMS_NEXMO_API_KEY) }},"NOTIFICATION_SMS_NEXMO_API_SECRET":${{ toJson(secrets.NOTIFICATION_SMS_NEXMO_API_SECRET) }},"NOTIFICATION_SMS_OVH":${{ toJson(secrets.NOTIFICATION_SMS_OVH) }},"NOTIFICATION_SMS_OVH_ACCOUNT":${{ toJson(secrets.NOTIFICATION_SMS_OVH_ACCOUNT) }},"NOTIFICATION_SMS_OVH_APP_KEY":${{ toJson(secrets.NOTIFICATION_SMS_OVH_APP_KEY) }},"NOTIFICATION_SMS_OVH_APP_SECRET":${{ toJson(secrets.NOTIFICATION_SMS_OVH_APP_SECRET) }},"NOTIFICATION_SMS_OVH_CONSUMER_KEY":${{ toJson(secrets.NOTIFICATION_SMS_OVH_CONSUMER_KEY) }},"NOTIFICATION_SMS_OVH_HOST":${{ toJson(secrets.NOTIFICATION_SMS_OVH_HOST) }},"NOTIFICATION_SMS_PLIVO":${{ toJson(secrets.NOTIFICATION_SMS_PLIVO) }},"NOTIFICATION_SMS_PLIVO_AUTH_ID":${{ toJson(secrets.NOTIFICATION_SMS_PLIVO_AUTH_ID) }},"NOTIFICATION_SMS_PLIVO_AUTH_TOKEN":${{ toJson(secrets.NOTIFICATION_SMS_PLIVO_AUTH_TOKEN) }},"NOTIFICATION_SMS_STRATEGY":${{ toJson(secrets.NOTIFICATION_SMS_STRATEGY) }},"NOTIFICATION_SMS_TO":${{ toJson(secrets.NOTIFICATION_SMS_TO) }},"NOTIFICATION_SMS_TWILIO":${{ toJson(secrets.NOTIFICATION_SMS_TWILIO) }},"NOTIFICATION_SMS_TWILIO_ACCOUNT_SID":${{ toJson(secrets.NOTIFICATION_SMS_TWILIO_ACCOUNT_SID) }},"NOTIFICATION_SMS_TWILIO_AUTH_TOKEN":${{ toJson(secrets.NOTIFICATION_SMS_TWILIO_AUTH_TOKEN) }},"NOTIFICATION_TEAMS":${{ toJson(secrets.NOTIFICATION_TEAMS) }},"NOTIFICATION_TEAMS_WEBHOOK_URL":${{ toJson(secrets.NOTIFICATION_TEAMS_WEBHOOK_URL) }},"NOTIFICATION_TELEGRAM":${{ toJson(secrets.NOTIFICATION_TELEGRAM) }},"NOTIFICATION_TELEGRAM_BOT_KEY":${{ toJson(secrets.NOTIFICATION_TELEGRAM_BOT_KEY) }},"NOTIFICATION_TELEGRAM_CHAT_ID":${{ toJson(secrets.NOTIFICATION_TELEGRAM_CHAT_ID) }},"NOTIFICATION_ZULIP_API_EMAIL":${{ toJson(secrets.NOTIFICATION_ZULIP_API_EMAIL) }},"NOTIFICATION_ZULIP_API_KEY":${{ toJson(secrets.NOTIFICATION_ZULIP_API_KEY) }},"NOTIFICATION_ZULIP_MESSAGE_URL":${{ toJson(secrets.NOTIFICATION_ZULIP_MESSAGE_URL) }},"RANDOM_MAX":${{ toJson(secrets.RANDOM_MAX) }},"RANDOM_MIN":${{ toJson(secrets.RANDOM_MIN) }},"SECRET_SITE":${{ toJson(secrets.SECRET_SITE) }},"USER_AGENT":${{ toJson(secrets.USER_AGENT) }}}' + GITHUB_TOKEN: ${{ github.token }} + SECRETS_CONTEXT: "{}" diff --git a/.github/workflows/setup.yml b/.github/workflows/setup.yml deleted file mode 100644 index fe290a592..000000000 --- a/.github/workflows/setup.yml +++ /dev/null @@ -1,90 +0,0 @@ -# -# =============================== -# Do not edit this file directly! -# =============================== -# -# Your changes will be overwritten when the Upptime template updates (by default, weekly) -# Instead, change .upptimerc.yml configuration and the workflows will be generated accordingly. -# -# 🔼 Upptime @v1.43.13 -# GitHub-powered open-source uptime monitor and status page by Anand Chowdhary - -# * Source: https://github.com/upptime/upptime -# * Docs and more: https://upptime.js.org -# * More by Anand Chowdhary: https://anandchowdhary.com - - -name: Setup CI -on: - push: - paths: - - ".upptimerc.yml" - repository_dispatch: - types: [setup] - workflow_dispatch: -concurrency: - group: ${{ github.repository }}-${{ github.head_ref || github.ref_name }}-upptime - cancel-in-progress: false -jobs: - release: - name: Setup Upptime - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v6 - with: - ref: ${{ github.head_ref || github.ref_name }} - token: ${{ secrets.GH_PAT || github.token }} - - name: Update template - uses: upptime/uptime-monitor@v1.43.13 - with: - command: "update-template" - env: - GH_PAT: ${{ secrets.GH_PAT || github.token }} - - name: Update response time - uses: upptime/uptime-monitor@v1.43.13 - with: - command: "response-time" - env: - GH_PAT: ${{ secrets.GH_PAT || github.token }} - # Configure the secret allowlist in .upptimerc.yml; do not edit this workflow directly. - SECRETS_CONTEXT: '{"DYNAMIC_STRING_LENGTH":${{ toJson(secrets.DYNAMIC_STRING_LENGTH) }},"GLOBALPING_TOKEN":${{ toJson(secrets.GLOBALPING_TOKEN) }},"NOTIFICATIONS_DOWN_MESSAGE":${{ toJson(secrets.NOTIFICATIONS_DOWN_MESSAGE) }},"NOTIFICATIONS_UP_MESSAGE":${{ toJson(secrets.NOTIFICATIONS_UP_MESSAGE) }},"NOTIFICATION_CUSTOM_WEBHOOK":${{ toJson(secrets.NOTIFICATION_CUSTOM_WEBHOOK) }},"NOTIFICATION_CUSTOM_WEBHOOK_URL":${{ toJson(secrets.NOTIFICATION_CUSTOM_WEBHOOK_URL) }},"NOTIFICATION_DISCORD_WEBHOOK_URL":${{ toJson(secrets.NOTIFICATION_DISCORD_WEBHOOK_URL) }},"NOTIFICATION_EMAIL":${{ toJson(secrets.NOTIFICATION_EMAIL) }},"NOTIFICATION_EMAIL_FROM":${{ toJson(secrets.NOTIFICATION_EMAIL_FROM) }},"NOTIFICATION_EMAIL_MAILGUN":${{ toJson(secrets.NOTIFICATION_EMAIL_MAILGUN) }},"NOTIFICATION_EMAIL_MAILGUN_API_KEY":${{ toJson(secrets.NOTIFICATION_EMAIL_MAILGUN_API_KEY) }},"NOTIFICATION_EMAIL_MAILGUN_DOMAIN_NAME":${{ toJson(secrets.NOTIFICATION_EMAIL_MAILGUN_DOMAIN_NAME) }},"NOTIFICATION_EMAIL_SENDGRID":${{ toJson(secrets.NOTIFICATION_EMAIL_SENDGRID) }},"NOTIFICATION_EMAIL_SENDGRID_API_KEY":${{ toJson(secrets.NOTIFICATION_EMAIL_SENDGRID_API_KEY) }},"NOTIFICATION_EMAIL_SES":${{ toJson(secrets.NOTIFICATION_EMAIL_SES) }},"NOTIFICATION_EMAIL_SES_ACCESS_KEY_ID":${{ toJson(secrets.NOTIFICATION_EMAIL_SES_ACCESS_KEY_ID) }},"NOTIFICATION_EMAIL_SES_REGION":${{ toJson(secrets.NOTIFICATION_EMAIL_SES_REGION) }},"NOTIFICATION_EMAIL_SES_SECRET_ACCESS_KEY":${{ toJson(secrets.NOTIFICATION_EMAIL_SES_SECRET_ACCESS_KEY) }},"NOTIFICATION_EMAIL_SES_SESSION_TOKEN":${{ toJson(secrets.NOTIFICATION_EMAIL_SES_SESSION_TOKEN) }},"NOTIFICATION_EMAIL_SMTP":${{ toJson(secrets.NOTIFICATION_EMAIL_SMTP) }},"NOTIFICATION_EMAIL_SMTP_HOST":${{ toJson(secrets.NOTIFICATION_EMAIL_SMTP_HOST) }},"NOTIFICATION_EMAIL_SMTP_PASSWORD":${{ toJson(secrets.NOTIFICATION_EMAIL_SMTP_PASSWORD) }},"NOTIFICATION_EMAIL_SMTP_PORT":${{ toJson(secrets.NOTIFICATION_EMAIL_SMTP_PORT) }},"NOTIFICATION_EMAIL_SMTP_USERNAME":${{ toJson(secrets.NOTIFICATION_EMAIL_SMTP_USERNAME) }},"NOTIFICATION_EMAIL_SPARKPOST":${{ toJson(secrets.NOTIFICATION_EMAIL_SPARKPOST) }},"NOTIFICATION_EMAIL_SPARKPOST_API_KEY":${{ toJson(secrets.NOTIFICATION_EMAIL_SPARKPOST_API_KEY) }},"NOTIFICATION_EMAIL_STRATEGY":${{ toJson(secrets.NOTIFICATION_EMAIL_STRATEGY) }},"NOTIFICATION_EMAIL_TO":${{ toJson(secrets.NOTIFICATION_EMAIL_TO) }},"NOTIFICATION_GOOGLE_CHAT_WEBHOOK_URL":${{ toJson(secrets.NOTIFICATION_GOOGLE_CHAT_WEBHOOK_URL) }},"NOTIFICATION_GOTIFY":${{ toJson(secrets.NOTIFICATION_GOTIFY) }},"NOTIFICATION_GOTIFY_PRIORITY":${{ toJson(secrets.NOTIFICATION_GOTIFY_PRIORITY) }},"NOTIFICATION_GOTIFY_TITLE":${{ toJson(secrets.NOTIFICATION_GOTIFY_TITLE) }},"NOTIFICATION_GOTIFY_TOKEN":${{ toJson(secrets.NOTIFICATION_GOTIFY_TOKEN) }},"NOTIFICATION_GOTIFY_URL":${{ toJson(secrets.NOTIFICATION_GOTIFY_URL) }},"NOTIFICATION_LARK":${{ toJson(secrets.NOTIFICATION_LARK) }},"NOTIFICATION_LARK_BOT_WEBHOOK":${{ toJson(secrets.NOTIFICATION_LARK_BOT_WEBHOOK) }},"NOTIFICATION_MASTODON":${{ toJson(secrets.NOTIFICATION_MASTODON) }},"NOTIFICATION_MASTODON_API_KEY":${{ toJson(secrets.NOTIFICATION_MASTODON_API_KEY) }},"NOTIFICATION_MASTODON_INSTANCE_URL":${{ toJson(secrets.NOTIFICATION_MASTODON_INSTANCE_URL) }},"NOTIFICATION_MASTODON_TOOT_VISIBILITY":${{ toJson(secrets.NOTIFICATION_MASTODON_TOOT_VISIBILITY) }},"NOTIFICATION_MISSKEY":${{ toJson(secrets.NOTIFICATION_MISSKEY) }},"NOTIFICATION_MISSKEY_API_KEY":${{ toJson(secrets.NOTIFICATION_MISSKEY_API_KEY) }},"NOTIFICATION_MISSKEY_CHAT":${{ toJson(secrets.NOTIFICATION_MISSKEY_CHAT) }},"NOTIFICATION_MISSKEY_CHAT_USER_ID":${{ toJson(secrets.NOTIFICATION_MISSKEY_CHAT_USER_ID) }},"NOTIFICATION_MISSKEY_INSTANCE_URL":${{ toJson(secrets.NOTIFICATION_MISSKEY_INSTANCE_URL) }},"NOTIFICATION_MISSKEY_NOTE":${{ toJson(secrets.NOTIFICATION_MISSKEY_NOTE) }},"NOTIFICATION_MISSKEY_NOTE_VISIBILITY":${{ toJson(secrets.NOTIFICATION_MISSKEY_NOTE_VISIBILITY) }},"NOTIFICATION_MISSKEY_NOTE_VISIBLE_USER_IDS":${{ toJson(secrets.NOTIFICATION_MISSKEY_NOTE_VISIBLE_USER_IDS) }},"NOTIFICATION_SLACK":${{ toJson(secrets.NOTIFICATION_SLACK) }},"NOTIFICATION_SLACK_STRATEGY":${{ toJson(secrets.NOTIFICATION_SLACK_STRATEGY) }},"NOTIFICATION_SLACK_WEBHOOK_URL":${{ toJson(secrets.NOTIFICATION_SLACK_WEBHOOK_URL) }},"NOTIFICATION_SMS_46ELKS":${{ toJson(secrets.NOTIFICATION_SMS_46ELKS) }},"NOTIFICATION_SMS_46ELKS_API_PASSWORD":${{ toJson(secrets.NOTIFICATION_SMS_46ELKS_API_PASSWORD) }},"NOTIFICATION_SMS_46ELKS_API_USERNAME":${{ toJson(secrets.NOTIFICATION_SMS_46ELKS_API_USERNAME) }},"NOTIFICATION_SMS_CALLR":${{ toJson(secrets.NOTIFICATION_SMS_CALLR) }},"NOTIFICATION_SMS_CALLR_LOGIN":${{ toJson(secrets.NOTIFICATION_SMS_CALLR_LOGIN) }},"NOTIFICATION_SMS_CALLR_PASSWORD":${{ toJson(secrets.NOTIFICATION_SMS_CALLR_PASSWORD) }},"NOTIFICATION_SMS_CLICKATELL":${{ toJson(secrets.NOTIFICATION_SMS_CLICKATELL) }},"NOTIFICATION_SMS_CLICKATELL_API_KEY":${{ toJson(secrets.NOTIFICATION_SMS_CLICKATELL_API_KEY) }},"NOTIFICATION_SMS_FROM":${{ toJson(secrets.NOTIFICATION_SMS_FROM) }},"NOTIFICATION_SMS_INFOBIP":${{ toJson(secrets.NOTIFICATION_SMS_INFOBIP) }},"NOTIFICATION_SMS_INFOBIP_PASSWORD":${{ toJson(secrets.NOTIFICATION_SMS_INFOBIP_PASSWORD) }},"NOTIFICATION_SMS_INFOBIP_USERNAME":${{ toJson(secrets.NOTIFICATION_SMS_INFOBIP_USERNAME) }},"NOTIFICATION_SMS_NEXMO":${{ toJson(secrets.NOTIFICATION_SMS_NEXMO) }},"NOTIFICATION_SMS_NEXMO_API_KEY":${{ toJson(secrets.NOTIFICATION_SMS_NEXMO_API_KEY) }},"NOTIFICATION_SMS_NEXMO_API_SECRET":${{ toJson(secrets.NOTIFICATION_SMS_NEXMO_API_SECRET) }},"NOTIFICATION_SMS_OVH":${{ toJson(secrets.NOTIFICATION_SMS_OVH) }},"NOTIFICATION_SMS_OVH_ACCOUNT":${{ toJson(secrets.NOTIFICATION_SMS_OVH_ACCOUNT) }},"NOTIFICATION_SMS_OVH_APP_KEY":${{ toJson(secrets.NOTIFICATION_SMS_OVH_APP_KEY) }},"NOTIFICATION_SMS_OVH_APP_SECRET":${{ toJson(secrets.NOTIFICATION_SMS_OVH_APP_SECRET) }},"NOTIFICATION_SMS_OVH_CONSUMER_KEY":${{ toJson(secrets.NOTIFICATION_SMS_OVH_CONSUMER_KEY) }},"NOTIFICATION_SMS_OVH_HOST":${{ toJson(secrets.NOTIFICATION_SMS_OVH_HOST) }},"NOTIFICATION_SMS_PLIVO":${{ toJson(secrets.NOTIFICATION_SMS_PLIVO) }},"NOTIFICATION_SMS_PLIVO_AUTH_ID":${{ toJson(secrets.NOTIFICATION_SMS_PLIVO_AUTH_ID) }},"NOTIFICATION_SMS_PLIVO_AUTH_TOKEN":${{ toJson(secrets.NOTIFICATION_SMS_PLIVO_AUTH_TOKEN) }},"NOTIFICATION_SMS_STRATEGY":${{ toJson(secrets.NOTIFICATION_SMS_STRATEGY) }},"NOTIFICATION_SMS_TO":${{ toJson(secrets.NOTIFICATION_SMS_TO) }},"NOTIFICATION_SMS_TWILIO":${{ toJson(secrets.NOTIFICATION_SMS_TWILIO) }},"NOTIFICATION_SMS_TWILIO_ACCOUNT_SID":${{ toJson(secrets.NOTIFICATION_SMS_TWILIO_ACCOUNT_SID) }},"NOTIFICATION_SMS_TWILIO_AUTH_TOKEN":${{ toJson(secrets.NOTIFICATION_SMS_TWILIO_AUTH_TOKEN) }},"NOTIFICATION_TEAMS":${{ toJson(secrets.NOTIFICATION_TEAMS) }},"NOTIFICATION_TEAMS_WEBHOOK_URL":${{ toJson(secrets.NOTIFICATION_TEAMS_WEBHOOK_URL) }},"NOTIFICATION_TELEGRAM":${{ toJson(secrets.NOTIFICATION_TELEGRAM) }},"NOTIFICATION_TELEGRAM_BOT_KEY":${{ toJson(secrets.NOTIFICATION_TELEGRAM_BOT_KEY) }},"NOTIFICATION_TELEGRAM_CHAT_ID":${{ toJson(secrets.NOTIFICATION_TELEGRAM_CHAT_ID) }},"NOTIFICATION_ZULIP_API_EMAIL":${{ toJson(secrets.NOTIFICATION_ZULIP_API_EMAIL) }},"NOTIFICATION_ZULIP_API_KEY":${{ toJson(secrets.NOTIFICATION_ZULIP_API_KEY) }},"NOTIFICATION_ZULIP_MESSAGE_URL":${{ toJson(secrets.NOTIFICATION_ZULIP_MESSAGE_URL) }},"RANDOM_MAX":${{ toJson(secrets.RANDOM_MAX) }},"RANDOM_MIN":${{ toJson(secrets.RANDOM_MIN) }},"SECRET_SITE":${{ toJson(secrets.SECRET_SITE) }},"USER_AGENT":${{ toJson(secrets.USER_AGENT) }}}' - - name: Update summary in README - uses: upptime/uptime-monitor@v1.43.13 - with: - command: "readme" - env: - GH_PAT: ${{ secrets.GH_PAT || github.token }} - - name: Generate graphs - id: dispatch_graphs - uses: benc-uk/workflow-dispatch@v1 - continue-on-error: true - with: - workflow: Graphs CI - token: ${{ secrets.GH_PAT || github.token }} - - name: Setup Node.js for direct graph generation - if: steps.dispatch_graphs.outcome == 'failure' - uses: actions/setup-node@v6 - with: - node-version: "20" - - name: Generate graphs directly if dispatch fails - if: steps.dispatch_graphs.outcome == 'failure' - uses: upptime/uptime-monitor@v1.43.13 - with: - command: "graphs" - env: - GH_PAT: ${{ secrets.GH_PAT || github.token }} - - name: Generate site - uses: upptime/uptime-monitor@v1.43.13 - with: - command: "site" - env: - GH_PAT: ${{ secrets.GH_PAT || github.token }} - - uses: peaceiris/actions-gh-pages@v4 - name: GitHub Pages Deploy - with: - github_token: ${{ secrets.GH_PAT || github.token }} - publish_dir: "site/status-page/__sapper__/export/" - force_orphan: "false" - user_name: "Upptime Bot" - user_email: "73812536+upptime-bot@users.noreply.github.com" diff --git a/.github/workflows/site.yml b/.github/workflows/site.yml index aa79ff6a2..f7827ea09 100644 --- a/.github/workflows/site.yml +++ b/.github/workflows/site.yml @@ -1,54 +1,69 @@ -# -# =============================== -# Do not edit this file directly! -# =============================== -# -# Your changes will be overwritten when the Upptime template updates (by default, weekly) -# Instead, change .upptimerc.yml configuration and the workflows will be generated accordingly. -# -# 🔼 Upptime @v1.43.13 -# GitHub-powered open-source uptime monitor and status page by Anand Chowdhary - -# * Source: https://github.com/upptime/upptime -# * Docs and more: https://upptime.js.org -# * More by Anand Chowdhary: https://anandchowdhary.com - - +# Hardened from Upptime v1.43.13. Review upgrades through UPSTREAM.md; +# status-page source and all Actions are pinned to immutable revisions. name: Static Site CI + on: - push: - paths: - - "assets/**" schedule: - - cron: "0 1 * * *" - repository_dispatch: - types: [static_site] + - cron: "27 1 * * *" workflow_dispatch: + +permissions: + contents: read + concurrency: - group: ${{ github.repository }}-${{ github.head_ref || github.ref_name }}-upptime + group: ${{ github.repository }}-upptime-static-site cancel-in-progress: false + jobs: release: - name: Build and deploy site + permissions: + contents: write + name: Build and publish static site + if: github.ref == 'refs/heads/main' && vars.STATUS_AUTOMATION_ENABLED == 'true' runs-on: ubuntu-latest - if: "!contains(github.event.head_commit.message, '[skip ci]')" + timeout-minutes: 20 steps: - - name: Checkout - uses: actions/checkout@v6 + - name: Checkout status repository + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 + with: + ref: main + persist-credentials: false + - name: Checkout pinned Upptime status page + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 with: - ref: ${{ github.head_ref || github.ref_name }} - token: ${{ secrets.GH_PAT || github.token }} - - name: Generate site - uses: upptime/uptime-monitor@v1.43.13 + repository: upptime/status-page + ref: 54c2ff5a3d998d525ee4c7e68dc7ce7414d89c33 # v1.17.0 + path: site + persist-credentials: false + - name: Apply Mighty main-branch compatibility patch + run: git -C site apply --index --unidiff-zero ../patches/upptime-status-page-main.patch + - name: Stage Mighty static assets + run: cp -R assets/. site/static/ + - name: Set up Node.js + uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6 with: - command: "site" + node-version: "20" + cache: npm + cache-dependency-path: site/package-lock.json + - name: Build static site from locked dependencies + working-directory: site env: - GH_PAT: ${{ secrets.GH_PAT || github.token }} - - uses: peaceiris/actions-gh-pages@v4 - name: GitHub Pages Deploy + CYPRESS_INSTALL_BINARY: "0" + run: | + npm ci --no-audit --no-fund + npm run export + - name: Verify generated output + run: | + test -s site/__sapper__/export/index.html + test -s site/__sapper__/export/manifest.json + test -s site/__sapper__/export/_headers + test -f site/__sapper__/export/mighty-logo.png + test "$(wc -c < site/__sapper__/export/mighty-logo.png)" -gt 1000 + - name: Publish gh-pages branch + uses: peaceiris/actions-gh-pages@84c30a85c19949d7eee79c4ff27748b70285e453 # v4 with: - github_token: ${{ secrets.GH_PAT || github.token }} - publish_dir: "site/status-page/__sapper__/export/" + github_token: ${{ github.token }} + publish_dir: site/__sapper__/export/ force_orphan: "false" - user_name: "Upptime Bot" - user_email: "73812536+upptime-bot@users.noreply.github.com" + user_name: Mighty Status Bot + user_email: 73812536+upptime-bot@users.noreply.github.com diff --git a/.github/workflows/summary.yml b/.github/workflows/summary.yml deleted file mode 100644 index a41e76ea1..000000000 --- a/.github/workflows/summary.yml +++ /dev/null @@ -1,42 +0,0 @@ -# -# =============================== -# Do not edit this file directly! -# =============================== -# -# Your changes will be overwritten when the Upptime template updates (by default, weekly) -# Instead, change .upptimerc.yml configuration and the workflows will be generated accordingly. -# -# 🔼 Upptime @v1.43.13 -# GitHub-powered open-source uptime monitor and status page by Anand Chowdhary - -# * Source: https://github.com/upptime/upptime -# * Docs and more: https://upptime.js.org -# * More by Anand Chowdhary: https://anandchowdhary.com - - -name: Summary CI -on: - schedule: - - cron: "0 0 * * *" - repository_dispatch: - types: [summary] - workflow_dispatch: -concurrency: - group: ${{ github.repository }}-${{ github.head_ref || github.ref_name }}-upptime - cancel-in-progress: false -jobs: - release: - name: Generate README - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v6 - with: - ref: ${{ github.head_ref || github.ref_name }} - token: ${{ secrets.GH_PAT || github.token }} - - name: Update summary in README - uses: upptime/uptime-monitor@v1.43.13 - with: - command: "readme" - env: - GH_PAT: ${{ secrets.GH_PAT || github.token }} diff --git a/.github/workflows/update-template.yml b/.github/workflows/update-template.yml deleted file mode 100644 index ba91dcbe5..000000000 --- a/.github/workflows/update-template.yml +++ /dev/null @@ -1,42 +0,0 @@ -# -# =============================== -# Do not edit this file directly! -# =============================== -# -# Your changes will be overwritten when the Upptime template updates (by default, weekly) -# Instead, change .upptimerc.yml configuration and the workflows will be generated accordingly. -# -# 🔼 Upptime @v1.43.13 -# GitHub-powered open-source uptime monitor and status page by Anand Chowdhary - -# * Source: https://github.com/upptime/upptime -# * Docs and more: https://upptime.js.org -# * More by Anand Chowdhary: https://anandchowdhary.com - - -name: Update Template CI -on: - schedule: - - cron: "0 0 * * *" - repository_dispatch: - types: [update_template] - workflow_dispatch: -concurrency: - group: ${{ github.repository }}-${{ github.head_ref || github.ref_name }}-upptime - cancel-in-progress: false -jobs: - release: - name: Build - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v6 - with: - ref: ${{ github.head_ref || github.ref_name }} - token: ${{ secrets.GH_PAT || github.token }} - - name: Update template - uses: upptime/uptime-monitor@master - with: - command: "update-template" - env: - GH_PAT: ${{ secrets.GH_PAT || github.token }} diff --git a/.github/workflows/updates.yml b/.github/workflows/updates.yml deleted file mode 100644 index 312dfa906..000000000 --- a/.github/workflows/updates.yml +++ /dev/null @@ -1,40 +0,0 @@ -# -# =============================== -# Do not edit this file directly! -# =============================== -# -# Your changes will be overwritten when the Upptime template updates (by default, weekly) -# Instead, change .upptimerc.yml configuration and the workflows will be generated accordingly. -# -# 🔼 Upptime @v1.43.13 -# GitHub-powered open-source uptime monitor and status page by Anand Chowdhary - -# * Source: https://github.com/upptime/upptime -# * Docs and more: https://upptime.js.org -# * More by Anand Chowdhary: https://anandchowdhary.com - - -name: Updates CI -on: - schedule: - - cron: "0 3 * * *" - repository_dispatch: - types: [updates] - workflow_dispatch: -concurrency: - group: ${{ github.repository }}-${{ github.head_ref || github.ref_name }}-upptime - cancel-in-progress: false -jobs: - release: - name: Deploy updates - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v6 - with: - ref: ${{ github.head_ref || github.ref_name }} - token: ${{ secrets.GH_PAT || github.token }} - - name: Update code - uses: upptime/updates@master - env: - GH_PAT: ${{ secrets.GH_PAT || github.token }} diff --git a/.github/workflows/uptime.yml b/.github/workflows/uptime.yml index c348665d2..5d9bd01f1 100644 --- a/.github/workflows/uptime.yml +++ b/.github/workflows/uptime.yml @@ -1,44 +1,38 @@ -# -# =============================== -# Do not edit this file directly! -# =============================== -# -# Your changes will be overwritten when the Upptime template updates (by default, weekly) -# Instead, change .upptimerc.yml configuration and the workflows will be generated accordingly. -# -# 🔼 Upptime @v1.43.13 -# GitHub-powered open-source uptime monitor and status page by Anand Chowdhary - -# * Source: https://github.com/upptime/upptime -# * Docs and more: https://upptime.js.org -# * More by Anand Chowdhary: https://anandchowdhary.com - - +# Hardened from Upptime v1.43.13. Review upgrades through UPSTREAM.md; +# never replace full commit SHAs with moving tags or branches. name: Uptime CI + on: schedule: - - cron: "*/5 * * * *" - repository_dispatch: - types: [uptime] + - cron: "3-58/5 * * * *" workflow_dispatch: + +permissions: + contents: read + concurrency: - group: ${{ github.repository }}-${{ github.head_ref || github.ref_name }}-upptime + group: ${{ github.repository }}-upptime-main-writer cancel-in-progress: false + jobs: release: - name: Check status + permissions: + contents: write + issues: write + name: Check public endpoints + if: github.ref == 'refs/heads/main' && vars.STATUS_AUTOMATION_ENABLED == 'true' runs-on: ubuntu-latest + timeout-minutes: 10 steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 with: - ref: ${{ github.head_ref || github.ref_name }} - token: ${{ secrets.GH_PAT || github.token }} + ref: main + token: ${{ github.token }} - name: Check endpoint status - uses: upptime/uptime-monitor@v1.43.13 + uses: upptime/uptime-monitor@4fec88256b5917a2ed07a088df6e205869b424d6 # v1.43.13 with: - command: "update" + command: update env: - GH_PAT: ${{ secrets.GH_PAT || github.token }} - # Configure the secret allowlist in .upptimerc.yml; do not edit this workflow directly. - SECRETS_CONTEXT: '{"DYNAMIC_STRING_LENGTH":${{ toJson(secrets.DYNAMIC_STRING_LENGTH) }},"GLOBALPING_TOKEN":${{ toJson(secrets.GLOBALPING_TOKEN) }},"NOTIFICATIONS_DOWN_MESSAGE":${{ toJson(secrets.NOTIFICATIONS_DOWN_MESSAGE) }},"NOTIFICATIONS_UP_MESSAGE":${{ toJson(secrets.NOTIFICATIONS_UP_MESSAGE) }},"NOTIFICATION_CUSTOM_WEBHOOK":${{ toJson(secrets.NOTIFICATION_CUSTOM_WEBHOOK) }},"NOTIFICATION_CUSTOM_WEBHOOK_URL":${{ toJson(secrets.NOTIFICATION_CUSTOM_WEBHOOK_URL) }},"NOTIFICATION_DISCORD_WEBHOOK_URL":${{ toJson(secrets.NOTIFICATION_DISCORD_WEBHOOK_URL) }},"NOTIFICATION_EMAIL":${{ toJson(secrets.NOTIFICATION_EMAIL) }},"NOTIFICATION_EMAIL_FROM":${{ toJson(secrets.NOTIFICATION_EMAIL_FROM) }},"NOTIFICATION_EMAIL_MAILGUN":${{ toJson(secrets.NOTIFICATION_EMAIL_MAILGUN) }},"NOTIFICATION_EMAIL_MAILGUN_API_KEY":${{ toJson(secrets.NOTIFICATION_EMAIL_MAILGUN_API_KEY) }},"NOTIFICATION_EMAIL_MAILGUN_DOMAIN_NAME":${{ toJson(secrets.NOTIFICATION_EMAIL_MAILGUN_DOMAIN_NAME) }},"NOTIFICATION_EMAIL_SENDGRID":${{ toJson(secrets.NOTIFICATION_EMAIL_SENDGRID) }},"NOTIFICATION_EMAIL_SENDGRID_API_KEY":${{ toJson(secrets.NOTIFICATION_EMAIL_SENDGRID_API_KEY) }},"NOTIFICATION_EMAIL_SES":${{ toJson(secrets.NOTIFICATION_EMAIL_SES) }},"NOTIFICATION_EMAIL_SES_ACCESS_KEY_ID":${{ toJson(secrets.NOTIFICATION_EMAIL_SES_ACCESS_KEY_ID) }},"NOTIFICATION_EMAIL_SES_REGION":${{ toJson(secrets.NOTIFICATION_EMAIL_SES_REGION) }},"NOTIFICATION_EMAIL_SES_SECRET_ACCESS_KEY":${{ toJson(secrets.NOTIFICATION_EMAIL_SES_SECRET_ACCESS_KEY) }},"NOTIFICATION_EMAIL_SES_SESSION_TOKEN":${{ toJson(secrets.NOTIFICATION_EMAIL_SES_SESSION_TOKEN) }},"NOTIFICATION_EMAIL_SMTP":${{ toJson(secrets.NOTIFICATION_EMAIL_SMTP) }},"NOTIFICATION_EMAIL_SMTP_HOST":${{ toJson(secrets.NOTIFICATION_EMAIL_SMTP_HOST) }},"NOTIFICATION_EMAIL_SMTP_PASSWORD":${{ toJson(secrets.NOTIFICATION_EMAIL_SMTP_PASSWORD) }},"NOTIFICATION_EMAIL_SMTP_PORT":${{ toJson(secrets.NOTIFICATION_EMAIL_SMTP_PORT) }},"NOTIFICATION_EMAIL_SMTP_USERNAME":${{ toJson(secrets.NOTIFICATION_EMAIL_SMTP_USERNAME) }},"NOTIFICATION_EMAIL_SPARKPOST":${{ toJson(secrets.NOTIFICATION_EMAIL_SPARKPOST) }},"NOTIFICATION_EMAIL_SPARKPOST_API_KEY":${{ toJson(secrets.NOTIFICATION_EMAIL_SPARKPOST_API_KEY) }},"NOTIFICATION_EMAIL_STRATEGY":${{ toJson(secrets.NOTIFICATION_EMAIL_STRATEGY) }},"NOTIFICATION_EMAIL_TO":${{ toJson(secrets.NOTIFICATION_EMAIL_TO) }},"NOTIFICATION_GOOGLE_CHAT_WEBHOOK_URL":${{ toJson(secrets.NOTIFICATION_GOOGLE_CHAT_WEBHOOK_URL) }},"NOTIFICATION_GOTIFY":${{ toJson(secrets.NOTIFICATION_GOTIFY) }},"NOTIFICATION_GOTIFY_PRIORITY":${{ toJson(secrets.NOTIFICATION_GOTIFY_PRIORITY) }},"NOTIFICATION_GOTIFY_TITLE":${{ toJson(secrets.NOTIFICATION_GOTIFY_TITLE) }},"NOTIFICATION_GOTIFY_TOKEN":${{ toJson(secrets.NOTIFICATION_GOTIFY_TOKEN) }},"NOTIFICATION_GOTIFY_URL":${{ toJson(secrets.NOTIFICATION_GOTIFY_URL) }},"NOTIFICATION_LARK":${{ toJson(secrets.NOTIFICATION_LARK) }},"NOTIFICATION_LARK_BOT_WEBHOOK":${{ toJson(secrets.NOTIFICATION_LARK_BOT_WEBHOOK) }},"NOTIFICATION_MASTODON":${{ toJson(secrets.NOTIFICATION_MASTODON) }},"NOTIFICATION_MASTODON_API_KEY":${{ toJson(secrets.NOTIFICATION_MASTODON_API_KEY) }},"NOTIFICATION_MASTODON_INSTANCE_URL":${{ toJson(secrets.NOTIFICATION_MASTODON_INSTANCE_URL) }},"NOTIFICATION_MASTODON_TOOT_VISIBILITY":${{ toJson(secrets.NOTIFICATION_MASTODON_TOOT_VISIBILITY) }},"NOTIFICATION_MISSKEY":${{ toJson(secrets.NOTIFICATION_MISSKEY) }},"NOTIFICATION_MISSKEY_API_KEY":${{ toJson(secrets.NOTIFICATION_MISSKEY_API_KEY) }},"NOTIFICATION_MISSKEY_CHAT":${{ toJson(secrets.NOTIFICATION_MISSKEY_CHAT) }},"NOTIFICATION_MISSKEY_CHAT_USER_ID":${{ toJson(secrets.NOTIFICATION_MISSKEY_CHAT_USER_ID) }},"NOTIFICATION_MISSKEY_INSTANCE_URL":${{ toJson(secrets.NOTIFICATION_MISSKEY_INSTANCE_URL) }},"NOTIFICATION_MISSKEY_NOTE":${{ toJson(secrets.NOTIFICATION_MISSKEY_NOTE) }},"NOTIFICATION_MISSKEY_NOTE_VISIBILITY":${{ toJson(secrets.NOTIFICATION_MISSKEY_NOTE_VISIBILITY) }},"NOTIFICATION_MISSKEY_NOTE_VISIBLE_USER_IDS":${{ toJson(secrets.NOTIFICATION_MISSKEY_NOTE_VISIBLE_USER_IDS) }},"NOTIFICATION_SLACK":${{ toJson(secrets.NOTIFICATION_SLACK) }},"NOTIFICATION_SLACK_STRATEGY":${{ toJson(secrets.NOTIFICATION_SLACK_STRATEGY) }},"NOTIFICATION_SLACK_WEBHOOK_URL":${{ toJson(secrets.NOTIFICATION_SLACK_WEBHOOK_URL) }},"NOTIFICATION_SMS_46ELKS":${{ toJson(secrets.NOTIFICATION_SMS_46ELKS) }},"NOTIFICATION_SMS_46ELKS_API_PASSWORD":${{ toJson(secrets.NOTIFICATION_SMS_46ELKS_API_PASSWORD) }},"NOTIFICATION_SMS_46ELKS_API_USERNAME":${{ toJson(secrets.NOTIFICATION_SMS_46ELKS_API_USERNAME) }},"NOTIFICATION_SMS_CALLR":${{ toJson(secrets.NOTIFICATION_SMS_CALLR) }},"NOTIFICATION_SMS_CALLR_LOGIN":${{ toJson(secrets.NOTIFICATION_SMS_CALLR_LOGIN) }},"NOTIFICATION_SMS_CALLR_PASSWORD":${{ toJson(secrets.NOTIFICATION_SMS_CALLR_PASSWORD) }},"NOTIFICATION_SMS_CLICKATELL":${{ toJson(secrets.NOTIFICATION_SMS_CLICKATELL) }},"NOTIFICATION_SMS_CLICKATELL_API_KEY":${{ toJson(secrets.NOTIFICATION_SMS_CLICKATELL_API_KEY) }},"NOTIFICATION_SMS_FROM":${{ toJson(secrets.NOTIFICATION_SMS_FROM) }},"NOTIFICATION_SMS_INFOBIP":${{ toJson(secrets.NOTIFICATION_SMS_INFOBIP) }},"NOTIFICATION_SMS_INFOBIP_PASSWORD":${{ toJson(secrets.NOTIFICATION_SMS_INFOBIP_PASSWORD) }},"NOTIFICATION_SMS_INFOBIP_USERNAME":${{ toJson(secrets.NOTIFICATION_SMS_INFOBIP_USERNAME) }},"NOTIFICATION_SMS_NEXMO":${{ toJson(secrets.NOTIFICATION_SMS_NEXMO) }},"NOTIFICATION_SMS_NEXMO_API_KEY":${{ toJson(secrets.NOTIFICATION_SMS_NEXMO_API_KEY) }},"NOTIFICATION_SMS_NEXMO_API_SECRET":${{ toJson(secrets.NOTIFICATION_SMS_NEXMO_API_SECRET) }},"NOTIFICATION_SMS_OVH":${{ toJson(secrets.NOTIFICATION_SMS_OVH) }},"NOTIFICATION_SMS_OVH_ACCOUNT":${{ toJson(secrets.NOTIFICATION_SMS_OVH_ACCOUNT) }},"NOTIFICATION_SMS_OVH_APP_KEY":${{ toJson(secrets.NOTIFICATION_SMS_OVH_APP_KEY) }},"NOTIFICATION_SMS_OVH_APP_SECRET":${{ toJson(secrets.NOTIFICATION_SMS_OVH_APP_SECRET) }},"NOTIFICATION_SMS_OVH_CONSUMER_KEY":${{ toJson(secrets.NOTIFICATION_SMS_OVH_CONSUMER_KEY) }},"NOTIFICATION_SMS_OVH_HOST":${{ toJson(secrets.NOTIFICATION_SMS_OVH_HOST) }},"NOTIFICATION_SMS_PLIVO":${{ toJson(secrets.NOTIFICATION_SMS_PLIVO) }},"NOTIFICATION_SMS_PLIVO_AUTH_ID":${{ toJson(secrets.NOTIFICATION_SMS_PLIVO_AUTH_ID) }},"NOTIFICATION_SMS_PLIVO_AUTH_TOKEN":${{ toJson(secrets.NOTIFICATION_SMS_PLIVO_AUTH_TOKEN) }},"NOTIFICATION_SMS_STRATEGY":${{ toJson(secrets.NOTIFICATION_SMS_STRATEGY) }},"NOTIFICATION_SMS_TO":${{ toJson(secrets.NOTIFICATION_SMS_TO) }},"NOTIFICATION_SMS_TWILIO":${{ toJson(secrets.NOTIFICATION_SMS_TWILIO) }},"NOTIFICATION_SMS_TWILIO_ACCOUNT_SID":${{ toJson(secrets.NOTIFICATION_SMS_TWILIO_ACCOUNT_SID) }},"NOTIFICATION_SMS_TWILIO_AUTH_TOKEN":${{ toJson(secrets.NOTIFICATION_SMS_TWILIO_AUTH_TOKEN) }},"NOTIFICATION_TEAMS":${{ toJson(secrets.NOTIFICATION_TEAMS) }},"NOTIFICATION_TEAMS_WEBHOOK_URL":${{ toJson(secrets.NOTIFICATION_TEAMS_WEBHOOK_URL) }},"NOTIFICATION_TELEGRAM":${{ toJson(secrets.NOTIFICATION_TELEGRAM) }},"NOTIFICATION_TELEGRAM_BOT_KEY":${{ toJson(secrets.NOTIFICATION_TELEGRAM_BOT_KEY) }},"NOTIFICATION_TELEGRAM_CHAT_ID":${{ toJson(secrets.NOTIFICATION_TELEGRAM_CHAT_ID) }},"NOTIFICATION_ZULIP_API_EMAIL":${{ toJson(secrets.NOTIFICATION_ZULIP_API_EMAIL) }},"NOTIFICATION_ZULIP_API_KEY":${{ toJson(secrets.NOTIFICATION_ZULIP_API_KEY) }},"NOTIFICATION_ZULIP_MESSAGE_URL":${{ toJson(secrets.NOTIFICATION_ZULIP_MESSAGE_URL) }},"RANDOM_MAX":${{ toJson(secrets.RANDOM_MAX) }},"RANDOM_MIN":${{ toJson(secrets.RANDOM_MIN) }},"SECRET_SITE":${{ toJson(secrets.SECRET_SITE) }},"USER_AGENT":${{ toJson(secrets.USER_AGENT) }}}' + GITHUB_TOKEN: ${{ github.token }} + SECRETS_CONTEXT: "{}" diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml new file mode 100644 index 000000000..32afe7222 --- /dev/null +++ b/.github/workflows/validate.yml @@ -0,0 +1,72 @@ +# Hardened from Upptime v1.43.13. Review upgrades through UPSTREAM.md; +# status-page source and all Actions are pinned to immutable revisions. +name: Validate + +on: + pull_request: + push: + branches: + - main + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: ${{ github.repository }}-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + config: + name: Validate status configuration + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - name: Checkout + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 + with: + persist-credentials: false + - name: Validate + run: ruby scripts/validate.rb + + static-site: + name: Build static site + if: github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' + runs-on: ubuntu-latest + timeout-minutes: 20 + steps: + - name: Checkout status repository + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 + with: + persist-credentials: false + - name: Checkout pinned Upptime status page + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 + with: + repository: upptime/status-page + ref: 54c2ff5a3d998d525ee4c7e68dc7ce7414d89c33 # v1.17.0 + path: site + persist-credentials: false + - name: Apply Mighty main-branch compatibility patch + run: git -C site apply --index --unidiff-zero ../patches/upptime-status-page-main.patch + - name: Stage Mighty static assets + run: cp -R assets/. site/static/ + - name: Set up Node.js + uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6 + with: + node-version: "20" + cache: npm + cache-dependency-path: site/package-lock.json + - name: Build static site from locked dependencies + working-directory: site + env: + CYPRESS_INSTALL_BINARY: "0" + run: | + npm ci --no-audit --no-fund + npm run export + - name: Verify generated output + run: | + test -s site/__sapper__/export/index.html + test -s site/__sapper__/export/manifest.json + test -s site/__sapper__/export/_headers + test -f site/__sapper__/export/mighty-logo.png + test "$(wc -c < site/__sapper__/export/mighty-logo.png)" -gt 1000 diff --git a/.upptimerc.yml b/.upptimerc.yml index 23c3580a8..d431938b3 100644 --- a/.upptimerc.yml +++ b/.upptimerc.yml @@ -1,31 +1,78 @@ -# Change these first -owner: upptime # Your GitHub organization or username, where this repository lives -repo: upptime # The name of this repository +# Mighty public status configuration. +# Upptime configuration reference: https://upptime.js.org/docs/configuration +owner: TryMightyAI +repo: status +user-agent: TryMightyAI + +# Public checks use no credentials. Keep this explicit allowlist empty unless a +# separately reviewed change introduces a narrowly scoped secret. +secrets: [] + +delay: 1000 +skipDeleteIssues: true +skipDescriptionUpdate: true +skipTopicsUpdate: true +skipHomepageUpdate: true sites: - - name: Google - url: https://www.google.com - - name: Wikipedia - url: https://en.wikipedia.org - - name: Hacker News - url: https://news.ycombinator.com - - name: Secret Site - url: $SECRET_SITE + - name: Website + slug: website + url: https://trymighty.ai/ + method: GET + expectedStatusCodes: + - 200 + maxResponseTime: 5000 + - name: API + slug: api + url: https://api.trymighty.ai/health + method: GET + expectedStatusCodes: + - 200 + maxResponseTime: 5000 + __dangerous__body_down_if_text_missing: '"status":"healthy"' + - name: Scan Gateway + slug: scan-gateway + url: https://gateway.trymighty.ai/health + method: GET + expectedStatusCodes: + - 200 + maxResponseTime: 5000 + __dangerous__body_down_if_text_missing: '"status":"ok"' + +assignees: + - masterfung status-website: - # Add your custom domain name, or remove the `cname` line if you don't have a domain - # Uncomment the `baseUrl` line if you don't have a custom domain and add your repo name there - cname: demo.upptime.js.org - # baseUrl: /your-repo-name - logoUrl: https://raw.githubusercontent.com/upptime/upptime.js.org/master/static/img/icon.svg - name: Upptime - introTitle: "**Upptime** is the open-source uptime monitor and status page, powered entirely by GitHub." - introMessage: This is a sample status page which uses **real-time** data from our [GitHub repository](https://github.com/upptime/upptime). No server required — just GitHub Actions, Issues, and Pages. [**Get your own for free**](https://github.com/upptime/upptime) + cname: status.trymighty.ai + logoUrl: /mighty-logo.png + name: Mighty Status + theme: night + introTitle: "**Mighty service status**" + introMessage: >- + Current availability and incident communications for Mighty production + services. Measurements are external observations and are not a contractual + service-level agreement. navbar: - title: Status href: / - - title: GitHub - href: https://github.com/$OWNER/$REPO + - title: Mighty + href: https://trymighty.ai/ + - title: Documentation + href: https://trymighty.ai/docs + - title: Security + href: https://trymighty.ai/security + +workflowSchedule: + uptime: "3-58/5 * * * *" + responseTime: "43 23 * * *" + staticSite: "27 1 * * *" + +commitMessages: + commitAuthorName: Mighty Status Bot + commitAuthorEmail: 73812536+upptime-bot@users.noreply.github.com + readmeContent: "chore(status): update summary [skip ci] [upptime]" + summaryJson: "chore(status): update status summary [skip ci] [upptime]" + statusChange: "$EMOJI $SITE_NAME is $STATUS ($RESPONSE_CODE in $RESPONSE_TIME ms) [skip ci] [upptime]" -# Upptime also supports notifications, assigning issues, and more -# See https://upptime.js.org/docs/configuration +i18n: + footer: This page is [open source]($REPO) and powered by [Upptime](https://upptime.js.org). diff --git a/README.md b/README.md index 0dd666bec..f304dc9a8 100644 --- a/README.md +++ b/README.md @@ -1,117 +1,34 @@ -# [![Upptime](https://raw.githubusercontent.com/upptime/upptime.js.org/master/static/img/logo.svg)](https://upptime.js.org) +# Mighty Service Status - +This repository is the public source, incident history, and uptime record for +[Mighty Status](https://status.trymighty.ai). It is powered by the MIT-licensed +[Upptime](https://github.com/upptime/upptime) project. -**Upptime** (https://upptime.js.org) is the open-source uptime monitor and status page, powered entirely by GitHub Actions, Issues, and Pages, made with 💚 by [Anand Chowdhary](https://anandchowdhary.com). +The public checks are useful observations, not a contractual service-level +agreement (SLA). Mighty keeps its internal monitoring and incident records as +the authoritative audit evidence. -> I find Upptime an incredible clever usage of \[GitHub Actions]. You essentially get a free configurable uptime monitor for whatever you want. – [CSS Tricks](https://css-tricks.com/upptime/) +[![Validate](https://github.com/TryMightyAI/status/actions/workflows/validate.yml/badge.svg)](https://github.com/TryMightyAI/status/actions/workflows/validate.yml) +[![Uptime CI](https://github.com/TryMightyAI/status/actions/workflows/uptime.yml/badge.svg)](https://github.com/TryMightyAI/status/actions/workflows/uptime.yml) +[![Static Site CI](https://github.com/TryMightyAI/status/actions/workflows/site.yml/badge.svg)](https://github.com/TryMightyAI/status/actions/workflows/site.yml) -
- Upptime is used by 3,000+ people and teams to ensure they know when their endpoints go down. +## [Live status](https://status.trymighty.ai) -I built Upptime because, like many developers, I needed an uptime monitor and status page for my startup Pabio that was affordable, flexible, and completely under my control. At the time, existing services felt expensive, rigid, or closed-source. GitHub Actions had just launched, and I thought: hmm... what if I turned Actions into a self-hosted uptime monitor? +Availability measurements begin when the launch checklist enables production +automation. No historical sample data is carried over from the upstream template. -Upptime runs scheduled checks using GitHub Actions (as often as every 5 minutes) to ping your endpoints and verify they're online. Response time data is recorded and committed to git, enabling long-term trend charts and historical insights. When downtime is detected, GitHub Issues are automatically opened and closed. A status page built with Svelte is hosted via GitHub Pages and shows uptime, response times, and incident history - so you get the full-stack uptime monitor and status page. +## Operations -I built it to be completely free if you're already using GitHub since there's no external server or subscription needed. All configuration lives in a single file, and your data is gone if you delete the repo. Plus, you get a git-native audit trail for all changes and events. +- [Hosting and launch checklist](docs/HOSTING.md) +- [Incident and maintenance runbook](docs/OPERATIONS.md) +- [Open-source platform decision](docs/DECISION.md) +- [Pinned upstream and upgrade process](UPSTREAM.md) -Since launching, Upptime has grown to over 16,000 stars and is actively used by developers and teams to monitor their services. In fact, Upptime is used by [over 3,000+ people and teams](https://github.com/topics/upptime), including Ubuntu-maker Canonical and my preferred developer time tracker Wakatime. +For a live incident, use the public timeline linked from the status page. If the +custom domain is unavailable, use this repository's [Issues](https://github.com/TryMightyAI/status/issues) +as the alternate public channel. -
+## License - - -[![Uptime CI](https://github.com/upptime/upptime/workflows/Uptime%20CI/badge.svg)](https://github.com/upptime/upptime/actions/workflows/uptime.yml) -[![Response Time CI](https://github.com/upptime/upptime/workflows/Response%20Time%20CI/badge.svg)](https://github.com/upptime/upptime/actions/workflows/response-time.yml?query=workflow%3A%22Response+Time+CI%22) -[![Graphs CI](https://github.com/upptime/upptime/workflows/Graphs%20CI/badge.svg)](https://github.com/upptime/upptime/actions/workflows/graphs.yml?query=workflow%3A%22Graphs+CI%22) -[![Static Site CI](https://github.com/upptime/upptime/workflows/Static%20Site%20CI/badge.svg)](https://github.com/upptime/upptime/actions/workflows/site.yml?query=workflow%3A%22Static+Site+CI%22) -[![Summary CI](https://github.com/upptime/upptime/workflows/Summary%20CI/badge.svg)](https://github.com/upptime/upptime/actions/workflows/summary.yml?query=workflow%3A%22Summary+CI%22) - -## [📈 Live Status](https://demo.upptime.js.org): **🟩 All systems operational** - - - - - -| URL | Status | History | Response Time | Uptime | -| --- | ------ | ------- | ------------- | ------ | -| [Google](https://www.google.com) | 🟩 Up | [google.yml](https://github.com/upptime/upptime/commits/HEAD/history/google.yml) |
Response time graph 79ms
Response time 123
24-hour response time 84
7-day response time 79
30-day response time 81
1-year response time 128
|
100.00%All-time uptime 99.99%
24-hour uptime 100.00%
7-day uptime 100.00%
30-day uptime 100.00%
1-year uptime 99.96%
-| [Wikipedia](https://en.wikipedia.org) | 🟩 Up | [wikipedia.yml](https://github.com/upptime/upptime/commits/HEAD/history/wikipedia.yml) |
Response time graph 208ms
Response time 195
24-hour response time 221
7-day response time 208
30-day response time 163
1-year response time 204
|
100.00%All-time uptime 100.00%
24-hour uptime 100.00%
7-day uptime 100.00%
30-day uptime 100.00%
1-year uptime 100.00%
-| [Hacker News](https://news.ycombinator.com) | 🟩 Up | [hacker-news.yml](https://github.com/upptime/upptime/commits/HEAD/history/hacker-news.yml) |
Response time graph 243ms
Response time 301
24-hour response time 262
7-day response time 243
30-day response time 257
1-year response time 283
|
100.00%All-time uptime 99.11%
24-hour uptime 100.00%
7-day uptime 100.00%
30-day uptime 100.00%
1-year uptime 100.00%
-| Secret Site | 🟩 Up | [secret-site.yml](https://github.com/upptime/upptime/commits/HEAD/history/secret-site.yml) |
Response time graph 41ms
Response time 41
24-hour response time 24
7-day response time 41
30-day response time 40
1-year response time 40
|
100.00%All-time uptime 100.00%
24-hour uptime 100.00%
7-day uptime 100.00%
30-day uptime 100.00%
1-year uptime 100.00%
- - - - - -## ⭐ How it works - -- GitHub Actions is used as an uptime monitor - - Every 5 minutes, a workflow visits your website to make sure it's up - - Response time is recorded every 6 hours and committed to git - - Graphs of response time are generated every day -- GitHub Issues is used for incident reports - - An issue is opened if an endpoint is down - - People from your team are assigned to the issue - - Incidents reports are posted as issue comments - - Issues are locked so non-members cannot comment on them - - Issues are closed automatically when your site comes back up - - Slack notifications are sent on updates -- GitHub Pages is used for the status website - - A simple, beautiful, and accessible PWA is generated - - Built with Svelte and Sapper - - Fetches data from this repository using the GitHub API - -_Upptime is not affiliated to or endorsed by GitHub._ - -[![Screenshot of status website](https://raw.githubusercontent.com/upptime/upptime.js.org/master/static/img/screenshot-status.png)](https://upptime.js.org) - -## 👩‍💻 [Documentation](https://upptime.js.org) - -1. [How it works](https://upptime.js.org/docs) -1. [Getting started](https://upptime.js.org/docs/get-started) -1. [Configuration](https://upptime.js.org/docs/configuration) -1. [Triggers](https://upptime.js.org/docs/triggers) -1. [Notifications](https://upptime.js.org/docs/notifications) -1. [Badges](https://upptime.js.org/docs/badges) -1. [Packages](https://upptime.js.org/docs/packages) -1. [Contributing](https://upptime.js.org/docs/contributing) -1. [Frequently Asked Questions](https://upptime.js.org/docs/faq) - -### Concepts - -#### Issues as incidents - -When the GitHub Actions workflow detects that one of your URLs is down, it automatically opens a GitHub issue ([example issue #67](https://github.com/upptime/upptime/issues/67)). You can add incident reports to this issue by adding comments. When your site comes back up, the issue will be closed automatically as well. - - - - - - -
- Screenshot of GitHub issue - - Screenshot of incident page -
- -#### Commits for response time - -Four times per day, another workflow runs and records the response time of your websites. This data is committed to GitHub, so it's available in the commit history of each file ([example commit history](https://github.com/koj-co/upptime/commits/master/history/wikipedia.yml)). Then, the GitHub API is used to graph the response time history of each endpoint and to track when a site went down. - - - - - - -
- Screenshot of GitHub commits - - Screenshot of live status -
- - -## 📄 License - -- Code: [MIT](./LICENSE) © [Anand Chowdhary](https://anandchowdhary.com) -- Data in the `./history` directory: [Open Database License](https://opendatacommons.org/licenses/odbl/1-0/) +The Upptime-derived code and configuration are available under the [MIT License](LICENSE). +Mighty names and logos remain the property of Mighty. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000..7c7c8bea9 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,12 @@ +# Security policy + +Please report a vulnerability in this status-page repository through +[GitHub private vulnerability reporting](https://github.com/TryMightyAI/status/security/advisories/new). +Do not open a public Issue with credentials, customer data, exploit details, or +an unpatched vulnerability. + +For an active Mighty product incident, follow the contact path on +[status.trymighty.ai](https://status.trymighty.ai) or email `hi@trymighty.ai`. + +This public repository intentionally contains only public health-check URLs. +No product, monitoring, notification, or Cloudflare credential belongs in it. diff --git a/UPSTREAM.md b/UPSTREAM.md new file mode 100644 index 000000000..005276179 --- /dev/null +++ b/UPSTREAM.md @@ -0,0 +1,44 @@ +# Upstream and supply-chain policy + +This repository was created from the public [Upptime template](https://github.com/upptime/upptime) +on 2026-08-11. + +- Template commit: [`8a77a68e276fd9ecae0aaa64bfaf4b987e5ca7bb`](https://github.com/upptime/upptime/commit/8a77a68e276fd9ecae0aaa64bfaf4b987e5ca7bb) +- Template tree: `227dccfa97ac3fc6b42d85ebd2cb0dc32ae1aab8` (verified identical to this repository's initial commit) +- Runtime release: [`upptime/uptime-monitor@v1.43.13`](https://github.com/upptime/uptime-monitor/releases/tag/v1.43.13) +- Runtime commit: [`4fec88256b5917a2ed07a088df6e205869b424d6`](https://github.com/upptime/uptime-monitor/commit/4fec88256b5917a2ed07a088df6e205869b424d6) +- Static-site release: [`upptime/status-page@v1.17.0`](https://github.com/upptime/status-page/releases/tag/v1.17.0) +- Static-site commit: [`54c2ff5a3d998d525ee4c7e68dc7ce7414d89c33`](https://github.com/upptime/status-page/commit/54c2ff5a3d998d525ee4c7e68dc7ce7414d89c33) +- License: [MIT](LICENSE) + +## Why automatic template updates are disabled + +The upstream template normally runs code from moving tags/branches and rewrites +its own workflows. That is convenient, but it bypasses review and weakens the +status page's integrity. Mighty instead: + +1. pins every GitHub Action and the static-site source to full commit SHAs; +2. builds the site with the upstream release's committed `package-lock.json`; +3. patches the old static client to read Mighty’s `main` branch and removes its + optional pre-rendered PNG graph dependency (history charts still render from + Git commits in the browser); +4. passes no monitor credentials (`secrets: []`) and stores no long-lived + automation token; +5. uses GitHub’s short-lived job token with only Contents/Issues write for the + monitor and Contents write for static publication; +6. reviews upstream changes in a pull request; and +7. runs `ruby scripts/validate.rb` plus a no-publish static build before merging. + +## Upgrade procedure + +At least monthly, and promptly after an upstream security advisory: + +1. compare the current template, monitor runtime, and status-page release with the SHAs above; +2. review source changes, release notes, dependencies, and open advisories; +3. regenerate only the required Upptime files on a branch; +4. restore full-SHA pins and least-privilege workflow settings; +5. run the validator and a test deployment; +6. merge through normal review; and +7. update the SHAs and date in this file. + +Do **not** run Upptime's `update-template` command directly on `main`. diff --git a/api/google/response-time-day.json b/api/google/response-time-day.json deleted file mode 100644 index 228d73551..000000000 --- a/api/google/response-time-day.json +++ /dev/null @@ -1 +0,0 @@ -{"schemaVersion":1,"label":"response time 24h","message":"84 ms","color":"brightgreen"} diff --git a/api/google/response-time-month.json b/api/google/response-time-month.json deleted file mode 100644 index 4d4b755fa..000000000 --- a/api/google/response-time-month.json +++ /dev/null @@ -1 +0,0 @@ -{"schemaVersion":1,"label":"response time 30d","message":"81 ms","color":"brightgreen"} diff --git a/api/google/response-time-week.json b/api/google/response-time-week.json deleted file mode 100644 index 5a1e20f5b..000000000 --- a/api/google/response-time-week.json +++ /dev/null @@ -1 +0,0 @@ -{"schemaVersion":1,"label":"response time 7d","message":"79 ms","color":"brightgreen"} diff --git a/api/google/response-time-year.json b/api/google/response-time-year.json deleted file mode 100644 index dfd7abf42..000000000 --- a/api/google/response-time-year.json +++ /dev/null @@ -1 +0,0 @@ -{"schemaVersion":1,"label":"response time 1y","message":"128 ms","color":"brightgreen"} diff --git a/api/google/response-time.json b/api/google/response-time.json deleted file mode 100644 index baed64026..000000000 --- a/api/google/response-time.json +++ /dev/null @@ -1 +0,0 @@ -{"schemaVersion":1,"label":"response time","message":"123 ms","color":"brightgreen"} diff --git a/api/google/uptime-day.json b/api/google/uptime-day.json deleted file mode 100644 index 226baeab5..000000000 --- a/api/google/uptime-day.json +++ /dev/null @@ -1 +0,0 @@ -{"schemaVersion":1,"label":"uptime 24h","message":"100%","color":"brightgreen"} diff --git a/api/google/uptime-month.json b/api/google/uptime-month.json deleted file mode 100644 index 059c01da0..000000000 --- a/api/google/uptime-month.json +++ /dev/null @@ -1 +0,0 @@ -{"schemaVersion":1,"label":"uptime 30d","message":"100%","color":"brightgreen"} diff --git a/api/google/uptime-week.json b/api/google/uptime-week.json deleted file mode 100644 index fccd794d2..000000000 --- a/api/google/uptime-week.json +++ /dev/null @@ -1 +0,0 @@ -{"schemaVersion":1,"label":"uptime 7d","message":"100%","color":"brightgreen"} diff --git a/api/google/uptime-year.json b/api/google/uptime-year.json deleted file mode 100644 index ecb61ef55..000000000 --- a/api/google/uptime-year.json +++ /dev/null @@ -1 +0,0 @@ -{"schemaVersion":1,"label":"uptime 1y","message":"99.96%","color":"brightgreen"} diff --git a/api/google/uptime.json b/api/google/uptime.json deleted file mode 100644 index c30fdd0aa..000000000 --- a/api/google/uptime.json +++ /dev/null @@ -1 +0,0 @@ -{"schemaVersion":1,"label":"uptime","message":"99.99%","color":"brightgreen"} diff --git a/api/hacker-news/response-time-day.json b/api/hacker-news/response-time-day.json deleted file mode 100644 index 6ed2bce0b..000000000 --- a/api/hacker-news/response-time-day.json +++ /dev/null @@ -1 +0,0 @@ -{"schemaVersion":1,"label":"response time 24h","message":"262 ms","color":"green"} diff --git a/api/hacker-news/response-time-month.json b/api/hacker-news/response-time-month.json deleted file mode 100644 index 26033d59b..000000000 --- a/api/hacker-news/response-time-month.json +++ /dev/null @@ -1 +0,0 @@ -{"schemaVersion":1,"label":"response time 30d","message":"257 ms","color":"green"} diff --git a/api/hacker-news/response-time-week.json b/api/hacker-news/response-time-week.json deleted file mode 100644 index 28bae06fd..000000000 --- a/api/hacker-news/response-time-week.json +++ /dev/null @@ -1 +0,0 @@ -{"schemaVersion":1,"label":"response time 7d","message":"243 ms","color":"green"} diff --git a/api/hacker-news/response-time-year.json b/api/hacker-news/response-time-year.json deleted file mode 100644 index 123565c68..000000000 --- a/api/hacker-news/response-time-year.json +++ /dev/null @@ -1 +0,0 @@ -{"schemaVersion":1,"label":"response time 1y","message":"283 ms","color":"green"} diff --git a/api/hacker-news/response-time.json b/api/hacker-news/response-time.json deleted file mode 100644 index 09128559f..000000000 --- a/api/hacker-news/response-time.json +++ /dev/null @@ -1 +0,0 @@ -{"schemaVersion":1,"label":"response time","message":"301 ms","color":"green"} diff --git a/api/hacker-news/uptime-day.json b/api/hacker-news/uptime-day.json deleted file mode 100644 index 226baeab5..000000000 --- a/api/hacker-news/uptime-day.json +++ /dev/null @@ -1 +0,0 @@ -{"schemaVersion":1,"label":"uptime 24h","message":"100%","color":"brightgreen"} diff --git a/api/hacker-news/uptime-month.json b/api/hacker-news/uptime-month.json deleted file mode 100644 index 059c01da0..000000000 --- a/api/hacker-news/uptime-month.json +++ /dev/null @@ -1 +0,0 @@ -{"schemaVersion":1,"label":"uptime 30d","message":"100%","color":"brightgreen"} diff --git a/api/hacker-news/uptime-week.json b/api/hacker-news/uptime-week.json deleted file mode 100644 index fccd794d2..000000000 --- a/api/hacker-news/uptime-week.json +++ /dev/null @@ -1 +0,0 @@ -{"schemaVersion":1,"label":"uptime 7d","message":"100%","color":"brightgreen"} diff --git a/api/hacker-news/uptime-year.json b/api/hacker-news/uptime-year.json deleted file mode 100644 index 8923b68ad..000000000 --- a/api/hacker-news/uptime-year.json +++ /dev/null @@ -1 +0,0 @@ -{"schemaVersion":1,"label":"uptime 1y","message":"100%","color":"brightgreen"} diff --git a/api/hacker-news/uptime.json b/api/hacker-news/uptime.json deleted file mode 100644 index 41fcc4bc7..000000000 --- a/api/hacker-news/uptime.json +++ /dev/null @@ -1 +0,0 @@ -{"schemaVersion":1,"label":"uptime","message":"99.11%","color":"brightgreen"} diff --git a/api/secret-site/response-time-day.json b/api/secret-site/response-time-day.json deleted file mode 100644 index 660e90229..000000000 --- a/api/secret-site/response-time-day.json +++ /dev/null @@ -1 +0,0 @@ -{"schemaVersion":1,"label":"response time 24h","message":"24 ms","color":"brightgreen"} diff --git a/api/secret-site/response-time-month.json b/api/secret-site/response-time-month.json deleted file mode 100644 index 5bb21c13f..000000000 --- a/api/secret-site/response-time-month.json +++ /dev/null @@ -1 +0,0 @@ -{"schemaVersion":1,"label":"response time 30d","message":"40 ms","color":"brightgreen"} diff --git a/api/secret-site/response-time-week.json b/api/secret-site/response-time-week.json deleted file mode 100644 index 90d25d964..000000000 --- a/api/secret-site/response-time-week.json +++ /dev/null @@ -1 +0,0 @@ -{"schemaVersion":1,"label":"response time 7d","message":"41 ms","color":"brightgreen"} diff --git a/api/secret-site/response-time-year.json b/api/secret-site/response-time-year.json deleted file mode 100644 index 45cd62d45..000000000 --- a/api/secret-site/response-time-year.json +++ /dev/null @@ -1 +0,0 @@ -{"schemaVersion":1,"label":"response time 1y","message":"40 ms","color":"brightgreen"} diff --git a/api/secret-site/response-time.json b/api/secret-site/response-time.json deleted file mode 100644 index 3ebedcdfb..000000000 --- a/api/secret-site/response-time.json +++ /dev/null @@ -1 +0,0 @@ -{"schemaVersion":1,"label":"response time","message":"41 ms","color":"brightgreen"} diff --git a/api/secret-site/uptime-day.json b/api/secret-site/uptime-day.json deleted file mode 100644 index 226baeab5..000000000 --- a/api/secret-site/uptime-day.json +++ /dev/null @@ -1 +0,0 @@ -{"schemaVersion":1,"label":"uptime 24h","message":"100%","color":"brightgreen"} diff --git a/api/secret-site/uptime-month.json b/api/secret-site/uptime-month.json deleted file mode 100644 index 059c01da0..000000000 --- a/api/secret-site/uptime-month.json +++ /dev/null @@ -1 +0,0 @@ -{"schemaVersion":1,"label":"uptime 30d","message":"100%","color":"brightgreen"} diff --git a/api/secret-site/uptime-week.json b/api/secret-site/uptime-week.json deleted file mode 100644 index fccd794d2..000000000 --- a/api/secret-site/uptime-week.json +++ /dev/null @@ -1 +0,0 @@ -{"schemaVersion":1,"label":"uptime 7d","message":"100%","color":"brightgreen"} diff --git a/api/secret-site/uptime-year.json b/api/secret-site/uptime-year.json deleted file mode 100644 index 8923b68ad..000000000 --- a/api/secret-site/uptime-year.json +++ /dev/null @@ -1 +0,0 @@ -{"schemaVersion":1,"label":"uptime 1y","message":"100%","color":"brightgreen"} diff --git a/api/secret-site/uptime.json b/api/secret-site/uptime.json deleted file mode 100644 index bd71d6f88..000000000 --- a/api/secret-site/uptime.json +++ /dev/null @@ -1 +0,0 @@ -{"schemaVersion":1,"label":"uptime","message":"100%","color":"brightgreen"} diff --git a/api/wikipedia/response-time-day.json b/api/wikipedia/response-time-day.json deleted file mode 100644 index 8178967ab..000000000 --- a/api/wikipedia/response-time-day.json +++ /dev/null @@ -1 +0,0 @@ -{"schemaVersion":1,"label":"response time 24h","message":"221 ms","color":"green"} diff --git a/api/wikipedia/response-time-month.json b/api/wikipedia/response-time-month.json deleted file mode 100644 index 8f6fbfbfa..000000000 --- a/api/wikipedia/response-time-month.json +++ /dev/null @@ -1 +0,0 @@ -{"schemaVersion":1,"label":"response time 30d","message":"163 ms","color":"brightgreen"} diff --git a/api/wikipedia/response-time-week.json b/api/wikipedia/response-time-week.json deleted file mode 100644 index 5ebfde3dc..000000000 --- a/api/wikipedia/response-time-week.json +++ /dev/null @@ -1 +0,0 @@ -{"schemaVersion":1,"label":"response time 7d","message":"208 ms","color":"green"} diff --git a/api/wikipedia/response-time-year.json b/api/wikipedia/response-time-year.json deleted file mode 100644 index 914b1eca6..000000000 --- a/api/wikipedia/response-time-year.json +++ /dev/null @@ -1 +0,0 @@ -{"schemaVersion":1,"label":"response time 1y","message":"204 ms","color":"green"} diff --git a/api/wikipedia/response-time.json b/api/wikipedia/response-time.json deleted file mode 100644 index 90250ece7..000000000 --- a/api/wikipedia/response-time.json +++ /dev/null @@ -1 +0,0 @@ -{"schemaVersion":1,"label":"response time","message":"195 ms","color":"brightgreen"} diff --git a/api/wikipedia/uptime-day.json b/api/wikipedia/uptime-day.json deleted file mode 100644 index 226baeab5..000000000 --- a/api/wikipedia/uptime-day.json +++ /dev/null @@ -1 +0,0 @@ -{"schemaVersion":1,"label":"uptime 24h","message":"100%","color":"brightgreen"} diff --git a/api/wikipedia/uptime-month.json b/api/wikipedia/uptime-month.json deleted file mode 100644 index 059c01da0..000000000 --- a/api/wikipedia/uptime-month.json +++ /dev/null @@ -1 +0,0 @@ -{"schemaVersion":1,"label":"uptime 30d","message":"100%","color":"brightgreen"} diff --git a/api/wikipedia/uptime-week.json b/api/wikipedia/uptime-week.json deleted file mode 100644 index fccd794d2..000000000 --- a/api/wikipedia/uptime-week.json +++ /dev/null @@ -1 +0,0 @@ -{"schemaVersion":1,"label":"uptime 7d","message":"100%","color":"brightgreen"} diff --git a/api/wikipedia/uptime-year.json b/api/wikipedia/uptime-year.json deleted file mode 100644 index 8923b68ad..000000000 --- a/api/wikipedia/uptime-year.json +++ /dev/null @@ -1 +0,0 @@ -{"schemaVersion":1,"label":"uptime 1y","message":"100%","color":"brightgreen"} diff --git a/api/wikipedia/uptime.json b/api/wikipedia/uptime.json deleted file mode 100644 index bd71d6f88..000000000 --- a/api/wikipedia/uptime.json +++ /dev/null @@ -1 +0,0 @@ -{"schemaVersion":1,"label":"uptime","message":"100%","color":"brightgreen"} diff --git a/assets/_headers b/assets/_headers new file mode 100644 index 000000000..cc2c628e9 --- /dev/null +++ b/assets/_headers @@ -0,0 +1,7 @@ +/* + Content-Security-Policy: default-src 'self'; connect-src 'self' https://api.github.com https://raw.githubusercontent.com; img-src 'self' data: https://icons.duckduckgo.com; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; font-src 'self'; object-src 'none'; base-uri 'self'; form-action 'none'; frame-ancestors 'none'; worker-src 'self' + X-Content-Type-Options: nosniff + X-Frame-Options: DENY + Referrer-Policy: strict-origin-when-cross-origin + Permissions-Policy: camera=(), geolocation=(), microphone=(), payment=(), usb=() + Strict-Transport-Security: max-age=31536000 diff --git a/assets/mighty-logo.png b/assets/mighty-logo.png new file mode 100644 index 000000000..2b5cbadbe Binary files /dev/null and b/assets/mighty-logo.png differ diff --git a/assets/upptime-icon.svg b/assets/upptime-icon.svg deleted file mode 100644 index f909d51a2..000000000 --- a/assets/upptime-icon.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/docs/DECISION.md b/docs/DECISION.md new file mode 100644 index 000000000..d2a1486a4 --- /dev/null +++ b/docs/DECISION.md @@ -0,0 +1,87 @@ +# Status page platform decision + +**Decision date:** 2026-08-11 +**Decision:** Upptime in a dedicated public repository, with the generated site +served from Cloudflare Pages at `status.trymighty.ai`. + +## Requirements + +The selected system must be open source, inexpensive to operate, outside the +Mighty production stack, usable at a custom domain, and able to show current +checks, incident updates, scheduled work, and past events. Its records should +support a SOC 2 Type 2 examination without being represented as compliance by +themselves. + +## Shortlist + +| Project | Strengths | Important limits | Result | +| --- | --- | --- | --- | +| [Upptime](https://github.com/upptime/upptime) | MIT; static site; free public-repo checks; incidents and operator comments use GitHub Issues; scheduled maintenance; Git history; custom domain | GitHub cron can be delayed; five-minute minimum; requires write-capable Actions job permissions; public GitHub/API dependency | **Selected: best match for zero-cost static hosting plus durable commentary** | +| [UptimeFlare](https://github.com/lyc8503/UptimeFlare) | Apache-2.0; Cloudflare Workers/Pages; one-minute and geographic checks; maintenance and automatic incident history | No comparable threaded human incident-update workflow; 90-day monitoring history; fixed 2026 credential-exposure advisory requires careful upgrades | Best free monitoring architecture, but not the best incident-communications record | +| [cState](https://github.com/cstate/cstate) | MIT; very small Hugo static site; excellent Git-authored incident posts | Explicitly has no automatic monitoring out of the box | Good manual communications site, incomplete alone | +| [Gatus](https://github.com/TwiN/gatus) | Apache-2.0; small Go service; broad checks; Markdown announcements and archived history | Always-on service and storage; no threaded incident workflow or subscriber system | Strong small self-hosted alternative, not static | +| [Kener](https://github.com/rajnandan1/kener) | MIT; full incident timelines, maintenance, roles, API, and notifications | Requires an always-on Node/Redis/database service and its own backup/security operations | Best lightweight GUI if static hosting stops being a requirement | +| [Uptime Kuma](https://github.com/louislam/uptime-kuma) | MIT; mature monitor and public pages; maintenance support | Stateful single service; human updates are more mutable and less audit-friendly | Good monitor, weaker fit for controlled public communications | +| [OpenStatus](https://github.com/openstatusHQ/openstatus) | AGPL-3.0; polished monitoring, incident reports, maintenance, subscribers | Managed custom domains are paid; self-hosting is a multi-service stack | Strong managed option, not the requested free/static setup | +| [OneUptime](https://github.com/OneUptime/oneuptime) | Apache-2.0; complete managed monitoring/incident platform; vendor advertises SOC 2 Type II | Active managed monitors are not fully free; self-hosting is far too heavy for one status page | Revisit if subscribers, a vendor SLA, or a full incident platform justify cost | +| [Cachet 3.x](https://github.com/cachethq/cachet) | Rich incident and schedule UI | Current custom license restricts standalone redistribution and is not an OSI-approved open-source license; dynamic PHP/DB stack | Rejected | +| [Statusfy](https://github.com/juliomrqz/statusfy) | Static Markdown incidents | Archived and explicitly unmaintained | Rejected | + +Repository activity, releases, licenses, documentation, and security advisories +were checked from official project sources on the decision date. + +## Why Upptime + +Upptime maps the public operating workflow onto tools Mighty already reviews: + +- Actions make external HTTP checks. +- A failure opens an Issue. +- Operators add timestamped comments such as investigating, identified, + monitoring, and resolved updates. +- Maintenance is an Issue with explicit UTC start/end metadata. +- Git stores check history and reviewed configuration. +- A static site is generated onto `gh-pages` and can be served by Cloudflare + Pages without an application server or database. + +This repository deliberately changes two upstream defaults. Short incidents are +**not deleted** (`skipDeleteIssues: true`), and self-updating workflows are +removed. Those choices retain evidence and require supply-chain changes to go +through review. + +## Hosting decision + +Cloudflare Pages should serve the already-generated `gh-pages` branch. It gives +Mighty a static global edge site and managed TLS outside the GCP production +stack. Use the Cloudflare Git integration restricted to this public repository; +do not put a broad Cloudflare API token in GitHub Actions. GitHub Pages is an +acceptable fallback host if the Pages integration cannot be approved. + +The public GitHub Issues list is the alternate communications URL if the custom +domain or Cloudflare is unavailable. This is not complete independence—Upptime +still uses GitHub for checks and incident data—so Mighty’s existing internal +monitoring remains the source for paging and audit evidence. The page is a +communication layer and an independent secondary observation. + +## SOC 2 interpretation + +SOC 2 does not require a public status page and the page does not make Mighty +compliant. It can support: + +- AICPA Trust Services Criteria CC2.3 (relevant, timely external communication), + CC7.4/CC7.5 (appropriate incident and recovery communication), CC8.1 + (controlled changes), and A1.2/A1.3 (recovery capability and testing). +- A Type 2 examination’s need to show that described controls operated during + the review period. + +The internal incident record must still reconcile monitoring alerts, tickets, +communications, recovery, and corrective work. Public text must not disclose +customer data or exploitable security details. Published uptime is an observed +measurement, not an SLA unless a contract explicitly says otherwise. + +Authoritative references: + +- [AICPA 2017 Trust Services Criteria, revised points of focus 2022](https://www.aicpa-cima.com/resources/download/2017-trust-services-criteria-with-revised-points-of-focus-2022) +- [AICPA 2018 SOC 2 Description Criteria, revised implementation guidance 2022 (PDF)](https://assets.ctfassets.net/rb9cdnjh59cm/1vCduR1U2OnhIvFFaDBjMv/836050054707e9afb65adeb30d2e95d8/92317096_dc_section_200_clean_version.pdf) +- [NIST SP 800-61 Rev. 3 incident-response recommendations (PDF)](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-61r3.pdf) +- [Upptime scheduled maintenance](https://upptime.js.org/docs/scheduled-maintenance/) +- [Upptime scheduler limitation](https://upptime.js.org/blog/2021/01/22/github-actions-schedule-not-working/) diff --git a/docs/HOSTING.md b/docs/HOSTING.md new file mode 100644 index 000000000..9df7c7c3b --- /dev/null +++ b/docs/HOSTING.md @@ -0,0 +1,125 @@ +# Hosting and launch checklist + +## Recommended topology + +```text +GitHub Actions (secondary public checks) + │ + ├── main: config, history, incident Issues/comments + └── gh-pages: generated static website + │ + ▼ + Cloudflare Pages + TLS + │ + status.trymighty.ai + +Mighty internal monitoring ──> paging/private incident record/audit evidence +``` + +The status system must stay outside the Mighty GCP application stack. A failure +of the web app, API, gateway, cluster, or product deployment pipeline must not +prevent the static page from loading. + +## Before enabling automation + +Every production job has a checked-in launch gate: +`vars.STATUS_AUTOMATION_ENABLED == 'true'`. The variable must remain absent or +false while the launch pull request is under review. The read-only `Validate` +workflow may run on the pull request; it builds but never publishes the site. + +Production does **not** need a stored personal access token. Each enabled job +requests only the short-lived repository token permissions it needs: Contents +and Issues write for monitoring, or Contents write for static publication. +GitHub expires that token after the job. Commits made with it intentionally do +not chain into other workflows; live status and Issues are read at page load, +and the static shell has its own schedule. + +1. Confirm `STATUS_AUTOMATION_ENABLED` is absent/false, then review and merge the + launch pull request. Scheduled jobs will skip safely while the gate is off. +2. Keep the repository's default `GITHUB_TOKEN` permission read-only and keep + “Allow GitHub Actions to create and approve pull requests” disabled. Do not + add a `GH_PAT` secret. +3. Keep the Actions allowlist limited to GitHub-owned actions plus the two exact + commit-SHA patterns recorded in the workflows; never switch it to “allow all.” +4. Verify GitHub private vulnerability reporting is enabled and the private + advisory URL works for a non-admin reporter. +5. Create the `maintenance` label if it does not exist. +6. Run `Validate`. Only after the label and security checks pass, enable the + three production workflows and set the repository variable + `STATUS_AUTOMATION_ENABLED` to exactly `true`. +7. Manually trigger these workflows in order: `Uptime CI`, `Response Time CI`, + and `Static Site CI`. To pause safely, set the variable to `false` before + changing automation. +8. Confirm that `history/` and the `gh-pages` branch contain only Mighty data. + Never import the upstream demo measurements. + +## Cloudflare Pages (recommended) + +Wait until `Static Site CI` creates `gh-pages`, then: + +1. In Cloudflare Pages, connect the public `TryMightyAI/status` repository. +2. Select `gh-pages` as the production branch. +3. Use no framework preset, no build command, and `.` as the output directory; + the branch already contains generated static files. +4. Expose no build secrets. Restrict the Cloudflare GitHub integration to this + repository rather than reusing a broad application API token. +5. Attach the custom domain `status.trymighty.ai`. When the zone is in the same + Cloudflare account, let Pages create the required DNS record and certificate. +6. Leave Cloudflare Access/password protection **off** for the public page. +7. Keep the default `*.pages.dev` hostname enabled as an operator diagnostic URL, + but publish the GitHub Issues list as the Cloudflare-independent fallback. + +Cloudflare must deploy after every force/update to `gh-pages`. Validate this with +a harmless branding pull request before launch. The static shell is rebuilt for +configuration/branding changes, but live component status, incident comments, +and scheduled maintenance are fetched from GitHub at page load; an outage update +does not wait for a Cloudflare rebuild. + +## GitHub Pages alternative + +If Cloudflare Pages cannot be approved, publish `gh-pages` `/ (root)` with +GitHub Pages and configure `status.trymighty.ai` as the custom domain. Do not run +both providers for the same custom hostname. The public repository and Issues +remain the alternate channel. + +## Launch validation + +From at least two networks/regions: + +```sh +curl --fail --show-error --location https://status.trymighty.ai/ +curl --fail --show-error https://trymighty.ai/ +curl --fail --show-error https://api.trymighty.ai/health +curl --fail --show-error https://gateway.trymighty.ai/health +``` + +Also verify: + +- valid TLS, automatic HTTP-to-HTTPS redirect, and the security headers from `assets/_headers`; +- logo, CSS, component history, and incident links; +- a future UTC maintenance test appears before its start, then moves into past + history after closing/completion; +- a repository admin can post an update when the Mighty application and normal + identity path are assumed unavailable; +- Cloudflare redeploys an updated `gh-pages` commit; +- the GitHub Issues fallback is documented in the internal incident runbook; +- private vulnerability reporting works without public disclosure; +- an external monitor checks the public status page without depending on this + repository's scheduler or Cloudflare Pages; and +- launch screenshots, headers, workflow run URLs, DNS/TLS result, and test Issue + export are saved to the approved evidence store. + +Do not claim the status-page control is operating until this test is complete. + +## Ongoing hosting controls + +- Monitor the status page itself from a service that does not depend on + Cloudflare Pages or this repository's scheduler. +- Review repository access and workflow job permissions at the organization’s + approved cadence; remove leavers promptly. +- Review Cloudflare Pages project access and deployment history. +- Export the repository and Issue/comment audit population for each SOC 2 + review period. A screenshot alone is weak evidence. +- Test the alternate publishing path at least annually and after material + provider/DNS/identity changes. +- Apply upstream security updates through the reviewed process in `UPSTREAM.md`. diff --git a/docs/OPERATIONS.md b/docs/OPERATIONS.md new file mode 100644 index 000000000..9996d76b5 --- /dev/null +++ b/docs/OPERATIONS.md @@ -0,0 +1,82 @@ +# Incident and maintenance runbook + +This runbook governs the **public status timeline**. Mighty’s private incident +response, security, legal, customer-notification, and recovery procedures remain +authoritative. + +## What belongs on the page + +Publish a status incident when a confirmed production problem materially +prevents or degrades customer use of a listed component. Publish scheduled +maintenance when an upcoming deployment or infrastructure change could create +customer impact. + +Do not publish every normal code push. Use a product changelog for ordinary +releases. The status page is for availability and customer-impacting work. + +Never include customer names/data, credentials, internal addresses, unpatched +exploit details, speculation, or statements that legal/security responders have +not authorized. A public status post never replaces contractual, regulatory, +or direct affected-customer notice. + +## Automated incidents + +Upptime opens an Issue when a check fails and closes it after recovery. The +assigned incident publisher should: + +1. Correlate the alert with internal monitoring before describing scope. +2. Rename the Issue to a clear customer-facing summary if needed. +3. Add a new comment for each stage; do not silently rewrite the timeline: + - **Investigating** — observed impact and known scope; + - **Identified** — cause category and mitigation, without risky detail; + - **Monitoring** — service restored and validation in progress; + - **Resolved** — validated resolution and final customer impact; and + - **Post-incident note** — link or safe summary when appropriate. +4. State the next update time or cadence in the first confirmed public update, + then meet it or explicitly correct it. Do not invent an ETA. +5. If an earlier statement is wrong, add a correction comment that preserves + what changed and when. +6. Reconcile the public timestamps with the private incident record after + resolution. + +`skipDeleteIssues: true` preserves short and false-positive incidents. Explain a +false positive in a closing comment; do not delete it to make the record look +cleaner. + +## Scheduled maintenance and customer-impacting pushes + +1. Open a **Scheduled maintenance** Issue early enough for the approved notice + target. +2. Replace every placeholder in the hidden metadata with ISO 8601 UTC times. +3. List only affected slugs: `website`, `api`, `scan-gateway`. +4. Describe expected customer impact, purpose at a safe level, rollback owner, + and where updates will appear. +5. Use `expectedDown` only for an expected outage and `expectedDegraded` only for + expected degraded service. These fields suppress automatic incident noise; + they must not hide unplanned impact. +6. Comment when work starts, if scope/timing changes, and when validation ends. +7. If actual impact exceeds the notice, treat it as an incident and preserve the + full timeline. + +## Evidence and retention + +For each incident or maintenance selected for audit, retain or export: + +- alert/check records and relevant internal monitor evidence; +- Issue body, comments, labels, authors, edits, and timestamps; +- severity/owner decisions and private response timeline; +- direct subscriber/customer notices when applicable; +- resolution validation, post-incident review, and corrective actions; and +- the configuration/deployment pull request for planned work. + +Git and GitHub Issues are supporting evidence, not the only system of record. +Retain exports for the full Type 2 observation period and the organization’s +approved policy/legal period. Block force-push and deletion where practical. + +## Accuracy and uptime language + +The page reports samples from external checkers. GitHub scheduled jobs may be +delayed, and a green check does not prove every feature or region works. Do not +call the displayed percentage an SLA, guarantee, or contractual availability +calculation unless the governing contract and measurement method explicitly do +so. diff --git a/graphs/google.png b/graphs/google.png deleted file mode 100644 index 52f13e8d0..000000000 Binary files a/graphs/google.png and /dev/null differ diff --git a/graphs/google/response-time-day.png b/graphs/google/response-time-day.png deleted file mode 100644 index e8064e30b..000000000 Binary files a/graphs/google/response-time-day.png and /dev/null differ diff --git a/graphs/google/response-time-month.png b/graphs/google/response-time-month.png deleted file mode 100644 index 203ee5bbd..000000000 Binary files a/graphs/google/response-time-month.png and /dev/null differ diff --git a/graphs/google/response-time-week.png b/graphs/google/response-time-week.png deleted file mode 100644 index 09559a778..000000000 Binary files a/graphs/google/response-time-week.png and /dev/null differ diff --git a/graphs/google/response-time-year.png b/graphs/google/response-time-year.png deleted file mode 100644 index 7a0dd8620..000000000 Binary files a/graphs/google/response-time-year.png and /dev/null differ diff --git a/graphs/google/response-time.png b/graphs/google/response-time.png deleted file mode 100644 index 4a3579ba5..000000000 Binary files a/graphs/google/response-time.png and /dev/null differ diff --git a/graphs/hacker-news.png b/graphs/hacker-news.png deleted file mode 100644 index f87a4ab09..000000000 Binary files a/graphs/hacker-news.png and /dev/null differ diff --git a/graphs/hacker-news/response-time-day.png b/graphs/hacker-news/response-time-day.png deleted file mode 100644 index b9c41d684..000000000 Binary files a/graphs/hacker-news/response-time-day.png and /dev/null differ diff --git a/graphs/hacker-news/response-time-month.png b/graphs/hacker-news/response-time-month.png deleted file mode 100644 index 17b787845..000000000 Binary files a/graphs/hacker-news/response-time-month.png and /dev/null differ diff --git a/graphs/hacker-news/response-time-week.png b/graphs/hacker-news/response-time-week.png deleted file mode 100644 index 0a9227e80..000000000 Binary files a/graphs/hacker-news/response-time-week.png and /dev/null differ diff --git a/graphs/hacker-news/response-time-year.png b/graphs/hacker-news/response-time-year.png deleted file mode 100644 index 6372ec0d8..000000000 Binary files a/graphs/hacker-news/response-time-year.png and /dev/null differ diff --git a/graphs/hacker-news/response-time.png b/graphs/hacker-news/response-time.png deleted file mode 100644 index 9cef0f706..000000000 Binary files a/graphs/hacker-news/response-time.png and /dev/null differ diff --git a/graphs/secret-site/response-time-day.png b/graphs/secret-site/response-time-day.png deleted file mode 100644 index 57c13c729..000000000 Binary files a/graphs/secret-site/response-time-day.png and /dev/null differ diff --git a/graphs/secret-site/response-time-month.png b/graphs/secret-site/response-time-month.png deleted file mode 100644 index 6875185d1..000000000 Binary files a/graphs/secret-site/response-time-month.png and /dev/null differ diff --git a/graphs/secret-site/response-time-week.png b/graphs/secret-site/response-time-week.png deleted file mode 100644 index 60e2be6f4..000000000 Binary files a/graphs/secret-site/response-time-week.png and /dev/null differ diff --git a/graphs/secret-site/response-time-year.png b/graphs/secret-site/response-time-year.png deleted file mode 100644 index 6875185d1..000000000 Binary files a/graphs/secret-site/response-time-year.png and /dev/null differ diff --git a/graphs/secret-site/response-time.png b/graphs/secret-site/response-time.png deleted file mode 100644 index c2492d844..000000000 Binary files a/graphs/secret-site/response-time.png and /dev/null differ diff --git a/graphs/wikipedia.png b/graphs/wikipedia.png deleted file mode 100644 index 2d7393a17..000000000 Binary files a/graphs/wikipedia.png and /dev/null differ diff --git a/graphs/wikipedia/response-time-day.png b/graphs/wikipedia/response-time-day.png deleted file mode 100644 index 1820e8912..000000000 Binary files a/graphs/wikipedia/response-time-day.png and /dev/null differ diff --git a/graphs/wikipedia/response-time-month.png b/graphs/wikipedia/response-time-month.png deleted file mode 100644 index b43a0fc08..000000000 Binary files a/graphs/wikipedia/response-time-month.png and /dev/null differ diff --git a/graphs/wikipedia/response-time-week.png b/graphs/wikipedia/response-time-week.png deleted file mode 100644 index 018e83802..000000000 Binary files a/graphs/wikipedia/response-time-week.png and /dev/null differ diff --git a/graphs/wikipedia/response-time-year.png b/graphs/wikipedia/response-time-year.png deleted file mode 100644 index 8d7c69818..000000000 Binary files a/graphs/wikipedia/response-time-year.png and /dev/null differ diff --git a/graphs/wikipedia/response-time.png b/graphs/wikipedia/response-time.png deleted file mode 100644 index cd62a7fcb..000000000 Binary files a/graphs/wikipedia/response-time.png and /dev/null differ diff --git a/history/LICENSE b/history/LICENSE deleted file mode 100644 index fc9491e52..000000000 --- a/history/LICENSE +++ /dev/null @@ -1,540 +0,0 @@ -## ODC Open Database License (ODbL) - -### Preamble - -The Open Database License (ODbL) is a license agreement intended to -allow users to freely share, modify, and use this Database while -maintaining this same freedom for others. Many databases are covered by -copyright, and therefore this document licenses these rights. Some -jurisdictions, mainly in the European Union, have specific rights that -cover databases, and so the ODbL addresses these rights, too. Finally, -the ODbL is also an agreement in contract for users of this Database to -act in certain ways in return for accessing this Database. - -Databases can contain a wide variety of types of content (images, -audiovisual material, and sounds all in the same database, for example), -and so the ODbL only governs the rights over the Database, and not the -contents of the Database individually. Licensors should use the ODbL -together with another license for the contents, if the contents have a -single set of rights that uniformly covers all of the contents. If the -contents have multiple sets of different rights, Licensors should -describe what rights govern what contents together in the individual -record or in some other way that clarifies what rights apply. - -Sometimes the contents of a database, or the database itself, can be -covered by other rights not addressed here (such as private contracts, -trade mark over the name, or privacy rights / data protection rights -over information in the contents), and so you are advised that you may -have to consult other documents or clear other rights before doing -activities not covered by this License. - ------- - -The Licensor (as defined below) - -and - -You (as defined below) - -agree as follows: - -### 1.0 Definitions of Capitalised Words - -"Collective Database" – Means this Database in unmodified form as part -of a collection of independent databases in themselves that together are -assembled into a collective whole. A work that constitutes a Collective -Database will not be considered a Derivative Database. - -"Convey" – As a verb, means Using the Database, a Derivative Database, -or the Database as part of a Collective Database in any way that enables -a Person to make or receive copies of the Database or a Derivative -Database. Conveying does not include interaction with a user through a -computer network, or creating and Using a Produced Work, where no -transfer of a copy of the Database or a Derivative Database occurs. -"Contents" – The contents of this Database, which includes the -information, independent works, or other material collected into the -Database. For example, the contents of the Database could be factual -data or works such as images, audiovisual material, text, or sounds. - -"Database" – A collection of material (the Contents) arranged in a -systematic or methodical way and individually accessible by electronic -or other means offered under the terms of this License. - -"Database Directive" – Means Directive 96/9/EC of the European -Parliament and of the Council of 11 March 1996 on the legal protection -of databases, as amended or succeeded. - -"Database Right" – Means rights resulting from the Chapter III ("sui -generis") rights in the Database Directive (as amended and as transposed -by member states), which includes the Extraction and Re-utilisation of -the whole or a Substantial part of the Contents, as well as any similar -rights available in the relevant jurisdiction under Section 10.4. - -"Derivative Database" – Means a database based upon the Database, and -includes any translation, adaptation, arrangement, modification, or any -other alteration of the Database or of a Substantial part of the -Contents. This includes, but is not limited to, Extracting or -Re-utilising the whole or a Substantial part of the Contents in a new -Database. - -"Extraction" – Means the permanent or temporary transfer of all or a -Substantial part of the Contents to another medium by any means or in -any form. - -"License" – Means this license agreement and is both a license of rights -such as copyright and Database Rights and an agreement in contract. - -"Licensor" – Means the Person that offers the Database under the terms -of this License. - -"Person" – Means a natural or legal person or a body of persons -corporate or incorporate. - -"Produced Work" – a work (such as an image, audiovisual material, text, -or sounds) resulting from using the whole or a Substantial part of the -Contents (via a search or other query) from this Database, a Derivative -Database, or this Database as part of a Collective Database. - -"Publicly" – means to Persons other than You or under Your control by -either more than 50% ownership or by the power to direct their -activities (such as contracting with an independent consultant). - -"Re-utilisation" – means any form of making available to the public all -or a Substantial part of the Contents by the distribution of copies, by -renting, by online or other forms of transmission. - -"Substantial" – Means substantial in terms of quantity or quality or a -combination of both. The repeated and systematic Extraction or -Re-utilisation of insubstantial parts of the Contents may amount to the -Extraction or Re-utilisation of a Substantial part of the Contents. - -"Use" – As a verb, means doing any act that is restricted by copyright -or Database Rights whether in the original medium or any other; and -includes without limitation distributing, copying, publicly performing, -publicly displaying, and preparing derivative works of the Database, as -well as modifying the Database as may be technically necessary to use it -in a different mode or format. - -"You" – Means a Person exercising rights under this License who has not -previously violated the terms of this License with respect to the -Database, or who has received express permission from the Licensor to -exercise rights under this License despite a previous violation. - -Words in the singular include the plural and vice versa. - -### 2.0 What this License covers - -2.1. Legal effect of this document. This License is: - - a. A license of applicable copyright and neighbouring rights; - - b. A license of the Database Right; and - - c. An agreement in contract between You and the Licensor. - -2.2 Legal rights covered. This License covers the legal rights in the -Database, including: - - a. Copyright. Any copyright or neighbouring rights in the Database. - The copyright licensed includes any individual elements of the - Database, but does not cover the copyright over the Contents - independent of this Database. See Section 2.4 for details. Copyright - law varies between jurisdictions, but is likely to cover: the Database - model or schema, which is the structure, arrangement, and organisation - of the Database, and can also include the Database tables and table - indexes; the data entry and output sheets; and the Field names of - Contents stored in the Database; - - b. Database Rights. Database Rights only extend to the Extraction and - Re-utilisation of the whole or a Substantial part of the Contents. - Database Rights can apply even when there is no copyright over the - Database. Database Rights can also apply when the Contents are removed - from the Database and are selected and arranged in a way that would - not infringe any applicable copyright; and - - c. Contract. This is an agreement between You and the Licensor for - access to the Database. In return you agree to certain conditions of - use on this access as outlined in this License. - -2.3 Rights not covered. - - a. This License does not apply to computer programs used in the making - or operation of the Database; - - b. This License does not cover any patents over the Contents or the - Database; and - - c. This License does not cover any trademarks associated with the - Database. - -2.4 Relationship to Contents in the Database. The individual items of -the Contents contained in this Database may be covered by other rights, -including copyright, patent, data protection, privacy, or personality -rights, and this License does not cover any rights (other than Database -Rights or in contract) in individual Contents contained in the Database. -For example, if used on a Database of images (the Contents), this -License would not apply to copyright over individual images, which could -have their own separate licenses, or one single license covering all of -the rights over the images. - -### 3.0 Rights granted - -3.1 Subject to the terms and conditions of this License, the Licensor -grants to You a worldwide, royalty-free, non-exclusive, terminable (but -only under Section 9) license to Use the Database for the duration of -any applicable copyright and Database Rights. These rights explicitly -include commercial use, and do not exclude any field of endeavour. To -the extent possible in the relevant jurisdiction, these rights may be -exercised in all media and formats whether now known or created in the -future. - -The rights granted cover, for example: - - a. Extraction and Re-utilisation of the whole or a Substantial part of - the Contents; - - b. Creation of Derivative Databases; - - c. Creation of Collective Databases; - - d. Creation of temporary or permanent reproductions by any means and - in any form, in whole or in part, including of any Derivative - Databases or as a part of Collective Databases; and - - e. Distribution, communication, display, lending, making available, or - performance to the public by any means and in any form, in whole or in - part, including of any Derivative Database or as a part of Collective - Databases. - -3.2 Compulsory license schemes. For the avoidance of doubt: - - a. Non-waivable compulsory license schemes. In those jurisdictions in - which the right to collect royalties through any statutory or - compulsory licensing scheme cannot be waived, the Licensor reserves - the exclusive right to collect such royalties for any exercise by You - of the rights granted under this License; - - b. Waivable compulsory license schemes. In those jurisdictions in - which the right to collect royalties through any statutory or - compulsory licensing scheme can be waived, the Licensor waives the - exclusive right to collect such royalties for any exercise by You of - the rights granted under this License; and, - - c. Voluntary license schemes. The Licensor waives the right to collect - royalties, whether individually or, in the event that the Licensor is - a member of a collecting society that administers voluntary licensing - schemes, via that society, from any exercise by You of the rights - granted under this License. - -3.3 The right to release the Database under different terms, or to stop -distributing or making available the Database, is reserved. Note that -this Database may be multiple-licensed, and so You may have the choice -of using alternative licenses for this Database. Subject to Section -10.4, all other rights not expressly granted by Licensor are reserved. - -### 4.0 Conditions of Use - -4.1 The rights granted in Section 3 above are expressly made subject to -Your complying with the following conditions of use. These are important -conditions of this License, and if You fail to follow them, You will be -in material breach of its terms. - -4.2 Notices. If You Publicly Convey this Database, any Derivative -Database, or the Database as part of a Collective Database, then You -must: - - a. Do so only under the terms of this License or another license - permitted under Section 4.4; - - b. Include a copy of this License (or, as applicable, a license - permitted under Section 4.4) or its Uniform Resource Identifier (URI) - with the Database or Derivative Database, including both in the - Database or Derivative Database and in any relevant documentation; and - - c. Keep intact any copyright or Database Right notices and notices - that refer to this License. - - d. If it is not possible to put the required notices in a particular - file due to its structure, then You must include the notices in a - location (such as a relevant directory) where users would be likely to - look for it. - -4.3 Notice for using output (Contents). Creating and Using a Produced -Work does not require the notice in Section 4.2. However, if you -Publicly Use a Produced Work, You must include a notice associated with -the Produced Work reasonably calculated to make any Person that uses, -views, accesses, interacts with, or is otherwise exposed to the Produced -Work aware that Content was obtained from the Database, Derivative -Database, or the Database as part of a Collective Database, and that it -is available under this License. - - a. Example notice. The following text will satisfy notice under - Section 4.3: - - Contains information from DATABASE NAME, which is made available - here under the Open Database License (ODbL). - -DATABASE NAME should be replaced with the name of the Database and a -hyperlink to the URI of the Database. "Open Database License" should -contain a hyperlink to the URI of the text of this License. If -hyperlinks are not possible, You should include the plain text of the -required URI's with the above notice. - -4.4 Share alike. - - a. Any Derivative Database that You Publicly Use must be only under - the terms of: - - i. This License; - - ii. A later version of this License similar in spirit to this - License; or - - iii. A compatible license. - - If You license the Derivative Database under one of the licenses - mentioned in (iii), You must comply with the terms of that license. - - b. For the avoidance of doubt, Extraction or Re-utilisation of the - whole or a Substantial part of the Contents into a new database is a - Derivative Database and must comply with Section 4.4. - - c. Derivative Databases and Produced Works. A Derivative Database is - Publicly Used and so must comply with Section 4.4. if a Produced Work - created from the Derivative Database is Publicly Used. - - d. Share Alike and additional Contents. For the avoidance of doubt, - You must not add Contents to Derivative Databases under Section 4.4 a - that are incompatible with the rights granted under this License. - - e. Compatible licenses. Licensors may authorise a proxy to determine - compatible licenses under Section 4.4 a iii. If they do so, the - authorised proxy's public statement of acceptance of a compatible - license grants You permission to use the compatible license. - - -4.5 Limits of Share Alike. The requirements of Section 4.4 do not apply -in the following: - - a. For the avoidance of doubt, You are not required to license - Collective Databases under this License if You incorporate this - Database or a Derivative Database in the collection, but this License - still applies to this Database or a Derivative Database as a part of - the Collective Database; - - b. Using this Database, a Derivative Database, or this Database as - part of a Collective Database to create a Produced Work does not - create a Derivative Database for purposes of Section 4.4; and - - c. Use of a Derivative Database internally within an organisation is - not to the public and therefore does not fall under the requirements - of Section 4.4. - -4.6 Access to Derivative Databases. If You Publicly Use a Derivative -Database or a Produced Work from a Derivative Database, You must also -offer to recipients of the Derivative Database or Produced Work a copy -in a machine readable form of: - - a. The entire Derivative Database; or - - b. A file containing all of the alterations made to the Database or - the method of making the alterations to the Database (such as an - algorithm), including any additional Contents, that make up all the - differences between the Database and the Derivative Database. - -The Derivative Database (under a.) or alteration file (under b.) must be -available at no more than a reasonable production cost for physical -distributions and free of charge if distributed over the internet. - -4.7 Technological measures and additional terms - - a. This License does not allow You to impose (except subject to - Section 4.7 b.) any terms or any technological measures on the - Database, a Derivative Database, or the whole or a Substantial part of - the Contents that alter or restrict the terms of this License, or any - rights granted under it, or have the effect or intent of restricting - the ability of any person to exercise those rights. - - b. Parallel distribution. You may impose terms or technological - measures on the Database, a Derivative Database, or the whole or a - Substantial part of the Contents (a "Restricted Database") in - contravention of Section 4.74 a. only if You also make a copy of the - Database or a Derivative Database available to the recipient of the - Restricted Database: - - i. That is available without additional fee; - - ii. That is available in a medium that does not alter or restrict - the terms of this License, or any rights granted under it, or have - the effect or intent of restricting the ability of any person to - exercise those rights (an "Unrestricted Database"); and - - iii. The Unrestricted Database is at least as accessible to the - recipient as a practical matter as the Restricted Database. - - c. For the avoidance of doubt, You may place this Database or a - Derivative Database in an authenticated environment, behind a - password, or within a similar access control scheme provided that You - do not alter or restrict the terms of this License or any rights - granted under it or have the effect or intent of restricting the - ability of any person to exercise those rights. - -4.8 Licensing of others. You may not sublicense the Database. Each time -You communicate the Database, the whole or Substantial part of the -Contents, or any Derivative Database to anyone else in any way, the -Licensor offers to the recipient a license to the Database on the same -terms and conditions as this License. You are not responsible for -enforcing compliance by third parties with this License, but You may -enforce any rights that You have over a Derivative Database. You are -solely responsible for any modifications of a Derivative Database made -by You or another Person at Your direction. You may not impose any -further restrictions on the exercise of the rights granted or affirmed -under this License. - -### 5.0 Moral rights - -5.1 Moral rights. This section covers moral rights, including any rights -to be identified as the author of the Database or to object to treatment -that would otherwise prejudice the author's honour and reputation, or -any other derogatory treatment: - - a. For jurisdictions allowing waiver of moral rights, Licensor waives - all moral rights that Licensor may have in the Database to the fullest - extent possible by the law of the relevant jurisdiction under Section - 10.4; - - b. If waiver of moral rights under Section 5.1 a in the relevant - jurisdiction is not possible, Licensor agrees not to assert any moral - rights over the Database and waives all claims in moral rights to the - fullest extent possible by the law of the relevant jurisdiction under - Section 10.4; and - - c. For jurisdictions not allowing waiver or an agreement not to assert - moral rights under Section 5.1 a and b, the author may retain their - moral rights over certain aspects of the Database. - -Please note that some jurisdictions do not allow for the waiver of moral -rights, and so moral rights may still subsist over the Database in some -jurisdictions. - -### 6.0 Fair dealing, Database exceptions, and other rights not affected - -6.1 This License does not affect any rights that You or anyone else may -independently have under any applicable law to make any use of this -Database, including without limitation: - - a. Exceptions to the Database Right including: Extraction of Contents - from non-electronic Databases for private purposes, Extraction for - purposes of illustration for teaching or scientific research, and - Extraction or Re-utilisation for public security or an administrative - or judicial procedure. - - b. Fair dealing, fair use, or any other legally recognised limitation - or exception to infringement of copyright or other applicable laws. - -6.2 This License does not affect any rights of lawful users to Extract -and Re-utilise insubstantial parts of the Contents, evaluated -quantitatively or qualitatively, for any purposes whatsoever, including -creating a Derivative Database (subject to other rights over the -Contents, see Section 2.4). The repeated and systematic Extraction or -Re-utilisation of insubstantial parts of the Contents may however amount -to the Extraction or Re-utilisation of a Substantial part of the -Contents. - -### 7.0 Warranties and Disclaimer - -7.1 The Database is licensed by the Licensor "as is" and without any -warranty of any kind, either express, implied, or arising by statute, -custom, course of dealing, or trade usage. Licensor specifically -disclaims any and all implied warranties or conditions of title, -non-infringement, accuracy or completeness, the presence or absence of -errors, fitness for a particular purpose, merchantability, or otherwise. -Some jurisdictions do not allow the exclusion of implied warranties, so -this exclusion may not apply to You. - -### 8.0 Limitation of liability - -8.1 Subject to any liability that may not be excluded or limited by law, -the Licensor is not liable for, and expressly excludes, all liability -for loss or damage however and whenever caused to anyone by any use -under this License, whether by You or by anyone else, and whether caused -by any fault on the part of the Licensor or not. This exclusion of -liability includes, but is not limited to, any special, incidental, -consequential, punitive, or exemplary damages such as loss of revenue, -data, anticipated profits, and lost business. This exclusion applies -even if the Licensor has been advised of the possibility of such -damages. - -8.2 If liability may not be excluded by law, it is limited to actual and -direct financial loss to the extent it is caused by proved negligence on -the part of the Licensor. - -### 9.0 Termination of Your rights under this License - -9.1 Any breach by You of the terms and conditions of this License -automatically terminates this License with immediate effect and without -notice to You. For the avoidance of doubt, Persons who have received the -Database, the whole or a Substantial part of the Contents, Derivative -Databases, or the Database as part of a Collective Database from You -under this License will not have their licenses terminated provided -their use is in full compliance with this License or a license granted -under Section 4.8 of this License. Sections 1, 2, 7, 8, 9 and 10 will -survive any termination of this License. - -9.2 If You are not in breach of the terms of this License, the Licensor -will not terminate Your rights under it. - -9.3 Unless terminated under Section 9.1, this License is granted to You -for the duration of applicable rights in the Database. - -9.4 Reinstatement of rights. If you cease any breach of the terms and -conditions of this License, then your full rights under this License -will be reinstated: - - a. Provisionally and subject to permanent termination until the 60th - day after cessation of breach; - - b. Permanently on the 60th day after cessation of breach unless - otherwise reasonably notified by the Licensor; or - - c. Permanently if reasonably notified by the Licensor of the - violation, this is the first time You have received notice of - violation of this License from the Licensor, and You cure the - violation prior to 30 days after your receipt of the notice. - -Persons subject to permanent termination of rights are not eligible to -be a recipient and receive a license under Section 4.8. - -9.5 Notwithstanding the above, Licensor reserves the right to release -the Database under different license terms or to stop distributing or -making available the Database. Releasing the Database under different -license terms or stopping the distribution of the Database will not -withdraw this License (or any other license that has been, or is -required to be, granted under the terms of this License), and this -License will continue in full force and effect unless terminated as -stated above. - -### 10.0 General - -10.1 If any provision of this License is held to be invalid or -unenforceable, that must not affect the validity or enforceability of -the remainder of the terms and conditions of this License and each -remaining provision of this License shall be valid and enforced to the -fullest extent permitted by law. - -10.2 This License is the entire agreement between the parties with -respect to the rights granted here over the Database. It replaces any -earlier understandings, agreements or representations with respect to -the Database. - -10.3 If You are in breach of the terms of this License, You will not be -entitled to rely on the terms of this License or to complain of any -breach by the Licensor. - -10.4 Choice of law. This License takes effect in and will be governed by -the laws of the relevant jurisdiction in which the License terms are -sought to be enforced. If the standard suite of rights granted under -applicable copyright law and Database Rights in the relevant -jurisdiction includes additional rights not granted under this License, -these additional rights are granted in this License in order to meet the -terms of this License. diff --git a/history/google.yml b/history/google.yml deleted file mode 100644 index f74124585..000000000 --- a/history/google.yml +++ /dev/null @@ -1,7 +0,0 @@ -url: https://www.google.com -status: up -code: 200 -responseTime: 84 -lastUpdated: 2026-08-10T23:24:37.185Z -startTime: 2020-08-10T07:54:39.000Z -generator: Upptime diff --git a/history/hacker-news.yml b/history/hacker-news.yml deleted file mode 100644 index d3dc9e770..000000000 --- a/history/hacker-news.yml +++ /dev/null @@ -1,7 +0,0 @@ -url: https://news.ycombinator.com -status: up -code: 200 -responseTime: 262 -lastUpdated: 2026-08-10T23:24:37.737Z -startTime: 2020-08-10T07:54:43.000Z -generator: Upptime diff --git a/history/secret-site.yml b/history/secret-site.yml deleted file mode 100644 index 1d51ac926..000000000 --- a/history/secret-site.yml +++ /dev/null @@ -1,7 +0,0 @@ -url: $SECRET_SITE -status: up -code: 200 -responseTime: 24 -lastUpdated: 2026-08-10T23:24:37.789Z -startTime: 2026-07-23T19:05:55.199Z -generator: Upptime diff --git a/history/summary.json b/history/summary.json deleted file mode 100644 index 60dcc9b1b..000000000 --- a/history/summary.json +++ /dev/null @@ -1,82 +0,0 @@ -[ - { - "name": "Google", - "url": "https://www.google.com", - "icon": "https://icons.duckduckgo.com/ip3/www.google.com.ico", - "slug": "google", - "status": "up", - "uptime": "99.99%", - "uptimeDay": "100.00%", - "uptimeWeek": "100.00%", - "uptimeMonth": "100.00%", - "uptimeYear": "99.96%", - "time": 123, - "timeDay": 84, - "timeWeek": 79, - "timeMonth": 81, - "timeYear": 128, - "dailyMinutesDown": { - "2025-10-14": 19, - "2025-12-14": 23, - "2026-01-04": 20, - "2026-01-05": 20, - "2026-04-11": 28, - "2026-04-12": 38, - "2026-04-19": 64 - } - }, - { - "name": "Wikipedia", - "url": "https://en.wikipedia.org", - "icon": "https://icons.duckduckgo.com/ip3/en.wikipedia.org.ico", - "slug": "wikipedia", - "status": "up", - "uptime": "100.00%", - "uptimeDay": "100.00%", - "uptimeWeek": "100.00%", - "uptimeMonth": "100.00%", - "uptimeYear": "100.00%", - "time": 195, - "timeDay": 221, - "timeWeek": 208, - "timeMonth": 163, - "timeYear": 204, - "dailyMinutesDown": {} - }, - { - "name": "Hacker News", - "url": "https://news.ycombinator.com", - "icon": "https://icons.duckduckgo.com/ip3/news.ycombinator.com.ico", - "slug": "hacker-news", - "status": "up", - "uptime": "99.11%", - "uptimeDay": "100.00%", - "uptimeWeek": "100.00%", - "uptimeMonth": "100.00%", - "uptimeYear": "100.00%", - "time": 301, - "timeDay": 262, - "timeWeek": 243, - "timeMonth": 257, - "timeYear": 283, - "dailyMinutesDown": {} - }, - { - "name": "Secret Site", - "url": "$SECRET_SITE", - "icon": "https://icons.duckduckgo.com/ip3/null.ico", - "slug": "secret-site", - "status": "up", - "uptime": "100.00%", - "uptimeDay": "100.00%", - "uptimeWeek": "100.00%", - "uptimeMonth": "100.00%", - "uptimeYear": "100.00%", - "time": 41, - "timeDay": 24, - "timeWeek": 41, - "timeMonth": 40, - "timeYear": 40, - "dailyMinutesDown": {} - } -] \ No newline at end of file diff --git a/history/wikipedia.yml b/history/wikipedia.yml deleted file mode 100644 index 315e1834f..000000000 --- a/history/wikipedia.yml +++ /dev/null @@ -1,7 +0,0 @@ -url: https://en.wikipedia.org -status: up -code: 200 -responseTime: 221 -lastUpdated: 2026-08-10T23:24:37.445Z -startTime: 2020-08-10T07:54:40.000Z -generator: Upptime diff --git a/patches/upptime-status-page-main.patch b/patches/upptime-status-page-main.patch new file mode 100644 index 000000000..11b945e4e --- /dev/null +++ b/patches/upptime-status-page-main.patch @@ -0,0 +1,55 @@ +diff --git a/src/components/LiveStatus.svelte b/src/components/LiveStatus.svelte +index 16eec5d..e266005 100644 +--- a/src/components/LiveStatus.svelte ++++ b/src/components/LiveStatus.svelte +@@ -17 +16,0 @@ +- const graphsBaseUrl = `${userContentBaseUrl}/${owner}/${repo}/master/graphs`; +@@ -24 +23 @@ +- const res = await fetch(`${userContentBaseUrl}/${owner}/${repo}/master/history/summary.json`); ++ const res = await fetch(`${userContentBaseUrl}/${owner}/${repo}/main/history/summary.json`); +@@ -101,14 +100,2 @@ +-

++
++

+@@ -156,6 +142,0 @@ +- article.graph { +- background-image: var(--background); +- background-size: contain; +- background-repeat: no-repeat; +- background-position: center right; +- } +diff --git a/src/components/Summary.svelte b/src/components/Summary.svelte +index 97ee5bc..8f510de 100644 +--- a/src/components/Summary.svelte ++++ b/src/components/Summary.svelte +@@ -20 +20 @@ +- const res = await fetch(`${userContentBaseUrl}/${owner}/${repo}/master/history/summary.json`); ++ const res = await fetch(`${userContentBaseUrl}/${owner}/${repo}/main/history/summary.json`); +diff --git a/src/routes/_layout.svelte b/src/routes/_layout.svelte +index 74c6a4a..2e411f8 100644 +--- a/src/routes/_layout.svelte ++++ b/src/routes/_layout.svelte +@@ -45,7 +44,0 @@ +- +@@ -55 +48 @@ +- href={(config["status-website"] || {}).favicon || `/logo-192.png`} ++ href={(config["status-website"] || {}).favicon || `/mighty-logo.png`} diff --git a/scripts/validate.rb b/scripts/validate.rb new file mode 100755 index 000000000..da63e1d86 --- /dev/null +++ b/scripts/validate.rb @@ -0,0 +1,147 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +require "yaml" +require "uri" + +ERRORS = [] + +def check(condition, message) + ERRORS << message unless condition +end + +config = YAML.safe_load(File.read(".upptimerc.yml"), aliases: false) +check(config.is_a?(Hash), ".upptimerc.yml must be a mapping") +check(config["owner"] == "TryMightyAI", "owner must be TryMightyAI") +check(config["repo"] == "status", "repo must be status") +check(config["secrets"] == [], "monitor secret allowlist must remain explicit and empty") +check(config["skipDeleteIssues"] == true, "short incidents must be retained") +%w[skipDescriptionUpdate skipTopicsUpdate skipHomepageUpdate].each do |key| + check(config[key] == true, "#{key}: automation must not rewrite repository metadata") +end +check(config.dig("status-website", "cname") == "status.trymighty.ai", "custom domain changed") +check(config.dig("status-website", "logoUrl") == "/mighty-logo.png", "logo must be served with the static page") + +sites = config.fetch("sites", []) +check(sites.length >= 3, "at least three customer-facing components are required") +slugs = sites.map { |site| site["slug"] } +check(slugs.compact.length == sites.length, "every component needs an explicit slug") +check(slugs.uniq.length == slugs.length, "component slugs must be unique") + +expected_bodies = { + "api" => '"status":"healthy"', + "scan-gateway" => '"status":"ok"' +} + +sites.each do |site| + check(site["method"] == "GET", "#{site["name"]}: checks must use GET") + if expected_bodies.key?(site["slug"]) + check(site["__dangerous__body_down_if_text_missing"] == expected_bodies[site["slug"]], + "#{site["name"]}: health-body assertion changed") + end + begin + uri = URI.parse(site.fetch("url")) + check(uri.is_a?(URI::HTTPS), "#{site["name"]}: URL must use HTTPS") + check(uri.userinfo.nil?, "#{site["name"]}: URL must not contain credentials") + check(uri.query.nil?, "#{site["name"]}: public checks must not put secrets/query data in URLs") + rescue StandardError => e + ERRORS << "#{site["name"] || "unnamed site"}: invalid URL (#{e.message})" + end + check(site["expectedStatusCodes"] == [200], "#{site["name"]}: require an exact HTTP 200") + check(site["maxResponseTime"].is_a?(Integer) && site["maxResponseTime"] <= 10_000, + "#{site["name"]}: maxResponseTime must be an integer no greater than 10 seconds") +end + +workflow_dir = ".github/workflows" +forbidden = %w[setup.yml update-template.yml updates.yml] +forbidden.each do |name| + check(!File.exist?(File.join(workflow_dir, name)), "self-modifying workflow #{name} must stay removed") +end + +runtime_workflows = %w[uptime.yml response-time.yml site.yml] +runtime_workflows.each do |name| + path = File.join(workflow_dir, name) + check(File.exist?(path), "missing runtime workflow #{name}") + next unless File.exist?(path) + + content = File.read(path) + begin + YAML.safe_load(content, aliases: false) + rescue StandardError => e + ERRORS << "#{name}: invalid YAML (#{e.message})" + end + check(content.include?("permissions: + contents: read"), "#{name}: top-level token must be read-only") + check(content.include?("timeout-minutes:"), "#{name}: job needs a timeout") + check(content.include?("if: github.ref == 'refs/heads/main' && vars.STATUS_AUTOMATION_ENABLED == 'true'"), + "#{name}: production automation needs the explicit launch gate") + check(!content.include?("pull_request_target"), "#{name}: pull_request_target is forbidden") + check(!content.include?("repository_dispatch"), "#{name}: repository_dispatch is not required") + check(!content.include?("GH_PAT"), "#{name}: long-lived PATs are forbidden") + check(!content.include?("secrets."), "#{name}: production jobs must not consume repository secrets") + + content.scan(/^\s*uses:\s*([^\s#]+)/).flatten.each do |action| + next if action.start_with?("./") + check(action.match?(/\A[^@]+@[0-9a-f]{40}\z/), "#{name}: action is not full-SHA pinned: #{action}") + end +end + +site_content = File.read(File.join(workflow_dir, "site.yml")) +check(site_content.include?("ref: 54c2ff5a3d998d525ee4c7e68dc7ce7414d89c33 # v1.17.0"), + "static site source must stay pinned to Upptime status-page v1.17.0") +check(site_content.include?("npm ci --no-audit --no-fund"), + "static site must use its upstream package lock") +check(!site_content.include?("command: site"), + "do not use Upptime's floating npm status-page install") +check(File.read("patches/upptime-status-page-main.patch").scan("/master/").length == 4, + "main-branch compatibility patch changed unexpectedly") + +%w[uptime.yml response-time.yml].each do |name| + content = File.read(File.join(workflow_dir, name)) + check(content.include?("group: ${{ github.repository }}-upptime-main-writer"), + "#{name}: main writers must share one concurrency group") + check(content.include?(" contents: write + issues: write"), + "#{name}: ephemeral token needs only Contents/Issues write") + check(content.include?("GITHUB_TOKEN: ${{ github.token }}"), + "#{name}: monitor must use the ephemeral job token") +end +check(site_content.include?(" contents: write"), + "site.yml: publisher needs job-scoped Contents write") +check(site_content.include?("github_token: ${{ github.token }}"), + "site.yml: publisher must use the ephemeral job token") + +check(!File.read("README.md").include?(""), + "README summary markers would generate links to intentionally omitted PNG graphs") + +validate_path = File.join(workflow_dir, "validate.yml") +if File.exist?(validate_path) + validate_content = File.read(validate_path) + validate_content.scan(/^\s*uses:\s*([^\s#]+)/).flatten.each do |action| + next if action.start_with?("./") + check(action.match?(/\A[^@]+@[0-9a-f]{40}\z/), "validate.yml: action is not full-SHA pinned: #{action}") + end +end + +headers = File.read("assets/_headers") +check(headers.include?("Content-Security-Policy: default-src 'self'"), "Cloudflare headers must set a CSP") +check(headers.include?("X-Content-Type-Options: nosniff"), "Cloudflare headers must disable MIME sniffing") +check(headers.include?("X-Frame-Options: DENY"), "Cloudflare headers must prevent framing") +check(headers.include?("Strict-Transport-Security:"), "Cloudflare headers must enable HSTS") + +issue_template = File.read(".github/ISSUE_TEMPLATE/scheduled-maintenance.md") +first_metadata = issue_template.split("", 2)&.first.to_s +check(first_metadata.include?("start: 2000-01-01T00:00:00Z"), + "first maintenance comment needs a safe start placeholder") +check(first_metadata.include?("end: 2000-01-01T00:30:00Z"), + "first maintenance comment needs a safe end placeholder") +check(first_metadata.include?("expectedDown:") && first_metadata.include?("expectedDegraded:"), + "first maintenance comment needs optional impact metadata") + +if ERRORS.empty? + puts "Status configuration validation passed (#{sites.length} components, full-SHA workflows)." +else + warn "Status configuration validation failed:" + ERRORS.each { |error| warn "- #{error}" } + exit 1 +end