mirror of
https://github.com/tiennm99/litellm.git
synced 2026-08-09 16:24:38 +00:00
Fix SSO Proxy Base URL input validation and remove normalizing / (#16332)
This commit is contained in:
@@ -96,7 +96,7 @@ describe("SSOModals", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("should automatically remove trailing slash from the proxy base url", async () => {
|
||||
it("should show validation error if the proxy base url ends with a trailing slash", async () => {
|
||||
const TestWrapper = () => {
|
||||
const [form] = Form.useForm();
|
||||
return (
|
||||
@@ -115,18 +115,137 @@ describe("SSOModals", () => {
|
||||
);
|
||||
};
|
||||
|
||||
const { getByLabelText, container } = render(<TestWrapper />);
|
||||
const { getByLabelText, getByText, container } = render(<TestWrapper />);
|
||||
|
||||
// Fill in the proxy base url with a trailing slash
|
||||
// Find and interact with the SSO provider select
|
||||
const ssoProviderSelect = container.querySelector("#sso_provider");
|
||||
if (ssoProviderSelect) {
|
||||
fireEvent.mouseDown(ssoProviderSelect);
|
||||
// Wait for dropdown and select Google
|
||||
await waitFor(() => {
|
||||
const googleOption = getByText("Google SSO");
|
||||
fireEvent.click(googleOption);
|
||||
});
|
||||
}
|
||||
|
||||
// Fill in the email field
|
||||
const emailInput = getByLabelText("Proxy Admin Email");
|
||||
fireEvent.change(emailInput, { target: { value: "test@example.com" } });
|
||||
|
||||
// Fill in a URL with trailing slash
|
||||
const urlInput = getByLabelText("PROXY BASE URL") as HTMLInputElement;
|
||||
fireEvent.change(urlInput, { target: { value: "https://example.com/" } });
|
||||
|
||||
// Trigger blur to ensure normalization is applied
|
||||
fireEvent.blur(urlInput);
|
||||
// Submit the form
|
||||
const saveButton = getByText("Save");
|
||||
fireEvent.click(saveButton);
|
||||
|
||||
// Check that the trailing slash was removed by the normalize function
|
||||
// Check for validation error
|
||||
await waitFor(() => {
|
||||
expect(urlInput.value).toBe("https://example.com");
|
||||
expect(getByText("URL must not end with a trailing slash")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it("should allow typing https:// without interfering with slashes", async () => {
|
||||
const TestWrapper = () => {
|
||||
const [form] = Form.useForm();
|
||||
return (
|
||||
<SSOModals
|
||||
isAddSSOModalVisible={true}
|
||||
isInstructionsModalVisible={false}
|
||||
handleAddSSOOk={() => {}}
|
||||
handleAddSSOCancel={() => {}}
|
||||
handleShowInstructions={() => {}}
|
||||
handleInstructionsOk={() => {}}
|
||||
handleInstructionsCancel={() => {}}
|
||||
form={form}
|
||||
accessToken={null}
|
||||
ssoConfigured={false}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const { getByLabelText } = render(<TestWrapper />);
|
||||
|
||||
const urlInput = getByLabelText("PROXY BASE URL") as HTMLInputElement;
|
||||
|
||||
// Simulate user typing "https://"
|
||||
fireEvent.change(urlInput, { target: { value: "h" } });
|
||||
expect(urlInput.value).toBe("h");
|
||||
|
||||
fireEvent.change(urlInput, { target: { value: "ht" } });
|
||||
expect(urlInput.value).toBe("ht");
|
||||
|
||||
fireEvent.change(urlInput, { target: { value: "http" } });
|
||||
expect(urlInput.value).toBe("http");
|
||||
|
||||
fireEvent.change(urlInput, { target: { value: "https" } });
|
||||
expect(urlInput.value).toBe("https");
|
||||
|
||||
fireEvent.change(urlInput, { target: { value: "https:" } });
|
||||
expect(urlInput.value).toBe("https:");
|
||||
|
||||
fireEvent.change(urlInput, { target: { value: "https:/" } });
|
||||
expect(urlInput.value).toBe("https:/");
|
||||
|
||||
fireEvent.change(urlInput, { target: { value: "https://" } });
|
||||
expect(urlInput.value).toBe("https://");
|
||||
|
||||
// Continue typing the domain
|
||||
fireEvent.change(urlInput, { target: { value: "https://example.com" } });
|
||||
expect(urlInput.value).toBe("https://example.com");
|
||||
});
|
||||
|
||||
it("should only show URL format error for incomplete URLs, not trailing slash error", async () => {
|
||||
const TestWrapper = () => {
|
||||
const [form] = Form.useForm();
|
||||
return (
|
||||
<SSOModals
|
||||
isAddSSOModalVisible={true}
|
||||
isInstructionsModalVisible={false}
|
||||
handleAddSSOOk={() => {}}
|
||||
handleAddSSOCancel={() => {}}
|
||||
handleShowInstructions={() => {}}
|
||||
handleInstructionsOk={() => {}}
|
||||
handleInstructionsCancel={() => {}}
|
||||
form={form}
|
||||
accessToken={null}
|
||||
ssoConfigured={false}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const { getByLabelText, getByText, queryByText, container } = render(<TestWrapper />);
|
||||
|
||||
// Find and interact with the SSO provider select
|
||||
const ssoProviderSelect = container.querySelector("#sso_provider");
|
||||
if (ssoProviderSelect) {
|
||||
fireEvent.mouseDown(ssoProviderSelect);
|
||||
// Wait for dropdown and select Google
|
||||
await waitFor(() => {
|
||||
const googleOption = getByText("Google SSO");
|
||||
fireEvent.click(googleOption);
|
||||
});
|
||||
}
|
||||
|
||||
// Fill in the email field
|
||||
const emailInput = getByLabelText("Proxy Admin Email");
|
||||
fireEvent.change(emailInput, { target: { value: "test@example.com" } });
|
||||
|
||||
// Fill in an incomplete URL like "http:"
|
||||
const urlInput = getByLabelText("PROXY BASE URL");
|
||||
fireEvent.change(urlInput, { target: { value: "http:" } });
|
||||
|
||||
// Submit the form
|
||||
const saveButton = getByText("Save");
|
||||
fireEvent.click(saveButton);
|
||||
|
||||
// Check that only the URL format error appears
|
||||
await waitFor(() => {
|
||||
expect(getByText("URL must start with http:// or https://")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
// Verify the trailing slash error does NOT appear
|
||||
expect(queryByText("URL must not end with a trailing slash")).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -309,7 +309,7 @@ const SSOModals: React.FC<SSOModalsProps> = ({
|
||||
<Form.Item
|
||||
label="PROXY BASE URL"
|
||||
name="proxy_base_url"
|
||||
normalize={(value) => value?.trim().replace(/\/+$/, "")}
|
||||
normalize={(value) => value?.trim()}
|
||||
rules={[
|
||||
{ required: true, message: "Please enter the proxy base url" },
|
||||
{
|
||||
@@ -317,8 +317,13 @@ const SSOModals: React.FC<SSOModalsProps> = ({
|
||||
message: "URL must start with http:// or https://",
|
||||
},
|
||||
{
|
||||
pattern: /^https?:\/\/[^\s]+[^\/]$/,
|
||||
message: "URL must not end with a trailing slash",
|
||||
validator: (_, value) => {
|
||||
// Only check for trailing slash if the URL starts with http:// or https://
|
||||
if (value && /^https?:\/\/.+/.test(value) && value.endsWith("/")) {
|
||||
return Promise.reject("URL must not end with a trailing slash");
|
||||
}
|
||||
return Promise.resolve();
|
||||
},
|
||||
},
|
||||
]}
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user