Files
auth-portal/packages/shared/src/contracts/audit.ts
T
Denozordec c48132e89e fix(api): ошибки типов, скрытые отсутствием typecheck
- jose v6 не экспортирует KeyLike → CryptoKey
- SimpleWebAuthn v13 требует Uint8Array<ArrayBuffer>
- targetType 'credential' в AUDIT_TARGET_TYPES (писался в аудит passkey-ов)
- target-app: начальные значения host/path/search никогда не читались
2026-09-23 14:51:38 +07:00

137 lines
4.2 KiB
TypeScript

import { z } from 'zod'
export const AUDIT_SEVERITIES = ['info', 'warning', 'critical'] as const
export type AuditSeverity = (typeof AUDIT_SEVERITIES)[number]
export const auditSeveritySchema = z.enum(AUDIT_SEVERITIES)
export const AUDIT_SOURCE_APPS = [
'portal',
'vps',
'cfdm',
'bgp',
'fw',
'dns',
'cdn',
'mm',
] as const
export type AuditSourceApp = (typeof AUDIT_SOURCE_APPS)[number]
export const auditSourceAppSchema = z.enum(AUDIT_SOURCE_APPS)
export const AUDIT_TARGET_TYPES = [
'user',
'settings',
'session',
'system',
'app_resource',
'credential',
] as const
export type AuditTargetType = (typeof AUDIT_TARGET_TYPES)[number]
export const auditTargetTypeSchema = z.enum(AUDIT_TARGET_TYPES)
/** Well-known portal-native action keys. */
export const AUDIT_ACTIONS = [
'auth.login',
'auth.login_failed',
'auth.logout',
'auth.sso_handoff',
'user.create',
'user.update',
'user.delete',
'user.access_update',
'app_switcher.update',
'audit.settings_update',
'audit.purge',
] as const
export type AuditAction = (typeof AUDIT_ACTIONS)[number]
export const auditActionSchema = z.enum(AUDIT_ACTIONS)
export const AUDIT_KINDS = ['logins', 'changes'] as const
export type AuditKind = (typeof AUDIT_KINDS)[number]
export const auditKindSchema = z.enum(AUDIT_KINDS)
export const AUTH_AUDIT_ACTIONS = [
'auth.login',
'auth.login_failed',
'auth.logout',
'auth.sso_handoff',
] as const
export const auditLogEntrySchema = z.object({
id: z.string(),
event_id: z.string().nullable(),
source_app: auditSourceAppSchema,
action: z.string(),
severity: auditSeveritySchema,
actor_user_id: z.string().nullable(),
actor_email: z.string().nullable(),
actor_name: z.string().nullable(),
target_type: auditTargetTypeSchema.nullable(),
target_id: z.string().nullable(),
summary: z.string(),
details: z.record(z.string(), z.unknown()).nullable(),
ip: z.string().nullable(),
created_at: z.string(),
})
export type AuditLogEntry = z.infer<typeof auditLogEntrySchema>
export const auditListQuerySchema = z.object({
action: z.string().optional(),
severity: auditSeveritySchema.optional(),
user_id: z.string().optional(),
actor_email: z.string().email().optional(),
source_app: auditSourceAppSchema.optional(),
kind: auditKindSchema.optional(),
limit: z.coerce.number().int().min(1).max(500).default(200),
})
export type AuditListQuery = z.infer<typeof auditListQuerySchema>
export const DEFAULT_AUDIT_RETENTION_DAYS = 90
export const MIN_AUDIT_RETENTION_DAYS = 7
export const MAX_AUDIT_RETENTION_DAYS = 3650
export const auditSettingsSchema = z.object({
retention_days: z
.number()
.int()
.min(MIN_AUDIT_RETENTION_DAYS)
.max(MAX_AUDIT_RETENTION_DAYS),
})
export type AuditSettings = z.infer<typeof auditSettingsSchema>
export const putAuditSettingsSchema = auditSettingsSchema
export type PutAuditSettings = z.infer<typeof putAuditSettingsSchema>
export const auditPurgeResponseSchema = z.object({
deleted: z.number().int().nonnegative(),
retention_days: z.number().int(),
})
export type AuditPurgeResponse = z.infer<typeof auditPurgeResponseSchema>
export const ingestAuditEventSchema = z.object({
event_id: z.string().min(1).max(128),
source_app: z.enum(['vps', 'cfdm', 'bgp', 'fw', 'dns', 'cdn', 'mm']),
action: z.string().min(1).max(200),
severity: auditSeveritySchema.optional(),
actor_user_id: z.string().nullable().optional(),
actor_email: z.string().email().nullable().optional(),
actor_name: z.string().nullable().optional(),
target_type: auditTargetTypeSchema.nullable().optional(),
target_id: z.string().nullable().optional(),
summary: z.string().min(1).max(500),
details: z.record(z.string(), z.unknown()).nullable().optional(),
ip: z.string().nullable().optional(),
created_at: z.string().optional(),
})
export type IngestAuditEvent = z.infer<typeof ingestAuditEventSchema>
export const ingestAuditRequestSchema = z.object({
events: z.array(ingestAuditEventSchema).min(1).max(50),
})
export type IngestAuditRequest = z.infer<typeof ingestAuditRequestSchema>
export const ingestAuditResponseSchema = z.object({
accepted: z.number().int().nonnegative(),
duplicates: z.number().int().nonnegative(),
})
export type IngestAuditResponse = z.infer<typeof ingestAuditResponseSchema>