feat: add browser auth shell
This commit is contained in:
@@ -128,16 +128,20 @@ describe("host protocol — descriptor validation", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("reports an unauthenticated caller distinctly from any other failure", async () => {
|
||||
for (const status of [401, 403]) {
|
||||
const { implementation } = stubFetch({
|
||||
"/api/v1/dashboard/navigation": () =>
|
||||
jsonResponse({ code: "AUTHORIZATION_DENIED" }, status),
|
||||
});
|
||||
await expect(
|
||||
loadDashboardNavigation({ apiBaseUrl, fetch: implementation }),
|
||||
).rejects.toMatchObject({ code: "HOST_UNAUTHENTICATED" });
|
||||
}
|
||||
it("distinguishes an authentication challenge from an authorization denial", async () => {
|
||||
const unauthenticated = stubFetch({
|
||||
"/api/v1/dashboard/navigation": () => jsonResponse({ code: "AUTHORIZATION_DENIED" }, 401),
|
||||
});
|
||||
await expect(
|
||||
loadDashboardNavigation({ apiBaseUrl, fetch: unauthenticated.implementation }),
|
||||
).rejects.toMatchObject({ code: "HOST_UNAUTHENTICATED" });
|
||||
|
||||
const forbidden = stubFetch({
|
||||
"/api/v1/dashboard/navigation": () => jsonResponse({ code: "AUTHORIZATION_DENIED" }, 403),
|
||||
});
|
||||
await expect(
|
||||
loadDashboardNavigation({ apiBaseUrl, fetch: forbidden.implementation }),
|
||||
).rejects.toMatchObject({ code: "HOST_ACCESS_DENIED" });
|
||||
|
||||
const { implementation } = stubFetch({
|
||||
"/api/v1/dashboard/navigation": () => jsonResponse({ code: "INTERNAL_ERROR" }, 500),
|
||||
@@ -346,6 +350,34 @@ describe("module UI host context", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("reports only 401/403 to the host while returning the module's original response", async () => {
|
||||
const statuses = [401, 403, 404, 200];
|
||||
const onAuthorizationResponse = vi.fn();
|
||||
const implementation = vi.fn(async () => {
|
||||
const status = statuses.shift();
|
||||
if (status === undefined) {
|
||||
throw new Error("unexpected request");
|
||||
}
|
||||
return new Response("module response", { status });
|
||||
}) as unknown as typeof fetch;
|
||||
const context = createModuleUiContext({
|
||||
config: { apiBaseUrl, fetch: implementation },
|
||||
descriptor: exampleDescriptor,
|
||||
onAuthorizationResponse,
|
||||
principal: { kind: "authenticated", userId: "user-1" },
|
||||
});
|
||||
|
||||
const responses = await Promise.all([
|
||||
context.api.request("one"),
|
||||
context.api.request("two"),
|
||||
context.api.request("three"),
|
||||
context.api.request("four"),
|
||||
]);
|
||||
|
||||
expect(responses.map((response) => response.status)).toEqual([401, 403, 404, 200]);
|
||||
expect(onAuthorizationResponse.mock.calls).toEqual([[401], [403]]);
|
||||
});
|
||||
|
||||
it("refuses to address anything outside the module's own API", async () => {
|
||||
const { calls, implementation } = recordingFetch();
|
||||
const api = contextFor(implementation).api;
|
||||
|
||||
Reference in New Issue
Block a user