From 366f1ea7064cf8f4cc853ce7a91542a78dc35baf Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Sat, 2 May 2026 16:35:19 -0700 Subject: [PATCH] fix(msteams): use manual delegated oauth setup --- extensions/msteams/src/setup-surface.test.ts | 27 -------------------- extensions/msteams/src/setup-surface.ts | 21 +++------------ 2 files changed, 4 insertions(+), 44 deletions(-) diff --git a/extensions/msteams/src/setup-surface.test.ts b/extensions/msteams/src/setup-surface.test.ts index 85cd8d45a07..a3effc8a445 100644 --- a/extensions/msteams/src/setup-surface.test.ts +++ b/extensions/msteams/src/setup-surface.test.ts @@ -1,10 +1,7 @@ -import { EventEmitter } from "node:events"; import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/setup"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { createMSTeamsSetupWizardBase, msteamsSetupAdapter } from "./setup-core.js"; -import { openDelegatedOAuthUrl } from "./setup-surface.js"; -const spawn = vi.hoisted(() => vi.fn()); const resolveMSTeamsUserAllowlist = vi.hoisted(() => vi.fn()); const resolveMSTeamsChannelAllowlist = vi.hoisted(() => vi.fn()); const normalizeSecretInputString = vi.hoisted(() => @@ -28,19 +25,10 @@ vi.mock("./token.js", () => ({ resolveMSTeamsCredentials, })); -vi.mock("node:child_process", async (importOriginal) => { - const actual = await importOriginal(); - return { - ...actual, - spawn, - }; -}); - describe("msteams setup surface", () => { const msteamsSetupWizard = createMSTeamsSetupWizardBase(); beforeEach(() => { - spawn.mockReset(); resolveMSTeamsUserAllowlist.mockReset(); resolveMSTeamsChannelAllowlist.mockReset(); normalizeSecretInputString.mockClear(); @@ -58,21 +46,6 @@ describe("msteams setup surface", () => { ); }); - it("opens delegated OAuth URLs without invoking a shell", async () => { - const url = "https://login.microsoftonline.com/auth?state=$(touch pwned)"; - const child = new EventEmitter(); - spawn.mockReturnValue(child); - - const result = openDelegatedOAuthUrl(url); - child.emit("exit", 0, null); - - await expect(result).resolves.toBeUndefined(); - expect(spawn).toHaveBeenCalledWith(process.platform === "darwin" ? "open" : "xdg-open", [url], { - stdio: "ignore", - shell: false, - }); - }); - it("enables the msteams channel without dropping existing config", () => { expect( msteamsSetupAdapter.applyAccountConfig?.({ diff --git a/extensions/msteams/src/setup-surface.ts b/extensions/msteams/src/setup-surface.ts index 5c612cc6ee2..0a625dde1f7 100644 --- a/extensions/msteams/src/setup-surface.ts +++ b/extensions/msteams/src/setup-surface.ts @@ -1,4 +1,3 @@ -import { spawn } from "node:child_process"; import { createTopLevelChannelAllowFromSetter, createTopLevelChannelDmPolicy, @@ -30,19 +29,9 @@ const setMSTeamsGroupPolicy = createTopLevelChannelGroupPolicySetter({ }); export function openDelegatedOAuthUrl(url: string): Promise { - return new Promise((resolve, reject) => { - const cmd = process.platform === "darwin" ? "open" : "xdg-open"; - const child = spawn(cmd, [url], { stdio: "ignore", shell: false }); - child.once("error", reject); - child.once("exit", (code, signal) => { - if (code === 0) { - resolve(); - return; - } - const reason = signal ? `signal ${signal}` : `code ${code ?? "unknown"}`; - reject(new Error(`${cmd} failed with ${reason}`)); - }); - }); + return Promise.reject( + new Error(`Automatic browser launch is not available. Open this URL manually: ${url}`), + ); } function looksLikeGuid(value: string): boolean { @@ -277,12 +266,10 @@ export const msteamsSetupWizard: ChannelSetupWizard = { }; try { const { loginMSTeamsDelegated } = await import("./oauth.js"); - const { shouldUseManualOAuthFlow } = await import("./oauth.flow.js"); - const isRemote = Boolean(process.env.SSH_TTY || process.env.SSH_CONNECTION); const progress = params.prompter.progress("MSTeams Delegated OAuth"); const tokens = await loginMSTeamsDelegated( { - isRemote: shouldUseManualOAuthFlow(isRemote), + isRemote: true, openUrl: openDelegatedOAuthUrl, log: (msg) => params.prompter.note(msg), note: (msg, title) => params.prompter.note(msg, title),