Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
1 change: 1 addition & 0 deletions packages/kap-server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"build": "tsdown",
"typecheck": "tsc -p tsconfig.json --noEmit",
"test": "vitest run",
"test:bench": "vitest run --config vitest.bench.config.ts",
"clean": "rm -rf dist"
},
"dependencies": {
Expand Down
33 changes: 17 additions & 16 deletions packages/kap-server/test/apiSurface.snapshot.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { mkdtempSync, rmSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';

import { afterEach, describe, expect, it } from 'vitest';
import { afterAll, beforeAll, describe, expect, it } from 'vitest';

import { startServer, type RunningServer } from '../src';
import { TEST_HOST_IDENTITY } from './helpers/hostIdentity';
Expand All @@ -25,7 +25,19 @@ describe('API surface snapshot', () => {
let home: string | undefined;
let server: RunningServer | undefined;

afterEach(async () => {
beforeAll(async () => {
home = mkdtempSync(join(tmpdir(), 'kimi-server-v2-api-surface-'));
server = await startServer({
hostIdentity: TEST_HOST_IDENTITY,
host: '127.0.0.1',
port: 0,
homeDir: home,
logLevel: 'silent',
debugEndpoints: true,
});
});

afterAll(async () => {
if (server !== undefined) {
try {
await server.close();
Expand All @@ -40,20 +52,9 @@ describe('API surface snapshot', () => {
});

it('matches the documented v2 route table and meta endpoints', async () => {
home = mkdtempSync(join(tmpdir(), 'kimi-server-v2-api-surface-'));

server = await startServer({
hostIdentity: TEST_HOST_IDENTITY,
host: '127.0.0.1',
port: 0,
homeDir: home,
logLevel: 'silent',
debugEndpoints: true,
});

const base = `http://${server.host}:${server.port}`;
const base = `http://${server!.host}:${server!.port}`;

const openApiRes = await fetch(`${base}/openapi.json`, { headers: authHeaders(server) } as never);
const openApiRes = await fetch(`${base}/openapi.json`, { headers: authHeaders(server as RunningServer) } as never);
expect(openApiRes.status).toBe(200);
const openApi = (await openApiRes.json()) as {
paths?: Record<string, Record<string, unknown>>;
Expand All @@ -73,7 +74,7 @@ describe('API surface snapshot', () => {

const meta: Array<[string, string, number]> = [];
for (const endpoint of META_ENDPOINTS) {
const res = await fetch(`${base}${endpoint}`, { headers: authHeaders(server) } as never);
const res = await fetch(`${base}${endpoint}`, { headers: authHeaders(server as RunningServer) } as never);
meta.push(['GET', endpoint, res.status]);
}
meta.sort((a, b) => a[0].localeCompare(b[0]) || a[1].localeCompare(b[1]) || a[2] - b[2]);
Expand Down
6 changes: 3 additions & 3 deletions packages/kap-server/test/approvals.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { tmpdir } from 'node:os';
import { join } from 'node:path';

import { ISessionApprovalService, ensureMainAgent, getLiveSessionById } from '@moonshot-ai/agent-core-v2';
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
import { afterAll, beforeAll, describe, expect, it } from 'vitest';

import { type RunningServer, startServer } from '../src/start';
import { TEST_HOST_IDENTITY } from './helpers/hostIdentity';
Expand Down Expand Up @@ -43,7 +43,7 @@ describe('server-v2 /api/v1/sessions/{sid}/approvals', () => {
let home: string | undefined;
let base: string;

beforeEach(async () => {
beforeAll(async () => {
home = await mkdtemp(join(tmpdir(), 'kimi-server-v2-approvals-'));
server = await startServer({
hostIdentity: TEST_HOST_IDENTITY,
Expand All @@ -55,7 +55,7 @@ describe('server-v2 /api/v1/sessions/{sid}/approvals', () => {
base = `http://127.0.0.1:${server.port}`;
});

afterEach(async () => {
afterAll(async () => {
if (server !== undefined) {
await server.close();
server = undefined;
Expand Down
28 changes: 14 additions & 14 deletions packages/kap-server/test/auth.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import { mkdtemp, rm, writeFile } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import { join } from 'node:path';

import { IConfigService } from '@moonshot-ai/agent-core-v2';
import { authSummarySchema, type AuthSummary } from '@moonshot-ai/agent-core-v2/app/authLegacy/authLegacy';
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
import { afterAll, beforeAll, describe, expect, it } from 'vitest';

import { type RunningServer, startServer } from '../src/start';
import { TEST_HOST_IDENTITY } from './helpers/hostIdentity';
Expand All @@ -21,11 +22,19 @@ describe('server-v2 GET /api/v1/auth', () => {
let home: string | undefined;
let base: string;

beforeEach(async () => {
beforeAll(async () => {
home = await mkdtemp(join(tmpdir(), 'kimi-server-v2-auth-'));
server = await startServer({
hostIdentity: TEST_HOST_IDENTITY,
host: '127.0.0.1',
port: 0,
homeDir: home,
logLevel: 'silent',
});
base = `http://127.0.0.1:${server.port}`;
});

afterEach(async () => {
afterAll(async () => {
if (server !== undefined) {
await server.close();
server = undefined;
Expand All @@ -37,17 +46,8 @@ describe('server-v2 GET /api/v1/auth', () => {
});

async function boot(toml?: string): Promise<void> {
if (toml !== undefined) {
await writeFile(join(home as string, 'config.toml'), toml, 'utf-8');
}
server = await startServer({
hostIdentity: TEST_HOST_IDENTITY,
host: '127.0.0.1',
port: 0,
homeDir: home,
logLevel: 'silent',
});
base = `http://127.0.0.1:${server.port}`;
await writeFile(join(home as string, 'config.toml'), toml ?? '', 'utf-8');
await (server as RunningServer).core.accessor.get(IConfigService).reload();
}

async function getAuth(): Promise<AuthSummary> {
Expand Down
24 changes: 10 additions & 14 deletions packages/kap-server/test/authMiddleware.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { mkdtemp, rm } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import { join } from 'node:path';

import { afterEach, beforeEach, describe, expect, it } from 'vitest';
import { afterAll, beforeAll, describe, expect, it } from 'vitest';

import { type RunningServer, startServer } from '../src/start';
import { TEST_HOST_IDENTITY } from './helpers/hostIdentity';
Expand All @@ -11,11 +11,12 @@ describe('server-v2 /api/v1 bearer auth', () => {
let server: RunningServer | undefined;
let home: string | undefined;

beforeEach(async () => {
beforeAll(async () => {
home = await mkdtemp(join(tmpdir(), 'kimi-server-v2-auth-middleware-'));
server = await startServer({ hostIdentity: TEST_HOST_IDENTITY, host: '127.0.0.1', port: 0, homeDir: home, logLevel: 'silent' });
});

afterEach(async () => {
afterAll(async () => {
if (server !== undefined) {
await server.close();
server = undefined;
Expand All @@ -27,22 +28,19 @@ describe('server-v2 /api/v1 bearer auth', () => {
});

it('allows healthz without a token', async () => {
server = await startServer({ hostIdentity: TEST_HOST_IDENTITY, host: '127.0.0.1', port: 0, homeDir: home, logLevel: 'silent' });
const res = await server.app.inject({ method: 'GET', url: '/api/v1/healthz' });
const res = await server!.app.inject({ method: 'GET', url: '/api/v1/healthz' });
expect(res.statusCode).toBe(200);
});

it('rejects /api/v1/auth without a token with 40101', async () => {
server = await startServer({ hostIdentity: TEST_HOST_IDENTITY, host: '127.0.0.1', port: 0, homeDir: home, logLevel: 'silent' });
const res = await server.app.inject({ method: 'GET', url: '/api/v1/auth' });
const res = await server!.app.inject({ method: 'GET', url: '/api/v1/auth' });
expect(res.statusCode).toBe(401);
const body = res.json() as Record<string, unknown>;
expect(body['code']).toBe(40101);
});

it('rejects /api/v1/auth with a wrong token', async () => {
server = await startServer({ hostIdentity: TEST_HOST_IDENTITY, host: '127.0.0.1', port: 0, homeDir: home, logLevel: 'silent' });
const res = await server.app.inject({
const res = await server!.app.inject({
method: 'GET',
url: '/api/v1/auth',
headers: { authorization: 'Bearer wrong-token' },
Expand All @@ -53,9 +51,8 @@ describe('server-v2 /api/v1 bearer auth', () => {
});

it('accepts /api/v1/auth with the persistent token', async () => {
server = await startServer({ hostIdentity: TEST_HOST_IDENTITY, host: '127.0.0.1', port: 0, homeDir: home, logLevel: 'silent' });
const token = server.authTokenService.getToken();
const res = await server.app.inject({
const token = server!.authTokenService.getToken();
const res = await server!.app.inject({
method: 'GET',
url: '/api/v1/auth',
headers: { authorization: `Bearer ${token}` },
Expand All @@ -66,8 +63,7 @@ describe('server-v2 /api/v1 bearer auth', () => {
});

it('requires auth for /openapi.json', async () => {
server = await startServer({ hostIdentity: TEST_HOST_IDENTITY, host: '127.0.0.1', port: 0, homeDir: home, logLevel: 'silent' });
const res = await server.app.inject({ method: 'GET', url: '/openapi.json' });
const res = await server!.app.inject({ method: 'GET', url: '/openapi.json' });
expect(res.statusCode).toBe(401);
});
});
16 changes: 12 additions & 4 deletions packages/kap-server/test/authWiring.e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { mkdtemp, readFile, rm, stat } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import { join } from 'node:path';

import { afterEach, beforeEach, describe, expect, it } from 'vitest';
import { afterAll, afterEach, beforeAll, describe, expect, it } from 'vitest';
import { WebSocket, type RawData } from 'ws';

import { type RunningServer, startServer } from '../src/start';
Expand Down Expand Up @@ -58,19 +58,26 @@ describe('production auth wiring', () => {
let base: string;
const sockets: WebSocket[] = [];

beforeEach(async () => {
beforeAll(async () => {
home = await mkdtemp(join(tmpdir(), 'kimi-server-v2-auth-wiring-'));
await boot();
});

async function boot(): Promise<void> {
server = await startServer({ hostIdentity: TEST_HOST_IDENTITY, host: '127.0.0.1', port: 0, homeDir: home, logLevel: 'silent' });
base = `http://127.0.0.1:${server.port}`;
});
}

afterEach(async () => {
afterEach(() => {
for (const ws of sockets.splice(0)) {
try {
ws.close();
} catch {
}
}
});

afterAll(async () => {
if (server !== undefined) {
await server.close();
server = undefined;
Expand All @@ -92,6 +99,7 @@ describe('production auth wiring', () => {
server = undefined;
const after = await stat(p);
expect(after.mode & 0o777).toBe(0o600);
await boot();
});

it('gates HTTP: 200 with the token, 401 without', async () => {
Expand Down
45 changes: 6 additions & 39 deletions packages/kap-server/test/capabilities.test.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,10 @@
import { mkdtemp, rm } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import { join } from 'node:path';

import { afterEach, beforeEach, describe, expect, it } from 'vitest';
import { describe, expect, it } from 'vitest';

import {
capabilityStatusSchema,
listCapabilitiesResponseSchema,
} from '../src/protocol/rest-capability';
import { type RunningServer, startServer } from '../src/start';
import { TEST_HOST_IDENTITY } from './helpers/hostIdentity';
import { authHeaders } from './helpers/auth';
import { sharedAuthHeaders, sharedServer } from './helpers/sharedServer';

interface Envelope<T> {
code: number;
Expand All @@ -20,44 +14,17 @@ interface Envelope<T> {
}

describe('server-v2 /api/v1 capabilities', () => {
let server: RunningServer | undefined;
let home: string | undefined;
let base: string;

beforeEach(async () => {
home = await mkdtemp(join(tmpdir(), 'kimi-server-v2-capabilities-'));
server = await startServer({
hostIdentity: TEST_HOST_IDENTITY,
host: '127.0.0.1',
port: 0,
homeDir: home,
logLevel: 'silent',
});
base = `http://127.0.0.1:${server.port}`;
});

afterEach(async () => {
if (server !== undefined) {
await server.close();
server = undefined;
}
if (home !== undefined) {
await rm(home, { recursive: true, force: true, maxRetries: 3, retryDelay: 25 } as never);
home = undefined;
}
});

async function getJson<T>(path: string): Promise<{ status: number; body: Envelope<T> }> {
const res = await fetch(`${base}${path}`, {
headers: authHeaders(server as RunningServer),
const res = await fetch(`${sharedServer().base}${path}`, {
headers: sharedAuthHeaders(),
} as never);
return { status: res.status, body: (await res.json()) as Envelope<T> };
}

async function postJson<T>(path: string): Promise<{ status: number; body: Envelope<T> }> {
const res = await fetch(`${base}${path}`, {
const res = await fetch(`${sharedServer().base}${path}`, {
method: 'POST',
headers: authHeaders(server as RunningServer, { 'content-type': 'application/json' }),
headers: sharedAuthHeaders({ 'content-type': 'application/json' }),
body: '{}',
} as never);
return { status: res.status, body: (await res.json()) as Envelope<T> };
Expand Down
Loading
Loading