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
9 changes: 7 additions & 2 deletions packages/cloud/src/Config.ts
Original file line number Diff line number Diff line change
@@ -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
16 changes: 6 additions & 10 deletions src/core/webview/ClineProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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" })
}
}

/**
Expand Down Expand Up @@ -1466,6 +1466,7 @@ export class ClineProvider
codebaseIndexEmbedderBaseUrl: "",
codebaseIndexEmbedderModelId: "",
},
mdmCompliant: this.checkMdmCompliance(),
}
}

Expand Down Expand Up @@ -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
}

Expand Down
4 changes: 2 additions & 2 deletions src/services/mdm/MdmService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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) {
Expand Down
26 changes: 18 additions & 8 deletions src/services/mdm/__tests__/MdmService.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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", () => ({
Expand All @@ -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
Expand All @@ -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),
Expand All @@ -73,6 +79,8 @@ describe("MdmService", () => {

// Reset mocks
vi.clearAllMocks()
// Re-setup the default after clearing
mockGetClerkBaseUrl.mockReturnValue("https://dev.clerk.roocode.com")
})

afterEach(() => {
Expand Down Expand Up @@ -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)

Expand All @@ -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)

Expand All @@ -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)

Expand All @@ -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)

Expand All @@ -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)

Expand All @@ -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)

Expand All @@ -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)

Expand Down Expand Up @@ -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()
Expand All @@ -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")
Expand Down
25 changes: 17 additions & 8 deletions webview-ui/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ const App = () => {
experiments,
cloudUserInfo,
cloudIsAuthenticated,
mdmCompliant,
} = useExtensionState()

// Create a persistent state manager
Expand All @@ -63,15 +64,23 @@ const App = () => {
const settingsRef = useRef<SettingsViewRef>(null)
const chatViewRef = useRef<ChatViewRef>(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<string | undefined>(undefined)

Expand Down
1 change: 1 addition & 0 deletions webview-ui/src/context/ExtensionStateContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading