mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-08-10 14:58:46 +00:00
* fix(auth): let deployments close local self-registration The OIDC provisioning policy (allowed_email_domains, require_verified_email, auto_create_users) is enforced only in the SSO callback via get_or_provision_oidc_user. POST /api/v1/auth/register creates a local account without consulting any of it, and nothing can turn that path off, so a deployment declaring an email-domain allowlist can still be joined by any address through local registration. Add auth.local.allow_registration (default true, so existing deployments are unchanged) and gate /register on it before the account is created. Report the flag from /setup-status so the login page stops offering a signup entry the Gateway will reject. /initialize is deliberately not gated: it is the bootstrap path, guarded by admin_count == 0, and closing it would leave a fresh install unable to create its first admin. An unreadable config.yaml falls back to the pre-gate default (open) rather than making these two endpoints a hard dependency on the file. * docs(auth): align registration-gate fallback wording with the FileNotFoundError catch
101 lines
2.6 KiB
TypeScript
101 lines
2.6 KiB
TypeScript
import { afterEach, describe, expect, rs, test } from "@rstest/core";
|
|
|
|
import {
|
|
canCreateRegularAccount,
|
|
fetchSetupStatus,
|
|
isSystemAlreadyInitializedError,
|
|
setupStatusFetchInit,
|
|
} from "@/core/auth/setup";
|
|
|
|
describe("auth setup helpers", () => {
|
|
afterEach(() => {
|
|
rs.unstubAllGlobals();
|
|
});
|
|
|
|
test("setup-status requests bypass browser caches", () => {
|
|
expect(setupStatusFetchInit).toMatchObject({
|
|
cache: "no-store",
|
|
credentials: "include",
|
|
});
|
|
});
|
|
|
|
test("fetchSetupStatus uses the shared no-store request options", async () => {
|
|
const fetchMock = rs.fn(() =>
|
|
Promise.resolve(
|
|
new Response(JSON.stringify({ needs_setup: true }), {
|
|
status: 200,
|
|
headers: { "Content-Type": "application/json" },
|
|
}),
|
|
),
|
|
);
|
|
rs.stubGlobal("fetch", fetchMock);
|
|
|
|
await expect(fetchSetupStatus()).resolves.toEqual({ needs_setup: true });
|
|
expect(fetchMock).toHaveBeenCalledWith(
|
|
"/api/v1/auth/setup-status",
|
|
setupStatusFetchInit,
|
|
);
|
|
});
|
|
|
|
test("regular sign-up is disabled only while setup is required or unknown", () => {
|
|
expect(canCreateRegularAccount({ checked: false, status: null })).toBe(
|
|
false,
|
|
);
|
|
expect(
|
|
canCreateRegularAccount({
|
|
checked: true,
|
|
status: { needs_setup: true },
|
|
}),
|
|
).toBe(false);
|
|
expect(
|
|
canCreateRegularAccount({
|
|
checked: true,
|
|
status: { needs_setup: false },
|
|
}),
|
|
).toBe(true);
|
|
expect(canCreateRegularAccount({ checked: true, status: null })).toBe(true);
|
|
});
|
|
|
|
test("regular sign-up follows the gateway's registration_enabled flag", () => {
|
|
expect(
|
|
canCreateRegularAccount({
|
|
checked: true,
|
|
status: { needs_setup: false, registration_enabled: false },
|
|
}),
|
|
).toBe(false);
|
|
expect(
|
|
canCreateRegularAccount({
|
|
checked: true,
|
|
status: { needs_setup: false, registration_enabled: true },
|
|
}),
|
|
).toBe(true);
|
|
// Older Gateways omit the field; absent must not hide the signup entry.
|
|
expect(
|
|
canCreateRegularAccount({
|
|
checked: true,
|
|
status: { needs_setup: false },
|
|
}),
|
|
).toBe(true);
|
|
});
|
|
|
|
test("detects already-initialized setup conflicts", () => {
|
|
expect(
|
|
isSystemAlreadyInitializedError({
|
|
detail: {
|
|
code: "system_already_initialized",
|
|
message: "System already initialized",
|
|
},
|
|
}),
|
|
).toBe(true);
|
|
|
|
expect(
|
|
isSystemAlreadyInitializedError({
|
|
detail: {
|
|
code: "invalid_credentials",
|
|
message: "Wrong password",
|
|
},
|
|
}),
|
|
).toBe(false);
|
|
});
|
|
});
|