mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-07-21 20:06:06 +00:00
fix(tenancy): close isolation and permission gaps
This commit is contained in:
@@ -53,3 +53,130 @@ test('terminal invitation errors refresh on a new fragment and allow account swi
|
||||
})),
|
||||
).toEqual({ token: null, userEmail: null });
|
||||
});
|
||||
|
||||
test('login preserves an explicit invitation email mismatch error', async ({
|
||||
page,
|
||||
}) => {
|
||||
await installLangBotApiMocks(page, { authenticated: false });
|
||||
await page.route('**/api/v1/invitations/inspect', async (route) => {
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
body: JSON.stringify({
|
||||
code: 0,
|
||||
data: {
|
||||
invitation: {
|
||||
uuid: 'mismatch-invitation',
|
||||
workspace_uuid: 'workspace-playwright',
|
||||
normalized_email: 'invited@example.com',
|
||||
role: 'viewer',
|
||||
status: 'pending',
|
||||
},
|
||||
workspace: {
|
||||
uuid: 'workspace-playwright',
|
||||
name: 'Playwright Workspace',
|
||||
},
|
||||
},
|
||||
msg: 'ok',
|
||||
}),
|
||||
});
|
||||
});
|
||||
await page.route('**/api/v1/invitations/accept', async (route) => {
|
||||
await route.fulfill({
|
||||
status: 400,
|
||||
contentType: 'application/json',
|
||||
body: JSON.stringify({
|
||||
code: 'invitation_email_mismatch',
|
||||
msg: 'Invitation email does not match the Account',
|
||||
}),
|
||||
});
|
||||
});
|
||||
|
||||
await page.goto('/invitations/accept#token=mismatch-invitation');
|
||||
await page.getByRole('button', { name: 'I already have an account' }).click();
|
||||
await page.getByPlaceholder('Enter email address').fill('other@example.com');
|
||||
await page.getByPlaceholder('Enter password').fill('password');
|
||||
await page.getByRole('button', { name: 'Login with password' }).click();
|
||||
|
||||
await expect(page).toHaveURL(
|
||||
/\/invitations\/accept\?error=invitation_email_mismatch$/,
|
||||
);
|
||||
await expect(
|
||||
page.getByText('This invitation belongs to a different email address.'),
|
||||
).toBeVisible();
|
||||
await expect(page.getByText('Login successful')).toHaveCount(0);
|
||||
});
|
||||
|
||||
test('a temporary accept failure keeps the authenticated invitation retryable', async ({
|
||||
page,
|
||||
}) => {
|
||||
await installLangBotApiMocks(page, { authenticated: false });
|
||||
await page.route('**/api/v1/invitations/inspect', async (route) => {
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
body: JSON.stringify({
|
||||
code: 0,
|
||||
data: {
|
||||
invitation: {
|
||||
uuid: 'retryable-invitation',
|
||||
workspace_uuid: 'workspace-playwright',
|
||||
normalized_email: 'invited@example.com',
|
||||
role: 'viewer',
|
||||
status: 'pending',
|
||||
},
|
||||
workspace: {
|
||||
uuid: 'workspace-playwright',
|
||||
name: 'Playwright Workspace',
|
||||
},
|
||||
},
|
||||
msg: 'ok',
|
||||
}),
|
||||
});
|
||||
});
|
||||
let acceptAttempts = 0;
|
||||
await page.route('**/api/v1/invitations/accept', async (route) => {
|
||||
acceptAttempts += 1;
|
||||
if (acceptAttempts === 1) {
|
||||
await route.fulfill({
|
||||
status: 503,
|
||||
contentType: 'application/json',
|
||||
body: JSON.stringify({
|
||||
code: 'temporary_failure',
|
||||
msg: 'Please retry',
|
||||
}),
|
||||
});
|
||||
return;
|
||||
}
|
||||
await route.fulfill({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
body: JSON.stringify({
|
||||
code: 0,
|
||||
data: {
|
||||
token: 'accepted-token',
|
||||
workspace_uuid: 'workspace-playwright',
|
||||
},
|
||||
msg: 'ok',
|
||||
}),
|
||||
});
|
||||
});
|
||||
|
||||
await page.goto('/invitations/accept#token=retryable-invitation');
|
||||
await page.getByRole('button', { name: 'I already have an account' }).click();
|
||||
await page
|
||||
.getByPlaceholder('Enter email address')
|
||||
.fill('invited@example.com');
|
||||
await page.getByPlaceholder('Enter password').fill('password');
|
||||
await page.getByRole('button', { name: 'Login with password' }).click();
|
||||
|
||||
await expect(page).toHaveURL(/\/invitations\/accept$/);
|
||||
await expect(
|
||||
page.getByRole('button', { name: 'Accept with current account' }),
|
||||
).toBeVisible();
|
||||
await page
|
||||
.getByRole('button', { name: 'Accept with current account' })
|
||||
.click();
|
||||
await expect(page).toHaveURL(/\/home(?:\/monitoring)?$/);
|
||||
expect(acceptAttempts).toBe(2);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user