Download packages/kap-server/test/hostExposure.e2e.test.ts from SaylorTwift/kimi-code: direct link, hf CLI and curl.
- Browser
- Download file 5.38 kB
-
https://huggingface.co/SaylorTwift/kimi-code/resolve/main/packages/kap-server/test/hostExposure.e2e.test.ts
- Command line
-
hf download hf://SaylorTwift/kimi-code/packages/kap-server/test/hostExposure.e2e.test.ts
-
curl -L -o hostExposure.e2e.test.ts https://huggingface.co/SaylorTwift/kimi-code/resolve/main/packages/kap-server/test/hostExposure.e2e.test.ts
5.38 kB
| import { mkdtemp, rm } from 'node:fs/promises'; | |
| import { tmpdir } from 'node:os'; | |
| import { join } from 'node:path'; | |
| import { Writable } from 'node:stream'; | |
| import { pino, type Logger } from 'pino'; | |
| import { afterEach, beforeEach, describe, expect, it } from 'vitest'; | |
| import { type RunningServer, startServer } from '../src/start'; | |
| import { TEST_HOST_IDENTITY } from './helpers/hostIdentity'; | |
| const createdDirs: string[] = []; | |
| const running: RunningServer[] = []; | |
| let prevPassword: string | undefined; | |
| async function tmpHome(): Promise<string> { | |
| const dir = await mkdtemp(join(tmpdir(), 'kimi-v2-host-exposure-')); | |
| createdDirs.push(dir); | |
| return dir; | |
| } | |
| function capturingLogger(): { logger: Logger; lines: string[] } { | |
| const lines: string[] = []; | |
| const dest = new Writable({ | |
| write(chunk, _enc, cb) { | |
| lines.push(String(chunk)); | |
| cb(); | |
| }, | |
| }); | |
| return { logger: pino({ level: 'info' }, dest), lines }; | |
| } | |
| beforeEach(() => { | |
| prevPassword = process.env['KIMI_CODE_PASSWORD']; | |
| }); | |
| afterEach(async () => { | |
| for (const r of running.splice(0)) { | |
| try { | |
| await r.close(); | |
| } catch { | |
| } | |
| } | |
| for (const dir of createdDirs.splice(0)) { | |
| await rm(dir, { recursive: true, force: true }); | |
| } | |
| if (prevPassword === undefined) { | |
| delete process.env['KIMI_CODE_PASSWORD']; | |
| } else { | |
| process.env['KIMI_CODE_PASSWORD'] = prevPassword; | |
| } | |
| }); | |
| describe('public-bind gate', () => { | |
| it('refuses to bind 0.0.0.0 without --insecure-no-tls', async () => { | |
| const home = await tmpHome(); | |
| await expect( | |
| startServer({ hostIdentity: TEST_HOST_IDENTITY, host: '0.0.0.0', port: 0, homeDir: home, logLevel: 'silent' }), | |
| ).rejects.toThrow(/without TLS/); | |
| }); | |
| it('boots 0.0.0.0 token-only and logs the token-only warning', async () => { | |
| delete process.env['KIMI_CODE_PASSWORD']; | |
| const home = await tmpHome(); | |
| const { logger, lines } = capturingLogger(); | |
| const server = await startServer({ | |
| hostIdentity: TEST_HOST_IDENTITY, | |
| host: '0.0.0.0', | |
| port: 0, | |
| homeDir: home, | |
| logLevel: 'silent', | |
| insecureNoTls: true, | |
| logger, | |
| }); | |
| running.push(server); | |
| const token = server.authTokenService.getToken(); | |
| const res = await fetch(`http://127.0.0.1:${server.port}/api/v1/healthz`, { | |
| headers: { authorization: `Bearer ${token}` }, | |
| }); | |
| expect(res.status).toBe(200); | |
| expect(lines.join('')).toContain('token-only auth'); | |
| }); | |
| }); | |
| describe('real password path (verifyPassword)', () => { | |
| async function bootPublic(): Promise<RunningServer> { | |
| process.env['KIMI_CODE_PASSWORD'] = 'test-pw'; | |
| const home = await tmpHome(); | |
| const server = await startServer({ | |
| hostIdentity: TEST_HOST_IDENTITY, | |
| host: '0.0.0.0', | |
| port: 0, | |
| homeDir: home, | |
| logLevel: 'silent', | |
| insecureNoTls: true, | |
| }); | |
| running.push(server); | |
| return server; | |
| } | |
| it('accepts the password as a bearer token and sets security headers', async () => { | |
| const server = await bootPublic(); | |
| const res = await fetch(`http://127.0.0.1:${server.port}/api/v1/sessions`, { | |
| headers: { authorization: 'Bearer test-pw' }, | |
| }); | |
| expect(res.status).toBe(200); | |
| expect(res.headers.get('x-content-type-options')).toBe('nosniff'); | |
| expect(res.headers.get('content-security-policy')).toBe( | |
| "default-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self' data:; form-action 'self'; base-uri 'none'; frame-ancestors 'self'", | |
| ); | |
| }); | |
| it('accepts the persistent token on a public bind', async () => { | |
| const server = await bootPublic(); | |
| const token = server.authTokenService.getToken(); | |
| const res = await fetch(`http://127.0.0.1:${server.port}/api/v1/sessions`, { | |
| headers: { authorization: `Bearer ${token}` }, | |
| }); | |
| expect(res.status).toBe(200); | |
| }); | |
| it('rejects wrong and missing credentials with 401', async () => { | |
| const server = await bootPublic(); | |
| const wrong = await fetch(`http://127.0.0.1:${server.port}/api/v1/sessions`, { | |
| headers: { authorization: 'Bearer wrong-password' }, | |
| }); | |
| expect(wrong.status).toBe(401); | |
| const missing = await fetch(`http://127.0.0.1:${server.port}/api/v1/sessions`); | |
| expect(missing.status).toBe(401); | |
| }); | |
| }); | |
| describe('auth-failure rate limit on a real bind', () => { | |
| it('returns 429 on the 11th bad token', async () => { | |
| const home = await tmpHome(); | |
| const server = await startServer({ | |
| hostIdentity: TEST_HOST_IDENTITY, | |
| host: '0.0.0.0', | |
| port: 0, | |
| homeDir: home, | |
| logLevel: 'silent', | |
| insecureNoTls: true, | |
| authTokenService: { | |
| _serviceBrand: undefined, | |
| getToken: () => 'persistent-token', | |
| isValid: async (candidate) => candidate === 'persistent-token', | |
| }, | |
| }); | |
| running.push(server); | |
| const url = `http://127.0.0.1:${server.port}/api/v1/sessions`; | |
| let lastStatus = 0; | |
| for (let i = 0; i < 11; i += 1) { | |
| const res = await fetch(url, { headers: { authorization: 'Bearer wrong' } }); | |
| lastStatus = res.status; | |
| if (i < 10) { | |
| expect(res.status).toBe(401); | |
| } | |
| } | |
| expect(lastStatus).toBe(429); | |
| const body = (await (await fetch(url, { headers: { authorization: 'Bearer wrong' } })).json()) as { | |
| code: number; | |
| }; | |
| expect(body.code).toBe(42901); | |
| }); | |
| }); | |