mirror of
https://github.com/Gitlawb/openclaude.git
synced 2026-11-13 16:03:44 -04:00
fix: address remaining code-scanning alert sites (#2461)
This commit is contained in:
@@ -52,7 +52,8 @@ async function getQuery(language: NonNullable<ReturnType<typeof getLanguageForFi
|
||||
try {
|
||||
return await promise
|
||||
} finally {
|
||||
if (queryLoadPromises.get(language) === promise) {
|
||||
// A cache reset may have started a newer load; compare operation identity.
|
||||
if (Object.is(queryLoadPromises.get(language), promise)) {
|
||||
queryLoadPromises.delete(language)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { afterAll, afterEach, expect, jest, mock, test } from 'bun:test'
|
||||
import { afterAll, afterEach, expect, jest, mock, spyOn, test } from 'bun:test'
|
||||
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { join } from 'node:path'
|
||||
@@ -1195,7 +1195,17 @@ test('a settled interrupted run resumes the profile write without re-provisionin
|
||||
|
||||
// Retry without --model: the default would be gpt-4o, but the settled receipt
|
||||
// must win.
|
||||
await runAimlapiTopup({ email: 'user@example.com', amountUsd: '25', noOpen: true })
|
||||
const output = spyOn(console, 'log').mockImplementation(() => {})
|
||||
try {
|
||||
await runAimlapiTopup({ email: 'user@example.com', amountUsd: '25', noOpen: true })
|
||||
const logged = output.mock.calls.flat().join('\n')
|
||||
expect(logged).toContain('Balance topped up and provider configured.')
|
||||
expect(logged).not.toContain('exchanged-key')
|
||||
expect(logged).not.toContain('exchan')
|
||||
expect(logged).not.toContain('exchanged-id')
|
||||
} finally {
|
||||
output.mockRestore()
|
||||
}
|
||||
|
||||
// The retained settled key finished the write — no account check/provisioning,
|
||||
// the persisted model is preserved, and the checkout state is cleared.
|
||||
|
||||
@@ -167,10 +167,6 @@ export function setAimlapiTopupTestDoubles(
|
||||
promptHiddenFn = doubles?.promptHidden ?? promptHidden
|
||||
}
|
||||
|
||||
function maskKey(key: string): string {
|
||||
return key.length <= 10 ? '****' : `${key.slice(0, 6)}...${key.slice(-4)}`
|
||||
}
|
||||
|
||||
// A session the provider reports as `exchanged` has already minted its one-shot
|
||||
// key; it can never be paid or exchanged again. Both the poll loop and the
|
||||
// resume path use this so neither opens a second, separately chargeable checkout
|
||||
@@ -262,7 +258,6 @@ export async function runAimlapiTopup(options: AimlapiTopupOptions): Promise<voi
|
||||
)
|
||||
}
|
||||
console.log(chalk.green('\n [OK] Balance topped up and provider configured.'))
|
||||
console.log(` key ${chalk.dim(maskKey(provisioned.apiKey))} (id ${provisioned.apiKeyId})`)
|
||||
console.log(` base URL ${chalk.dim(provisioned.baseUrl)}`)
|
||||
console.log(` model ${chalk.dim(provisioned.model)}`)
|
||||
console.log(` profile ${chalk.dim(profilePath)}`)
|
||||
|
||||
@@ -273,7 +273,8 @@ export async function rebuildIndex(memoryDir: string): Promise<void> {
|
||||
try {
|
||||
await rebuild
|
||||
} finally {
|
||||
if (state.pending === rebuild) {
|
||||
// Compare the in-flight operations themselves, not their resolved values.
|
||||
if (Object.is(state.pending, rebuild)) {
|
||||
state.pending = null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,6 +137,8 @@ test('partitions local openai-compatible model cache scope by credentials and he
|
||||
process.env.ANTHROPIC_CUSTOM_HEADERS = 'X-Route: first'
|
||||
|
||||
const firstScope = getAdditionalModelOptionsCacheScope()
|
||||
expect(getAdditionalModelOptionsCacheScope()).toBe(firstScope)
|
||||
expect(firstScope).not.toContain('first-key')
|
||||
|
||||
process.env.OPENAI_API_KEY = 'second-key'
|
||||
const secondScope = getAdditionalModelOptionsCacheScope()
|
||||
@@ -144,6 +146,8 @@ test('partitions local openai-compatible model cache scope by credentials and he
|
||||
process.env.OPENAI_API_KEY = 'first-key'
|
||||
process.env.ANTHROPIC_CUSTOM_HEADERS = 'X-Route: second'
|
||||
const thirdScope = getAdditionalModelOptionsCacheScope()
|
||||
process.env.ANTHROPIC_CUSTOM_HEADERS = 'X-Route: first'
|
||||
expect(getAdditionalModelOptionsCacheScope()).toBe(firstScope)
|
||||
|
||||
delete process.env.OPENAI_API_KEY
|
||||
process.env.ANTHROPIC_CUSTOM_HEADERS = 'X-Route: first'
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { existsSync, readFileSync } from 'node:fs'
|
||||
import { createHash } from 'node:crypto'
|
||||
import { createHmac } from 'node:crypto'
|
||||
import { isIP } from 'node:net'
|
||||
import { homedir } from 'node:os'
|
||||
import { join } from 'node:path'
|
||||
@@ -210,8 +210,10 @@ type ModelDescriptor = {
|
||||
const LOCALHOST_HOSTNAMES = new Set(['localhost', '127.0.0.1', '::1'])
|
||||
|
||||
function hashCacheScopePartition(value: unknown): string {
|
||||
return createHash('sha256')
|
||||
.update(JSON.stringify(value))
|
||||
// Credential-keyed fingerprint, not a password hash. Keep it deterministic
|
||||
// because model discovery scopes are persisted across CLI runs.
|
||||
return createHmac('sha256', JSON.stringify(value))
|
||||
.update('openclaude:additional-model-options:v1')
|
||||
.digest('hex')
|
||||
.slice(0, 16)
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ function assertReadonlyCollectionTypes(
|
||||
readonlyTuple[0].a.push('mutates')
|
||||
|
||||
// @ts-expect-error DeepImmutable preserves readonly tuple arity.
|
||||
readonlyTuple[2]
|
||||
void readonlyTuple[2]
|
||||
}
|
||||
|
||||
void assertReadonlyCollectionTypes
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import { marked } from "marked";
|
||||
import { existsSync, mkdtempSync, readFileSync, rmSync } from "node:fs";
|
||||
import { homedir, tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
@@ -113,7 +114,14 @@ describe("diagnostic issue report", () => {
|
||||
errors: [],
|
||||
});
|
||||
|
||||
report.checks = [{
|
||||
label: "Path",
|
||||
ok: true,
|
||||
detail: String.raw`C:\tools\bin | next\|cell`,
|
||||
}];
|
||||
const markdown = formatIssueReportAsMarkdown(report);
|
||||
const html = marked.parse(markdown) as string;
|
||||
expect(html).toContain(String.raw`<td>C:\tools\bin | next\|cell</td>`);
|
||||
|
||||
expect(markdown).toContain("# OpenClaude diagnostic report");
|
||||
expect(markdown).toContain("## Summary");
|
||||
|
||||
@@ -659,6 +659,7 @@ function formatStatus(ok: boolean): string {
|
||||
|
||||
function tableEscape(value: string | number | boolean | null | undefined): string {
|
||||
return String(value ?? '')
|
||||
.replace(/\\/g, '\\\\')
|
||||
.replace(/\|/g, '\\|')
|
||||
.replace(/\r?\n/g, ' ')
|
||||
}
|
||||
|
||||
@@ -145,7 +145,7 @@ test('rejects unencoded-percent lookalikes the producer never emits', () => {
|
||||
const sub = join(PLANS, AGENT_PLANS_SUBDIR)
|
||||
for (const rawComponent of [
|
||||
'writer@100%', // canonical form is writer@100%25
|
||||
'writer@a%2Fb'.replace('%2F', '%'), // writer@a%b -> canonical writer@a%25b
|
||||
'writer@a%b', // writer@a%b -> canonical writer@a%25b
|
||||
'a%', // bare trailing percent
|
||||
'a%zz', // percent not starting a known escape
|
||||
'a%2', // truncated escape
|
||||
|
||||
Reference in New Issue
Block a user