d67ebb0c77
Memind CI / Test, build, and release guards (pull_request) Waiting to run
Gate stacks inherited developer MCP env and routed sandbox-fs writes to the 8082 workspace root, so PAGE/DATA scenarios failed with ENOENT despite a healthy goosed. Sanitize isolated portal env, grant gate skills, and align CHAT search assertions with the tkmind_search tool name. Co-authored-by: Cursor <cursoragent@cursor.com>
84 lines
3.2 KiB
JavaScript
84 lines
3.2 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import net from 'node:net';
|
|
import test from 'node:test';
|
|
|
|
import {
|
|
assertGatePortAvailable,
|
|
buildContainerPgConnectionString,
|
|
buildPgConnectionString,
|
|
makeIsolatedDatabaseName,
|
|
sanitizeIsolatedGatePortalEnv,
|
|
} from './local-stack.mjs';
|
|
|
|
test('isolated database names are bounded and identifier-safe', () => {
|
|
const name = makeIsolatedDatabaseName('Gate 2026-07-26 / ABC', 'memind_gate');
|
|
assert.equal(name, 'memind_gate_gate_2026_07_26_abc');
|
|
assert.match(name, /^[a-z][a-z0-9_]+$/);
|
|
assert.ok(name.length <= 63);
|
|
});
|
|
|
|
test('PostgreSQL Unix socket DSN is preserved while database is isolated', () => {
|
|
const dsn = buildPgConnectionString(
|
|
'postgresql://gate:secret@localhost/base?host=%2Ftmp&port=5433',
|
|
'mindspace_gate_abc',
|
|
);
|
|
const parsed = new URL(dsn);
|
|
assert.equal(parsed.pathname, '/mindspace_gate_abc');
|
|
assert.equal(parsed.searchParams.get('host'), '/tmp');
|
|
assert.equal(parsed.searchParams.get('port'), '5433');
|
|
});
|
|
|
|
test('container PostgreSQL DSN keeps credentials and host while isolating database', () => {
|
|
const dsn = buildContainerPgConnectionString(
|
|
'postgresql://john:secret@host.docker.internal:5433/mindspace_userdata_dev',
|
|
'mindspace_gate_abc',
|
|
);
|
|
const parsed = new URL(dsn);
|
|
assert.equal(parsed.hostname, 'host.docker.internal');
|
|
assert.equal(parsed.port, '5433');
|
|
assert.equal(parsed.username, 'john');
|
|
assert.equal(parsed.password, 'secret');
|
|
assert.equal(parsed.pathname, '/mindspace_gate_abc');
|
|
});
|
|
|
|
test('isolated database names reject empty or unsafe prefixes', () => {
|
|
assert.throws(() => makeIsolatedDatabaseName('abc', '../bad'), /Unsafe/);
|
|
});
|
|
|
|
test('sanitizeIsolatedGatePortalEnv drops split-service MCP routing', () => {
|
|
const sanitized = sanitizeIsolatedGatePortalEnv({
|
|
MINDSPACE_SERVER_ADAPTER: 'remote',
|
|
MINDSPACE_REMOTE_BASE_URL: 'http://127.0.0.1:8082',
|
|
MINDSPACE_REMOTE_AUTH_TOKEN: 'local-dev-secret',
|
|
MINDSPACE_MCP_BASE_URL: 'http://127.0.0.1:8082',
|
|
MINDSPACE_MCP_TOKEN_SECRET: 'local-dev-secret',
|
|
MINDSPACE_AGENT_API_BASE_URL: 'http://127.0.0.1:8081/api',
|
|
}, { port: 19087, runtimeProfile: 'local' });
|
|
|
|
assert.equal(sanitized.MINDSPACE_SERVER_ADAPTER, 'local');
|
|
assert.equal(sanitized.MEMIND_RUNTIME_PROFILE, 'local');
|
|
assert.equal(sanitized.H5_PORTAL_BASE_URL, 'http://127.0.0.1:19087');
|
|
assert.equal(sanitized.MINDSPACE_AGENT_API_BASE_URL, 'http://127.0.0.1:19087/api');
|
|
assert.equal(sanitized.MINDSPACE_REMOTE_BASE_URL, undefined);
|
|
assert.equal(sanitized.MINDSPACE_MCP_BASE_URL, undefined);
|
|
assert.equal(sanitized.MINDSPACE_MCP_TOKEN_SECRET, undefined);
|
|
});
|
|
|
|
test('assertGatePortAvailable rejects occupied loopback ports', async () => {
|
|
const server = net.createServer();
|
|
await new Promise((resolve, reject) => {
|
|
server.once('error', reject);
|
|
server.listen(0, '127.0.0.1', resolve);
|
|
});
|
|
const address = server.address();
|
|
assert.ok(address && typeof address === 'object');
|
|
await assert.rejects(
|
|
() => assertGatePortAvailable(address.port),
|
|
/already in use/,
|
|
);
|
|
await new Promise((resolve, reject) => {
|
|
server.close((error) => (error ? reject(error) : resolve()));
|
|
});
|
|
await assertGatePortAvailable(address.port);
|
|
});
|