feat(ee): SIEM (#2471)

This commit is contained in:
Philip Okugbe
2026-09-04 14:53:14 +01:00
committed by GitHub
parent 5b85464561
commit 0d69d48c52
43 changed files with 2612 additions and 122 deletions
@@ -0,0 +1,66 @@
import { Kysely, sql } from 'kysely';
export async function up(db: Kysely<any>): Promise<void> {
await db.schema
.createTable('siem_destinations')
.ifNotExists()
.addColumn('id', 'uuid', (col) =>
col.primaryKey().defaultTo(sql`gen_uuid_v7()`),
)
.addColumn('workspace_id', 'uuid', (col) =>
col.notNull().references('workspaces.id').onDelete('cascade'),
)
.addColumn('name', 'varchar', (col) => col.notNull())
.addColumn('type', 'varchar', (col) => col.notNull())
.addColumn('enabled', 'boolean', (col) => col.notNull().defaultTo(true))
.addColumn('config', 'jsonb', (col) => col.notNull())
.addColumn('secrets', 'text', (col) => col.notNull())
.addColumn('cursor_created_at', 'timestamptz', (col) =>
col.notNull().defaultTo(sql`now()`),
)
.addColumn('cursor_id', 'uuid', (col) =>
col.notNull().defaultTo(sql`gen_uuid_v7()`),
)
.addColumn('cursor_snapshot', 'text')
// Fences cursor writes from stale jobs after configuration changes.
.addColumn('version', 'integer', (col) => col.notNull().defaultTo(0))
.addColumn('status', 'varchar', (col) => col.notNull().defaultTo('healthy'))
.addColumn('consecutive_failures', 'integer', (col) =>
col.notNull().defaultTo(0),
)
.addColumn('next_attempt_at', 'timestamptz')
.addColumn('last_delivered_at', 'timestamptz')
.addColumn('last_error', 'text')
.addColumn('last_error_at', 'timestamptz')
.addColumn('failing_since', 'timestamptz')
.addColumn('creator_id', 'uuid', (col) =>
col.references('users.id').onDelete('set null'),
)
.addColumn('created_at', 'timestamptz', (col) =>
col.notNull().defaultTo(sql`now()`),
)
.addColumn('updated_at', 'timestamptz', (col) =>
col.notNull().defaultTo(sql`now()`),
)
.execute();
await db.schema
.createIndex('idx_siem_destinations_workspace_id')
.ifNotExists()
.on('siem_destinations')
.columns(['workspace_id'])
.execute();
await sql`
CREATE INDEX IF NOT EXISTS idx_siem_destinations_due
ON siem_destinations (next_attempt_at)
WHERE enabled = true
`.execute(db);
await db.schema.alterTable('audit').addColumn('user_agent', 'text').execute();
}
export async function down(db: Kysely<any>): Promise<void> {
await db.schema.alterTable('audit').dropColumn('user_agent').execute();
await db.schema.dropTable('siem_destinations').ifExists().execute();
}
+26
View File
@@ -74,6 +74,7 @@ export interface Audit {
resourceId: string | null;
resourceType: string;
spaceId: string | null;
userAgent: string | null;
workspaceId: string;
}
@@ -361,6 +362,30 @@ export interface SpaceMembers {
userId: string | null;
}
export interface SiemDestinations {
config: Json;
consecutiveFailures: Generated<number>;
createdAt: Generated<Timestamp>;
creatorId: string | null;
cursorCreatedAt: Generated<Timestamp>;
cursorId: Generated<string>;
cursorSnapshot: string | null;
enabled: Generated<boolean>;
failingSince: Timestamp | null;
id: Generated<string>;
lastDeliveredAt: Timestamp | null;
lastError: string | null;
lastErrorAt: Timestamp | null;
name: string;
nextAttemptAt: Timestamp | null;
secrets: string;
status: Generated<string>;
type: string;
updatedAt: Generated<Timestamp>;
version: Generated<number>;
workspaceId: string;
}
export interface Spaces {
createdAt: Generated<Timestamp>;
creatorId: string | null;
@@ -724,6 +749,7 @@ export interface DB {
pages: Pages;
scimTokens: ScimTokens;
shares: Shares;
siemDestinations: SiemDestinations;
spaceMembers: SpaceMembers;
spaces: Spaces;
templates: Templates;
@@ -37,6 +37,7 @@ import {
UserSessions,
ApiKeys,
ScimTokens,
SiemDestinations,
Watchers,
Audit as _Audit,
Templates,
@@ -267,3 +268,8 @@ export type UpdatableBaseRow = Updateable<Omit<BaseRows, 'id'>>;
export type BaseView = Selectable<BaseViews>;
export type InsertableBaseView = Insertable<BaseViews>;
export type UpdatableBaseView = Updateable<Omit<BaseViews, 'id'>>;
// SIEM destinations
export type SiemDestination = Selectable<SiemDestinations>;
export type InsertableSiemDestination = Insertable<SiemDestinations>;
export type UpdatableSiemDestination = Updateable<Omit<SiemDestinations, 'id'>>;