Block a deploy when a vendor status page says they are down
Deploying while GitHub, your cloud host or your payment provider is mid-outage is how a normal release turns into a long night. Most vendor status pages run on Atlassian Statuspage or a compatible service, and they all serve the same machine-readable summary at /api/v2/summary.json. This page gives you a 25-line Node script that reads a few of them and exits with code 1 when any is in a major outage, so a CI job or a shell script can stop before it ships. It needs Node 18 or newer and no packages.
The script
Save it as vendor-gate.mjs. It was run on 2026-10-14 against 60 hosts from the Status Endpoint Atlas; it printed BLOCK for two that were in a major state at that moment (Aiven and Cloudflare) and ok for the rest.
// vendor-gate.mjs: exit 1 if any vendor status page is not healthy. Node 18+, no dependencies.
// Usage: node vendor-gate.mjs www.githubstatus.com status.npmjs.org
const hosts = process.argv.slice(2);
if (!hosts.length) { console.error("usage: node vendor-gate.mjs <status-host> [...]"); process.exit(2); }
const RANK = { none: 0, maintenance: 0, minor: 1, major: 2, critical: 3 };
let bad = 0;
await Promise.all(hosts.map(async (h) => {
try {
const r = await fetch(`https://${h}/api/v2/summary.json`, { signal: AbortSignal.timeout(10000) });
if (!r.ok) throw new Error(`HTTP ${r.status}`);
const j = await r.json();
const ind = j?.status?.indicator;
if (!(ind in RANK)) throw new Error(`unknown indicator ${ind}`);
const open = (j.incidents || []).map((i) => i.name);
const down = (j.components || []).filter((c) => c.status === "major_outage").map((c) => c.name);
const fail = RANK[ind] >= 2 || down.length > 0;
console.log(`${fail ? "BLOCK" : "ok "} ${h} indicator=${ind} open_incidents=${open.length} major_outage_components=${down.length}`);
if (fail) bad++;
} catch (e) {
console.log(`UNKNOWN ${h}: ${e.message} (treated as not blocking; change if you prefer)`);
}
}));
process.exit(bad ? 1 : 0);
How it decides
- Blocks when the page indicator is
majororcritical, or when any single component is inmajor_outage. Aminorindicator,degraded_performanceorpartial_outagedoes not block, because on large vendors something is nearly always slightly degraded. ChangeRANK[ind] >= 2to>= 1if you want a stricter gate. - Maintenance is not an outage. The indicator
maintenanceand the component stateunder_maintenancedo not block. See the status values reference for every string and what it means. - Unknown is not green. A 404, a timeout or an unexpected indicator prints
UNKNOWNand does not block here, because a broken status page should not freeze every release. If a vendor is critical to the deploy, change the catch branch to count it inbad. - Whole-vendor outages are rare, component outages are common. On a large page, one region or one API can be in
major_outagewhile the product you use is fine (Cloudflare lists hundreds of components, one per data centre). For big vendors, filter the components to the ones you depend on, for examplec.name.includes("Workers").
Use it
Locally or in any shell, before a release step:
node vendor-gate.mjs www.githubstatus.com status.npmjs.org www.vercel-status.com && ./deploy.sh
In GitHub Actions, as the first step of a deploy job (save the script in your repo, for example under scripts/):
- uses: actions/setup-node@v4
with: { node-version: 20 }
- run: node scripts/vendor-gate.mjs www.githubstatus.com status.npmjs.org
A non-zero exit fails the job, and the log shows which host and how many open incidents. Remember that a status page is often updated some minutes after an outage starts, so this gate catches declared incidents, not all of them.
Finding the right host for each vendor
The host is not always status.vendor.com: GitHub is www.githubstatus.com, Vercel is www.vercel-status.com, Netlify is www.netlifystatus.com. The Status Endpoint Atlas lists 246 verified hosts with their summary.json URL, component counts, CORS header and feed availability, and the API guide explains the format and its quirks. A free browser checker tests a single host.
Poll politely: a deploy gate makes one request per host per run, which is fine; a dashboard should cache and poll at 60 seconds or slower.