fix(bar): bound native credential and quota waits

This commit is contained in:
Tam Nhu Tran committed 2026-08-08 21:12:28 -04:00
1 parent 833473c5f6
commit da2de60015
8 files changed
+201 -89

No files matched your search

+43
View File
@@ -1116,6 +1116,49 @@ describe('/summary force flag passed to getNativeAccountRows', () => {
expect(status).toBe(200);
expect(body.some((r) => r.provider === 'codex')).toBe(true);
});
it('enforces one absolute deadline across cost, quota, and blocked native work', async () => {
const { createBarRouter, resetForceFreshDebounce: resetDebounce } = await import(
'../../../src/web-server/routes/bar-routes'
);
const app = express();
app.use(express.json());
const router = createBarRouter({
// eslint-disable-next-line @typescript-eslint/no-explicit-any
getAllAccountsSummary: () => ({ agy: [makeAccountInfo()] }) as any,
getCachedQuota: () => makeQuotaResult(),
setCachedQuota: () => {},
invalidateQuotaCache: () => {},
fetchAccountQuota: () => new Promise(() => {}),
getTodayCostByAccount: () => ({}),
loadCliproxyDetails: () => new Promise((resolve) => setTimeout(() => resolve([]), 1_400)),
loadDailyUsage: async () => [],
loadHourlyUsage: async () => [],
getNativeAccountRows: () => new Promise(() => {}),
getCachedNativeRows: () => [],
});
app.use('/api/bar', router);
const srv = await new Promise<Server>((resolve, reject) => {
const instance = app.listen(0, '127.0.0.1');
instance.once('error', reject);
instance.once('listening', () => resolve(instance));
});
const addr = srv.address();
if (!addr || typeof addr === 'string') throw new Error('No server address');
resetDebounce();
const startedAt = Date.now();
const { status } = await getJson<BarSummaryRow[]>(
`http://127.0.0.1:${(addr as { port: number }).port}`,
'/api/bar/summary?refresh=true'
);
const elapsed = Date.now() - startedAt;
await new Promise<void>((resolve) => srv.close(() => resolve()));
expect(status).toBe(200);
expect(elapsed).toBeGreaterThanOrEqual(2_200);
expect(elapsed).toBeLessThan(3_200);
});
});
// ============================================================================
@@ -27,14 +27,14 @@ function makeCreds(overrides: Record<string, unknown> = {}): ClaudeNativeCredent
}
describe('readClaudeCredentials', () => {
it('parses the on-disk credentials file when present (file-first, no Keychain)', () => {
it('parses the on-disk credentials file when present (file-first, no Keychain)', async () => {
let keychainCalled = false;
const creds = readClaudeCredentials({
const creds = await readClaudeCredentials({
platform: 'darwin',
homedir: '/home/test',
existsSyncImpl: () => true,
readFileSyncImpl: () => JSON.stringify(makeCreds()),
execSyncImpl: () => {
execFileImpl: () => {
keychainCalled = true;
return '';
},
@@ -44,44 +44,52 @@ describe('readClaudeCredentials', () => {
expect(keychainCalled).toBe(false);
});
it('falls back to the macOS Keychain when the file is absent', () => {
const creds = readClaudeCredentials({
it('falls back to the macOS Keychain when the file is absent', async () => {
let executable = '';
let args: readonly string[] = [];
const creds = await readClaudeCredentials({
platform: 'darwin',
homedir: '/home/test',
existsSyncImpl: () => false,
readFileSyncImpl: () => {
throw new Error('should not read file');
},
execSyncImpl: () => JSON.stringify(makeCreds({ subscriptionType: 'pro' })),
execFileImpl: (file, receivedArgs, _options, callback) => {
executable = file;
args = receivedArgs;
callback(null, JSON.stringify(makeCreds({ subscriptionType: 'pro' })));
},
});
expect(creds?.claudeAiOauth?.subscriptionType).toBe('pro');
expect(executable).toBe('/usr/bin/security');
expect(args).toEqual(['find-generic-password', '-s', 'Claude Code-credentials', '-w']);
});
it('returns null when both file and Keychain are absent', () => {
const creds = readClaudeCredentials({
it('returns null when both file and Keychain are absent', async () => {
const creds = await readClaudeCredentials({
platform: 'darwin',
homedir: '/home/test',
existsSyncImpl: () => false,
readFileSyncImpl: () => {
throw new Error('no file');
},
execSyncImpl: () => {
throw new Error('no keychain entry');
execFileImpl: (_file, _args, _options, callback) => {
callback(new Error('no keychain entry'), '');
},
});
expect(creds).toBeNull();
});
it('does not consult the Keychain on non-darwin platforms', () => {
it('does not consult the Keychain on non-darwin platforms', async () => {
let keychainCalled = false;
const creds = readClaudeCredentials({
const creds = await readClaudeCredentials({
platform: 'linux',
homedir: '/home/test',
existsSyncImpl: () => false,
readFileSyncImpl: () => {
throw new Error('no file');
},
execSyncImpl: () => {
execFileImpl: () => {
keychainCalled = true;
return '';
},
@@ -149,16 +157,16 @@ describe('readClaudeCredentialsForConfigDir', () => {
const configDir = '/home/test/.ccs/instances/work';
const credFile = `${configDir}/.credentials.json`;
it('reads <configDir>/.credentials.json when present (file-first, no Keychain)', () => {
it('reads <configDir>/.credentials.json when present (file-first, no Keychain)', async () => {
let keychainCalled = false;
const creds = readClaudeCredentialsForConfigDir(configDir, {
const creds = await readClaudeCredentialsForConfigDir(configDir, {
platform: 'darwin',
existsSyncImpl: (p: string) => p === credFile,
readFileSyncImpl: (p: string) => {
expect(p).toBe(credFile);
return JSON.stringify(makeCreds());
},
execSyncImpl: () => {
execFileImpl: () => {
keychainCalled = true;
return '';
},
@@ -167,46 +175,61 @@ describe('readClaudeCredentialsForConfigDir', () => {
expect(keychainCalled).toBe(false);
});
it('falls back to the per-config-dir Keychain service when the file is absent', () => {
let keychainCmd = '';
const creds = readClaudeCredentialsForConfigDir(configDir, {
it('uses absolute security path and argument array for the per-config-dir Keychain item', async () => {
let executable = '';
let args: readonly string[] = [];
const creds = await readClaudeCredentialsForConfigDir(configDir, {
platform: 'darwin',
existsSyncImpl: () => false,
readFileSyncImpl: () => {
throw new Error('should not read file');
},
execSyncImpl: (cmd: string) => {
keychainCmd = cmd;
return JSON.stringify(makeCreds({ subscriptionType: 'team' }));
execFileImpl: (file, receivedArgs, _options, callback) => {
executable = file;
args = receivedArgs;
callback(null, JSON.stringify(makeCreds({ subscriptionType: 'team' })));
},
});
expect(creds?.claudeAiOauth?.subscriptionType).toBe('team');
expect(keychainCmd).toContain('Claude Code-credentials-ffeb4b45');
expect(executable).toBe('/usr/bin/security');
expect(args).toEqual(['find-generic-password', '-s', 'Claude Code-credentials-ffeb4b45', '-w']);
});
it('returns null when both file and Keychain are absent', () => {
const creds = readClaudeCredentialsForConfigDir(configDir, {
it('returns null when both file and Keychain are absent', async () => {
const creds = await readClaudeCredentialsForConfigDir(configDir, {
platform: 'darwin',
existsSyncImpl: () => false,
readFileSyncImpl: () => {
throw new Error('no file');
},
execSyncImpl: () => {
throw new Error('no keychain entry');
execFileImpl: (_file, _args, _options, callback) => {
callback(new Error('no keychain entry'), '');
},
});
expect(creds).toBeNull();
});
it('does not consult the Keychain on non-darwin platforms', () => {
it('bounds a blocked Keychain lookup without exposing a credential payload', async () => {
const startedAt = Date.now();
const creds = await readClaudeCredentialsForConfigDir(configDir, {
platform: 'darwin',
existsSyncImpl: () => false,
keychainTimeoutMs: 20,
execFileImpl: () => ({ kill: () => {} }),
});
expect(creds).toBeNull();
expect(Date.now() - startedAt).toBeLessThan(250);
});
it('does not consult the Keychain on non-darwin platforms', async () => {
let keychainCalled = false;
const creds = readClaudeCredentialsForConfigDir(configDir, {
const creds = await readClaudeCredentialsForConfigDir(configDir, {
platform: 'linux',
existsSyncImpl: () => false,
readFileSyncImpl: () => {
throw new Error('no file');
},
execSyncImpl: () => {
execFileImpl: () => {
keychainCalled = true;
return '';
},
@@ -1032,7 +1032,7 @@ function makeMultiProfileDeps(opts: {
listCodexProfiles: () => codexProfiles,
defaultClaudeProfile: () => claudeDefault,
defaultCodexProfile: () => codexDefault,
// Credential seams (file-only, no keychain)
// Credential seams (fully injected; no real filesystem or Keychain access)
readClaudeCredentialsForProfile: credsForProfile,
readCodexNativeAuth: codexNativeAuth,
// Fetch seams
@@ -1195,7 +1195,7 @@ describe('multi-profile: account_id and wire fields', () => {
});
});
describe('multi-profile: Claude file-only reader', () => {
describe('multi-profile: Claude credential reader', () => {
it('profile with .credentials.json present -> live fetch row (paused:false when default)', async () => {
const clock = { now: 1_000_000 };
const deps = makeMultiProfileDeps({