@vaultcompass/vault-guard-mcp 1.1.0 → 1.1.2

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.
Files changed (3) hide show
  1. package/README.md +3 -0
  2. package/dist/index.js +69 -17
  3. 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.0" : "0.0.0-dev";
90
- function makeScanner() {
91
- const cwd = process.cwd();
89
+ var SERVER_VERSION = true ? "1.1.2" : "0.0.0-dev";
90
+ function loadMcpConfig(workspaceRoot) {
92
91
  let cfg;
93
92
  try {
94
- cfg = (0, import_vault_guard_core2.loadConfig)(cwd);
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 new import_vault_guard_core2.SecretScanner(cfg);
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 scanner = makeScanner();
156
- const dir = import_path2.default.resolve(process.cwd(), root ?? ".");
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(dir, scanner);
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 scanner = makeScanner();
187
- const fp = import_path2.default.resolve(process.cwd(), file_path);
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: process.cwd(), run })),
204
- sarif: (0, import_vault_guard_core2.formatSarif)(results, { cwd: process.cwd(), run })
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 : [process.cwd()];
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
- walkFile(import_path2.default.resolve(process.cwd(), t));
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.0",
3
+ "version": "1.1.2",
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-core": "1.1.0",
30
- "@vaultcompass/vault-guard-telemetry": "1.1.0"
29
+ "@vaultcompass/vault-guard-core": "1.1.2",
30
+ "@vaultcompass/vault-guard-telemetry": "1.1.2"
31
31
  },
32
32
  "devDependencies": {
33
33
  "@types/jest": "^30.0.0",
34
- "@types/node": "^25.9.1",
35
- "esbuild": "^0.25.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"