mirror of
https://github.com/tiennm99/ccs.git
synced 2026-10-11 03:13:12 +00:00
fix: enforce tier lock during quota preflight (#1550)
Tier lock now fails closed in quota preflight when no healthy locked-tier account is available, instead of falling through cross-tier.
This commit is contained in:
1 parent
06e83091be
commit
361328c788
2 files changed
+51
-3
No files matched your search
@@ -658,8 +658,8 @@ export async function preflightCheck(provider: CLIProxyProvider): Promise<Prefli
|
||||
// match the locked tier. If it doesn't, route to a healthy account in the
|
||||
// locked tier instead. Locks are per-provider: locking "agy" to "ultra"
|
||||
// does NOT constrain "claude", "codex", "gemini", or "ghcp".
|
||||
// Graceful degradation: if no locked-tier account is available, fall through
|
||||
// to the default (don't block the request entirely).
|
||||
// This is intentionally strict: if no locked-tier account is available, do
|
||||
// not fail open to a cross-tier default.
|
||||
const tierLock = getTierLockForProvider(quotaConfig.manual, provider);
|
||||
if (tierLock !== null && (defaultAccount.tier || 'unknown') !== tierLock) {
|
||||
const lockedTierAccount = await findHealthyAccount(provider, []);
|
||||
@@ -673,7 +673,12 @@ export async function preflightCheck(provider: CLIProxyProvider): Promise<Prefli
|
||||
reason: `Tier lock: selected ${tierLock} account`,
|
||||
};
|
||||
}
|
||||
// No locked-tier account available — fall through and use default
|
||||
|
||||
return {
|
||||
proceed: false,
|
||||
accountId: '',
|
||||
reason: `Tier lock: no healthy ${tierLock} account available`,
|
||||
};
|
||||
}
|
||||
|
||||
// Check if default is paused
|
||||
|
||||
@@ -352,6 +352,49 @@ describe('quota-manager findHealthyAccount — tier_lock', () => {
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// preflightCheck must enforce the same strict tier lock as findHealthyAccount
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
it('preflightCheck blocks a cross-tier default when no healthy locked-tier account exists', async () => {
|
||||
writeMinimalConfig(tempHome, { agy: 'pro' });
|
||||
_mockAccounts = [ULTRA_ACCOUNT, PRO_ACCOUNT];
|
||||
|
||||
const uid = `preflight-lock-pro-exhausted-${Date.now()}-${Math.random()}`;
|
||||
const { preflightCheck, setCachedQuota } = await import(
|
||||
`../../../src/cliproxy/quota/quota-manager?${uid}`
|
||||
);
|
||||
|
||||
// Default is ultra, but agy is locked to pro. The only pro account is
|
||||
// exhausted, so preflight must not fail open to the healthy ultra default.
|
||||
setCachedQuota('agy', ULTRA_ACCOUNT.id, HEALTHY_QUOTA as never);
|
||||
setCachedQuota('agy', PRO_ACCOUNT.id, EXHAUSTED_QUOTA as never);
|
||||
|
||||
const result = await preflightCheck('agy');
|
||||
expect(result.proceed).toBe(false);
|
||||
expect(result.accountId).not.toBe(ULTRA_ACCOUNT.id);
|
||||
expect(result.reason).toBe('Tier lock: no healthy pro account available');
|
||||
});
|
||||
|
||||
it('preflightCheck switches a cross-tier default to a healthy locked-tier account', async () => {
|
||||
writeMinimalConfig(tempHome, { agy: 'pro' });
|
||||
_mockAccounts = [ULTRA_ACCOUNT, PRO_ACCOUNT];
|
||||
|
||||
const uid = `preflight-lock-pro-healthy-${Date.now()}-${Math.random()}`;
|
||||
const { preflightCheck, setCachedQuota } = await import(
|
||||
`../../../src/cliproxy/quota/quota-manager?${uid}`
|
||||
);
|
||||
|
||||
setCachedQuota('agy', ULTRA_ACCOUNT.id, HEALTHY_QUOTA as never);
|
||||
setCachedQuota('agy', PRO_ACCOUNT.id, HEALTHY_QUOTA as never);
|
||||
|
||||
const result = await preflightCheck('agy');
|
||||
expect(result.proceed).toBe(true);
|
||||
expect(result.accountId).toBe(PRO_ACCOUNT.id);
|
||||
expect(result.switchedFrom).toBe(ULTRA_ACCOUNT.id);
|
||||
expect(result.reason).toBe('Tier lock: selected pro account');
|
||||
});
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Baseline: no tier_lock — any available healthy account is returned.
|
||||
//
|
||||
|
||||
Reference in new issue
Block a user