/** * Unit tests for skip-local-auth functionality when using remote proxy with auth token * * When --proxy-host and --proxy-auth-token are provided together, the system should * skip local OAuth checks because the remote proxy handles authentication. * * Implementation uses: const remoteAuthToken = proxyConfig.authToken?.trim(); * const skipLocalAuth = useRemoteProxy && !!remoteAuthToken; */ import { describe, it, expect } from 'bun:test'; /** * Helper to compute skipLocalAuth exactly as the implementation does * Mirrors logic from cliproxy-executor.ts lines 503-505 */ function computeSkipLocalAuth( useRemoteProxy: boolean, proxyConfig: { authToken?: string | null } ): boolean { const remoteAuthToken = proxyConfig.authToken?.trim(); return useRemoteProxy && !!remoteAuthToken; } describe('skip-local-auth logic', () => { describe('skipLocalAuth flag determination', () => { it('should skip local auth when both useRemoteProxy and authToken are truthy', () => { const useRemoteProxy = true; const proxyConfig = { authToken: 'test-token-123' }; const skipLocalAuth = computeSkipLocalAuth(useRemoteProxy, proxyConfig); expect(skipLocalAuth).toBe(true); }); it('should NOT skip local auth when useRemoteProxy is false', () => { const useRemoteProxy = false; const proxyConfig = { authToken: 'test-token-123' }; const skipLocalAuth = computeSkipLocalAuth(useRemoteProxy, proxyConfig); expect(skipLocalAuth).toBe(false); }); it('should NOT skip local auth when authToken is undefined', () => { const useRemoteProxy = true; const proxyConfig = { authToken: undefined }; const skipLocalAuth = computeSkipLocalAuth(useRemoteProxy, proxyConfig); expect(skipLocalAuth).toBe(false); }); it('should NOT skip local auth when authToken is empty string', () => { const useRemoteProxy = true; const proxyConfig = { authToken: '' }; const skipLocalAuth = computeSkipLocalAuth(useRemoteProxy, proxyConfig); expect(skipLocalAuth).toBe(false); }); it('should NOT skip local auth when both are falsy', () => { const useRemoteProxy = false; const proxyConfig = { authToken: undefined }; const skipLocalAuth = computeSkipLocalAuth(useRemoteProxy, proxyConfig); expect(skipLocalAuth).toBe(false); }); }); describe('authToken edge cases', () => { it('should NOT skip local auth when authToken is whitespace-only', () => { const useRemoteProxy = true; const proxyConfig = { authToken: ' ' }; const skipLocalAuth = computeSkipLocalAuth(useRemoteProxy, proxyConfig); expect(skipLocalAuth).toBe(false); }); it('should NOT skip local auth when authToken is tabs and newlines', () => { const useRemoteProxy = true; const proxyConfig = { authToken: '\t\n\r' }; const skipLocalAuth = computeSkipLocalAuth(useRemoteProxy, proxyConfig); expect(skipLocalAuth).toBe(false); }); it('should NOT skip local auth when authToken is null', () => { const useRemoteProxy = true; const proxyConfig = { authToken: null }; const skipLocalAuth = computeSkipLocalAuth(useRemoteProxy, proxyConfig); expect(skipLocalAuth).toBe(false); }); it('should skip local auth when authToken has leading/trailing whitespace but valid content', () => { const useRemoteProxy = true; const proxyConfig = { authToken: ' valid-token-123 ' }; const skipLocalAuth = computeSkipLocalAuth(useRemoteProxy, proxyConfig); expect(skipLocalAuth).toBe(true); }); it('should skip local auth when authToken contains special characters', () => { const useRemoteProxy = true; const proxyConfig = { authToken: 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.test' }; const skipLocalAuth = computeSkipLocalAuth(useRemoteProxy, proxyConfig); expect(skipLocalAuth).toBe(true); }); }); describe('OAuth check bypass scenarios', () => { it('should document that OAuth is skipped for remote proxy with auth', () => { // This test documents the expected behavior: // When using remote proxy with auth token, the remote server // already has its own OAuth sessions, so local OAuth is unnecessary const scenario = { useRemoteProxy: true, authToken: 'bearer-token', providerRequiresOAuth: true, }; const skipLocalAuth = scenario.useRemoteProxy && scenario.authToken; const shouldTriggerLocalOAuth = scenario.providerRequiresOAuth && !skipLocalAuth; expect(skipLocalAuth).toBeTruthy(); expect(shouldTriggerLocalOAuth).toBe(false); }); it('should document that OAuth runs when no remote proxy', () => { const scenario = { useRemoteProxy: false, authToken: undefined, providerRequiresOAuth: true, }; const skipLocalAuth = scenario.useRemoteProxy && scenario.authToken; const shouldTriggerLocalOAuth = scenario.providerRequiresOAuth && !skipLocalAuth; expect(skipLocalAuth).toBeFalsy(); expect(shouldTriggerLocalOAuth).toBe(true); }); it('should document that OAuth runs when remote proxy has no auth token', () => { // Edge case: remote proxy configured but no auth token // This should fall back to local OAuth const scenario = { useRemoteProxy: true, authToken: undefined, providerRequiresOAuth: true, }; const skipLocalAuth = scenario.useRemoteProxy && scenario.authToken; const shouldTriggerLocalOAuth = scenario.providerRequiresOAuth && !skipLocalAuth; expect(skipLocalAuth).toBeFalsy(); expect(shouldTriggerLocalOAuth).toBe(true); }); }); describe('preflight quota check bypass', () => { it('should skip preflight for agy provider when using remote proxy with auth', () => { const provider = 'agy'; const skipLocalAuth = true; const shouldRunPreflight = provider === 'agy' && !skipLocalAuth; expect(shouldRunPreflight).toBe(false); }); it('should run preflight for agy provider when using local mode', () => { const provider = 'agy'; const skipLocalAuth = false; const shouldRunPreflight = provider === 'agy' && !skipLocalAuth; expect(shouldRunPreflight).toBe(true); }); it('should not run preflight for non-agy providers regardless of mode', () => { const providers = ['gemini', 'codex', 'ghcp', 'kiro']; for (const provider of providers) { const shouldRunPreflight = provider === 'agy' && !false; expect(shouldRunPreflight).toBe(false); } }); }); describe('model configuration bypass', () => { it('should skip model config when using remote proxy with auth', () => { const supportsModelConfig = true; const skipLocalAuth = true; const shouldConfigureModel = supportsModelConfig && !skipLocalAuth; expect(shouldConfigureModel).toBe(false); }); it('should run model config when using local mode', () => { const supportsModelConfig = true; const skipLocalAuth = false; const shouldConfigureModel = supportsModelConfig && !skipLocalAuth; expect(shouldConfigureModel).toBe(true); }); }); describe('broken model warning behavior', () => { it('should show broken model warning in BOTH remote and local modes', () => { // Updated behavior: warnings always shown (with different messaging for remote) // Remote users need to know about broken models too const currentModel = 'some-broken-model'; const isModelBroken = true; // Warning should show regardless of skipLocalAuth const shouldWarnRemote = currentModel && isModelBroken; // skipLocalAuth=true const shouldWarnLocal = currentModel && isModelBroken; // skipLocalAuth=false expect(shouldWarnRemote).toBe(true); expect(shouldWarnLocal).toBe(true); }); it('should show different message for remote vs local mode', () => { const skipLocalAuth = true; const currentModel = 'some-broken-model'; const isModelBroken = true; // When remote: "Note: Model may be overridden by remote proxy configuration." // When local: "Run ccs --config to change model." const remoteMessage = skipLocalAuth ? 'Note: Model may be overridden by remote proxy configuration.' : 'Run "ccs provider --config" to change model.'; expect(remoteMessage).toContain('remote proxy'); }); }); describe('CI/CD workflow scenarios', () => { it('should enable headless CI workflow with remote proxy', () => { // Simulate GitHub Actions workflow configuration const workflowConfig = { headless: true, proxyHost: 'proxy.example.com', proxyPort: 443, proxyProtocol: 'https', proxyAuthToken: 'github-secret-token', remoteOnly: true, }; // Determine if this configuration should skip local OAuth const useRemoteProxy = !!workflowConfig.proxyHost; const skipLocalAuth = useRemoteProxy && !!workflowConfig.proxyAuthToken; expect(useRemoteProxy).toBe(true); expect(skipLocalAuth).toBe(true); }); it('should require local OAuth when no proxy configured', () => { // Simulate local development without proxy const localConfig = { headless: false, proxyHost: undefined, proxyAuthToken: undefined, }; const useRemoteProxy = !!localConfig.proxyHost; const skipLocalAuth = useRemoteProxy && !!localConfig.proxyAuthToken; expect(useRemoteProxy).toBe(false); expect(skipLocalAuth).toBe(false); }); }); });