@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.
- package/README.md +67 -2
- package/dist/api/gateway-request.js +49 -0
- package/dist/api/gateway-request.js.map +1 -0
- package/dist/api/projects.js +67 -0
- package/dist/api/projects.js.map +1 -1
- package/dist/api/repository-link.js +157 -0
- package/dist/api/repository-link.js.map +1 -0
- package/dist/auth/auth-store.js +107 -25
- package/dist/auth/auth-store.js.map +1 -1
- package/dist/auth/auth.js +21 -0
- package/dist/auth/auth.js.map +1 -1
- package/dist/clients/cursor.js +5 -1
- package/dist/clients/cursor.js.map +1 -1
- package/dist/clients/vscode.js +38 -29
- package/dist/clients/vscode.js.map +1 -1
- package/dist/commands/mcp/allow.js +219 -0
- package/dist/commands/mcp/allow.js.map +1 -0
- package/dist/commands/mcp/connect.js +337 -0
- package/dist/commands/mcp/connect.js.map +1 -0
- package/dist/commands/mcp/index.js +170 -0
- package/dist/commands/mcp/index.js.map +1 -0
- package/dist/commands/mcp/proxy.js +264 -0
- package/dist/commands/mcp/proxy.js.map +1 -0
- package/dist/commands/mcp/scan.js +349 -0
- package/dist/commands/mcp/scan.js.map +1 -0
- package/dist/commands/mcp/sync.js +215 -0
- package/dist/commands/mcp/sync.js.map +1 -0
- package/dist/config.js +6 -0
- package/dist/config.js.map +1 -1
- package/dist/diagnostics.js +78 -12
- package/dist/diagnostics.js.map +1 -1
- package/dist/doctor.js +19 -0
- package/dist/doctor.js.map +1 -1
- package/dist/guards-evaluator/analysis-types.js +27 -0
- package/dist/guards-evaluator/analysis-types.js.map +1 -0
- package/dist/guards-evaluator/command-analysis.js +572 -0
- package/dist/guards-evaluator/command-analysis.js.map +1 -0
- package/dist/guards-evaluator/command-view.js +586 -0
- package/dist/guards-evaluator/command-view.js.map +1 -0
- package/dist/guards-evaluator/env.js +11 -0
- package/dist/guards-evaluator/env.js.map +1 -0
- package/dist/guards-evaluator/evaluate.js +91 -41
- package/dist/guards-evaluator/evaluate.js.map +1 -1
- package/dist/guards-evaluator/index.js +2 -1
- package/dist/guards-evaluator/index.js.map +1 -1
- package/dist/guards-evaluator/inline-code.js +259 -0
- package/dist/guards-evaluator/inline-code.js.map +1 -0
- package/dist/guards-evaluator/normalize.js +716 -0
- package/dist/guards-evaluator/normalize.js.map +1 -0
- package/dist/guards-evaluator/preprocess.js +13 -5
- package/dist/guards-evaluator/preprocess.js.map +1 -1
- package/dist/guards-evaluator/redact.js +19 -0
- package/dist/guards-evaluator/redact.js.map +1 -1
- package/dist/guards-evaluator/regex.js +25 -3
- package/dist/guards-evaluator/regex.js.map +1 -1
- package/dist/guards-evaluator/safe-commands.js +155 -0
- package/dist/guards-evaluator/safe-commands.js.map +1 -0
- package/dist/guards-evaluator/triage.js +315 -0
- package/dist/guards-evaluator/triage.js.map +1 -0
- package/dist/hook-runner.js +24679 -5079
- package/dist/hooks/install.js +38 -0
- package/dist/hooks/install.js.map +1 -1
- package/dist/hooks/runtime/config.js +38 -0
- package/dist/hooks/runtime/config.js.map +1 -1
- package/dist/hooks/runtime/emit.js +94 -61
- package/dist/hooks/runtime/emit.js.map +1 -1
- package/dist/hooks/runtime/fetch-rules.js +22 -7
- package/dist/hooks/runtime/fetch-rules.js.map +1 -1
- package/dist/hooks/runtime/gateway-http-error.js +34 -0
- package/dist/hooks/runtime/gateway-http-error.js.map +1 -0
- package/dist/hooks/runtime/guard-rules-cache.js +139 -17
- package/dist/hooks/runtime/guard-rules-cache.js.map +1 -1
- package/dist/hooks/runtime/guard-violations-buffer.js +321 -48
- package/dist/hooks/runtime/guard-violations-buffer.js.map +1 -1
- package/dist/hooks/runtime/judge-cache.js +6 -0
- package/dist/hooks/runtime/judge-cache.js.map +1 -1
- package/dist/hooks/runtime/judge-triage.js +193 -0
- package/dist/hooks/runtime/judge-triage.js.map +1 -0
- package/dist/hooks/runtime/judge.js +7 -1
- package/dist/hooks/runtime/judge.js.map +1 -1
- package/dist/hooks/runtime/pre-compact.js +12 -6
- package/dist/hooks/runtime/pre-compact.js.map +1 -1
- package/dist/hooks/runtime/resolve.js +90 -8
- package/dist/hooks/runtime/resolve.js.map +1 -1
- package/dist/hooks/runtime/retry-policy.js +57 -0
- package/dist/hooks/runtime/retry-policy.js.map +1 -0
- package/dist/hooks/runtime/review-sessions.js +74 -0
- package/dist/hooks/runtime/review-sessions.js.map +1 -0
- package/dist/hooks/runtime/script-resolve.js +695 -0
- package/dist/hooks/runtime/script-resolve.js.map +1 -0
- package/dist/hooks/runtime/session-activation.js +5 -1
- package/dist/hooks/runtime/session-activation.js.map +1 -1
- package/dist/hooks/runtime/session-review.js +163 -45
- package/dist/hooks/runtime/session-review.js.map +1 -1
- package/dist/hooks/runtime/session-start.js +2 -1
- package/dist/hooks/runtime/session-start.js.map +1 -1
- package/dist/hooks/runtime/session-writes.js +232 -0
- package/dist/hooks/runtime/session-writes.js.map +1 -0
- package/dist/hooks/runtime/sniff.js +26 -7
- package/dist/hooks/runtime/sniff.js.map +1 -1
- package/dist/hooks/runtime/target-resolve.js +336 -0
- package/dist/hooks/runtime/target-resolve.js.map +1 -0
- package/dist/hooks/runtime/unmapped-tools.js +93 -0
- package/dist/hooks/runtime/unmapped-tools.js.map +1 -0
- package/dist/hooks/runtime/usage-block.js +4 -0
- package/dist/hooks/runtime/usage-block.js.map +1 -1
- package/dist/hooks/runtime/user-prompt-submit.js +2 -1
- package/dist/hooks/runtime/user-prompt-submit.js.map +1 -1
- package/dist/hooks/runtime/wire-text.js +41 -0
- package/dist/hooks/runtime/wire-text.js.map +1 -0
- package/dist/hooks/runtime/work-dir.js +84 -0
- package/dist/hooks/runtime/work-dir.js.map +1 -0
- package/dist/index.js +45 -12
- package/dist/index.js.map +1 -1
- package/dist/install.js +174 -11
- package/dist/install.js.map +1 -1
- package/dist/link.js +74 -48
- package/dist/link.js.map +1 -1
- package/dist/login.js +77 -11
- package/dist/login.js.map +1 -1
- package/dist/mcp/auth/agent-sign-ins.js +174 -0
- package/dist/mcp/auth/agent-sign-ins.js.map +1 -0
- package/dist/mcp/auth/callback.js +200 -0
- package/dist/mcp/auth/callback.js.map +1 -0
- package/dist/mcp/auth/connect.js +392 -0
- package/dist/mcp/auth/connect.js.map +1 -0
- package/dist/mcp/auth/discovery.js +399 -0
- package/dist/mcp/auth/discovery.js.map +1 -0
- package/dist/mcp/auth/oauth.js +326 -0
- package/dist/mcp/auth/oauth.js.map +1 -0
- package/dist/mcp/auth/probe.js +128 -0
- package/dist/mcp/auth/probe.js.map +1 -0
- package/dist/mcp/auth/secrets.js +446 -0
- package/dist/mcp/auth/secrets.js.map +1 -0
- package/dist/mcp/auth/store.js +260 -0
- package/dist/mcp/auth/store.js.map +1 -0
- package/dist/mcp/auth/tokenSource.js +55 -0
- package/dist/mcp/auth/tokenSource.js.map +1 -0
- package/dist/mcp/config/atomicWrite.js +98 -0
- package/dist/mcp/config/atomicWrite.js.map +1 -0
- package/dist/mcp/config/clients.js +171 -0
- package/dist/mcp/config/clients.js.map +1 -0
- package/dist/mcp/config/cybedefend-servers.js +48 -0
- package/dist/mcp/config/cybedefend-servers.js.map +1 -0
- package/dist/mcp/config/discover.js +114 -0
- package/dist/mcp/config/discover.js.map +1 -0
- package/dist/mcp/config/hook.js +123 -0
- package/dist/mcp/config/hook.js.map +1 -0
- package/dist/mcp/config/index.js +11 -0
- package/dist/mcp/config/index.js.map +1 -0
- package/dist/mcp/config/install.js +132 -0
- package/dist/mcp/config/install.js.map +1 -0
- package/dist/mcp/config/installed.js +37 -0
- package/dist/mcp/config/installed.js.map +1 -0
- package/dist/mcp/config/jsonEdit.js +119 -0
- package/dist/mcp/config/jsonEdit.js.map +1 -0
- package/dist/mcp/config/lock.js +102 -0
- package/dist/mcp/config/lock.js.map +1 -0
- package/dist/mcp/config/proxyBinary.js +211 -0
- package/dist/mcp/config/proxyBinary.js.map +1 -0
- package/dist/mcp/config/rewrite.js +388 -0
- package/dist/mcp/config/rewrite.js.map +1 -0
- package/dist/mcp/config/types.js +34 -0
- package/dist/mcp/config/types.js.map +1 -0
- package/dist/mcp/proxy/audit.js +83 -0
- package/dist/mcp/proxy/audit.js.map +1 -0
- package/dist/mcp/proxy/authInterceptor.js +119 -0
- package/dist/mcp/proxy/authInterceptor.js.map +1 -0
- package/dist/mcp/proxy/expand.js +93 -0
- package/dist/mcp/proxy/expand.js.map +1 -0
- package/dist/mcp/proxy/inject.js +397 -0
- package/dist/mcp/proxy/inject.js.map +1 -0
- package/dist/mcp/proxy/intercept.js +37 -0
- package/dist/mcp/proxy/intercept.js.map +1 -0
- package/dist/mcp/proxy/jsonrpc.js +153 -0
- package/dist/mcp/proxy/jsonrpc.js.map +1 -0
- package/dist/mcp/proxy/log.js +109 -0
- package/dist/mcp/proxy/log.js.map +1 -0
- package/dist/mcp/proxy/paths.js +53 -0
- package/dist/mcp/proxy/paths.js.map +1 -0
- package/dist/mcp/proxy/proxy.js +510 -0
- package/dist/mcp/proxy/proxy.js.map +1 -0
- package/dist/mcp/proxy/spec.js +203 -0
- package/dist/mcp/proxy/spec.js.map +1 -0
- package/dist/mcp/proxy/sse.js +77 -0
- package/dist/mcp/proxy/sse.js.map +1 -0
- package/dist/mcp/proxy/upstream.js +2 -0
- package/dist/mcp/proxy/upstream.js.map +1 -0
- package/dist/mcp/proxy/upstreamHttp.js +499 -0
- package/dist/mcp/proxy/upstreamHttp.js.map +1 -0
- package/dist/mcp/proxy/upstreamStdio.js +188 -0
- package/dist/mcp/proxy/upstreamStdio.js.map +1 -0
- package/dist/mcp/proxy/upstreams.js +143 -0
- package/dist/mcp/proxy/upstreams.js.map +1 -0
- package/dist/mcp/proxy/verifyInterceptor.js +559 -0
- package/dist/mcp/proxy/verifyInterceptor.js.map +1 -0
- package/dist/mcp/proxy/windowsCommand.js +99 -0
- package/dist/mcp/proxy/windowsCommand.js.map +1 -0
- package/dist/mcp/scan/args.js +228 -0
- package/dist/mcp/scan/args.js.map +1 -0
- package/dist/mcp/scan/results.js +253 -0
- package/dist/mcp/scan/results.js.map +1 -0
- package/dist/mcp/scan/types.js +40 -0
- package/dist/mcp/scan/types.js.map +1 -0
- package/dist/mcp/verify/api.js +475 -0
- package/dist/mcp/verify/api.js.map +1 -0
- package/dist/mcp/verify/backend.js +143 -0
- package/dist/mcp/verify/backend.js.map +1 -0
- package/dist/mcp/verify/cache.js +182 -0
- package/dist/mcp/verify/cache.js.map +1 -0
- package/dist/mcp/verify/contract-errors.js +198 -0
- package/dist/mcp/verify/contract-errors.js.map +1 -0
- package/dist/mcp/verify/digest.js +91 -0
- package/dist/mcp/verify/digest.js.map +1 -0
- package/dist/mcp/verify/factory.js +56 -0
- package/dist/mcp/verify/factory.js.map +1 -0
- package/dist/mcp/verify/identity.js +173 -0
- package/dist/mcp/verify/identity.js.map +1 -0
- package/dist/mcp/verify/policy-store.js +63 -0
- package/dist/mcp/verify/policy-store.js.map +1 -0
- package/dist/mcp/verify/policy.js +158 -0
- package/dist/mcp/verify/policy.js.map +1 -0
- package/dist/mcp/verify/pool.js +27 -0
- package/dist/mcp/verify/pool.js.map +1 -0
- package/dist/mcp/verify/token-refresh.js +44 -0
- package/dist/mcp/verify/token-refresh.js.map +1 -0
- package/dist/mcp/verify/token.js +67 -0
- package/dist/mcp/verify/token.js.map +1 -0
- package/dist/mcp/verify/verifier.js +1009 -0
- package/dist/mcp/verify/verifier.js.map +1 -0
- package/dist/org-gate.js +1 -1
- package/dist/org-gate.js.map +1 -1
- package/dist/org.js +146 -0
- package/dist/org.js.map +1 -0
- package/dist/project-create.js +129 -0
- package/dist/project-create.js.map +1 -0
- package/dist/prompts.js +21 -0
- package/dist/prompts.js.map +1 -1
- package/dist/re2.wasm +0 -0
- package/dist/status.js +61 -0
- package/dist/status.js.map +1 -1
- package/dist/uninstall.js +49 -4
- package/dist/uninstall.js.map +1 -1
- package/dist/utils.js +62 -6
- package/dist/utils.js.map +1 -1
- package/package.json +10 -3
package/README.md
CHANGED
|
@@ -27,7 +27,15 @@ 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.
|
|
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.
|
|
35
|
+
6. **MCP sign-ins** — the sign-ins Claude Code or Codex already hold for
|
|
36
|
+
those servers are taken over on their own. Your browser opens only for the
|
|
37
|
+
servers left without one, if you say yes (or later:
|
|
38
|
+
`vibedefend connect --all`).
|
|
31
39
|
|
|
32
40
|
Run through `npx` (or `pnpm dlx` / `yarn dlx`), the installer first installs
|
|
33
41
|
the CLI globally (`npm install -g @cybedefend/vibedefend`), so the
|
|
@@ -125,12 +133,18 @@ For any other repo (no remote, a mirror, a monorepo subfolder, an
|
|
|
125
133
|
unimported project…), link it once:
|
|
126
134
|
|
|
127
135
|
```bash
|
|
128
|
-
vibedefend link # interactive: auto-detect,
|
|
136
|
+
vibedefend link # interactive: auto-detect, pick org → project, or create one
|
|
129
137
|
vibedefend link --project <uuid> # non-interactive, if you know the project UUID
|
|
130
138
|
# or without a global install:
|
|
131
139
|
npx -y @cybedefend/vibedefend@latest link --project <PROJECT_ID>
|
|
132
140
|
```
|
|
133
141
|
|
|
142
|
+
No project yet? `link` offers to create one (team managers and organization
|
|
143
|
+
administrators can). When `origin` is a github.com / gitlab.com repository
|
|
144
|
+
that the organization's GitHub App / GitLab integration can see, the new
|
|
145
|
+
project is linked to it and its first scan starts; otherwise start a first
|
|
146
|
+
scan from the dashboard.
|
|
147
|
+
|
|
134
148
|
`link` writes a `.cybedefend/config.json` next to your code:
|
|
135
149
|
|
|
136
150
|
```json
|
|
@@ -141,6 +155,16 @@ That file is now **optional** for GitHub/GitLab-linked projects, but it
|
|
|
141
155
|
remains a supported override everywhere — when present, it always wins over
|
|
142
156
|
git-origin auto-resolution (as does the `CYBEDEFEND_PROJECT_ID` env var).
|
|
143
157
|
|
|
158
|
+
The project is read from the directory your agent works in, as its client
|
|
159
|
+
reports it (Cursor: the workspace root). When the agent writes a file of
|
|
160
|
+
another repository, such as another git worktree or clone, the rules for that
|
|
161
|
+
file come from that repository's project, or from the agent's project when
|
|
162
|
+
that repository has none. Action Guards always use the agent's directory.
|
|
163
|
+
|
|
164
|
+
`link` also adds `.cybedefend/` to the directory's `.gitignore` (idempotent):
|
|
165
|
+
the link describes *your* checkout, not the code. Remove the line if your team
|
|
166
|
+
prefers to share it — the hooks read the file either way.
|
|
167
|
+
|
|
144
168
|
**Folders that are not CybeDefend projects.** The hooks are installed for
|
|
145
169
|
every folder your agent opens. When a session starts in a folder with no
|
|
146
170
|
`.cybedefend/config.json` and no project linked to its GitHub/GitLab `origin`
|
|
@@ -164,6 +188,47 @@ You can grab the UUID from the project page on the EU dashboard
|
|
|
164
188
|
([eu.cybedefend.com](https://eu.cybedefend.com)) or the US dashboard
|
|
165
189
|
([us.cybedefend.com](https://us.cybedefend.com)).
|
|
166
190
|
|
|
191
|
+
## Where VibeDefend is active
|
|
192
|
+
|
|
193
|
+
The hooks are wired **globally** (one `~/.claude/settings.json`, one
|
|
194
|
+
`~/.codex/hooks.json`, …), so the question is which repos they act on. The
|
|
195
|
+
installer asks:
|
|
196
|
+
|
|
197
|
+
| Mode | Behaviour |
|
|
198
|
+
|---|---|
|
|
199
|
+
| `auto` (default) | Every repo that resolves to a CybeDefend project — via `.cybedefend/config.json`, `CYBEDEFEND_PROJECT_ID`, or git-origin auto-discovery. |
|
|
200
|
+
| `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. |
|
|
201
|
+
|
|
202
|
+
The choice lives in `~/.cybedefend/runtime-config.json` (`hooks.activation`);
|
|
203
|
+
re-run `vibedefend install` to change it, or override it per shell with
|
|
204
|
+
`CYBEDEFEND_ACTIVATION=auto|opt-in`. `vibedefend status` shows the effective mode.
|
|
205
|
+
|
|
206
|
+
## Action Guards — how commands are read
|
|
207
|
+
|
|
208
|
+
The guard evaluates a Bash command **by shell position**, not by substring
|
|
209
|
+
(BACK-174): a heredoc written to a file, a URL query string (`&su=…`), quoted
|
|
210
|
+
data (`echo "a && su"`) or code handed to a non-shell interpreter
|
|
211
|
+
(`python3 -c "…"`) can no longer trip a rule meant for a command word, while
|
|
212
|
+
`su -`, `…; su -`, `bash -c "…; su -"` and `curl … | bash` on any line of a
|
|
213
|
+
shell heredoc are still blocked.
|
|
214
|
+
|
|
215
|
+
Scripts the agent writes in its **own harness scratchpad** —
|
|
216
|
+
`/tmp/claude-<uid>/…`, `/private/tmp/claude-<uid>/…` and the Codex / Cursor /
|
|
217
|
+
Windsurf / Copilot equivalents — are not "executed from /tmp". Add your own
|
|
218
|
+
prefixes with `CYBEDEFEND_SCRATCH_DIRS` (`PATH`-style list).
|
|
219
|
+
|
|
220
|
+
Tool calls the guard cannot map to a file, command or URL are **allowed
|
|
221
|
+
fail-open**. Tools that carry no target by construction (`ToolSearch`, todo
|
|
222
|
+
lists, sub-agents, the `mcp__cybedefend__*` tools) pass silently; anything
|
|
223
|
+
else is counted in `~/.cybedefend/guards-unmapped-tools.json`, announced once
|
|
224
|
+
per session on stderr, and listed by `vibedefend status`. Set
|
|
225
|
+
`CYBEDEFEND_GUARDS_STRICT=1` to block those instead.
|
|
226
|
+
|
|
227
|
+
Rule regexes run on RE2 (linear time, no ReDoS): the engine is bundled into
|
|
228
|
+
the hook runner and `re2.wasm` ships next to it for every install shape. If a
|
|
229
|
+
hook ever reports `RE2 engine unavailable`, run `vibedefend doctor` — it
|
|
230
|
+
restores the missing binary.
|
|
231
|
+
|
|
167
232
|
## Updating
|
|
168
233
|
|
|
169
234
|
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"}
|
package/dist/api/projects.js
CHANGED
|
@@ -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
|
package/dist/api/projects.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"projects.js","sourceRoot":"","sources":["../../src/api/projects.ts"],"names":[],"mappings":"AAAA
|
|
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":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAoBtD,sFAAsF;AACtF,MAAM,UAAU,GAAuC;IACrD,MAAM,EAAE,YAAY;IACpB,MAAM,EAAE,YAAY;CACrB,CAAC;AACF,MAAM,KAAK,GAAuC;IAChD,MAAM,EAAE,QAAQ;IAChB,MAAM,EAAE,QAAQ;CACjB,CAAC;AACF,6EAA6E;AAC7E,MAAM,YAAY,GAA2B;IAC3C,gBAAgB,EAAE,YAAY;IAC9B,mBAAmB,EAAE,YAAY;CAClC,CAAC;AACF,MAAM,eAAe,GAAG,MAAM,CAAC;AAC/B,uDAAuD;AACvD,MAAM,eAAe,GAAG,MAAM,CAAC;AAe/B,SAAS,GAAG,CAAC,CAAU;IACrB,OAAO,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACxC,CAAC;AAED,SAAS,YAAY,CAAC,GAAY,EAAE,OAAe;IACjD,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,EAAE,CAA4B,CAAC;IACjD,OAAO,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,SAAS,EAAE,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC;AAC/E,CAAC;AAED,8GAA8G;AAC9G,SAAS,gBAAgB,CACvB,QAA4B,EAC5B,IAAa;IAEb,MAAM,IAAI,GAAI,IAA0C,EAAE,YAAY,CAAC;IACvE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IACpC,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC1B,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,mBAAmB,CAAC,CAAC,CAAC;IAC/D,CAAC;IACD,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,YAAY,EAAE,EAAE;QACnC,MAAM,KAAK,GAAI,YAAgD,EAAE,UAAU,CAAC;QAC5E,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;YACzB,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC;YAC/C,CAAC,CAAC,EAAE,CAAC;IACT,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,gBAAgB,CAAC,IAAY;IACpC,OAAO;QACL,MAAM,EAAE,WAAW;QACnB,OAAO,EACL,qEAAqE;YACrE,uEAAuE;YACvE,QAAQ,IAAI,sCAAsC;KACrD,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,OAAe,EACf,KAAa,EACb,cAAsB,EACtB,UAAyB,EACzB,OAAwB,EAAE;IAE1B,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,UAAU,CAAC;IACtC,MAAM,KAAK,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC;IAC9B,MAAM,GAAG,GAAG,kBAAkB,CAAC,cAAc,CAAC,CAAC;IAE/C,MAAM,GAAG,GAAG,CAAC,UAAU,CAAC,IAAI,IAAI,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC3E,MAAM,IAAI,GAAG,YAAY,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC;IACtC,IAAI,IAAI,KAAK,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAClC,OAAO;YACL,OAAO,EAAE;gBACP,MAAM,EAAE,kBAAkB;gBAC1B,OAAO,EACL,GAAG,IAAI,qCAAqC,KAAK,oBAAoB;oBACrE,UAAU,UAAU,CAAC,QAAQ,CAAC,GAAG;aACpC;SACF,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GACX,QAAQ,KAAK,QAAQ;QACnB,CAAC,CAAC,GAAG,OAAO,iBAAiB,GAAG,sBAAsB;QACtD,CAAC,CAAC,GAAG,OAAO,qCAAqC,GAAG,eAAe,CAAC;IACxE,MAAM,MAAM,GAAG,MAAM,cAAc,CACjC,OAAO,EACP,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,EACxB,IAAI,EACJ,eAAe,CAChB,CAAC;IACF,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;QACf,IAAI,MAAM,CAAC,MAAM,KAAK,GAAG;YAAE,OAAO,EAAE,OAAO,EAAE,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC;QACtE,OAAO;YACL,OAAO,EAAE;gBACP,MAAM,EAAE,QAAQ;gBAChB,OAAO,EAAE,qCAAqC,KAAK,kBAAkB,MAAM,CAAC,OAAO,IAAI;aACxF;SACF,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IAClC,MAAM,OAAO,GAAG,gBAAgB,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,CAC5D,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,MAAM,CACvC,CAAC;IACF,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO;YACL,OAAO,EAAE;gBACP,MAAM,EAAE,WAAW;gBACnB,OAAO,EACL,QAAQ,KAAK,QAAQ;oBACnB,CAAC,CAAC,GAAG,IAAI,gEAAgE;wBACvE,gEAAgE;wBAChE,uDAAuD;oBACzD,CAAC,CAAC,GAAG,IAAI,mEAAmE;wBAC1E,sEAAsE;wBACtE,uDAAuD;aAC9D;SACF,CAAC;IACJ,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO;YACL,OAAO,EAAE;gBACP,MAAM,EAAE,QAAQ;gBAChB,OAAO,EAAE,WAAW,KAAK,uBAAuB,IAAI,iEAAiE;aACtH;SACF,CAAC;IACJ,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC;IACxB,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;QACpB,OAAO;YACL,OAAO,EAAE;gBACP,MAAM,EAAE,gBAAgB;gBACxB,eAAe,EAAE,KAAK,CAAC,SAAS;gBAChC,OAAO,EACL,GAAG,IAAI,iCAAiC,KAAK,CAAC,SAAS,eAAe;oBACtE,oEAAoE;aACvE;SACF,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,CAAC;AACnB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,OAAe,EACf,KAAa,EACb,MAAqD,EACrD,UAAyB,EACzB,OAAwB,EAAE;IAE1B,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,UAAU,CAAC;IACtC,MAAM,KAAK,GAAG,MAAM,gBAAgB,CAClC,OAAO,EACP,KAAK,EACL,MAAM,CAAC,cAAc,EACrB,UAAU,EACV,IAAI,CACL,CAAC;IACF,IAAI,SAAS,IAAI,KAAK;QAAE,OAAO,KAAK,CAAC,OAAO,CAAC;IAE7C,MAAM,GAAG,GAAG,kBAAkB,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;IACtD,MAAM,OAAO,GAAG,kBAAkB,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACrD,MAAM,OAAO,GACX,QAAQ,KAAK,QAAQ;QACnB,CAAC,CAAC,GAAG,OAAO,iBAAiB,GAAG,YAAY,OAAO,cAAc;QACjE,CAAC,CAAC,GAAG,OAAO,qCAAqC,GAAG,YAAY,OAAO,OAAO,CAAC;IACnF,MAAM,MAAM,GAAG,MAAM,cAAc,CACjC,OAAO,EACP,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,YAAY,EAAE,KAAK,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,EACjE,IAAI,EACJ,eAAe,CAChB,CAAC;IACF,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;QACf,IAAI,MAAM,CAAC,MAAM,KAAK,GAAG;YAAE,OAAO,gBAAgB,CAAC,IAAI,CAAC,CAAC;QACzD,OAAO;YACL,MAAM,EAAE,QAAQ;YAChB,OAAO,EAAE,kBAAkB,IAAI,KAAK,MAAM,CAAC,OAAO,IAAI;SACvD,CAAC;IACJ,CAAC;IACD,OAAO;QACL,MAAM,EAAE,QAAQ;QAChB,OAAO,EAAE,GAAG,IAAI,8EAA8E;KAC/F,CAAC;AACJ,CAAC"}
|
package/dist/auth/auth-store.js
CHANGED
|
@@ -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
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
158
|
-
const
|
|
159
|
-
|
|
160
|
-
|
|
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
|
|
163
|
-
|
|
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
|
-
|
|
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":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EACL,UAAU,EACV,YAAY,EACZ,aAAa,EACb,SAAS,EACT,SAAS,GACV,MAAM,SAAS,CAAC;AA0BjB,gFAAgF;AAEhF,MAAM,gBAAgB,GAAG,uBAAuB,CAAC;AAEjD,6CAA6C;AAC7C,SAAS,UAAU,CAAC,OAAe;IACjC,OAAO,GAAG,OAAO,aAAa,CAAC;AACjC,CAAC;AAED,iFAAiF;AAEjF,qDAAqD;AACrD,MAAM,UAAU,SAAS,CAAC,OAAe,EAAE,IAAgB;IACzD,
|
|
1
|
+
{"version":3,"file":"auth-store.js","sourceRoot":"","sources":["../../src/auth/auth-store.ts"],"names":[],"mappings":"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"}
|