feat(admin): 审计 & 安全事件页(T4.B 收尾)

- 新增「审计 & 安全」页(/audit,运维组):接 /admin/audit + /admin/guardrail-events
  - 安全事件:护栏拦截/灰区放行(kind 徽标 + 原因 + method/path + actor/ip/时间)
  - 操作审计:变更操作(方法配色徽标 + 路径 + 状态码着色 + actor/ip/时间)
  - 顶栏统计(操作留痕/护栏拦截/灰区) + 30s 自刷 + 手动刷新
- api.ts 增 listAudit / listGuardrailEvents + 类型
- 风格对齐重做后的服务状态页(中性克制)
- T4.B 整组完成(剩 HITL 审批明细可选小项)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Blizzard
2026-07-02 09:43:41 +08:00
parent 9e43d07428
commit a830ae2a04
4 changed files with 190 additions and 3 deletions
+36
View File
@@ -242,6 +242,42 @@ export async function adminOverview(): Promise<AdminOverview> {
return (await res.json()) as AdminOverview;
}
// —— 审计 / 安全事件(敏感操作留痕 + 护栏命中)——
export interface AuditEntry {
id: string;
actor: string; // 操作者 uid
action: string; // POST / PUT / DELETE / PATCH
route: string;
path: string;
status: number;
ip: string;
detail: string;
at: string;
}
export interface GuardrailEventItem {
id: string;
actor: string;
kind: string; // blocked / suspect
reason: string;
signals: string; // JSON 数组字符串
method: string;
path: string;
ip: string;
at: string;
}
export async function listAudit(limit = 50, offset = 0): Promise<AuditEntry[]> {
const res = guard(await fetch(`${ADMIN}/audit?limit=${limit}&offset=${offset}`, { headers: authHeaders() }));
if (!res.ok) throw new Error(`audit failed: ${res.status}`);
return ((await res.json()) as { logs?: AuditEntry[] }).logs ?? [];
}
export async function listGuardrailEvents(limit = 50, offset = 0): Promise<GuardrailEventItem[]> {
const res = guard(await fetch(`${ADMIN}/guardrail-events?limit=${limit}&offset=${offset}`, { headers: authHeaders() }));
if (!res.ok) throw new Error(`guardrail events failed: ${res.status}`);
return ((await res.json()) as { events?: GuardrailEventItem[] }).events ?? [];
}
// —— Prompt 控制面(建版本 → 激活 → 控制面热下发各服务,不重启即生效)——
// 注意:prompt 路由在 RequireAuth 组下(/api/v1/prompts),不在 /admin 前缀内。
const PROMPTS = `${GATEWAY}/api/v1/prompts`;