mindspace: close authority boundaries

This commit is contained in:
john
2026-07-27 15:34:35 +08:00
parent dfab78c75a
commit e94052ff24
78 changed files with 11962 additions and 2162 deletions
+416
View File
@@ -176,6 +176,422 @@ test('sandbox MCP rejects browser storage in generated page code', async (t) =>
assert.doesNotMatch(fs.readFileSync(path.join(root, 'public', 'ledger.html'), 'utf8'), /indexedDB/);
});
test('sandbox MCP delegates scoped workspace tools to MindSpace without local file writes', async (t) => {
const requests = [];
const api = http.createServer((req, res) => {
let body = '';
req.setEncoding('utf8');
req.on('data', (chunk) => {
body += chunk;
});
req.on('end', () => {
const parsedBody = JSON.parse(body);
requests.push({
url: req.url,
authorization:
req.headers.authorization,
body: parsedBody,
});
const tool = req.url.split('/').at(-1);
if (
tool === 'generate_long_image' &&
parsedBody.arguments
?.output_path ===
'public/fail.long.png'
) {
res.statusCode = 503;
res.setHeader(
'content-type',
'application/json',
);
res.end(
JSON.stringify({
ok: false,
code:
'long_image_unavailable',
}),
);
return;
}
const results = {
write_file: {
relativePath: 'public/page.html',
packageId: 'cp_session-1',
sizeBytes: 20,
},
read_file: {
relativePath: 'public/page.html',
packageId: 'cp_session-1',
content: '<html>remote</html>',
},
publish_page: {
relativePath: 'public/page.html',
packageId: 'cp_session-1',
canonicalUrl:
'https://example.com/MindSpace/user-1/public/page.html',
},
generate_long_image: {
relativePath:
'public/page.long.png',
packageId: 'cp_session-1',
sizeBytes: 4096,
canonicalUrl:
'https://example.com/MindSpace/user-1/public/page.long.png',
},
};
res.setHeader(
'content-type',
'application/json',
);
res.end(
JSON.stringify({
ok: true,
result: results[tool] ?? {},
}),
);
});
});
api.listen(0, '127.0.0.1');
await once(api, 'listening');
const root = fs.mkdtempSync(
path.join(
os.tmpdir(),
'mindspace-sandbox-rpc-',
),
);
const sandbox = startSandbox(root, {
ALLOWED_TOOLS:
'read_file,write_file,publish_page,generate_long_image',
MINDSPACE_MCP_BASE_URL:
`http://127.0.0.1:${api.address().port}`,
MINDSPACE_MCP_SCOPED_TOKEN:
'scoped-token',
MINDSPACE_WORKSPACE_REF:
'mindspace://users/user-1/workspace',
MINDSPACE_SESSION_ID: 'session-1',
MINDSPACE_PACKAGE_ID: 'cp_session-1',
});
t.after(() => sandbox.child.kill());
t.after(() => api.close());
await sandbox.request('initialize');
const written = await sandbox.request(
'tools/call',
{
name: 'write_file',
arguments: {
path: 'public/page.html',
content: '<html>remote</html>',
},
},
);
const read = await sandbox.request(
'tools/call',
{
name: 'read_file',
arguments: {
path: 'public/page.html',
},
},
);
const published = await sandbox.request(
'tools/call',
{
name: 'publish_page',
arguments: {
path: 'public/page.html',
},
},
);
const longImage = await sandbox.request(
'tools/call',
{
name: 'generate_long_image',
arguments: {
html_path: 'public/page.html',
output_path:
'public/page.long.png',
},
},
);
const failedLongImage =
await sandbox.request(
'tools/call',
{
name: 'generate_long_image',
arguments: {
html_path:
'public/page.html',
output_path:
'public/fail.long.png',
},
},
);
assert.equal(written.result.isError, false);
assert.match(
written.result.content[0].text,
/package cp_session-1/,
);
assert.equal(
read.result.content[0].text,
'<html>remote</html>',
);
assert.match(
published.result.content[0].text,
/canonicalUrl/,
);
assert.match(
longImage.result.content[0].text,
/page\.long\.png/,
);
assert.equal(
failedLongImage.result.isError,
true,
);
assert.equal(
fs.existsSync(
path.join(root, 'public', 'page.html'),
),
false,
);
assert.equal(
fs.existsSync(
path.join(
root,
'public',
'page.long.png',
),
),
false,
);
assert.equal(
fs.existsSync(
path.join(
root,
'public',
'fail.long.png',
),
),
false,
);
assert.deepEqual(
requests.map((request) => request.url),
[
'/mindspace/v1/mcp/write_file',
'/mindspace/v1/mcp/read_file',
'/mindspace/v1/mcp/publish_page',
'/mindspace/v1/mcp/generate_long_image',
'/mindspace/v1/mcp/generate_long_image',
],
);
assert.ok(
requests.every(
(request) =>
request.authorization ===
'Bearer scoped-token',
),
);
assert.deepEqual(requests[0].body, {
arguments: {
path: 'public/page.html',
content: '<html>remote</html>',
},
});
});
test('generate_docx uploads its binary through scoped MindSpace RPC without writing the target workspace path', async (t) => {
const requests = [];
const api = http.createServer((req, res) => {
let body = '';
req.setEncoding('utf8');
req.on('data', (chunk) => {
body += chunk;
});
req.on('end', () => {
requests.push({
url: req.url,
authorization:
req.headers.authorization,
body: JSON.parse(body),
});
res.setHeader(
'content-type',
'application/json',
);
res.end(
JSON.stringify({
ok: true,
result: {
relativePath:
'public/report.docx',
packageId:
'cp_session-1',
sizeBytes: 1024,
},
}),
);
});
});
api.listen(0, '127.0.0.1');
await once(api, 'listening');
const root = fs.mkdtempSync(
path.join(
os.tmpdir(),
'mindspace-sandbox-docx-rpc-',
),
);
copyDocxGenerateSkill(root);
const sandbox = startSandbox(root, {
ALLOWED_TOOLS: 'generate_docx',
MINDSPACE_MCP_BASE_URL:
`http://127.0.0.1:${api.address().port}`,
MINDSPACE_MCP_SCOPED_TOKEN:
'scoped-token',
MINDSPACE_WORKSPACE_REF:
'mindspace://users/user-1/workspace',
MINDSPACE_SESSION_ID: 'session-1',
MINDSPACE_PACKAGE_ID: 'cp_session-1',
});
t.after(() => sandbox.child.kill());
t.after(() => api.close());
await sandbox.request('initialize');
const generated = await sandbox.request(
'tools/call',
{
name: 'generate_docx',
arguments: {
output_path:
'public/report.docx',
title: 'Scoped report',
sections:
summarySections('Scoped report'),
},
},
);
assert.equal(
generated.result.isError,
false,
generated.result.content?.[0]?.text,
);
assert.equal(
fs.existsSync(
path.join(
root,
'public',
'report.docx',
),
),
false,
);
assert.equal(
requests[0].url,
'/mindspace/v1/mcp/write_binary_file',
);
assert.equal(
requests[0].authorization,
'Bearer scoped-token',
);
assert.equal(
requests[0].body.arguments.path,
'public/report.docx',
);
const uploaded = Buffer.from(
requests[0].body.arguments
.bodyBase64,
'base64',
);
assert.equal(
uploaded.subarray(0, 2).toString(
'utf8',
),
'PK',
);
assert.ok(uploaded.length > 500);
});
test('scoped DOCX generation fails closed when MindSpace rejects the binary write', async (t) => {
const api = http.createServer(
(req, res) => {
req.resume();
req.on('end', () => {
res.statusCode = 503;
res.setHeader(
'content-type',
'application/json',
);
res.end(
JSON.stringify({
ok: false,
code:
'mindspace_unavailable',
}),
);
});
},
);
api.listen(0, '127.0.0.1');
await once(api, 'listening');
const root = fs.mkdtempSync(
path.join(
os.tmpdir(),
'mindspace-sandbox-docx-fail-',
),
);
copyDocxGenerateSkill(root);
const sandbox = startSandbox(root, {
ALLOWED_TOOLS: 'generate_docx',
MINDSPACE_MCP_BASE_URL:
`http://127.0.0.1:${api.address().port}`,
MINDSPACE_MCP_SCOPED_TOKEN:
'scoped-token',
MINDSPACE_WORKSPACE_REF:
'mindspace://users/user-1/workspace',
MINDSPACE_SESSION_ID: 'session-1',
MINDSPACE_PACKAGE_ID: 'cp_session-1',
});
t.after(() => sandbox.child.kill());
t.after(() => api.close());
await sandbox.request('initialize');
const generated = await sandbox.request(
'tools/call',
{
name: 'generate_docx',
arguments: {
output_path:
'public/report.docx',
title: 'Rejected report',
sections:
summarySections(
'Rejected report',
),
},
},
);
assert.equal(
generated.result.isError,
true,
);
assert.match(
generated.result.content[0].text,
/mindspace_unavailable/,
);
assert.equal(
fs.existsSync(
path.join(
root,
'public',
'report.docx',
),
),
false,
);
});
test('sandbox MCP exposes and protects the user private data space', async (t) => {
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'mindspace-sandbox-'));
const server = startSandbox(root);