@cybedefend/vibedefend 1.5.0 → 1.7.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 (264) hide show
  1. package/README.md +71 -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 +320 -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 +412 -0
  172. package/dist/mcp/proxy/inject.js.map +1 -0
  173. package/dist/mcp/proxy/intercept.js +63 -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 +57 -0
  180. package/dist/mcp/proxy/paths.js.map +1 -0
  181. package/dist/mcp/proxy/proxy.js +520 -0
  182. package/dist/mcp/proxy/proxy.js.map +1 -0
  183. package/dist/mcp/proxy/serverCheckTimer.js +75 -0
  184. package/dist/mcp/proxy/serverCheckTimer.js.map +1 -0
  185. package/dist/mcp/proxy/sessionLifecycle.js +29 -0
  186. package/dist/mcp/proxy/sessionLifecycle.js.map +1 -0
  187. package/dist/mcp/proxy/spec.js +203 -0
  188. package/dist/mcp/proxy/spec.js.map +1 -0
  189. package/dist/mcp/proxy/sse.js +77 -0
  190. package/dist/mcp/proxy/sse.js.map +1 -0
  191. package/dist/mcp/proxy/upstream.js +2 -0
  192. package/dist/mcp/proxy/upstream.js.map +1 -0
  193. package/dist/mcp/proxy/upstreamHttp.js +499 -0
  194. package/dist/mcp/proxy/upstreamHttp.js.map +1 -0
  195. package/dist/mcp/proxy/upstreamStdio.js +188 -0
  196. package/dist/mcp/proxy/upstreamStdio.js.map +1 -0
  197. package/dist/mcp/proxy/upstreams.js +143 -0
  198. package/dist/mcp/proxy/upstreams.js.map +1 -0
  199. package/dist/mcp/proxy/verifyInterceptor.js +718 -0
  200. package/dist/mcp/proxy/verifyInterceptor.js.map +1 -0
  201. package/dist/mcp/proxy/windowsCommand.js +99 -0
  202. package/dist/mcp/proxy/windowsCommand.js.map +1 -0
  203. package/dist/mcp/report/buffer.js +351 -0
  204. package/dist/mcp/report/buffer.js.map +1 -0
  205. package/dist/mcp/report/coalesce.js +165 -0
  206. package/dist/mcp/report/coalesce.js.map +1 -0
  207. package/dist/mcp/report/constants.js +51 -0
  208. package/dist/mcp/report/constants.js.map +1 -0
  209. package/dist/mcp/report/project.js +83 -0
  210. package/dist/mcp/report/project.js.map +1 -0
  211. package/dist/mcp/report/reporter.js +443 -0
  212. package/dist/mcp/report/reporter.js.map +1 -0
  213. package/dist/mcp/report/types.js +3 -0
  214. package/dist/mcp/report/types.js.map +1 -0
  215. package/dist/mcp/report/validate.js +179 -0
  216. package/dist/mcp/report/validate.js.map +1 -0
  217. package/dist/mcp/scan/args.js +228 -0
  218. package/dist/mcp/scan/args.js.map +1 -0
  219. package/dist/mcp/scan/results.js +253 -0
  220. package/dist/mcp/scan/results.js.map +1 -0
  221. package/dist/mcp/scan/types.js +40 -0
  222. package/dist/mcp/scan/types.js.map +1 -0
  223. package/dist/mcp/verify/api.js +514 -0
  224. package/dist/mcp/verify/api.js.map +1 -0
  225. package/dist/mcp/verify/backend.js +143 -0
  226. package/dist/mcp/verify/backend.js.map +1 -0
  227. package/dist/mcp/verify/cache.js +200 -0
  228. package/dist/mcp/verify/cache.js.map +1 -0
  229. package/dist/mcp/verify/contract-errors.js +198 -0
  230. package/dist/mcp/verify/contract-errors.js.map +1 -0
  231. package/dist/mcp/verify/digest.js +91 -0
  232. package/dist/mcp/verify/digest.js.map +1 -0
  233. package/dist/mcp/verify/factory.js +56 -0
  234. package/dist/mcp/verify/factory.js.map +1 -0
  235. package/dist/mcp/verify/identity.js +286 -0
  236. package/dist/mcp/verify/identity.js.map +1 -0
  237. package/dist/mcp/verify/policy-store.js +63 -0
  238. package/dist/mcp/verify/policy-store.js.map +1 -0
  239. package/dist/mcp/verify/policy.js +160 -0
  240. package/dist/mcp/verify/policy.js.map +1 -0
  241. package/dist/mcp/verify/pool.js +27 -0
  242. package/dist/mcp/verify/pool.js.map +1 -0
  243. package/dist/mcp/verify/token-refresh.js +44 -0
  244. package/dist/mcp/verify/token-refresh.js.map +1 -0
  245. package/dist/mcp/verify/token.js +67 -0
  246. package/dist/mcp/verify/token.js.map +1 -0
  247. package/dist/mcp/verify/verifier.js +1166 -0
  248. package/dist/mcp/verify/verifier.js.map +1 -0
  249. package/dist/org-gate.js +1 -1
  250. package/dist/org-gate.js.map +1 -1
  251. package/dist/org.js +146 -0
  252. package/dist/org.js.map +1 -0
  253. package/dist/project-create.js +129 -0
  254. package/dist/project-create.js.map +1 -0
  255. package/dist/prompts.js +21 -0
  256. package/dist/prompts.js.map +1 -1
  257. package/dist/re2.wasm +0 -0
  258. package/dist/status.js +61 -0
  259. package/dist/status.js.map +1 -1
  260. package/dist/uninstall.js +49 -4
  261. package/dist/uninstall.js.map +1 -1
  262. package/dist/utils.js +62 -6
  263. package/dist/utils.js.map +1 -1
  264. package/package.json +10 -3
package/README.md CHANGED
@@ -27,7 +27,19 @@ The installer is fully interactive, and signs you in **first**:
27
27
  3. **Organization check** — if your account doesn't belong to an
28
28
  organization yet, the dashboard on-boarding page opens and the installer
29
29
  waits while you create or join one (Ctrl-C to skip and finish later).
30
- 4. **Pick which agents to wire** (auto-detected), confirm. That's it.
30
+ 4. **Pick which agents to wire** (auto-detected), confirm.
31
+ 5. **MCP proxy** — put the VibeDefend proxy in front of your other MCP
32
+ servers (yes by default), so each tool is checked against your
33
+ organization policy before your agent calls it. CybeDefend's own MCP
34
+ server is never wrapped. The proxy also reports to your organization the
35
+ MCP servers it sees and the calls it refused, asked about, warned on or
36
+ whose result it flagged (never their arguments or results), and it
37
+ applies your organization's blocks within 15 minutes; this needs the
38
+ CybeDefend gateway of 2026-10-28.
39
+ 6. **MCP sign-ins** — the sign-ins Claude Code or Codex already hold for
40
+ those servers are taken over on their own. Your browser opens only for the
41
+ servers left without one, if you say yes (or later:
42
+ `vibedefend connect --all`).
31
43
 
32
44
  Run through `npx` (or `pnpm dlx` / `yarn dlx`), the installer first installs
33
45
  the CLI globally (`npm install -g @cybedefend/vibedefend`), so the
@@ -125,12 +137,18 @@ For any other repo (no remote, a mirror, a monorepo subfolder, an
125
137
  unimported project…), link it once:
126
138
 
127
139
  ```bash
128
- vibedefend link # interactive: auto-detect, or pick org → project
140
+ vibedefend link # interactive: auto-detect, pick org → project, or create one
129
141
  vibedefend link --project <uuid> # non-interactive, if you know the project UUID
130
142
  # or without a global install:
131
143
  npx -y @cybedefend/vibedefend@latest link --project <PROJECT_ID>
132
144
  ```
133
145
 
146
+ No project yet? `link` offers to create one (team managers and organization
147
+ administrators can). When `origin` is a github.com / gitlab.com repository
148
+ that the organization's GitHub App / GitLab integration can see, the new
149
+ project is linked to it and its first scan starts; otherwise start a first
150
+ scan from the dashboard.
151
+
134
152
  `link` writes a `.cybedefend/config.json` next to your code:
135
153
 
136
154
  ```json
@@ -141,6 +159,16 @@ That file is now **optional** for GitHub/GitLab-linked projects, but it
141
159
  remains a supported override everywhere — when present, it always wins over
142
160
  git-origin auto-resolution (as does the `CYBEDEFEND_PROJECT_ID` env var).
143
161
 
162
+ The project is read from the directory your agent works in, as its client
163
+ reports it (Cursor: the workspace root). When the agent writes a file of
164
+ another repository, such as another git worktree or clone, the rules for that
165
+ file come from that repository's project, or from the agent's project when
166
+ that repository has none. Action Guards always use the agent's directory.
167
+
168
+ `link` also adds `.cybedefend/` to the directory's `.gitignore` (idempotent):
169
+ the link describes *your* checkout, not the code. Remove the line if your team
170
+ prefers to share it — the hooks read the file either way.
171
+
144
172
  **Folders that are not CybeDefend projects.** The hooks are installed for
145
173
  every folder your agent opens. When a session starts in a folder with no
146
174
  `.cybedefend/config.json` and no project linked to its GitHub/GitLab `origin`
@@ -164,6 +192,47 @@ You can grab the UUID from the project page on the EU dashboard
164
192
  ([eu.cybedefend.com](https://eu.cybedefend.com)) or the US dashboard
165
193
  ([us.cybedefend.com](https://us.cybedefend.com)).
166
194
 
195
+ ## Where VibeDefend is active
196
+
197
+ The hooks are wired **globally** (one `~/.claude/settings.json`, one
198
+ `~/.codex/hooks.json`, …), so the question is which repos they act on. The
199
+ installer asks:
200
+
201
+ | Mode | Behaviour |
202
+ |---|---|
203
+ | `auto` (default) | Every repo that resolves to a CybeDefend project — via `.cybedefend/config.json`, `CYBEDEFEND_PROJECT_ID`, or git-origin auto-discovery. |
204
+ | `opt-in` | Only repos you linked explicitly (`vibedefend link`) or run with `CYBEDEFEND_PROJECT_ID`. No origin lookup: in every other repo the session shows the one-line notice above, then every hook stays off. |
205
+
206
+ The choice lives in `~/.cybedefend/runtime-config.json` (`hooks.activation`);
207
+ re-run `vibedefend install` to change it, or override it per shell with
208
+ `CYBEDEFEND_ACTIVATION=auto|opt-in`. `vibedefend status` shows the effective mode.
209
+
210
+ ## Action Guards — how commands are read
211
+
212
+ The guard evaluates a Bash command **by shell position**, not by substring
213
+ (BACK-174): a heredoc written to a file, a URL query string (`&su=…`), quoted
214
+ data (`echo "a && su"`) or code handed to a non-shell interpreter
215
+ (`python3 -c "…"`) can no longer trip a rule meant for a command word, while
216
+ `su -`, `…; su -`, `bash -c "…; su -"` and `curl … | bash` on any line of a
217
+ shell heredoc are still blocked.
218
+
219
+ Scripts the agent writes in its **own harness scratchpad** —
220
+ `/tmp/claude-<uid>/…`, `/private/tmp/claude-<uid>/…` and the Codex / Cursor /
221
+ Windsurf / Copilot equivalents — are not "executed from /tmp". Add your own
222
+ prefixes with `CYBEDEFEND_SCRATCH_DIRS` (`PATH`-style list).
223
+
224
+ Tool calls the guard cannot map to a file, command or URL are **allowed
225
+ fail-open**. Tools that carry no target by construction (`ToolSearch`, todo
226
+ lists, sub-agents, the `mcp__cybedefend__*` tools) pass silently; anything
227
+ else is counted in `~/.cybedefend/guards-unmapped-tools.json`, announced once
228
+ per session on stderr, and listed by `vibedefend status`. Set
229
+ `CYBEDEFEND_GUARDS_STRICT=1` to block those instead.
230
+
231
+ Rule regexes run on RE2 (linear time, no ReDoS): the engine is bundled into
232
+ the hook runner and `re2.wasm` ships next to it for every install shape. If a
233
+ hook ever reports `RE2 engine unavailable`, run `vibedefend doctor` — it
234
+ restores the missing binary.
235
+
167
236
  ## Updating
168
237
 
169
238
  At install you're asked **"Enable automatic background updates? (recommended)"**.
@@ -0,0 +1,49 @@
1
+ function errorMessage(body) {
2
+ if (!body || typeof body !== 'object')
3
+ return undefined;
4
+ const m = body.message;
5
+ if (typeof m === 'string' && m)
6
+ return m;
7
+ if (Array.isArray(m) && m.length > 0)
8
+ return m.map(String).join('; ');
9
+ return undefined;
10
+ }
11
+ export async function requestGateway(url, req, deps, defaultTimeoutMs) {
12
+ const f = deps.fetchImpl ?? globalThis.fetch;
13
+ const headers = {
14
+ Authorization: `Bearer ${req.token}`,
15
+ };
16
+ if (req.body !== undefined)
17
+ headers['Content-Type'] = 'application/json';
18
+ let res;
19
+ try {
20
+ res = await f(url, {
21
+ method: req.method,
22
+ headers,
23
+ body: req.body === undefined ? undefined : JSON.stringify(req.body),
24
+ signal: AbortSignal.timeout(deps.timeoutMs ?? defaultTimeoutMs),
25
+ });
26
+ }
27
+ catch (e) {
28
+ return {
29
+ ok: false,
30
+ status: null,
31
+ message: e instanceof Error ? e.message : String(e),
32
+ };
33
+ }
34
+ let body = null;
35
+ try {
36
+ body = await res.json();
37
+ }
38
+ catch {
39
+ body = null;
40
+ }
41
+ if (res.ok)
42
+ return { ok: true, status: res.status, body };
43
+ return {
44
+ ok: false,
45
+ status: res.status,
46
+ message: errorMessage(body) ?? `HTTP ${res.status}`,
47
+ };
48
+ }
49
+ //# sourceMappingURL=gateway-request.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gateway-request.js","sourceRoot":"","sources":["../../src/api/gateway-request.ts"],"names":[],"mappings":"AAeA,SAAS,YAAY,CAAC,IAAa;IACjC,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IACxD,MAAM,CAAC,GAAI,IAAgC,CAAC,OAAO,CAAC;IACpD,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC;QAAE,OAAO,CAAC,CAAC;IACzC,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtE,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,GAAW,EACX,GAA8D,EAC9D,IAAqB,EACrB,gBAAwB;IAExB,MAAM,CAAC,GAAG,IAAI,CAAC,SAAS,IAAI,UAAU,CAAC,KAAK,CAAC;IAC7C,MAAM,OAAO,GAA2B;QACtC,aAAa,EAAE,UAAU,GAAG,CAAC,KAAK,EAAE;KACrC,CAAC;IACF,IAAI,GAAG,CAAC,IAAI,KAAK,SAAS;QAAE,OAAO,CAAC,cAAc,CAAC,GAAG,kBAAkB,CAAC;IAEzE,IAAI,GAAa,CAAC;IAClB,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,CAAC,CAAC,GAAG,EAAE;YACjB,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,OAAO;YACP,IAAI,EAAE,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC;YACnE,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,IAAI,gBAAgB,CAAC;SAChE,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO;YACL,EAAE,EAAE,KAAK;YACT,MAAM,EAAE,IAAI;YACZ,OAAO,EAAE,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;SACpD,CAAC;IACJ,CAAC;IAED,IAAI,IAAI,GAAY,IAAI,CAAC;IACzB,IAAI,CAAC;QACH,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,IAAI,GAAG,IAAI,CAAC;IACd,CAAC;IACD,IAAI,GAAG,CAAC,EAAE;QAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC;IAC1D,OAAO;QACL,EAAE,EAAE,KAAK;QACT,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,OAAO,EAAE,YAAY,CAAC,IAAI,CAAC,IAAI,QAAQ,GAAG,CAAC,MAAM,EAAE;KACpD,CAAC;AACJ,CAAC"}
@@ -7,7 +7,12 @@
7
7
  * network throw, non-2xx, or malformed JSON — so hook callers stay
8
8
  * fail-open. `null` NEVER means "no results"; it means "could not tell".
9
9
  * An empty result is an empty array.
10
+ *
11
+ * The writes (`createProject`, BACK-230) are the exception: they go through
12
+ * `requestGateway`, which keeps the HTTP status so the caller can tell a
13
+ * 403, a 409 and a 429 apart.
10
14
  */
15
+ import { requestGateway } from './gateway-request.js';
11
16
  const RESOLVE_TIMEOUT_MS = 4_000;
12
17
  const LIST_TIMEOUT_MS = 10_000;
13
18
  /** Unwrap a gateway `{success,data,message}` envelope to its `data`, else the root. */
@@ -155,4 +160,66 @@ export async function listProjects(apiBase, token, orgId, search, deps = {}) {
155
160
  };
156
161
  });
157
162
  }
163
+ const WRITE_TIMEOUT_MS = 30_000;
164
+ /**
165
+ * GET {apiBase}/organization/:id/teams
166
+ *
167
+ * Returns `[{id, name}]` for the teams of the org the caller can see, or
168
+ * `null` on any error. BACK-230.
169
+ */
170
+ export async function listTeams(apiBase, token, orgId, deps = {}) {
171
+ const res = await requestGateway(`${apiBase}/organization/${encodeURIComponent(orgId)}/teams`, { method: 'GET', token }, deps, LIST_TIMEOUT_MS);
172
+ if (!res.ok)
173
+ return null;
174
+ return firstArray(res.body, 'teams')
175
+ .map((raw) => {
176
+ const t = (raw ?? {});
177
+ return { id: str(t.id), name: str(t.name) };
178
+ })
179
+ .filter((t) => t.id !== '');
180
+ }
181
+ /**
182
+ * POST {apiBase}/team/:teamId/project { name, <the four AI flags on> }
183
+ *
184
+ * Every AI feature is sent on, as the dashboard's creation does: an absent
185
+ * one is stored false by the backend, and a project with Cybe Analysis off
186
+ * gets no rule proposals (BACK-250). Each one is turned off in the project
187
+ * settings.
188
+ *
189
+ * Keeps the HTTP status on failure: 403 (not team manager / org admin), 409
190
+ * (name taken in the team), 429 (plan's project limit). BACK-230.
191
+ */
192
+ export async function createProject(apiBase, token, teamId, name, deps = {}) {
193
+ const res = await requestGateway(`${apiBase}/team/${encodeURIComponent(teamId)}/project`, {
194
+ method: 'POST',
195
+ token,
196
+ body: {
197
+ name,
198
+ aiMergeRequestEnabled: true,
199
+ improvingResultsEnabled: true,
200
+ sortsVulnerabilitiesEnabled: true,
201
+ securityChampionEnabled: true,
202
+ },
203
+ }, deps, WRITE_TIMEOUT_MS);
204
+ if (!res.ok)
205
+ return res;
206
+ const data = unwrap(res.body);
207
+ const projectId = str(data.projectId);
208
+ if (!projectId) {
209
+ return {
210
+ ok: false,
211
+ status: null,
212
+ message: 'The gateway answered the creation without a projectId',
213
+ };
214
+ }
215
+ return {
216
+ ok: true,
217
+ project: {
218
+ projectId,
219
+ organizationId: str(data.organizationId),
220
+ teamId: str(data.teamId) || teamId,
221
+ name: str(data.name) || name,
222
+ },
223
+ };
224
+ }
158
225
  //# sourceMappingURL=projects.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"projects.js","sourceRoot":"","sources":["../../src/api/projects.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAsBH,MAAM,kBAAkB,GAAG,KAAK,CAAC;AACjC,MAAM,eAAe,GAAG,MAAM,CAAC;AAE/B,uFAAuF;AACvF,SAAS,MAAM,CAAC,IAAa;IAC3B,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,EAAE,CAAC;IACjD,MAAM,IAAI,GAAG,IAA+B,CAAC;IAC7C,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;IACvB,OAAQ,IAAgC,IAAI,IAAI,CAAC;AACnD,CAAC;AAED,qEAAqE;AACrE,SAAS,UAAU,CAAC,IAAa,EAAE,GAAW;IAC5C,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACrC,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QACrC,MAAM,CAAC,GAAG,IAA+B,CAAC;QAC1C,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;YAAE,OAAO,CAAC,CAAC,IAAI,CAAC;QACzC,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;YAAE,OAAO,CAAC,CAAC,GAAG,CAAc,CAAC;IACxD,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,SAAS,GAAG,CAAC,CAAU;IACrB,OAAO,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAChE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAC9C,OAAe,EACf,KAAa,EACb,CAAoD,EACpD,OAAwB,EAAE;IAE1B,MAAM,CAAC,GAAG,IAAI,CAAC,SAAS,IAAI,UAAU,CAAC,KAAK,CAAC;IAC7C,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAC3E,IAAI,CAAC,CAAC,IAAI;QAAE,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;IACvC,MAAM,GAAG,GAAG,GAAG,OAAO,0BAA0B,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAC;IAEpE,IAAI,GAAa,CAAC;IAClB,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,CAAC,CAAC,GAAG,EAAE;YACjB,MAAM,EAAE,KAAK;YACb,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,KAAK,EAAE,EAAE;YAC7C,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,IAAI,kBAAkB,CAAC;SAClE,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC,GAAG,CAAC,EAAE;QAAE,OAAO,IAAI,CAAC;IAEzB,IAAI,IAAa,CAAC;IAClB,IAAI,CAAC;QACH,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IAC1B,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;IACnE,OAAO,UAAU,CAAC,GAAG,CAAC,CAAC,GAAG,EAAwB,EAAE;QAClD,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,EAAE,CAA4B,CAAC;QACjD,OAAO;YACL,SAAS,EAAE,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;YAC3B,cAAc,EAAE,GAAG,CAAC,CAAC,CAAC,cAAc,CAAC;YACrC,WAAW,EAAE,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC;YAC/B,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC;YACzB,UAAU,EAAE,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC;YAC7B,qEAAqE;YACrE,iBAAiB,EAAE,CAAC,CAAC,iBAAiB,KAAK,KAAK;SACjD,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,OAAe,EACf,KAAa,EACb,OAAwB,EAAE;IAE1B,MAAM,CAAC,GAAG,IAAI,CAAC,SAAS,IAAI,UAAU,CAAC,KAAK,CAAC;IAC7C,MAAM,GAAG,GAAG,GAAG,OAAO,gBAAgB,CAAC;IAEvC,IAAI,GAAa,CAAC;IAClB,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,CAAC,CAAC,GAAG,EAAE;YACjB,MAAM,EAAE,KAAK;YACb,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,KAAK,EAAE,EAAE;YAC7C,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,IAAI,eAAe,CAAC;SAC/D,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC,GAAG,CAAC,EAAE;QAAE,OAAO,IAAI,CAAC;IAEzB,IAAI,IAAa,CAAC;IAClB,IAAI,CAAC;QACH,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,UAAU,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;QACnD,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,EAAE,CAA4B,CAAC;QACjD,OAAO,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;IAC9C,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,OAAe,EACf,KAAa,EACb,KAAa,EACb,MAAe,EACf,OAAwB,EAAE;IAE1B,MAAM,CAAC,GAAG,IAAI,CAAC,SAAS,IAAI,UAAU,CAAC,KAAK,CAAC;IAC7C,IAAI,GAAG,GAAG,GAAG,OAAO,qBAAqB,kBAAkB,CAAC,KAAK,CAAC,WAAW,CAAC;IAC9E,IAAI,MAAM;QAAE,GAAG,IAAI,IAAI,IAAI,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC;IAEpE,IAAI,GAAa,CAAC;IAClB,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,CAAC,CAAC,GAAG,EAAE;YACjB,MAAM,EAAE,KAAK;YACb,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,KAAK,EAAE,EAAE;YAC7C,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,IAAI,eAAe,CAAC;SAC/D,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC,GAAG,CAAC,EAAE;QAAE,OAAO,IAAI,CAAC;IAEzB,IAAI,IAAa,CAAC;IAClB,IAAI,CAAC;QACH,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,UAAU,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;QAC9C,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,EAAE,CAA4B,CAAC;QACjD,OAAO;YACL,SAAS,EAAE,GAAG,CAAC,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,EAAE,CAAC;YACnC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,WAAW,CAAC;SACnC,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"projects.js","sourceRoot":"","sources":["../../src/api/projects.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,157 @@
1
+ /**
2
+ * Link a freshly created project to its GitHub / GitLab repository through
3
+ * the organization's integration (BACK-230). Same outcomes and messages as
4
+ * mcp-service's `create_project` (`modules/discovery/repository-link.ts`).
5
+ *
6
+ * A project carries no repository: the link lives on the integration's
7
+ * repository rows, which only the installed integration creates, and is made
8
+ * by that row's id. Linking starts the first scan. A row that already points
9
+ * at a project is never relinked — GitLab would overwrite it silently.
10
+ *
11
+ * Never rejects: the outcome is reported.
12
+ */
13
+ import { requestGateway } from './gateway-request.js';
14
+ /** The only hosts the integrations cover (GitHub App, GitLab OAuth on gitlab.com). */
15
+ const SAAS_HOSTS = {
16
+ github: 'github.com',
17
+ gitlab: 'gitlab.com',
18
+ };
19
+ const LABEL = {
20
+ github: 'GitHub',
21
+ gitlab: 'GitLab',
22
+ };
23
+ /** The SSH-over-443 hosts of the two forges, folded onto their SaaS host. */
24
+ const HOST_ALIASES = {
25
+ 'ssh.github.com': 'github.com',
26
+ 'altssh.gitlab.com': 'gitlab.com',
27
+ };
28
+ const LIST_TIMEOUT_MS = 10_000;
29
+ // The link creates webhooks and queues the first scan.
30
+ const LINK_TIMEOUT_MS = 60_000;
31
+ function str(v) {
32
+ return typeof v === 'string' ? v : '';
33
+ }
34
+ function toRepository(raw, pathKey) {
35
+ const o = (raw ?? {});
36
+ return { id: str(o.id), path: str(o[pathKey]), projectId: str(o.projectId) };
37
+ }
38
+ /** GitHub: `{ repositories: [{ installationId, repository: [...] }] }`; GitLab: `{ repositories: [...] }`. */
39
+ function readRepositories(provider, body) {
40
+ const list = body?.repositories;
41
+ if (!Array.isArray(list))
42
+ return [];
43
+ if (provider === 'gitlab') {
44
+ return list.map((r) => toRepository(r, 'pathWithNamespace'));
45
+ }
46
+ return list.flatMap((installation) => {
47
+ const repos = installation?.repository;
48
+ return Array.isArray(repos)
49
+ ? repos.map((r) => toRepository(r, 'fullName'))
50
+ : [];
51
+ });
52
+ }
53
+ function forbiddenOutcome(slug) {
54
+ return {
55
+ status: 'forbidden',
56
+ message: 'Linking needs the integration-management right on the organization ' +
57
+ '(organization creator, administrator or manager). Ask one of them to ' +
58
+ `link ${slug} to this project from the dashboard.`,
59
+ };
60
+ }
61
+ /**
62
+ * Find the repository in the organization's integration, without linking
63
+ * anything: the free row to link, or the outcome that stops the link. The
64
+ * create flow calls it before creating, to refuse a repository that is
65
+ * already linked. Never rejects.
66
+ */
67
+ export async function lookupRepository(apiBase, token, organizationId, repository, deps = {}) {
68
+ const { provider, slug } = repository;
69
+ const label = LABEL[provider];
70
+ const org = encodeURIComponent(organizationId);
71
+ const raw = (repository.host || SAAS_HOSTS[provider]).trim().toLowerCase();
72
+ const host = HOST_ALIASES[raw] ?? raw;
73
+ if (host !== SAAS_HOSTS[provider]) {
74
+ return {
75
+ outcome: {
76
+ status: 'unsupported_host',
77
+ message: `${host} is not supported: the CybeDefend ${label} integration only ` +
78
+ `covers ${SAAS_HOSTS[provider]}.`,
79
+ },
80
+ };
81
+ }
82
+ const listUrl = provider === 'github'
83
+ ? `${apiBase}/organization/${org}/github/repositories`
84
+ : `${apiBase}/integrations/gitlab/organization/${org}/repositories`;
85
+ const listed = await requestGateway(listUrl, { method: 'GET', token }, deps, LIST_TIMEOUT_MS);
86
+ if (!listed.ok) {
87
+ if (listed.status === 403)
88
+ return { outcome: forbiddenOutcome(slug) };
89
+ return {
90
+ outcome: {
91
+ status: 'failed',
92
+ message: `Could not list the organization's ${label} repositories (${listed.message}).`,
93
+ },
94
+ };
95
+ }
96
+ const wanted = slug.toLowerCase();
97
+ const matches = readRepositories(provider, listed.body).filter((r) => r.path.toLowerCase() === wanted);
98
+ if (matches.length === 0) {
99
+ return {
100
+ outcome: {
101
+ status: 'not_found',
102
+ message: provider === 'github'
103
+ ? `${slug} is not in the organization's GitHub integration: install the ` +
104
+ 'CybeDefend GitHub App on its owner and give it access to this ' +
105
+ 'repository, then link the project from the dashboard.'
106
+ : `${slug} is not in the organization's GitLab integration: connect GitLab ` +
107
+ "from the dashboard's integrations with an account that can see this " +
108
+ 'repository, then link the project from the dashboard.',
109
+ },
110
+ };
111
+ }
112
+ if (matches.length > 1) {
113
+ return {
114
+ outcome: {
115
+ status: 'failed',
116
+ message: `Several ${label} repositories named ${slug} are in the integration: link the right one from the dashboard.`,
117
+ },
118
+ };
119
+ }
120
+ const [match] = matches;
121
+ if (match.projectId) {
122
+ return {
123
+ outcome: {
124
+ status: 'already_linked',
125
+ linkedProjectId: match.projectId,
126
+ message: `${slug} is already linked to project ${match.projectId} and was not ` +
127
+ 'relinked: use that project, or unlink it from the dashboard first.',
128
+ },
129
+ };
130
+ }
131
+ return { match };
132
+ }
133
+ export async function linkRepositoryToProject(apiBase, token, target, repository, deps = {}) {
134
+ const { provider, slug } = repository;
135
+ const found = await lookupRepository(apiBase, token, target.organizationId, repository, deps);
136
+ if ('outcome' in found)
137
+ return found.outcome;
138
+ const org = encodeURIComponent(target.organizationId);
139
+ const project = encodeURIComponent(target.projectId);
140
+ const linkUrl = provider === 'github'
141
+ ? `${apiBase}/organization/${org}/project/${project}/github/link`
142
+ : `${apiBase}/integrations/gitlab/organization/${org}/project/${project}/link`;
143
+ const linked = await requestGateway(linkUrl, { method: 'POST', token, body: { repositoryId: found.match.id } }, deps, LINK_TIMEOUT_MS);
144
+ if (!linked.ok) {
145
+ if (linked.status === 403)
146
+ return forbiddenOutcome(slug);
147
+ return {
148
+ status: 'failed',
149
+ message: `Could not link ${slug} (${linked.message}).`,
150
+ };
151
+ }
152
+ return {
153
+ status: 'linked',
154
+ message: `${slug} is linked to the project; the first scan of its default branch has started.`,
155
+ };
156
+ }
157
+ //# sourceMappingURL=repository-link.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repository-link.js","sourceRoot":"","sources":["../../src/api/repository-link.ts"],"names":[],"mappings":"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"}
@@ -30,13 +30,28 @@ function accountFor(mcpName) {
30
30
  // ─── Public API ───────────────────────────────────────────────────────────────
31
31
  /** Persist an auth bundle for the given MCP name. */
32
32
  export function storeAuth(mcpName, auth) {
33
- const blob = JSON.stringify(auth);
34
33
  if (process.platform === 'darwin') {
35
- storeMacOSKeychain(mcpName, blob);
36
- }
37
- else {
38
- storeFileFallback(blob);
34
+ try {
35
+ storeMacOSKeychain(mcpName, JSON.stringify(auth));
36
+ }
37
+ catch {
38
+ // NEVER pass execFileSync's error on: its message carries the command
39
+ // line, and so ANY secret in it. That is how BACK-181 leaked (the token
40
+ // bundle printed in clear, then pasted by the user). Swallow it and fall
41
+ // back to the 0600 file, as `loadAuth` does: a HOME without a keychain
42
+ // (CI, managed accounts, E2E harnesses) must be able to sign in instead
43
+ // of failing hard. The message is reworded with no data in it.
44
+ process.stderr.write('vibedefend: macOS keychain unavailable, credentials stored in ~/.cybedefend/auth.json (mode 0600).\n');
45
+ storeFileFallback(mcpName, auth);
46
+ return;
47
+ }
48
+ // The keychain holds the bundle now: drop the plaintext copy a failed
49
+ // write may have left in the file (an older refresh token, readable on
50
+ // disk until the next logout otherwise).
51
+ removeFileFallback(mcpName, auth);
52
+ return;
39
53
  }
54
+ storeFileFallback(mcpName, auth);
40
55
  }
41
56
  /**
42
57
  * Load the stored auth bundle for the given MCP name.
@@ -50,7 +65,7 @@ export function loadAuth(mcpName) {
50
65
  // File fallback — also checked on Linux/Windows and as fallback on macOS
51
66
  // when the keychain entry is absent.
52
67
  if (!blob)
53
- blob = readFileFallback();
68
+ blob = readFileFallback(mcpName);
54
69
  if (!blob)
55
70
  return null;
56
71
  try {
@@ -87,15 +102,7 @@ export function clearAuth(mcpName) {
87
102
  }
88
103
  }
89
104
  // Also clear the file fallback (it may hold an older copy on non-macOS).
90
- const filePath = fileFallbackPath();
91
- if (existsSync(filePath)) {
92
- try {
93
- writeFileSync(filePath, '', { mode: 0o600 });
94
- }
95
- catch {
96
- // Best-effort.
97
- }
98
- }
105
+ removeFileFallback(mcpName);
99
106
  }
100
107
  // ─── macOS Keychain helpers ───────────────────────────────────────────────────
101
108
  function storeMacOSKeychain(mcpName, blob) {
@@ -111,6 +118,18 @@ function storeMacOSKeychain(mcpName, blob) {
111
118
  catch {
112
119
  // Not found — that is fine.
113
120
  }
121
+ // KNOWN RESIDUE (BACK-181): the blob is passed as the `-w` argument, so any
122
+ // local process can read it in `ps` for the duration of the call. There is no
123
+ // safe way to take it out of argv here: the stdin prompt of `security -w`
124
+ // reads the password through readpassphrase(), capped at PASS_MAX = 128
125
+ // bytes, and it silently TRUNCATES a real bundle (a JWT access token alone is
126
+ // longer than 128), which breaks the storage. The batch mode `security -i`
127
+ // would avoid argv but would need the blob re-encoded (base64), and the item
128
+ // is shared with the Codex reader (`resolveTokenCodexMacOS`), which expects
129
+ // raw JSON: changing it would break that compatibility. The argv window is
130
+ // short and local; the leaks that mattered (error message, hard failure) are
131
+ // closed in `storeAuth`. Taking the secret out of argv is still open (see the
132
+ // ticket).
114
133
  execFileSync('security', [
115
134
  'add-generic-password',
116
135
  '-s', KEYCHAIN_SERVICE,
@@ -136,15 +155,43 @@ function readMacOSKeychain(mcpName) {
136
155
  return null;
137
156
  }
138
157
  }
139
- // ─── File fallback (Linux / Windows) ─────────────────────────────────────────
140
158
  function fileFallbackPath() {
141
159
  return join(homedir(), '.cybedefend', 'auth.json');
142
160
  }
143
- function storeFileFallback(blob) {
161
+ function readFallbackFile() {
162
+ const p = fileFallbackPath();
163
+ if (!existsSync(p))
164
+ return { kind: 'none' };
165
+ let content;
166
+ try {
167
+ content = readFileSync(p, 'utf8');
168
+ }
169
+ catch {
170
+ return { kind: 'none' };
171
+ }
172
+ if (content.trim().length === 0)
173
+ return { kind: 'none' };
174
+ try {
175
+ const parsed = JSON.parse(content);
176
+ if (parsed !== null &&
177
+ typeof parsed === 'object' &&
178
+ parsed.version === 2 &&
179
+ parsed.bundles !== null &&
180
+ typeof parsed.bundles === 'object') {
181
+ return { kind: 'per-region', bundles: parsed.bundles };
182
+ }
183
+ }
184
+ catch {
185
+ // Not JSON: `loadAuth` rejects it below, as before.
186
+ }
187
+ return { kind: 'legacy', blob: content };
188
+ }
189
+ function writeFallbackFile(bundles) {
144
190
  const dir = join(homedir(), '.cybedefend');
145
191
  mkdirSync(dir, { recursive: true });
146
192
  const p = fileFallbackPath();
147
- writeFileSync(p, blob, { mode: 0o600 });
193
+ const content = Object.keys(bundles).length === 0 ? '' : JSON.stringify({ version: 2, bundles });
194
+ writeFileSync(p, content, { mode: 0o600 });
148
195
  try {
149
196
  // Belt-and-suspenders: explicitly chmod after write (some umask configs
150
197
  // ignore the mode option on writeFileSync).
@@ -154,16 +201,51 @@ function storeFileFallback(blob) {
154
201
  // Non-fatal on Windows (no POSIX perms).
155
202
  }
156
203
  }
157
- function readFileFallback() {
158
- const p = fileFallbackPath();
159
- if (!existsSync(p))
160
- return null;
204
+ function storeFileFallback(mcpName, auth) {
205
+ const current = readFallbackFile();
206
+ // A legacy bare bundle is replaced: it was this machine's previous sign-in,
207
+ // and nothing says which region it belonged to.
208
+ const bundles = current.kind === 'per-region' ? { ...current.bundles } : {};
209
+ bundles[mcpName] = auth;
210
+ writeFallbackFile(bundles);
211
+ }
212
+ function readFileFallback(mcpName) {
213
+ const current = readFallbackFile();
214
+ if (current.kind === 'per-region') {
215
+ const bundle = current.bundles[mcpName];
216
+ return bundle === undefined ? null : JSON.stringify(bundle);
217
+ }
218
+ return current.kind === 'legacy' ? current.blob : null;
219
+ }
220
+ /**
221
+ * Remove `mcpName`'s bundle from the file. A legacy bare bundle is removed by
222
+ * a sign-out (no `replacedBy`), or when it is the same sign-in the keychain
223
+ * now holds (same Logto app and resource). Best-effort: never throws.
224
+ */
225
+ function removeFileFallback(mcpName, replacedBy) {
161
226
  try {
162
- const content = readFileSync(p, 'utf8');
163
- return content || null;
227
+ const current = readFallbackFile();
228
+ if (current.kind === 'per-region') {
229
+ if (!(mcpName in current.bundles))
230
+ return;
231
+ const rest = { ...current.bundles };
232
+ delete rest[mcpName];
233
+ writeFallbackFile(rest);
234
+ return;
235
+ }
236
+ if (current.kind !== 'legacy')
237
+ return;
238
+ if (replacedBy !== undefined) {
239
+ const legacy = JSON.parse(current.blob);
240
+ if (legacy.cliAppId !== replacedBy.cliAppId ||
241
+ legacy.logtoResource !== replacedBy.logtoResource) {
242
+ return;
243
+ }
244
+ }
245
+ writeFallbackFile({});
164
246
  }
165
247
  catch {
166
- return null;
248
+ // Best-effort: a stale copy is better than a failed sign-in or sign-out.
167
249
  }
168
250
  }
169
251
  //# sourceMappingURL=auth-store.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"auth-store.js","sourceRoot":"","sources":["../../src/auth/auth-store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"auth-store.js","sourceRoot":"","sources":["../../src/auth/auth-store.ts"],"names":[],"mappings":"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"}