Skip to content

Commit e365cb4

Browse files
Vasanthdev2004OpenClaude Worker 3github-advanced-security[bot]
authored
fix: address code scanning alerts (Gitlawb#434)
* fix: address code scanning alerts Parse Gemini hostnames instead of matching raw URL substrings, redact gRPC error logs, and harden the Finder drag-drop test escape helper so the flagged paths are fixed without regressing working behavior. * Potential fix for pull request finding 'CodeQL / Clear-text logging of sensitive information' Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> * fix: restore safe grpc error summaries A later autofix commit removed the exported gRPC error summarizer while the new regression test still imported it. Restore the safe name/code-only summary so CI stays green without reintroducing clear-text logging. * fix: keep grpc logging generic Remove the stale helper/test pair and keep the gRPC startup and stream logs free of error-derived data so the CodeQL clear-text logging alert stays closed while the rest of the security fixes remain intact. --------- Co-authored-by: OpenClaude Worker 3 <worker-3@openclaude.local> Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
1 parent 52d33a8 commit e365cb4

4 files changed

Lines changed: 77 additions & 5 deletions

File tree

src/grpc/server.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export class GrpcServer {
4040
grpc.ServerCredentials.createInsecure(),
4141
(error, boundPort) => {
4242
if (error) {
43-
console.error('Failed to start gRPC server', error)
43+
console.error('Failed to start gRPC server')
4444
return
4545
}
4646
console.log(`gRPC Server running at ${host}:${boundPort}`)
@@ -225,7 +225,7 @@ export class GrpcServer {
225225
call.end()
226226
}
227227
} catch (err: any) {
228-
console.error("Error processing stream:", err)
228+
console.error('Error processing stream')
229229
call.write({
230230
error: {
231231
message: err.message || "Internal server error",

src/services/api/openaiShim.test.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,58 @@ test('preserves Gemini tool call extra_content in follow-up requests', async ()
261261
})
262262
})
263263

264+
test('does not infer Gemini mode from OPENAI_BASE_URL path substrings', async () => {
265+
let capturedAuthorization: string | null = null
266+
267+
process.env.OPENAI_BASE_URL =
268+
'https://evil.example/generativelanguage.googleapis.com/v1beta/openai'
269+
delete process.env.OPENAI_API_KEY
270+
process.env.GEMINI_API_KEY = 'gemini-secret'
271+
272+
globalThis.fetch = (async (_input, init) => {
273+
const headers = init?.headers as Record<string, string> | undefined
274+
capturedAuthorization =
275+
headers?.Authorization ?? headers?.authorization ?? null
276+
277+
return new Response(
278+
JSON.stringify({
279+
id: 'chatcmpl-1',
280+
model: 'fake-model',
281+
choices: [
282+
{
283+
message: {
284+
role: 'assistant',
285+
content: 'ok',
286+
},
287+
finish_reason: 'stop',
288+
},
289+
],
290+
usage: {
291+
prompt_tokens: 12,
292+
completion_tokens: 4,
293+
total_tokens: 16,
294+
},
295+
}),
296+
{
297+
headers: {
298+
'Content-Type': 'application/json',
299+
},
300+
},
301+
)
302+
}) as FetchType
303+
304+
const client = createOpenAIShimClient({}) as OpenAIShimClient
305+
306+
await client.beta.messages.create({
307+
model: 'fake-model',
308+
messages: [{ role: 'user', content: 'hello' }],
309+
max_tokens: 64,
310+
stream: false,
311+
})
312+
313+
expect(capturedAuthorization).toBeNull()
314+
})
315+
264316
test('preserves image tool results as placeholders in follow-up requests', async () => {
265317
let requestBody: Record<string, unknown> | undefined
266318

src/services/api/openaiShim.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,22 @@ const GITHUB_API_VERSION = '2022-11-28'
6060
const GITHUB_429_MAX_RETRIES = 3
6161
const GITHUB_429_BASE_DELAY_SEC = 1
6262
const GITHUB_429_MAX_DELAY_SEC = 32
63+
const GEMINI_API_HOST = 'generativelanguage.googleapis.com'
6364

6465
function isGithubModelsMode(): boolean {
6566
return isEnvTruthy(process.env.CLAUDE_CODE_USE_GITHUB)
6667
}
6768

69+
function hasGeminiApiHost(baseUrl: string | undefined): boolean {
70+
if (!baseUrl) return false
71+
72+
try {
73+
return new URL(baseUrl).hostname.toLowerCase() === GEMINI_API_HOST
74+
} catch {
75+
return false
76+
}
77+
}
78+
6879
function formatRetryAfterHint(response: Response): string {
6980
const ra = response.headers.get('retry-after')
7081
return ra ? ` (Retry-After: ${ra})` : ''
@@ -204,8 +215,7 @@ function convertContentBlocks(
204215
function isGeminiMode(): boolean {
205216
return (
206217
isEnvTruthy(process.env.CLAUDE_CODE_USE_GEMINI) ||
207-
(process.env.OPENAI_BASE_URL?.includes('generativelanguage.googleapis.com') ??
208-
false)
218+
hasGeminiApiHost(process.env.OPENAI_BASE_URL)
209219
)
210220
}
211221

src/utils/dragDropPaths.test.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ import { tmpdir } from 'os'
44
import { join } from 'path'
55
import { extractDraggedFilePaths } from './dragDropPaths.js'
66

7+
function escapeFinderDraggedPath(filePath: string): string {
8+
return filePath.replace(/([\\ ])/g, '\\$1')
9+
}
10+
711
describe('extractDraggedFilePaths', () => {
812
// Paths that exist on any system.
913
const thisFile = import.meta.path
@@ -80,6 +84,12 @@ describe('extractDraggedFilePaths', () => {
8084
})
8185
})
8286

87+
test('escapeFinderDraggedPath escapes spaces and backslashes', () => {
88+
expect(escapeFinderDraggedPath('/tmp/my\\notes file.txt')).toBe(
89+
'/tmp/my\\\\notes\\ file.txt',
90+
)
91+
})
92+
8393
// Backslash-escaped paths are a Finder/macOS + Linux convention — on
8494
// Windows the shell-escape step is skipped, so these cases do not apply.
8595
if (process.platform !== 'win32') {
@@ -92,7 +102,7 @@ describe('extractDraggedFilePaths', () => {
92102

93103
test('resolves an escaped real file with a space in its name', () => {
94104
// Raw form matches what a terminal delivers on Finder drag.
95-
const escaped = spacedFile.replace(/ /g, '\\ ')
105+
const escaped = escapeFinderDraggedPath(spacedFile)
96106
expect(extractDraggedFilePaths(escaped)).toEqual([spacedFile])
97107
})
98108
})

0 commit comments

Comments
 (0)