Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 48 additions & 1 deletion packages/deploy/src/connect.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import test from 'node:test';
import assert from 'node:assert/strict';
import { relayfileIntegrationResolver } from './connect.js';
import { connectIntegrations, relayfileIntegrationResolver } from './connect.js';
import { createBufferedIO } from './io.js';

function okJson(body: unknown, status = 200): Response {
Expand Down Expand Up @@ -100,3 +100,50 @@ test('relayfileIntegrationResolver connect times out clearly', async () => {
/Timed out waiting for github OAuth/
);
});

test('connectIntegrations fails fast on auth errors without prompting to connect', async () => {
const io = createBufferedIO();
let connectCalled = false;
let confirmCalled = false;
io.confirm = async () => {
confirmCalled = true;
return true;
};

const result = await connectIntegrations({
persona: {
id: 'essay',
intent: 'essay',
description: 'test persona',
tags: ['implementation'],
integrations: { notion: {} }
} as never,
workspace: 'ws-1',
noConnect: false,
io,
integrations: {
async isConnected() {
throw new Error(
'cloud integration request failed: unauthorized. Open https://origin.agentrelay.cloud/cloud to verify your cloud session, then run `agent-relay cloud whoami` and `agentworkforce login` to refresh the active workspace.'
);
},
async connect() {
connectCalled = true;
throw new Error('connect should not be called after auth failure');
}
}
});

assert.equal(confirmCalled, false);
assert.equal(connectCalled, false);
assert.deepEqual(result.outcomes, [
{
provider: 'notion',
status: 'failed',
message:
'cloud integration request failed: unauthorized. Open https://origin.agentrelay.cloud/cloud to verify your cloud session, then run `agent-relay cloud whoami` and `agentworkforce login` to refresh the active workspace.'
}
]);
assert.ok(io.messages.some((message) => message.level === 'warn' && message.message.includes('failed to check connection status for notion')));
assert.ok(io.messages.some((message) => message.level === 'error' && message.message.includes('auth failed')));
});
Comment thread
coderabbitai[bot] marked this conversation as resolved.
27 changes: 25 additions & 2 deletions packages/deploy/src/connect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,11 +183,13 @@ export async function connectIntegrations(input: ConnectAllInput): Promise<Conne
const outcomes: IntegrationConnectOutcome[] = [];

for (const provider of Object.keys(integrations)) {
let statusCheckFailure: string | undefined;
const connected = await input.integrations
.isConnected({ workspace: input.workspace, provider })
.catch((err) => {
statusCheckFailure = err instanceof Error ? err.message : String(err);
input.io.warn(
`failed to check connection status for ${provider}: ${err instanceof Error ? err.message : String(err)}`
`failed to check connection status for ${provider}: ${statusCheckFailure}`
);
return false;
});
Expand All @@ -198,6 +200,16 @@ export async function connectIntegrations(input: ConnectAllInput): Promise<Conne
continue;
}

if (statusCheckFailure && isIntegrationAuthFailure(statusCheckFailure)) {
input.io.error(`integrations.${provider}: auth failed while checking connection status`);
outcomes.push({
provider,
status: 'failed',
message: statusCheckFailure
});
continue;
}

if (input.noConnect) {
input.io.error(
`integrations.${provider}: not connected, and prompts are disabled`
Expand Down Expand Up @@ -285,14 +297,25 @@ async function requestJson(
}
});
if (res.status === 401) {
throw new Error('cloud integration request failed: unauthorized. Run `agentworkforce login` and retry.');
throw new Error(
'cloud integration request failed: unauthorized. Open https://origin.agentrelay.cloud/cloud to verify your cloud session, then run `agent-relay cloud whoami` and `agentworkforce login` to refresh the active workspace.'
);
}
if (res.status === 403) {
throw new Error(
'cloud integration request failed: forbidden. The active account is not authorized for this workspace; open https://origin.agentrelay.cloud/cloud to verify account/workspace access, then run `agent-relay cloud whoami` and `agentworkforce login` to refresh the active workspace.'
);
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}
if (!res.ok) {
throw new Error(`cloud integration request failed: ${res.status} ${await res.text().catch(() => '')}`.trim());
}
return await res.json();
}

function isIntegrationAuthFailure(message: string): boolean {
return /cloud integration request failed: (unauthorized|forbidden)\b/i.test(message);
}

function listHasConnectedProvider(body: unknown, provider: string): boolean {
const candidates = Array.isArray(body)
? body
Expand Down
Loading