From ecfe769200530cbc7e27453981884d586daf0e37 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Mon, 16 Jun 2025 21:58:32 -0400 Subject: [PATCH 1/3] Better check for production clerk --- packages/cloud/src/Config.ts | 9 +++++++-- src/services/mdm/MdmService.ts | 4 ++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/cloud/src/Config.ts b/packages/cloud/src/Config.ts index 0205e5b0e3c..08b0cc7a188 100644 --- a/packages/cloud/src/Config.ts +++ b/packages/cloud/src/Config.ts @@ -1,2 +1,7 @@ -export const getClerkBaseUrl = () => process.env.CLERK_BASE_URL || "https://clerk.roocode.com" -export const getRooCodeApiUrl = () => process.env.ROO_CODE_API_URL || "https://app.roocode.com" +// Production constants +export const PRODUCTION_CLERK_BASE_URL = "https://clerk.roocode.com" +export const PRODUCTION_ROO_CODE_API_URL = "https://app.roocode.com" + +// Functions with environment variable fallbacks +export const getClerkBaseUrl = () => process.env.CLERK_BASE_URL || PRODUCTION_CLERK_BASE_URL +export const getRooCodeApiUrl = () => process.env.ROO_CODE_API_URL || PRODUCTION_ROO_CODE_API_URL diff --git a/src/services/mdm/MdmService.ts b/src/services/mdm/MdmService.ts index da4e7dfc049..b649f4d4a27 100644 --- a/src/services/mdm/MdmService.ts +++ b/src/services/mdm/MdmService.ts @@ -4,7 +4,7 @@ import * as os from "os" import * as vscode from "vscode" import { z } from "zod" -import { CloudService } from "@roo-code/cloud" +import { CloudService, getClerkBaseUrl, PRODUCTION_CLERK_BASE_URL } from "@roo-code/cloud" import { Package } from "../../shared/package" // MDM Configuration Schema @@ -145,7 +145,7 @@ export class MdmService { */ private getMdmConfigPath(): string { const platform = os.platform() - const isProduction = process.env.NODE_ENV === "production" + const isProduction = getClerkBaseUrl() === PRODUCTION_CLERK_BASE_URL const configFileName = isProduction ? "mdm.json" : "mdm.dev.json" switch (platform) { From b9888d54e08f8cbe5f96006fb10937c4658be154 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Mon, 16 Jun 2025 23:20:06 -0400 Subject: [PATCH 2/3] Send to account tab if required --- src/core/webview/ClineProvider.ts | 16 +++++------- webview-ui/src/App.tsx | 25 +++++++++++++------ .../src/context/ExtensionStateContext.tsx | 1 + 3 files changed, 24 insertions(+), 18 deletions(-) diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts index b486015f1bd..7b3589c3b51 100644 --- a/src/core/webview/ClineProvider.ts +++ b/src/core/webview/ClineProvider.ts @@ -529,11 +529,6 @@ export class ClineProvider > > = {}, ) { - // Check MDM compliance before proceeding - if (!this.checkMdmCompliance()) { - return // Block task creation if not compliant - } - const { apiConfiguration, organizationAllowList, @@ -1252,6 +1247,11 @@ export class ClineProvider // Update VSCode context for experiments await this.updateVSCodeContext() + + // Check MDM compliance and send user to account tab if not compliant + if (!this.checkMdmCompliance()) { + await this.postMessageToWebview({ type: "action", action: "accountButtonClicked" }) + } } /** @@ -1466,6 +1466,7 @@ export class ClineProvider codebaseIndexEmbedderBaseUrl: "", codebaseIndexEmbedderModelId: "", }, + mdmCompliant: this.checkMdmCompliance(), } } @@ -1721,11 +1722,6 @@ export class ClineProvider const compliance = this.mdmService.isCompliant() if (!compliance.compliant) { - vscode.window.showErrorMessage(compliance.reason, "Sign In").then((selection) => { - if (selection === "Sign In") { - this.postMessageToWebview({ type: "action", action: "accountButtonClicked" }) - } - }) return false } diff --git a/webview-ui/src/App.tsx b/webview-ui/src/App.tsx index 505cb0b6eed..61d892c2340 100644 --- a/webview-ui/src/App.tsx +++ b/webview-ui/src/App.tsx @@ -42,6 +42,7 @@ const App = () => { experiments, cloudUserInfo, cloudIsAuthenticated, + mdmCompliant, } = useExtensionState() // Create a persistent state manager @@ -63,15 +64,23 @@ const App = () => { const settingsRef = useRef(null) const chatViewRef = useRef(null) - const switchTab = useCallback((newTab: Tab) => { - setCurrentSection(undefined) + const switchTab = useCallback( + (newTab: Tab) => { + // Check MDM compliance before allowing tab switching + if (mdmCompliant === false && newTab !== "account") { + return + } - if (settingsRef.current?.checkUnsaveChanges) { - settingsRef.current.checkUnsaveChanges(() => setTab(newTab)) - } else { - setTab(newTab) - } - }, []) + setCurrentSection(undefined) + + if (settingsRef.current?.checkUnsaveChanges) { + settingsRef.current.checkUnsaveChanges(() => setTab(newTab)) + } else { + setTab(newTab) + } + }, + [mdmCompliant], + ) const [currentSection, setCurrentSection] = useState(undefined) diff --git a/webview-ui/src/context/ExtensionStateContext.tsx b/webview-ui/src/context/ExtensionStateContext.tsx index ab79f63df88..6898051c6de 100644 --- a/webview-ui/src/context/ExtensionStateContext.tsx +++ b/webview-ui/src/context/ExtensionStateContext.tsx @@ -37,6 +37,7 @@ export interface ExtensionStateContextType extends ExtensionState { cloudIsAuthenticated: boolean sharingEnabled: boolean maxConcurrentFileReads?: number + mdmCompliant?: boolean condensingApiConfigId?: string setCondensingApiConfigId: (value: string) => void customCondensingPrompt?: string From 38fb1e0735c340baa0e75e630d4a9827c65cd30c Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Mon, 16 Jun 2025 23:38:01 -0400 Subject: [PATCH 3/3] Fix tests --- src/services/mdm/__tests__/MdmService.spec.ts | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/services/mdm/__tests__/MdmService.spec.ts b/src/services/mdm/__tests__/MdmService.spec.ts index b2fce5fb9ef..79ce83c3b52 100644 --- a/src/services/mdm/__tests__/MdmService.spec.ts +++ b/src/services/mdm/__tests__/MdmService.spec.ts @@ -19,6 +19,8 @@ vi.mock("@roo-code/cloud", () => ({ getOrganizationId: vi.fn(), }, }, + getClerkBaseUrl: vi.fn(), + PRODUCTION_CLERK_BASE_URL: "https://clerk.roocode.com", })) vi.mock("vscode", () => ({ @@ -44,12 +46,13 @@ import * as fs from "fs" import * as os from "os" import * as vscode from "vscode" import { MdmService } from "../MdmService" -import { CloudService } from "@roo-code/cloud" +import { CloudService, getClerkBaseUrl, PRODUCTION_CLERK_BASE_URL } from "@roo-code/cloud" const mockFs = fs as any const mockOs = os as any const mockCloudService = CloudService as any const mockVscode = vscode as any +const mockGetClerkBaseUrl = getClerkBaseUrl as any describe("MdmService", () => { let originalPlatform: string @@ -64,6 +67,9 @@ describe("MdmService", () => { // Set default platform for tests mockOs.platform.mockReturnValue("darwin") + // Setup default mock for getClerkBaseUrl to return development URL + mockGetClerkBaseUrl.mockReturnValue("https://dev.clerk.roocode.com") + // Setup VSCode mocks const mockConfig = { get: vi.fn().mockReturnValue(false), @@ -73,6 +79,8 @@ describe("MdmService", () => { // Reset mocks vi.clearAllMocks() + // Re-setup the default after clearing + mockGetClerkBaseUrl.mockReturnValue("https://dev.clerk.roocode.com") }) afterEach(() => { @@ -142,7 +150,7 @@ describe("MdmService", () => { it("should use correct path for Windows in production", async () => { mockOs.platform.mockReturnValue("win32") process.env.PROGRAMDATA = "C:\\ProgramData" - process.env.NODE_ENV = "production" + mockGetClerkBaseUrl.mockReturnValue(PRODUCTION_CLERK_BASE_URL) mockFs.existsSync.mockReturnValue(false) @@ -154,7 +162,7 @@ describe("MdmService", () => { it("should use correct path for Windows in development", async () => { mockOs.platform.mockReturnValue("win32") process.env.PROGRAMDATA = "C:\\ProgramData" - process.env.NODE_ENV = "development" + mockGetClerkBaseUrl.mockReturnValue("https://dev.clerk.roocode.com") mockFs.existsSync.mockReturnValue(false) @@ -165,7 +173,7 @@ describe("MdmService", () => { it("should use correct path for macOS in production", async () => { mockOs.platform.mockReturnValue("darwin") - process.env.NODE_ENV = "production" + mockGetClerkBaseUrl.mockReturnValue(PRODUCTION_CLERK_BASE_URL) mockFs.existsSync.mockReturnValue(false) @@ -176,7 +184,7 @@ describe("MdmService", () => { it("should use correct path for macOS in development", async () => { mockOs.platform.mockReturnValue("darwin") - process.env.NODE_ENV = "development" + mockGetClerkBaseUrl.mockReturnValue("https://dev.clerk.roocode.com") mockFs.existsSync.mockReturnValue(false) @@ -187,7 +195,7 @@ describe("MdmService", () => { it("should use correct path for Linux in production", async () => { mockOs.platform.mockReturnValue("linux") - process.env.NODE_ENV = "production" + mockGetClerkBaseUrl.mockReturnValue(PRODUCTION_CLERK_BASE_URL) mockFs.existsSync.mockReturnValue(false) @@ -198,7 +206,7 @@ describe("MdmService", () => { it("should use correct path for Linux in development", async () => { mockOs.platform.mockReturnValue("linux") - process.env.NODE_ENV = "development" + mockGetClerkBaseUrl.mockReturnValue("https://dev.clerk.roocode.com") mockFs.existsSync.mockReturnValue(false) @@ -209,7 +217,7 @@ describe("MdmService", () => { it("should default to dev config when NODE_ENV is not set", async () => { mockOs.platform.mockReturnValue("darwin") - delete process.env.NODE_ENV + mockGetClerkBaseUrl.mockReturnValue("https://dev.clerk.roocode.com") mockFs.existsSync.mockReturnValue(false) @@ -248,6 +256,7 @@ describe("MdmService", () => { mockFs.existsSync.mockReturnValue(true) mockFs.readFileSync.mockReturnValue(JSON.stringify(mockConfig)) + // Mock CloudService to indicate no instance or no active session mockCloudService.hasInstance.mockReturnValue(false) const service = await MdmService.createInstance() @@ -267,6 +276,7 @@ describe("MdmService", () => { mockFs.existsSync.mockReturnValue(true) mockFs.readFileSync.mockReturnValue(JSON.stringify(mockConfig)) + // Mock CloudService to have instance and active session but wrong org mockCloudService.hasInstance.mockReturnValue(true) mockCloudService.instance.hasActiveSession.mockReturnValue(true) mockCloudService.instance.getOrganizationId.mockReturnValue("different-org-456")