feat(runtime): add production control-plane foundation

This commit is contained in:
chick
2026-07-18 12:43:46 +08:00
parent 9451e1ee42
commit 293c015f89
13 changed files with 513 additions and 31 deletions
+191
View File
@@ -0,0 +1,191 @@
import { EventEmitter } from 'node:events';
import { lstat, mkdtemp, mkdir, rm, symlink, writeFile } from 'node:fs/promises';
import { createServer } from 'node:http';
import { tmpdir } from 'node:os';
import { join, resolve } from 'node:path';
import { afterEach, describe, expect, it, vi } from 'vitest';
import { createRuntimeConfig, GATEWAY_AUTH_HEADER } from './runtime-config.js';
import { buildApp } from './app.js';
import { createCanaryGateway, type CanaryGateway } from './canary-gateway.js';
import { createProductionReadiness } from './production-readiness.js';
import { defaultKeychainMetadataCheck } from './production-readiness.js';
import { readCanaryRuntimeOptions } from './canary-runtime.js';
import { installBoundedShutdown } from './shutdown.js';
import { secureTokenEqual } from './app.js';
import { openDatabase } from './infrastructure/database/database.js';
import { migrateDatabase } from './infrastructure/database/migrations.js';
const cleanup: Array<() => Promise<void>> = [];
afterEach(async () => {
await Promise.all(cleanup.splice(0).map((fn) => fn()));
});
const token = 'runtime-gateway-token-with-at-least-32-bytes';
describe('production runtime foundation', () => {
it('creates one deeply immutable fixed-listener config and validates before side effects', () => {
const root = resolve('/tmp/multi-simadmin-data');
const config = createRuntimeConfig({
MULTI_SIMADMIN_DATA_ROOT: root,
MULTI_SIMADMIN_DATABASE_PATH: join(root, 'db.sqlite'),
MULTI_SIMADMIN_GATEWAY_TOKEN: token,
API_HOST: '127.0.0.1',
API_PORT: '8790',
});
expect(config).toEqual({
api: { host: '127.0.0.1', port: 8790 },
dataRoot: root,
databasePath: join(root, 'db.sqlite'),
gatewayToken: token,
});
expect(Object.isFrozen(config)).toBe(true);
expect(Object.isFrozen(config.api)).toBe(true);
expect(() =>
createRuntimeConfig({
MULTI_SIMADMIN_DATA_ROOT: root,
MULTI_SIMADMIN_DATABASE_PATH: '/tmp/escape.sqlite',
MULTI_SIMADMIN_GATEWAY_TOKEN: token,
}),
).toThrow(/data root/i);
expect(() =>
createRuntimeConfig({
MULTI_SIMADMIN_DATA_ROOT: root,
MULTI_SIMADMIN_DATABASE_PATH: join(root, 'db.sqlite'),
MULTI_SIMADMIN_GATEWAY_TOKEN: 'weak',
}),
).toThrow(/token/i);
});
it('rejects a database path whose existing symlink ancestor escapes before creating a DB', async () => {
const directory = await mkdtemp(join(tmpdir(), 'runtime-containment-'));
cleanup.push(() => rm(directory, { recursive: true, force: true }));
const root = join(directory, 'data');
const outside = join(directory, 'outside');
await mkdir(root);
await mkdir(outside);
await symlink(outside, join(root, 'escape'));
const databasePath = join(root, 'escape', 'db.sqlite');
expect(() =>
createRuntimeConfig({
MULTI_SIMADMIN_DATA_ROOT: root,
MULTI_SIMADMIN_DATABASE_PATH: databasePath,
MULTI_SIMADMIN_GATEWAY_TOKEN: token,
}),
).toThrow(/data root|symlink/i);
await expect(lstat(join(outside, 'db.sqlite'))).rejects.toMatchObject({ code: 'ENOENT' });
});
it('reads and validates the canary gateway token from its environment', () => {
expect(
readCanaryRuntimeOptions({
MULTI_SIMADMIN_GATEWAY_TOKEN: token,
CANARY_DIST_DIR: '/tmp/dist',
CANARY_PORT: '8789',
CANARY_UPSTREAM_PORT: '8790',
}),
).toMatchObject({ gatewayToken: token, port: 8789, upstreamPort: 8790 });
expect(() => readCanaryRuntimeOptions({ CANARY_DIST_DIR: '/tmp/dist' })).toThrow(/token/i);
expect(() =>
readCanaryRuntimeOptions({
CANARY_DIST_DIR: '/tmp/dist',
MULTI_SIMADMIN_GATEWAY_TOKEN: 'weak',
}),
).toThrow(/token/i);
});
it('always compares fixed-size token digests with timingSafeEqual', () => {
const compare = vi.fn(() => false);
expect(secureTokenEqual('x', token, compare)).toBe(false);
expect(compare).toHaveBeenCalledOnce();
const [actual, expected] = compare.mock.calls[0] as unknown as [Buffer, Buffer];
expect(actual).toHaveLength(32);
expect(expected).toHaveLength(32);
});
it('forces pluggable termination when graceful shutdown exceeds its deadline', async () => {
vi.useFakeTimers();
const target = new EventEmitter();
const terminate = vi.fn();
const stop = installBoundedShutdown(
target,
{ close: () => new Promise(() => undefined) },
{ timeoutMs: 25, terminate },
);
const stopping = stop();
await vi.advanceTimersByTimeAsync(25);
await stopping;
expect(terminate).toHaveBeenCalledOnce();
vi.useRealTimers();
});
it('default Keychain readiness checks only Darwin security executable metadata', async () => {
const stat = vi.fn(async () => ({ isFile: () => true, mode: 0o100755 }));
await expect(defaultKeychainMetadataCheck('darwin', stat)).resolves.toBe(true);
expect(stat).toHaveBeenCalledExactlyOnceWith('/usr/bin/security');
stat.mockClear();
await expect(defaultKeychainMetadataCheck('linux', stat)).resolves.toBe(false);
expect(stat).not.toHaveBeenCalled();
});
it('authenticates internal requests without reflecting credentials', async () => {
const app = buildApp({ gatewayToken: token });
cleanup.push(() => app.close());
expect((await app.inject({ url: '/healthz' })).statusCode).toBe(401);
expect(
(
await app.inject({
url: '/healthz',
headers: { [GATEWAY_AUTH_HEADER]: 'wrong-but-same-length-xxxxxxxxxxxxxxxxx' },
})
).statusCode,
).toBe(401);
const ok = await app.inject({ url: '/healthz', headers: { [GATEWAY_AUTH_HEADER]: token } });
expect(ok.statusCode).toBe(200);
expect(ok.payload).not.toContain(token);
});
it('readiness checks a live migrated DB and auth configuration without reading secrets', async () => {
const directory = await mkdtemp(join(tmpdir(), 'runtime-ready-'));
cleanup.push(() => rm(directory, { recursive: true, force: true }));
const db = openDatabase(join(directory, 'db.sqlite'));
migrateDatabase(db);
const keychainMetadataCheck = vi.fn(async () => true);
const readiness = createProductionReadiness({ db, gatewayToken: token, keychainMetadataCheck });
expect(await readiness()).toEqual({
ready: true,
checks: { database: 'ready', migrations: 'ready', gatewayAuth: 'ready', keychain: 'ready' },
});
expect(keychainMetadataCheck).toHaveBeenCalledOnce();
db.close();
expect((await readiness()).ready).toBe(false);
});
it('gateway replaces forged auth and only falls back for extensionless routes', async () => {
const directory = await mkdtemp(join(tmpdir(), 'runtime-gateway-'));
await mkdir(join(directory, 'assets'));
await writeFile(join(directory, 'index.html'), '<main>SPA</main>');
cleanup.push(() => rm(directory, { recursive: true, force: true }));
let seen: string | string[] | undefined;
const upstream = createServer((request, response) => {
seen = request.headers[GATEWAY_AUTH_HEADER];
response.end('ok');
});
await new Promise<void>((done) => upstream.listen(0, '127.0.0.1', done));
cleanup.push(() => new Promise<void>((done) => upstream.close(() => done())));
const address = upstream.address();
if (!address || typeof address === 'string') throw new Error('address');
const gateway: CanaryGateway = createCanaryGateway({
distDir: directory,
port: 0,
upstreamPort: address.port,
gatewayToken: token,
});
await gateway.start();
cleanup.push(() => gateway.stop());
await fetch(`${gateway.origin}/healthz`, { headers: { [GATEWAY_AUTH_HEADER]: 'forged' } });
expect(seen).toBe(token);
expect((await fetch(`${gateway.origin}/assets/missing.js`)).status).toBe(404);
expect((await fetch(`${gateway.origin}/missing.css`)).status).toBe(404);
expect((await fetch(`${gateway.origin}/instances/one`)).status).toBe(200);
});
});