feat(bot): add secure reminder job runtime

This commit is contained in:
2026-03-08 22:15:01 +04:00
parent f6d1f34acf
commit 6c0dbfc48e
14 changed files with 670 additions and 4 deletions

View File

@@ -6,7 +6,17 @@ describe('createBotWebhookServer', () => {
const server = createBotWebhookServer({
webhookPath: '/webhook/telegram',
webhookSecret: 'secret-token',
webhookHandler: async () => new Response('ok', { status: 200 })
webhookHandler: async () => new Response('ok', { status: 200 }),
scheduler: {
sharedSecret: 'scheduler-secret',
handler: async (_request, reminderType) =>
new Response(JSON.stringify({ ok: true, reminderType }), {
status: 200,
headers: {
'content-type': 'application/json; charset=utf-8'
}
})
}
})
test('returns health payload', async () => {
@@ -59,4 +69,46 @@ describe('createBotWebhookServer', () => {
expect(response.status).toBe(200)
expect(await response.text()).toBe('ok')
})
test('rejects scheduler request with missing secret', async () => {
const response = await server.fetch(
new Request('http://localhost/jobs/reminder/utilities', {
method: 'POST',
body: JSON.stringify({ period: '2026-03' })
})
)
expect(response.status).toBe(401)
})
test('rejects non-post method for scheduler endpoint', async () => {
const response = await server.fetch(
new Request('http://localhost/jobs/reminder/utilities', {
method: 'GET',
headers: {
'x-household-scheduler-secret': 'scheduler-secret'
}
})
)
expect(response.status).toBe(405)
})
test('accepts authorized scheduler request', async () => {
const response = await server.fetch(
new Request('http://localhost/jobs/reminder/rent-due', {
method: 'POST',
headers: {
'x-household-scheduler-secret': 'scheduler-secret'
},
body: JSON.stringify({ period: '2026-03' })
})
)
expect(response.status).toBe(200)
expect(await response.json()).toEqual({
ok: true,
reminderType: 'rent-due'
})
})
})