6df82818c5
Gate and bound Portal shadow observations while preserving Native execution. Add fail-closed service boundaries, terminal retention controls, Canary readiness telemetry, ops visibility, and isolated regression coverage.
338 lines
12 KiB
JavaScript
338 lines
12 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import test from 'node:test';
|
|
import {
|
|
createOrchestratorAdminConfigService,
|
|
defaultOrchestratorConfig,
|
|
normalizeOrchestratorConfig,
|
|
} from './admin-config.mjs';
|
|
|
|
function createPool() {
|
|
let row = null;
|
|
let createTableCalls = 0;
|
|
return {
|
|
get createTableCalls() {
|
|
return createTableCalls;
|
|
},
|
|
async query(sql, params = []) {
|
|
if (sql.includes('CREATE TABLE')) {
|
|
createTableCalls += 1;
|
|
return [[], []];
|
|
}
|
|
if (sql.includes('SELECT config_json')) return [[...(row ? [row] : [])], []];
|
|
if (sql.includes('INSERT INTO')) {
|
|
row = {
|
|
config_json: params[1],
|
|
config_version: params[2],
|
|
updated_by: params[3],
|
|
updated_at: params[4],
|
|
};
|
|
return [{ affectedRows: 1 }, []];
|
|
}
|
|
throw new Error(`Unexpected SQL: ${sql}`);
|
|
},
|
|
};
|
|
}
|
|
|
|
test('orchestrator config defaults to a disabled native-safe runtime', async () => {
|
|
const service = createOrchestratorAdminConfigService(createPool(), { env: {} });
|
|
const state = await service.getAdminConfig();
|
|
assert.equal(state.config.mode, 'off');
|
|
assert.equal(state.config.primaryEngine, 'langgraph');
|
|
assert.equal(state.runtime.effective, false);
|
|
assert.equal(state.runtime.reason, 'mode_off');
|
|
assert.deepEqual(state.runtime.shadowObservation, {
|
|
requested: false,
|
|
enabled: false,
|
|
reason: 'shadow_observation_not_requested',
|
|
environmentGate: false,
|
|
});
|
|
assert.equal(state.engines.find((engine) => engine.id === 'native').configured, true);
|
|
assert.equal(state.engines.find((engine) => engine.id === 'langgraph').configured, false);
|
|
assert.deepEqual(
|
|
state.executors.map((executor) => executor.id),
|
|
['goosed', 'aider', 'openhands'],
|
|
);
|
|
assert.equal(state.executors.every((executor) => executor.enabled === false), true);
|
|
assert.equal(
|
|
state.executors.every((executor) => executor.dispatchImplemented === true),
|
|
true,
|
|
);
|
|
assert.equal(state.config.executionEnabled, false);
|
|
});
|
|
|
|
test('orchestrator config normalizes unsafe values and keeps a workflow allowlist', () => {
|
|
const normalized = normalizeOrchestratorConfig({
|
|
mode: 'active',
|
|
serviceUrl: 'file:///tmp/graph',
|
|
requestTimeoutMs: 1,
|
|
rolloutPercent: 500,
|
|
workflowAllowlist: ['code-run-v1', 'INVALID WORKFLOW', 'code-run-v1'],
|
|
});
|
|
assert.equal(normalized.serviceUrl, '');
|
|
assert.equal(normalized.requestTimeoutMs, 500);
|
|
assert.equal(normalized.rolloutPercent, 100);
|
|
assert.deepEqual(normalized.workflowAllowlist, ['code-run-v1']);
|
|
assert.equal(
|
|
normalizeOrchestratorConfig({
|
|
serviceUrl: 'https://orchestrator.example/internal?token=secret',
|
|
}).serviceUrl,
|
|
'',
|
|
);
|
|
});
|
|
|
|
test('orchestrator config initializes its schema once per shared pool', async () => {
|
|
const pool = createPool();
|
|
const first = createOrchestratorAdminConfigService(pool, { env: {} });
|
|
const second = createOrchestratorAdminConfigService(pool, { env: {} });
|
|
await first.ensureSchema();
|
|
await first.getRuntimeState();
|
|
await second.getAdminConfig();
|
|
assert.equal(pool.createTableCalls, 1);
|
|
});
|
|
|
|
test('orchestrator blocks non-loopback service origins unless explicitly allowed', async () => {
|
|
const pool = createPool();
|
|
const blockedService = createOrchestratorAdminConfigService(pool, { env: {} });
|
|
const blocked = await blockedService.updateAdminConfig({
|
|
mode: 'shadow',
|
|
serviceUrl: 'https://orchestrator.example',
|
|
});
|
|
assert.equal(blocked.runtime.effective, false);
|
|
assert.equal(blocked.runtime.reason, 'service_url_not_allowed');
|
|
assert.deepEqual(blocked.runtime.shadowObservation, {
|
|
requested: true,
|
|
enabled: false,
|
|
reason: 'service_url_not_allowed',
|
|
environmentGate: false,
|
|
});
|
|
|
|
const allowedService = createOrchestratorAdminConfigService(pool, {
|
|
env: {
|
|
MEMIND_ORCHESTRATOR_ALLOWED_ORIGINS: 'https://orchestrator.example',
|
|
},
|
|
});
|
|
const allowed = await allowedService.getRuntimeState();
|
|
assert.equal(allowed.runtime.effective, true);
|
|
assert.equal(allowed.runtime.reason, null);
|
|
});
|
|
|
|
test('orchestrator config persists versioned admin updates and selects canary users', async () => {
|
|
const service = createOrchestratorAdminConfigService(createPool(), { env: {} });
|
|
const updated = await service.updateAdminConfig({
|
|
...defaultOrchestratorConfig(),
|
|
mode: 'canary',
|
|
serviceUrl: 'http://127.0.0.1:8093',
|
|
rolloutPercent: 0,
|
|
userAllowlist: ['user-1'],
|
|
}, { updatedBy: 'admin-1' });
|
|
assert.equal(updated.configVersion, 1);
|
|
assert.equal(updated.updatedBy, 'admin-1');
|
|
assert.equal(updated.runtime.effective, true);
|
|
|
|
const selected = await service.selectEngine({
|
|
runId: 'run-1',
|
|
userId: 'user-1',
|
|
workflowName: 'code-run-v1',
|
|
});
|
|
assert.equal(selected.engine, 'native');
|
|
assert.equal(selected.candidateEngine, 'langgraph');
|
|
assert.equal(selected.reason, 'execution_gate_disabled');
|
|
assert.equal(selected.candidateReason, 'user_allowlist');
|
|
assert.equal(selected.dryRun, true);
|
|
|
|
const native = await service.selectEngine({
|
|
runId: 'run-2',
|
|
userId: 'user-2',
|
|
workflowName: 'code-run-v1',
|
|
});
|
|
assert.equal(native.engine, 'native');
|
|
assert.equal(native.candidateEngine, 'native');
|
|
assert.equal(native.reason, 'canary_not_selected');
|
|
});
|
|
|
|
test('orchestrator execution handoff remains disabled without both admin and environment gates', async () => {
|
|
const service = createOrchestratorAdminConfigService(createPool(), { env: {} });
|
|
await service.updateAdminConfig({
|
|
mode: 'active',
|
|
serviceUrl: 'http://127.0.0.1:8093',
|
|
});
|
|
|
|
const runtime = await service.getRuntimeState();
|
|
assert.equal(runtime.runtime.plansLangGraph, true);
|
|
assert.equal(runtime.runtime.executesLangGraph, false);
|
|
assert.deepEqual(runtime.runtime.executionHandoff, {
|
|
implemented: true,
|
|
requested: false,
|
|
enabled: false,
|
|
reason: 'environment_execution_gate_disabled',
|
|
environmentGate: false,
|
|
});
|
|
|
|
const selected = await service.selectEngine({
|
|
runId: 'run-1',
|
|
userId: 'user-1',
|
|
workflowName: 'code-run-v1',
|
|
});
|
|
assert.equal(selected.engine, 'native');
|
|
assert.equal(selected.candidateEngine, 'langgraph');
|
|
assert.equal(selected.dryRun, true);
|
|
});
|
|
|
|
test('orchestrator selects LangGraph only when admin and environment execution gates agree', async () => {
|
|
const service = createOrchestratorAdminConfigService(createPool(), {
|
|
env: { MEMIND_ORCHESTRATOR_EXECUTION_HANDOFF_ENABLED: '1' },
|
|
});
|
|
await service.updateAdminConfig({
|
|
mode: 'canary',
|
|
serviceUrl: 'http://127.0.0.1:8093',
|
|
executionEnabled: true,
|
|
userAllowlist: ['user-1'],
|
|
});
|
|
const runtime = await service.getRuntimeState();
|
|
assert.equal(runtime.runtime.executesLangGraph, true);
|
|
assert.equal(runtime.runtime.executionHandoff.environmentGate, true);
|
|
const selected = await service.selectEngine({
|
|
runId: 'run-1',
|
|
userId: 'user-1',
|
|
workflowName: 'code-run-v1',
|
|
});
|
|
assert.equal(selected.engine, 'langgraph');
|
|
assert.equal(selected.candidateEngine, 'langgraph');
|
|
assert.equal(selected.reason, 'user_allowlist');
|
|
assert.equal(selected.dryRun, false);
|
|
});
|
|
|
|
test('orchestrator keeps a Native primary as a non-dry-run Native selection', async () => {
|
|
const service = createOrchestratorAdminConfigService(createPool(), { env: {} });
|
|
await service.updateAdminConfig({
|
|
mode: 'active',
|
|
primaryEngine: 'native',
|
|
});
|
|
|
|
const selected = await service.selectEngine({
|
|
runId: 'run-native',
|
|
workflowName: 'code-run-v1',
|
|
});
|
|
assert.equal(selected.engine, 'native');
|
|
assert.equal(selected.candidateEngine, 'native');
|
|
assert.equal(selected.reason, 'active');
|
|
assert.equal(selected.dryRun, false);
|
|
});
|
|
|
|
test('Shadow mode evaluates the Canary rollout while Native remains effective', async () => {
|
|
const service = createOrchestratorAdminConfigService(createPool(), { env: {} });
|
|
await service.updateAdminConfig({
|
|
mode: 'shadow',
|
|
serviceUrl: 'http://127.0.0.1:8093',
|
|
rolloutPercent: 0,
|
|
userAllowlist: ['user-preview'],
|
|
});
|
|
|
|
const selected = await service.selectEngine({
|
|
runId: 'run-preview-selected',
|
|
userId: 'user-preview',
|
|
workflowName: 'code-run-v1',
|
|
});
|
|
assert.equal(selected.engine, 'native');
|
|
assert.equal(selected.shadowEngine, 'langgraph');
|
|
assert.equal(selected.candidateEngine, 'langgraph');
|
|
assert.equal(selected.candidateReason, 'user_allowlist');
|
|
assert.equal(selected.dryRun, true);
|
|
|
|
const native = await service.selectEngine({
|
|
runId: 'run-preview-native',
|
|
userId: 'user-native',
|
|
workflowName: 'code-run-v1',
|
|
});
|
|
assert.equal(native.engine, 'native');
|
|
assert.equal(native.shadowEngine, 'langgraph');
|
|
assert.equal(native.candidateEngine, 'native');
|
|
assert.equal(native.candidateReason, 'canary_not_selected');
|
|
assert.equal(native.dryRun, true);
|
|
const runtime = await service.getRuntimeState();
|
|
assert.equal(runtime.runtime.shadowsLangGraph, false);
|
|
assert.deepEqual(runtime.runtime.shadowObservation, {
|
|
requested: true,
|
|
enabled: false,
|
|
reason: 'environment_shadow_observation_gate_disabled',
|
|
environmentGate: false,
|
|
});
|
|
});
|
|
|
|
test('Shadow runtime reports the independent Portal observation wiring gate', async () => {
|
|
const service = createOrchestratorAdminConfigService(createPool(), {
|
|
env: { MEMIND_ORCHESTRATOR_SHADOW_OBSERVATION_ENABLED: '1' },
|
|
});
|
|
await service.updateAdminConfig({
|
|
mode: 'shadow',
|
|
serviceUrl: 'http://127.0.0.1:8093',
|
|
});
|
|
const runtime = await service.getRuntimeState();
|
|
assert.equal(runtime.runtime.shadowsLangGraph, true);
|
|
assert.deepEqual(runtime.runtime.shadowObservation, {
|
|
requested: true,
|
|
enabled: true,
|
|
reason: null,
|
|
environmentGate: true,
|
|
});
|
|
});
|
|
|
|
test('orchestrator emergency kill switch always forces native selection', async () => {
|
|
const service = createOrchestratorAdminConfigService(createPool(), {
|
|
env: { MEMIND_ORCHESTRATOR_KILL_SWITCH: '1' },
|
|
});
|
|
await service.updateAdminConfig({
|
|
mode: 'active',
|
|
serviceUrl: 'http://127.0.0.1:8093',
|
|
});
|
|
const selected = await service.selectEngine({
|
|
runId: 'run-1',
|
|
userId: 'user-1',
|
|
workflowName: 'code-run-v1',
|
|
});
|
|
assert.equal(selected.engine, 'native');
|
|
assert.equal(selected.reason, 'kill_switch');
|
|
});
|
|
|
|
test('orchestrator runtime probe reports sanitized service health', async () => {
|
|
let requestedUrl = null;
|
|
const service = createOrchestratorAdminConfigService(createPool(), {
|
|
env: {},
|
|
fetchImpl: async (url) => {
|
|
requestedUrl = url;
|
|
return new Response(JSON.stringify({
|
|
status: 'ok',
|
|
service: 'memind-langgraph-orchestrator',
|
|
checkpoint: { kind: 'postgres', durable: true, password: 'must-not-pass-through' },
|
|
execution: 'observe-only',
|
|
executorGateway: {
|
|
dispatchImplemented: false,
|
|
executionEnabled: false,
|
|
store: { kind: 'postgres', durable: true, password: 'must-not-pass-through' },
|
|
adapters: [{ id: 'goosed', secret: 'must-not-pass-through' }],
|
|
},
|
|
ignoredSecret: 'must-not-pass-through',
|
|
}), {
|
|
status: 200,
|
|
headers: { 'content-type': 'application/json' },
|
|
});
|
|
},
|
|
});
|
|
await service.updateAdminConfig({
|
|
mode: 'shadow',
|
|
serviceUrl: 'http://127.0.0.1:8093',
|
|
});
|
|
|
|
const runtime = await service.getRuntimeState({ probe: true });
|
|
assert.equal(requestedUrl, 'http://127.0.0.1:8093/ready');
|
|
assert.equal(runtime.serviceHealth.ok, true);
|
|
assert.equal(runtime.serviceHealth.details.checkpoint.durable, true);
|
|
assert.deepEqual(runtime.serviceHealth.details.executorGateway, {
|
|
dispatchImplemented: false,
|
|
executionEnabled: false,
|
|
store: { kind: 'postgres', durable: true },
|
|
});
|
|
assert.equal('password' in runtime.serviceHealth.details.checkpoint, false);
|
|
assert.equal('ignoredSecret' in runtime.serviceHealth.details, false);
|
|
});
|