feat: implement sensitive operation audit retention (TASK-WP6-04)
Dada P0-A isolated Windows CI / validate-and-package (push) Failing after 59s

This commit is contained in:
suyx
2026-08-04 11:51:09 +08:00
parent c589b8bb4e
commit 1c46311e05
21 changed files with 1670 additions and 11 deletions
+80
View File
@@ -9,10 +9,13 @@ import {
AccountProfileUpdateRequestSchema,
AccountProfileUpdateResponseSchema,
AccountSettingsResponseSchema,
AdminAuditQuerySchema,
AdminAuthenticatedUserSchema,
AdminGenerationRecordSchema,
AdminGenerationListResponseSchema,
AdminOverviewResponseSchema,
AdminOperationAuditItemSchema,
AdminOperationAuditResponseSchema,
AdminServicesResponseSchema,
AdminServiceHealthCheckRequestSchema,
AdminServiceLimitRequestSchema,
@@ -78,6 +81,8 @@ import {
PrivateContentNoticeAckRequestSchema,
PrivateContentNoticeAckResponseSchema,
PrivateContentPromptResponseSchema,
PrivateContentAccessAuditItemSchema,
PrivateContentAccessAuditResponseSchema,
FailedEmptyTrashRequestSchema,
FailedEmptyTrashResponseSchema,
ExportFormatSchema,
@@ -129,6 +134,7 @@ import {
type AdminLoginCompleteRequest,
type AdminLoginSendRequest,
type AdminOverviewResponse,
type AdminAuditQuery,
type AdminDiagnosticsResponse,
type AdminServicesStorageResponse,
type AccountDeletionCompleteRequest,
@@ -195,6 +201,11 @@ import {
registrationFieldError,
} from "./registration-errors.js";
import type { RegistrationService } from "./registration.js";
import {
AdminAuditQueryError,
listAdminOperationAudit,
listPrivateContentAccessAudit,
} from "./admin-audit.js";
import type { AssetPreviewGrantService } from "./preview-grants.js";
import type { RecentAssetService } from "./recent-assets.js";
import type { AmapAdapter } from "./amap-adapter.js";
@@ -749,11 +760,16 @@ export async function createApp(options: CreateAppOptions = {}) {
AdminLoginCompleteRequestSchema,
AdminLoginCompleteResponseSchema,
AdminSessionResponseSchema,
AdminAuditQuerySchema,
AdminOperationAuditItemSchema,
AdminOperationAuditResponseSchema,
AdminGenerationRecordSchema,
AdminGenerationListResponseSchema,
PrivateContentNoticeAckRequestSchema,
PrivateContentNoticeAckResponseSchema,
PrivateContentPromptResponseSchema,
PrivateContentAccessAuditItemSchema,
PrivateContentAccessAuditResponseSchema,
PrivateContentGenerationParamsSchema,
AdminOverviewResponseSchema,
AdminServicesResponseSchema,
@@ -1684,6 +1700,70 @@ export async function createApp(options: CreateAppOptions = {}) {
},
);
app.get(
"/api/v1/admin/audit/operations",
{
schema: {
operationId: "getAdminOperationAudit",
querystring: Type.Ref(AdminAuditQuerySchema),
response: {
200: Type.Ref(AdminOperationAuditResponseSchema),
400: Type.Null(),
401: Type.Ref(ErrorEnvelopeSchema),
503: Type.Null(),
},
tags: ["Admin Operations"],
},
},
async (request, reply) => {
if (!options.registration) return reply.code(503).send(null);
const token = cookieValue(headerValue(request.headers.cookie), adminSessionCookieName);
const session = token ? options.registration.readAdminSession(token) : undefined;
if (!session) {
return reply.code(401).send(createErrorEnvelope({ code: "AUTH_SESSION_INVALID", correlationId: request.id }));
}
try {
reply.header("Cache-Control", "private, no-store");
return listAdminOperationAudit(options.registration.database, request.query as AdminAuditQuery);
} catch (error) {
if (error instanceof AdminAuditQueryError) return reply.code(400).send(null);
throw error;
}
},
);
app.get(
"/api/v1/admin/audit/private-content",
{
schema: {
operationId: "getPrivateContentAccessAudit",
querystring: Type.Ref(AdminAuditQuerySchema),
response: {
200: Type.Ref(PrivateContentAccessAuditResponseSchema),
400: Type.Null(),
401: Type.Ref(ErrorEnvelopeSchema),
503: Type.Null(),
},
tags: ["Admin Operations"],
},
},
async (request, reply) => {
if (!options.registration) return reply.code(503).send(null);
const token = cookieValue(headerValue(request.headers.cookie), adminSessionCookieName);
const session = token ? options.registration.readAdminSession(token) : undefined;
if (!session) {
return reply.code(401).send(createErrorEnvelope({ code: "AUTH_SESSION_INVALID", correlationId: request.id }));
}
try {
reply.header("Cache-Control", "private, no-store");
return listPrivateContentAccessAudit(options.registration.database, request.query as AdminAuditQuery);
} catch (error) {
if (error instanceof AdminAuditQueryError) return reply.code(400).send(null);
throw error;
}
},
);
app.get(
"/api/v1/admin/overview",
{