fix: align DeepSeek canary tool rounds with gate
Memind CI / Test, build, and release guards (pull_request) Successful in 1m32s
Memind CI / Test, build, and release guards (pull_request) Successful in 1m32s
This commit is contained in:
@@ -63,6 +63,16 @@ test('runtime builder materializes and declares required Linux ARM64 native pack
|
||||
assert.match(source, /缺少原生 \.node 文件/);
|
||||
});
|
||||
|
||||
test('runtime builder bundles the DeepSeek compatibility dependency into the artifact', async () => {
|
||||
const source = await fs.readFile(
|
||||
path.join(ROOT, 'scripts', 'build-portal-runtime.mjs'),
|
||||
'utf8',
|
||||
);
|
||||
assert.match(source, /bundleDeepseekCompatProxy/);
|
||||
assert.match(source, /--outfile=\.runtime\/portal\/deepseek-no-think-proxy\.mjs/);
|
||||
assert.match(source, /await bundleDeepseekCompatProxy\(\)/);
|
||||
});
|
||||
|
||||
test('packaged runtime gate isolates persistent roots and rejects artifact mutation', async () => {
|
||||
const localStackSource = await fs.readFile(
|
||||
path.join(ROOT, 'release-gate', 'local-stack.mjs'),
|
||||
@@ -70,7 +80,10 @@ test('packaged runtime gate isolates persistent roots and rejects artifact mutat
|
||||
);
|
||||
assert.match(localStackSource, /MEMIND_PORTAL_H5_ROOT: sandboxRoot/);
|
||||
assert.match(localStackSource, /MEMIND_DEEPSEEK_DISABLE_THINKING: '1'/);
|
||||
assert.match(localStackSource, /deepseek-no-think-proxy\.mjs/);
|
||||
assert.match(
|
||||
localStackSource,
|
||||
/path\.join\(resolvedPortalRoot, 'deepseek-no-think-proxy\.mjs'\)/,
|
||||
);
|
||||
assert.match(localStackSource, /MEMIND_ORCHESTRATOR_MODE: 'shadow'/);
|
||||
assert.match(localStackSource, /MEMIND_ORCHESTRATOR_PAGE_DATA_VALIDATION_GATE_ENABLED: '1'/);
|
||||
assert.match(localStackSource, /H5_USERS_ROOT: usersRoot/);
|
||||
@@ -119,6 +132,9 @@ test('production canary keeps stable 8081 live and switches only after verified
|
||||
const edgeBackup = source.indexOf('Create and verify the active 105 nginx routing backup');
|
||||
const goosedStart = source.indexOf('Start an isolated goosed candidate on 18015');
|
||||
const candidateStart = source.indexOf('Start the passive candidate Portal on 18081');
|
||||
const deepseekCompatStart = source.indexOf(
|
||||
'Start the DeepSeek tool-round compatibility proxy on 18036',
|
||||
);
|
||||
const proxyStart = source.indexOf('Start the fail-closed identity router on 18082');
|
||||
const tunnelStart = source.indexOf('Start the isolated 105 reverse tunnel on 19082');
|
||||
const edgeSwitch = source.indexOf(
|
||||
@@ -129,7 +145,8 @@ test('production canary keeps stable 8081 live and switches only after verified
|
||||
assert.ok(persistBackup > fullBackup);
|
||||
assert.ok(edgeBackup > persistBackup);
|
||||
assert.ok(goosedStart > edgeBackup);
|
||||
assert.ok(candidateStart > goosedStart);
|
||||
assert.ok(deepseekCompatStart > goosedStart);
|
||||
assert.ok(candidateStart > deepseekCompatStart);
|
||||
assert.ok(proxyStart > candidateStart);
|
||||
assert.ok(tunnelStart > proxyStart);
|
||||
assert.ok(edgeSwitch > tunnelStart);
|
||||
@@ -140,6 +157,12 @@ test('production canary keeps stable 8081 live and switches only after verified
|
||||
assert.match(source, /nginx -t/);
|
||||
assert.match(source, /CANARY_PROXY_PORT=18082/);
|
||||
assert.match(source, /CANARY_TUNNEL_REMOTE_PORT=19082/);
|
||||
assert.match(source, /DEEPSEEK_COMPAT_PORT=18036/);
|
||||
assert.match(source, /deepseek-no-think-proxy\.mjs/);
|
||||
assert.match(source, /run-deepseek-compat-proxy-candidate\.sh/);
|
||||
assert.match(source, /MEMIND_CANARY_CANDIDATE_HEALTH_URLS/);
|
||||
assert.match(source, /deepseek_compat_healthy/);
|
||||
assert.match(source, /bootout.*DEEPSEEK_COMPAT_LABEL/);
|
||||
assert.match(
|
||||
source,
|
||||
/edge_ssh\(\) \{\s*#.*\n\s*#.*\n\s*ssh -n -o BatchMode=yes/,
|
||||
@@ -176,6 +199,11 @@ test('candidate runner overrides stable host MCP paths with container-visible pa
|
||||
[
|
||||
'GOOSED_MCP_NODE_PATH=/opt/homebrew/opt/node@24/bin/node',
|
||||
'GOOSED_MCP_SERVER_PATH=/Users/john/Project/Memind/mindspace-sandbox-mcp.mjs',
|
||||
'MEMIND_DEEPSEEK_DISABLE_THINKING=0',
|
||||
'MEMIND_DEEPSEEK_NO_THINK_PORT=9999',
|
||||
'MEMIND_DEEPSEEK_NO_THINK_BASE_URL=http://wrong.invalid/v1',
|
||||
'MEMIND_DEEPSEEK_NO_THINK_HOST=wrong.invalid',
|
||||
'MEMIND_GOOSED_HOST_GATEWAY=wrong.invalid',
|
||||
'',
|
||||
].join('\n'),
|
||||
);
|
||||
@@ -186,6 +214,11 @@ test('candidate runner overrides stable host MCP paths with container-visible pa
|
||||
'printf "cwd=%s\\n" "$PWD"',
|
||||
'printf "mcp_node=%s\\n" "$GOOSED_MCP_NODE_PATH"',
|
||||
'printf "mcp_server=%s\\n" "$GOOSED_MCP_SERVER_PATH"',
|
||||
'printf "deepseek_disable=%s\\n" "$MEMIND_DEEPSEEK_DISABLE_THINKING"',
|
||||
'printf "deepseek_port=%s\\n" "$MEMIND_DEEPSEEK_NO_THINK_PORT"',
|
||||
'printf "deepseek_gateway=%s\\n" "$MEMIND_GOOSED_HOST_GATEWAY"',
|
||||
'printf "deepseek_base=%s\\n" "${MEMIND_DEEPSEEK_NO_THINK_BASE_URL-unset}"',
|
||||
'printf "deepseek_host=%s\\n" "${MEMIND_DEEPSEEK_NO_THINK_HOST-unset}"',
|
||||
'printf "entrypoint=%s\\n" "$1"',
|
||||
'',
|
||||
].join('\n'),
|
||||
@@ -215,9 +248,78 @@ test('candidate runner overrides stable host MCP paths with container-visible pa
|
||||
result.stdout,
|
||||
/^mcp_server=\/opt\/portal\/mindspace-sandbox-mcp\.mjs$/m,
|
||||
);
|
||||
assert.match(result.stdout, /^deepseek_disable=1$/m);
|
||||
assert.match(result.stdout, /^deepseek_port=18036$/m);
|
||||
assert.match(result.stdout, /^deepseek_gateway=host\.docker\.internal$/m);
|
||||
assert.match(result.stdout, /^deepseek_base=unset$/m);
|
||||
assert.match(result.stdout, /^deepseek_host=unset$/m);
|
||||
assert.match(result.stdout, new RegExp(`^entrypoint=${ROOT}/server\\.mjs$`, 'm'));
|
||||
});
|
||||
|
||||
test('canary rollback stops the DeepSeek compatibility process with the other canary services', async () => {
|
||||
const source = await fs.readFile(CANARY_ROLLBACK, 'utf8');
|
||||
assert.match(
|
||||
source,
|
||||
/DEEPSEEK_COMPAT_LABEL="cn\.tkmind\.memind-deepseek-compat-candidate"/,
|
||||
);
|
||||
assert.match(source, /bootout.*DEEPSEEK_COMPAT_LABEL/);
|
||||
assert.match(source, /docker rm -f goosed-prod-canary/);
|
||||
});
|
||||
|
||||
test('DeepSeek compatibility runner preserves stable upstream config but enforces candidate controls', async (t) => {
|
||||
const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'memind-deepseek-runner-'));
|
||||
t.after(() => fs.rm(tempRoot, { recursive: true, force: true }));
|
||||
|
||||
const stableRoot = path.join(tempRoot, 'stable');
|
||||
const fakeNode = path.join(tempRoot, 'node');
|
||||
await fs.mkdir(stableRoot);
|
||||
await fs.writeFile(
|
||||
path.join(stableRoot, '.env'),
|
||||
[
|
||||
'DEEPSEEK_API_BASE_URL=https://synthetic-upstream.invalid/v1',
|
||||
'MEMIND_DEEPSEEK_PROXY_ENTRYPOINT=0',
|
||||
'MEMIND_DEEPSEEK_NO_THINK_PORT=9999',
|
||||
'',
|
||||
].join('\n'),
|
||||
);
|
||||
await fs.writeFile(
|
||||
fakeNode,
|
||||
[
|
||||
'#!/usr/bin/env bash',
|
||||
'printf "proxy_entrypoint=%s\\n" "$MEMIND_DEEPSEEK_PROXY_ENTRYPOINT"',
|
||||
'printf "proxy_port=%s\\n" "$MEMIND_DEEPSEEK_NO_THINK_PORT"',
|
||||
'printf "upstream=%s\\n" "$DEEPSEEK_API_BASE_URL"',
|
||||
'printf "entrypoint=%s\\n" "$1"',
|
||||
'',
|
||||
].join('\n'),
|
||||
{ mode: 0o755 },
|
||||
);
|
||||
|
||||
const result = spawnSync(
|
||||
'bash',
|
||||
[path.join(ROOT, 'scripts', 'run-deepseek-compat-proxy-candidate.sh')],
|
||||
{
|
||||
cwd: '/',
|
||||
encoding: 'utf8',
|
||||
env: {
|
||||
...process.env,
|
||||
MEMIND_CANARY_STABLE_ROOT: stableRoot,
|
||||
MEMIND_CANARY_DEEPSEEK_PROXY_PORT: '18036',
|
||||
NODE_BIN: fakeNode,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
assert.equal(result.status, 0, result.stderr);
|
||||
assert.match(result.stdout, /^proxy_entrypoint=1$/m);
|
||||
assert.match(result.stdout, /^proxy_port=18036$/m);
|
||||
assert.match(result.stdout, /^upstream=https:\/\/synthetic-upstream\.invalid\/v1$/m);
|
||||
assert.match(
|
||||
result.stdout,
|
||||
new RegExp(`^entrypoint=${ROOT}/deepseek-no-think-proxy\\.mjs$`, 'm'),
|
||||
);
|
||||
});
|
||||
|
||||
test('canary release and rollback remote shells remain syntactically valid', async () => {
|
||||
const releaseSource = await fs.readFile(CANARY_RELEASE, 'utf8');
|
||||
const rollbackSource = await fs.readFile(CANARY_ROLLBACK, 'utf8');
|
||||
|
||||
Reference in New Issue
Block a user