Add drift report submission + stack deletion endpoints to P2
This commit is contained in:
@@ -1,7 +1,59 @@
|
||||
import { FastifyInstance } from 'fastify';
|
||||
import { z } from 'zod';
|
||||
import crypto from 'crypto';
|
||||
import { withTenant } from '../data/db.js';
|
||||
|
||||
const submitReportSchema = z.object({
|
||||
stack_name: z.string().min(1).max(200),
|
||||
stack_fingerprint: z.string().min(1),
|
||||
agent_version: z.string().default('manual'),
|
||||
scanned_at: z.string().datetime().optional(),
|
||||
state_serial: z.number().int().min(0),
|
||||
lineage: z.string().default('manual'),
|
||||
total_resources: z.number().int().min(0),
|
||||
drift_score: z.number().min(0).max(100),
|
||||
raw_report: z.record(z.unknown()).default({}),
|
||||
});
|
||||
|
||||
export async function registerApiRoutes(app: FastifyInstance) {
|
||||
// Submit a drift report (from agent or manual)
|
||||
app.post('/api/v1/reports', async (request, reply) => {
|
||||
const tenantId = (request as any).tenantId;
|
||||
const pool = (app as any).pool;
|
||||
const body = submitReportSchema.parse(request.body);
|
||||
const nonce = crypto.randomUUID();
|
||||
|
||||
const result = await withTenant(pool, tenantId, async (client) => {
|
||||
const { rows } = await client.query(
|
||||
`INSERT INTO drift_reports (tenant_id, stack_name, stack_fingerprint, agent_version, scanned_at, state_serial, lineage, total_resources, drift_score, nonce, raw_report)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
|
||||
RETURNING id, stack_name, drift_score, scanned_at`,
|
||||
[tenantId, body.stack_name, body.stack_fingerprint, body.agent_version,
|
||||
body.scanned_at ?? new Date().toISOString(), body.state_serial, body.lineage,
|
||||
body.total_resources, body.drift_score, nonce, JSON.stringify(body.raw_report)]
|
||||
);
|
||||
return rows[0];
|
||||
});
|
||||
|
||||
return reply.status(201).send({ report: result });
|
||||
});
|
||||
|
||||
// Delete all reports for a stack
|
||||
app.delete('/api/v1/stacks/:stackName', async (request, reply) => {
|
||||
const tenantId = (request as any).tenantId;
|
||||
const { stackName } = request.params as { stackName: string };
|
||||
const pool = (app as any).pool;
|
||||
|
||||
await withTenant(pool, tenantId, async (client) => {
|
||||
await client.query(
|
||||
'DELETE FROM drift_reports WHERE tenant_id = $1 AND stack_name = $2',
|
||||
[tenantId, stackName]
|
||||
);
|
||||
});
|
||||
|
||||
return reply.status(200).send({ status: 'deleted', stack_name: stackName });
|
||||
});
|
||||
|
||||
// List stacks
|
||||
app.get('/api/v1/stacks', async (request, reply) => {
|
||||
const tenantId = (request as any).tenantId;
|
||||
|
||||
Reference in New Issue
Block a user