Skip to content
This repository was archived by the owner on May 15, 2026. It is now read-only.

Commit d08f26c

Browse files
committed
fix(ClineProvider): strip openRouterImageApiKey from webview broadcast
1 parent 0892455 commit d08f26c

5 files changed

Lines changed: 29 additions & 5 deletions

File tree

packages/types/src/vscode-extension-host.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,7 @@ export type ExtensionState = Pick<
365365
marketplaceInstalledMetadata?: { project: Record<string, any>; global: Record<string, any> }
366366
profileThresholds: Record<string, number>
367367
hasOpenedModeSelector: boolean
368-
openRouterImageApiKey?: string
368+
openRouterImageApiKeyConfigured: boolean
369369
messageQueue?: QueuedMessage[]
370370
lastShownAnnouncementId?: string
371371
apiModelId?: string

src/core/webview/ClineProvider.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2352,7 +2352,7 @@ export class ClineProvider
23522352
maxGitStatusFiles: maxGitStatusFiles ?? 0,
23532353
taskSyncEnabled,
23542354
imageGenerationProvider,
2355-
openRouterImageApiKey,
2355+
openRouterImageApiKeyConfigured: !!openRouterImageApiKey,
23562356
openRouterImageGenerationSelectedModel,
23572357
openAiCodexIsAuthenticated: await (async () => {
23582358
try {
@@ -2376,7 +2376,7 @@ export class ClineProvider
23762376
Omit<
23772377
ExtensionState,
23782378
"clineMessages" | "renderContext" | "hasOpenedModeSelector" | "version" | "shouldShowAnnouncement"
2379-
>
2379+
> & { openRouterImageApiKey?: string }
23802380
> {
23812381
const stateValues = this.contextProxy.getValues()
23822382
const customModes = await this.customModesManager.getCustomModes()
@@ -2572,6 +2572,7 @@ export class ClineProvider
25722572
taskSyncEnabled,
25732573
imageGenerationProvider: stateValues.imageGenerationProvider,
25742574
openRouterImageApiKey: stateValues.openRouterImageApiKey,
2575+
openRouterImageApiKeyConfigured: !!stateValues.openRouterImageApiKey,
25752576
openRouterImageGenerationSelectedModel: stateValues.openRouterImageGenerationSelectedModel,
25762577
}
25772578
}

src/core/webview/__tests__/ClineProvider.spec.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -549,7 +549,7 @@ describe("ClineProvider", () => {
549549
profileThresholds: {},
550550
hasOpenedModeSelector: false,
551551
diagnosticsEnabled: true,
552-
openRouterImageApiKey: undefined,
552+
openRouterImageApiKeyConfigured: false,
553553
openRouterImageGenerationSelectedModel: undefined,
554554
taskSyncEnabled: false,
555555
checkpointTimeout: DEFAULT_CHECKPOINT_TIMEOUT_SECONDS,
@@ -564,6 +564,27 @@ describe("ClineProvider", () => {
564564
expect(mockPostMessage).toHaveBeenCalledWith(message)
565565
})
566566

567+
describe("getStateToPostToWebview secrets redaction", () => {
568+
test("omits raw openRouterImageApiKey from broadcast payload when key is set", async () => {
569+
// Use contextProxy.setValue rather than mocking secrets.get because ContextProxy only
570+
// reads secrets.get during initialize() (which ran during provider construction). Any
571+
// mock changes after construction are too late — they never reach secretCache.
572+
await provider.contextProxy.setValue("openRouterImageApiKey", "sk-or-v1-supersecret")
573+
574+
const state = await provider.getStateToPostToWebview()
575+
576+
expect("openRouterImageApiKey" in state).toBe(false)
577+
expect(state.openRouterImageApiKeyConfigured).toBe(true)
578+
})
579+
580+
test("sets openRouterImageApiKeyConfigured to false when no key is stored", async () => {
581+
const state = await provider.getStateToPostToWebview()
582+
583+
expect("openRouterImageApiKey" in state).toBe(false)
584+
expect(state.openRouterImageApiKeyConfigured).toBe(false)
585+
})
586+
})
587+
567588
test("postMessageToWebview does not throw when webview is disposed", async () => {
568589
await provider.resolveWebviewView(mockWebviewView)
569590

webview-ui/src/context/ExtensionStateContext.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
258258
codebaseIndexModels: { ollama: {}, openai: {} },
259259
includeDiagnosticMessages: true,
260260
maxDiagnosticMessages: 50,
261-
openRouterImageApiKey: "",
261+
openRouterImageApiKeyConfigured: false,
262262
openRouterImageGenerationSelectedModel: "",
263263
includeCurrentTime: true,
264264
includeCurrentCost: true,

webview-ui/src/context/__tests__/ExtensionStateContext.spec.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,7 @@ describe("mergeExtensionState", () => {
217217
taskSyncEnabled: false,
218218
checkpointTimeout: DEFAULT_CHECKPOINT_TIMEOUT_SECONDS, // Add the checkpoint timeout property
219219
maxReadFileLine: -1,
220+
openRouterImageApiKeyConfigured: false,
220221
}
221222

222223
const prevState: ExtensionState = {
@@ -286,6 +287,7 @@ describe("mergeExtensionState", () => {
286287
taskSyncEnabled: false,
287288
checkpointTimeout: DEFAULT_CHECKPOINT_TIMEOUT_SECONDS,
288289
maxReadFileLine: -1,
290+
openRouterImageApiKeyConfigured: false,
289291
}
290292

291293
const makeMessage = (ts: number, text: string): ClineMessage =>

0 commit comments

Comments
 (0)