Add a server health check that reports to Discord - #23
Merged
Conversation
Runs every 30 minutes and on demand, probes the live server from the outside, and posts to Discord when something is wrong. It reports three states, not two. A boolean would be wrong here: this server currently answers roughly one ping in four from some networks while being completely healthy, so a one-shot check would cry outage constantly and everyone would learn to ignore the channel. Instead it retries and reports the ratio, which distinguishes "down" from "reachable but lossy". Its first live run correctly produced "up but lossy, 1/4 pings succeeded", which is exactly the condition being chased right now. SECURITY, since this is the first workflow holding a credential: No SSH, and none of the MC_SSH_* secrets are referenced. Port 22 on the droplet is open only to DigitalOcean console ranges, so a GitHub-hosted runner cannot reach it regardless. The options were to open 22 to GitHub's published ranges, which is thousands of third-party addresses, or to put a long-lived SSH credential into CI where every workflow and every fork PR becomes a path to the box. Both trade a real security boundary for a richer report, so neither was taken. Everything reported comes from the same public interface a player uses, which means a green result answers the question an owner actually has: can people get in. Only DISCORD_WEBHOOK is exposed, and only to the single step that needs it. That URL is a bearer credential, so it is never echoed, never put in a job-wide env block, and never written to disk; `set -x` is deliberately absent for the same reason. Verified by running with a fake webhook and grepping the output: zero occurrences. No pull_request trigger, so a fork PR cannot run modified code with access to the secret. Permissions are contents:read. Actions are pinned to full commit SHAs rather than tags, which can be repointed. checkout uses persist-credentials:false. Five-minute timeout. Standard library only, so an unattended monthly run has no dependency that can be swapped underneath it. Concurrency is serialised on purpose: this server drops TCP under concurrent connections, so overlapping probes would manufacture the very failure they exist to detect. On the schedule it stays silent while healthy and posts only on trouble. A green message every 30 minutes is how a channel gets muted, and a muted channel means the one red message is missed too. Manual runs default to posting so the wiring can be confirmed. Player names are opt-in and off by default. If the webhook ever leaks, everything posted through it leaks with it, and these players are children.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Runs every 30 minutes and on demand. Probes the live server from outside and posts to Discord when something is wrong.
It reports three states, not two
A boolean would be wrong here. The server currently answers roughly one ping in four from some networks while being completely healthy, so a one-shot check would cry outage constantly and the channel would get muted.
It retries and reports the ratio, distinguishing down from reachable but lossy. Its first live run produced exactly that:
Security, since this is the first workflow holding a credential
No SSH, and none of the
MC_SSH_*secrets are referenced. Port 22 is open only to DigitalOcean console ranges, so a GitHub runner cannot reach it anyway. The options were opening 22 to GitHub published ranges (thousands of third-party addresses) or putting a long-lived SSH credential in CI where every workflow and every fork PR becomes a path to the box. Both trade a real boundary for a nicer report.Everything reported comes from the same public interface a player uses, so green answers the question that actually matters: can people get in.
DISCORD_WEBHOOKexposed to one step, never job-wideset -x, never written to diskpull_requesttriggercontents: readpersist-credentials: falseVerified with a fake webhook: 0 occurrences in output.
Concurrency is serialised deliberately
This server drops TCP under concurrent connections, so overlapping probes would manufacture the very failure they exist to detect.
Quiet when healthy
On the schedule it posts only on trouble. A green message every 30 minutes is how a channel gets muted, and a muted channel means the red one is missed too. Manual runs default to posting so you can confirm the wiring.
Player names are opt-in and off by default. If the webhook leaks, everything posted through it leaks with it, and these players are children.
Tested
After merge, run it manually from the Actions tab to confirm the Discord webhook works end to end.