Webhookのメッセージをカスタマイズできるように

This commit is contained in:
CyberRex
2026-05-27 10:59:58 +09:00
parent 2a4050d442
commit 38acbd35bb
14 changed files with 994 additions and 49 deletions

View File

@@ -102,6 +102,11 @@ describe('certificate monitoring', () => {
};
}
if (sql.includes('FROM user_notification_settings')) {
expect(params).toEqual([USER_ID]);
return { rows: [] };
}
if (sql.includes('FROM notification_methods') && sql.includes("notification_type = 'push'")) {
expect(params).toEqual([USER_ID]);
return {
@@ -138,7 +143,12 @@ describe('certificate monitoring', () => {
expect(pool.connect).toHaveBeenCalledOnce();
expect(getCertificateExpiry).toHaveBeenCalledWith('https://example.com/');
expect(deliverNotifications).toHaveBeenCalledOnce();
expect(deliverNotifications).toHaveBeenCalledWith(
expect.objectContaining({
webhookMessageBody:
'example.com の有効期限が 12時間前 になりました。\n2026/05/25 20:30:00 に期限切れになります。',
}),
);
expect(mocks.client.release).toHaveBeenCalledOnce();
expect(result).toMatchObject({
checkedSites: 1,
@@ -490,4 +500,95 @@ describe('certificate monitoring', () => {
results: [{ siteId: SITE_ID, ok: true, alertsCreated: 1 }],
});
});
it('renders a custom webhook message with the configured timezone and timing labels', async () => {
vi.setSystemTime(new Date('2026-12-24T05:36:07.000Z'));
const issuer = 'C = US, O = Example CA, CN = Example Root';
const issuedAt = new Date('2026-01-01T00:00:00.000Z');
const expiresAt = new Date('2026-12-31T05:06:07.000Z');
getCertificateExpiry.mockResolvedValue({
issuer,
issuedAt,
expiresAt,
hoursUntilExpiry: 168,
});
deliverNotifications.mockResolvedValue({
webhook: [],
push: { ok: false, skipped: true },
});
mocks.client.query.mockImplementation(async (sql, params) => {
if (sql.includes('FROM sites s') && sql.includes('LEFT JOIN site_alert_conditions')) {
return {
rows: [
{
site_id: SITE_ID,
user_id: USER_ID,
url: 'https://example.com/',
alias: 'Example Site',
conditions: [
{
site_alert_condition_id: CONDITION_ID,
threshold_hours: 168,
webhook_method_ids: [WEBHOOK_ID],
push_enabled: false,
},
],
},
],
};
}
if (sql.includes('SET certificate_issuer')) {
expect(params).toEqual([SITE_ID, issuer, issuedAt, expiresAt]);
return { rows: [] };
}
if (sql.includes('FROM notification_methods') && sql.includes("notification_type = 'webhook'")) {
return {
rows: [
{
notification_method_id: WEBHOOK_ID,
alias: 'Deploy hook',
url: 'https://hooks.example.com/',
},
],
};
}
if (sql.includes('FROM user_notification_settings')) {
expect(params).toEqual([USER_ID]);
return {
rows: [
{
webhook_message_template:
'{{siteName}}/{{siteDomain}}/{{condTiming}}/{{expiryDate}}/{{expiryTime}}/{{expiryDateTime}}',
timezone: 'America/New_York',
},
],
};
}
if (sql.includes('INSERT INTO alert_history')) {
return { rows: [{ alert_id: '77777777-7777-4777-8777-777777777777' }] };
}
if (sql.includes('UPDATE site_alert_conditions')) {
expect(params).toEqual([CONDITION_ID, expiresAt]);
return { rows: [] };
}
throw new Error(`Unexpected query: ${sql}`);
});
await runCertificateMonitoring({ concurrency: 1 });
expect(deliverNotifications).toHaveBeenCalledWith(
expect.objectContaining({
webhookMessageBody:
'Example Site/example.com/1週間前/2026/12/31/00:06:07/2026/12/31 00:06:07',
}),
);
});
});