mindspace: close authority boundaries
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import {
|
||||
mintMindSpaceMcpScopedToken,
|
||||
verifyMindSpaceMcpScopedToken,
|
||||
} from './mindspace-mcp-scoped-token.mjs';
|
||||
|
||||
const secret = 'mindspace-test-secret-1234';
|
||||
|
||||
test('MindSpace MCP token binds user, session, package, workspace, and tools', () => {
|
||||
const token = mintMindSpaceMcpScopedToken({
|
||||
secret,
|
||||
userId: 'user-1',
|
||||
sessionId: 'session-1',
|
||||
packageId: 'cp_session-1',
|
||||
workspaceRef:
|
||||
'mindspace://users/user-1/workspace',
|
||||
tools: ['write_file', 'read_file'],
|
||||
now: 1_000_000,
|
||||
tokenId: 'token-1',
|
||||
});
|
||||
|
||||
const claims = verifyMindSpaceMcpScopedToken({
|
||||
token,
|
||||
secret,
|
||||
tool: 'write_file',
|
||||
now: 1_001_000,
|
||||
});
|
||||
|
||||
assert.deepEqual(claims, {
|
||||
userId: 'user-1',
|
||||
sessionId: 'session-1',
|
||||
packageId: 'cp_session-1',
|
||||
workspaceRef:
|
||||
'mindspace://users/user-1/workspace',
|
||||
tools: ['read_file', 'write_file'],
|
||||
issuedAt: 1_000_000,
|
||||
expiresAt: 1_900_000,
|
||||
tokenId: 'token-1',
|
||||
});
|
||||
});
|
||||
|
||||
test('MindSpace MCP token rejects tampering, expiry, and tools outside the allowlist', () => {
|
||||
const token = mintMindSpaceMcpScopedToken({
|
||||
secret,
|
||||
userId: 'user-1',
|
||||
sessionId: 'session-1',
|
||||
packageId: 'cp_session-1',
|
||||
workspaceRef:
|
||||
'mindspace://users/user-1/workspace',
|
||||
tools: ['read_file'],
|
||||
ttlSeconds: 60,
|
||||
now: 1_000_000,
|
||||
tokenId: 'token-1',
|
||||
});
|
||||
|
||||
assert.throws(
|
||||
() =>
|
||||
verifyMindSpaceMcpScopedToken({
|
||||
token: `${token}x`,
|
||||
secret,
|
||||
now: 1_001_000,
|
||||
}),
|
||||
/signature/,
|
||||
);
|
||||
assert.throws(
|
||||
() =>
|
||||
verifyMindSpaceMcpScopedToken({
|
||||
token,
|
||||
secret,
|
||||
tool: 'write_file',
|
||||
now: 1_001_000,
|
||||
}),
|
||||
(error) =>
|
||||
error?.code === 'mcp_tool_forbidden',
|
||||
);
|
||||
assert.throws(
|
||||
() =>
|
||||
verifyMindSpaceMcpScopedToken({
|
||||
token,
|
||||
secret,
|
||||
now: 2_000_000,
|
||||
clockSkewSeconds: 0,
|
||||
}),
|
||||
(error) =>
|
||||
error?.code === 'expired_mcp_token',
|
||||
);
|
||||
});
|
||||
|
||||
test('MindSpace MCP token refuses incomplete scopes and weak secrets', () => {
|
||||
assert.throws(
|
||||
() =>
|
||||
mintMindSpaceMcpScopedToken({
|
||||
secret: 'short',
|
||||
userId: 'user-1',
|
||||
sessionId: 'session-1',
|
||||
packageId: 'cp_session-1',
|
||||
workspaceRef:
|
||||
'mindspace://users/user-1/workspace',
|
||||
tools: ['read_file'],
|
||||
}),
|
||||
(error) =>
|
||||
error?.code ===
|
||||
'invalid_mcp_token_secret',
|
||||
);
|
||||
assert.throws(
|
||||
() =>
|
||||
mintMindSpaceMcpScopedToken({
|
||||
secret,
|
||||
userId: 'user-1',
|
||||
sessionId: 'session-1',
|
||||
packageId: 'cp_session-1',
|
||||
workspaceRef:
|
||||
'mindspace://users/user-1/workspace',
|
||||
tools: [],
|
||||
}),
|
||||
(error) =>
|
||||
error?.code === 'invalid_mcp_scope',
|
||||
);
|
||||
});
|
||||
Reference in New Issue
Block a user