@h-ai/audit 0.1.0-alpha9 → 1.0.0-beta.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +199 -0
- package/README.ja.md +199 -0
- package/README.md +108 -22
- package/dist/index.d.ts +359 -76
- package/dist/index.js +1163 -144
- package/dist/index.js.map +1 -1
- package/package.json +35 -10
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
|
+
import { ReachFunctions } from '@h-ai/reach';
|
|
2
|
+
import { StorageFunctions } from '@h-ai/storage';
|
|
1
3
|
import { z } from 'zod';
|
|
2
4
|
import * as _h_ai_core from '@h-ai/core';
|
|
3
|
-
import { HaiResult } from '@h-ai/core';
|
|
5
|
+
import { HaiResult, PaginationOptionsInput, PaginatedResult } from '@h-ai/core';
|
|
6
|
+
import * as _h_ai_reldb from '@h-ai/reldb';
|
|
7
|
+
import { DmlWithTxOperations } from '@h-ai/reldb';
|
|
8
|
+
import { SchedulerInitInput } from '@h-ai/scheduler';
|
|
4
9
|
|
|
5
10
|
/**
|
|
6
11
|
* @h-ai/audit — 错误码与配置
|
|
@@ -13,32 +18,111 @@ import { HaiResult } from '@h-ai/core';
|
|
|
13
18
|
* 审计模块初始化配置 Schema(Zod)
|
|
14
19
|
*
|
|
15
20
|
* 所有字段均有默认值,可直接调用 `audit.init()` 无需传参。
|
|
16
|
-
*
|
|
17
21
|
* @example
|
|
18
22
|
* ```ts
|
|
19
|
-
* import {
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* await audit.init()
|
|
23
|
-
*
|
|
24
|
-
* // 自定义用户表映射
|
|
25
|
-
* await audit.init({
|
|
26
|
-
* userTable: 'sys_users',
|
|
27
|
-
* userIdColumn: 'user_id',
|
|
28
|
-
* userNameColumn: 'name',
|
|
29
|
-
* })
|
|
23
|
+
* import { AuditInitConfigSchema } from '@h-ai/audit'
|
|
24
|
+
* const config = AuditInitConfigSchema.parse({ userTable: 'app_users' })
|
|
25
|
+
* // 这里只校验字段映射;实际初始化前必须已有可用的 RelDB。
|
|
30
26
|
* ```
|
|
31
27
|
*/
|
|
32
28
|
declare const AuditInitConfigSchema: z.ZodObject<{
|
|
29
|
+
alerts: z.ZodDefault<z.ZodObject<{
|
|
30
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
31
|
+
maxNotificationsPerCheck: z.ZodDefault<z.ZodNumber>;
|
|
32
|
+
rules: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
33
|
+
id: z.ZodString;
|
|
34
|
+
actions: z.ZodArray<z.ZodString>;
|
|
35
|
+
resource: z.ZodOptional<z.ZodString>;
|
|
36
|
+
outcomes: z.ZodDefault<z.ZodArray<z.ZodEnum<{
|
|
37
|
+
success: "success";
|
|
38
|
+
failure: "failure";
|
|
39
|
+
denied: "denied";
|
|
40
|
+
}>>>;
|
|
41
|
+
minimumSeverity: z.ZodDefault<z.ZodEnum<{
|
|
42
|
+
error: "error";
|
|
43
|
+
info: "info";
|
|
44
|
+
warning: "warning";
|
|
45
|
+
critical: "critical";
|
|
46
|
+
}>>;
|
|
47
|
+
severity: z.ZodDefault<z.ZodEnum<{
|
|
48
|
+
error: "error";
|
|
49
|
+
warning: "warning";
|
|
50
|
+
critical: "critical";
|
|
51
|
+
}>>;
|
|
52
|
+
threshold: z.ZodDefault<z.ZodNumber>;
|
|
53
|
+
windowSeconds: z.ZodDefault<z.ZodNumber>;
|
|
54
|
+
targets: z.ZodArray<z.ZodObject<{
|
|
55
|
+
id: z.ZodString;
|
|
56
|
+
provider: z.ZodString;
|
|
57
|
+
to: z.ZodString;
|
|
58
|
+
}, z.core.$strip>>;
|
|
59
|
+
}, z.core.$strip>>>;
|
|
60
|
+
schedule: z.ZodDefault<z.ZodObject<{
|
|
61
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
62
|
+
cron: z.ZodDefault<z.ZodString>;
|
|
63
|
+
timezone: z.ZodDefault<z.ZodString>;
|
|
64
|
+
}, z.core.$strip>>;
|
|
65
|
+
}, z.core.$strip>>;
|
|
66
|
+
backup: z.ZodDefault<z.ZodObject<{
|
|
67
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
68
|
+
batchSize: z.ZodDefault<z.ZodNumber>;
|
|
69
|
+
maxRecordBytes: z.ZodDefault<z.ZodNumber>;
|
|
70
|
+
schedule: z.ZodDefault<z.ZodObject<{
|
|
71
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
72
|
+
cron: z.ZodDefault<z.ZodString>;
|
|
73
|
+
timezone: z.ZodDefault<z.ZodString>;
|
|
74
|
+
}, z.core.$strip>>;
|
|
75
|
+
}, z.core.$strip>>;
|
|
76
|
+
capture: z.ZodDefault<z.ZodObject<{
|
|
77
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
78
|
+
includeReads: z.ZodDefault<z.ZodBoolean>;
|
|
79
|
+
}, z.core.$strip>>;
|
|
80
|
+
retention: z.ZodOptional<z.ZodObject<{
|
|
81
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
82
|
+
minDays: z.ZodDefault<z.ZodNumber>;
|
|
83
|
+
}, z.core.$strip>>;
|
|
84
|
+
privacy: z.ZodDefault<z.ZodObject<{
|
|
85
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
86
|
+
fields: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
87
|
+
}, z.core.$strip>>;
|
|
33
88
|
userTable: z.ZodDefault<z.ZodString>;
|
|
34
89
|
userIdColumn: z.ZodDefault<z.ZodString>;
|
|
35
90
|
userNameColumn: z.ZodDefault<z.ZodString>;
|
|
36
91
|
}, z.core.$strip>;
|
|
37
|
-
/**
|
|
92
|
+
/**
|
|
93
|
+
* 审计模块初始化配置(解析后)
|
|
94
|
+
* @example
|
|
95
|
+
* ```ts
|
|
96
|
+
* import { AuditInitConfigSchema, type AuditInitConfig } from '@h-ai/audit'
|
|
97
|
+
* const config: AuditInitConfig = AuditInitConfigSchema.parse({ userTable: 'app_users' })
|
|
98
|
+
* ```
|
|
99
|
+
*/
|
|
38
100
|
type AuditInitConfig = z.output<typeof AuditInitConfigSchema>;
|
|
39
|
-
/**
|
|
40
|
-
|
|
101
|
+
/**
|
|
102
|
+
* 审计模块初始化配置(传入参数)
|
|
103
|
+
* @example
|
|
104
|
+
* ```ts
|
|
105
|
+
* import type { AuditInitConfigInput } from '@h-ai/audit'
|
|
106
|
+
* const record: AuditInitConfigInput = { userTable: 'app_users', userIdColumn: 'id', userNameColumn: 'username' }
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
109
|
+
type AuditInitConfigInput = z.input<typeof AuditInitConfigSchema> & {
|
|
110
|
+
/** 开启备份时注入已初始化且私有访问的存储;audit 不拥有它的生命周期。 */
|
|
111
|
+
storage?: StorageFunctions;
|
|
112
|
+
/** 开启告警时注入已初始化的 Reach;通知人员/目标仍由应用配置。 */
|
|
113
|
+
reach?: ReachFunctions;
|
|
114
|
+
};
|
|
41
115
|
|
|
116
|
+
/**
|
|
117
|
+
* 审计初始化、写入、查询和清理失败的稳定错误定义。
|
|
118
|
+
* @example
|
|
119
|
+
* ```ts
|
|
120
|
+
* import { HaiAuditError } from '@h-ai/audit'
|
|
121
|
+
* import { err } from '@h-ai/core'
|
|
122
|
+
* const failed = err(HaiAuditError.NOT_INITIALIZED, 'Audit is not initialized')
|
|
123
|
+
* if (!failed.success) failed.error.code
|
|
124
|
+
* ```
|
|
125
|
+
*/
|
|
42
126
|
declare const HaiAuditError: {
|
|
43
127
|
readonly LOG_FAILED: _h_ai_core.HaiErrorDef;
|
|
44
128
|
readonly QUERY_FAILED: _h_ai_core.HaiErrorDef;
|
|
@@ -47,13 +131,72 @@ declare const HaiAuditError: {
|
|
|
47
131
|
readonly INIT_IN_PROGRESS: _h_ai_core.HaiErrorDef;
|
|
48
132
|
readonly NOT_INITIALIZED: _h_ai_core.HaiErrorDef;
|
|
49
133
|
readonly CONFIG_ERROR: _h_ai_core.HaiErrorDef;
|
|
134
|
+
readonly BACKUP_DISABLED: _h_ai_core.HaiErrorDef;
|
|
135
|
+
readonly BACKUP_FAILED: _h_ai_core.HaiErrorDef;
|
|
136
|
+
readonly BACKUP_INVALID: _h_ai_core.HaiErrorDef;
|
|
137
|
+
readonly BACKUP_CONFLICT: _h_ai_core.HaiErrorDef;
|
|
138
|
+
readonly ALERTS_DISABLED: _h_ai_core.HaiErrorDef;
|
|
139
|
+
readonly ALERTS_FAILED: _h_ai_core.HaiErrorDef;
|
|
50
140
|
};
|
|
141
|
+
/**
|
|
142
|
+
* 事件发生时的最小身份快照,不承载授权真值或凭据。
|
|
143
|
+
* @example
|
|
144
|
+
* ```ts
|
|
145
|
+
* import type { AuditActorSnapshot } from '@h-ai/audit'
|
|
146
|
+
* const actor: AuditActorSnapshot = { id: 'user-1', username: 'alice', roles: ['auditor'] }
|
|
147
|
+
* ```
|
|
148
|
+
*/
|
|
149
|
+
interface AuditActorSnapshot {
|
|
150
|
+
id: string;
|
|
151
|
+
username?: string;
|
|
152
|
+
displayName?: string;
|
|
153
|
+
roles?: string[];
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* 异步请求的审计上下文;不替代会话校验或权限守卫。
|
|
157
|
+
* @example
|
|
158
|
+
* ```ts
|
|
159
|
+
* import type { AuditContext } from '@h-ai/audit'
|
|
160
|
+
* const context: AuditContext = { requestId: 'request-1', actor: { id: 'user-1', username: 'alice' }, ipAddress: '192.0.2.8' }
|
|
161
|
+
* ```
|
|
162
|
+
*/
|
|
163
|
+
interface AuditContext {
|
|
164
|
+
actor?: AuditActorSnapshot | null;
|
|
165
|
+
category?: 'system' | 'business';
|
|
166
|
+
requestId?: string;
|
|
167
|
+
traceId?: string;
|
|
168
|
+
scopeId?: string;
|
|
169
|
+
ipAddress?: string;
|
|
170
|
+
userAgent?: string;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* 分类、结果、等级及事件身份;旧记录升级前未知的值保持 null。
|
|
174
|
+
* @example
|
|
175
|
+
* ```ts
|
|
176
|
+
* import type { AuditEventFields } from '@h-ai/audit'
|
|
177
|
+
* const fields: AuditEventFields = { category: 'system', outcome: 'denied', severity: 'warning', requestId: 'request-1' }
|
|
178
|
+
* ```
|
|
179
|
+
*/
|
|
180
|
+
interface AuditEventFields {
|
|
181
|
+
category?: 'system' | 'business' | null;
|
|
182
|
+
outcome?: 'success' | 'failure' | 'denied' | null;
|
|
183
|
+
severity?: 'info' | 'warning' | 'error' | 'critical' | null;
|
|
184
|
+
requestId?: string | null;
|
|
185
|
+
traceId?: string | null;
|
|
186
|
+
scopeId?: string | null;
|
|
187
|
+
actorSnapshot?: AuditActorSnapshot | null;
|
|
188
|
+
}
|
|
51
189
|
/**
|
|
52
190
|
* 审计日志记录
|
|
53
191
|
*
|
|
54
192
|
* 表示一条已持久化的审计日志条目。
|
|
193
|
+
* @example
|
|
194
|
+
* ```ts
|
|
195
|
+
* import type { AuditLog } from '@h-ai/audit'
|
|
196
|
+
* const record: AuditLog = { id: 'audit_example', userId: 'user_1', action: 'create', resource: 'orders', resourceId: 'order_1', details: null, ipAddress: null, userAgent: null, createdAt: new Date() }
|
|
197
|
+
* ```
|
|
55
198
|
*/
|
|
56
|
-
interface AuditLog {
|
|
199
|
+
interface AuditLog extends AuditEventFields {
|
|
57
200
|
/** 审计日志 ID,格式为 `audit_` 前缀 + 随机串 */
|
|
58
201
|
id: string;
|
|
59
202
|
/** 操作用户 ID;系统操作时为 null */
|
|
@@ -76,7 +219,12 @@ interface AuditLog {
|
|
|
76
219
|
/**
|
|
77
220
|
* 审计日志记录(含用户名)
|
|
78
221
|
*
|
|
79
|
-
*
|
|
222
|
+
* 新记录使用事件时身份快照;无快照的历史记录才保留旧的用户表关联展示。
|
|
223
|
+
* @example
|
|
224
|
+
* ```ts
|
|
225
|
+
* import type { AuditLogWithUser } from '@h-ai/audit'
|
|
226
|
+
* const record: AuditLogWithUser = { id: 'audit_example', userId: 'user_1', action: 'create', resource: 'orders', resourceId: 'order_1', details: null, ipAddress: null, userAgent: null, createdAt: new Date() , username: 'alice' }
|
|
227
|
+
* ```
|
|
80
228
|
*/
|
|
81
229
|
interface AuditLogWithUser extends AuditLog {
|
|
82
230
|
/** 操作用户的用户名;用户不存在或系统操作时为 null */
|
|
@@ -87,8 +235,13 @@ interface AuditLogWithUser extends AuditLog {
|
|
|
87
235
|
*
|
|
88
236
|
* 调用 {@link AuditFunctions.log} 时传入的参数。
|
|
89
237
|
* 仅 `action` 和 `resource` 为必填。
|
|
238
|
+
* @example
|
|
239
|
+
* ```ts
|
|
240
|
+
* import type { CreateAuditLogInput } from '@h-ai/audit'
|
|
241
|
+
* const record: CreateAuditLogInput = { userId: 'user_1', action: 'create', resource: 'orders', resourceId: 'order_1', details: { status: 'pending' } }
|
|
242
|
+
* ```
|
|
90
243
|
*/
|
|
91
|
-
interface CreateAuditLogInput {
|
|
244
|
+
interface CreateAuditLogInput extends AuditEventFields {
|
|
92
245
|
/** 操作用户 ID;系统操作可省略 */
|
|
93
246
|
userId?: string | null;
|
|
94
247
|
/** 操作类型(如 login / create / update / delete) */
|
|
@@ -97,7 +250,7 @@ interface CreateAuditLogInput {
|
|
|
97
250
|
resource: string;
|
|
98
251
|
/** 资源 ID;不涉及特定资源时可省略 */
|
|
99
252
|
resourceId?: string | null;
|
|
100
|
-
/**
|
|
253
|
+
/** 操作详情对象;密码、token、secret 等凭证类字段会先自动脱敏,再 JSON 序列化存储 */
|
|
101
254
|
details?: Record<string, unknown> | null;
|
|
102
255
|
/** 客户端 IP 地址 */
|
|
103
256
|
ipAddress?: string | null;
|
|
@@ -108,8 +261,22 @@ interface CreateAuditLogInput {
|
|
|
108
261
|
* 审计日志列表查询选项
|
|
109
262
|
*
|
|
110
263
|
* 所有字段均为可选,不传则不过滤。
|
|
264
|
+
* @example
|
|
265
|
+
* ```ts
|
|
266
|
+
* import type { ListAuditLogsOptions } from '@h-ai/audit'
|
|
267
|
+
* const record: ListAuditLogsOptions = { action: 'create', resource: 'orders', page: 1, pageSize: 20 }
|
|
268
|
+
* ```
|
|
111
269
|
*/
|
|
112
|
-
interface ListAuditLogsOptions {
|
|
270
|
+
interface ListAuditLogsOptions extends PaginationOptionsInput {
|
|
271
|
+
/** 按可信入口生成或校验的请求/追踪编号定位关联事件。 */
|
|
272
|
+
requestId?: string;
|
|
273
|
+
traceId?: string;
|
|
274
|
+
category?: 'system' | 'business';
|
|
275
|
+
outcome?: 'success' | 'failure' | 'denied';
|
|
276
|
+
severity?: 'info' | 'warning' | 'error' | 'critical';
|
|
277
|
+
scopeId?: string;
|
|
278
|
+
sortBy?: 'createdAt' | 'action' | 'resource' | 'category' | 'outcome' | 'severity';
|
|
279
|
+
sortDirection?: 'asc' | 'desc';
|
|
113
280
|
/** 按用户 ID 过滤 */
|
|
114
281
|
userId?: string;
|
|
115
282
|
/** 按操作类型过滤(精确匹配) */
|
|
@@ -120,19 +287,16 @@ interface ListAuditLogsOptions {
|
|
|
120
287
|
startDate?: Date;
|
|
121
288
|
/** 结束时间(含),只返回此时间之前的日志 */
|
|
122
289
|
endDate?: Date;
|
|
123
|
-
/** 页码,从 1 开始 */
|
|
124
|
-
page?: number;
|
|
125
|
-
/**
|
|
126
|
-
* 每页条数
|
|
127
|
-
*
|
|
128
|
-
* @default 20
|
|
129
|
-
*/
|
|
130
|
-
pageSize?: number;
|
|
131
290
|
}
|
|
132
291
|
/**
|
|
133
292
|
* 审计统计结果项
|
|
134
293
|
*
|
|
135
294
|
* 按操作类型(action)分组的统计条目。
|
|
295
|
+
* @example
|
|
296
|
+
* ```ts
|
|
297
|
+
* import type { AuditStatItem } from '@h-ai/audit'
|
|
298
|
+
* const record: AuditStatItem = { action: 'create', count: 12 }
|
|
299
|
+
* ```
|
|
136
300
|
*/
|
|
137
301
|
interface AuditStatItem {
|
|
138
302
|
/** 操作类型 */
|
|
@@ -144,8 +308,13 @@ interface AuditStatItem {
|
|
|
144
308
|
* CRUD 审计操作输入
|
|
145
309
|
*
|
|
146
310
|
* 调用 {@link AuditHelper.crud} 时传入的参数。
|
|
311
|
+
* @example
|
|
312
|
+
* ```ts
|
|
313
|
+
* import type { CrudAuditInput } from '@h-ai/audit'
|
|
314
|
+
* const record: CrudAuditInput = { userId: 'user_1', action: 'update', resource: 'orders', resourceId: 'order_1', details: { status: 'paid' } }
|
|
315
|
+
* ```
|
|
147
316
|
*/
|
|
148
|
-
interface CrudAuditInput {
|
|
317
|
+
interface CrudAuditInput extends AuditEventFields {
|
|
149
318
|
/** 操作用户 ID(系统操作传 null) */
|
|
150
319
|
userId?: string | null;
|
|
151
320
|
/** 操作类型 */
|
|
@@ -166,11 +335,14 @@ interface CrudAuditInput {
|
|
|
166
335
|
*
|
|
167
336
|
* 封装常见审计场景(认证、CRUD),简化调用方代码。
|
|
168
337
|
* 通过 {@link AuditFunctions.helper} 访问。
|
|
169
|
-
*
|
|
170
338
|
* @example
|
|
171
339
|
* ```ts
|
|
172
|
-
*
|
|
173
|
-
*
|
|
340
|
+
* import type { AuditHelper } from '@h-ai/audit'
|
|
341
|
+
* // helper 来自已初始化的 audit;数据库生命周期归调用方。
|
|
342
|
+
* async function recordLogin(helper: AuditHelper) {
|
|
343
|
+
* const result = await helper.login('user_1', '127.0.0.1')
|
|
344
|
+
* return result.success ? 'recorded' : result.error.message
|
|
345
|
+
* }
|
|
174
346
|
* ```
|
|
175
347
|
*/
|
|
176
348
|
interface AuditHelper {
|
|
@@ -230,21 +402,45 @@ interface AuditHelper {
|
|
|
230
402
|
* 审计模块函数接口
|
|
231
403
|
*
|
|
232
404
|
* 统一的审计日志访问入口。
|
|
233
|
-
*
|
|
234
405
|
* @example
|
|
235
406
|
* ```ts
|
|
236
407
|
* import { audit } from '@h-ai/audit'
|
|
237
|
-
* import {
|
|
238
|
-
*
|
|
239
|
-
*
|
|
240
|
-
* await
|
|
241
|
-
*
|
|
242
|
-
*
|
|
243
|
-
*
|
|
244
|
-
*
|
|
408
|
+
* import { core } from '@h-ai/core'
|
|
409
|
+
* import { reldb, type ReldbConfigInput } from '@h-ai/reldb'
|
|
410
|
+
* async function recordCreation(config: ReldbConfigInput) {
|
|
411
|
+
* const database = await reldb.init(config)
|
|
412
|
+
* if (!database.success) return database
|
|
413
|
+
* try {
|
|
414
|
+
* const initialized = await audit.init()
|
|
415
|
+
* if (!initialized.success) return initialized
|
|
416
|
+
* const logged = await audit.log({ action: 'create', resource: 'orders', resourceId: 'order_1' })
|
|
417
|
+
* if (logged.success) core.logger.info('Audit recorded', { id: logged.data.id })
|
|
418
|
+
* return logged
|
|
419
|
+
* } finally {
|
|
420
|
+
* const auditClosed = await audit.close()
|
|
421
|
+
* if (!auditClosed.success) return auditClosed // 保留依赖连接,修复后重试关闭。
|
|
422
|
+
* const databaseClosed = await reldb.close()
|
|
423
|
+
* if (!databaseClosed.success) return databaseClosed
|
|
424
|
+
* }
|
|
425
|
+
* }
|
|
245
426
|
* ```
|
|
246
427
|
*/
|
|
247
428
|
interface AuditFunctions {
|
|
429
|
+
/** 手动流式归档与完整性核对,关闭后返回未初始化。 */
|
|
430
|
+
readonly backup: AuditBackupOperations;
|
|
431
|
+
/** 宿主显式装配的备份/告警任务计划;没有启用自动任务时为 null。 */
|
|
432
|
+
readonly schedulerPlan: Required<Pick<SchedulerInitInput, 'tasks' | 'hooks'>> | null;
|
|
433
|
+
/** 检查已提交事件的本窗口和前一窗口;每个规则/目标/窗口只尝试一次外部通知。 */
|
|
434
|
+
checkAlerts: (options?: {
|
|
435
|
+
signal?: AbortSignal;
|
|
436
|
+
}) => Promise<HaiResult<AuditAlertReport>>;
|
|
437
|
+
/**
|
|
438
|
+
* 在异步隔离的审计上下文中执行操作;同步或异步结果原样返回,调用方异常原样传播。
|
|
439
|
+
* @param context - 可信宿主解析的关联字段与身份快照。
|
|
440
|
+
* @param operation - 业务操作,内部 audit.log 自动补齐未显式指定的字段。
|
|
441
|
+
* @returns 业务操作的原始返回值或 Promise。
|
|
442
|
+
*/
|
|
443
|
+
withContext: <T>(context: AuditContext, operation: () => T) => T;
|
|
248
444
|
/**
|
|
249
445
|
* 初始化审计模块
|
|
250
446
|
*
|
|
@@ -255,26 +451,37 @@ interface AuditFunctions {
|
|
|
255
451
|
/**
|
|
256
452
|
* 关闭审计模块,释放内部状态
|
|
257
453
|
*/
|
|
258
|
-
close: () => Promise<void
|
|
454
|
+
close: () => Promise<HaiResult<void>>;
|
|
259
455
|
/** 当前是否已初始化 */
|
|
260
456
|
readonly isInitialized: boolean;
|
|
261
457
|
/**
|
|
262
458
|
* 记录一条审计日志
|
|
263
459
|
*
|
|
264
460
|
* @param input - 日志内容(action 和 resource 为必填)
|
|
461
|
+
* @param tx - 可选的调用者事务;提交或回滚同时决定事件,不在此提交事务。
|
|
265
462
|
* @returns 成功时返回创建的 AuditLog;失败时返回 LOG_FAILED
|
|
266
463
|
*/
|
|
267
|
-
log: (input: CreateAuditLogInput) => Promise<HaiResult<AuditLog>>;
|
|
464
|
+
log: (input: CreateAuditLogInput, tx?: DmlWithTxOperations) => Promise<HaiResult<AuditLog>>;
|
|
465
|
+
/**
|
|
466
|
+
* 框架入口自动记录。模块未初始化或关闭自动采集时跳过;默认跳过成功读取。
|
|
467
|
+
* 不改变原业务结果;调用方仍须检查记录失败,避免静默丢失审计。
|
|
468
|
+
* @param input - 仅包含安全的事件字段,不应复制请求体或凭据。
|
|
469
|
+
* @param options - 入口是否属于读取操作;失败和拒绝的读取始终采集。
|
|
470
|
+
* @param options.read - 读取标志;默认 false。
|
|
471
|
+
* @param options.tx - 可选的调用者事务;回滚不会留下成功变更事件。
|
|
472
|
+
* @returns 持久化成功或按配置跳过时成功,否则返回审计错误。
|
|
473
|
+
*/
|
|
474
|
+
capture: (input: CreateAuditLogInput, options?: {
|
|
475
|
+
read?: boolean;
|
|
476
|
+
tx?: DmlWithTxOperations;
|
|
477
|
+
}) => Promise<HaiResult<void>>;
|
|
268
478
|
/**
|
|
269
479
|
* 分页查询审计日志列表(含用户名 LEFT JOIN)
|
|
270
480
|
*
|
|
271
481
|
* @param options - 查询过滤与分页选项
|
|
272
|
-
* @returns 成功时返回
|
|
482
|
+
* @returns 成功时返回 PaginatedResult(items/total/page/pageSize);失败时返回 QUERY_FAILED
|
|
273
483
|
*/
|
|
274
|
-
list: (options?: ListAuditLogsOptions) => Promise<HaiResult<
|
|
275
|
-
items: AuditLogWithUser[];
|
|
276
|
-
total: number;
|
|
277
|
-
}>>;
|
|
484
|
+
list: (options?: ListAuditLogsOptions) => Promise<HaiResult<PaginatedResult<AuditLogWithUser>>>;
|
|
278
485
|
/**
|
|
279
486
|
* 获取指定用户的最近活动记录
|
|
280
487
|
*
|
|
@@ -296,7 +503,7 @@ interface AuditFunctions {
|
|
|
296
503
|
* @param days - 统计天数,默认 7
|
|
297
504
|
* @returns 成功时返回 AuditStatItem 数组;失败时返回 STATS_FAILED
|
|
298
505
|
*/
|
|
299
|
-
getStats: (days?: number) => Promise<HaiResult<AuditStatItem[]>>;
|
|
506
|
+
getStats: (days?: number, filters?: Pick<ListAuditLogsOptions, 'category' | 'outcome' | 'severity' | 'scopeId' | 'userId' | 'resource'>) => Promise<HaiResult<AuditStatItem[]>>;
|
|
300
507
|
/**
|
|
301
508
|
* 便捷记录器,封装常见审计场景
|
|
302
509
|
*
|
|
@@ -304,24 +511,82 @@ interface AuditFunctions {
|
|
|
304
511
|
*/
|
|
305
512
|
readonly helper: AuditHelper;
|
|
306
513
|
}
|
|
307
|
-
|
|
308
514
|
/**
|
|
309
|
-
*
|
|
310
|
-
*
|
|
311
|
-
*
|
|
312
|
-
* @
|
|
515
|
+
* 私有归档键前缀;宿主公开文件入口须拒绝此命名空间,即使备份策略已关闭。
|
|
516
|
+
* @example
|
|
517
|
+
* ```ts
|
|
518
|
+
* import { AUDIT_BACKUP_PREFIX } from '@h-ai/audit'
|
|
519
|
+
* const key = `${AUDIT_BACKUP_PREFIX}daily-archive.jsonl`
|
|
520
|
+
* ```
|
|
313
521
|
*/
|
|
314
|
-
|
|
522
|
+
declare const AUDIT_BACKUP_PREFIX = "hai-private/audit-backups/";
|
|
315
523
|
/**
|
|
316
|
-
*
|
|
317
|
-
*
|
|
318
|
-
*
|
|
319
|
-
*
|
|
320
|
-
*
|
|
321
|
-
*
|
|
322
|
-
* @returns 便捷记录器接口
|
|
524
|
+
* 归档扫描条件。缺省截止时刻在开始时固定,过程中新增日志交给下一次归档。
|
|
525
|
+
* @example
|
|
526
|
+
* ```ts
|
|
527
|
+
* import type { AuditBackupOptions } from '@h-ai/audit'
|
|
528
|
+
* const options: AuditBackupOptions = { id: 'daily-archive', from: new Date('2026-01-01T00:00:00Z') }
|
|
529
|
+
* ```
|
|
323
530
|
*/
|
|
324
|
-
|
|
531
|
+
interface AuditBackupOptions {
|
|
532
|
+
/** 同一业务执行使用稳定 ID;省略时生成随机 ID。已有 ID 仅核对并复用完整归档。 */
|
|
533
|
+
id?: string;
|
|
534
|
+
from?: Date;
|
|
535
|
+
to?: Date;
|
|
536
|
+
signal?: AbortSignal;
|
|
537
|
+
}
|
|
538
|
+
/**
|
|
539
|
+
* 完整归档回执;SHA-256 校验内容完整性,不能替代独立存储权限或真实性认证。
|
|
540
|
+
* @example
|
|
541
|
+
* ```ts
|
|
542
|
+
* import { audit, type AuditBackupInfo } from '@h-ai/audit'
|
|
543
|
+
* // 宿主已初始化 RelDB、私有 Storage 和 Audit。
|
|
544
|
+
* const result = await audit.backup.run()
|
|
545
|
+
* if (result.success) { const receipt: AuditBackupInfo = result.data; void receipt.sha256 }
|
|
546
|
+
* ```
|
|
547
|
+
*/
|
|
548
|
+
interface AuditBackupInfo {
|
|
549
|
+
id: string;
|
|
550
|
+
key: string;
|
|
551
|
+
recordCount: number;
|
|
552
|
+
sha256: string;
|
|
553
|
+
createdAt: Date;
|
|
554
|
+
cutoff: Date;
|
|
555
|
+
}
|
|
556
|
+
/**
|
|
557
|
+
* 备份不覆盖在线审计。JSONL 归档可核对后用于离线恢复/独立查询存储。
|
|
558
|
+
* @example
|
|
559
|
+
* ```ts
|
|
560
|
+
* import { audit, type AuditBackupOperations } from '@h-ai/audit'
|
|
561
|
+
* const operations: AuditBackupOperations = audit.backup
|
|
562
|
+
* const result = await operations.run({ id: 'daily-archive' })
|
|
563
|
+
* if (!result.success) result.error.code
|
|
564
|
+
* ```
|
|
565
|
+
*/
|
|
566
|
+
interface AuditBackupOperations {
|
|
567
|
+
/** 创建或核对并复用同一 ID 的完整归档;已有归档不覆盖,输入无效、取消或存储失败返回失败。 */
|
|
568
|
+
run: (options?: AuditBackupOptions) => Promise<HaiResult<AuditBackupInfo>>;
|
|
569
|
+
/** 有界流式核对规范、记录数和校验和;只允许读取私有归档命名空间。 */
|
|
570
|
+
verify: (key: string, options?: {
|
|
571
|
+
signal?: AbortSignal;
|
|
572
|
+
}) => Promise<HaiResult<AuditBackupInfo>>;
|
|
573
|
+
}
|
|
574
|
+
/**
|
|
575
|
+
* 本次检查的通知提交回执;submitted 不证明收件人已阅读,queued 仅表示 Reach 持久入队。
|
|
576
|
+
* @example
|
|
577
|
+
* ```ts
|
|
578
|
+
* import { audit, type AuditAlertReport } from '@h-ai/audit'
|
|
579
|
+
* const result = await audit.checkAlerts()
|
|
580
|
+
* if (result.success) { const report: AuditAlertReport = result.data; void report.failed }
|
|
581
|
+
* ```
|
|
582
|
+
*/
|
|
583
|
+
interface AuditAlertReport {
|
|
584
|
+
submitted: number;
|
|
585
|
+
queued: number;
|
|
586
|
+
failed: number;
|
|
587
|
+
/** 已达到单轮通知上限,后续检查继续领取未尝试目标。 */
|
|
588
|
+
more: boolean;
|
|
589
|
+
}
|
|
325
590
|
|
|
326
591
|
/**
|
|
327
592
|
* @h-ai/audit — 审计日志服务主入口
|
|
@@ -343,23 +608,41 @@ declare function createHelper(logFn: (input: CreateAuditLogInput) => Promise<Hai
|
|
|
343
608
|
* - `audit.getStats()` — 获取统计数据
|
|
344
609
|
* - `audit.helper` — 便捷记录器
|
|
345
610
|
* - `audit.isInitialized` — 初始化状态
|
|
346
|
-
*
|
|
347
611
|
* @example
|
|
348
612
|
* ```ts
|
|
349
613
|
* import { audit } from '@h-ai/audit'
|
|
350
|
-
* import {
|
|
351
|
-
*
|
|
352
|
-
*
|
|
353
|
-
*
|
|
354
|
-
*
|
|
355
|
-
*
|
|
614
|
+
* import { core } from '@h-ai/core'
|
|
615
|
+
* import { reldb, type ReldbConfigInput } from '@h-ai/reldb'
|
|
616
|
+
* async function recordCreation(config: ReldbConfigInput) {
|
|
617
|
+
* const database = await reldb.init(config)
|
|
618
|
+
* if (!database.success) return database
|
|
619
|
+
* try {
|
|
620
|
+
* const initialized = await audit.init()
|
|
621
|
+
* if (!initialized.success) return initialized
|
|
622
|
+
* const logged = await audit.log({ action: 'create', resource: 'orders', resourceId: 'order_1' })
|
|
623
|
+
* if (logged.success) core.logger.info('Audit recorded', { id: logged.data.id })
|
|
624
|
+
* return logged
|
|
625
|
+
* } finally {
|
|
626
|
+
* const auditClosed = await audit.close()
|
|
627
|
+
* if (!auditClosed.success) return auditClosed // 保留依赖连接,修复后重试关闭。
|
|
628
|
+
* const databaseClosed = await reldb.close()
|
|
629
|
+
* if (!databaseClosed.success) return databaseClosed
|
|
630
|
+
* }
|
|
356
631
|
* }
|
|
357
|
-
*
|
|
358
|
-
* await audit.helper.login('user_1', '127.0.0.1')
|
|
359
|
-
* const logs = await audit.list({ pageSize: 10 })
|
|
360
|
-
* await audit.close()
|
|
361
632
|
* ```
|
|
362
633
|
*/
|
|
363
634
|
declare const audit: AuditFunctions;
|
|
364
635
|
|
|
365
|
-
|
|
636
|
+
/**
|
|
637
|
+
* 只读预检或迁移审计字段、保留设置和写入保护;升级前停旧写入并备份。
|
|
638
|
+
* @example
|
|
639
|
+
* ```ts
|
|
640
|
+
* import { migrateAudit } from '@h-ai/audit'
|
|
641
|
+
* const plan = await migrateAudit({ dryRun: true }) // RelDB 已初始化;不改写记录。
|
|
642
|
+
* ```
|
|
643
|
+
*/
|
|
644
|
+
declare function migrateAudit(options?: {
|
|
645
|
+
dryRun?: boolean;
|
|
646
|
+
}): Promise<HaiResult<_h_ai_reldb.SchemaMigrationPlan>>;
|
|
647
|
+
|
|
648
|
+
export { AUDIT_BACKUP_PREFIX, type AuditActorSnapshot, type AuditAlertReport, type AuditBackupInfo, type AuditBackupOperations, type AuditBackupOptions, type AuditContext, type AuditEventFields, type AuditFunctions, type AuditHelper, type AuditInitConfig, type AuditInitConfigInput, AuditInitConfigSchema, type AuditLog, type AuditLogWithUser, type AuditStatItem, type CreateAuditLogInput, type CrudAuditInput, HaiAuditError, type ListAuditLogsOptions, audit, migrateAudit };
|