diff --git a/services/o11y/src/alerting/gastown-health-query.ts b/services/o11y/src/alerting/gastown-health-query.ts index cc1a7f071e..2823efaa38 100644 --- a/services/o11y/src/alerting/gastown-health-query.ts +++ b/services/o11y/src/alerting/gastown-health-query.ts @@ -16,12 +16,17 @@ type QueryEnv = { type FetchFn = (url: string, init?: RequestInit) => Promise; +const AnalyticsEngineNumberSchema = z.preprocess( + value => (typeof value === 'string' && value.trim() !== '' ? Number(value) : value), + z.number().finite().nonnegative().nullable() +); + const GastownHealthResponseSchema = z.object({ data: z.array( z.object({ town_id: z.string(), - weighted_failed_checks: z.number().nonnegative().nullable(), - weighted_successful_checks: z.number().nonnegative().nullable(), + weighted_failed_checks: AnalyticsEngineNumberSchema, + weighted_successful_checks: AnalyticsEngineNumberSchema, latest_event_timestamp: z.string().nullable(), }) ), diff --git a/services/o11y/test/gastown-health-query.spec.ts b/services/o11y/test/gastown-health-query.spec.ts index e4c968c20d..fc8bb660a6 100644 --- a/services/o11y/test/gastown-health-query.spec.ts +++ b/services/o11y/test/gastown-health-query.spec.ts @@ -31,20 +31,20 @@ describe('queryGastownHealth', () => { data: [ { town_id: 'town-1', - weighted_failed_checks: 20, - weighted_successful_checks: 100, + weighted_failed_checks: '20', + weighted_successful_checks: '100', latest_event_timestamp: '2026-06-24 15:09:00.000', }, { town_id: 'town-2', - weighted_failed_checks: 4, - weighted_successful_checks: 50, + weighted_failed_checks: '4', + weighted_successful_checks: '50', latest_event_timestamp: '2026-06-24 15:10:00.000', }, { town_id: '', - weighted_failed_checks: 3, - weighted_successful_checks: 2, + weighted_failed_checks: '3', + weighted_successful_checks: '2', latest_event_timestamp: '2026-06-24 15:08:00.000', }, ], @@ -107,6 +107,25 @@ describe('queryGastownHealth', () => { }); }); + it.each(['', 'not-a-number', '-1', 'Infinity'])( + 'rejects invalid Analytics Engine aggregate %j', + async aggregate => { + const fetchFn: FetchFn = async () => + Response.json({ + data: [ + { + town_id: '', + weighted_failed_checks: aggregate, + weighted_successful_checks: '0', + latest_event_timestamp: null, + }, + ], + }); + + await expect(queryGastownHealth(makeEnv(), fetchFn)).rejects.toThrow(); + } + ); + it('rejects malformed Analytics Engine responses', async () => { const fetchFn: FetchFn = async () => Response.json({ data: [{ weighted_failed_checks: '20' }] });