Таблица audit_log, recordAudit на CRUD, GET /api/v1/audit и dual-write source_app=cfdm. Co-authored-by: Cursor <[email protected]>
98 lines
2.8 KiB
TypeScript
98 lines
2.8 KiB
TypeScript
import { describe, expect, it, vi, afterEach } from "vitest";
|
|
import { buildApp } from "../src/app.js";
|
|
import { loadConfig } from "../src/config.js";
|
|
import * as auditPortalPush from "../src/services/audit-portal-push.js";
|
|
|
|
describe("audit log", () => {
|
|
afterEach(() => {
|
|
vi.restoreAllMocks();
|
|
});
|
|
|
|
it("GET /api/v1/audit returns local entries", async () => {
|
|
const pushSpy = vi
|
|
.spyOn(auditPortalPush, "pushAuditEvents")
|
|
.mockResolvedValue(undefined);
|
|
|
|
const app = await buildApp({
|
|
config: {
|
|
...loadConfig(),
|
|
staticDir: null,
|
|
authAuditIngestSecret: null,
|
|
},
|
|
memory: true,
|
|
});
|
|
|
|
const login = await app.inject({
|
|
method: "POST",
|
|
url: "/api/v1/auth/login",
|
|
payload: { username: "admin", password: "admin" },
|
|
});
|
|
expect(login.statusCode).toBe(200);
|
|
const token = (login.json() as { token: string }).token;
|
|
|
|
const create = await app.inject({
|
|
method: "POST",
|
|
url: "/api/v1/groups",
|
|
headers: { authorization: `Bearer ${token}` },
|
|
payload: { name: "Audit Test", slug: "audit-test" },
|
|
});
|
|
expect(create.statusCode).toBe(200);
|
|
|
|
const list = await app.inject({
|
|
method: "GET",
|
|
url: "/api/v1/audit?action=group.create",
|
|
headers: { authorization: `Bearer ${token}` },
|
|
});
|
|
expect(list.statusCode).toBe(200);
|
|
const entries = list.json() as { action: string; source_app: string }[];
|
|
expect(entries.length).toBeGreaterThanOrEqual(1);
|
|
expect(entries[0]?.action).toBe("group.create");
|
|
expect(entries[0]?.source_app).toBe("cfdm");
|
|
|
|
expect(pushSpy).not.toHaveBeenCalled();
|
|
await app.close();
|
|
});
|
|
|
|
it("recordAudit pushes to portal when secret configured", async () => {
|
|
const pushSpy = vi
|
|
.spyOn(auditPortalPush, "pushAuditEvents")
|
|
.mockResolvedValue(undefined);
|
|
|
|
const app = await buildApp({
|
|
config: {
|
|
...loadConfig(),
|
|
staticDir: null,
|
|
authPortalUrl: "http://portal.test",
|
|
authAuditIngestSecret: "test-ingest-secret",
|
|
},
|
|
memory: true,
|
|
});
|
|
|
|
const login = await app.inject({
|
|
method: "POST",
|
|
url: "/api/v1/auth/login",
|
|
payload: { username: "admin", password: "admin" },
|
|
});
|
|
const token = (login.json() as { token: string }).token;
|
|
|
|
await app.inject({
|
|
method: "POST",
|
|
url: "/api/v1/groups",
|
|
headers: { authorization: `Bearer ${token}` },
|
|
payload: { name: "Portal Push", slug: "portal-push" },
|
|
});
|
|
|
|
await vi.waitFor(() => {
|
|
expect(pushSpy).toHaveBeenCalledOnce();
|
|
});
|
|
|
|
const [portalUrl, secret, events] = pushSpy.mock.calls[0]!;
|
|
expect(portalUrl).toBe("http://portal.test");
|
|
expect(secret).toBe("test-ingest-secret");
|
|
expect(events[0]?.source_app).toBe("cfdm");
|
|
expect(events[0]?.action).toBe("group.create");
|
|
|
|
await app.close();
|
|
});
|
|
});
|