Skip to content

Commit c87eb71

Browse files
committed
fix: address observability review comments
1 parent 03a5ce0 commit c87eb71

5 files changed

Lines changed: 102 additions & 34 deletions

File tree

src/core/task/Task.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3156,6 +3156,8 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
31563156
cost: tokens.total ?? costResult.totalCost,
31573157
})
31583158

3159+
const mode = await this.getTaskMode().catch(() => defaultModeSlug)
3160+
31593161
// Zoo Code observability telemetry
31603162
import("../../services/zoo-telemetry")
31613163
.then(({ sendLlmTelemetry }) =>
@@ -3165,7 +3167,7 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
31653167
model: this.apiConfiguration
31663168
? (getModelId(this.apiConfiguration) ?? "unknown")
31673169
: "unknown",
3168-
mode: this.taskMode,
3170+
mode,
31693171
inputTokens: costResult.totalInputTokens,
31703172
outputTokens: costResult.totalOutputTokens,
31713173
cacheReadTokens: tokens.cacheRead ?? 0,

src/core/webview/ClineProvider.ts

Lines changed: 30 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2166,6 +2166,35 @@ export class ClineProvider
21662166
const mergedDeniedCommands = this.mergeDeniedCommands(deniedCommands)
21672167
const cwd = this.cwd
21682168
const currentTask = this.getCurrentTask()
2169+
let zooCodeState: {
2170+
zooCodeIsAuthenticated: boolean
2171+
zooCodeUserName: string | undefined
2172+
zooCodeUserEmail: string | undefined
2173+
zooCodeUserImage: string | undefined
2174+
zooCodeBaseUrl: string
2175+
} = {
2176+
zooCodeIsAuthenticated: false,
2177+
zooCodeUserName: undefined,
2178+
zooCodeUserEmail: undefined,
2179+
zooCodeUserImage: undefined,
2180+
zooCodeBaseUrl: "https://www.zoocode.dev",
2181+
}
2182+
2183+
try {
2184+
const { isZooCodeAuthenticated, getCachedZooCodeUserInfo, getZooCodeBaseUrl } = await import(
2185+
"../../services/zoo-code-auth"
2186+
)
2187+
const userInfo = getCachedZooCodeUserInfo()
2188+
zooCodeState = {
2189+
zooCodeIsAuthenticated: await isZooCodeAuthenticated(),
2190+
zooCodeUserName: userInfo?.name,
2191+
zooCodeUserEmail: userInfo?.email,
2192+
zooCodeUserImage: userInfo?.image,
2193+
zooCodeBaseUrl: getZooCodeBaseUrl(),
2194+
}
2195+
} catch {
2196+
// Keep unauthenticated defaults if the optional auth service is unavailable.
2197+
}
21692198

21702199
return {
21712200
version: this.context.extension?.packageJSON?.version ?? "",
@@ -2289,33 +2318,7 @@ export class ClineProvider
22892318
return false
22902319
}
22912320
})(),
2292-
zooCodeIsAuthenticated: await (async () => {
2293-
try {
2294-
const { isZooCodeAuthenticated } = await import("../../services/zoo-code-auth")
2295-
return await isZooCodeAuthenticated()
2296-
} catch {
2297-
return false
2298-
}
2299-
})(),
2300-
...(() => {
2301-
try {
2302-
const { getCachedZooCodeUserInfo, getZooCodeBaseUrl } = require("../../services/zoo-code-auth")
2303-
const userInfo = getCachedZooCodeUserInfo()
2304-
return {
2305-
zooCodeUserName: userInfo.name,
2306-
zooCodeUserEmail: userInfo.email,
2307-
zooCodeUserImage: userInfo.image,
2308-
zooCodeBaseUrl: getZooCodeBaseUrl(),
2309-
}
2310-
} catch {
2311-
return {
2312-
zooCodeUserName: undefined,
2313-
zooCodeUserEmail: undefined,
2314-
zooCodeUserImage: undefined,
2315-
zooCodeBaseUrl: "https://www.zoocode.dev",
2316-
}
2317-
}
2318-
})(),
2321+
...zooCodeState,
23192322
debug: vscode.workspace.getConfiguration(Package.name).get<boolean>("debug", false),
23202323
}
23212324
}

src/services/__tests__/zoo-code-auth.test.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
setZooCodeToken,
99
clearZooCodeToken,
1010
getZooCodeBaseUrl,
11+
handleAuthCallback,
1112
} from "../zoo-code-auth"
1213

1314
// Mock vscode
@@ -20,6 +21,17 @@ vi.mock("vscode", () => ({
2021
}),
2122
})),
2223
},
24+
window: {
25+
showErrorMessage: vi.fn(),
26+
showInformationMessage: vi.fn(),
27+
},
28+
env: {
29+
asExternalUri: vi.fn(async (uri: any) => uri),
30+
openExternal: vi.fn(),
31+
},
32+
Uri: {
33+
parse: vi.fn((value: string) => ({ toString: () => value })),
34+
},
2335
}))
2436

2537
// Mock fetch
@@ -190,6 +202,43 @@ describe("zoo-code-auth subscription checking", () => {
190202
})
191203
})
192204

205+
describe("handleAuthCallback", () => {
206+
it("does not persist invalid prefixed tokens", async () => {
207+
await initZooCodeAuth(mockContext)
208+
209+
mockFetch.mockResolvedValueOnce({
210+
ok: true,
211+
json: async () => ({ valid: false }),
212+
})
213+
214+
const success = await handleAuthCallback("zoo_ext_fake_token")
215+
216+
expect(success).toBe(false)
217+
expect(getCachedZooCodeToken()).toBe("")
218+
expect(mockSecrets.store).not.toHaveBeenCalledWith("zoo-code-session-token", "zoo_ext_fake_token")
219+
})
220+
221+
it("persists token only after backend verification succeeds", async () => {
222+
await initZooCodeAuth(mockContext)
223+
224+
mockFetch
225+
.mockResolvedValueOnce({
226+
ok: true,
227+
json: async () => ({ valid: true }),
228+
})
229+
.mockResolvedValueOnce({
230+
ok: true,
231+
json: async () => ({ isSubscriber: true }),
232+
})
233+
234+
const success = await handleAuthCallback("zoo_ext_real_token")
235+
236+
expect(success).toBe(true)
237+
expect(getCachedZooCodeToken()).toBe("zoo_ext_real_token")
238+
expect(mockSecrets.store).toHaveBeenCalledWith("zoo-code-session-token", "zoo_ext_real_token")
239+
})
240+
})
241+
193242
describe("clearZooCodeToken", () => {
194243
it("should reset subscription status when token is cleared", async () => {
195244
await initZooCodeAuth(mockContext)

src/services/zoo-code-auth.ts

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,9 @@ export async function startZooCodeAuth(): Promise<void> {
206206
const editor = "VS Code"
207207
const version = Package.version
208208

209-
const callbackUri = await vscode.env.asExternalUri(vscode.Uri.parse("vscode://zoo-code.zoo-code/auth-callback"))
209+
const callbackUri = await vscode.env.asExternalUri(
210+
vscode.Uri.parse(`vscode://${Package.publisher}.${Package.name}/auth-callback`),
211+
)
210212

211213
const authUrl = `${baseUrl}/dashboard/connect?device=${encodeURIComponent(deviceName)}&editor=${encodeURIComponent(editor)}&version=${encodeURIComponent(version)}&callback_uri=${encodeURIComponent(callbackUri.toString())}`
212214

@@ -219,6 +221,12 @@ export async function handleAuthCallback(token: string): Promise<boolean> {
219221
return false
220222
}
221223

224+
const isValid = await verifyZooCodeTokenValue(token)
225+
if (!isValid) {
226+
vscode.window.showErrorMessage("Zoo Code: Authentication failed. Please try signing in again.")
227+
return false
228+
}
229+
222230
await setZooCodeToken(token)
223231

224232
// Check subscription status after successful auth
@@ -236,21 +244,27 @@ export async function verifyZooCodeToken(): Promise<boolean> {
236244

237245
const baseUrl = getZooCodeBaseUrl()
238246

247+
const isValid = await verifyZooCodeTokenValue(token, baseUrl)
248+
if (!isValid) {
249+
await clearZooCodeToken()
250+
return false
251+
}
252+
253+
return true
254+
}
255+
256+
async function verifyZooCodeTokenValue(token: string, baseUrl = getZooCodeBaseUrl()): Promise<boolean> {
239257
try {
240258
const response = await fetch(`${baseUrl}/api/extension/auth/verify`, {
241259
headers: { Authorization: `Bearer ${token}` },
242260
signal: AbortSignal.timeout(10_000),
243261
})
244262

245263
if (!response.ok) {
246-
await clearZooCodeToken()
247264
return false
248265
}
249266

250267
const data = (await response.json()) as { valid?: boolean }
251-
if (!data.valid) {
252-
await clearZooCodeToken()
253-
}
254268
return data.valid === true
255269
} catch {
256270
return false

src/services/zoo-telemetry.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ export async function sendLlmTelemetry(payload: LlmTelemetryPayload): Promise<vo
4848
editor: "vscode",
4949
}
5050

51-
await fetch(`${baseUrl}/api/observability/events`, {
51+
void fetch(`${baseUrl}/api/observability/events`, {
5252
method: "POST",
5353
headers: {
5454
"Content-Type": "application/json",

0 commit comments

Comments
 (0)