feat(audit): Add core audit logging infrastructure

- Add AuditLogger class with rotation support
- Add audit configuration to config schema
- Instrument tool execution with full audit logging
- Instrument session lifecycle (create, message, delete, transfer, compact)
- Add audit logger initialization in daemon
- Add cron scheduler audit logging

Audit events captured:
- tool.start/success/error/denied
- session.create/message/delete/transfer/compact
- cron.trigger/add/remove

All logs go to ~/.local/share/flynn/audit.log (JSON lines)
with rotation (10MB files, 30-day retention)
This commit is contained in:
William Valentin
2026-02-11 15:58:07 -08:00
parent fae3565480
commit d62e836b5d
12 changed files with 732 additions and 1 deletions
+16
View File
@@ -1,6 +1,7 @@
import { Cron } from 'croner';
import type { CronJobConfig } from '../config/schema.js';
import type { ChannelAdapter, ChannelStatus, InboundMessage, OutboundMessage } from '../channels/types.js';
import { auditLogger } from '../audit/index.js';
/** Minimal interface for the parts of ChannelRegistry we need. */
interface ChannelLookup {
@@ -46,6 +47,7 @@ export class CronScheduler implements ChannelAdapter {
const enabledCount = this.jobConfigs.filter(j => j.enabled).length;
if (enabledCount > 0) {
console.log(`CronScheduler: ${enabledCount} job(s) scheduled`);
auditLogger?.systemStart('CronScheduler', { jobs_enabled: enabledCount });
}
}
@@ -55,6 +57,7 @@ export class CronScheduler implements ChannelAdapter {
}
this.cronInstances.clear();
this._status = 'disconnected';
auditLogger?.systemStop('CronScheduler');
}
async send(peerId: string, message: OutboundMessage): Promise<void> {
@@ -93,6 +96,14 @@ export class CronScheduler implements ChannelAdapter {
metadata: { cronJob: jobName, scheduled: true, modelTier: job.model_tier },
};
auditLogger?.cronTrigger({
job_name: jobName,
schedule: job.schedule,
message: job.message,
output_channel: job.output.channel,
output_peer: job.output.peer,
});
this.messageHandler?.(msg);
}
@@ -118,6 +129,8 @@ export class CronScheduler implements ChannelAdapter {
this.jobs.set(config.name, config);
auditLogger?.cronAdd(config.name, config.schedule);
if (config.enabled && this._status === 'connected') {
const cronInstance = new Cron(config.schedule, {
timezone: config.timezone,
@@ -148,6 +161,9 @@ export class CronScheduler implements ChannelAdapter {
}
this.jobs.delete(name);
auditLogger?.cronRemove(name);
return true;
}
}