-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgithub-status.ts
More file actions
132 lines (120 loc) · 3.86 KB
/
github-status.ts
File metadata and controls
132 lines (120 loc) · 3.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/**
* @file Probe githubstatus.com to detect platform degradation before making
* GitHub API calls. Useful in scripts, release tooling, and CI pre-flight
* checks where a cryptic "operation was canceled" error would otherwise mask
* an upstream GitHub outage. Component IDs are stable GitHub-assigned
* identifiers from githubstatus.com/api/v2/components.json. The probe adds at
* most 8 seconds to startup (configurable timeout) and fails open on network
* error so a down status page never blocks a healthy workflow.
*/
// oxlint-disable-next-line socket/no-platform-specific-import -- server-only module; node platform is intentional.
import { httpJson } from '../http-request/node'
export type GitHubComponentStatus =
| 'degraded_performance'
| 'major_outage'
| 'operational'
| 'partial_outage'
| 'under_maintenance'
export type GitHubStatusResult = {
/**
* Worst-case status across all monitored components.
*/
status: GitHubComponentStatus | 'unknown'
/**
* Whether any monitored component is not fully operational.
*/
degraded: boolean
/**
* Human-readable summary, e.g. "Actions: degraded_performance".
*/
summary: string
/**
* Per-component breakdown for the monitored set.
*/
components: Array<{
id: string
name: string
status: GitHubComponentStatus
}>
}
// Component IDs that matter for CI / GitHub API call workflows.
// Stable identifiers from githubstatus.com; the names are display-only.
const MONITORED_COMPONENT_IDS: ReadonlyMap<string, string> = new Map([
['br0l2tvcx85d', 'Actions'],
['8l4ygp009s5s', 'Git Operations'],
['brv1bkgrwx7q', 'API Requests'],
])
const SEVERITY: ReadonlyMap<string, number> = new Map([
['major_outage', 4],
['partial_outage', 3],
['degraded_performance', 2],
['under_maintenance', 1],
['operational', 0],
])
const STATUS_API_URL = 'https://www.githubstatus.com/api/v2/components.json'
/**
* Probe githubstatus.com and return the health of GitHub Actions, Git
* Operations, and API Requests. Fails open (returns `{ status: 'unknown' }`)
* when the probe itself fails — so a down status page never blocks a healthy
* workflow.
*
* @example
* ;```typescript
* import { probeGitHubStatus } from '@socketsecurity/lib/env/github-status'
*
* const health = await probeGitHubStatus()
* if (health.degraded) {
* console.warn(`GitHub degraded: ${health.summary}`)
* }
* ```
*
* @param timeoutMs - Maximum milliseconds to wait for the probe. Default 8000.
*/
export async function probeGitHubStatus(
timeoutMs = 8000,
): Promise<GitHubStatusResult> {
let body: unknown
try {
body = await httpJson(STATUS_API_URL, {
timeout: timeoutMs,
})
} catch {
return {
status: 'unknown',
degraded: false,
summary: 'githubstatus.com unreachable — cannot confirm GitHub health',
components: [],
}
}
const raw = body as {
components?: Array<{ id: string; name: string; status: string }> | undefined
}
const allComponents = raw.components ?? []
const monitored: GitHubStatusResult['components'] = []
let worstSeverity = 0
let worstStatus: GitHubComponentStatus = 'operational'
for (const c of allComponents) {
const name = MONITORED_COMPONENT_IDS.get(c.id)
if (!name) {
continue
}
const status = c.status as GitHubComponentStatus
const sev = SEVERITY.get(status) ?? 0
if (sev > worstSeverity) {
worstSeverity = sev
worstStatus = status
}
monitored.push({ id: c.id, name, status })
}
const degradedComponents = monitored.filter(c => c.status !== 'operational')
const degraded = degradedComponents.length > 0
const summary = degraded
? degradedComponents.map(c => `${c.name}: ${c.status}`).join(', ')
: 'All monitored GitHub components operational'
return {
status: worstStatus,
degraded,
summary,
components: monitored,
}
}