2599 lines
95 KiB
TypeScript
Raw Permalink Normal View History

import { afterEach, describe, it } from 'node:test';
import { strict as assert } from 'node:assert';
import { spawn, type ChildProcessWithoutNullStreams } from 'node:child_process';
import * as fs from 'node:fs';
import * as http from 'node:http';
import * as net from 'node:net';
import * as os from 'node:os';
import * as path from 'node:path';
import { connect as natsConnect, type NatsConnection } from 'nats';
import { runMxCli, parseLastJson, assertExitCode } from '../helpers/cli-harness.js';
import { hiveCastLoginCommand, hiveCastLogoutCommand } from '../../src/commands/auth.js';
import { readHiveCastLinkStatus, removeHiveCastHostLink, saveHiveCastHostLink } from '../../src/utils/hivecast-link-store.js';
describe('FP-30 mx auth session commands', () => {
const tempDirs: string[] = [];
const restoreEnvFns: Array<() => void> = [];
const TEST_LOCAL_OWNER_ROOT = 'local-test-owner-root';
afterEach(() => {
while (restoreEnvFns.length > 0) {
const restore = restoreEnvFns.pop();
if (restore) {
restore();
}
}
while (tempDirs.length > 0) {
const dir = tempDirs.pop();
if (dir) {
fs.rmSync(dir, { recursive: true, force: true });
}
}
});
function useMatrixHome(matrixHome: string): void {
const previousMatrixHome = process.env.MATRIX_HOME;
const previousHostHome = process.env.MATRIX_HOST_HOME;
const previousCliConfig = process.env.MATRIX_CLI_CONFIG;
const previousPackageRegistry = process.env.MATRIX_PACKAGE_REGISTRY;
const previousRegistryUrl = process.env.MATRIX_REGISTRY_URL;
const previousHivecastRegistry = process.env.HIVECAST_PACKAGE_REGISTRY;
const previousNpmUserConfig = process.env.NPM_CONFIG_USERCONFIG;
const previousNodeAuthToken = process.env.NODE_AUTH_TOKEN;
const previousNpmToken = process.env.NPM_TOKEN;
process.env.MATRIX_HOME = matrixHome;
delete process.env.MATRIX_HOST_HOME;
delete process.env.MATRIX_CLI_CONFIG;
delete process.env.MATRIX_PACKAGE_REGISTRY;
delete process.env.MATRIX_REGISTRY_URL;
delete process.env.HIVECAST_PACKAGE_REGISTRY;
delete process.env.NPM_CONFIG_USERCONFIG;
delete process.env.NODE_AUTH_TOKEN;
delete process.env.NPM_TOKEN;
restoreEnvFns.push(() => {
restoreEnv('MATRIX_HOME', previousMatrixHome);
restoreEnv('MATRIX_HOST_HOME', previousHostHome);
restoreEnv('MATRIX_CLI_CONFIG', previousCliConfig);
restoreEnv('MATRIX_PACKAGE_REGISTRY', previousPackageRegistry);
restoreEnv('MATRIX_REGISTRY_URL', previousRegistryUrl);
restoreEnv('HIVECAST_PACKAGE_REGISTRY', previousHivecastRegistry);
restoreEnv('NPM_CONFIG_USERCONFIG', previousNpmUserConfig);
restoreEnv('NODE_AUTH_TOKEN', previousNodeAuthToken);
restoreEnv('NPM_TOKEN', previousNpmToken);
});
}
function restoreEnv(key: string, value: string | undefined): void {
if (value === undefined) {
delete process.env[key];
return;
}
process.env[key] = value;
}
async function readRequestBody(req: http.IncomingMessage): Promise<string> {
const chunks: Buffer[] = [];
for await (const chunk of req) {
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
}
return Buffer.concat(chunks).toString('utf8');
}
function asRecord(value: unknown): Record<string, unknown> | null {
return value && typeof value === 'object' && !Array.isArray(value)
? value as Record<string, unknown>
: null;
}
function optionalString(value: unknown): string | undefined {
return typeof value === 'string' && value.trim().length > 0 ? value.trim() : undefined;
}
function installToken(installId: string): string {
return installId
.toUpperCase()
.replace(/[^A-Z0-9]+/g, '-')
.replace(/^-+|-+$/g, '');
}
function installRootToken(installId: string): string {
return installId
.toLowerCase()
.replace(/[^a-z0-9]+/g, '-')
.replace(/^-+|-+$/g, '');
}
function localRootForInstallId(installId: string): string {
return `local-${installRootToken(installId)}`;
}
function installScopeForInstallId(installId: string): string {
return installToken(installId);
}
function writeInstallIdentity(matrixHome: string, installId: string): void {
const credentialsDir = path.join(matrixHome, 'credentials');
fs.mkdirSync(credentialsDir, { recursive: true });
fs.writeFileSync(path.join(credentialsDir, 'hivecast-install.json'), `${JSON.stringify({
version: 1,
installId,
createdAt: '2026-05-27T00:00:00.000Z',
updatedAt: '2026-05-27T00:00:00.000Z',
}, null, 2)}\n`, 'utf8');
}
function readInstallIdentityId(matrixHome: string): string {
const identity = readJsonRecord(path.join(matrixHome, 'credentials', 'hivecast-install.json'));
const installId = optionalString(identity.installId);
assert.ok(installId);
return installId;
}
async function getAvailablePort(): Promise<number> {
return await new Promise<number>((resolve, reject) => {
const server = net.createServer();
server.once('error', reject);
server.listen(0, '127.0.0.1', () => {
const address = server.address();
if (!address || typeof address === 'string') {
server.close(() => reject(new Error('Failed to allocate TCP port')));
return;
}
const port = address.port;
server.close((err) => (err ? reject(err) : resolve(port)));
});
});
}
async function waitForTcpPort(port: number): Promise<void> {
const deadline = Date.now() + 10_000;
while (Date.now() < deadline) {
const open = await new Promise<boolean>((resolve) => {
const socket = net.connect({ host: '127.0.0.1', port });
socket.once('connect', () => {
socket.destroy();
resolve(true);
});
socket.once('error', () => {
socket.destroy();
resolve(false);
});
socket.setTimeout(500, () => {
socket.destroy();
resolve(false);
});
});
if (open) {
return;
}
await new Promise((resolve) => setTimeout(resolve, 50));
}
throw new Error(`Timed out waiting for nats-server on port ${port}`);
}
function resolveNatsServerBinary(): string {
const binaryName = process.platform === 'win32' ? 'nats-server.exe' : 'nats-server';
const candidates = [
process.env.NATS_SERVER_BINARY,
path.resolve(process.cwd(), 'projects', 'nats-server', binaryName),
path.resolve(process.cwd(), '..', '..', '..', 'nats-server', binaryName),
path.resolve(process.cwd(), '..', 'hivecast', 'dist', 'bin', binaryName),
...((process.env.PATH ?? '').split(path.delimiter).map((entry) => path.join(entry, binaryName))),
].filter((value): value is string => typeof value === 'string' && value.trim().length > 0);
const found = candidates.find((candidate) => fs.existsSync(candidate));
if (!found) {
throw new Error('nats-server binary is required for HiveCast running-Host reload proof');
}
return found;
}
async function stopProcess(child: ChildProcessWithoutNullStreams): Promise<void> {
if (child.exitCode !== null) {
return;
}
await new Promise<void>((resolve) => {
const timeout = setTimeout(() => {
if (child.exitCode === null) {
child.kill('SIGKILL');
}
}, 2_000);
child.once('exit', () => {
clearTimeout(timeout);
resolve();
});
child.kill('SIGTERM');
});
}
async function withNatsServer<T>(run: (natsUrl: string) => Promise<T>): Promise<T> {
const port = await getAvailablePort();
const dataDir = fs.mkdtempSync(path.join(os.tmpdir(), 'mx-fp30-nats-'));
tempDirs.push(dataDir);
const configPath = path.join(dataDir, 'nats-server.conf');
fs.writeFileSync(configPath, [
'host: "127.0.0.1"',
`port: ${port}`,
'',
].join('\n'), 'utf8');
const child = spawn(resolveNatsServerBinary(), ['-c', configPath], {
stdio: 'pipe',
env: process.env,
});
let stderr = '';
child.stderr.on('data', (chunk: Buffer) => {
stderr += chunk.toString('utf8');
});
try {
await Promise.race([
waitForTcpPort(port),
new Promise<never>((_resolve, reject) => {
child.once('exit', (code) => {
reject(new Error(`nats-server exited early (${code}): ${stderr}`));
});
}),
]);
return await run(`nats://127.0.0.1:${port}`);
} finally {
await stopProcess(child);
}
}
function writeHostStatusFromConfig(matrixHome: string, natsUrl: string, previousPid = process.pid): void {
const hostConfig = asRecord(JSON.parse(fs.readFileSync(path.join(matrixHome, 'host.json'), 'utf8')));
assert.ok(hostConfig);
const transport = asRecord(hostConfig.transport);
assert.ok(transport);
const nats = asRecord(transport.nats);
const root = optionalString(transport.root);
assert.ok(root);
const authorityRoot = optionalString(transport.authorityRoot) ?? root;
const addressRoot = optionalString(transport.addressRoot) ?? authorityRoot;
const wsUrl = optionalString(nats?.wsUrl);
fs.writeFileSync(path.join(matrixHome, 'host.status.json'), `${JSON.stringify({
kind: 'MatrixHostStatus',
version: 1,
status: 'running',
root,
authorityRoot,
addressRoot,
pid: previousPid,
home: matrixHome,
supervisorMount: 'host.supervisor.PID-TEST',
startedAt: '2026-04-28T00:00:00.000Z',
updatedAt: new Date().toISOString(),
http: {
host: '127.0.0.1',
port: 3100,
origin: 'http://127.0.0.1:3100',
},
transport: {
root,
authorityRoot,
addressRoot,
...(optionalString(transport.spaceId) ? { spaceId: optionalString(transport.spaceId) } : {}),
...(optionalString(transport.routeKey) ? { routeKey: optionalString(transport.routeKey) } : {}),
...(optionalString(transport.publicNamespace)
? { publicNamespace: optionalString(transport.publicNamespace) }
: {}),
nats: {
mode: 'external',
url: natsUrl,
...(wsUrl ? { wsUrl } : {}),
},
},
}, null, 2)}\n`, 'utf8');
}
function testWsUrlForNatsUrl(natsUrl: string): string {
const parsed = new URL(natsUrl);
const port = Number.parseInt(parsed.port, 10);
assert.equal(Number.isInteger(port), true);
return `ws://127.0.0.1:${port + 1}`;
}
function writeLocalOwnerHostStatus(
matrixHome: string,
natsUrl: string,
root = TEST_LOCAL_OWNER_ROOT,
): void {
fs.mkdirSync(matrixHome, { recursive: true });
const wsUrl = testWsUrlForNatsUrl(natsUrl);
fs.writeFileSync(path.join(matrixHome, 'host.status.json'), `${JSON.stringify({
kind: 'MatrixHostStatus',
version: 1,
status: 'running',
root,
authorityRoot: root,
addressRoot: root,
pid: process.pid,
home: matrixHome,
supervisorMount: 'host.supervisor.PID-TEST',
startedAt: '2026-04-28T00:00:00.000Z',
updatedAt: new Date().toISOString(),
http: {
host: '127.0.0.1',
port: 3100,
origin: 'http://127.0.0.1:3100',
},
transport: {
root,
authorityRoot: root,
nats: {
mode: 'external',
url: natsUrl,
wsUrl,
},
},
}, null, 2)}\n`, 'utf8');
}
function readJsonRecord(filePath: string): Record<string, unknown> {
const parsed = asRecord(JSON.parse(fs.readFileSync(filePath, 'utf8')));
assert.ok(parsed, `Expected JSON object at ${filePath}`);
return parsed;
}
function assertHostConfigRoot(
matrixHome: string,
expectedRoot: string,
expected: {
readonly routeKey?: string;
readonly publicNamespace?: string;
readonly spaceId?: string;
} = {},
): void {
const hostConfig = readJsonRecord(path.join(matrixHome, 'host.json'));
const transport = asRecord(hostConfig.transport);
assert.ok(transport);
const root = optionalString(transport.root);
const authorityRoot = optionalString(transport.authorityRoot) ?? root;
const addressRoot = optionalString(transport.addressRoot) ?? authorityRoot;
assert.equal(root, expectedRoot);
assert.equal(authorityRoot, expectedRoot);
assert.equal(addressRoot, expectedRoot);
assert.equal(transport.routeKey, expected.routeKey);
assert.equal(transport.publicNamespace, expected.publicNamespace);
assert.equal(transport.spaceId, expected.spaceId);
}
function assertHostStatusRoot(
matrixHome: string,
expectedRoot: string,
expected: {
readonly routeKey?: string;
readonly publicNamespace?: string;
readonly spaceId?: string;
} = {},
): void {
const status = readJsonRecord(path.join(matrixHome, 'host.status.json'));
const transport = asRecord(status.transport);
assert.ok(transport);
assert.equal(status.root, expectedRoot);
assert.equal(status.authorityRoot, expectedRoot);
assert.equal(status.addressRoot, expectedRoot);
assert.equal(transport.root, expectedRoot);
assert.equal(transport.authorityRoot, expectedRoot);
assert.equal(transport.addressRoot, expectedRoot);
assert.equal(transport.routeKey, expected.routeKey);
assert.equal(transport.publicNamespace, expected.publicNamespace);
assert.equal(transport.spaceId, expected.spaceId);
}
async function withReloadSupervisor<T>(
natsUrl: string,
matrixHome: string,
run: (reloadCount: () => number) => Promise<T>,
onReload?: (reloadCount: number) => void,
): Promise<T> {
const nc: NatsConnection = await natsConnect({ servers: [natsUrl], name: 'mx-cli-reload-proof' });
const sub = nc.subscribe('>');
let reloads = 0;
const loop = (async () => {
for await (const msg of sub) {
const decoded = asRecord(JSON.parse(new TextDecoder().decode(msg.data) || '{}'));
if (decoded?.op !== 'config.reload') {
continue;
}
reloads += 1;
onReload?.(reloads);
writeHostStatusFromConfig(matrixHome, natsUrl);
const replyTo = optionalString(decoded.replyTo) ?? msg.reply;
if (replyTo) {
nc.publish(replyTo, new TextEncoder().encode(JSON.stringify({
ok: true,
correlationId: optionalString(decoded.correlationId),
result: { ok: true, status: 'reloading' },
})));
}
}
})();
try {
return await run(() => reloads);
} finally {
sub.unsubscribe();
await nc.drain();
await loop.catch(() => undefined);
}
}
async function withTokenExchangeServer<T>(
handler: (body: Record<string, unknown>) => Record<string, unknown>,
run: (cloudUrl: string) => Promise<T>,
): Promise<T> {
const server = http.createServer(async (req, res) => {
if (req.method !== 'POST' || req.url !== '/api/token-exchange') {
res.writeHead(404, { 'content-type': 'application/json' });
res.end(JSON.stringify({ ok: false, error: 'not found' }));
return;
}
const body = JSON.parse(await readRequestBody(req)) as Record<string, unknown>;
const payload = handler(body);
res.writeHead(200, { 'content-type': 'application/json' });
res.end(JSON.stringify(payload));
});
await new Promise<void>((resolve) => server.listen(0, '127.0.0.1', resolve));
const address = server.address();
assert(address && typeof address === 'object');
try {
return await run(`http://127.0.0.1:${address.port}`);
} finally {
await new Promise<void>((resolve, reject) => {
server.close((err) => {
if (err) {
reject(err);
return;
}
resolve();
});
});
}
}
async function withPairFlowServer<T>(
config: {
readonly pairRequestId: string;
readonly approvalCode: string;
readonly exchange: Record<string, unknown>;
readonly expectedRouteKey?: string;
readonly autoApprove?: boolean;
},
run: (
cloudUrl: string,
controls: {
readonly getLastLocalReturnUrl: () => string | null;
readonly getStartBody: () => Record<string, unknown> | null;
},
) => Promise<T>,
): Promise<T> {
let origin = '';
let lastLocalReturnUrl: string | null = null;
let startBody: Record<string, unknown> | null = null;
const server = http.createServer(async (req, res) => {
if (req.method === 'POST' && req.url === '/_auth/pair/start') {
const body = JSON.parse(await readRequestBody(req) || '{}') as Record<string, unknown>;
startBody = body;
if (config.expectedRouteKey !== undefined) {
assert.equal(body.routeKey, config.expectedRouteKey);
}
if (typeof body.localReturnUrl === 'string') {
lastLocalReturnUrl = body.localReturnUrl;
}
res.writeHead(200, { 'content-type': 'application/json' });
res.end(JSON.stringify({
ok: true,
pairRequestId: config.pairRequestId,
approvalUrl: `${origin}/_auth/pair/${config.pairRequestId}`,
expiresIn: 600,
}));
if (config.autoApprove && lastLocalReturnUrl) {
const nonce = typeof body.nonce === 'string' ? body.nonce : '';
setImmediate(() => {
void fetch(`${lastLocalReturnUrl}?pairRequestId=${config.pairRequestId}&approvalCode=${config.approvalCode}&nonce=${encodeURIComponent(nonce)}`);
});
}
return;
}
if (req.method === 'POST' && req.url === '/_auth/pair/exchange') {
const body = JSON.parse(await readRequestBody(req)) as Record<string, unknown>;
assert.equal(body.pairRequestId, config.pairRequestId);
assert.equal(body.approvalCode, config.approvalCode);
res.writeHead(200, { 'content-type': 'application/json' });
res.end(JSON.stringify({
ok: true,
...config.exchange,
}));
return;
}
res.writeHead(404, { 'content-type': 'application/json' });
res.end(JSON.stringify({ ok: false, error: 'not found' }));
});
await new Promise<void>((resolve) => server.listen(0, '127.0.0.1', resolve));
const address = server.address();
assert(address && typeof address === 'object');
origin = `http://127.0.0.1:${address.port}`;
try {
return await run(origin, {
getLastLocalReturnUrl: () => lastLocalReturnUrl,
getStartBody: () => startBody,
});
} finally {
await new Promise<void>((resolve, reject) => {
server.close((err) => {
if (err) {
reject(err);
return;
}
resolve();
});
});
}
}
async function withDeviceFlowServer<T>(
run: (cloudUrl: string) => Promise<T>,
config: { readonly authorityCoordinator?: boolean } = {},
): Promise<T> {
const server = http.createServer(async (req, res) => {
if (req.method === 'POST' && req.url === '/_auth/device/start') {
const body = JSON.parse(await readRequestBody(req) || '{}') as Record<string, unknown>;
assert.equal(body.routeKey, 'hivecast-lab');
assert.equal(body.hostName, 'test-host');
assert.equal(body.authorityCoordinator, false);
assert.equal(Object.prototype.hasOwnProperty.call(body, 'name'), false);
res.writeHead(200, { 'content-type': 'application/json' });
res.end(JSON.stringify({
ok: true,
deviceCode: 'DEVICE-123',
userCode: 'K7P9-TQ2M',
verificationUri: 'https://hivecast.example.test/activate',
verificationUriComplete: 'https://hivecast.example.test/activate?user_code=K7P9-TQ2M',
expiresIn: 600,
interval: 1,
}));
return;
}
if (req.method === 'POST' && req.url === '/_auth/device/poll') {
const body = JSON.parse(await readRequestBody(req)) as Record<string, unknown>;
assert.equal(body.deviceCode, 'DEVICE-123');
res.writeHead(200, { 'content-type': 'application/json' });
res.end(JSON.stringify({ ok: true, status: 'approved', interval: 1 }));
return;
}
if (req.method === 'POST' && req.url === '/_auth/device/exchange') {
const body = JSON.parse(await readRequestBody(req)) as Record<string, unknown>;
assert.equal(body.deviceCode, 'DEVICE-123');
res.writeHead(200, { 'content-type': 'application/json' });
res.end(JSON.stringify({
ok: true,
root: 'SPACE-HIVECAST-LAB',
routeKey: 'hivecast-lab',
publicNamespace: 'space.hivecast-lab',
spaceId: 'space_01DEVICE',
principalId: 'p_device',
hostName: 'test-host',
deviceSlug: 'test-host',
hostLink: {
id: 'host-link-device-01',
hostId: 'DEVICE-123',
hostName: 'test-host',
deviceSlug: 'test-host',
...(typeof config.authorityCoordinator === 'boolean' ? { authorityCoordinator: config.authorityCoordinator } : {}),
heartbeatToken: 'hlink_test_device_token',
status: 'active',
},
...(typeof config.authorityCoordinator === 'boolean' ? { authorityCoordinator: config.authorityCoordinator } : {}),
nats: {
url: 'nats://hivecast.example.test:4222',
wsUrl: 'wss://hivecast.example.test/nats-ws',
},
credentials: {
jwt: 'device.jwt.token',
seed: 'SUDEVICESEED',
},
}));
return;
}
if (req.method === 'POST' && req.url === '/_auth/host-link/revoke') {
assert.equal(req.headers.authorization, 'Bearer hlink_test_device_token');
const body = JSON.parse(await readRequestBody(req)) as Record<string, unknown>;
assert.equal(body.hostLinkId, 'host-link-device-01');
assert.equal(body.hostId, 'DEVICE-123');
res.writeHead(200, { 'content-type': 'application/json' });
res.end(JSON.stringify({
ok: true,
hostLink: {
id: 'host-link-device-01',
hostId: 'DEVICE-123',
status: 'revoked',
},
}));
return;
}
res.writeHead(404, { 'content-type': 'application/json' });
res.end(JSON.stringify({ ok: false, error: 'not found' }));
});
await new Promise<void>((resolve) => server.listen(0, '127.0.0.1', resolve));
const address = server.address();
assert(address && typeof address === 'object');
try {
return await run(`http://127.0.0.1:${address.port}`);
} finally {
await new Promise<void>((resolve, reject) => {
server.close((err) => {
if (err) {
reject(err);
return;
}
resolve();
});
});
}
}
async function withDeviceNamespaceRequiredServer<T>(
run: (cloudUrl: string) => Promise<T>,
): Promise<T> {
const server = http.createServer(async (req, res) => {
if (req.method === 'POST' && req.url === '/_auth/device/start') {
const body = JSON.parse(await readRequestBody(req) || '{}') as Record<string, unknown>;
assert.equal(body.routeKey, 'owned-key');
res.writeHead(200, { 'content-type': 'application/json' });
res.end(JSON.stringify({
ok: true,
deviceCode: 'DEVICE-OWNED',
userCode: 'K7P9-OWND',
verificationUri: 'https://hivecast.example.test/activate',
verificationUriComplete: 'https://hivecast.example.test/activate?user_code=K7P9-OWND',
expiresIn: 600,
interval: 1,
}));
return;
}
if (req.method === 'POST' && req.url === '/_auth/device/poll') {
const body = JSON.parse(await readRequestBody(req)) as Record<string, unknown>;
assert.equal(body.deviceCode, 'DEVICE-OWNED');
res.writeHead(409, { 'content-type': 'application/json' });
res.end(JSON.stringify({
ok: false,
error: 'namespace_required',
status: 'namespace_required',
setupUrl: '/apps/web/#setup?redirect=%2Factivate%3Fuser_code%3DK7P9-OWND',
}));
return;
}
if (req.method === 'POST' && req.url === '/_auth/device/exchange') {
res.writeHead(500, { 'content-type': 'application/json' });
res.end(JSON.stringify({ ok: false, error: 'exchange should not be reached' }));
return;
}
res.writeHead(404, { 'content-type': 'application/json' });
res.end(JSON.stringify({ ok: false, error: 'not found' }));
});
await new Promise<void>((resolve) => server.listen(0, '127.0.0.1', resolve));
const address = server.address();
assert(address && typeof address === 'object');
try {
return await run(`http://127.0.0.1:${address.port}`);
} finally {
await new Promise<void>((resolve, reject) => {
server.close((err) => {
if (err) {
reject(err);
return;
}
resolve();
});
});
}
}
it('supports login, whoami, and logout lifecycle', async () => {
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'mx-fp30-auth-'));
tempDirs.push(root);
const credentialsFile = path.join(root, '.matrix', 'credentials.json');
const loginResult = await runMxCli([
'node',
'mx',
'login',
'--username',
'alice',
'--token',
'token-123',
'--registry',
'https://pkg.matrix.dev',
'--credentials-file',
credentialsFile,
'--json',
], { cwd: root });
assertExitCode(loginResult, 0);
const whoamiAfterLogin = await runMxCli([
'node',
'mx',
'whoami',
'--registry',
'https://pkg.matrix.dev',
'--credentials-file',
credentialsFile,
'--json',
], { cwd: root });
assertExitCode(whoamiAfterLogin, 0);
const whoamiPayload = parseLastJson(whoamiAfterLogin.logs) as { authenticated: boolean; username?: string };
assert.equal(whoamiPayload.authenticated, true);
assert.equal(whoamiPayload.username, 'alice');
const logoutResult = await runMxCli([
'node',
'mx',
'logout',
'--registry',
'https://pkg.matrix.dev',
'--credentials-file',
credentialsFile,
'--json',
], { cwd: root });
assertExitCode(logoutResult, 0);
const whoamiAfterLogout = await runMxCli([
'node',
'mx',
'whoami',
'--registry',
'https://pkg.matrix.dev',
'--credentials-file',
credentialsFile,
'--json',
], { cwd: root });
assertExitCode(whoamiAfterLogout, 0);
const afterLogoutPayload = parseLastJson(whoamiAfterLogout.logs) as { authenticated: boolean };
assert.equal(afterLogoutPayload.authenticated, false);
});
it('reads npm auth token from configured .npmrc for whoami', async () => {
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'mx-fp30-npmrc-auth-'));
tempDirs.push(root);
useMatrixHome(path.join(root, '.matrix'));
const registry = 'https://registry.example.test/api/packages/open-matrix/npm/';
const npmrcPath = path.join(root, '.npmrc');
fs.writeFileSync(
npmrcPath,
'//registry.example.test/api/packages/open-matrix/npm/:_authToken=test-token-from-npmrc\n',
'utf8',
);
process.env.NPM_CONFIG_USERCONFIG = npmrcPath;
const whoamiResult = await runMxCli([
'node',
'mx',
'whoami',
'--registry',
registry,
'--json',
], { cwd: root });
assertExitCode(whoamiResult, 0);
const payload = parseLastJson(whoamiResult.logs) as {
authenticated: boolean;
username?: string;
registry: string;
};
assert.equal(payload.authenticated, true);
assert.equal(payload.username, 'npm-token');
assert.equal(payload.registry, registry);
});
it('does not read home .npmrc when NPM_CONFIG_USERCONFIG points at an explicit file', async () => {
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'mx-fp30-explicit-npmrc-auth-'));
tempDirs.push(root);
const homeDir = path.join(root, 'home');
fs.mkdirSync(homeDir, { recursive: true });
useMatrixHome(path.join(root, '.matrix'));
const previousHome = process.env.HOME;
const previousUserConfig = process.env.NPM_CONFIG_USERCONFIG;
restoreEnvFns.push(() => {
restoreEnv('HOME', previousHome);
restoreEnv('NPM_CONFIG_USERCONFIG', previousUserConfig);
});
process.env.HOME = homeDir;
const registry = 'https://registry.example.test/api/packages/open-matrix/npm/';
fs.writeFileSync(
path.join(homeDir, '.npmrc'),
'//registry.example.test/api/packages/open-matrix/npm/:_authToken=poisoned-home-token\n',
'utf8',
);
const explicitNpmrcPath = path.join(root, 'empty.npmrc');
fs.writeFileSync(explicitNpmrcPath, '', 'utf8');
process.env.NPM_CONFIG_USERCONFIG = explicitNpmrcPath;
const whoamiResult = await runMxCli([
'node',
'mx',
'whoami',
'--registry',
registry,
'--json',
], { cwd: root });
assertExitCode(whoamiResult, 0);
const payload = parseLastJson(whoamiResult.logs) as {
authenticated: boolean;
username?: string;
registry: string;
};
assert.equal(payload.authenticated, false);
assert.equal(payload.username, undefined);
assert.equal(payload.registry, registry);
});
it('uses Matrix CLI config for the default registry', async () => {
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'mx-fp30-config-'));
tempDirs.push(root);
useMatrixHome(path.join(root, '.matrix'));
const configuredRegistry = 'http://127.0.0.1:4567/api/packages/open-matrix/npm/';
const defaultConfig = await runMxCli([
'node',
'mx',
'config',
'get',
'registry',
'--json',
], { cwd: root });
assertExitCode(defaultConfig, 0);
const defaultPayload = parseLastJson(defaultConfig.logs) as { value: string; source: string };
assert.equal(defaultPayload.value, 'https://registry.hivecast.ai/api/packages/open-matrix/npm/');
assert.equal(defaultPayload.source, 'default');
const setConfig = await runMxCli([
'node',
'mx',
'config',
'set',
'registry',
configuredRegistry,
'--json',
], { cwd: root });
assertExitCode(setConfig, 0);
const listConfig = await runMxCli([
'node',
'mx',
'config',
'list',
'--json',
], { cwd: root });
assertExitCode(listConfig, 0);
const listPayload = parseLastJson(listConfig.logs) as {
values: { registry?: string };
effective: { registry: string; registrySource: string };
};
assert.equal(listPayload.values.registry, configuredRegistry);
assert.equal(listPayload.effective.registry, configuredRegistry);
assert.equal(listPayload.effective.registrySource, 'config');
const credentialsFile = path.join(root, '.matrix', 'credentials.json');
const loginResult = await runMxCli([
'node',
'mx',
'login',
'--username',
'alice',
'--token',
'token-123',
'--credentials-file',
credentialsFile,
'--json',
], { cwd: root });
assertExitCode(loginResult, 0);
const loginPayload = parseLastJson(loginResult.logs) as { registry: string };
assert.equal(loginPayload.registry, configuredRegistry);
const whoamiResult = await runMxCli([
'node',
'mx',
'whoami',
'--credentials-file',
credentialsFile,
'--json',
], { cwd: root });
assertExitCode(whoamiResult, 0);
const whoamiPayload = parseLastJson(whoamiResult.logs) as { authenticated: boolean; registry: string };
assert.equal(whoamiPayload.authenticated, true);
assert.equal(whoamiPayload.registry, configuredRegistry);
const resetConfig = await runMxCli([
'node',
'mx',
'config',
'reset',
'--json',
], { cwd: root });
assertExitCode(resetConfig, 0);
const afterReset = await runMxCli([
'node',
'mx',
'config',
'get',
'registry',
'--json',
], { cwd: root });
assertExitCode(afterReset, 0);
const resetPayload = parseLastJson(afterReset.logs) as { value: string; source: string };
assert.equal(resetPayload.value, 'https://registry.hivecast.ai/api/packages/open-matrix/npm/');
assert.equal(resetPayload.source, 'default');
});
it('prints a HiveCast pair approval URL before approval is available', async () => {
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'mx-fp30-hivecast-url-'));
tempDirs.push(root);
const matrixHome = path.join(root, '.matrix');
await withPairFlowServer(
{
pairRequestId: 'PAIR-URL-123',
approvalCode: 'PAIR-URL-APPROVAL',
expectedRouteKey: 'hivecast-lab',
exchange: {
root: 'SPACE-HIVECAST-LAB',
routeKey: 'hivecast-lab',
publicNamespace: 'space.hivecast-lab',
nats: {
url: 'wss://hivecast.example.test/nats-ws',
},
credentials: {
jwt: 'unused.jwt.token',
seed: 'SUUNUSED',
},
},
},
async (cloudUrl, controls) => {
const loginResult = await runMxCli([
'node',
'mx',
'login',
'--hivecast',
'--cloud',
cloudUrl,
'--route-key',
'hivecast-lab',
'--no-wait',
'--home',
matrixHome,
'--json',
], { cwd: root });
assertExitCode(loginResult, 0);
const payload = parseLastJson(loginResult.logs) as {
mode: string;
linked: boolean;
setupUrl: string;
};
assert.equal(payload.mode, 'approval-required');
assert.equal(payload.linked, false);
const setupUrl = new URL(payload.setupUrl);
assert.equal(setupUrl.origin, cloudUrl);
assert.equal(setupUrl.pathname, '/_auth/pair/PAIR-URL-123');
const startBody = controls.getStartBody();
assert.ok(startBody);
assert.equal(startBody.routeKey, 'hivecast-lab');
assert.equal(startBody.authorityCoordinator, true);
assert.equal(controls.getLastLocalReturnUrl(), null);
},
);
});
it('completes HiveCast setup exchange and stores local Host link state', async () => {
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'mx-fp30-hivecast-link-'));
tempDirs.push(root);
const matrixHome = path.join(root, '.matrix');
fs.mkdirSync(matrixHome, { recursive: true });
fs.writeFileSync(path.join(matrixHome, 'host.json'), `${JSON.stringify({
kind: 'MatrixHostConfig',
version: 1,
home: matrixHome,
transport: {
root: TEST_LOCAL_OWNER_ROOT,
nats: {
mode: 'embedded',
port: 45222,
wsPort: 45223,
dataDir: 'nats/test-local',
pidFile: 'nats/test-local/nats-server.pid',
binaryPath: 'bin/nats-server',
},
},
}, null, 2)}\n`);
await withTokenExchangeServer(
(body) => {
assert.equal(body.code, 'SETUP-123');
return {
ok: true,
root: 'SPACE-HIVECAST-LAB',
routeKey: 'hivecast-lab',
publicNamespace: 'space.hivecast-lab',
spaceId: 'space_01TEST',
principalId: 'p_test',
displayName: 'HiveCast Lab',
nats: {
url: 'wss://hivecast.example.test/nats-ws',
wsUrl: 'wss://hivecast.example.test/nats-ws',
},
credentials: {
jwt: 'setup.jwt.token',
seed: 'SUFAKESEED',
},
};
},
async (cloudUrl) => {
const loginResult = await runMxCli([
'node',
'mx',
'login',
'--hivecast',
'--cloud',
cloudUrl,
'--setup-code',
'SETUP-123',
'--home',
matrixHome,
'--json',
], { cwd: root });
assertExitCode(loginResult, 0);
const loginPayload = parseLastJson(loginResult.logs) as {
linked: boolean;
authorityRoot: string;
routeKey: string;
matrixHome: string;
};
assert.equal(loginPayload.linked, true);
assert.equal(loginPayload.authorityRoot, 'SPACE-HIVECAST-LAB');
assert.equal(loginPayload.routeKey, 'hivecast-lab');
assert.equal(loginPayload.matrixHome, matrixHome);
const linkPath = path.join(matrixHome, 'credentials', 'hivecast-link.json');
const natsPath = path.join(matrixHome, 'credentials', 'hivecast-nats.json');
const hostConfigPath = path.join(matrixHome, 'host.json');
assert.equal(fs.existsSync(linkPath), true);
assert.equal(fs.existsSync(natsPath), true);
assert.equal(fs.existsSync(hostConfigPath), true);
const natsCredentials = JSON.parse(fs.readFileSync(natsPath, 'utf8')) as {
jwt?: string;
seed?: string;
accountSeed?: string;
};
assert.equal(natsCredentials.jwt, 'setup.jwt.token');
assert.equal(natsCredentials.seed, 'SUFAKESEED');
assert.equal(Object.prototype.hasOwnProperty.call(natsCredentials, 'accountSeed'), false);
const hostConfig = JSON.parse(fs.readFileSync(hostConfigPath, 'utf8')) as {
transport: {
root: string;
authorityRoot: string;
nats: {
mode: string;
url: string;
credentialsRef?: string;
};
};
hivecastLocalOwnerTransport?: {
root?: string;
nats?: {
mode?: string;
port?: number;
wsPort?: number;
};
};
};
assert.equal(hostConfig.transport.root, TEST_LOCAL_OWNER_ROOT);
assert.equal(hostConfig.transport.authorityRoot, TEST_LOCAL_OWNER_ROOT);
assert.equal(hostConfig.transport.nats.mode, 'embedded');
assert.equal(hostConfig.transport.nats.credentialsRef, undefined);
assert.equal(hostConfig.hivecastLocalOwnerTransport?.root, TEST_LOCAL_OWNER_ROOT);
assert.equal(hostConfig.hivecastLocalOwnerTransport?.nats?.mode, 'embedded');
assert.equal(hostConfig.hivecastLocalOwnerTransport?.nats?.port, 45222);
assert.equal(hostConfig.hivecastLocalOwnerTransport?.nats?.wsPort, 45223);
const whoamiResult = await runMxCli([
'node',
'mx',
'whoami',
'--hivecast',
'--home',
matrixHome,
'--json',
], { cwd: root });
assertExitCode(whoamiResult, 0);
const whoamiPayload = parseLastJson(whoamiResult.logs) as {
linked: boolean;
authorityRoot: string;
routeKey: string;
publicNamespace: string;
principalId: string;
};
assert.equal(whoamiPayload.linked, true);
assert.equal(whoamiPayload.authorityRoot, 'SPACE-HIVECAST-LAB');
assert.equal(whoamiPayload.routeKey, 'hivecast-lab');
assert.equal(whoamiPayload.publicNamespace, 'space.hivecast-lab');
assert.equal(whoamiPayload.principalId, 'p_test');
const statusResult = await runMxCli([
'node',
'mx',
'link-status',
'--home',
matrixHome,
'--json',
], { cwd: root });
assertExitCode(statusResult, 0);
const statusPayload = parseLastJson(statusResult.logs) as {
linked: boolean;
authorityRoot: string;
spaceId: string;
natsCredentialsPresent: boolean;
hostConfigPresent: boolean;
};
assert.equal(statusPayload.linked, true);
assert.equal(statusPayload.authorityRoot, 'SPACE-HIVECAST-LAB');
assert.equal(statusPayload.spaceId, 'space_01TEST');
assert.equal(statusPayload.natsCredentialsPresent, true);
assert.equal(statusPayload.hostConfigPresent, true);
const logoutResult = await runMxCli([
'node',
'mx',
'logout',
'--hivecast',
'--home',
matrixHome,
'--json',
], { cwd: root });
assertExitCode(logoutResult, 0);
const logoutPayload = parseLastJson(logoutResult.logs) as { removed: boolean; hostConfigReset: boolean };
assert.equal(logoutPayload.removed, true);
assert.equal(logoutPayload.hostConfigReset, true);
assert.equal(fs.existsSync(linkPath), false);
assert.equal(fs.existsSync(natsPath), false);
assert.equal(fs.existsSync(path.join(matrixHome, 'credentials.json')), false);
const localOnlyHostConfig = JSON.parse(fs.readFileSync(hostConfigPath, 'utf8')) as {
transport: {
root: string;
authorityRoot?: string;
routeKey?: string;
publicNamespace?: string;
spaceId?: string;
nats: {
mode: string;
port?: number;
wsPort?: number;
dataDir?: string;
credentialsRef?: string;
};
};
};
assert.equal(localOnlyHostConfig.transport.root, TEST_LOCAL_OWNER_ROOT);
assert.equal(localOnlyHostConfig.transport.authorityRoot, undefined);
assert.equal(localOnlyHostConfig.transport.routeKey, undefined);
assert.equal(localOnlyHostConfig.transport.publicNamespace, undefined);
assert.equal(localOnlyHostConfig.transport.spaceId, undefined);
assert.equal(localOnlyHostConfig.transport.nats.mode, 'embedded');
assert.equal(localOnlyHostConfig.transport.nats.port, 45222);
assert.equal(localOnlyHostConfig.transport.nats.wsPort, 45223);
assert.equal(localOnlyHostConfig.transport.nats.dataDir, 'nats/test-local');
assert.equal(localOnlyHostConfig.transport.nats.credentialsRef, undefined);
const afterLogoutStatusResult = await runMxCli([
'node',
'mx',
'link-status',
'--home',
matrixHome,
'--json',
], { cwd: root });
assertExitCode(afterLogoutStatusResult, 0);
const afterLogoutStatus = parseLastJson(afterLogoutStatusResult.logs) as {
linked: boolean;
natsCredentialsPresent: boolean;
hostConfigLinked: boolean;
};
assert.equal(afterLogoutStatus.linked, false);
assert.equal(afterLogoutStatus.natsCredentialsPresent, false);
assert.equal(afterLogoutStatus.hostConfigLinked, false);
},
);
});
it('preserves the running local owner NATS ports when linking from a started Host', () => {
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'mx-fp30-hivecast-running-ports-'));
tempDirs.push(root);
const matrixHome = path.join(root, '.matrix');
fs.mkdirSync(matrixHome, { recursive: true });
const installId = 'install_running_ports';
writeInstallIdentity(matrixHome, installId);
fs.writeFileSync(path.join(matrixHome, 'host.json'), `${JSON.stringify({
kind: 'MatrixHostConfig',
version: 1,
home: matrixHome,
transport: {
root: TEST_LOCAL_OWNER_ROOT,
nats: {
mode: 'embedded',
port: 4222,
wsPort: 4223,
dataDir: 'nats/host-default',
pidFile: 'nats/host-default/nats-server.pid',
binaryPath: 'bin/nats-server',
},
},
}, null, 2)}\n`);
fs.writeFileSync(path.join(matrixHome, 'host.status.json'), `${JSON.stringify({
kind: 'MatrixHostStatus',
version: 1,
status: 'running',
pid: process.pid,
home: matrixHome,
supervisorMount: `host.supervisor.PID-${process.pid}`,
startedAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
http: {
host: '127.0.0.1',
port: 45100,
origin: 'http://127.0.0.1:45100',
},
transport: {
root: TEST_LOCAL_OWNER_ROOT,
authorityRoot: TEST_LOCAL_OWNER_ROOT,
nats: {
mode: 'external',
url: 'nats://127.0.0.1:45222',
wsUrl: 'ws://127.0.0.1:45223',
},
},
}, null, 2)}\n`);
const localScope = installScopeForInstallId(installId);
const localEdgeRuntimeId = `RUNTIME-HOST-${localScope}-EDGE`;
const staleLinkedRuntimeId = 'RUNTIME-HOST-STALE-LINKED-EDGE';
const staleLinkedChatRuntimeId = 'RUNTIME-HOST-STALE-LINKED-CHAT';
for (const runtimeId of [localEdgeRuntimeId, staleLinkedRuntimeId, staleLinkedChatRuntimeId]) {
const recordDir = path.join(matrixHome, 'runtimes', runtimeId);
fs.mkdirSync(recordDir, { recursive: true });
fs.writeFileSync(path.join(recordDir, 'runtime.json'), `${JSON.stringify({
runtimeId,
packageDir: path.join(matrixHome, 'packages', 'global', 'node_modules', '@open-matrix', 'matrix-edge'),
status: 'stopped',
startup: 'auto',
restart: 'always',
startedAt: new Date().toISOString(),
stoppedAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
localMounts: ['edge'],
metadata: {},
}, null, 2)}\n`);
}
saveHiveCastHostLink({
cwd: root,
matrixHome,
cloudUrl: 'https://hivecast.example.test',
hostId: 'host_running_ports',
authorityRoot: 'SPACE-HIVECAST-LAB',
routeKey: 'hivecast-lab',
publicNamespace: 'space.hivecast-lab',
spaceId: 'space_01RUNNINGPORTS',
nats: { url: 'wss://hivecast.example.test/nats-ws' },
natsCredentials: { accountSeed: 'SARUNNINGPORTS' },
});
const linkedConfig = JSON.parse(fs.readFileSync(path.join(matrixHome, 'host.json'), 'utf8')) as {
transport?: {
root?: string;
authorityRoot?: string;
routeKey?: string;
publicNamespace?: string;
spaceId?: string;
nats?: {
credentialsRef?: string;
};
};
hivecastLocalOwnerTransport?: {
nats?: {
mode?: string;
url?: string;
wsUrl?: string;
port?: number;
wsPort?: number;
};
};
};
assert.equal(linkedConfig.transport?.root, TEST_LOCAL_OWNER_ROOT);
assert.equal(linkedConfig.transport?.authorityRoot, TEST_LOCAL_OWNER_ROOT);
assert.equal(linkedConfig.transport?.routeKey, undefined);
assert.equal(linkedConfig.transport?.publicNamespace, undefined);
assert.equal(linkedConfig.transport?.spaceId, undefined);
assert.equal(linkedConfig.transport?.nats?.credentialsRef, undefined);
assert.equal(linkedConfig.hivecastLocalOwnerTransport?.nats?.mode, 'external');
assert.equal(linkedConfig.hivecastLocalOwnerTransport?.nats?.url, 'nats://127.0.0.1:45222');
assert.equal(linkedConfig.hivecastLocalOwnerTransport?.nats?.wsUrl, 'ws://127.0.0.1:45223');
assert.equal(linkedConfig.hivecastLocalOwnerTransport?.nats?.port, 45222);
assert.equal(linkedConfig.hivecastLocalOwnerTransport?.nats?.wsPort, 45223);
const localEdgeAfterLink = JSON.parse(fs.readFileSync(
path.join(matrixHome, 'runtimes', localEdgeRuntimeId, 'runtime.json'),
'utf8',
)) as { startup?: string; restart?: string };
assert.equal(localEdgeAfterLink.startup, 'auto');
assert.equal(localEdgeAfterLink.restart, 'always');
const removed = removeHiveCastHostLink(root, matrixHome);
assert.equal(removed.hostConfigReset, true);
const localConfig = JSON.parse(fs.readFileSync(path.join(matrixHome, 'host.json'), 'utf8')) as {
transport: {
authorityRoot?: string;
nats: {
mode?: string;
url?: string;
wsUrl?: string;
port?: number;
wsPort?: number;
};
};
};
assert.equal(localConfig.transport.authorityRoot, undefined);
assert.equal(localConfig.transport.nats.mode, 'external');
assert.equal(localConfig.transport.nats.url, 'nats://127.0.0.1:45222');
assert.equal(localConfig.transport.nats.wsUrl, 'ws://127.0.0.1:45223');
assert.equal(localConfig.transport.nats.port, 45222);
assert.equal(localConfig.transport.nats.wsPort, 45223);
const localEdgeAfterLogout = JSON.parse(fs.readFileSync(
path.join(matrixHome, 'runtimes', localEdgeRuntimeId, 'runtime.json'),
'utf8',
)) as { startup?: string; restart?: string };
const staleLinkedAfterLogout = JSON.parse(fs.readFileSync(
path.join(matrixHome, 'runtimes', staleLinkedRuntimeId, 'runtime.json'),
'utf8',
)) as { startup?: string; restart?: string };
const staleLinkedChatAfterLogout = JSON.parse(fs.readFileSync(
path.join(matrixHome, 'runtimes', staleLinkedChatRuntimeId, 'runtime.json'),
'utf8',
)) as { startup?: string; restart?: string };
assert.equal(localEdgeAfterLogout.startup, 'auto');
assert.equal(localEdgeAfterLogout.restart, 'always');
assert.equal(staleLinkedAfterLogout.startup, 'manual');
assert.equal(staleLinkedAfterLogout.restart, 'never');
assert.equal(staleLinkedChatAfterLogout.startup, 'manual');
assert.equal(staleLinkedChatAfterLogout.restart, 'never');
});
it('derives a fresh unlinked Device root from the stable install identity', () => {
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'mx-fp30-hivecast-fresh-local-root-'));
tempDirs.push(root);
const matrixHome = path.join(root, '.matrix');
const installId = 'install_fresh_device_root';
writeInstallIdentity(matrixHome, installId);
saveHiveCastHostLink({
cwd: root,
matrixHome,
cloudUrl: 'https://hivecast.example.test',
hostId: 'host_fresh_local_root',
authorityRoot: 'SPACE-HIVECAST-LAB',
routeKey: 'hivecast-lab',
publicNamespace: 'space.hivecast-lab',
spaceId: 'space_01FRESHLOCALROOT',
nats: { url: 'wss://hivecast.example.test/nats-ws' },
natsCredentials: { accountSeed: 'SAFRESHLOCALROOT' },
});
const hostConfig = readJsonRecord(path.join(matrixHome, 'host.json'));
const transport = asRecord(hostConfig.transport);
assert.ok(transport);
assert.equal(transport.root, localRootForInstallId(installId));
assert.equal(transport.authorityRoot, localRootForInstallId(installId));
assert.equal(transport.addressRoot, localRootForInstallId(installId));
assert.match(String(transport.root), /^local-install-fresh-device-root$/);
});
it('preserves local owner NATS ports from runtime records when device login links a stopped Host', () => {
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'mx-fp30-hivecast-stopped-ports-'));
tempDirs.push(root);
const matrixHome = path.join(root, '.matrix');
fs.mkdirSync(matrixHome, { recursive: true });
const installId = 'install_stopped_ports';
writeInstallIdentity(matrixHome, installId);
fs.writeFileSync(path.join(matrixHome, 'host.json'), `${JSON.stringify({
kind: 'MatrixHostConfig',
version: 1,
home: matrixHome,
transport: {
root: TEST_LOCAL_OWNER_ROOT,
nats: {
mode: 'embedded',
port: 4222,
wsPort: 4223,
dataDir: 'nats/host-default',
pidFile: 'nats/host-default/nats-server.pid',
binaryPath: 'bin/nats-server',
},
},
}, null, 2)}\n`);
const localScope = installScopeForInstallId(installId);
const localGatewayRuntimeId = `RUNTIME-HOST-${localScope}-GATEWAY`;
const recordDir = path.join(matrixHome, 'runtimes', localGatewayRuntimeId);
fs.mkdirSync(recordDir, { recursive: true });
fs.writeFileSync(path.join(recordDir, 'runtime.json'), `${JSON.stringify({
runtimeId: localGatewayRuntimeId,
packageDir: path.join(matrixHome, 'packages', 'system', '@open-matrix', 'system-gateway-http'),
status: 'stopped',
startup: 'auto',
restart: 'always',
startedAt: new Date().toISOString(),
stoppedAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
localMounts: ['system.gateway.http'],
metadata: {
transport: {
root: TEST_LOCAL_OWNER_ROOT,
authorityRoot: TEST_LOCAL_OWNER_ROOT,
nats: {
mode: 'external',
url: 'nats://127.0.0.1:46222',
wsUrl: 'ws://127.0.0.1:46223',
},
},
},
}, null, 2)}\n`);
saveHiveCastHostLink({
cwd: root,
matrixHome,
cloudUrl: 'https://hivecast.example.test',
hostId: 'host_stopped_ports',
authorityRoot: 'SPACE-HIVECAST-LAB',
routeKey: 'hivecast-lab',
publicNamespace: 'space.hivecast-lab',
spaceId: 'space_01STOPPEDPORTS',
nats: { url: 'wss://hivecast.example.test/nats-ws' },
natsCredentials: { accountSeed: 'SASTOPPEDPORTS' },
});
const linkedConfig = JSON.parse(fs.readFileSync(path.join(matrixHome, 'host.json'), 'utf8')) as {
hivecastLocalOwnerTransport?: {
nats?: {
port?: number;
wsPort?: number;
};
};
};
assert.equal(linkedConfig.hivecastLocalOwnerTransport?.nats?.port, 46222);
assert.equal(linkedConfig.hivecastLocalOwnerTransport?.nats?.wsPort, 46223);
const removed = removeHiveCastHostLink(root, matrixHome);
assert.equal(removed.hostConfigReset, true);
const localConfig = JSON.parse(fs.readFileSync(path.join(matrixHome, 'host.json'), 'utf8')) as {
transport: {
root?: string;
authorityRoot?: string;
routeKey?: string;
publicNamespace?: string;
spaceId?: string;
nats: {
mode?: string;
port?: number;
wsPort?: number;
};
};
};
assert.equal(localConfig.transport.root, TEST_LOCAL_OWNER_ROOT);
assert.equal(localConfig.transport.authorityRoot, undefined);
assert.equal(localConfig.transport.routeKey, undefined);
assert.equal(localConfig.transport.publicNamespace, undefined);
assert.equal(localConfig.transport.spaceId, undefined);
assert.equal(localConfig.transport.nats.mode, 'external');
assert.equal(localConfig.transport.nats.url, 'nats://127.0.0.1:46222');
assert.equal(localConfig.transport.nats.wsUrl, 'ws://127.0.0.1:46223');
assert.equal(localConfig.transport.nats.port, 46222);
assert.equal(localConfig.transport.nats.wsPort, 46223);
});
it('preserves sibling local owner NATS ports from host config when linking a stopped Host', () => {
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'mx-fp30-hivecast-stopped-config-ports-'));
tempDirs.push(root);
const matrixHome = path.join(root, '.matrix');
fs.mkdirSync(matrixHome, { recursive: true });
fs.writeFileSync(path.join(matrixHome, 'host.json'), `${JSON.stringify({
kind: 'MatrixHostConfig',
version: 1,
home: matrixHome,
transport: {
root: TEST_LOCAL_OWNER_ROOT,
authorityRoot: TEST_LOCAL_OWNER_ROOT,
nats: {
mode: 'external',
url: 'nats://127.0.0.1:47222',
wsUrl: 'ws://127.0.0.1:47223',
port: 47222,
wsPort: 47223,
dataDir: 'nats/host-default',
pidFile: 'nats/host-default/nats-server.pid',
binaryPath: 'bin/nats-server',
},
},
}, null, 2)}\n`);
saveHiveCastHostLink({
cwd: root,
matrixHome,
cloudUrl: 'https://hivecast.example.test',
hostId: 'host_stopped_config_ports',
authorityRoot: 'SPACE-HIVECAST-LAB',
routeKey: 'hivecast-lab',
publicNamespace: 'space.hivecast-lab',
spaceId: 'space_01STOPPEDCONFIGPORTS',
nats: { url: 'wss://hivecast.example.test/nats-ws' },
natsCredentials: { accountSeed: 'SASTOPPEDCONFIGPORTS' },
});
const linkedConfig = JSON.parse(fs.readFileSync(path.join(matrixHome, 'host.json'), 'utf8')) as {
hivecastLocalOwnerTransport?: {
nats?: {
port?: number;
wsPort?: number;
};
};
};
assert.equal(linkedConfig.hivecastLocalOwnerTransport?.nats?.port, 47222);
assert.equal(linkedConfig.hivecastLocalOwnerTransport?.nats?.wsPort, 47223);
const removed = removeHiveCastHostLink(root, matrixHome);
assert.equal(removed.hostConfigReset, true);
const localConfig = JSON.parse(fs.readFileSync(path.join(matrixHome, 'host.json'), 'utf8')) as {
transport: {
root?: string;
authorityRoot?: string;
routeKey?: string;
publicNamespace?: string;
spaceId?: string;
nats: {
mode?: string;
port?: number;
wsPort?: number;
credentialsRef?: string;
};
};
};
assert.equal(localConfig.transport.root, TEST_LOCAL_OWNER_ROOT);
assert.equal(localConfig.transport.authorityRoot, undefined);
assert.equal(localConfig.transport.routeKey, undefined);
assert.equal(localConfig.transport.publicNamespace, undefined);
assert.equal(localConfig.transport.spaceId, undefined);
assert.equal(localConfig.transport.nats.mode, 'external');
assert.equal(localConfig.transport.nats.url, 'nats://127.0.0.1:47222');
assert.equal(localConfig.transport.nats.wsUrl, 'ws://127.0.0.1:47223');
assert.equal(localConfig.transport.nats.port, 47222);
assert.equal(localConfig.transport.nats.wsPort, 47223);
assert.equal(localConfig.transport.nats.credentialsRef, undefined);
});
it('moves authority-coordinator Host config onto the linked user authority root', () => {
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'mx-fp30-hivecast-linked-coordinator-root-'));
tempDirs.push(root);
const matrixHome = path.join(root, '.matrix');
fs.mkdirSync(matrixHome, { recursive: true });
const installId = 'install_42fab8eeedac46d6e348';
writeInstallIdentity(matrixHome, installId);
fs.writeFileSync(path.join(matrixHome, 'host.json'), `${JSON.stringify({
kind: 'MatrixHostConfig',
version: 1,
home: matrixHome,
transport: {
root: TEST_LOCAL_OWNER_ROOT,
authorityRoot: TEST_LOCAL_OWNER_ROOT,
nats: {
mode: 'external',
url: 'nats://127.0.0.1:48222',
wsUrl: 'ws://127.0.0.1:48223',
port: 48222,
wsPort: 48223,
},
},
}, null, 2)}\n`);
const installScope = installScopeForInstallId(installId);
const installSystemRuntimeId = `RUNTIME-HOST-${installScope}-SYSTEM`;
const installHostOpsRuntimeId = `RUNTIME-HOST-${installScope}-HOST-OPS`;
const localScope = 'LOCAL-STALE-HASH-SCOPE';
const localSystemRuntimeId = `RUNTIME-HOST-${localScope}-SYSTEM`;
const localHostOpsRuntimeId = `RUNTIME-HOST-${localScope}-HOST-OPS`;
for (const runtimeId of [
installSystemRuntimeId,
installHostOpsRuntimeId,
localSystemRuntimeId,
localHostOpsRuntimeId,
]) {
const recordDir = path.join(matrixHome, 'runtimes', runtimeId);
fs.mkdirSync(recordDir, { recursive: true });
fs.writeFileSync(path.join(recordDir, 'runtime.json'), `${JSON.stringify({
runtimeId,
packageDir: path.join(matrixHome, 'packages', 'global', 'node_modules', '@open-matrix', 'system'),
status: 'stopped',
startup: 'auto',
restart: 'always',
updatedAt: new Date().toISOString(),
localMounts: ['system', 'system.registry', 'system.devices', 'system.runtimes'],
metadata: {},
}, null, 2)}\n`);
}
saveHiveCastHostLink({
cwd: root,
matrixHome,
cloudUrl: 'https://hivecast.example.test',
hostId: 'install_42fab8eeedac46d6e348',
authorityRoot: 'test-user-1',
routeKey: 'test-user-1',
publicNamespace: 'test-user-1',
spaceId: 'space_test_user_1',
authorityCoordinator: true,
nats: {
url: 'nats://dev-platform:4222',
wsUrl: 'wss://dev-platform/nats-ws',
},
natsCredentials: { accountSeed: 'SATESTUSER1' },
});
const linkedConfig = JSON.parse(fs.readFileSync(path.join(matrixHome, 'host.json'), 'utf8')) as {
transport?: {
root?: string;
authorityRoot?: string;
addressRoot?: string;
routeKey?: string;
publicNamespace?: string;
spaceId?: string;
nats?: {
mode?: string;
url?: string;
wsUrl?: string;
port?: number;
wsPort?: number;
credentialsRef?: string;
};
};
hivecastLocalOwnerTransport?: {
root?: string;
nats?: {
url?: string;
wsUrl?: string;
};
};
};
assert.equal(linkedConfig.transport?.root, 'test-user-1');
assert.equal(linkedConfig.transport?.authorityRoot, 'test-user-1');
assert.equal(linkedConfig.transport?.addressRoot, 'test-user-1');
assert.equal(linkedConfig.transport?.routeKey, 'test-user-1');
assert.equal(linkedConfig.transport?.publicNamespace, 'test-user-1');
assert.equal(linkedConfig.transport?.spaceId, 'space_test_user_1');
assert.equal(linkedConfig.transport?.nats?.mode, 'external');
assert.equal(linkedConfig.transport?.nats?.url, 'nats://dev-platform:4222');
assert.equal(linkedConfig.transport?.nats?.wsUrl, 'wss://dev-platform/nats-ws');
assert.equal(linkedConfig.transport?.nats?.port, undefined);
assert.equal(linkedConfig.transport?.nats?.wsPort, undefined);
assert.equal(
linkedConfig.transport?.nats?.credentialsRef,
`file:${path.join(matrixHome, 'credentials', 'hivecast-nats.json')}`,
);
assert.equal(linkedConfig.hivecastLocalOwnerTransport?.root, TEST_LOCAL_OWNER_ROOT);
assert.equal(linkedConfig.hivecastLocalOwnerTransport?.nats?.url, 'nats://127.0.0.1:48222');
assert.equal(linkedConfig.hivecastLocalOwnerTransport?.nats?.wsUrl, 'ws://127.0.0.1:48223');
const installSystemAfterLink = JSON.parse(fs.readFileSync(
path.join(matrixHome, 'runtimes', installSystemRuntimeId, 'runtime.json'),
'utf8',
)) as { startup?: string; restart?: string; metadata?: { hivecastDefaultRuntimePolicy?: string } };
assert.equal(installSystemAfterLink.startup, 'auto');
assert.equal(installSystemAfterLink.restart, 'always');
assert.equal(installSystemAfterLink.metadata?.hivecastDefaultRuntimePolicy, 'active');
const localSystemAfterLink = JSON.parse(fs.readFileSync(
path.join(matrixHome, 'runtimes', localSystemRuntimeId, 'runtime.json'),
'utf8',
)) as { startup?: string; restart?: string; metadata?: { hivecastDefaultRuntimePolicy?: string } };
assert.equal(localSystemAfterLink.startup, 'manual');
assert.equal(localSystemAfterLink.restart, 'never');
assert.equal(localSystemAfterLink.metadata?.hivecastDefaultRuntimePolicy, 'inactive');
const installHostOpsAfterLink = JSON.parse(fs.readFileSync(
path.join(matrixHome, 'runtimes', installHostOpsRuntimeId, 'runtime.json'),
'utf8',
)) as { startup?: string; restart?: string; metadata?: { hivecastDefaultRuntimePolicy?: string } };
assert.equal(installHostOpsAfterLink.startup, 'auto');
assert.equal(installHostOpsAfterLink.restart, 'always');
assert.equal(installHostOpsAfterLink.metadata?.hivecastDefaultRuntimePolicy, 'active');
const localHostOpsAfterLink = JSON.parse(fs.readFileSync(
path.join(matrixHome, 'runtimes', localHostOpsRuntimeId, 'runtime.json'),
'utf8',
)) as { startup?: string; restart?: string; metadata?: { hivecastDefaultRuntimePolicy?: string } };
assert.equal(localHostOpsAfterLink.startup, 'manual');
assert.equal(localHostOpsAfterLink.restart, 'never');
assert.equal(localHostOpsAfterLink.metadata?.hivecastDefaultRuntimePolicy, 'inactive');
});
it('refuses authority-coordinator links without an installed local Host transport', () => {
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'mx-fp30-hivecast-linked-coordinator-no-local-'));
tempDirs.push(root);
const matrixHome = path.join(root, '.matrix');
fs.mkdirSync(matrixHome, { recursive: true });
assert.throws(
() => saveHiveCastHostLink({
cwd: root,
matrixHome,
cloudUrl: 'https://hivecast.example.test',
hostId: 'install_ws_only',
authorityRoot: 'test-user-1',
authorityCoordinator: true,
nats: { url: 'wss://hivecast.example.test/nats-ws' },
natsCredentials: { jwt: 'device.jwt.token', seed: 'SUDEVICESEED' },
}),
/HIVECAST_LINK_LOCAL_TRANSPORT_MISSING/,
);
});
it('does not classify local owner authorityRoot as a HiveCast link', () => {
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'mx-fp30-hivecast-local-authority-'));
tempDirs.push(root);
const matrixHome = path.join(root, '.matrix');
fs.mkdirSync(matrixHome, { recursive: true });
fs.writeFileSync(path.join(matrixHome, 'host.json'), `${JSON.stringify({
kind: 'MatrixHostConfig',
version: 1,
home: matrixHome,
transport: {
root: TEST_LOCAL_OWNER_ROOT,
authorityRoot: TEST_LOCAL_OWNER_ROOT,
nats: {
mode: 'embedded',
port: 46222,
wsPort: 46223,
},
},
}, null, 2)}\n`);
const status = readHiveCastLinkStatus(root, matrixHome);
assert.equal(status.linked, false);
assert.equal(status.hostConfigLinked, false);
});
it('does not classify sibling local owner NATS as a HiveCast link', () => {
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'mx-fp30-hivecast-local-sibling-'));
tempDirs.push(root);
const matrixHome = path.join(root, '.matrix');
fs.mkdirSync(matrixHome, { recursive: true });
fs.writeFileSync(path.join(matrixHome, 'host.json'), `${JSON.stringify({
kind: 'MatrixHostConfig',
version: 1,
home: matrixHome,
transport: {
root: TEST_LOCAL_OWNER_ROOT,
authorityRoot: TEST_LOCAL_OWNER_ROOT,
nats: {
mode: 'external',
url: 'nats://127.0.0.1:47222',
wsUrl: 'ws://127.0.0.1:47223',
port: 47222,
wsPort: 47223,
},
},
}, null, 2)}\n`);
const status = readHiveCastLinkStatus(root, matrixHome);
assert.equal(status.linked, false);
assert.equal(status.hostConfigLinked, false);
});
it('completes HiveCast device login and stores local Host link state', async () => {
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'mx-fp30-hivecast-device-'));
tempDirs.push(root);
const matrixHome = path.join(root, '.matrix');
await withDeviceFlowServer(async (cloudUrl) => {
const loginResult = await runMxCli([
'node',
'mx',
'login',
'--hivecast',
'--device',
'--cloud',
cloudUrl,
'--route-key',
'hivecast-lab',
'--name',
'test-host',
'--home',
matrixHome,
'--json',
], { cwd: root });
assertExitCode(loginResult, 0);
const loginPayload = parseLastJson(loginResult.logs) as {
linked: boolean;
hostLinkId: string;
hostId: string;
authorityRoot: string;
routeKey: string;
publicNamespace: string;
spaceId: string;
hostName?: string;
deviceSlug?: string;
};
assert.equal(loginPayload.linked, true);
assert.equal(loginPayload.hostLinkId, 'host-link-device-01');
assert.equal(loginPayload.hostId, 'DEVICE-123');
assert.equal(loginPayload.authorityRoot, 'SPACE-HIVECAST-LAB');
assert.equal(loginPayload.routeKey, 'hivecast-lab');
assert.equal(loginPayload.publicNamespace, 'space.hivecast-lab');
assert.equal(loginPayload.spaceId, 'space_01DEVICE');
assert.equal(loginPayload.hostName, 'test-host');
assert.equal(loginPayload.deviceSlug, 'test-host');
assert.equal(fs.existsSync(path.join(matrixHome, 'credentials', 'hivecast-link.json')), true);
const natsCredentials = JSON.parse(fs.readFileSync(path.join(matrixHome, 'credentials', 'hivecast-nats.json'), 'utf8')) as {
jwt?: string;
seed?: string;
accountSeed?: string;
};
assert.equal(natsCredentials.jwt, 'device.jwt.token');
assert.equal(natsCredentials.seed, 'SUDEVICESEED');
assert.equal(Object.prototype.hasOwnProperty.call(natsCredentials, 'accountSeed'), false);
assert.equal(fs.existsSync(path.join(matrixHome, 'host.json')), true);
const hostConfig = JSON.parse(fs.readFileSync(path.join(matrixHome, 'host.json'), 'utf8')) as {
transport: {
root: string;
authorityRoot: string;
routeKey?: string;
publicNamespace?: string;
spaceId?: string;
nats?: {
credentialsRef?: string;
};
};
};
const expectedLocalRoot = localRootForInstallId(readInstallIdentityId(matrixHome));
assert.equal(hostConfig.transport.root, expectedLocalRoot);
assert.equal(hostConfig.transport.authorityRoot, expectedLocalRoot);
assert.equal(hostConfig.transport.routeKey, undefined);
assert.equal(hostConfig.transport.publicNamespace, undefined);
assert.equal(hostConfig.transport.spaceId, undefined);
assert.equal(hostConfig.transport.nats?.credentialsRef, undefined);
const whoamiResult = await runMxCli([
'node',
'mx',
'whoami',
'--hivecast',
'--home',
matrixHome,
'--json',
], { cwd: root });
assertExitCode(whoamiResult, 0);
const whoamiPayload = parseLastJson(whoamiResult.logs) as {
linked: boolean;
hostLinkId: string;
authorityRoot: string;
routeKey: string;
publicNamespace: string;
principalId: string;
hostName?: string;
deviceSlug?: string;
};
assert.equal(whoamiPayload.linked, true);
assert.equal(whoamiPayload.hostLinkId, 'host-link-device-01');
assert.equal(whoamiPayload.authorityRoot, 'SPACE-HIVECAST-LAB');
assert.equal(whoamiPayload.routeKey, 'hivecast-lab');
assert.equal(whoamiPayload.publicNamespace, 'space.hivecast-lab');
assert.equal(whoamiPayload.principalId, 'p_device');
assert.equal(whoamiPayload.hostName, 'test-host');
assert.equal(whoamiPayload.deviceSlug, 'test-host');
const statusResult = await runMxCli([
'node',
'mx',
'link-status',
'--home',
matrixHome,
'--json',
], { cwd: root });
assertExitCode(statusResult, 0);
const statusPayload = parseLastJson(statusResult.logs) as {
linked: boolean;
hostLinkId: string;
authorityRoot: string;
routeKey: string;
publicNamespace: string;
spaceId: string;
natsCredentialsPresent: boolean;
hostConfigLinked: boolean;
};
assert.equal(statusPayload.linked, true);
assert.equal(statusPayload.hostLinkId, 'host-link-device-01');
assert.equal(statusPayload.authorityRoot, 'SPACE-HIVECAST-LAB');
assert.equal(statusPayload.routeKey, 'hivecast-lab');
assert.equal(statusPayload.publicNamespace, 'space.hivecast-lab');
assert.equal(statusPayload.spaceId, 'space_01DEVICE');
assert.equal(statusPayload.natsCredentialsPresent, true);
assert.equal(statusPayload.hostConfigLinked, true);
const logoutResult = await runMxCli([
'node',
'mx',
'logout',
'--hivecast',
'--revoke-cloud-link',
'--home',
matrixHome,
'--json',
], { cwd: root });
assertExitCode(logoutResult, 0);
const logoutPayload = parseLastJson(logoutResult.logs) as {
removed: boolean;
cloudRevoke?: {
attempted: boolean;
revoked: boolean;
};
hostConfigReset: boolean;
};
assert.equal(logoutPayload.removed, true);
assert.equal(logoutPayload.cloudRevoke?.attempted, true);
assert.equal(logoutPayload.cloudRevoke?.revoked, true);
assert.equal(logoutPayload.hostConfigReset, true);
assert.equal(fs.existsSync(path.join(matrixHome, 'credentials', 'hivecast-link.json')), false);
});
});
it('prints HiveCast device-code challenge without polling when no-wait is requested', async () => {
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'mx-fp30-hivecast-device-no-wait-'));
tempDirs.push(root);
const matrixHome = path.join(root, '.matrix');
await withDeviceFlowServer(async (cloudUrl) => {
const loginResult = await runMxCli([
'node',
'mx',
'login',
'--hivecast',
'--device',
'--cloud',
cloudUrl,
'--route-key',
'hivecast-lab',
'--name',
'test-host',
'--home',
matrixHome,
'--json',
'--no-wait',
], { cwd: root });
assertExitCode(loginResult, 0);
const loginPayload = parseLastJson(loginResult.logs) as {
mode: string;
linked: boolean;
deviceCode: string;
userCode: string;
verificationUri: string;
verificationUriComplete: string;
setupUrl: string;
};
assert.equal(loginPayload.mode, 'approval-required');
assert.equal(loginPayload.linked, false);
assert.equal(loginPayload.deviceCode, 'DEVICE-123');
assert.equal(loginPayload.userCode, 'K7P9-TQ2M');
assert.equal(loginPayload.verificationUri, 'https://hivecast.example.test/activate');
assert.equal(loginPayload.verificationUriComplete, 'https://hivecast.example.test/activate?user_code=K7P9-TQ2M');
assert.equal(loginPayload.setupUrl, loginPayload.verificationUriComplete);
assert.equal(fs.existsSync(path.join(matrixHome, 'credentials', 'hivecast-link.json')), false);
assert.equal(fs.existsSync(path.join(matrixHome, 'credentials', 'hivecast-nats.json')), false);
});
});
it('treats --headless as the product alias for HiveCast device-code login', async () => {
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'mx-fp30-hivecast-headless-'));
tempDirs.push(root);
const matrixHome = path.join(root, '.matrix');
await withDeviceFlowServer(async (cloudUrl) => {
const loginResult = await runMxCli([
'node',
'mx',
'login',
'--hivecast',
'--headless',
'--cloud',
cloudUrl,
'--route-key',
'hivecast-lab',
'--name',
'test-host',
'--home',
matrixHome,
'--json',
], { cwd: root });
assertExitCode(loginResult, 0);
const loginPayload = parseLastJson(loginResult.logs) as {
linked: boolean;
hostLinkId: string;
authorityRoot: string;
};
assert.equal(loginPayload.linked, true);
assert.equal(loginPayload.hostLinkId, 'host-link-device-01');
assert.equal(loginPayload.authorityRoot, 'SPACE-HIVECAST-LAB');
assert.equal(fs.existsSync(path.join(matrixHome, 'credentials', 'hivecast-link.json')), true);
});
});
it('keeps headless HiveCast device login on the linked authority root for an installed Host', async () => {
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'mx-fp30-hivecast-headless-root-'));
tempDirs.push(root);
const matrixHome = path.join(root, '.matrix');
await withNatsServer(async (natsUrl) => {
writeLocalOwnerHostStatus(matrixHome, natsUrl, 'hivecast-headless-local-owner-root');
await withReloadSupervisor(natsUrl, matrixHome, async (reloadCount) => {
await withDeviceFlowServer(async (cloudUrl) => {
const loginResult = await runMxCli([
'node',
'mx',
'login',
'--hivecast',
'--headless',
'--cloud',
cloudUrl,
'--route-key',
'hivecast-lab',
'--name',
'test-host',
'--home',
matrixHome,
'--json',
], { cwd: root });
assertExitCode(loginResult, 0);
const loginPayload = parseLastJson(loginResult.logs) as {
linked: boolean;
hostLinkId: string;
authorityRoot: string;
authorityCoordinator: boolean;
};
assert.equal(loginPayload.linked, true);
assert.equal(loginPayload.hostLinkId, 'host-link-device-01');
assert.equal(loginPayload.authorityRoot, 'SPACE-HIVECAST-LAB');
assert.equal(loginPayload.authorityCoordinator, false);
assert.equal(reloadCount(), 1);
assertHostConfigRoot(matrixHome, 'SPACE-HIVECAST-LAB', {
routeKey: 'hivecast-lab',
publicNamespace: 'space.hivecast-lab',
spaceId: 'space_01DEVICE',
});
assertHostStatusRoot(matrixHome, 'SPACE-HIVECAST-LAB', {
routeKey: 'hivecast-lab',
publicNamespace: 'space.hivecast-lab',
spaceId: 'space_01DEVICE',
});
}, { authorityCoordinator: true });
});
});
});
it('keeps polling HiveCast device login while approval waits for namespace setup', async () => {
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'mx-fp30-hivecast-device-owned-key-'));
tempDirs.push(root);
const matrixHome = path.join(root, '.matrix');
await withDeviceNamespaceRequiredServer(async (cloudUrl) => {
const result = await runMxCli([
'node',
'mx',
'login',
'--hivecast',
'--device',
'--cloud',
cloudUrl,
'--route-key',
'owned-key',
'--home',
matrixHome,
'--json',
'--poll-timeout-ms',
'50',
], { cwd: root });
assertExitCode(result, 1);
assert.match(result.errors.join('\n'), /HIVECAST_DEVICE_TIMEOUT/);
assert.equal(fs.existsSync(path.join(matrixHome, 'credentials', 'hivecast-link.json')), false);
assert.equal(fs.existsSync(path.join(matrixHome, 'credentials', 'hivecast-nats.json')), false);
});
});
it('keeps HiveCast login idempotent and refuses accidental relink to a different route key', async () => {
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'mx-fp30-hivecast-idempotent-'));
tempDirs.push(root);
const matrixHome = path.join(root, '.matrix');
let exchangeCalls = 0;
await withTokenExchangeServer(
(body) => {
exchangeCalls += 1;
const code = String(body.code ?? '');
if (code === 'FIRST') {
return {
ok: true,
root: 'SPACE-HIVECAST-LAB',
routeKey: 'hivecast-lab',
publicNamespace: 'space.hivecast-lab',
spaceId: 'space_01IDEMPOTENT',
nats: { url: 'wss://hivecast.example.test/nats-ws' },
credentials: { jwt: 'first.jwt.token', seed: 'SUFIRSTIDEMPOTENT' },
};
}
if (code === 'SECOND') {
return {
ok: true,
root: 'SPACE-OTHER-LAB',
routeKey: 'other-lab',
publicNamespace: 'space.other-lab',
spaceId: 'space_01RELINK',
nats: { url: 'wss://hivecast.example.test/nats-ws' },
credentials: { jwt: 'second.jwt.token', seed: 'SUSECONDRELINK' },
};
}
return { ok: false, error: `unexpected code ${code}` };
},
async (cloudUrl) => {
const first = await hiveCastLoginCommand({
cwd: root,
home: matrixHome,
cloudUrl,
setupCode: 'FIRST',
});
assert.equal(first.linked, true);
assert.equal(first.routeKey, 'hivecast-lab');
assert.equal(exchangeCalls, 1);
const alreadyLinked = await hiveCastLoginCommand({
cwd: root,
home: matrixHome,
cloudUrl,
routeKey: 'hivecast-lab',
});
assert.equal(alreadyLinked.linked, true);
assert.equal(alreadyLinked.alreadyLinked, true);
assert.equal(alreadyLinked.routeKey, 'hivecast-lab');
assert.equal(exchangeCalls, 1);
await assert.rejects(
() => hiveCastLoginCommand({
cwd: root,
home: matrixHome,
cloudUrl,
routeKey: 'other-lab',
}),
/HIVECAST_LINK_ROUTE_MISMATCH/,
);
await assert.rejects(
() => hiveCastLoginCommand({
cwd: root,
home: matrixHome,
cloudUrl: 'https://other-hivecast.example.test',
routeKey: 'hivecast-lab',
}),
/HIVECAST_LINK_CLOUD_MISMATCH/,
);
assert.equal(exchangeCalls, 1);
const relinked = await hiveCastLoginCommand({
cwd: root,
home: matrixHome,
cloudUrl,
setupCode: 'SECOND',
forceRelink: true,
});
assert.equal(relinked.linked, true);
assert.equal(relinked.alreadyLinked, undefined);
assert.equal(relinked.routeKey, 'other-lab');
assert.equal(relinked.authorityRoot, 'SPACE-OTHER-LAB');
assert.equal(exchangeCalls, 2);
},
);
});
it('keeps running Host roots converged across HiveCast login, already-linked, relink, and logout', async () => {
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'mx-fp30-hivecast-running-host-'));
tempDirs.push(root);
const matrixHome = path.join(root, '.matrix');
const localOwnerRoot = 'hivecast-proof-local-owner-root';
const hostCredentialsPath = path.join(matrixHome, 'credentials.json');
const credentialPresenceAtReload: boolean[] = [];
await withNatsServer(async (natsUrl) => {
writeLocalOwnerHostStatus(matrixHome, natsUrl, localOwnerRoot);
await withReloadSupervisor(natsUrl, matrixHome, async (reloadCount) => {
await withTokenExchangeServer(
(body) => {
const code = String(body.code ?? '');
if (code === 'RUNNING-HOST') {
return {
ok: true,
root: 'SPACE-HIVECAST-RUNNING',
routeKey: 'hivecast-running',
publicNamespace: 'space.hivecast-running',
spaceId: 'space_01RUNNING',
authorityCoordinator: true,
nats: {
url: 'nats://hivecast.example.test:4222',
},
credentials: {
jwt: 'running.jwt.token',
seed: 'SURUNNINGHOST',
},
};
}
if (code === 'RELINK-HOST') {
return {
ok: true,
root: 'SPACE-HIVECAST-RELINK',
routeKey: 'hivecast-relink',
publicNamespace: 'space.hivecast-relink',
spaceId: 'space_01RELINKHOST',
authorityCoordinator: true,
nats: {
url: 'nats://hivecast.example.test:4222',
},
credentials: {
jwt: 'relink.jwt.token',
seed: 'SURELINKHOST',
},
};
}
return {
ok: false,
error: `unexpected code ${code}`,
};
},
async (cloudUrl) => {
const result = await hiveCastLoginCommand({
cwd: root,
home: matrixHome,
cloudUrl,
setupCode: 'RUNNING-HOST',
});
assert.equal(result.linked, true);
assert.equal(result.authorityCoordinator, true);
const loginReload = result.hostConfigReload;
assert.ok(loginReload);
assert.equal(loginReload.attempted, true);
assert.equal(loginReload.applied, true);
assert.equal(reloadCount(), 1);
assertHostConfigRoot(matrixHome, 'SPACE-HIVECAST-RUNNING', {
routeKey: 'hivecast-running',
publicNamespace: 'space.hivecast-running',
spaceId: 'space_01RUNNING',
});
assertHostStatusRoot(matrixHome, 'SPACE-HIVECAST-RUNNING', {
routeKey: 'hivecast-running',
publicNamespace: 'space.hivecast-running',
spaceId: 'space_01RUNNING',
});
const alreadyLinked = await hiveCastLoginCommand({
cwd: root,
home: matrixHome,
cloudUrl,
routeKey: 'hivecast-running',
});
assert.equal(alreadyLinked.linked, true);
assert.equal(alreadyLinked.alreadyLinked, true);
assert.equal(alreadyLinked.authorityRoot, 'SPACE-HIVECAST-RUNNING');
assert.equal(alreadyLinked.authorityCoordinator, true);
assert.equal(reloadCount(), 2);
assertHostConfigRoot(matrixHome, 'SPACE-HIVECAST-RUNNING', {
routeKey: 'hivecast-running',
publicNamespace: 'space.hivecast-running',
spaceId: 'space_01RUNNING',
});
assertHostStatusRoot(matrixHome, 'SPACE-HIVECAST-RUNNING', {
routeKey: 'hivecast-running',
publicNamespace: 'space.hivecast-running',
spaceId: 'space_01RUNNING',
});
const relinked = await hiveCastLoginCommand({
cwd: root,
home: matrixHome,
cloudUrl,
setupCode: 'RELINK-HOST',
forceRelink: true,
});
assert.equal(relinked.linked, true);
assert.equal(relinked.alreadyLinked, undefined);
assert.equal(relinked.authorityRoot, 'SPACE-HIVECAST-RELINK');
assert.equal(relinked.authorityCoordinator, true);
assert.equal(reloadCount(), 3);
assertHostConfigRoot(matrixHome, 'SPACE-HIVECAST-RELINK', {
routeKey: 'hivecast-relink',
publicNamespace: 'space.hivecast-relink',
spaceId: 'space_01RELINKHOST',
});
assertHostStatusRoot(matrixHome, 'SPACE-HIVECAST-RELINK', {
routeKey: 'hivecast-relink',
publicNamespace: 'space.hivecast-relink',
spaceId: 'space_01RELINKHOST',
});
const logout = await hiveCastLogoutCommand({
cwd: root,
home: matrixHome,
});
assert.equal(logout.removed, true);
const logoutReload = logout.hostConfigReload;
assert.ok(logoutReload);
assert.equal(logoutReload.attempted, true);
assert.equal(logoutReload.applied, true);
assert.equal(reloadCount(), 4);
assertHostConfigRoot(matrixHome, localOwnerRoot);
assertHostStatusRoot(matrixHome, localOwnerRoot);
assert.deepEqual(credentialPresenceAtReload, [true, true, true, true]);
assert.equal(fs.existsSync(hostCredentialsPath), false);
},
);
}, () => {
credentialPresenceAtReload.push(fs.existsSync(hostCredentialsPath));
});
});
});
it('rewrites invalid shared bootstrap root to the install-local root before saving linked Host config', () => {
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'mx-fp30-hivecast-root-repair-'));
tempDirs.push(root);
const matrixHome = path.join(root, '.matrix');
const installId = 'install_root_repair_01';
const expectedLocalRoot = localRootForInstallId(installId);
const invalidSharedRoot = 'hivecast-local-development-platform-topic';
writeInstallIdentity(matrixHome, installId);
fs.writeFileSync(path.join(matrixHome, 'host.json'), `${JSON.stringify({
kind: 'MatrixHostConfig',
version: 1,
home: matrixHome,
transport: {
root: invalidSharedRoot,
authorityRoot: invalidSharedRoot,
addressRoot: invalidSharedRoot,
nats: {
mode: 'external',
url: 'nats://127.0.0.1:48222',
wsUrl: 'ws://127.0.0.1:48223',
port: 48222,
wsPort: 48223,
},
},
}, null, 2)}\n`, 'utf8');
saveHiveCastHostLink({
cwd: root,
matrixHome,
cloudUrl: 'https://hivecast.example.test',
hostId: 'install_root_repair_01',
authorityRoot: 'richard-santomauro-nimbletec-com',
authorityCoordinator: true,
nats: {
url: 'nats://hivecast.example.test:4222',
},
natsCredentials: {
jwt: 'root.repair.jwt',
seed: 'SUROOTREPAIR',
},
hostLinkToken: 'hostlink-root-repair-token',
hostLinkId: 'hostlink_root_repair',
principalId: 'principal_root_repair',
hostName: 'root-repair-device',
});
const linkedConfig = readJsonRecord(path.join(matrixHome, 'host.json'));
const localOwnerTransport = asRecord(linkedConfig.hivecastLocalOwnerTransport);
assert.ok(localOwnerTransport);
assert.equal(localOwnerTransport.root, expectedLocalRoot);
assertHostConfigRoot(matrixHome, 'richard-santomauro-nimbletec-com');
const removed = removeHiveCastHostLink(root, matrixHome);
assert.equal(removed.hostConfigReset, true);
assertHostConfigRoot(matrixHome, expectedLocalRoot);
});
it('refuses linked success when a running Host does not apply linked config', async () => {
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'mx-fp30-hivecast-reload-failure-'));
tempDirs.push(root);
const matrixHome = path.join(root, '.matrix');
await withNatsServer(async (natsUrl) => {
writeLocalOwnerHostStatus(matrixHome, natsUrl, 'hivecast-reload-failure-local-root');
await withTokenExchangeServer(
() => ({
ok: true,
root: 'SPACE-HIVECAST-RELOAD-FAILED',
routeKey: 'hivecast-reload-failed',
publicNamespace: 'space.hivecast-reload-failed',
spaceId: 'space_01RELOADFAILED',
authorityCoordinator: true,
nats: {
url: 'nats://hivecast.example.test:4222',
},
credentials: {
jwt: 'reload-failed.jwt.token',
seed: 'SURELOADFAILED',
},
}),
async (cloudUrl) => {
await assert.rejects(
() => hiveCastLoginCommand({
cwd: root,
home: matrixHome,
cloudUrl,
setupCode: 'RELOAD-FAILED',
}),
/HIVECAST_LINK_HOST_CONFIG_RELOAD_FAILED: running Host did not apply linked config[\s\S]*expectedRoot=SPACE-HIVECAST-RELOAD-FAILED/,
);
},
);
});
});
it('waits for loopback HiveCast pair approval before exchanging the approval code', async () => {
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'mx-fp30-hivecast-wait-'));
tempDirs.push(root);
const matrixHome = path.join(root, '.matrix');
const openedApprovalUrls: string[] = [];
await withNatsServer(async (natsUrl) => {
writeLocalOwnerHostStatus(matrixHome, natsUrl, 'hivecast-loopback-local-owner-root');
await withReloadSupervisor(natsUrl, matrixHome, async (reloadCount) => {
await withPairFlowServer(
{
pairRequestId: 'PAIR-WAIT',
approvalCode: 'APPROVAL-WAIT',
exchange: {
root: 'SPACE-HIVECAST-WAIT',
routeKey: 'hivecast-wait',
publicNamespace: 'space.hivecast-wait',
spaceId: 'space_01WAIT',
authorityCoordinator: true,
nats: {
url: 'nats://hivecast.example.test:4222',
},
credentials: {
jwt: 'wait.jwt.token',
seed: 'SUFAKEWAIT',
},
},
},
async (cloudUrl, controls) => {
const result = await hiveCastLoginCommand({
cwd: root,
home: matrixHome,
cloudUrl,
waitForCallback: true,
noOpen: true,
callbackTimeoutMs: 5_000,
openApprovalUrl: (approvalUrl) => {
openedApprovalUrls.push(approvalUrl);
},
onSetupUrl: (setupUrl) => {
const parsed = new URL(setupUrl);
assert.equal(parsed.origin, cloudUrl);
assert.equal(parsed.pathname, '/_auth/pair/PAIR-WAIT');
const localReturnUrl = controls.getLastLocalReturnUrl();
assert.ok(localReturnUrl);
const startBody = controls.getStartBody();
assert.equal(typeof startBody?.nonce, 'string');
setImmediate(() => {
void fetch(`${localReturnUrl}?pairRequestId=PAIR-WAIT&approvalCode=APPROVAL-WAIT&nonce=${encodeURIComponent(String(startBody?.nonce))}`);
});
},
});
assert.equal(result.linked, true);
assert.equal(result.authorityRoot, 'SPACE-HIVECAST-WAIT');
assert.equal(result.authorityCoordinator, true);
assert.equal(result.routeKey, 'hivecast-wait');
assert.equal(reloadCount(), 1);
assertHostConfigRoot(matrixHome, 'SPACE-HIVECAST-WAIT', {
routeKey: 'hivecast-wait',
publicNamespace: 'space.hivecast-wait',
spaceId: 'space_01WAIT',
});
assertHostStatusRoot(matrixHome, 'SPACE-HIVECAST-WAIT', {
routeKey: 'hivecast-wait',
publicNamespace: 'space.hivecast-wait',
spaceId: 'space_01WAIT',
});
assert.equal(fs.existsSync(path.join(matrixHome, 'credentials', 'hivecast-link.json')), true);
assert.deepEqual(openedApprovalUrls, []);
},
);
});
});
});
it('opens the HiveCast pair approval URL by default during loopback login', async () => {
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'mx-fp30-hivecast-open-'));
tempDirs.push(root);
const matrixHome = path.join(root, '.matrix');
const openedApprovalUrls: string[] = [];
await withPairFlowServer(
{
pairRequestId: 'PAIR-OPEN',
approvalCode: 'APPROVAL-OPEN',
exchange: {
root: 'SPACE-HIVECAST-OPEN',
routeKey: 'hivecast-open',
publicNamespace: 'space.hivecast-open',
nats: {
url: 'wss://hivecast.example.test/nats-ws',
},
credentials: {
jwt: 'open.jwt.token',
seed: 'SUFAKEOPEN',
},
},
},
async (cloudUrl, controls) => {
let announcedSetupUrl = '';
const result = await hiveCastLoginCommand({
cwd: root,
home: matrixHome,
cloudUrl,
waitForCallback: true,
callbackTimeoutMs: 5_000,
openApprovalUrl: (approvalUrl) => {
openedApprovalUrls.push(approvalUrl);
},
onSetupUrl: (setupUrl) => {
announcedSetupUrl = setupUrl;
const localReturnUrl = controls.getLastLocalReturnUrl();
assert.ok(localReturnUrl);
const startBody = controls.getStartBody();
assert.equal(typeof startBody?.nonce, 'string');
setImmediate(() => {
void fetch(`${localReturnUrl}?pairRequestId=PAIR-OPEN&approvalCode=APPROVAL-OPEN&nonce=${encodeURIComponent(String(startBody?.nonce))}`);
});
},
});
assert.equal(result.linked, true);
assert.equal(result.authorityRoot, 'SPACE-HIVECAST-OPEN');
assert.equal(result.routeKey, 'hivecast-open');
assert.deepEqual(openedApprovalUrls, [announcedSetupUrl]);
},
);
});
it('prints the HiveCast pair approval URL without opening a browser when --print-url is used', async () => {
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'mx-fp30-hivecast-print-url-'));
tempDirs.push(root);
const matrixHome = path.join(root, '.matrix');
await withPairFlowServer(
{
pairRequestId: 'PAIR-PRINT',
approvalCode: 'APPROVAL-PRINT',
autoApprove: true,
exchange: {
root: 'SPACE-HIVECAST-PRINT',
routeKey: 'hivecast-print',
publicNamespace: 'space.hivecast-print',
nats: {
url: 'wss://hivecast.example.test/nats-ws',
},
credentials: {
jwt: 'print.jwt.token',
seed: 'SUFAKEPRINT',
},
},
},
async (cloudUrl) => {
const result = await runMxCli([
'node',
'mx',
'login',
'--hivecast',
'--cloud',
cloudUrl,
'--home',
matrixHome,
'--print-url',
], { cwd: root });
assertExitCode(result, 0);
assert.equal(result.logs.includes('Open this URL to approve connecting this device to HiveCast:'), true);
assert.equal(result.logs.includes(`${cloudUrl}/_auth/pair/PAIR-PRINT`), true);
assert.equal(result.logs.some((line) => line.includes('HiveCast device connected: SPACE-HIVECAST-PRINT')), true);
},
);
});
});