Fix sandbox MCP path resolution for session policy sync.
Resolve mindspace-sandbox-mcp.mjs from the code module location instead of h5Root, and copy it into the portal runtime artifact so goosed can spawn sandbox-fs on production. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+67
-1
@@ -1,5 +1,6 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import fs from 'node:fs';
|
||||
import {
|
||||
buildAgentExtensionPolicy,
|
||||
buildPageEditAgentPolicy,
|
||||
@@ -7,20 +8,30 @@ import {
|
||||
clampUserCapabilities,
|
||||
DEFAULT_USER_CAPABILITIES,
|
||||
normalizeCapabilityPatch,
|
||||
resolveSandboxMcpServerPath,
|
||||
sandboxDeveloperTools,
|
||||
sandboxMcpTools,
|
||||
} from './capabilities.mjs';
|
||||
import { applyPoliciesToCapabilities } from './policies.mjs';
|
||||
|
||||
test('resolveSandboxMcpServerPath resolves to an existing MCP entry file', () => {
|
||||
const serverPath = resolveSandboxMcpServerPath();
|
||||
assert.match(serverPath, /mindspace-sandbox-mcp\.mjs$/);
|
||||
assert.ok(fs.existsSync(serverPath));
|
||||
});
|
||||
|
||||
test('default user policy blocks dangerous capabilities', () => {
|
||||
assert.equal(DEFAULT_USER_CAPABILITIES.shell, false);
|
||||
assert.equal(DEFAULT_USER_CAPABILITIES.filesystem, false);
|
||||
assert.equal(DEFAULT_USER_CAPABILITIES.extension_admin, false);
|
||||
assert.equal(DEFAULT_USER_CAPABILITIES.static_publish, false);
|
||||
assert.equal(DEFAULT_USER_CAPABILITIES.private_data_space, true);
|
||||
assert.equal(DEFAULT_USER_CAPABILITIES.code_browse, false);
|
||||
assert.equal(DEFAULT_USER_CAPABILITIES.memory_store, true);
|
||||
assert.equal(DEFAULT_USER_CAPABILITIES.skills, true);
|
||||
assert.equal(DEFAULT_USER_CAPABILITIES.chat_recall, true);
|
||||
assert.equal(DEFAULT_USER_CAPABILITIES.aider, false);
|
||||
assert.equal(DEFAULT_USER_CAPABILITIES.openhands, false);
|
||||
});
|
||||
|
||||
test('buildAgentExtensionPolicy returns null overrides and auto mode for unrestricted users', () => {
|
||||
@@ -73,6 +84,16 @@ test('buildAgentExtensionPolicy filters developer tools', () => {
|
||||
);
|
||||
});
|
||||
|
||||
test('buildAgentExtensionPolicy includes aider and openhands when granted', () => {
|
||||
const policy = buildAgentExtensionPolicy({
|
||||
...DEFAULT_USER_CAPABILITIES,
|
||||
aider: true,
|
||||
openhands: true,
|
||||
});
|
||||
assert.ok(policy.extensionOverrides.some((ext) => ext.name === 'aider'));
|
||||
assert.ok(policy.extensionOverrides.some((ext) => ext.name === 'openhands'));
|
||||
});
|
||||
|
||||
test('normalizeCapabilityPatch ignores unknown keys', () => {
|
||||
assert.deepEqual(normalizeCapabilityPatch({ shell: true, unknown: true }), { shell: true });
|
||||
});
|
||||
@@ -139,7 +160,19 @@ test('buildPageEditAgentPolicy grants shell for static_publish sandbox users wit
|
||||
|
||||
test('sandboxMcpTools returns correct tool list based on capabilities', () => {
|
||||
const base = { ...DEFAULT_USER_CAPABILITIES, static_publish: true };
|
||||
assert.deepEqual(sandboxMcpTools(base), ['read_file', 'write_file', 'edit_file', 'create_dir']);
|
||||
assert.deepEqual(sandboxMcpTools(base), [
|
||||
'read_file',
|
||||
'write_file',
|
||||
'edit_file',
|
||||
'create_dir',
|
||||
'private_data_info',
|
||||
'private_data_schema',
|
||||
'private_data_query',
|
||||
'private_data_execute',
|
||||
'schedule_create_item',
|
||||
'schedule_create_reminder',
|
||||
'schedule_list_items',
|
||||
]);
|
||||
|
||||
const withBrowse = { ...base, code_browse: true };
|
||||
assert.ok(sandboxMcpTools(withBrowse).includes('list_dir'));
|
||||
@@ -148,6 +181,39 @@ test('sandboxMcpTools returns correct tool list based on capabilities', () => {
|
||||
assert.ok(sandboxMcpTools(withShell).includes('list_dir'));
|
||||
});
|
||||
|
||||
test('private_data_space alone exposes private data tools through sandbox MCP', () => {
|
||||
const caps = { ...DEFAULT_USER_CAPABILITIES, static_publish: false, private_data_space: true };
|
||||
assert.deepEqual(sandboxMcpTools(caps), [
|
||||
'private_data_info',
|
||||
'private_data_schema',
|
||||
'private_data_query',
|
||||
'private_data_execute',
|
||||
'schedule_create_item',
|
||||
'schedule_create_reminder',
|
||||
'schedule_list_items',
|
||||
]);
|
||||
|
||||
const policy = buildAgentExtensionPolicy(caps, {
|
||||
sandboxMcp: {
|
||||
serverPath: '/opt/h5/mindspace-sandbox-mcp.mjs',
|
||||
sandboxRoot: '/opt/h5/MindSpace/user-1',
|
||||
userId: 'user-1',
|
||||
},
|
||||
});
|
||||
const sandboxExt = policy.extensionOverrides.find((ext) => ext.name === 'sandbox-fs');
|
||||
assert.ok(sandboxExt);
|
||||
assert.equal(sandboxExt.envs.PRIVATE_DATA_USER_ID, 'user-1');
|
||||
assert.deepEqual(sandboxExt.available_tools, [
|
||||
'private_data_info',
|
||||
'private_data_schema',
|
||||
'private_data_query',
|
||||
'private_data_execute',
|
||||
'schedule_create_item',
|
||||
'schedule_create_reminder',
|
||||
'schedule_list_items',
|
||||
]);
|
||||
});
|
||||
|
||||
test('static_publish with sandboxMcp uses stdio sandbox-fs extension instead of developer', () => {
|
||||
const caps = { ...DEFAULT_USER_CAPABILITIES, static_publish: true };
|
||||
const sandboxMcp = { serverPath: '/opt/h5/mindspace-sandbox-mcp.mjs', sandboxRoot: '/opt/h5/MindSpace/abc123' };
|
||||
|
||||
Reference in New Issue
Block a user