|
1 | 1 | import { auditLog, db } from '@sim/db' |
| 2 | +import { user } from '@sim/db/schema' |
2 | 3 | import { createLogger } from '@sim/logger' |
| 4 | +import { eq } from 'drizzle-orm' |
3 | 5 | import { nanoid } from 'nanoid' |
4 | 6 |
|
5 | 7 | const logger = createLogger('AuditLog') |
@@ -185,41 +187,58 @@ interface AuditLogParams { |
185 | 187 |
|
186 | 188 | /** |
187 | 189 | * Records an audit log entry. Fire-and-forget — never throws or blocks the caller. |
| 190 | + * If actorName and actorEmail are both undefined (not provided by the caller), |
| 191 | + * resolves them from the user table before inserting. |
188 | 192 | */ |
189 | 193 | export function recordAudit(params: AuditLogParams): void { |
190 | | - try { |
191 | | - const ipAddress = |
192 | | - params.request?.headers.get('x-forwarded-for')?.split(',')[0].trim() ?? |
193 | | - params.request?.headers.get('x-real-ip') ?? |
194 | | - undefined |
195 | | - const userAgent = params.request?.headers.get('user-agent') ?? undefined |
196 | | - |
197 | | - db.insert(auditLog) |
198 | | - .values({ |
199 | | - id: nanoid(), |
200 | | - workspaceId: params.workspaceId || null, |
201 | | - actorId: params.actorId, |
202 | | - action: params.action, |
203 | | - resourceType: params.resourceType, |
204 | | - resourceId: params.resourceId, |
205 | | - actorName: params.actorName ?? undefined, |
206 | | - actorEmail: params.actorEmail ?? undefined, |
207 | | - resourceName: params.resourceName, |
208 | | - description: params.description, |
209 | | - metadata: params.metadata ?? {}, |
210 | | - ipAddress, |
211 | | - userAgent, |
212 | | - }) |
213 | | - .then(() => { |
214 | | - logger.debug('Audit log recorded', { |
215 | | - action: params.action, |
216 | | - resourceType: params.resourceType, |
217 | | - }) |
218 | | - }) |
219 | | - .catch((error) => { |
220 | | - logger.error('Failed to record audit log', { error, action: params.action }) |
221 | | - }) |
222 | | - } catch (error) { |
223 | | - logger.error('Failed to initiate audit log', { error, action: params.action }) |
| 194 | + insertAuditLog(params).catch((error) => { |
| 195 | + logger.error('Failed to record audit log', { error, action: params.action }) |
| 196 | + }) |
| 197 | +} |
| 198 | + |
| 199 | +async function insertAuditLog(params: AuditLogParams): Promise<void> { |
| 200 | + const ipAddress = |
| 201 | + params.request?.headers.get('x-forwarded-for')?.split(',')[0].trim() ?? |
| 202 | + params.request?.headers.get('x-real-ip') ?? |
| 203 | + undefined |
| 204 | + const userAgent = params.request?.headers.get('user-agent') ?? undefined |
| 205 | + |
| 206 | + let { actorName, actorEmail } = params |
| 207 | + |
| 208 | + // Only look up if the caller didn't provide either field at all. |
| 209 | + // Explicit null (e.g. user with no display name) is respected as-is. |
| 210 | + if (actorName === undefined && actorEmail === undefined && params.actorId) { |
| 211 | + try { |
| 212 | + const [row] = await db |
| 213 | + .select({ name: user.name, email: user.email }) |
| 214 | + .from(user) |
| 215 | + .where(eq(user.id, params.actorId)) |
| 216 | + .limit(1) |
| 217 | + actorName = row?.name ?? null |
| 218 | + actorEmail = row?.email ?? null |
| 219 | + } catch { |
| 220 | + // Lookup failure is non-fatal — insert without actor info |
| 221 | + } |
224 | 222 | } |
| 223 | + |
| 224 | + await db.insert(auditLog).values({ |
| 225 | + id: nanoid(), |
| 226 | + workspaceId: params.workspaceId || null, |
| 227 | + actorId: params.actorId, |
| 228 | + action: params.action, |
| 229 | + resourceType: params.resourceType, |
| 230 | + resourceId: params.resourceId, |
| 231 | + actorName: actorName ?? undefined, |
| 232 | + actorEmail: actorEmail ?? undefined, |
| 233 | + resourceName: params.resourceName, |
| 234 | + description: params.description, |
| 235 | + metadata: params.metadata ?? {}, |
| 236 | + ipAddress, |
| 237 | + userAgent, |
| 238 | + }) |
| 239 | + |
| 240 | + logger.debug('Audit log recorded', { |
| 241 | + action: params.action, |
| 242 | + resourceType: params.resourceType, |
| 243 | + }) |
225 | 244 | } |
0 commit comments