Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
186 changes: 186 additions & 0 deletions services/git-token-service/src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1302,6 +1302,192 @@ describe('GitTokenRPCEntrypoint GitHub session capability RPCs', () => {
});
});

describe('GitTokenRPCEntrypoint Kilo session capability RPCs', () => {
const kiloTargets = {
backendBaseUrl: 'https://api.kilo.ai',
providerBaseUrl: 'https://api.kilo.ai',
sessionIngestBaseUrl: 'https://ingest.kilosessions.ai',
};
const kiloSubject = {
userId: 'user_1',
cloudAgentSessionId: 'cloud-agent-session-1',
kiloSessionId: 'kilo-session-1',
outboundContainerId,
userToken: 'raw-user-token',
providerToken: 'raw-provider-token',
targets: kiloTargets,
};

it('issues an opaque Kilo capability that does not leak the enclosed tokens', async () => {
const result = await createService().issueKiloSessionCapability(kiloSubject);

expect(result).toMatchObject({ success: true });
if (!result.success) throw new Error('Expected successful issuance');
expect(result.capability).toMatch(/^kka1\./);
expect(result.capability).not.toContain(kiloSubject.userToken);
expect(result.capability).not.toContain(kiloSubject.providerToken);
});

it('rejects issuance for malformed targets', async () => {
const result = await createService().issueKiloSessionCapability({
...kiloSubject,
targets: { ...kiloTargets, backendBaseUrl: 'https://user@api.kilo.ai' },
});

expect(result).toEqual({ success: false, reason: 'invalid_targets' });
});

it('returns a sanitized declared failure when capability key configuration is invalid', async () => {
const service = new GitTokenRPCEntrypoint(
{} as ExecutionContext,
{ SCM_SESSION_CAPABILITY_ENCRYPTION_KEY: 'not-a-valid-key' } as unknown as CloudflareEnv
);

await expect(service.issueKiloSessionCapability(kiloSubject)).resolves.toEqual({
success: false,
reason: 'capability_configuration_error',
});
});

it('redeems the provider token for provider model routes', async () => {
const service = createService();
const issued = await service.issueKiloSessionCapability(kiloSubject);
if (!issued.success) throw new Error('Expected successful issuance');

await expect(
service.redeemKiloSessionCapability({
capability: issued.capability,
outboundContainerId,
requestUrl: 'https://api.kilo.ai/api/openrouter/v1/chat/completions',
})
).resolves.toEqual({
success: true,
authorization: 'Bearer raw-provider-token',
routeClass: 'provider_model',
});
});

it('redeems the user token for backend API routes', async () => {
const service = createService();
const issued = await service.issueKiloSessionCapability(kiloSubject);
if (!issued.success) throw new Error('Expected successful issuance');

await expect(
service.redeemKiloSessionCapability({
capability: issued.capability,
outboundContainerId,
requestUrl: 'https://api.kilo.ai/api/users/me',
})
).resolves.toEqual({
success: true,
authorization: 'Bearer raw-user-token',
routeClass: 'backend_api',
});
});

it('falls back to the user token for provider routes when no provider token was issued', async () => {
const service = createService();
const issued = await service.issueKiloSessionCapability({
...kiloSubject,
providerToken: undefined,
});
if (!issued.success) throw new Error('Expected successful issuance');

await expect(
service.redeemKiloSessionCapability({
capability: issued.capability,
outboundContainerId,
requestUrl: 'https://api.kilo.ai/api/openrouter/v1/chat/completions',
})
).resolves.toEqual({
success: true,
authorization: 'Bearer raw-user-token',
routeClass: 'provider_model',
});
});

it('redeems the user token for session export/import routes', async () => {
const service = createService();
const issued = await service.issueKiloSessionCapability(kiloSubject);
if (!issued.success) throw new Error('Expected successful issuance');

await expect(
service.redeemKiloSessionCapability({
capability: issued.capability,
outboundContainerId,
requestUrl: 'https://ingest.kilosessions.ai/api/session/kilo-session-1/export',
})
).resolves.toEqual({
success: true,
authorization: 'Bearer raw-user-token',
routeClass: 'session_ingest',
});
});

it('does not redeem a session ingest route for another Kilo session', async () => {
const service = createService();
const issued = await service.issueKiloSessionCapability(kiloSubject);
if (!issued.success) throw new Error('Expected successful issuance');

await expect(
service.redeemKiloSessionCapability({
capability: issued.capability,
outboundContainerId,
requestUrl: 'https://ingest.kilosessions.ai/api/session/another-session/export',
})
).resolves.toEqual({ success: false, reason: 'upstream_not_allowed' });
});

it('does not leak the user token to another session ingest route on a shared origin', async () => {
const service = createService();
const issued = await service.issueKiloSessionCapability({
...kiloSubject,
targets: {
backendBaseUrl: 'https://api.kilo.ai',
providerBaseUrl: 'https://api.kilo.ai/api/openrouter',
sessionIngestBaseUrl: 'https://api.kilo.ai',
},
});
if (!issued.success) throw new Error('Expected successful issuance');

await expect(
service.redeemKiloSessionCapability({
capability: issued.capability,
outboundContainerId,
requestUrl: 'https://api.kilo.ai/api/session/another-session/export',
})
).resolves.toEqual({ success: false, reason: 'upstream_not_allowed' });
});

it('does not redeem a capability from another outbound container', async () => {
const service = createService();
const issued = await service.issueKiloSessionCapability(kiloSubject);
if (!issued.success) throw new Error('Expected successful issuance');

await expect(
service.redeemKiloSessionCapability({
capability: issued.capability,
outboundContainerId: 'another-outbound-container',
requestUrl: 'https://api.kilo.ai/api/users/me',
})
).resolves.toEqual({ success: false, reason: 'container_mismatch' });
});

it('rejects redemption against a disallowed upstream', async () => {
const service = createService();
const issued = await service.issueKiloSessionCapability(kiloSubject);
if (!issued.success) throw new Error('Expected successful issuance');

await expect(
service.redeemKiloSessionCapability({
capability: issued.capability,
outboundContainerId,
requestUrl: 'https://evil.example.com/api/users/me',
})
).resolves.toEqual({ success: false, reason: 'upstream_not_allowed' });
});
});

describe('GitTokenRPCEntrypoint GitLab session capability RPCs', () => {
beforeEach(() => {
vi.clearAllMocks();
Expand Down
87 changes: 87 additions & 0 deletions services/git-token-service/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,17 @@ import {
BitbucketEnsureWebhookRequestSchema,
BitbucketPullRequestRequestSchema,
} from './bitbucket-code-review-service.js';
import {
KiloSessionCapabilityCodec,
KiloSessionCapabilityError,
type KiloSessionCapabilityFailureReason,
type KiloSessionCapabilitySubject,
} from './kilo-session-capability.js';
import {
areValidKiloCapabilityTargets,
classifyKiloCapabilityRequest,
type KiloCapabilityRouteClass,
} from './kilo-capability-policy.js';

export type GetTokenForRepoParams = {
githubRepo: string;
Expand Down Expand Up @@ -208,6 +219,25 @@ export type RedeemGitLabSessionCapabilityResult =
}
| { success: false; reason: RedeemGitLabSessionCapabilityFailureReason };

export type IssueKiloSessionCapabilityParams = KiloSessionCapabilitySubject;
export type IssueKiloSessionCapabilityResult =
| { success: true; capability: string }
| { success: false; reason: KiloSessionCapabilityFailureReason | 'invalid_targets' };

export type RedeemKiloSessionCapabilityParams = {
capability: string;
outboundContainerId: string;
requestUrl: string;
};
export type RedeemKiloSessionCapabilityFailureReason =
| KiloSessionCapabilityFailureReason
| 'container_mismatch'
| 'invalid_upstream_url'
| 'upstream_not_allowed';
export type RedeemKiloSessionCapabilityResult =
| { success: true; authorization: string; routeClass: KiloCapabilityRouteClass }
| { success: false; reason: RedeemKiloSessionCapabilityFailureReason };

const DISCONNECT_PATH = '/internal/github-user-authorizations/disconnect';
const BITBUCKET_REPOSITORIES_PATH = '/internal/bitbucket/repositories';
const BITBUCKET_CODE_REVIEW_PULL_REQUEST_PATH = '/internal/bitbucket/code-review/pull-request';
Expand Down Expand Up @@ -1043,6 +1073,63 @@ export class GitTokenRPCEntrypoint extends WorkerEntrypoint<CloudflareEnv> {
return { success: true, headers: { authorization: `Bearer ${token}` } };
}

async issueKiloSessionCapability(
params: IssueKiloSessionCapabilityParams
): Promise<IssueKiloSessionCapabilityResult> {
if (!areValidKiloCapabilityTargets(params.targets)) {
return { success: false, reason: 'invalid_targets' };
}

try {
const encryptionKey = await resolveSecret(this.env.SCM_SESSION_CAPABILITY_ENCRYPTION_KEY);
const capability = new KiloSessionCapabilityCodec(encryptionKey).issue(params);
return { success: true, capability };
} catch (error) {
if (error instanceof KiloSessionCapabilityError) {
return { success: false, reason: error.reason };
}
return { success: false, reason: 'capability_configuration_error' };
}
}

async redeemKiloSessionCapability(
params: RedeemKiloSessionCapabilityParams
): Promise<RedeemKiloSessionCapabilityResult> {
let claims;
try {
const encryptionKey = await resolveSecret(this.env.SCM_SESSION_CAPABILITY_ENCRYPTION_KEY);
claims = new KiloSessionCapabilityCodec(encryptionKey).decode(params.capability);
} catch (error) {
if (error instanceof KiloSessionCapabilityError) {
return { success: false, reason: error.reason };
}
return { success: false, reason: 'capability_configuration_error' };
}

if (claims.outboundContainerId !== params.outboundContainerId) {
return { success: false, reason: 'container_mismatch' };
}

const classification = classifyKiloCapabilityRequest(
Comment thread
eshurakov marked this conversation as resolved.
params.requestUrl,
claims.targets,
claims.kiloSessionId
);
if (!classification.success) {
return { success: false, reason: classification.reason };
}

const token =
classification.credential === 'provider'
? (claims.providerToken ?? claims.userToken)
: claims.userToken;
return {
success: true,
authorization: `Bearer ${token}`,
routeClass: classification.routeClass,
};
}

private getGitLabAuthType(integration: GitLabLookupSuccess): GitLabAuthType | null {
if (integration.metadata.auth_type) return integration.metadata.auth_type;
if (integration.integrationType === 'oauth' || integration.integrationType === 'pat') {
Expand Down
Loading