diff --git a/frontend/src/pages/admin/AdminImpersonationSafeguards.test.tsx b/frontend/src/pages/admin/AdminImpersonationSafeguards.test.tsx
new file mode 100644
index 00000000..b6c8f19c
--- /dev/null
+++ b/frontend/src/pages/admin/AdminImpersonationSafeguards.test.tsx
@@ -0,0 +1,115 @@
+import { describe, it, expect, beforeEach } from "vitest";
+import { render, screen, waitFor } from "@testing-library/react";
+import userEvent from "@testing-library/user-event";
+import { http, HttpResponse } from "msw";
+import { server } from "../../test/mocks/server";
+import { MemoryRouter } from "react-router-dom";
+import AdminImpersonationSafeguards from "./AdminImpersonationSafeguards";
+
+const mockSession = {
+ id: "session-1",
+ adminId: "admin-security-chief",
+ impersonatedUserId: "user-target-88",
+ reason: "Investigating user issue ticket #SUP-4412",
+ approvalTicketId: "SUP-4412",
+ status: "ACTIVE" as const,
+ tokenHash: "hash-123",
+ maxDurationMinutes: 30,
+ expiresAt: new Date(Date.now() + 1800000).toISOString(),
+ endedAt: null,
+ ipAddress: "127.0.0.1",
+ createdAt: new Date().toISOString(),
+ updatedAt: new Date().toISOString(),
+};
+
+const mockAuditLogs = [
+ {
+ id: "log-1",
+ sessionId: "session-1",
+ requestMethod: "GET",
+ requestPath: "/api/v1/user/profile",
+ actorAdminId: "admin-security-chief",
+ targetUserId: "user-target-88",
+ ipAddress: "127.0.0.1",
+ timestamp: new Date().toISOString(),
+ },
+];
+
+let currentSessions = [mockSession];
+
+function setup() {
+ currentSessions = [mockSession];
+ server.use(
+ http.get("/api/v1/admin/impersonation/sessions", () =>
+ HttpResponse.json({ sessions: currentSessions })
+ ),
+ http.post("/api/v1/admin/impersonation/start", () =>
+ HttpResponse.json({
+ session: mockSession,
+ token: "impersonation-token-123",
+ })
+ ),
+ http.post("/api/v1/admin/impersonation/stop", () => {
+ currentSessions = [{ ...mockSession, status: "ENDED" }];
+ return HttpResponse.json({ success: true });
+ }),
+ http.get("/api/v1/admin/impersonation/audit-logs", () =>
+ HttpResponse.json({ auditLogs: mockAuditLogs })
+ )
+ );
+ window.localStorage.setItem("bridge-watch:admin-api-key:v1", JSON.stringify("test-token"));
+}
+
+function renderPage() {
+ return render(
+
+
+
+ );
+}
+
+describe("AdminImpersonationSafeguards page", () => {
+ beforeEach(() => {
+ setup();
+ });
+
+ it("renders heading and active impersonation session", async () => {
+ renderPage();
+ expect(
+ screen.getByRole("heading", { name: /admin impersonation safeguards/i })
+ ).toBeInTheDocument();
+
+ await waitFor(() => {
+ expect(screen.getByText(/ACTIVE IMPERSONATION SESSION/i)).toBeInTheDocument();
+ });
+ expect(screen.getAllByText("user-target-88").length).toBeGreaterThan(0);
+ });
+
+ it("handles stopping an impersonation session", async () => {
+ renderPage();
+
+ const stopButton = await screen.findByRole("button", { name: /end session now/i });
+ expect(stopButton).toBeInTheDocument();
+ await userEvent.click(stopButton);
+
+ await waitFor(() => {
+ expect(screen.queryByText(/ACTIVE IMPERSONATION SESSION/i)).not.toBeInTheDocument();
+ });
+ });
+
+ it("fetches audit logs when session detail is requested", async () => {
+ renderPage();
+
+ await waitFor(() => {
+ expect(screen.getAllByText("user-target-88").length).toBeGreaterThan(0);
+ });
+
+ const auditTrailButtons = screen.getAllByRole("button", { name: /audit trail/i });
+ if (auditTrailButtons.length > 0) {
+ await userEvent.click(auditTrailButtons[0]);
+ await waitFor(() => {
+ expect(screen.getByText("/api/v1/user/profile")).toBeInTheDocument();
+ });
+ }
+ });
+});
diff --git a/frontend/src/pages/admin/AllowlistManagement.test.tsx b/frontend/src/pages/admin/AllowlistManagement.test.tsx
new file mode 100644
index 00000000..66c95486
--- /dev/null
+++ b/frontend/src/pages/admin/AllowlistManagement.test.tsx
@@ -0,0 +1,103 @@
+import { describe, it, expect, beforeEach } from "vitest";
+import { render, screen, waitFor } from "@testing-library/react";
+import userEvent from "@testing-library/user-event";
+import { http, HttpResponse } from "msw";
+import { server } from "../../test/mocks/server";
+import { MemoryRouter } from "react-router-dom";
+import AllowlistManagement from "./AllowlistManagement";
+
+const mockAllowlist = [
+ {
+ id: "entry-1",
+ contractAddress: "CCW67TSB3SSS4ZXGBOI2CCBGH2QPBDH2VMKCEW47GFZ2G5J57TL2JG3V",
+ addedBy: "admin-1",
+ addedAt: new Date().toISOString(),
+ isActive: true,
+ },
+];
+
+const mockRequests = [
+ {
+ id: "req-1",
+ contractAddress: "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMWAXA26TXTXFX",
+ action: "add" as const,
+ reason: "New liquidity pool integration",
+ requestedBy: "op-lead",
+ status: "pending" as const,
+ reviewedBy: null,
+ reviewComment: null,
+ reviewedAt: null,
+ createdAt: new Date().toISOString(),
+ },
+];
+
+function setup() {
+ server.use(
+ http.get("/api/v1/admin/allowlist", () =>
+ HttpResponse.json({ allowlist: mockAllowlist })
+ ),
+ http.get("/api/v1/admin/allowlist/change-requests", () =>
+ HttpResponse.json({ changeRequests: mockRequests })
+ ),
+ http.post("/api/v1/admin/allowlist/change-requests", () =>
+ HttpResponse.json({ success: true }, { status: 201 })
+ ),
+ http.post("/api/v1/admin/allowlist/change-requests/:id/review", () =>
+ HttpResponse.json({ success: true })
+ )
+ );
+}
+
+function renderPage() {
+ return render(
+
+
+
+ );
+}
+
+describe("AllowlistManagement page", () => {
+ beforeEach(() => {
+ setup();
+ });
+
+ it("renders page heading and allowlist entries", async () => {
+ renderPage();
+ expect(
+ screen.getByRole("heading", { name: /contract allowlist management/i })
+ ).toBeInTheDocument();
+
+ await waitFor(() => {
+ expect(
+ screen.getByText("CCW67TSB3SSS4ZXGBOI2CCBGH2QPBDH2VMKCEW47GFZ2G5J57TL2JG3V")
+ ).toBeInTheDocument();
+ });
+ });
+
+ it("switches tabs and displays change requests", async () => {
+ renderPage();
+ const requestsTabButton = screen.getByRole("button", { name: /change requests/i });
+ await userEvent.click(requestsTabButton);
+
+ await waitFor(() => {
+ expect(
+ screen.getByText("CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMWAXA26TXTXFX")
+ ).toBeInTheDocument();
+ });
+ });
+
+ it("allows submitting a new change request", async () => {
+ const { container } = renderPage();
+ const addressInput = screen.getByPlaceholderText("0x...");
+ const textareaReason = container.querySelector("textarea")!;
+ const submitBtn = screen.getByRole("button", { name: /submit request/i });
+
+ await userEvent.type(addressInput, "CABC1234567890TESTCONTRACTADDRESSEXAMPLE");
+ await userEvent.type(textareaReason, "Testing submission flow");
+ await userEvent.click(submitBtn);
+
+ await waitFor(() => {
+ expect(addressInput).toHaveValue("");
+ });
+ });
+});
diff --git a/frontend/src/pages/admin/ParseQuarantineQueue.test.tsx b/frontend/src/pages/admin/ParseQuarantineQueue.test.tsx
new file mode 100644
index 00000000..01e5cae7
--- /dev/null
+++ b/frontend/src/pages/admin/ParseQuarantineQueue.test.tsx
@@ -0,0 +1,119 @@
+import { describe, it, expect, beforeEach } from "vitest";
+import { render, screen, waitFor } from "@testing-library/react";
+import userEvent from "@testing-library/user-event";
+import { http, HttpResponse } from "msw";
+import { server } from "../../test/mocks/server";
+import { MemoryRouter } from "react-router-dom";
+import ParseQuarantineQueue from "./ParseQuarantineQueue";
+
+const mockRecord = {
+ id: "qr-101",
+ source: "horizon-ingestor",
+ dataType: "transaction_meta",
+ rawPayload: { hash: "0x123abc" },
+ parseError: "Unexpected end of JSON input",
+ errorCode: "ERR_JSON_PARSE",
+ status: "quarantined" as const,
+ retryCount: 1,
+ priority: 5,
+ createdAt: new Date().toISOString(),
+ updatedAt: new Date().toISOString(),
+};
+
+const mockStats = {
+ total: 10,
+ byStatus: {
+ quarantined: 4,
+ in_review: 2,
+ resolved: 3,
+ disposed: 1,
+ failed: 0,
+ },
+ bySource: {
+ "horizon-ingestor": 10,
+ },
+};
+
+function setup() {
+ server.use(
+ http.get("/api/v1/admin/quarantine", () =>
+ HttpResponse.json({ records: [mockRecord] })
+ ),
+ http.get("/api/v1/admin/quarantine/stats", () =>
+ HttpResponse.json({ stats: mockStats })
+ ),
+ http.post("/api/v1/admin/quarantine", () =>
+ HttpResponse.json({ record: mockRecord }, { status: 201 })
+ ),
+ http.post("/api/v1/admin/quarantine/:id/retry", () =>
+ HttpResponse.json({ record: { ...mockRecord, status: "resolved" } })
+ ),
+ http.post("/api/v1/admin/quarantine/:id/resolve", () =>
+ HttpResponse.json({ record: { ...mockRecord, status: "resolved" } })
+ ),
+ http.delete("/api/v1/admin/quarantine/:id", () =>
+ HttpResponse.json({ success: true })
+ )
+ );
+ window.localStorage.setItem("bridge-watch:admin-api-key:v1", JSON.stringify("test-token"));
+}
+
+function renderPage() {
+ return render(
+
+
+
+ );
+}
+
+describe("ParseQuarantineQueue page", () => {
+ beforeEach(() => {
+ setup();
+ });
+
+ it("renders heading and quarantine queue items", async () => {
+ renderPage();
+ expect(
+ screen.getByRole("heading", { name: /failed parse quarantine/i })
+ ).toBeInTheDocument();
+
+ await waitFor(() => {
+ expect(screen.getByText("horizon-ingestor")).toBeInTheDocument();
+ });
+ expect(screen.getByText(/ERR_JSON_PARSE/i)).toBeInTheDocument();
+ });
+
+ it("handles enqueueing a new quarantine item", async () => {
+ renderPage();
+
+ const sourceInput = screen.getByPlaceholderText("some-exchange");
+ const dataTypeInput = screen.getByPlaceholderText("asset");
+ const parseErrorInput = screen.getByPlaceholderText("Unexpected field 'foo'");
+
+ await userEvent.type(sourceInput, "horizon-stream");
+ await userEvent.type(dataTypeInput, "ledger_header");
+ await userEvent.type(parseErrorInput, "SyntaxError");
+
+ const enqueueBtn = screen.getByRole("button", { name: /enqueue record/i });
+ await userEvent.click(enqueueBtn);
+
+ await waitFor(() => {
+ expect(sourceInput).toHaveValue("");
+ });
+ });
+
+ it("retries and resolves quarantine items", async () => {
+ renderPage();
+
+ await waitFor(() => {
+ expect(screen.getByText("horizon-ingestor")).toBeInTheDocument();
+ });
+
+ const retryBtn = screen.getByRole("button", { name: /retry/i });
+ await userEvent.click(retryBtn);
+
+ await waitFor(() => {
+ expect(screen.getByRole("heading", { name: /failed parse quarantine/i })).toBeInTheDocument();
+ });
+ });
+});
diff --git a/frontend/src/pages/admin/SecurityEventCorrelation.test.tsx b/frontend/src/pages/admin/SecurityEventCorrelation.test.tsx
new file mode 100644
index 00000000..422cc2be
--- /dev/null
+++ b/frontend/src/pages/admin/SecurityEventCorrelation.test.tsx
@@ -0,0 +1,56 @@
+import { describe, it, expect } from "vitest";
+import { render, screen } from "@testing-library/react";
+import userEvent from "@testing-library/user-event";
+import { MemoryRouter } from "react-router-dom";
+import SecurityEventCorrelation from "./SecurityEventCorrelation";
+
+function renderPage() {
+ return render(
+
+
+
+ );
+}
+
+describe("SecurityEventCorrelation page", () => {
+ it("renders page heading and initial security correlations", () => {
+ renderPage();
+ expect(
+ screen.getByRole("heading", { name: /security event correlation/i })
+ ).toBeInTheDocument();
+
+ expect(
+ screen.getByText("Multiple Failed Webhook & Auth Signatures")
+ ).toBeInTheDocument();
+ expect(
+ screen.getByText("Sensitive Field Bulk Export Anomaly")
+ ).toBeInTheDocument();
+ });
+
+ it("filters correlations by search term", async () => {
+ renderPage();
+ const searchInput = screen.getByPlaceholderText(/search correlation views/i);
+ await userEvent.type(searchInput, "Webhook");
+
+ expect(
+ screen.getByText("Multiple Failed Webhook & Auth Signatures")
+ ).toBeInTheDocument();
+ expect(
+ screen.queryByText("Sensitive Field Bulk Export Anomaly")
+ ).not.toBeInTheDocument();
+ });
+
+ it("opens create modal and adds a correlation rule", async () => {
+ const { container } = renderPage();
+ const createBtn = screen.getByRole("button", { name: /\+ Create Correlation View/i });
+ await userEvent.click(createBtn);
+
+ const titleInput = container.querySelector('form input[type="text"]')!;
+ await userEvent.type(titleInput, "Unusual Geo IP Spike");
+
+ const submitBtn = screen.getByRole("button", { name: /save correlation view/i });
+ await userEvent.click(submitBtn);
+
+ expect(screen.getByText("Unusual Geo IP Spike")).toBeInTheDocument();
+ });
+});
diff --git a/frontend/src/pages/admin/SignedRequestVerification.test.tsx b/frontend/src/pages/admin/SignedRequestVerification.test.tsx
new file mode 100644
index 00000000..55d40958
--- /dev/null
+++ b/frontend/src/pages/admin/SignedRequestVerification.test.tsx
@@ -0,0 +1,46 @@
+import { describe, it, expect } from "vitest";
+import { render, screen } from "@testing-library/react";
+import userEvent from "@testing-library/user-event";
+import { MemoryRouter } from "react-router-dom";
+import SignedRequestVerification from "./SignedRequestVerification";
+
+function renderPage() {
+ return render(
+
+
+
+ );
+}
+
+describe("SignedRequestVerification page", () => {
+ it("renders page title and active signing keys", () => {
+ renderPage();
+ expect(
+ screen.getByRole("heading", { name: /signed request verification middleware/i })
+ ).toBeInTheDocument();
+ expect(screen.getByText("payment-gateway")).toBeInTheDocument();
+ expect(screen.getByText("partner-oracle")).toBeInTheDocument();
+ });
+
+ it("opens create key modal and adds a new key", async () => {
+ renderPage();
+ const createBtn = screen.getByRole("button", { name: /\+ Issue New Signing Key/i });
+ await userEvent.click(createBtn);
+
+ const ownerInput = screen.getByPlaceholderText(/e\.g\. payment-processor/i);
+ await userEvent.type(ownerInput, "analytics-worker");
+
+ const submitBtn = screen.getByRole("button", { name: /generate key credentials/i });
+ await userEvent.click(submitBtn);
+
+ expect(screen.getByText("analytics-worker")).toBeInTheDocument();
+ });
+
+ it("runs the signature verification sandbox", async () => {
+ renderPage();
+ const verifyBtn = screen.getByRole("button", { name: /compute & verify test signature/i });
+ await userEvent.click(verifyBtn);
+
+ expect(screen.getByText(/Generated Signature Header/i)).toBeInTheDocument();
+ });
+});
diff --git a/frontend/src/pages/admin/WebhookIpAllowlist.test.tsx b/frontend/src/pages/admin/WebhookIpAllowlist.test.tsx
new file mode 100644
index 00000000..f2c5c6ee
--- /dev/null
+++ b/frontend/src/pages/admin/WebhookIpAllowlist.test.tsx
@@ -0,0 +1,54 @@
+import { describe, it, expect } from "vitest";
+import { render, screen } from "@testing-library/react";
+import userEvent from "@testing-library/user-event";
+import { MemoryRouter } from "react-router-dom";
+import WebhookIpAllowlist from "./WebhookIpAllowlist";
+
+function renderPage() {
+ return render(
+
+
+
+ );
+}
+
+describe("WebhookIpAllowlist page", () => {
+ it("renders page title and initial allowlist entries", () => {
+ renderPage();
+ expect(
+ screen.getByRole("heading", { name: /webhook ip allowlist/i })
+ ).toBeInTheDocument();
+
+ expect(screen.getByText("192.168.1.0/24")).toBeInTheDocument();
+ expect(screen.getByText("10.0.4.50")).toBeInTheDocument();
+ });
+
+ it("adds a new IP allowlist entry via modal", async () => {
+ const { container } = renderPage();
+ const addBtn = screen.getByRole("button", { name: /\+ Add Allowlist Entry/i });
+ await userEvent.click(addBtn);
+
+ const ipInput = screen.getByPlaceholderText(/e\.g\. 192\.168\.1\.0\/24/i);
+ const descTextarea = container.querySelector("textarea")!;
+
+ await userEvent.type(ipInput, "172.16.0.0/16");
+ await userEvent.type(descTextarea, "VPN Subnet");
+
+ const submitBtn = screen.getByRole("button", { name: /add rule/i });
+ await userEvent.click(submitBtn);
+
+ expect(screen.getByText("172.16.0.0/16")).toBeInTheDocument();
+ expect(screen.getByText("VPN Subnet")).toBeInTheDocument();
+ });
+
+ it("tests an IP against active rules", async () => {
+ renderPage();
+ const testIpInput = screen.getByPlaceholderText(/Enter test IP/i);
+ const runTestBtn = screen.getByRole("button", { name: /Evaluate Access/i });
+
+ await userEvent.type(testIpInput, "192.168.1.50");
+ await userEvent.click(runTestBtn);
+
+ expect(screen.getByText(/Matched rule/i)).toBeInTheDocument();
+ });
+});