@cybedefend/vibedefend 1.5.0 → 1.6.0

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 (246) hide show
  1. package/README.md +67 -2
  2. package/dist/api/gateway-request.js +49 -0
  3. package/dist/api/gateway-request.js.map +1 -0
  4. package/dist/api/projects.js +67 -0
  5. package/dist/api/projects.js.map +1 -1
  6. package/dist/api/repository-link.js +157 -0
  7. package/dist/api/repository-link.js.map +1 -0
  8. package/dist/auth/auth-store.js +107 -25
  9. package/dist/auth/auth-store.js.map +1 -1
  10. package/dist/auth/auth.js +21 -0
  11. package/dist/auth/auth.js.map +1 -1
  12. package/dist/clients/cursor.js +5 -1
  13. package/dist/clients/cursor.js.map +1 -1
  14. package/dist/clients/vscode.js +38 -29
  15. package/dist/clients/vscode.js.map +1 -1
  16. package/dist/commands/mcp/allow.js +219 -0
  17. package/dist/commands/mcp/allow.js.map +1 -0
  18. package/dist/commands/mcp/connect.js +337 -0
  19. package/dist/commands/mcp/connect.js.map +1 -0
  20. package/dist/commands/mcp/index.js +170 -0
  21. package/dist/commands/mcp/index.js.map +1 -0
  22. package/dist/commands/mcp/proxy.js +264 -0
  23. package/dist/commands/mcp/proxy.js.map +1 -0
  24. package/dist/commands/mcp/scan.js +349 -0
  25. package/dist/commands/mcp/scan.js.map +1 -0
  26. package/dist/commands/mcp/sync.js +215 -0
  27. package/dist/commands/mcp/sync.js.map +1 -0
  28. package/dist/config.js +6 -0
  29. package/dist/config.js.map +1 -1
  30. package/dist/diagnostics.js +78 -12
  31. package/dist/diagnostics.js.map +1 -1
  32. package/dist/doctor.js +19 -0
  33. package/dist/doctor.js.map +1 -1
  34. package/dist/guards-evaluator/analysis-types.js +27 -0
  35. package/dist/guards-evaluator/analysis-types.js.map +1 -0
  36. package/dist/guards-evaluator/command-analysis.js +572 -0
  37. package/dist/guards-evaluator/command-analysis.js.map +1 -0
  38. package/dist/guards-evaluator/command-view.js +586 -0
  39. package/dist/guards-evaluator/command-view.js.map +1 -0
  40. package/dist/guards-evaluator/env.js +11 -0
  41. package/dist/guards-evaluator/env.js.map +1 -0
  42. package/dist/guards-evaluator/evaluate.js +91 -41
  43. package/dist/guards-evaluator/evaluate.js.map +1 -1
  44. package/dist/guards-evaluator/index.js +2 -1
  45. package/dist/guards-evaluator/index.js.map +1 -1
  46. package/dist/guards-evaluator/inline-code.js +259 -0
  47. package/dist/guards-evaluator/inline-code.js.map +1 -0
  48. package/dist/guards-evaluator/normalize.js +716 -0
  49. package/dist/guards-evaluator/normalize.js.map +1 -0
  50. package/dist/guards-evaluator/preprocess.js +13 -5
  51. package/dist/guards-evaluator/preprocess.js.map +1 -1
  52. package/dist/guards-evaluator/redact.js +19 -0
  53. package/dist/guards-evaluator/redact.js.map +1 -1
  54. package/dist/guards-evaluator/regex.js +25 -3
  55. package/dist/guards-evaluator/regex.js.map +1 -1
  56. package/dist/guards-evaluator/safe-commands.js +155 -0
  57. package/dist/guards-evaluator/safe-commands.js.map +1 -0
  58. package/dist/guards-evaluator/triage.js +315 -0
  59. package/dist/guards-evaluator/triage.js.map +1 -0
  60. package/dist/hook-runner.js +24679 -5079
  61. package/dist/hooks/install.js +38 -0
  62. package/dist/hooks/install.js.map +1 -1
  63. package/dist/hooks/runtime/config.js +38 -0
  64. package/dist/hooks/runtime/config.js.map +1 -1
  65. package/dist/hooks/runtime/emit.js +94 -61
  66. package/dist/hooks/runtime/emit.js.map +1 -1
  67. package/dist/hooks/runtime/fetch-rules.js +22 -7
  68. package/dist/hooks/runtime/fetch-rules.js.map +1 -1
  69. package/dist/hooks/runtime/gateway-http-error.js +34 -0
  70. package/dist/hooks/runtime/gateway-http-error.js.map +1 -0
  71. package/dist/hooks/runtime/guard-rules-cache.js +139 -17
  72. package/dist/hooks/runtime/guard-rules-cache.js.map +1 -1
  73. package/dist/hooks/runtime/guard-violations-buffer.js +321 -48
  74. package/dist/hooks/runtime/guard-violations-buffer.js.map +1 -1
  75. package/dist/hooks/runtime/judge-cache.js +6 -0
  76. package/dist/hooks/runtime/judge-cache.js.map +1 -1
  77. package/dist/hooks/runtime/judge-triage.js +193 -0
  78. package/dist/hooks/runtime/judge-triage.js.map +1 -0
  79. package/dist/hooks/runtime/judge.js +7 -1
  80. package/dist/hooks/runtime/judge.js.map +1 -1
  81. package/dist/hooks/runtime/pre-compact.js +12 -6
  82. package/dist/hooks/runtime/pre-compact.js.map +1 -1
  83. package/dist/hooks/runtime/resolve.js +90 -8
  84. package/dist/hooks/runtime/resolve.js.map +1 -1
  85. package/dist/hooks/runtime/retry-policy.js +57 -0
  86. package/dist/hooks/runtime/retry-policy.js.map +1 -0
  87. package/dist/hooks/runtime/review-sessions.js +74 -0
  88. package/dist/hooks/runtime/review-sessions.js.map +1 -0
  89. package/dist/hooks/runtime/script-resolve.js +695 -0
  90. package/dist/hooks/runtime/script-resolve.js.map +1 -0
  91. package/dist/hooks/runtime/session-activation.js +5 -1
  92. package/dist/hooks/runtime/session-activation.js.map +1 -1
  93. package/dist/hooks/runtime/session-review.js +163 -45
  94. package/dist/hooks/runtime/session-review.js.map +1 -1
  95. package/dist/hooks/runtime/session-start.js +2 -1
  96. package/dist/hooks/runtime/session-start.js.map +1 -1
  97. package/dist/hooks/runtime/session-writes.js +232 -0
  98. package/dist/hooks/runtime/session-writes.js.map +1 -0
  99. package/dist/hooks/runtime/sniff.js +26 -7
  100. package/dist/hooks/runtime/sniff.js.map +1 -1
  101. package/dist/hooks/runtime/target-resolve.js +336 -0
  102. package/dist/hooks/runtime/target-resolve.js.map +1 -0
  103. package/dist/hooks/runtime/unmapped-tools.js +93 -0
  104. package/dist/hooks/runtime/unmapped-tools.js.map +1 -0
  105. package/dist/hooks/runtime/usage-block.js +4 -0
  106. package/dist/hooks/runtime/usage-block.js.map +1 -1
  107. package/dist/hooks/runtime/user-prompt-submit.js +2 -1
  108. package/dist/hooks/runtime/user-prompt-submit.js.map +1 -1
  109. package/dist/hooks/runtime/wire-text.js +41 -0
  110. package/dist/hooks/runtime/wire-text.js.map +1 -0
  111. package/dist/hooks/runtime/work-dir.js +84 -0
  112. package/dist/hooks/runtime/work-dir.js.map +1 -0
  113. package/dist/index.js +45 -12
  114. package/dist/index.js.map +1 -1
  115. package/dist/install.js +174 -11
  116. package/dist/install.js.map +1 -1
  117. package/dist/link.js +74 -48
  118. package/dist/link.js.map +1 -1
  119. package/dist/login.js +77 -11
  120. package/dist/login.js.map +1 -1
  121. package/dist/mcp/auth/agent-sign-ins.js +174 -0
  122. package/dist/mcp/auth/agent-sign-ins.js.map +1 -0
  123. package/dist/mcp/auth/callback.js +200 -0
  124. package/dist/mcp/auth/callback.js.map +1 -0
  125. package/dist/mcp/auth/connect.js +392 -0
  126. package/dist/mcp/auth/connect.js.map +1 -0
  127. package/dist/mcp/auth/discovery.js +399 -0
  128. package/dist/mcp/auth/discovery.js.map +1 -0
  129. package/dist/mcp/auth/oauth.js +326 -0
  130. package/dist/mcp/auth/oauth.js.map +1 -0
  131. package/dist/mcp/auth/probe.js +128 -0
  132. package/dist/mcp/auth/probe.js.map +1 -0
  133. package/dist/mcp/auth/secrets.js +446 -0
  134. package/dist/mcp/auth/secrets.js.map +1 -0
  135. package/dist/mcp/auth/store.js +260 -0
  136. package/dist/mcp/auth/store.js.map +1 -0
  137. package/dist/mcp/auth/tokenSource.js +55 -0
  138. package/dist/mcp/auth/tokenSource.js.map +1 -0
  139. package/dist/mcp/config/atomicWrite.js +98 -0
  140. package/dist/mcp/config/atomicWrite.js.map +1 -0
  141. package/dist/mcp/config/clients.js +171 -0
  142. package/dist/mcp/config/clients.js.map +1 -0
  143. package/dist/mcp/config/cybedefend-servers.js +48 -0
  144. package/dist/mcp/config/cybedefend-servers.js.map +1 -0
  145. package/dist/mcp/config/discover.js +114 -0
  146. package/dist/mcp/config/discover.js.map +1 -0
  147. package/dist/mcp/config/hook.js +123 -0
  148. package/dist/mcp/config/hook.js.map +1 -0
  149. package/dist/mcp/config/index.js +11 -0
  150. package/dist/mcp/config/index.js.map +1 -0
  151. package/dist/mcp/config/install.js +132 -0
  152. package/dist/mcp/config/install.js.map +1 -0
  153. package/dist/mcp/config/installed.js +37 -0
  154. package/dist/mcp/config/installed.js.map +1 -0
  155. package/dist/mcp/config/jsonEdit.js +119 -0
  156. package/dist/mcp/config/jsonEdit.js.map +1 -0
  157. package/dist/mcp/config/lock.js +102 -0
  158. package/dist/mcp/config/lock.js.map +1 -0
  159. package/dist/mcp/config/proxyBinary.js +211 -0
  160. package/dist/mcp/config/proxyBinary.js.map +1 -0
  161. package/dist/mcp/config/rewrite.js +388 -0
  162. package/dist/mcp/config/rewrite.js.map +1 -0
  163. package/dist/mcp/config/types.js +34 -0
  164. package/dist/mcp/config/types.js.map +1 -0
  165. package/dist/mcp/proxy/audit.js +83 -0
  166. package/dist/mcp/proxy/audit.js.map +1 -0
  167. package/dist/mcp/proxy/authInterceptor.js +119 -0
  168. package/dist/mcp/proxy/authInterceptor.js.map +1 -0
  169. package/dist/mcp/proxy/expand.js +93 -0
  170. package/dist/mcp/proxy/expand.js.map +1 -0
  171. package/dist/mcp/proxy/inject.js +397 -0
  172. package/dist/mcp/proxy/inject.js.map +1 -0
  173. package/dist/mcp/proxy/intercept.js +37 -0
  174. package/dist/mcp/proxy/intercept.js.map +1 -0
  175. package/dist/mcp/proxy/jsonrpc.js +153 -0
  176. package/dist/mcp/proxy/jsonrpc.js.map +1 -0
  177. package/dist/mcp/proxy/log.js +109 -0
  178. package/dist/mcp/proxy/log.js.map +1 -0
  179. package/dist/mcp/proxy/paths.js +53 -0
  180. package/dist/mcp/proxy/paths.js.map +1 -0
  181. package/dist/mcp/proxy/proxy.js +510 -0
  182. package/dist/mcp/proxy/proxy.js.map +1 -0
  183. package/dist/mcp/proxy/spec.js +203 -0
  184. package/dist/mcp/proxy/spec.js.map +1 -0
  185. package/dist/mcp/proxy/sse.js +77 -0
  186. package/dist/mcp/proxy/sse.js.map +1 -0
  187. package/dist/mcp/proxy/upstream.js +2 -0
  188. package/dist/mcp/proxy/upstream.js.map +1 -0
  189. package/dist/mcp/proxy/upstreamHttp.js +499 -0
  190. package/dist/mcp/proxy/upstreamHttp.js.map +1 -0
  191. package/dist/mcp/proxy/upstreamStdio.js +188 -0
  192. package/dist/mcp/proxy/upstreamStdio.js.map +1 -0
  193. package/dist/mcp/proxy/upstreams.js +143 -0
  194. package/dist/mcp/proxy/upstreams.js.map +1 -0
  195. package/dist/mcp/proxy/verifyInterceptor.js +559 -0
  196. package/dist/mcp/proxy/verifyInterceptor.js.map +1 -0
  197. package/dist/mcp/proxy/windowsCommand.js +99 -0
  198. package/dist/mcp/proxy/windowsCommand.js.map +1 -0
  199. package/dist/mcp/scan/args.js +228 -0
  200. package/dist/mcp/scan/args.js.map +1 -0
  201. package/dist/mcp/scan/results.js +253 -0
  202. package/dist/mcp/scan/results.js.map +1 -0
  203. package/dist/mcp/scan/types.js +40 -0
  204. package/dist/mcp/scan/types.js.map +1 -0
  205. package/dist/mcp/verify/api.js +475 -0
  206. package/dist/mcp/verify/api.js.map +1 -0
  207. package/dist/mcp/verify/backend.js +143 -0
  208. package/dist/mcp/verify/backend.js.map +1 -0
  209. package/dist/mcp/verify/cache.js +182 -0
  210. package/dist/mcp/verify/cache.js.map +1 -0
  211. package/dist/mcp/verify/contract-errors.js +198 -0
  212. package/dist/mcp/verify/contract-errors.js.map +1 -0
  213. package/dist/mcp/verify/digest.js +91 -0
  214. package/dist/mcp/verify/digest.js.map +1 -0
  215. package/dist/mcp/verify/factory.js +56 -0
  216. package/dist/mcp/verify/factory.js.map +1 -0
  217. package/dist/mcp/verify/identity.js +173 -0
  218. package/dist/mcp/verify/identity.js.map +1 -0
  219. package/dist/mcp/verify/policy-store.js +63 -0
  220. package/dist/mcp/verify/policy-store.js.map +1 -0
  221. package/dist/mcp/verify/policy.js +158 -0
  222. package/dist/mcp/verify/policy.js.map +1 -0
  223. package/dist/mcp/verify/pool.js +27 -0
  224. package/dist/mcp/verify/pool.js.map +1 -0
  225. package/dist/mcp/verify/token-refresh.js +44 -0
  226. package/dist/mcp/verify/token-refresh.js.map +1 -0
  227. package/dist/mcp/verify/token.js +67 -0
  228. package/dist/mcp/verify/token.js.map +1 -0
  229. package/dist/mcp/verify/verifier.js +1009 -0
  230. package/dist/mcp/verify/verifier.js.map +1 -0
  231. package/dist/org-gate.js +1 -1
  232. package/dist/org-gate.js.map +1 -1
  233. package/dist/org.js +146 -0
  234. package/dist/org.js.map +1 -0
  235. package/dist/project-create.js +129 -0
  236. package/dist/project-create.js.map +1 -0
  237. package/dist/prompts.js +21 -0
  238. package/dist/prompts.js.map +1 -1
  239. package/dist/re2.wasm +0 -0
  240. package/dist/status.js +61 -0
  241. package/dist/status.js.map +1 -1
  242. package/dist/uninstall.js +49 -4
  243. package/dist/uninstall.js.map +1 -1
  244. package/dist/utils.js +62 -6
  245. package/dist/utils.js.map +1 -1
  246. package/package.json +10 -3
@@ -0,0 +1,264 @@
1
+ import { chain } from '../../mcp/proxy/intercept.js';
2
+ import { createTokenSource } from '../../mcp/auth/tokenSource.js';
3
+ import { connectCommandFor, createAuthInterceptor } from '../../mcp/proxy/authInterceptor.js';
4
+ import { createAudit } from '../../mcp/proxy/audit.js';
5
+ import { createVerifyInterceptor } from '../../mcp/proxy/verifyInterceptor.js';
6
+ import { buildVerifier } from '../../mcp/verify/factory.js';
7
+ import { isProxyInstalled } from '../../mcp/config/installed.js';
8
+ import { withSyncLock } from '../../mcp/config/lock.js';
9
+ import { checkProxyBinary } from '../../mcp/config/proxyBinary.js';
10
+ import { applySyncPlan, planSync } from '../../mcp/config/rewrite.js';
11
+ import { loggerFromEnv, parseLogLevel } from '../../mcp/proxy/log.js';
12
+ import { mcpLogsDir, PROXY_ENV_PREFIX } from '../../mcp/proxy/paths.js';
13
+ import { Proxy } from '../../mcp/proxy/proxy.js';
14
+ import { createLogger } from '../../mcp/proxy/log.js';
15
+ import { describeUpstream, resolveUpstreamSpec, UpstreamSpecError, } from '../../mcp/proxy/spec.js';
16
+ import { expandedSpecOf, resolveNamedUpstream, specOf, UnknownUpstreamError, } from '../../mcp/proxy/upstreams.js';
17
+ /** Exit code for a usage error, distinct from an upstream that died. */
18
+ export const EXIT_USAGE = 2;
19
+ export async function runMcpProxyCommand(options, runtime) {
20
+ // TWO specs, and they are not interchangeable.
21
+ //
22
+ // `spec` is what the upstream is reached with: expanded, because the child
23
+ // needs the value the originating client would have given it.
24
+ //
25
+ // `identitySpec` is the entry as stored: NOT expanded, because
26
+ // `upstreamServerId` hashes `command` + `args` (or the url), and that hash
27
+ // keys the verdict cache and the user's own `allow`/`deny` overrides —
28
+ // which `vibedefend allow|deny|status` compute from the stored entry.
29
+ // Deriving it from the expanded spec makes a `deny` stop applying the
30
+ // moment a reference appears in `args`, silently. Measured, not feared:
31
+ // see the conformance test that pins it.
32
+ let spec;
33
+ let identitySpec;
34
+ // Variable references the originating client would have resolved. Names
35
+ // only — these are logged, and one of them is an API key.
36
+ let expansion = { resolved: [], missing: [] };
37
+ try {
38
+ // `--name` is the shape `vibedefend install` writes into a client config,
39
+ // so it wins over anything else on the command line.
40
+ if (options.name) {
41
+ const { entry } = resolveNamedUpstream(options.name, runtime.env);
42
+ // Expanded HERE, at the moment of use — `upstreams.json` keeps the
43
+ // reference, never the value. See `expand.ts`.
44
+ const expanded = expandedSpecOf(entry, runtime.env);
45
+ spec = expanded.value;
46
+ identitySpec = specOf(entry);
47
+ expansion = { resolved: expanded.resolved, missing: expanded.missing };
48
+ }
49
+ else {
50
+ spec = resolveUpstreamSpec(options);
51
+ // Nothing was expanded, so the two are the same object.
52
+ identitySpec = spec;
53
+ }
54
+ }
55
+ catch (error) {
56
+ if (error instanceof UpstreamSpecError || error instanceof UnknownUpstreamError) {
57
+ runtime.stderr.write(`vibedefend mcp: ${error.message}\n`);
58
+ return EXIT_USAGE;
59
+ }
60
+ throw error;
61
+ }
62
+ const level = options.logLevel
63
+ ? parseLogLevel(options.logLevel)
64
+ : parseLogLevel(runtime.env[`${PROXY_ENV_PREFIX}LOG_LEVEL`]);
65
+ const logger = options.logLevel
66
+ ? createLogger({
67
+ level,
68
+ dir: mcpLogsDir(runtime.env),
69
+ base: { pid: process.pid, upstream: describeUpstream(spec) },
70
+ mirrorToStderr: runtime.env[`${PROXY_ENV_PREFIX}LOG_STDERR`] === '1',
71
+ })
72
+ : loggerFromEnv({ pid: process.pid, upstream: describeUpstream(spec) }, runtime.env);
73
+ // Names only, never values — this line is the one that would have made the
74
+ // signoz 401 a ten-second diagnosis instead of a dogfooding session.
75
+ if (expansion.resolved.length > 0 || expansion.missing.length > 0) {
76
+ logger.info('expanded variable references from the client entry', {
77
+ resolved: expansion.resolved,
78
+ resolvedCount: expansion.resolved.length,
79
+ missing: expansion.missing,
80
+ });
81
+ }
82
+ for (const name of expansion.missing) {
83
+ logger.warn('a variable referenced by this server is not set and has no default; ' +
84
+ 'the literal text is passed through, exactly as the client would', { variable: name });
85
+ }
86
+ const proxy = new Proxy({
87
+ spec,
88
+ logger,
89
+ interceptor: buildInterceptor(spec, identitySpec, options.name, logger, runtime),
90
+ stdin: runtime.stdin,
91
+ stdout: runtime.stdout,
92
+ stderr: runtime.stderr,
93
+ proxyVersion: runtime.version,
94
+ // Only an http upstream can carry a bearer. The source reads nothing until
95
+ // the server answers 401, so a server that wants no token never causes a
96
+ // credential-store lookup at all.
97
+ auth: spec.transport === 'http'
98
+ ? createTokenSource(spec.url, {
99
+ onLookup: (outcome) => logger.info('credential lookup', { outcome }),
100
+ })
101
+ : undefined,
102
+ afterInitialize: runtime.env[`${PROXY_ENV_PREFIX}NO_SYNC`] === '1'
103
+ ? undefined
104
+ : () => backgroundSync(options, runtime, logger),
105
+ agentInitializeDeadlineMs: positiveMs(runtime.env[`${PROXY_ENV_PREFIX}INIT_DEADLINE_MS`]),
106
+ upstreamInitializeTimeoutMs: positiveMs(runtime.env[`${PROXY_ENV_PREFIX}UPSTREAM_INIT_TIMEOUT_MS`]),
107
+ });
108
+ const register = runtime.onSignal ?? ((handler) => {
109
+ process.on('SIGINT', () => handler('SIGINT'));
110
+ process.on('SIGTERM', () => handler('SIGTERM'));
111
+ });
112
+ register((signal) => {
113
+ logger.info('received a signal', { signal });
114
+ proxy.shutdown(0);
115
+ });
116
+ return proxy.run();
117
+ }
118
+ /** An override is honoured only when it is a positive number of milliseconds. */
119
+ function positiveMs(value) {
120
+ if (!value)
121
+ return undefined;
122
+ const parsed = Number(value);
123
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : undefined;
124
+ }
125
+ /**
126
+ * May this proxy rewrite the clients' configs?
127
+ *
128
+ * Only when all three hold: it was spawned from a wrapped entry (`--name`,
129
+ * not an ad hoc `--upstream` typed by a human), the user explicitly installed
130
+ * the proxy (the `installed` marker), and the binary running is the one
131
+ * `vibedefend` resolves to on the PATH — so the entries it would write point
132
+ * at itself. A checkout's `node dist/index.js` fails the third, whatever the
133
+ * marker says: measured on 2026-09-08, it wrapped twelve real servers behind
134
+ * a global release that had no `mcp` command.
135
+ */
136
+ function backgroundSyncPermission(options, runtime) {
137
+ if (!options.name)
138
+ return 'ad-hoc';
139
+ if (!isProxyInstalled(runtime.env))
140
+ return 'not-installed';
141
+ const check = checkProxyBinary({ env: runtime.env, argv1: runtime.argv1 ?? process.argv[1] });
142
+ if (!check.matches)
143
+ return check.reason ?? 'different-binary';
144
+ return 'granted';
145
+ }
146
+ /**
147
+ * The background `sync` the plan asks the proxy to run at startup.
148
+ *
149
+ * It exists so that a server added with `claude mcp add` mid-week ends up
150
+ * behind the proxy without anyone remembering a command. Three things make it
151
+ * safe to run from here:
152
+ *
153
+ * - the permission above, checked first and logged when refused;
154
+ * - the lock. One proxy runs per MCP server, so five of them start within
155
+ * the same second and would otherwise all rewrite `~/.claude.json` at
156
+ * once; whoever gets the lock does the work and the rest do nothing.
157
+ * - no backup. A timestamped copy per session, per server, would fill the
158
+ * user's home with files nobody asked for. The originals are in
159
+ * `upstreams.json`, which is what `uninstall` restores from anyway.
160
+ *
161
+ * Every failure is logged and swallowed: an MCP session must not end because
162
+ * a config file could not be rewritten.
163
+ */
164
+ async function backgroundSync(options, runtime, logger) {
165
+ const env = runtime.env;
166
+ const permission = backgroundSyncPermission(options, runtime);
167
+ if (permission !== 'granted') {
168
+ // An ad hoc launch is routine; the other two mean an installed proxy that
169
+ // cannot do its job, which somebody reading the log should see.
170
+ logger[permission === 'ad-hoc' ? 'debug' : 'info']('background sync skipped', {
171
+ reason: permission,
172
+ });
173
+ return;
174
+ }
175
+ const ran = await withSyncLock(() => {
176
+ const plan = planSync({ env });
177
+ const result = applySyncPlan(plan, { env, backup: false });
178
+ return { plan, result };
179
+ }, { env });
180
+ if (!ran) {
181
+ logger.debug('background sync skipped: another process holds the lock');
182
+ return;
183
+ }
184
+ const wrapped = ran.plan.changes.filter((change) => change.kind === 'wrap').length;
185
+ const forgotten = ran.plan.changes.filter((change) => change.kind === 'forget').length;
186
+ if (wrapped === 0 && forgotten === 0 && ran.result.failed.length === 0) {
187
+ logger.debug('background sync: nothing to do');
188
+ return;
189
+ }
190
+ logger.info('background sync', {
191
+ wrapped,
192
+ forgotten,
193
+ failed: ran.result.failed.length,
194
+ files: ran.result.written,
195
+ });
196
+ }
197
+ /**
198
+ * The interceptors, in the order they see a message.
199
+ *
200
+ * Auth first: an http upstream that refuses every token gets `initialize`
201
+ * answered by the proxy and a tool list reduced to
202
+ * `vibedefend_connect_required`, and verification has nothing to say about a
203
+ * list the proxy wrote itself. It is wired whatever `VIBEDEFEND_MCP_NO_VERIFY`
204
+ * says, because it is not verification: it is section 0's rule that
205
+ * `initialize` is always answered.
206
+ */
207
+ function buildInterceptor(spec, identitySpec, name, logger, runtime) {
208
+ const interceptors = [];
209
+ if (spec.transport === 'http') {
210
+ interceptors.push(createAuthInterceptor({
211
+ // Displayed, so the stored form: an expanded url would print the
212
+ // value of the reference into the agent's context.
213
+ serverName: name ?? describeUpstream(identitySpec),
214
+ connectCommand: connectCommandFor({ name, spec: identitySpec }),
215
+ proxyVersion: runtime.version,
216
+ logger,
217
+ }));
218
+ }
219
+ const verify = buildVerifyInterceptor(identitySpec, name, logger, runtime);
220
+ if (verify)
221
+ interceptors.push(verify);
222
+ if (interceptors.length === 0)
223
+ return undefined;
224
+ return interceptors.length === 1 ? interceptors[0] : chain(interceptors);
225
+ }
226
+ /**
227
+ * The verification seam, wired to the local cache and to the CybeDefend
228
+ * backend — through `buildVerifier`, the same wiring `vibedefend scan` uses,
229
+ * so what one buys the other finds.
230
+ *
231
+ * `VIBEDEFEND_MCP_NO_VERIFY=1` takes it out entirely, which is what the
232
+ * Phase 1 conformance suite runs with: those tests assert that the proxy is
233
+ * indistinguishable from the server, and a `vibedefend_alert` appended to a
234
+ * tool list is, correctly, a difference.
235
+ */
236
+ function buildVerifyInterceptor(spec, name, logger, runtime) {
237
+ if (runtime.env[`${PROXY_ENV_PREFIX}NO_VERIFY`] === '1') {
238
+ logger.info('verification disabled by the environment');
239
+ return undefined;
240
+ }
241
+ // No credential means no backend call, and the cache alone decides. That
242
+ // is a supported state, not a degraded one: a machine with a blacklisted
243
+ // server in its cache still refuses it. No network here: an organization
244
+ // that is not persisted yet is resolved at the first verification, after
245
+ // `initialize` has been answered (section 0).
246
+ const { verifier, serverId, serverName, backend } = buildVerifier(spec, name ?? describeUpstream(spec), logger, runtime.env);
247
+ logger.info('verification enabled', {
248
+ serverId,
249
+ backend: backend !== null,
250
+ organization: backend?.organizationId ? 'persisted' : backend ? 'resolved-at-first-call' : 'none',
251
+ });
252
+ return createVerifyInterceptor({
253
+ verifier,
254
+ logger,
255
+ spec,
256
+ serverId,
257
+ serverName,
258
+ // Sizes and rule names, never arguments and never results: the plan's
259
+ // rule is that nothing from a `tools/call` leaves the machine, and a file
260
+ // quoting them would be a second copy of everything the user has done.
261
+ audit: createAudit({ env: runtime.env }),
262
+ });
263
+ }
264
+ //# sourceMappingURL=proxy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxy.js","sourceRoot":"","sources":["../../../src/commands/mcp/proxy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,349 @@
1
+ /**
2
+ * `vibedefend scan` — talk to every upstream once, with no agent in the loop.
3
+ *
4
+ * `initialize` plus `tools/list` against each server in `upstreams.json`, and
5
+ * a line per server. It is the command you run when something is wrong and
6
+ * you want to know which server it is, and it is what a CI job runs to find
7
+ * out whether the park changed under it.
8
+ *
9
+ * It is also the AUDIT. An agent session buys a judgement only for the tool
10
+ * it calls; `scan` buys one for every tool of every reachable server
11
+ * (`Verifier.judgeAll`), because the user who typed it asked exactly that
12
+ * question. The `verdict` column is the worst verdict on the server, the
13
+ * flagged tools are listed under it, and a `malicious` server exits
14
+ * non-zero. Without a credential the column reads `unverified`, which is
15
+ * honest: nobody could be asked. `VIBEDEFEND_MCP_NO_VERIFY=1` skips it.
16
+ */
17
+ import { spawn } from 'node:child_process';
18
+ import { probeMcpHttp } from '../../mcp/auth/probe.js';
19
+ import { ensureMcpAccessToken } from '../../mcp/auth/store.js';
20
+ import { createNullLogger } from '../../mcp/proxy/log.js';
21
+ import { encodeMessage, LineFramer } from '../../mcp/proxy/jsonrpc.js';
22
+ import { PROXY_ENV_PREFIX } from '../../mcp/proxy/paths.js';
23
+ import { describeUpstream, upstreamEnvironment } from '../../mcp/proxy/spec.js';
24
+ import { planSpawn } from '../../mcp/proxy/windowsCommand.js';
25
+ import { expandedSpecOf, readUpstreams, specOf } from '../../mcp/proxy/upstreams.js';
26
+ import { resolveBackendConfig } from '../../mcp/verify/backend.js';
27
+ import { createJsonVerifyCache } from '../../mcp/verify/cache.js';
28
+ import { buildVerifier } from '../../mcp/verify/factory.js';
29
+ import { runPool } from '../../mcp/verify/pool.js';
30
+ import { log } from '../../utils.js';
31
+ export const EXIT_OK = 0;
32
+ export const EXIT_PROBLEM = 1;
33
+ export const EXIT_USAGE = 2;
34
+ const DEFAULT_TIMEOUT_MS = 20_000;
35
+ /** A judge takes about a second per tool; a catalogue of a hundred is a coffee. */
36
+ const DEFAULT_VERIFY_TIMEOUT_MS = 180_000;
37
+ /**
38
+ * Servers judged side by side. Probing stays sequential — a stdio server is
39
+ * a process, and spawning the whole park at once is the wrong kind of
40
+ * fast — but a judgement is a network call that waits on a backend, and
41
+ * four of them waiting together cost the backend nothing it does not cap.
42
+ */
43
+ const JUDGE_CONCURRENCY = 4;
44
+ export async function runMcpScanCommand(options, runtime) {
45
+ const stdout = runtime.stdout ?? process.stdout;
46
+ const stderr = runtime.stderr ?? process.stderr;
47
+ const upstreams = readUpstreams(runtime.env);
48
+ let entries = Object.values(upstreams.servers);
49
+ if (options.name) {
50
+ const one = upstreams.servers[options.name];
51
+ if (!one) {
52
+ stderr.write(`vibedefend scan: no upstream named "${options.name}". Known: ${Object.keys(upstreams.servers).join(', ') || '(none)'}.\n`);
53
+ return EXIT_USAGE;
54
+ }
55
+ entries = [one];
56
+ }
57
+ if (entries.length === 0) {
58
+ if (options.json)
59
+ stdout.write(`${JSON.stringify({ servers: [] }, null, 2)}\n`);
60
+ else
61
+ log.info('No MCP server is registered. Run `vibedefend sync` after configuring one.');
62
+ return EXIT_OK;
63
+ }
64
+ const prepared = await prepareRuntime(runtime, stderr);
65
+ // Two phases. Reach every server, one at a time; then judge the ones that
66
+ // answered, a few at a time. The rows stay in the order of the entries
67
+ // whatever finishes first.
68
+ const probed = [];
69
+ for (const entry of entries) {
70
+ probed.push(await probeOne(entry, options, prepared));
71
+ }
72
+ const judge = prepared.judge ?? judgeWithBackend;
73
+ await runPool(probed.filter((server) => server.tools !== undefined), JUDGE_CONCURRENCY, async (server) => {
74
+ const started = Date.now();
75
+ const judged = await judge(server.spec, server.tools ?? [], options, prepared, server.row.name);
76
+ Object.assign(server.row, judged);
77
+ server.row.ms += elapsed(started);
78
+ });
79
+ const rows = probed.map((server) => server.row);
80
+ if (options.json) {
81
+ stdout.write(`${JSON.stringify({ servers: rows }, null, 2)}\n`);
82
+ }
83
+ else {
84
+ writeTable(rows);
85
+ }
86
+ // A server that wants a login is not a failure of the scan: it is
87
+ // information, and `vibedefend connect` is the answer. A malicious server
88
+ // is, and so is one that could not be reached.
89
+ return rows.some((row) => row.status === 'unreachable' ||
90
+ row.status === 'unusable' ||
91
+ row.verdict === 'malicious' ||
92
+ row.override === 'deny')
93
+ ? EXIT_PROBLEM
94
+ : EXIT_OK;
95
+ }
96
+ /**
97
+ * Resolves what every judgement of this scan shares — backend, cache — once.
98
+ *
99
+ * Only when the real judge will run: an injected judge never touches them,
100
+ * and `VIBEDEFEND_MCP_NO_VERIFY=1` means nobody is asked at all.
101
+ */
102
+ async function prepareRuntime(runtime, stderr) {
103
+ if (runtime.judge || runtime.env[`${PROXY_ENV_PREFIX}NO_VERIFY`] === '1')
104
+ return runtime;
105
+ const backend = runtime.backend !== undefined
106
+ ? runtime.backend
107
+ : await (runtime.resolveBackendConfigFn ?? resolveBackendConfig)({
108
+ env: runtime.env,
109
+ // Typed by a human: the reason nothing is verified goes to them.
110
+ warn: (message) => stderr.write(`vibedefend scan: ${message}\n`),
111
+ });
112
+ return {
113
+ ...runtime,
114
+ backend,
115
+ cache: runtime.cache ?? createJsonVerifyCache({ env: runtime.env }),
116
+ };
117
+ }
118
+ async function probeOne(entry, options, runtime) {
119
+ const started = Date.now();
120
+ const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
121
+ const base = { name: entry.name, transport: entry.transport, verdict: 'unverified' };
122
+ // TWO specs, as in the proxy (`runMcpProxyCommand`). The expanded one is
123
+ // what the server is REACHED with — a `${VAR}` in a url, a header or an
124
+ // argument must resolve here too, or `scan` reports a server the proxy
125
+ // would reach as unreachable. The stored one is what the verdict is FILED
126
+ // under: `upstreamServerId` hashes `command` + `args` (or the url), and
127
+ // that hash keys the cache and the user's `allow`/`deny`, which the proxy
128
+ // and `vibedefend allow` compute from the stored entry. Judging under the
129
+ // expanded spec would open a second cache file per server (with the
130
+ // resolved value in its name), bill every tool twice, and hide the
131
+ // override from `scan`.
132
+ const identitySpec = specOf(entry);
133
+ const failed = (status) => ({
134
+ row: { ...base, status, ms: elapsed(started) },
135
+ spec: identitySpec,
136
+ });
137
+ try {
138
+ if (entry.transport === 'http') {
139
+ const spec = expandedSpecOf(entry, runtime.env).value;
140
+ if (spec.transport !== 'http')
141
+ return failed('unusable');
142
+ const common = {
143
+ timeoutMs,
144
+ headers: spec.headers,
145
+ clientInfo: { name: 'vibedefend', version: runtime.version },
146
+ };
147
+ // Bare first. Most servers want no token, and asking the credential
148
+ // store for one costs a keychain round trip — and, on a locked macOS
149
+ // keychain, a dialog — for a lookup that was never going to find
150
+ // anything.
151
+ let probe = await probeMcpHttp(spec.url, { ...common, token: null });
152
+ if (probe.verdict === 'refused') {
153
+ // Renewed if it expired, and persisted: a token that ran out in the
154
+ // last hour used to send the user to `vibedefend connect --all` with
155
+ // the refresh token that would have fixed it sitting in the store
156
+ // (2026-09-16, three servers at once). A dead refresh token is erased
157
+ // on the way, and the row honestly reads `needs-auth`.
158
+ const token = await ensureMcpAccessToken(spec.url, { env: runtime.env });
159
+ if (token)
160
+ probe = await probeMcpHttp(spec.url, { ...common, token });
161
+ }
162
+ if (probe.verdict === 'open') {
163
+ return {
164
+ row: { ...base, status: 'ok', toolCount: probe.toolCount, ms: elapsed(started) },
165
+ spec: identitySpec,
166
+ tools: probe.tools ?? [],
167
+ };
168
+ }
169
+ if (probe.verdict === 'refused')
170
+ return failed('needs-auth');
171
+ if (probe.verdict === 'unreachable')
172
+ return failed('unreachable');
173
+ return failed('unusable');
174
+ }
175
+ const tools = await listStdioTools(entry, timeoutMs, runtime.env);
176
+ if (tools === null)
177
+ return failed('unreachable');
178
+ return {
179
+ row: { ...base, status: 'ok', toolCount: tools.length, ms: elapsed(started) },
180
+ spec: identitySpec,
181
+ tools,
182
+ };
183
+ }
184
+ catch {
185
+ return failed('unreachable');
186
+ }
187
+ }
188
+ function elapsed(started) {
189
+ return Date.now() - started;
190
+ }
191
+ /**
192
+ * Buys the judgement of every tool listed, and reads the verdicts back.
193
+ *
194
+ * Wired exactly like the proxy (`buildVerifier`): same cache, same identity,
195
+ * same name on the finding and same credential path, so what `scan` buys is
196
+ * what the next agent session finds, and vice versa. Without a credential
197
+ * nothing is asked and the row says `unverified`.
198
+ */
199
+ export const judgeWithBackend = async (spec, listed, options, runtime, name) => {
200
+ if (runtime.env[`${PROXY_ENV_PREFIX}NO_VERIFY`] === '1')
201
+ return { verdict: 'unverified' };
202
+ const tools = listed.filter((tool) => typeof tool === 'object' && tool !== null && typeof tool.name === 'string');
203
+ // Resolved once by `runMcpScanCommand`; a direct caller gets it here.
204
+ const backend = runtime.backend !== undefined
205
+ ? runtime.backend
206
+ : await (runtime.resolveBackendConfigFn ?? resolveBackendConfig)({ env: runtime.env });
207
+ if (!backend)
208
+ return { verdict: 'unverified' };
209
+ const { verifier } = buildVerifier(spec, name ?? describeUpstream(spec), createNullLogger(), runtime.env, {
210
+ backend,
211
+ cache: runtime.cache,
212
+ });
213
+ try {
214
+ const outcome = await verifier.judgeAll(tools, {
215
+ timeoutMs: options.verifyTimeoutMs ?? DEFAULT_VERIFY_TIMEOUT_MS,
216
+ });
217
+ return rowFromOutcome(outcome);
218
+ }
219
+ catch {
220
+ return { verdict: 'unverified' };
221
+ }
222
+ };
223
+ /**
224
+ * The row, from the outcome — and from the DECISION, not the verdict alone.
225
+ *
226
+ * The flagged tools come from `outcome.tools`, which is scoped to the tools
227
+ * listed now; the cache file is never pruned and walking it would show a
228
+ * tool the server dropped last month. The user's override is read off the
229
+ * decision's rationale, the one place `vibedefend allow` / `deny` surfaces.
230
+ */
231
+ export function rowFromOutcome(outcome) {
232
+ const flagged = [];
233
+ for (const tool of outcome.tools ?? []) {
234
+ if (tool.verdict === 'malicious' || tool.verdict === 'suspicious') {
235
+ flagged.push({ name: tool.name, verdict: tool.verdict, ...(tool.reason ? { reason: tool.reason } : {}) });
236
+ }
237
+ }
238
+ const judged = outcome.verdict === 'malicious' || outcome.verdict === 'suspicious' || outcome.verdict === 'ok'
239
+ ? outcome.verdict
240
+ : 'unverified';
241
+ const override = outcome.decision.rationale === 'allowed-by-user'
242
+ ? 'allow'
243
+ : outcome.decision.rationale === 'denied-by-user'
244
+ ? 'deny'
245
+ : undefined;
246
+ return {
247
+ verdict: override === 'allow' ? 'ok' : judged,
248
+ ...(flagged.length > 0 ? { flagged } : {}),
249
+ ...(override ? { override } : {}),
250
+ };
251
+ }
252
+ /**
253
+ * Spawns a stdio server, does the handshake, counts its tools and stops it.
254
+ *
255
+ * The proxy's own transport is not reused here: it exists to forward, and
256
+ * what this needs is a two-message conversation with a hard deadline and no
257
+ * session to keep. `null` means the server never got that far.
258
+ */
259
+ async function listStdioTools(entry, timeoutMs, env) {
260
+ const spec = expandedSpecOf(entry, env).value;
261
+ if (spec.transport !== 'stdio')
262
+ return null;
263
+ void createNullLogger();
264
+ const plan = planSpawn(spec.command, spec.args, process.platform, env);
265
+ const child = spawn(plan.command, plan.args, {
266
+ env: upstreamEnvironment(env, spec.env),
267
+ cwd: spec.cwd,
268
+ stdio: ['pipe', 'pipe', 'ignore'],
269
+ windowsVerbatimArguments: plan.windowsVerbatimArguments,
270
+ shell: false,
271
+ });
272
+ return new Promise((resolve) => {
273
+ const framer = new LineFramer();
274
+ let settled = false;
275
+ const finish = (value) => {
276
+ if (settled)
277
+ return;
278
+ settled = true;
279
+ clearTimeout(timer);
280
+ try {
281
+ child.stdin.end();
282
+ child.kill();
283
+ }
284
+ catch {
285
+ /* already gone */
286
+ }
287
+ resolve(value);
288
+ };
289
+ const timer = setTimeout(() => finish(null), timeoutMs);
290
+ if (typeof timer.unref === 'function')
291
+ timer.unref();
292
+ child.once('error', () => finish(null));
293
+ child.once('exit', () => finish(null));
294
+ child.stdout?.on('data', (chunk) => {
295
+ for (const message of framer.push(chunk).messages) {
296
+ const typed = message;
297
+ if (typed.id === 1) {
298
+ child.stdin.write(encodeMessage({ jsonrpc: '2.0', method: 'notifications/initialized' }));
299
+ child.stdin.write(encodeMessage({ jsonrpc: '2.0', id: 2, method: 'tools/list' }));
300
+ continue;
301
+ }
302
+ if (typed.id === 2) {
303
+ const result = typed.result;
304
+ finish(Array.isArray(result?.tools) ? result.tools : []);
305
+ }
306
+ }
307
+ });
308
+ child.stdin.write(encodeMessage({
309
+ jsonrpc: '2.0',
310
+ id: 1,
311
+ method: 'initialize',
312
+ params: {
313
+ protocolVersion: '2025-06-18',
314
+ capabilities: {},
315
+ clientInfo: { name: 'vibedefend-scan', version: '1.0.0' },
316
+ },
317
+ }));
318
+ });
319
+ }
320
+ function writeTable(rows) {
321
+ const width = Math.max(6, ...rows.map((row) => row.name.length));
322
+ log.step('MCP servers');
323
+ for (const row of rows) {
324
+ const name = row.name.padEnd(width);
325
+ const tools = row.toolCount === undefined ? '' : `${row.toolCount} tools`;
326
+ const verdict = row.status === 'ok' ? row.verdict : '';
327
+ const said = row.override === 'allow' ? ' [allowed by you]' : row.override === 'deny' ? ' [denied by you]' : '';
328
+ const line = `${name} ${row.transport.padEnd(5)} ${row.status.padEnd(11)} ${tools.padEnd(9)} ${verdict.padEnd(10)} ${row.ms} ms${said}`;
329
+ if (row.verdict === 'malicious' || row.override === 'deny')
330
+ log.err(line);
331
+ else if (row.verdict === 'suspicious')
332
+ log.warn(line);
333
+ else if (row.status === 'ok')
334
+ log.ok(line);
335
+ else if (row.status === 'needs-auth')
336
+ log.warn(`${line} → vibedefend connect ${row.name}`);
337
+ else
338
+ log.err(line);
339
+ for (const tool of row.flagged ?? []) {
340
+ const reason = tool.reason ? ` — ${tool.reason}` : '';
341
+ const detail = ` ${tool.verdict.padEnd(10)} ${tool.name}${reason}`;
342
+ if (tool.verdict === 'malicious')
343
+ log.err(detail);
344
+ else
345
+ log.warn(detail);
346
+ }
347
+ }
348
+ }
349
+ //# sourceMappingURL=scan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan.js","sourceRoot":"","sources":["../../../src/commands/mcp/scan.ts"],"names":[],"mappings":"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"}