Fix: Prevent auto-logout on 401 errors in oss mode (#13466)

This commit is contained in:
Chris Bagwell
2026-03-19 10:33:01 -05:00
committed by GitHub
parent 2224127ac3
commit 120fd7516a
3 changed files with 50 additions and 14 deletions

View File

@@ -156,11 +156,19 @@ describe("UserContextMenu", () => {
useSelectedOrganizationStore.setState({ organizationId: null });
});
it("should render the default context items for a user", () => {
it("should render the default context items for a user", async () => {
vi.spyOn(OptionService, "getConfig").mockResolvedValue(
createMockWebClientConfig({ app_mode: "saas" }),
);
renderUserContextMenu({ type: "member", onClose: vi.fn, onOpenInviteModal: vi.fn });
screen.getByTestId("org-selector");
screen.getByText("ACCOUNT_SETTINGS$LOGOUT");
// Wait for config to load so logout button appears
await waitFor(() => {
expect(screen.getByText("ACCOUNT_SETTINGS$LOGOUT")).toBeInTheDocument();
});
expect(
screen.queryByText("ORG$INVITE_ORG_MEMBERS"),
@@ -304,6 +312,20 @@ describe("UserContextMenu", () => {
screen.queryByText("Organization Members"),
).not.toBeInTheDocument();
});
it("should not display logout button in OSS mode", async () => {
renderUserContextMenu({ type: "member", onClose: vi.fn, onOpenInviteModal: vi.fn });
// Wait for the config to load
await waitFor(() => {
expect(screen.getByText("SETTINGS$NAV_LLM")).toBeInTheDocument();
});
// Verify logout button is NOT rendered in OSS mode
expect(
screen.queryByText("ACCOUNT_SETTINGS$LOGOUT"),
).not.toBeInTheDocument();
});
});
describe("HIDE_LLM_SETTINGS feature flag", () => {
@@ -382,10 +404,15 @@ describe("UserContextMenu", () => {
});
it("should call the logout handler when Logout is clicked", async () => {
vi.spyOn(OptionService, "getConfig").mockResolvedValue(
createMockWebClientConfig({ app_mode: "saas" }),
);
const logoutSpy = vi.spyOn(AuthService, "logout");
renderUserContextMenu({ type: "member", onClose: vi.fn, onOpenInviteModal: vi.fn });
const logoutButton = screen.getByText("ACCOUNT_SETTINGS$LOGOUT");
// Wait for config to load so logout button appears
const logoutButton = await screen.findByText("ACCOUNT_SETTINGS$LOGOUT");
await userEvent.click(logoutButton);
expect(logoutSpy).toHaveBeenCalledOnce();
@@ -488,6 +515,10 @@ describe("UserContextMenu", () => {
});
it("should call the onClose handler after each action", async () => {
vi.spyOn(OptionService, "getConfig").mockResolvedValue(
createMockWebClientConfig({ app_mode: "saas" }),
);
// Mock a team org so org management buttons are visible
vi.spyOn(organizationService, "getOrganizations").mockResolvedValue({
items: [MOCK_TEAM_ORG_ACME],
@@ -497,7 +528,8 @@ describe("UserContextMenu", () => {
const onCloseMock = vi.fn();
renderUserContextMenu({ type: "owner", onClose: onCloseMock, onOpenInviteModal: vi.fn });
const logoutButton = screen.getByText("ACCOUNT_SETTINGS$LOGOUT");
// Wait for config to load so logout button appears
const logoutButton = await screen.findByText("ACCOUNT_SETTINGS$LOGOUT");
await userEvent.click(logoutButton);
expect(onCloseMock).toHaveBeenCalledTimes(1);

View File

@@ -156,6 +156,8 @@ export function UserContextMenu({
{t(I18nKey.SIDEBAR$DOCS)}
</a>
{/* Only show logout in saas mode - oss mode has no session to invalidate */}
{isSaasMode && (
<ContextMenuListItem
onClick={handleLogout}
className={contextMenuListItemClassName}
@@ -163,6 +165,7 @@ export function UserContextMenu({
<IoLogOutOutline className="text-white" size={16} />
{t(I18nKey.ACCOUNT_SETTINGS$LOGOUT)}
</ContextMenuListItem>
)}
</div>
</div>
</div>

View File

@@ -35,13 +35,14 @@ export const useGitUser = () => {
}
}, [user.data]);
// If we get a 401 here, it means that the integration tokens need to be
// In saas mode, a 401 means that the integration tokens need to be
// refreshed. Since this happens at login, we log out.
// In oss mode, skip auto-logout since there's no token refresh mechanism
React.useEffect(() => {
if (user?.error?.response?.status === 401) {
if (user?.error?.response?.status === 401 && config?.app_mode === "saas") {
logout.mutate();
}
}, [user.status]);
}, [user.status, config?.app_mode]);
return user;
};