feat(auth): add remembered local login to the frontend
This commit is contained in:
@@ -1,14 +1,21 @@
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import { render, screen, waitFor, within } from "@testing-library/react";
|
||||
import { act, render, screen, waitFor, within } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { http, HttpResponse } from "msw";
|
||||
import { beforeEach, expect, test, vi } from "vitest";
|
||||
import { server } from "../test/msw";
|
||||
import { canonicalWorkspaceFixture, workspaceRevisionFixture, workspaceSummaryFixture } from "../test/workspace-fixtures";
|
||||
import { WorkspaceManager } from "./WorkspaceManager";
|
||||
import { setAuthState } from "../auth/authState";
|
||||
import { queryClient } from "../app/queryClient";
|
||||
|
||||
const workspace = canonicalWorkspaceFixture("psd-clinical");
|
||||
const revision = workspaceRevisionFixture("psd-clinical");
|
||||
const authenticatedWorkspaceUser = {
|
||||
issuer: "local", subject: "workspace-user", roles: ["user"] as const,
|
||||
permissions: ["workspace.manage", "workspace.secrets.manage"], isAdmin: false,
|
||||
csrfToken: "w".repeat(43), session: null,
|
||||
};
|
||||
const requirement = {
|
||||
id: "dwh.password",
|
||||
connector: "dwh",
|
||||
@@ -34,14 +41,24 @@ function renderManager(onClose = vi.fn()) {
|
||||
onClose,
|
||||
...render(
|
||||
<QueryClientProvider client={client}>
|
||||
<WorkspaceManager open onClose={onClose} />
|
||||
<WorkspaceManager open onClose={onClose} canManageWorkspace canManageSecrets />
|
||||
</QueryClientProvider>,
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
function renderDeniedManager() {
|
||||
const client = new QueryClient({ defaultOptions: { queries: { retry: false } } });
|
||||
return render(
|
||||
<QueryClientProvider client={client}>
|
||||
<WorkspaceManager open onClose={vi.fn()} canManageWorkspace={false} canManageSecrets={false} />
|
||||
</QueryClientProvider>,
|
||||
);
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
localStorage.clear();
|
||||
setAuthState(authenticatedWorkspaceUser);
|
||||
server.use(
|
||||
http.get("/api/workspace-registry/status", () => HttpResponse.json({
|
||||
branch: "main",
|
||||
@@ -70,6 +87,17 @@ beforeEach(() => {
|
||||
);
|
||||
});
|
||||
|
||||
test("defaults workspace mutations and secrets to denied", async () => {
|
||||
renderDeniedManager();
|
||||
expect(await screen.findByRole("heading", { name: "Workspace management" })).toBeVisible();
|
||||
expect(screen.queryByRole("button", { name: "Update workspace repository" })).not.toBeInTheDocument();
|
||||
await userEvent.click(await screen.findByRole("button", { name: "PSD Clinical" }));
|
||||
expect(await screen.findByRole("heading", { name: "Workspace-specific actions" })).toBeVisible();
|
||||
expect(screen.queryByRole("button", { name: "Validate workspace source" })).not.toBeInTheDocument();
|
||||
expect(screen.queryByRole("button", { name: "Test workspace connections" })).not.toBeInTheDocument();
|
||||
expect(screen.queryByRole("heading", { name: "Runtime secrets" })).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
test("uses a tall viewport area and keeps the workspace content scrollable", () => {
|
||||
renderManager();
|
||||
|
||||
@@ -236,6 +264,44 @@ test("secret fields are write-only, clear after blind save, and may be forgotten
|
||||
expect(await screen.findByText("Not configured")).toBeVisible();
|
||||
});
|
||||
|
||||
test("a delayed runtime-secret save from user A cannot repopulate user B's cache or notice", async () => {
|
||||
let release!: () => void;
|
||||
let started!: () => void;
|
||||
let settled!: () => void;
|
||||
const held = new Promise<void>((resolve) => { release = resolve; });
|
||||
const requestStarted = new Promise<void>((resolve) => { started = resolve; });
|
||||
const requestSettled = new Promise<void>((resolve) => { settled = resolve; });
|
||||
server.use(http.put("/api/workspaces/psd-clinical/secrets", async () => {
|
||||
started();
|
||||
try {
|
||||
await held;
|
||||
return HttpResponse.json(runtimeConfiguration(true));
|
||||
} finally {
|
||||
settled();
|
||||
}
|
||||
}));
|
||||
queryClient.clear();
|
||||
setAuthState({ issuer: "local", subject: "user-a", roles: ["user"], permissions: ["workspace.secrets.manage"], isAdmin: false, csrfToken: "a".repeat(43), session: null });
|
||||
render(
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<WorkspaceManager open onClose={vi.fn()} canManageWorkspace canManageSecrets />
|
||||
</QueryClientProvider>,
|
||||
);
|
||||
await userEvent.click(await screen.findByRole("button", { name: "PSD Clinical" }));
|
||||
const input = await screen.findByLabelText("Data warehouse password");
|
||||
await userEvent.type(input, "a-secret");
|
||||
await userEvent.click(screen.getByRole("button", { name: "Save entered secrets" }));
|
||||
await requestStarted;
|
||||
|
||||
act(() => setAuthState({ issuer: "local", subject: "user-b", roles: ["user"], permissions: ["workspace.secrets.manage"], isAdmin: false, csrfToken: "b".repeat(43), session: null }));
|
||||
expect(queryClient.getQueryData(["workspace-runtime-configuration", "psd-clinical"])).toBeUndefined();
|
||||
release();
|
||||
await act(async () => { await requestSettled; });
|
||||
|
||||
expect(queryClient.getQueryData(["workspace-runtime-configuration", "psd-clinical"])).toBeUndefined();
|
||||
expect(screen.queryByText("Runtime secrets saved. Stored values remain hidden.")).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
test("closing clears unsaved secret fields", async () => {
|
||||
const user = userEvent.setup();
|
||||
const onClose = vi.fn();
|
||||
|
||||
Reference in New Issue
Block a user