Skip to content

Commit 7a4efc3

Browse files
proof-ops[bot]proof-ops
andauthored
ops: downgrade optional admin status checks to warnings (#822)
Co-authored-by: proof-ops <proof-ops@local>
1 parent ece8c80 commit 7a4efc3

2 files changed

Lines changed: 59 additions & 14 deletions

File tree

apps/worker/src/routes/admin.ts

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -135,15 +135,26 @@ admin.get('/stats', async (c) => {
135135

136136
// ── GET /status — deep health check for all integrations ───────────────────────
137137

138-
type CheckResult = { ok: boolean; latency_ms: number; error?: string; [k: string]: unknown }
139-
type CheckInput = { ok: boolean; error?: string; [k: string]: unknown }
138+
type CheckResult = {
139+
ok: boolean
140+
latency_ms: number
141+
error?: string
142+
severity?: 'critical' | 'warning'
143+
[k: string]: unknown
144+
}
145+
type CheckInput = {
146+
ok: boolean
147+
error?: string
148+
severity?: 'critical' | 'warning'
149+
[k: string]: unknown
150+
}
140151

141152
async function timed(fn: () => Promise<CheckInput>): Promise<CheckResult> {
142153
const t0 = Date.now()
143154
try {
144155
return { ...await fn(), latency_ms: Date.now() - t0 }
145156
} catch (err: any) {
146-
return { ok: false, error: err?.message ?? 'unknown', latency_ms: Date.now() - t0 }
157+
return { ok: false, error: err?.message ?? 'unknown', severity: 'critical', latency_ms: Date.now() - t0 }
147158
}
148159
}
149160

@@ -153,51 +164,56 @@ admin.get('/status', async (c) => {
153164
const [d1, kv, resend, stripe, ses] = await Promise.all([
154165
timed(async () => {
155166
await env.DB.prepare('SELECT 1').first()
156-
return { ok: true }
167+
return { ok: true, severity: 'critical' }
157168
}),
158169
timed(async () => {
159170
await env.WIDGET_KV.get('__healthcheck')
160-
return { ok: true }
171+
return { ok: true, severity: 'critical' }
161172
}),
162173
timed(async () => {
163-
if (!env.RESEND_API_KEY) return { ok: false, error: 'RESEND_API_KEY not set' }
174+
if (!env.RESEND_API_KEY) return { ok: false, error: 'RESEND_API_KEY not set', severity: 'critical' }
164175
const res = await fetch('https://api.resend.com/domains', {
165176
headers: { Authorization: `Bearer ${env.RESEND_API_KEY}` },
166177
})
167-
if (!res.ok) return { ok: false, error: `HTTP ${res.status}` }
168-
return { ok: true }
178+
if (!res.ok) return { ok: false, error: `HTTP ${res.status}`, severity: 'critical' }
179+
return { ok: true, severity: 'critical' }
169180
}),
170181
timed(async () => {
171-
if (!env.STRIPE_SECRET_KEY) return { ok: false, error: 'STRIPE_SECRET_KEY not set' }
182+
if (!env.STRIPE_SECRET_KEY) return { ok: false, error: 'STRIPE_SECRET_KEY not set', severity: 'warning' }
172183
const res = await fetch('https://api.stripe.com/v1/balance', {
173184
headers: { Authorization: `Bearer ${env.STRIPE_SECRET_KEY}` },
174185
})
175-
if (!res.ok) return { ok: false, error: `HTTP ${res.status}` }
176-
return { ok: true }
186+
if (!res.ok) return { ok: false, error: `HTTP ${res.status}`, severity: 'warning' }
187+
return { ok: true, severity: 'warning' }
177188
}),
178189
timed(async () => {
179190
if (!env.SES_AWS_ACCESS_KEY_ID || !env.SES_AWS_SECRET_ACCESS_KEY) {
180-
return { ok: false, error: 'SES credentials not set' }
191+
return { ok: false, error: 'SES credentials not set', severity: 'warning' }
181192
}
182193
const result = await sesCheckCredentials(
183194
env.SES_AWS_ACCESS_KEY_ID,
184195
env.SES_AWS_SECRET_ACCESS_KEY,
185196
env.SES_REGION ?? 'us-east-1',
186197
)
187-
if (!result.ok) return { ok: false, error: result.detail }
198+
if (!result.ok) return { ok: false, error: result.detail, severity: 'warning' }
188199
return {
189200
ok: true,
201+
severity: 'warning',
190202
region: env.SES_REGION ?? 'us-east-1',
191203
from: env.SES_FROM_EMAIL ?? '(not set)',
192204
}
193205
}),
194206
])
195207

196208
const checks: Record<string, CheckResult> = { d1, kv, resend, stripe, ses }
197-
const allOk = Object.values(checks).every((ch) => ch.ok)
209+
const criticalChecks = Object.values(checks).filter((ch) => (ch.severity ?? 'critical') === 'critical')
210+
const warningChecks = Object.values(checks).filter((ch) => ch.severity === 'warning')
211+
const allOk = criticalChecks.every((ch) => ch.ok)
212+
const hasWarnings = warningChecks.some((ch) => !ch.ok)
198213

199214
return c.json({
200215
ok: allOk,
216+
has_warnings: hasWarnings,
201217
checks,
202218
env: env.ENVIRONMENT ?? 'unknown',
203219
ts: new Date().toISOString(),

apps/worker/test/admin.test.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,35 @@ describe('GET /api/admin/status', () => {
219219
expect(json.checks.stripe.ok).toBe(false)
220220
expect(json.checks.ses.ok).toBe(false)
221221
})
222+
223+
it('returns 200 when only warning-level integrations fail', async () => {
224+
const warningEnv = {
225+
...adminEnv,
226+
RESEND_API_KEY: 're_test_key',
227+
SES_AWS_ACCESS_KEY_ID: '',
228+
SES_AWS_SECRET_ACCESS_KEY: '',
229+
}
230+
const fetchMock = vi.fn(async (input: RequestInfo | URL) => {
231+
const url = String(input)
232+
if (url.includes('api.resend.com/domains')) {
233+
return new Response(JSON.stringify({ data: [] }), { status: 200 })
234+
}
235+
throw new Error(`unexpected fetch ${url}`)
236+
})
237+
vi.stubGlobal('fetch', fetchMock)
238+
239+
const res = await app.request('/api/admin/status', {
240+
headers: { Authorization: 'Bearer test-admin-token' },
241+
}, warningEnv)
242+
243+
const json = await res.json() as Record<string, any>
244+
expect(res.status).toBe(200)
245+
expect(json.ok).toBe(true)
246+
expect(json.has_warnings).toBe(true)
247+
expect(json.checks.stripe.severity).toBe('warning')
248+
expect(json.checks.ses.severity).toBe('warning')
249+
expect(json.checks.resend.severity).toBe('critical')
250+
})
222251
})
223252

224253
// ── Outreach endpoints ─────────────────────────────────────────────────────────

0 commit comments

Comments
 (0)