mirror of
https://github.com/tiennm99/ccs.git
synced 2026-10-15 14:16:16 +00:00
fix(kiro): harden idc and callback auth paths
- keep headless paste routing aligned with the selected Kiro auth method - validate local callback replay targets and add prompt cancellation safeguards - wire IDC params through the dashboard start route and support equals-form CLI flags
This commit is contained in:
1 parent
bb7dbd108d
commit
f40d435a92
8 files changed
+431
-81
No files matched your search
@@ -0,0 +1,33 @@
|
||||
import { describe, expect, it } from 'bun:test';
|
||||
import { readOptionValue } from '../../../src/cliproxy/executor/index';
|
||||
|
||||
describe('readOptionValue', () => {
|
||||
it('parses split-token option values', () => {
|
||||
expect(readOptionValue(['--kiro-idc-start-url', 'https://d-123.awsapps.com/start'], '--kiro-idc-start-url')).toEqual({
|
||||
present: true,
|
||||
value: 'https://d-123.awsapps.com/start',
|
||||
missingValue: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('parses equals-form option values', () => {
|
||||
expect(readOptionValue(['--kiro-idc-flow=device'], '--kiro-idc-flow')).toEqual({
|
||||
present: true,
|
||||
value: 'device',
|
||||
missingValue: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('marks empty or missing values as invalid', () => {
|
||||
expect(readOptionValue(['--kiro-idc-region'], '--kiro-idc-region')).toEqual({
|
||||
present: true,
|
||||
value: undefined,
|
||||
missingValue: true,
|
||||
});
|
||||
expect(readOptionValue(['--kiro-idc-flow='], '--kiro-idc-flow')).toEqual({
|
||||
present: true,
|
||||
value: undefined,
|
||||
missingValue: true,
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -76,6 +76,20 @@ describe('requestPasteCallbackStart', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('usesKiroLocalCallbackReplay', () => {
|
||||
it('limits local callback replay to CLI auth-code flows', async () => {
|
||||
const { usesKiroLocalCallbackReplay } = await import(
|
||||
`../../../src/cliproxy/auth/oauth-handler?kiro-local-callback-mode=${Date.now()}`
|
||||
);
|
||||
|
||||
expect(usesKiroLocalCallbackReplay('aws-authcode', 'authcode')).toBe(true);
|
||||
expect(usesKiroLocalCallbackReplay('idc', 'authcode')).toBe(true);
|
||||
expect(usesKiroLocalCallbackReplay('idc', 'device')).toBe(false);
|
||||
expect(usesKiroLocalCallbackReplay('google', 'authcode')).toBe(false);
|
||||
expect(usesKiroLocalCallbackReplay('aws', 'authcode')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('resolvePasteCallbackAuthUrl', () => {
|
||||
it('returns the immediate auth URL without polling', async () => {
|
||||
const { resolvePasteCallbackAuthUrl } = await import(
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import { describe, expect, it } from 'bun:test';
|
||||
import { extractLikelyAuthFailureFromStderr } from '../../../src/cliproxy/auth/oauth-process';
|
||||
import {
|
||||
extractLikelyAuthFailureFromStderr,
|
||||
getExpectedLocalCallback,
|
||||
validateManualCallbackUrl,
|
||||
} from '../../../src/cliproxy/auth/oauth-process';
|
||||
|
||||
describe('oauth-process stderr parsing', () => {
|
||||
it('ignores non-ghcp providers', () => {
|
||||
@@ -33,3 +37,50 @@ describe('oauth-process stderr parsing', () => {
|
||||
expect((parsed as string).length).toBe(240);
|
||||
});
|
||||
});
|
||||
|
||||
describe('oauth-process manual callback validation', () => {
|
||||
const authUrl =
|
||||
'https://oidc.example.com/authorize?redirect_uri=http%3A%2F%2F127.0.0.1%3A9876%2Foauth%2Fcallback&state=test-state';
|
||||
|
||||
it('extracts the expected local callback target from the auth URL', () => {
|
||||
expect(getExpectedLocalCallback(authUrl)).toEqual({
|
||||
origin: 'http://127.0.0.1:9876',
|
||||
pathname: '/oauth/callback',
|
||||
state: 'test-state',
|
||||
});
|
||||
});
|
||||
|
||||
it('accepts matching loopback callback URLs', () => {
|
||||
expect(
|
||||
validateManualCallbackUrl(
|
||||
'http://127.0.0.1:9876/oauth/callback?code=abc123&state=test-state',
|
||||
authUrl
|
||||
)
|
||||
).toBeNull();
|
||||
});
|
||||
|
||||
it('rejects non-loopback callback URLs', () => {
|
||||
expect(
|
||||
validateManualCallbackUrl(
|
||||
'https://evil.example.com/oauth/callback?code=abc123&state=test-state',
|
||||
authUrl
|
||||
)
|
||||
).toContain('local OAuth callback server');
|
||||
});
|
||||
|
||||
it('rejects callback URLs with the wrong path or state', () => {
|
||||
expect(
|
||||
validateManualCallbackUrl(
|
||||
'http://127.0.0.1:9876/not-the-callback?code=abc123&state=test-state',
|
||||
authUrl
|
||||
)
|
||||
).toContain('expected local OAuth callback target');
|
||||
|
||||
expect(
|
||||
validateManualCallbackUrl(
|
||||
'http://127.0.0.1:9876/oauth/callback?code=abc123&state=wrong-state',
|
||||
authUrl
|
||||
)
|
||||
).toContain('state does not match');
|
||||
});
|
||||
});
|
||||
@@ -1,5 +1,6 @@
|
||||
import { describe, expect, it } from 'bun:test';
|
||||
import {
|
||||
getKiroStartIDCValidationError,
|
||||
getStartAuthFailureMessage,
|
||||
getStartAuthNicknameError,
|
||||
getStartUrlUnsupportedReason,
|
||||
@@ -38,6 +39,44 @@ describe('cliproxy-auth-routes start-url guard', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('cliproxy-auth-routes Kiro IDC start validation', () => {
|
||||
it('requires an IDC start URL when idc auth is selected', () => {
|
||||
expect(
|
||||
getKiroStartIDCValidationError({
|
||||
kiroMethod: 'idc',
|
||||
kiroIDCStartUrl: undefined,
|
||||
invalidKiroIDCFlow: false,
|
||||
})
|
||||
).toEqual({
|
||||
error: 'Kiro IDC login requires kiroIDCStartUrl',
|
||||
code: 'MISSING_KIRO_IDC_START_URL',
|
||||
});
|
||||
});
|
||||
|
||||
it('rejects invalid IDC flow values before triggerOAuth is called', () => {
|
||||
expect(
|
||||
getKiroStartIDCValidationError({
|
||||
kiroMethod: 'idc',
|
||||
kiroIDCStartUrl: 'https://d-123.awsapps.com/start',
|
||||
invalidKiroIDCFlow: true,
|
||||
})
|
||||
).toEqual({
|
||||
error: 'Invalid kiroIDCFlow. Supported: authcode, device',
|
||||
code: 'INVALID_KIRO_IDC_FLOW',
|
||||
});
|
||||
});
|
||||
|
||||
it('allows valid IDC start payloads through', () => {
|
||||
expect(
|
||||
getKiroStartIDCValidationError({
|
||||
kiroMethod: 'idc',
|
||||
kiroIDCStartUrl: 'https://d-123.awsapps.com/start',
|
||||
invalidKiroIDCFlow: false,
|
||||
})
|
||||
).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('cliproxy-auth-routes start failure messaging', () => {
|
||||
it('returns ghcp-specific guidance for Copilot verification failures', () => {
|
||||
expect(getStartAuthFailureMessage('ghcp')).toContain(
|
||||
|
||||
Reference in new issue
Block a user