@saiteja1123/mcp-server 1.1.3 → 1.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +59 -54
- package/src/api-scan.mjs +362 -93
- package/src/cli.js +713 -322
- package/src/deep-scan/contracts.js +201 -0
- package/src/deep-scan/deterministic-scan.js +337 -0
- package/src/deep-scan/index.js +109 -0
- package/src/deep-scan/project-map.js +507 -0
- package/src/deep-scan/ralph-accept.js +510 -0
- package/src/deep-scan/ralph-compare.js +498 -0
- package/src/deep-scan/ralph-tasks.js +598 -0
- package/src/deep-scan/ralph-track.js +548 -0
- package/src/deep-scan/registry.js +159 -0
- package/src/deep-scan/runtime.js +275 -0
- package/src/deep-scan/sample-steppers.js +128 -0
- package/src/deep-scan/sourceSafe.js +73 -0
- package/src/deep-scan/status.js +70 -0
- package/src/deep-scan/store.js +57 -0
- package/src/deep-scan/test-plan.js +760 -0
- package/src/index.js +6 -6
- package/src/lock.mjs +55 -14
- package/src/middleware/governance.js +135 -0
- package/src/orchestrator/runScan.js +211 -0
- package/src/project-bindings.mjs +215 -0
- package/src/rule-engine/index.js +3 -2
- package/src/rule-engine/localScan.js +41 -12
- package/src/rule-engine/metadata.js +20 -0
- package/src/rule-engine/prompt.js +6 -5
- package/src/rule-engine/rules.js +71 -43
- package/src/rule-engine/score.js +5 -4
- package/src/security/pathGuard.js +170 -0
- package/src/selftest.js +2473 -0
- package/src/server.js +161 -145
- package/src/tools/deepScan.js +286 -0
- package/src/tools/localScan.js +85 -0
- package/src/tools/projects.js +124 -0
- package/src/tools/scanFile.js +131 -0
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
|
|
3
|
+
import { verifyInstallBinding } from '../api-scan.mjs';
|
|
4
|
+
import { isRuntimeCompatibleLock, validateScanPath } from '../lock.mjs';
|
|
5
|
+
import { resolveBindingForScanPath } from '../project-bindings.mjs';
|
|
6
|
+
|
|
7
|
+
export function createBindingGuard({
|
|
8
|
+
boundRoot,
|
|
9
|
+
installToken,
|
|
10
|
+
authToken,
|
|
11
|
+
apiBase,
|
|
12
|
+
universalMode = false,
|
|
13
|
+
normalizePath = (requestedPath) => path.resolve(requestedPath),
|
|
14
|
+
validateScanPathImpl = validateScanPath,
|
|
15
|
+
isRuntimeCompatibleLockImpl = isRuntimeCompatibleLock,
|
|
16
|
+
verifyInstallBindingImpl = verifyInstallBinding,
|
|
17
|
+
resolveBindingForScanPathImpl = resolveBindingForScanPath,
|
|
18
|
+
debugLog = () => {},
|
|
19
|
+
} = {}) {
|
|
20
|
+
const resolvedBoundRoot = boundRoot ? path.resolve(boundRoot) : null;
|
|
21
|
+
const isUniversal = universalMode || (!!authToken && !resolvedBoundRoot);
|
|
22
|
+
|
|
23
|
+
async function ensureLegacyServerBinding(lockedRootHash, activeInstallToken) {
|
|
24
|
+
const verify = await verifyInstallBindingImpl({
|
|
25
|
+
installToken: activeInstallToken,
|
|
26
|
+
lockedRootHash,
|
|
27
|
+
apiBase,
|
|
28
|
+
});
|
|
29
|
+
if (!verify.ok || !verify.json?.success) {
|
|
30
|
+
return {
|
|
31
|
+
ok: false,
|
|
32
|
+
httpStatus: verify.status || 403,
|
|
33
|
+
code: verify.json?.code || 'SERVER_BINDING_INVALID',
|
|
34
|
+
message: verify.json?.error || verify.error || 'Unable to verify server-issued MCP binding.',
|
|
35
|
+
rebindHint: `vibesecur-mcp rebind ${resolvedBoundRoot}`,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
return { ok: true };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async function guardLegacy(requestedPath) {
|
|
42
|
+
const target = normalizePath(requestedPath);
|
|
43
|
+
debugLog('guardPath legacy', { requestedPath, normalizedTarget: target, resolvedBoundRoot });
|
|
44
|
+
|
|
45
|
+
if (!resolvedBoundRoot || !installToken) {
|
|
46
|
+
return {
|
|
47
|
+
ok: false,
|
|
48
|
+
httpStatus: 403,
|
|
49
|
+
code: 'BINDING_REQUIRED',
|
|
50
|
+
message:
|
|
51
|
+
'Missing MCP binding env. Use a universal config (VIBESECUR_AUTH_TOKEN) or bind one folder ' +
|
|
52
|
+
'with VIBESECUR_INSTALL_TOKEN + VIBESECUR_BOUND_ROOT.',
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (!target.startsWith(resolvedBoundRoot + path.sep) && target !== resolvedBoundRoot) {
|
|
57
|
+
return {
|
|
58
|
+
ok: false,
|
|
59
|
+
httpStatus: 403,
|
|
60
|
+
code: 'OUT_OF_FOLDER',
|
|
61
|
+
message:
|
|
62
|
+
`Path "${target}" is outside the locked project folder "${resolvedBoundRoot}". ` +
|
|
63
|
+
'Use a universal MCP config to manage multiple projects, or rebind to this folder.',
|
|
64
|
+
rebindHint: `vibesecur-mcp rebind ${target}`,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const result = await validateScanPathImpl(target, installToken);
|
|
69
|
+
if (!result.ok) return result;
|
|
70
|
+
if (!isRuntimeCompatibleLockImpl(result.lock)) {
|
|
71
|
+
return {
|
|
72
|
+
ok: false,
|
|
73
|
+
httpStatus: 403,
|
|
74
|
+
code: 'LOCAL_LOCK_NOT_RUNTIME_BINDING',
|
|
75
|
+
message:
|
|
76
|
+
'Local diagnostic lock found; runtime scans require a server-issued binding. ' +
|
|
77
|
+
'Run projectUpsert or vibesecur-mcp bind with VIBESECUR_AUTH_TOKEN set.',
|
|
78
|
+
rebindHint: `vibesecur-mcp bind ${result.boundRoot}`,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const lockedRootHash = result.lockedRootHash || result.lock?.lockedRootHash || result.lock?.rootHash;
|
|
83
|
+
const verify = await ensureLegacyServerBinding(lockedRootHash, installToken);
|
|
84
|
+
if (!verify.ok) return verify;
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
ok: true,
|
|
88
|
+
resolvedRoot: target,
|
|
89
|
+
projectRoot: resolvedBoundRoot,
|
|
90
|
+
installToken,
|
|
91
|
+
lock: result.lock,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
async function guardUniversal(requestedPath) {
|
|
96
|
+
const target = normalizePath(requestedPath);
|
|
97
|
+
debugLog('guardPath universal', { requestedPath, normalizedTarget: target });
|
|
98
|
+
|
|
99
|
+
if (!authToken) {
|
|
100
|
+
return {
|
|
101
|
+
ok: false,
|
|
102
|
+
httpStatus: 403,
|
|
103
|
+
code: 'AUTH_REQUIRED',
|
|
104
|
+
message:
|
|
105
|
+
'Universal MCP mode requires VIBESECUR_AUTH_TOKEN. ' +
|
|
106
|
+
'Generate config from the dashboard or set your login JWT in MCP env.',
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const binding = await resolveBindingForScanPathImpl({
|
|
111
|
+
requestedPath: target,
|
|
112
|
+
authToken,
|
|
113
|
+
apiBase,
|
|
114
|
+
autoUpsert: true,
|
|
115
|
+
});
|
|
116
|
+
if (!binding.ok) {
|
|
117
|
+
return {
|
|
118
|
+
ok: false,
|
|
119
|
+
httpStatus: 403,
|
|
120
|
+
code: binding.code || 'PROJECT_BINDING_FAILED',
|
|
121
|
+
message: binding.message || 'Unable to resolve project binding for this path.',
|
|
122
|
+
rebindHint: 'projectUpsert rootPath="<codebase-folder>"',
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const projectRoot = path.resolve(binding.projectRoot);
|
|
127
|
+
if (!target.startsWith(projectRoot + path.sep) && target !== projectRoot) {
|
|
128
|
+
return {
|
|
129
|
+
ok: false,
|
|
130
|
+
httpStatus: 403,
|
|
131
|
+
code: 'OUT_OF_FOLDER',
|
|
132
|
+
message: `Path "${target}" is outside registered project "${projectRoot}".`,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const lockCheck = await validateScanPathImpl(target, binding.installToken);
|
|
137
|
+
if (!lockCheck.ok) return lockCheck;
|
|
138
|
+
|
|
139
|
+
return {
|
|
140
|
+
ok: true,
|
|
141
|
+
resolvedRoot: target,
|
|
142
|
+
projectRoot,
|
|
143
|
+
installToken: binding.installToken,
|
|
144
|
+
lockedRootHash: binding.lockedRootHash,
|
|
145
|
+
projectHash: binding.projectHash,
|
|
146
|
+
projectId: binding.projectId,
|
|
147
|
+
lock: binding.lock || lockCheck.lock,
|
|
148
|
+
mode: 'universal',
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return async function guardPath(requestedPath) {
|
|
153
|
+
if (isUniversal) return guardUniversal(requestedPath);
|
|
154
|
+
return guardLegacy(requestedPath);
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export function formatGuardError(guard) {
|
|
159
|
+
const status = guard.httpStatus ? ` (${guard.httpStatus})` : '';
|
|
160
|
+
const text = JSON.stringify({
|
|
161
|
+
error: guard.code || 'SCAN_BLOCKED',
|
|
162
|
+
message: guard.message,
|
|
163
|
+
rebindHint: guard.rebindHint || null,
|
|
164
|
+
docs: 'https://vibesecur.com/docs/mcp-setup',
|
|
165
|
+
}, null, 2);
|
|
166
|
+
return {
|
|
167
|
+
content: [{ type: 'text', text: `Security Lock Error${status}:\n${text}` }],
|
|
168
|
+
isError: true,
|
|
169
|
+
};
|
|
170
|
+
}
|