feat: add Patchmon Sync job
Syncs patchmon field on instances by querying the Patchmon hosts API and matching hostnames. API token masked as REDACTED in responses. seedJobs now uses INSERT OR IGNORE so new jobs are seeded on existing installs without re-running the full seed. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -460,6 +460,12 @@ const testJob = {
|
||||
config: JSON.stringify({ api_key: 'tskey-test', tailnet: 'example.com' }),
|
||||
}
|
||||
|
||||
const patchmonJob = {
|
||||
key: 'patchmon_sync', name: 'Patchmon Sync', description: 'Test patchmon job',
|
||||
enabled: 0, schedule: 60,
|
||||
config: JSON.stringify({ api_url: 'http://patchmon:3000/api/v1/api/hosts', api_token: 'secret-token' }),
|
||||
}
|
||||
|
||||
// ── GET /api/jobs ─────────────────────────────────────────────────────────────
|
||||
|
||||
describe('GET /api/jobs', () => {
|
||||
@@ -475,6 +481,12 @@ describe('GET /api/jobs', () => {
|
||||
expect(res.body).toHaveLength(1)
|
||||
expect(res.body[0].config.api_key).toBe('**REDACTED**')
|
||||
})
|
||||
|
||||
it('returns jobs with masked api_token', async () => {
|
||||
createJob(patchmonJob)
|
||||
const res = await request(app).get('/api/jobs')
|
||||
expect(res.body[0].config.api_token).toBe('**REDACTED**')
|
||||
})
|
||||
})
|
||||
|
||||
// ── GET /api/jobs/:id ─────────────────────────────────────────────────────────
|
||||
@@ -554,4 +566,23 @@ describe('POST /api/jobs/:id/run', () => {
|
||||
const detail = await request(app).get(`/api/jobs/${id}`)
|
||||
expect(detail.body.runs[0].status).toBe('error')
|
||||
})
|
||||
|
||||
it('patchmon_sync: marks instances present in host list as patchmon=1', async () => {
|
||||
createJob(patchmonJob)
|
||||
const id = (await request(app).get('/api/jobs')).body[0].id
|
||||
vi.stubGlobal('fetch', vi.fn().mockResolvedValueOnce({
|
||||
ok: true,
|
||||
json: async () => [{ name: 'plex' }, { name: 'traefik' }],
|
||||
}))
|
||||
const res = await request(app).post(`/api/jobs/${id}/run`)
|
||||
expect(res.status).toBe(200)
|
||||
expect(res.body.summary).toMatch(/updated of/)
|
||||
})
|
||||
|
||||
it('patchmon_sync: returns 500 when API token is missing', async () => {
|
||||
createJob({ ...patchmonJob, config: JSON.stringify({ api_url: 'http://patchmon:3000/api/v1/api/hosts', api_token: '' }) })
|
||||
const id = (await request(app).get('/api/jobs')).body[0].id
|
||||
const res = await request(app).post(`/api/jobs/${id}/run`)
|
||||
expect(res.status).toBe(500)
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user