mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-28 20:21:50 +01:00
fix(connections): preserve wizard recovery and repository restrictions
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
cf8578a9dd
commit
87945c8cf3
15 files changed
+750
-189
No files matched your search
@@ -20,45 +20,44 @@ import {
|
||||
|
||||
async function exerciseGitHubReviewSetup(page: Page, mock: ChatMock, seed: Seed, provider: ProviderCase) {
|
||||
await expect(page.getByRole("heading", { name: "Choose agent", exact: true })).toBeVisible();
|
||||
await page.getByRole("button", { name: "Choose an agent", exact: true }).click();
|
||||
await page.getByRole("button", { name: "Select agent…", exact: true }).click();
|
||||
await page.getByRole("button", { name: "Select Maya", exact: true }).click();
|
||||
await expect(page.getByText("Maya is not configured for low-trust review")).toBeVisible();
|
||||
await expect(page.getByRole("link", { name: "Learn about low-trust agents" })).toHaveAttribute("href", /trust-and-low-trust-review/);
|
||||
await page.getByRole("button", { name: "Change Maya to a low trust agent" }).click();
|
||||
await expect(page.getByText("Maya is not configured for low-trust review")).toHaveCount(0);
|
||||
await page.getByRole("button", { name: "Continue", exact: true }).click();
|
||||
await expect.poll(() => mock.createdWithAgentId).toBe(seed.agentId);
|
||||
await expect(page.getByRole("heading", { name: "Connect GitHub App", exact: true })).toBeVisible();
|
||||
await page.getByRole("button", { name: "Use an existing App" }).click();
|
||||
await expect(page.getByRole("heading", { name: "Connect GitHub", exact: true })).toBeVisible();
|
||||
await expect(page.getByLabel("GitHub account")).toHaveValue("personal");
|
||||
await expect(page.getByLabel("App name", { exact: true })).toHaveValue("Maya");
|
||||
await page.getByLabel("GitHub account").selectOption("organization");
|
||||
await page.getByLabel("Organization", { exact: true }).fill("paperclip-ai");
|
||||
await page.getByRole("button", { name: "Save & exit", exact: true }).click();
|
||||
await page.goto(`/${seed.prefix}/apps/chat/connect?provider=github&purpose=chat&resume=endpoint-github`);
|
||||
await expect(page.getByLabel("GitHub account")).toHaveValue("organization");
|
||||
await expect(page.getByLabel("Organization", { exact: true })).toHaveValue("paperclip-ai");
|
||||
await expect(page.getByRole("button", { name: "Select agent…", exact: true })).toHaveCount(0);
|
||||
// Existing-App recovery stays available and preserves entered credentials after failure.
|
||||
await page.getByRole("button", { name: "I already have an App" }).click();
|
||||
await page.getByLabel("App ID", { exact: true }).fill("123456");
|
||||
await page.getByLabel("Private key", { exact: true }).fill(GITHUB_PRIVATE_KEY_PASTE_FIXTURE);
|
||||
await page.getByLabel("Webhook secret", { exact: true }).fill("github-webhook-secret");
|
||||
await page.getByRole("button", { name: "Connect App", exact: true }).click();
|
||||
await page.getByRole("button", { name: "Connect existing App", exact: true }).click();
|
||||
await expect(page.getByRole("alert")).toContainText("GitHub rejected the supplied App credentials.");
|
||||
await expect(page.getByLabel("Private key", { exact: true })).toHaveValue(GITHUB_PRIVATE_KEY_PASTE_FIXTURE);
|
||||
await page.getByRole("button", { name: "Connect App", exact: true }).click();
|
||||
await expect(page.getByRole("heading", { name: "Install GitHub App", exact: true })).toBeVisible();
|
||||
await expect(page.getByText(provider.resourceLabel, { exact: true })).toHaveCount(0);
|
||||
await page.getByRole("button", { name: "I’ve installed the App" }).click();
|
||||
await expect(page.getByRole("heading", { name: "Select repositories", exact: true })).toBeVisible();
|
||||
await expect(page.getByRole("link", { name: "Configure access on GitHub" })).toHaveAttribute("href", "https://github.com/settings/installations/2468");
|
||||
await page.getByRole("button", { name: "Refresh access" }).click();
|
||||
await expect.poll(() => mock.githubRepositoryRefreshes).toBe(2);
|
||||
await page.getByRole("switch", { name: provider.resourceLabel, exact: true }).click();
|
||||
await page.getByRole("button", { name: "Save repositories" }).click();
|
||||
await expect(page.getByRole("heading", { name: "Verify connection & tools", exact: true })).toBeVisible();
|
||||
await page.getByRole("button", { name: "Verify connection", exact: true }).click();
|
||||
await expect(page.getByRole("button", { name: "Continue", exact: true })).toBeDisabled();
|
||||
await page.getByRole("button", { name: "Assign this bot’s GitHub tools" }).click();
|
||||
await page.getByRole("button", { name: "Continue", exact: true }).click();
|
||||
await page.getByRole("button", { name: "Connect existing App", exact: true }).click();
|
||||
await expect(page.getByRole("heading", { name: "Connect your account", exact: true })).toBeVisible();
|
||||
await page.getByLabel("Your GitHub connection").selectOption("personal-github");
|
||||
await page.getByRole("button", { name: "Verify my account" }).click();
|
||||
await page.getByLabel("Existing GitHub connection").selectOption("personal-github");
|
||||
await expect(page.getByRole("button", { name: "Check my account" })).toBeVisible();
|
||||
await page.getByRole("button", { name: "Check my account" }).click();
|
||||
expect(mock.githubIdentityConfirmed).toBe(false);
|
||||
await page.getByRole("button", { name: "Confirm this is my account" }).click();
|
||||
await page.getByRole("button", { name: "Confirm my account" }).click();
|
||||
await expect.poll(() => mock.githubIdentityConfirmed).toBe(true);
|
||||
await expect(page.getByRole("heading", { name: "Configure behavior", exact: true })).toBeVisible();
|
||||
await page.getByRole("button", { name: "Save behavior" }).click();
|
||||
await expect(page.getByRole("heading", { name: "Try it", exact: true })).toBeVisible();
|
||||
await page.getByRole("button", { name: "Finish without test" }).click();
|
||||
await expect(page.getByRole("heading", { name: "GitHub connected", exact: true })).toBeVisible();
|
||||
await expect(page.getByText(provider.resourceLabel, { exact: true })).toBeVisible();
|
||||
await expect(page.getByRole("button", { name: /Finish|Verify connection|Refresh access|Save repositories/ })).toHaveCount(0);
|
||||
await page.getByRole("link", { name: "Connection settings", exact: true }).click();
|
||||
await expect(page).toHaveURL(/\/apps\/chat\/endpoint-github\/settings$/);
|
||||
const nav = page.getByRole("navigation", { name: "Chat connection" });
|
||||
for (const tab of ["Settings", "Access", "Reviews", "Conversations", "Activity"]) {
|
||||
@@ -82,8 +81,8 @@ async function exerciseGitHubReviewSetup(page: Page, mock: ChatMock, seed: Seed,
|
||||
await page.reload();
|
||||
await page.getByText("Connection health and controls", { exact: true }).click();
|
||||
await page.getByRole("button", { name: "Reconnect", exact: true }).click();
|
||||
await expect(page.getByRole("heading", { name: "Connect GitHub App", exact: true })).toBeVisible();
|
||||
await expect(page.getByText(/Leave the credentials blank to keep them/)).toBeVisible();
|
||||
await expect(page.getByRole("heading", { name: "Connect GitHub", exact: true })).toBeVisible();
|
||||
await expect(page.getByText(/Leave these blank to reuse/)).toBeVisible();
|
||||
await expect(page.getByRole("button", { name: "Choose an agent", exact: true })).toHaveCount(0);
|
||||
await expect(page.getByLabel("Private key", { exact: true })).toHaveValue("");
|
||||
const reconnectResponse = page.waitForResponse((response) =>
|
||||
@@ -95,7 +94,7 @@ async function exerciseGitHubReviewSetup(page: Page, mock: ChatMock, seed: Seed,
|
||||
const reconnected = await reconnectResponse;
|
||||
expect(reconnected.request().postDataJSON()).toEqual({ action: "reconnect" });
|
||||
expect(await reconnected.json()).toMatchObject({ assignedAgentId: seed.agentId, assignedAgentName: "Maya" });
|
||||
await expect(page.getByRole("heading", { name: "Verify connection & tools", exact: true })).toBeVisible();
|
||||
await expect(page.getByRole("heading", { name: "GitHub connected", exact: true })).toBeVisible();
|
||||
mock.setStatus("active");
|
||||
await page.goto(`/${seed.prefix}/apps/chat/endpoint-github/settings`);
|
||||
await expect(page.getByText(/Maya is permanently assigned to this bot/)).toBeVisible();
|
||||
|
||||
@@ -425,6 +425,18 @@ export async function installChatControlPlaneMock(
|
||||
if (provider.provider === "github" && pathname.startsWith(`/api/chat-endpoints/${endpoint.id}/github/`)) {
|
||||
const operation = pathname.split("/github/")[1];
|
||||
const body = method === "GET" ? {} : bodyOf(route);
|
||||
if (operation === "setup") {
|
||||
if (!githubAppConnected) { await fulfill(route, { endpointId: endpoint.id, state: "create" }); return; }
|
||||
if (!state.githubIdentityConfirmed) { await fulfill(route, { endpointId: endpoint.id, state: "identity", identityMethod: "existing_connection" }); return; }
|
||||
githubConfiguration.configuration.toolsEnabled = true;
|
||||
resource.enabled = true;
|
||||
Object.assign(endpoint, { status: "active", botExternalId: "123456", resources: [resource], setup: { ...endpoint.setup, step: "complete" } });
|
||||
await fulfill(route, { endpointId: endpoint.id, state: "connected", identityLinked: true, verification: { ready: true, checks: [] } }); return;
|
||||
}
|
||||
if (operation === "draft") {
|
||||
Object.assign(endpoint.setup, { github: { ...endpoint.setup.github, appName: body.name, ownerType: body.ownerType, ownerLogin: body.ownerLogin } });
|
||||
await fulfill(route, endpoint); return;
|
||||
}
|
||||
if (operation === "configuration") {
|
||||
if (method === "PUT") { expect(body.expectedRevision).toBe(githubConfiguration.revision); githubConfiguration = { revision: githubConfiguration.revision + 1, configuration: body.configuration as typeof githubConfiguration.configuration }; }
|
||||
await fulfill(route, githubConfiguration); return;
|
||||
@@ -438,7 +450,7 @@ export async function installChatControlPlaneMock(
|
||||
state.configuredCredentialKeys = Object.keys(body).sort();
|
||||
if (state.setupAttempts === 1) { await fulfill(route, { error: "GitHub rejected the supplied App credentials." }, 422); return; }
|
||||
githubAppConnected = true;
|
||||
Object.assign(endpoint, { status: "attention", botUsername: "maya-paperclip[bot]" });
|
||||
Object.assign(endpoint, { status: "attention", botExternalId: "123456", botUsername: "maya-paperclip[bot]", botLabel: "Maya" });
|
||||
Object.assign(endpoint.setup, { github: { stage: "install", appSlug: "maya-paperclip", installationUrl: "https://github.com/apps/maya-paperclip/installations/new", managementUrl: "https://github.com/settings/installations/2468" } });
|
||||
await fulfill(route, endpoint); return;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user