This commit introduces a complete transparency infrastructure including: Core Transparency Modules: - AuditLog: Immutable, cryptographically-linked audit trail for all actions - EventStream: Real-time SSE streaming and webhook support - TransparencyDashboard: Aggregated metrics and system health monitoring - DigitalSignatures: Cryptographic verification for handoffs and certificates API Endpoints: - /api/transparency/dashboard - Full platform metrics - /api/transparency/audit - Query and log audit entries - /api/transparency/events - SSE stream and event history - /api/transparency/webhooks - Webhook management - /api/transparency/signatures - Digital signature operations - /api/transparency/certificate/[plantId] - Plant authenticity certificates - /api/transparency/export - Multi-format data export - /api/transparency/report - Compliance reporting - /api/transparency/health - System health checks Features: - Immutable audit logging with chain integrity verification - Real-time event streaming via Server-Sent Events - Webhook support with HMAC signature verification - Digital signatures for transport handoffs and ownership transfers - Certificate of Authenticity generation for plants - Multi-format data export (JSON, CSV, summary) - Public transparency portal at /transparency - System health monitoring for all components Documentation: - Comprehensive TRANSPARENCY.md guide with API examples
128 lines
3.6 KiB
TypeScript
128 lines
3.6 KiB
TypeScript
/**
|
|
* Audit Log API
|
|
* GET /api/transparency/audit - Query audit entries
|
|
* POST /api/transparency/audit - Log a custom audit entry
|
|
*
|
|
* Provides access to the immutable audit trail.
|
|
*/
|
|
|
|
import type { NextApiRequest, NextApiResponse } from 'next';
|
|
import { getAuditLog, AuditQuery, AuditAction, AuditCategory, AuditSeverity } from '../../../lib/transparency';
|
|
|
|
export default async function handler(
|
|
req: NextApiRequest,
|
|
res: NextApiResponse
|
|
) {
|
|
const auditLog = getAuditLog();
|
|
|
|
if (req.method === 'GET') {
|
|
try {
|
|
const {
|
|
startDate,
|
|
endDate,
|
|
actions,
|
|
categories,
|
|
severities,
|
|
actorId,
|
|
actorType,
|
|
resourceType,
|
|
resourceId,
|
|
correlationId,
|
|
search,
|
|
limit = '100',
|
|
offset = '0',
|
|
format = 'json'
|
|
} = req.query;
|
|
|
|
const query: AuditQuery = {
|
|
startDate: startDate as string,
|
|
endDate: endDate as string,
|
|
actions: actions ? (actions as string).split(',') as AuditAction[] : undefined,
|
|
categories: categories ? (categories as string).split(',') as AuditCategory[] : undefined,
|
|
severities: severities ? (severities as string).split(',') as AuditSeverity[] : undefined,
|
|
actorId: actorId as string,
|
|
actorType: actorType as any,
|
|
resourceType: resourceType as string,
|
|
resourceId: resourceId as string,
|
|
correlationId: correlationId as string,
|
|
searchTerm: search as string,
|
|
limit: parseInt(limit as string, 10),
|
|
offset: parseInt(offset as string, 10)
|
|
};
|
|
|
|
// Handle different formats
|
|
if (format === 'csv') {
|
|
const csv = auditLog.export('csv', query);
|
|
res.setHeader('Content-Type', 'text/csv');
|
|
res.setHeader('Content-Disposition', 'attachment; filename=audit-log.csv');
|
|
return res.status(200).send(csv);
|
|
}
|
|
|
|
if (format === 'summary') {
|
|
const summary = auditLog.export('summary', query);
|
|
res.setHeader('Content-Type', 'text/plain');
|
|
return res.status(200).send(summary);
|
|
}
|
|
|
|
const result = auditLog.query(query);
|
|
|
|
return res.status(200).json({
|
|
success: true,
|
|
data: {
|
|
entries: result.entries,
|
|
total: result.total,
|
|
limit: query.limit,
|
|
offset: query.offset
|
|
}
|
|
});
|
|
} catch (error) {
|
|
console.error('[API] Audit query error:', error);
|
|
return res.status(500).json({
|
|
success: false,
|
|
error: 'Failed to query audit log'
|
|
});
|
|
}
|
|
}
|
|
|
|
if (req.method === 'POST') {
|
|
try {
|
|
const { action, category, description, severity, actor, resource, metadata } = req.body;
|
|
|
|
if (!action || !category || !description) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
error: 'Missing required fields: action, category, description'
|
|
});
|
|
}
|
|
|
|
const entry = auditLog.log(
|
|
action as AuditAction,
|
|
category as AuditCategory,
|
|
description,
|
|
{
|
|
severity: severity as AuditSeverity,
|
|
actor: {
|
|
...actor,
|
|
ip: req.headers['x-forwarded-for'] as string || req.socket.remoteAddress,
|
|
userAgent: req.headers['user-agent']
|
|
},
|
|
resource,
|
|
metadata
|
|
}
|
|
);
|
|
|
|
return res.status(201).json({
|
|
success: true,
|
|
data: entry
|
|
});
|
|
} catch (error) {
|
|
console.error('[API] Audit log error:', error);
|
|
return res.status(500).json({
|
|
success: false,
|
|
error: 'Failed to create audit entry'
|
|
});
|
|
}
|
|
}
|
|
|
|
return res.status(405).json({ error: 'Method not allowed' });
|
|
}
|