hivecast-sdk/archive/mx-cli-runtime-host-tests/standalone-webapp-server.spec.ts

245 lines
8.6 KiB
TypeScript

import { describe, it } from 'node:test';
import { strict as assert } from 'node:assert';
import * as fs from 'node:fs';
import * as net from 'node:net';
import * as os from 'node:os';
import * as path from 'node:path';
import type { ILoadedMatrixPackageEnvironment } from '../../src/utils/package-environment.js';
import type { IResolvedRunnerTransportPlan } from '../../src/utils/runner-transport.js';
import type { ILoadedMatrixWebappManifest } from '../../src/utils/webapp-manifest.js';
import { startStandaloneWebappServer } from '../../src/utils/standalone-webapp-server.js';
async function getAvailablePort(): Promise<number> {
const server = await new Promise<net.Server>((resolve, reject) => {
const candidate = net.createServer();
candidate.once('error', reject);
candidate.listen(0, '127.0.0.1', () => resolve(candidate));
});
const address = server.address();
assert.ok(address && typeof address === 'object');
const port = address.port;
await new Promise<void>((resolve, reject) => {
server.close((error) => (error ? reject(error) : resolve()));
});
return port;
}
describe('standalone webapp server', () => {
it('advertises JWT browser auth when the runner transport uses credentialsRef', async () => {
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'standalone-webapp-server-'));
const packageDir = path.join(tempRoot, 'package');
const distDir = path.join(packageDir, 'dist');
fs.mkdirSync(distDir, { recursive: true });
const httpPort = await getAvailablePort();
const credentialsPath = path.join(tempRoot, 'credentials.json');
fs.writeFileSync(credentialsPath, JSON.stringify({
jwt: 'sample.jwt.value',
seed: 'SUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
}), 'utf8');
fs.writeFileSync(
path.join(distDir, 'index.html'),
'<!doctype html><html><body>fixture</body></html>',
'utf8',
);
const loadedEnvironment: ILoadedMatrixPackageEnvironment = {
packageDir,
envName: 'host',
environmentPath: path.join(packageDir, '.matrix', 'host.environment.json'),
environment: {
name: 'host',
runtime: { root: 'COM.TEST.EXTERNAL' },
nats: {
mode: 'external',
url: 'nats://example.test:4222',
wsUrl: 'wss://example.test/nats-ws',
credentialsRef: `file:${credentialsPath}`,
},
http: {
enabled: true,
port: httpPort,
},
},
};
const webapp: ILoadedMatrixWebappManifest = {
packageDir,
packageName: '@acme/webapp',
manifestPath: path.join(packageDir, 'matrix.json'),
distDir,
entryFile: 'index.html',
appName: 'webapp',
};
const runnerTransport: IResolvedRunnerTransportPlan = {
envName: 'host',
root: 'COM.TEST.EXTERNAL',
mode: 'external',
url: 'nats://example.test:4222',
wsUrl: 'wss://example.test/nats-ws',
credentialsRef: `file:${credentialsPath}`,
};
const server = await startStandaloneWebappServer({
loadedEnvironment,
webapp,
runnerTransport,
});
try {
const bootstrap = await fetch(`${server.baseUrl}/api/bootstrap`);
assert.equal(bootstrap.status, 200);
const bootstrapPayload = await bootstrap.json() as {
authorityContext?: {
assetHostRoot?: string;
platformServiceRoot?: string;
sessionAuthorityRoot?: string | null;
selectedAuthorityRoot?: string | null;
runtimeInstanceRoot?: string | null;
isAuthenticated?: boolean;
isPlatformAdmin?: boolean;
selectableAuthorityRoots?: string[];
};
authorityRoot?: string;
busRoot?: string;
runtimeInstanceRoot?: string | null;
transportPlan?: {
authMode?: string;
authEndpoint?: string | null;
wsPath?: string;
};
sources?: {
transportAuthMode?: string;
};
};
assert.deepEqual(bootstrapPayload.authorityContext, {
assetHostRoot: 'COM.TEST.EXTERNAL',
platformServiceRoot: 'COM.TEST.EXTERNAL',
sessionAuthorityRoot: 'COM.TEST.EXTERNAL',
selectedAuthorityRoot: 'COM.TEST.EXTERNAL',
runtimeInstanceRoot: null,
isAuthenticated: true,
isPlatformAdmin: false,
selectableAuthorityRoots: ['COM.TEST.EXTERNAL'],
});
assert.equal(bootstrapPayload.authorityRoot, 'COM.TEST.EXTERNAL');
assert.equal(bootstrapPayload.busRoot, 'COM.TEST.EXTERNAL');
assert.equal(bootstrapPayload.runtimeInstanceRoot, null);
assert.equal(bootstrapPayload.transportPlan?.wsPath, '/nats-ws');
assert.equal(bootstrapPayload.transportPlan?.authMode, 'jwt');
assert.equal(bootstrapPayload.transportPlan?.authEndpoint, '/api/nats-jwt');
assert.equal(bootstrapPayload.sources?.transportAuthMode, 'credentials-ref');
const auth = await fetch(`${server.baseUrl}/api/nats-jwt`, { method: 'POST' });
assert.equal(auth.status, 200);
const authPayload = await auth.json() as {
mode?: string;
jwt?: string;
seed?: string;
};
assert.equal(authPayload.mode, 'jwt');
assert.equal(authPayload.jwt, 'sample.jwt.value');
assert.equal(authPayload.seed, 'SUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA');
} finally {
await server.shutdown();
}
});
it('forwards explicit upstream WebSocket paths without duplicating /nats-ws', async () => {
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'standalone-webapp-server-proxy-'));
const packageDir = path.join(tempRoot, 'package');
const distDir = path.join(packageDir, 'dist');
fs.mkdirSync(distDir, { recursive: true });
fs.writeFileSync(
path.join(distDir, 'index.html'),
'<!doctype html><html><body>fixture</body></html>',
'utf8',
);
const httpPort = await getAvailablePort();
const upstreamPort = await getAvailablePort();
let capturedRequest = '';
const upstream = net.createServer();
const captured = new Promise<void>((resolve) => {
upstream.on('connection', (socket) => {
socket.once('data', (chunk: Buffer) => {
capturedRequest = chunk.toString('utf8');
socket.end('HTTP/1.1 404 Not Found\r\nConnection: close\r\nContent-Length: 0\r\n\r\n');
resolve();
});
});
});
await new Promise<void>((resolve, reject) => {
upstream.once('error', reject);
upstream.listen(upstreamPort, '127.0.0.1', () => {
upstream.off('error', reject);
resolve();
});
});
const loadedEnvironment: ILoadedMatrixPackageEnvironment = {
packageDir,
envName: 'host',
environmentPath: path.join(packageDir, '.matrix', 'host.environment.json'),
environment: {
name: 'host',
runtime: { root: 'COM.TEST.EXTERNAL' },
nats: {
mode: 'external',
url: `nats://127.0.0.1:${upstreamPort}`,
wsUrl: `ws://127.0.0.1:${upstreamPort}/nats-ws`,
},
http: {
enabled: true,
port: httpPort,
},
},
};
const webapp: ILoadedMatrixWebappManifest = {
packageDir,
packageName: '@acme/webapp',
manifestPath: path.join(packageDir, 'matrix.json'),
distDir,
entryFile: 'index.html',
appName: 'webapp',
};
const runnerTransport: IResolvedRunnerTransportPlan = {
envName: 'host',
root: 'COM.TEST.EXTERNAL',
mode: 'external',
url: `nats://127.0.0.1:${upstreamPort}`,
wsUrl: `ws://127.0.0.1:${upstreamPort}/nats-ws`,
};
const server = await startStandaloneWebappServer({
loadedEnvironment,
webapp,
runnerTransport,
});
const client = net.connect(httpPort, '127.0.0.1');
try {
await new Promise<void>((resolve) => {
client.once('connect', resolve);
});
client.write([
'GET /nats-ws?probe=1 HTTP/1.1',
`Host: 127.0.0.1:${httpPort}`,
'Connection: Upgrade',
'Upgrade: websocket',
'Origin: http://127.0.0.1:9999',
'Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==',
'Sec-WebSocket-Version: 13',
'',
'',
].join('\r\n'));
await captured;
assert.match(capturedRequest, /^GET \/nats-ws\?probe=1 HTTP\/1\.1\r\n/);
assert.doesNotMatch(capturedRequest, /\/nats-ws\/nats-ws/);
assert.doesNotMatch(capturedRequest, /\r\nOrigin:/i);
} finally {
client.destroy();
await server.shutdown();
await new Promise<void>((resolve) => {
upstream.close(() => resolve());
});
}
});
});