fix(auth): make diagnostics bounded and portable

This commit is contained in:
2026-08-17 12:19:19 +02:00
parent 7cfbee36fa
commit be1724890a
23 changed files with 1088 additions and 116 deletions
@@ -43,6 +43,15 @@ test.each([
expect(result).toEqual([expect.objectContaining({ level: "error", code, field: "TOT Users" })]);
});
test("rejects more than the requested two bounded group results", async () => {
const response = groups("TOT Users", "Unrelated One", "Unrelated Two");
const result = await catalog(vi.fn<typeof globalThis.fetch>(async () => response))
.verifyConfiguredGroups(["TOT Users"], new AbortController().signal);
expect(result).toEqual([expect.objectContaining({ code: "oidc_group_catalog_unreachable" })]);
expect(JSON.stringify(result)).not.toContain("Unrelated");
});
test("treats a pagination continuation as an ambiguous configured group", async () => {
const response = Response.json({ pagination: { next: "https://authentik.example.test/api/v3/core/groups/?page=2" }, results: [{ name: "TOT Users" }] });
const result = await catalog(vi.fn<typeof globalThis.fetch>(async () => response))
@@ -51,6 +60,34 @@ test("treats a pagination continuation as an ambiguous configured group", async
expect(result).toEqual([expect.objectContaining({ code: "oidc_mapped_group_ambiguous", field: "TOT Users" })]);
});
test.each([
["missing next", { pagination: {}, results: [{ name: "TOT Users" }] }],
["numeric next", { pagination: { next: 2 }, results: [{ name: "TOT Users" }] }],
["boolean next", { pagination: { next: false }, results: [{ name: "TOT Users" }] }],
["malformed continuation", { pagination: { next: "not a URL" }, results: [{ name: "TOT Users" }] }],
])("rejects a group response with %s as unreachable", async (_label, body) => {
const result = await catalog(vi.fn<typeof globalThis.fetch>(async () => Response.json(body)))
.verifyConfiguredGroups(["TOT Users"], new AbortController().signal);
expect(result).toEqual([expect.objectContaining({ code: "oidc_group_catalog_unreachable" })]);
expect(result).not.toContainEqual(expect.objectContaining({ code: "oidc_mapped_group_ambiguous" }));
});
test("enforces the exact Authentik token boundary before making a request", async () => {
const fetch = vi.fn<typeof globalThis.fetch>(async () => groups("TOT Users"));
const accepted = createAuthentikGroupCatalog({
baseUrl: "https://authentik.example.test", apiToken: "a".repeat(16 * 1024), fetch,
});
const rejected = createAuthentikGroupCatalog({
baseUrl: "https://authentik.example.test", apiToken: "a".repeat(16 * 1024 + 1), fetch,
});
await expect(accepted.verifyConfiguredGroups(["TOT Users"], new AbortController().signal)).resolves.toEqual([]);
await expect(rejected.verifyConfiguredGroups(["TOT Users"], new AbortController().signal))
.resolves.toEqual([expect.objectContaining({ code: "oidc_group_catalog_unreachable" })]);
expect(fetch).toHaveBeenCalledOnce();
});
test.each([
["unauthorized", new Response("upstream body must not escape", { status: 401 }), "oidc_group_catalog_unauthorized"],
["forbidden", new Response("upstream body must not escape", { status: 403 }), "oidc_group_catalog_unauthorized"],