@vaultcompass/vault-guard-mcp 1.1.0 → 1.1.1
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/README.md +3 -0
- package/dist/index.js +69 -17
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -29,6 +29,9 @@ Restart the editor. Vault Guard tools are now available to your AI agent.
|
|
|
29
29
|
|
|
30
30
|
## Tools
|
|
31
31
|
|
|
32
|
+
File and directory paths are resolved under the server's `cwd`. Paths outside
|
|
33
|
+
that workspace are rejected.
|
|
34
|
+
|
|
32
35
|
| Tool | Purpose |
|
|
33
36
|
|------|---------|
|
|
34
37
|
| `scan_workspace` | Scan a directory (`.gitignore`-aware). Returns JSON, SARIF, and summary. |
|
package/dist/index.js
CHANGED
|
@@ -59,8 +59,8 @@ var BINARY_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
59
59
|
function isBinaryFile(filePath) {
|
|
60
60
|
return BINARY_EXTENSIONS.has(import_path.default.extname(filePath).toLowerCase());
|
|
61
61
|
}
|
|
62
|
-
async function scanWorkspaceDirectory(root, scanner, concurrency = 10) {
|
|
63
|
-
const files = await (0, import_vault_guard_core.getFilesToScanAsync)(root, false);
|
|
62
|
+
async function scanWorkspaceDirectory(root, scanner, concurrency = 10, configIgnorePatterns2 = []) {
|
|
63
|
+
const files = await (0, import_vault_guard_core.getFilesToScanAsync)(root, false, void 0, configIgnorePatterns2);
|
|
64
64
|
const results = [];
|
|
65
65
|
let filesScanned = 0;
|
|
66
66
|
let bytesScanned = 0;
|
|
@@ -86,12 +86,11 @@ async function scanWorkspaceDirectory(root, scanner, concurrency = 10) {
|
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
// src/server.ts
|
|
89
|
-
var SERVER_VERSION = true ? "1.1.
|
|
90
|
-
function
|
|
91
|
-
const cwd = process.cwd();
|
|
89
|
+
var SERVER_VERSION = true ? "1.1.1" : "0.0.0-dev";
|
|
90
|
+
function loadMcpConfig(workspaceRoot) {
|
|
92
91
|
let cfg;
|
|
93
92
|
try {
|
|
94
|
-
cfg = (0, import_vault_guard_core2.loadConfig)(
|
|
93
|
+
cfg = (0, import_vault_guard_core2.loadConfig)(workspaceRoot);
|
|
95
94
|
} catch (e) {
|
|
96
95
|
if (e instanceof import_vault_guard_core2.ConfigError) {
|
|
97
96
|
process.stderr.write(
|
|
@@ -103,14 +102,48 @@ function makeScanner() {
|
|
|
103
102
|
throw e;
|
|
104
103
|
}
|
|
105
104
|
}
|
|
106
|
-
return
|
|
105
|
+
return cfg;
|
|
106
|
+
}
|
|
107
|
+
function makeScanner(config) {
|
|
108
|
+
return new import_vault_guard_core2.SecretScanner(config);
|
|
107
109
|
}
|
|
108
110
|
function toolPayload(obj) {
|
|
109
111
|
return {
|
|
110
112
|
content: [{ type: "text", text: JSON.stringify(obj, null, 2) }]
|
|
111
113
|
};
|
|
112
114
|
}
|
|
115
|
+
function isPathInside(root, candidate) {
|
|
116
|
+
const rel = import_path2.default.relative(root, candidate);
|
|
117
|
+
return rel === "" || !rel.startsWith("..") && !import_path2.default.isAbsolute(rel);
|
|
118
|
+
}
|
|
119
|
+
function realpathIfExists(p) {
|
|
120
|
+
try {
|
|
121
|
+
return import_fs2.default.realpathSync(p);
|
|
122
|
+
} catch {
|
|
123
|
+
return p;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
function resolveWorkspacePath(workspaceRoot, input) {
|
|
127
|
+
const root = import_path2.default.resolve(workspaceRoot);
|
|
128
|
+
const requested = import_path2.default.resolve(root, input);
|
|
129
|
+
if (!isPathInside(root, requested)) {
|
|
130
|
+
return { ok: false, error: "path_outside_workspace", path: requested };
|
|
131
|
+
}
|
|
132
|
+
const realRoot = realpathIfExists(root);
|
|
133
|
+
const realRequested = realpathIfExists(requested);
|
|
134
|
+
if (!isPathInside(realRoot, realRequested)) {
|
|
135
|
+
return { ok: false, error: "path_outside_workspace", path: requested };
|
|
136
|
+
}
|
|
137
|
+
return { ok: true, path: requested };
|
|
138
|
+
}
|
|
139
|
+
function configIgnorePatterns(config) {
|
|
140
|
+
return [
|
|
141
|
+
...config.ignore?.paths ?? [],
|
|
142
|
+
...config.ignore?.patterns ?? []
|
|
143
|
+
];
|
|
144
|
+
}
|
|
113
145
|
function createMcpServer(options = {}) {
|
|
146
|
+
const workspaceRoot = import_path2.default.resolve(options.workspaceRoot ?? process.cwd());
|
|
114
147
|
const server = new import_mcp.McpServer(
|
|
115
148
|
{ name: "vault-guard", version: SERVER_VERSION },
|
|
116
149
|
{
|
|
@@ -152,10 +185,20 @@ function createMcpServer(options = {}) {
|
|
|
152
185
|
}
|
|
153
186
|
},
|
|
154
187
|
async ({ root }) => {
|
|
155
|
-
const
|
|
156
|
-
const
|
|
188
|
+
const config = loadMcpConfig(workspaceRoot);
|
|
189
|
+
const scanner = makeScanner(config);
|
|
190
|
+
const resolved = resolveWorkspacePath(workspaceRoot, root ?? ".");
|
|
191
|
+
if (!resolved.ok) {
|
|
192
|
+
return toolPayload({ error: resolved.error, path: resolved.path });
|
|
193
|
+
}
|
|
194
|
+
const dir = resolved.path;
|
|
157
195
|
const t0 = Date.now();
|
|
158
|
-
const { results, filesScanned, bytesScanned } = await scanWorkspaceDirectory(
|
|
196
|
+
const { results, filesScanned, bytesScanned } = await scanWorkspaceDirectory(
|
|
197
|
+
dir,
|
|
198
|
+
scanner,
|
|
199
|
+
10,
|
|
200
|
+
configIgnorePatterns(config)
|
|
201
|
+
);
|
|
159
202
|
const run = {
|
|
160
203
|
duration_ms: Date.now() - t0,
|
|
161
204
|
files_scanned: filesScanned,
|
|
@@ -183,8 +226,13 @@ function createMcpServer(options = {}) {
|
|
|
183
226
|
}
|
|
184
227
|
},
|
|
185
228
|
async ({ file_path }) => {
|
|
186
|
-
const
|
|
187
|
-
const
|
|
229
|
+
const config = loadMcpConfig(workspaceRoot);
|
|
230
|
+
const scanner = makeScanner(config);
|
|
231
|
+
const resolved = resolveWorkspacePath(workspaceRoot, file_path);
|
|
232
|
+
if (!resolved.ok) {
|
|
233
|
+
return toolPayload({ error: resolved.error, path: resolved.path });
|
|
234
|
+
}
|
|
235
|
+
const fp = resolved.path;
|
|
188
236
|
if (!import_fs2.default.existsSync(fp) || !import_fs2.default.statSync(fp).isFile()) {
|
|
189
237
|
return toolPayload({ error: "not_a_file", path: fp });
|
|
190
238
|
}
|
|
@@ -200,8 +248,8 @@ function createMcpServer(options = {}) {
|
|
|
200
248
|
const results = matches.length ? [{ file: fp, matches }] : [];
|
|
201
249
|
return toolPayload({
|
|
202
250
|
summary: { files_with_secrets: results.length, total_matches: matches.length },
|
|
203
|
-
json: JSON.parse((0, import_vault_guard_core2.formatJson)(results, { cwd:
|
|
204
|
-
sarif: (0, import_vault_guard_core2.formatSarif)(results, { cwd:
|
|
251
|
+
json: JSON.parse((0, import_vault_guard_core2.formatJson)(results, { cwd: workspaceRoot, run })),
|
|
252
|
+
sarif: (0, import_vault_guard_core2.formatSarif)(results, { cwd: workspaceRoot, run })
|
|
205
253
|
});
|
|
206
254
|
}
|
|
207
255
|
);
|
|
@@ -216,7 +264,7 @@ function createMcpServer(options = {}) {
|
|
|
216
264
|
}
|
|
217
265
|
},
|
|
218
266
|
async ({ text, virtual_path }) => {
|
|
219
|
-
const scanner = makeScanner();
|
|
267
|
+
const scanner = makeScanner(loadMcpConfig(workspaceRoot));
|
|
220
268
|
const t0 = Date.now();
|
|
221
269
|
const matches = scanner.scanContent(text);
|
|
222
270
|
const label = virtual_path ?? "inline://snippet";
|
|
@@ -246,7 +294,7 @@ function createMcpServer(options = {}) {
|
|
|
246
294
|
}
|
|
247
295
|
},
|
|
248
296
|
async ({ paths }) => {
|
|
249
|
-
const targets = paths && paths.length > 0 ? paths : [
|
|
297
|
+
const targets = paths && paths.length > 0 ? paths : ["."];
|
|
250
298
|
let total = 0;
|
|
251
299
|
const breakdown = {};
|
|
252
300
|
const walkFile = (file) => {
|
|
@@ -269,7 +317,11 @@ function createMcpServer(options = {}) {
|
|
|
269
317
|
}
|
|
270
318
|
};
|
|
271
319
|
for (const t of targets) {
|
|
272
|
-
|
|
320
|
+
const resolved = resolveWorkspacePath(workspaceRoot, t);
|
|
321
|
+
if (!resolved.ok) {
|
|
322
|
+
return toolPayload({ error: resolved.error, path: resolved.path });
|
|
323
|
+
}
|
|
324
|
+
walkFile(resolved.path);
|
|
273
325
|
}
|
|
274
326
|
const estCostAnthropic = tokenCounter.calculateCost("anthropic", total, 0);
|
|
275
327
|
return toolPayload({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vaultcompass/vault-guard-mcp",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "Let Cursor and Claude scan AI-proposed edits for secrets before applying. Local MCP server.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -26,13 +26,13 @@
|
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
28
28
|
"zod": "^4.4.3",
|
|
29
|
-
"@vaultcompass/vault-guard-
|
|
30
|
-
"@vaultcompass/vault-guard-
|
|
29
|
+
"@vaultcompass/vault-guard-telemetry": "1.1.1",
|
|
30
|
+
"@vaultcompass/vault-guard-core": "1.1.1"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@types/jest": "^30.0.0",
|
|
34
|
-
"@types/node": "^25.9.
|
|
35
|
-
"esbuild": "^0.
|
|
34
|
+
"@types/node": "^25.9.3",
|
|
35
|
+
"esbuild": "^0.28.1",
|
|
36
36
|
"jest": "^30.4.2",
|
|
37
37
|
"ts-jest": "^29.4.11",
|
|
38
38
|
"typescript": "^5.3.3"
|