mobbdev 1.0.207 → 1.0.209
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/dist/args/commands/upload_ai_blame.d.mts +4403 -1
- package/dist/args/commands/upload_ai_blame.mjs +574 -1053
- package/dist/index.mjs +1352 -1325
- package/package.json +1 -1
|
@@ -28,13 +28,11 @@ var init_env = __esm({
|
|
|
28
28
|
});
|
|
29
29
|
|
|
30
30
|
// src/mcp/core/configs.ts
|
|
31
|
-
var
|
|
31
|
+
var MCP_LOGIN_MAX_WAIT, MCP_LOGIN_CHECK_DELAY, MCP_VUL_REPORT_DIGEST_TIMEOUT_MS, MCP_MAX_FILE_SIZE, MCP_PERIODIC_CHECK_INTERVAL, MCP_REPORT_ID_EXPIRATION_MS, MCP_TOOLS_BROWSER_COOLDOWN_MS, isAutoScan, MVS_AUTO_FIX_OVERRIDE, MCP_PERIODIC_TRACK_INTERVAL, MCP_SYSTEM_FIND_TIMEOUT_MS;
|
|
32
32
|
var init_configs = __esm({
|
|
33
33
|
"src/mcp/core/configs.ts"() {
|
|
34
34
|
"use strict";
|
|
35
35
|
init_env();
|
|
36
|
-
MCP_DEFAULT_API_URL = "https://api.mobb.ai/v1/graphql";
|
|
37
|
-
MCP_API_KEY_HEADER_NAME = "x-mobb-key";
|
|
38
36
|
MCP_LOGIN_MAX_WAIT = 2 * 60 * 1e3;
|
|
39
37
|
MCP_LOGIN_CHECK_DELAY = 2 * 1e3;
|
|
40
38
|
MCP_VUL_REPORT_DIGEST_TIMEOUT_MS = 30 * 60 * 1e3;
|
|
@@ -42,7 +40,6 @@ var init_configs = __esm({
|
|
|
42
40
|
MCP_PERIODIC_CHECK_INTERVAL = 15 * 60 * 1e3;
|
|
43
41
|
MCP_REPORT_ID_EXPIRATION_MS = 2 * 60 * 60 * 1e3;
|
|
44
42
|
MCP_TOOLS_BROWSER_COOLDOWN_MS = 24 * 60 * 60 * 1e3;
|
|
45
|
-
MCP_DEFAULT_LIMIT = 3;
|
|
46
43
|
isAutoScan = process.env["AUTO_SCAN"] !== "false";
|
|
47
44
|
MVS_AUTO_FIX_OVERRIDE = process.env["MVS_AUTO_FIX"];
|
|
48
45
|
MCP_PERIODIC_TRACK_INTERVAL = 60 * 60 * 1e3;
|
|
@@ -94,21 +91,18 @@ var init_GitService = __esm({
|
|
|
94
91
|
// src/args/commands/upload_ai_blame.ts
|
|
95
92
|
import fsPromises2 from "fs/promises";
|
|
96
93
|
import path6 from "path";
|
|
97
|
-
import
|
|
94
|
+
import chalk3 from "chalk";
|
|
95
|
+
import Configstore2 from "configstore";
|
|
98
96
|
import { withFile } from "tmp-promise";
|
|
99
|
-
import
|
|
97
|
+
import z26 from "zod";
|
|
100
98
|
|
|
101
|
-
// src/
|
|
99
|
+
// src/commands/handleMobbLogin.ts
|
|
100
|
+
import crypto from "crypto";
|
|
101
|
+
import os from "os";
|
|
102
|
+
import chalk2 from "chalk";
|
|
103
|
+
import Configstore from "configstore";
|
|
102
104
|
import Debug7 from "debug";
|
|
103
|
-
import
|
|
104
|
-
|
|
105
|
-
// src/features/analysis/graphql/gql.ts
|
|
106
|
-
import fetchOrig from "cross-fetch";
|
|
107
|
-
import Debug6 from "debug";
|
|
108
|
-
import { GraphQLClient } from "graphql-request";
|
|
109
|
-
import { HttpProxyAgent } from "http-proxy-agent";
|
|
110
|
-
import { HttpsProxyAgent as HttpsProxyAgent2 } from "https-proxy-agent";
|
|
111
|
-
import { v4 as uuidv4 } from "uuid";
|
|
105
|
+
import open from "open";
|
|
112
106
|
|
|
113
107
|
// src/constants.ts
|
|
114
108
|
import path2 from "path";
|
|
@@ -2151,39 +2145,99 @@ var errorMessages = {
|
|
|
2151
2145
|
};
|
|
2152
2146
|
var VUL_REPORT_DIGEST_TIMEOUT_MS = 1e3 * 60 * 30;
|
|
2153
2147
|
|
|
2148
|
+
// src/features/analysis/graphql/gql.ts
|
|
2149
|
+
import fetchOrig from "cross-fetch";
|
|
2150
|
+
import Debug6 from "debug";
|
|
2151
|
+
import { GraphQLClient } from "graphql-request";
|
|
2152
|
+
import { HttpProxyAgent } from "http-proxy-agent";
|
|
2153
|
+
import { HttpsProxyAgent as HttpsProxyAgent2 } from "https-proxy-agent";
|
|
2154
|
+
import { v4 as uuidv4 } from "uuid";
|
|
2155
|
+
|
|
2154
2156
|
// src/mcp/core/Errors.ts
|
|
2155
|
-
var
|
|
2156
|
-
constructor(message
|
|
2157
|
+
var _ReportDigestError = class _ReportDigestError extends Error {
|
|
2158
|
+
constructor(message, failReason) {
|
|
2157
2159
|
super(message);
|
|
2158
|
-
this.
|
|
2160
|
+
this.failReason = failReason;
|
|
2161
|
+
this.name = "ReportDigestError";
|
|
2162
|
+
this.failReason = failReason;
|
|
2159
2163
|
}
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2164
|
+
getDisplayMessage() {
|
|
2165
|
+
if (this.failReason?.trim()) {
|
|
2166
|
+
return `\u{1F575}\uFE0F\u200D\u2642\uFE0F Digesting report failed. ${this.failReason}`;
|
|
2167
|
+
}
|
|
2168
|
+
return _ReportDigestError.defaultMessage;
|
|
2165
2169
|
}
|
|
2166
2170
|
};
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
}
|
|
2171
|
+
__publicField(_ReportDigestError, "defaultMessage", "\u{1F575}\uFE0F\u200D\u2642\uFE0F Digesting report failed. Please verify that the file provided is of a valid supported report format.");
|
|
2172
|
+
var ReportDigestError = _ReportDigestError;
|
|
2173
|
+
|
|
2174
|
+
// src/types.ts
|
|
2175
|
+
var ScanContext = {
|
|
2176
|
+
FULL_SCAN: "FULL_SCAN",
|
|
2177
|
+
BACKGROUND_PERIODIC: "BACKGROUND_PERIODIC",
|
|
2178
|
+
BACKGROUND_INITIAL: "BACKGROUND_INITIAL",
|
|
2179
|
+
USER_REQUEST: "USER_REQUEST",
|
|
2180
|
+
BUGSY: "BUGSY"
|
|
2178
2181
|
};
|
|
2179
2182
|
|
|
2180
2183
|
// src/utils/keypress.ts
|
|
2181
2184
|
import readline from "readline";
|
|
2185
|
+
async function keypress() {
|
|
2186
|
+
const rl = readline.createInterface({
|
|
2187
|
+
input: process.stdin,
|
|
2188
|
+
output: process.stdout
|
|
2189
|
+
});
|
|
2190
|
+
return new Promise((resolve) => {
|
|
2191
|
+
rl.question("", (answer) => {
|
|
2192
|
+
rl.close();
|
|
2193
|
+
process.stderr.moveCursor(0, -1);
|
|
2194
|
+
process.stderr.clearLine(1);
|
|
2195
|
+
resolve(answer);
|
|
2196
|
+
});
|
|
2197
|
+
});
|
|
2198
|
+
}
|
|
2182
2199
|
|
|
2183
2200
|
// src/utils/spinner.ts
|
|
2184
2201
|
import {
|
|
2185
2202
|
createSpinner as _createSpinner
|
|
2186
2203
|
} from "nanospinner";
|
|
2204
|
+
function printToStdError(opts) {
|
|
2205
|
+
if (opts?.text) console.error(opts.text);
|
|
2206
|
+
}
|
|
2207
|
+
var mockSpinner = {
|
|
2208
|
+
success: (opts) => {
|
|
2209
|
+
printToStdError(opts);
|
|
2210
|
+
return mockSpinner;
|
|
2211
|
+
},
|
|
2212
|
+
error: (opts) => {
|
|
2213
|
+
printToStdError(opts);
|
|
2214
|
+
return mockSpinner;
|
|
2215
|
+
},
|
|
2216
|
+
warn: (opts) => {
|
|
2217
|
+
printToStdError(opts);
|
|
2218
|
+
return mockSpinner;
|
|
2219
|
+
},
|
|
2220
|
+
stop: (opts) => {
|
|
2221
|
+
printToStdError(opts);
|
|
2222
|
+
return mockSpinner;
|
|
2223
|
+
},
|
|
2224
|
+
start: (opts) => {
|
|
2225
|
+
printToStdError(opts);
|
|
2226
|
+
return mockSpinner;
|
|
2227
|
+
},
|
|
2228
|
+
update: (opts) => {
|
|
2229
|
+
printToStdError(opts);
|
|
2230
|
+
return mockSpinner;
|
|
2231
|
+
},
|
|
2232
|
+
reset: () => mockSpinner,
|
|
2233
|
+
clear: () => mockSpinner,
|
|
2234
|
+
spin: () => mockSpinner
|
|
2235
|
+
};
|
|
2236
|
+
function Spinner({ ci = false } = {}) {
|
|
2237
|
+
return {
|
|
2238
|
+
createSpinner: (text, options) => ci ? mockSpinner : _createSpinner(text, options)
|
|
2239
|
+
};
|
|
2240
|
+
}
|
|
2187
2241
|
|
|
2188
2242
|
// src/utils/check_node_version.ts
|
|
2189
2243
|
import fs2 from "fs";
|
|
@@ -2205,6 +2259,8 @@ if (!semver.satisfies(process.version, packageJson.engines.node)) {
|
|
|
2205
2259
|
|
|
2206
2260
|
// src/utils/index.ts
|
|
2207
2261
|
var sleep = (ms = 2e3) => new Promise((r) => setTimeout(r, ms));
|
|
2262
|
+
var CliError = class extends Error {
|
|
2263
|
+
};
|
|
2208
2264
|
|
|
2209
2265
|
// src/features/analysis/scm/utils/index.ts
|
|
2210
2266
|
import { z as z15 } from "zod";
|
|
@@ -4268,6 +4324,9 @@ var BitbucketParseResultZ = z20.object({
|
|
|
4268
4324
|
import { setTimeout as setTimeout3 } from "timers/promises";
|
|
4269
4325
|
import { z as z21 } from "zod";
|
|
4270
4326
|
|
|
4327
|
+
// src/features/analysis/scm/constants.ts
|
|
4328
|
+
var REPORT_DEFAULT_FILE_NAME = "report.json";
|
|
4329
|
+
|
|
4271
4330
|
// src/features/analysis/scm/index.ts
|
|
4272
4331
|
init_env();
|
|
4273
4332
|
|
|
@@ -4503,458 +4562,38 @@ function getProxyAgent(url) {
|
|
|
4503
4562
|
}
|
|
4504
4563
|
return void 0;
|
|
4505
4564
|
}
|
|
4506
|
-
|
|
4507
|
-
// src/features/analysis/upload-file.ts
|
|
4508
|
-
var debug8 = Debug7("mobbdev:upload-file");
|
|
4509
|
-
async function uploadFile({
|
|
4510
|
-
file,
|
|
4511
|
-
url,
|
|
4512
|
-
uploadKey,
|
|
4513
|
-
uploadFields,
|
|
4514
|
-
logger: logger2
|
|
4515
|
-
}) {
|
|
4516
|
-
const logInfo = logger2 || ((_message, _data) => {
|
|
4517
|
-
});
|
|
4518
|
-
logInfo(`FileUpload: upload file start ${url}`);
|
|
4519
|
-
logInfo(`FileUpload: upload fields`, uploadFields);
|
|
4520
|
-
logInfo(`FileUpload: upload key ${uploadKey}`);
|
|
4521
|
-
debug8("upload file start %s", url);
|
|
4522
|
-
debug8("upload fields %o", uploadFields);
|
|
4523
|
-
debug8("upload key %s", uploadKey);
|
|
4524
|
-
const form = new FormData();
|
|
4525
|
-
Object.entries(uploadFields).forEach(([key, value]) => {
|
|
4526
|
-
form.append(key, value);
|
|
4527
|
-
});
|
|
4528
|
-
if (!form.has("key")) {
|
|
4529
|
-
form.append("key", uploadKey);
|
|
4530
|
-
}
|
|
4531
|
-
if (typeof file === "string") {
|
|
4532
|
-
debug8("upload file from path %s", file);
|
|
4533
|
-
logInfo(`FileUpload: upload file from path ${file}`);
|
|
4534
|
-
form.append("file", await fileFrom(file));
|
|
4535
|
-
} else {
|
|
4536
|
-
debug8("upload file from buffer");
|
|
4537
|
-
logInfo(`FileUpload: upload file from buffer`);
|
|
4538
|
-
form.append("file", new File([new Uint8Array(file)], "file"));
|
|
4539
|
-
}
|
|
4540
|
-
const agent = getProxyAgent(url);
|
|
4541
|
-
const response = await fetch3(url, {
|
|
4542
|
-
method: "POST",
|
|
4543
|
-
body: form,
|
|
4544
|
-
agent
|
|
4545
|
-
});
|
|
4546
|
-
if (!response.ok) {
|
|
4547
|
-
debug8("error from S3 %s %s", response.body, response.status);
|
|
4548
|
-
logInfo(`FileUpload: error from S3 ${response.body} ${response.status}`);
|
|
4549
|
-
throw new Error(`Failed to upload the file: ${response.status}`);
|
|
4550
|
-
}
|
|
4551
|
-
debug8("upload file done");
|
|
4552
|
-
logInfo(`FileUpload: upload file done`);
|
|
4553
|
-
}
|
|
4554
|
-
|
|
4555
|
-
// src/mcp/services/McpGQLClient.ts
|
|
4556
|
-
import crypto2 from "crypto";
|
|
4557
|
-
import { GraphQLClient as GraphQLClient2 } from "graphql-request";
|
|
4558
|
-
import { v4 as uuidv42 } from "uuid";
|
|
4559
|
-
init_configs();
|
|
4560
|
-
|
|
4561
|
-
// src/mcp/Logger.ts
|
|
4562
|
-
import Configstore from "configstore";
|
|
4563
|
-
|
|
4564
|
-
// src/mcp/services/WorkspaceService.ts
|
|
4565
|
-
var WorkspaceService = class {
|
|
4566
|
-
/**
|
|
4567
|
-
* Sets a known workspace path that was discovered through successful validation
|
|
4568
|
-
* @param path The validated workspace path to store
|
|
4569
|
-
*/
|
|
4570
|
-
static setKnownWorkspacePath(path7) {
|
|
4571
|
-
this.knownWorkspacePath = path7;
|
|
4572
|
-
}
|
|
4573
|
-
/**
|
|
4574
|
-
* Gets the known workspace path that was previously validated
|
|
4575
|
-
* @returns The known workspace path or undefined if none stored
|
|
4576
|
-
*/
|
|
4577
|
-
static getKnownWorkspacePath() {
|
|
4578
|
-
return this.knownWorkspacePath;
|
|
4579
|
-
}
|
|
4580
|
-
/**
|
|
4581
|
-
* Clears the known workspace path cache
|
|
4582
|
-
*/
|
|
4583
|
-
static clearKnownWorkspacePath() {
|
|
4584
|
-
this.knownWorkspacePath = void 0;
|
|
4585
|
-
}
|
|
4586
|
-
/**
|
|
4587
|
-
* Gets the workspace folder path from known path or environment variables
|
|
4588
|
-
* @returns The workspace folder path or undefined if none found
|
|
4589
|
-
*/
|
|
4590
|
-
static getWorkspaceFolderPath() {
|
|
4591
|
-
if (this.knownWorkspacePath) {
|
|
4592
|
-
return this.knownWorkspacePath;
|
|
4593
|
-
}
|
|
4594
|
-
const workspaceEnvVars = [
|
|
4595
|
-
"WORKSPACE_FOLDER_PATHS",
|
|
4596
|
-
// Cursor IDE
|
|
4597
|
-
"PWD",
|
|
4598
|
-
// Claude Code and general shell
|
|
4599
|
-
"WORKSPACE_ROOT",
|
|
4600
|
-
// Generic workspace root
|
|
4601
|
-
"PROJECT_ROOT"
|
|
4602
|
-
// Generic project root
|
|
4603
|
-
];
|
|
4604
|
-
for (const envVar of workspaceEnvVars) {
|
|
4605
|
-
const value = process.env[envVar];
|
|
4606
|
-
if (value?.trim()) {
|
|
4607
|
-
return value.trim();
|
|
4608
|
-
}
|
|
4609
|
-
}
|
|
4610
|
-
return void 0;
|
|
4611
|
-
}
|
|
4612
|
-
///this should be deleted, use instead the host detection from the McpUsageService
|
|
4613
|
-
/**
|
|
4614
|
-
* Detects the IDE/editor host based on environment variables
|
|
4615
|
-
* @returns The detected IDE host
|
|
4616
|
-
*/
|
|
4617
|
-
static getHost() {
|
|
4618
|
-
if (process.env["WORKSPACE_FOLDER_PATHS"]) {
|
|
4619
|
-
return "CURSOR";
|
|
4620
|
-
}
|
|
4621
|
-
if (process.env["VSCODE_IPC_HOOK"] || process.env["VSCODE_PID"] || process.env["TERM_PROGRAM"] === "vscode") {
|
|
4622
|
-
return "VSCODE";
|
|
4623
|
-
}
|
|
4624
|
-
if (process.env["WINDSURF_IPC_HOOK"] || process.env["WINDSURF_PID"] || process.env["TERM_PROGRAM"] === "windsurf") {
|
|
4625
|
-
return "WINDSURF";
|
|
4626
|
-
}
|
|
4627
|
-
if (process.env["CLAUDE_DESKTOP"] || process.env["ANTHROPIC_CLAUDE"]) {
|
|
4628
|
-
return "CLAUDE";
|
|
4629
|
-
}
|
|
4630
|
-
if (process.env["WEBSTORM_VM_OPTIONS"] || process.env["IDEA_VM_OPTIONS"] || process.env["JETBRAINS_IDE"]) {
|
|
4631
|
-
return "WEBSTORM";
|
|
4632
|
-
}
|
|
4633
|
-
return "UNKNOWN";
|
|
4634
|
-
}
|
|
4635
|
-
};
|
|
4636
|
-
__publicField(WorkspaceService, "knownWorkspacePath");
|
|
4637
|
-
|
|
4638
|
-
// src/mcp/Logger.ts
|
|
4639
|
-
var MAX_LOGS_SIZE = 1e3;
|
|
4640
|
-
var Logger = class {
|
|
4641
|
-
constructor() {
|
|
4642
|
-
__publicField(this, "mobbConfigStore");
|
|
4643
|
-
__publicField(this, "host");
|
|
4644
|
-
__publicField(this, "unknownPathSuffix");
|
|
4645
|
-
__publicField(this, "lastKnownPath", null);
|
|
4646
|
-
this.host = WorkspaceService.getHost();
|
|
4647
|
-
this.unknownPathSuffix = Math.floor(1e3 + Math.random() * 9e3).toString();
|
|
4648
|
-
this.mobbConfigStore = new Configstore("mobb-logs", {});
|
|
4649
|
-
this.mobbConfigStore.set("version", packageJson.version);
|
|
4650
|
-
}
|
|
4651
|
-
/**
|
|
4652
|
-
* Gets the current log path, fetching workspace path dynamically
|
|
4653
|
-
*/
|
|
4654
|
-
getCurrentLogPath() {
|
|
4655
|
-
const workspacePath = WorkspaceService.getWorkspaceFolderPath();
|
|
4656
|
-
if (workspacePath) {
|
|
4657
|
-
return `${this.host}:${workspacePath}`;
|
|
4658
|
-
}
|
|
4659
|
-
return `${this.host}:unknown-${this.unknownPathSuffix}`;
|
|
4660
|
-
}
|
|
4661
|
-
/**
|
|
4662
|
-
* Migrates logs from unknown path to known workspace path
|
|
4663
|
-
*/
|
|
4664
|
-
migrateLogs(fromPath, toPath) {
|
|
4665
|
-
const existingLogs = this.mobbConfigStore.get(fromPath) ?? [];
|
|
4666
|
-
const targetLogs = this.mobbConfigStore.get(toPath) ?? [];
|
|
4667
|
-
if (existingLogs.length > 0) {
|
|
4668
|
-
const combinedLogs = [...targetLogs, ...existingLogs];
|
|
4669
|
-
const finalLogs = combinedLogs.slice(-MAX_LOGS_SIZE);
|
|
4670
|
-
this.mobbConfigStore.set(toPath, finalLogs);
|
|
4671
|
-
this.mobbConfigStore.delete(fromPath);
|
|
4672
|
-
}
|
|
4673
|
-
}
|
|
4674
|
-
/**
|
|
4675
|
-
* Log a message to the console.
|
|
4676
|
-
* @param message - The message to log.
|
|
4677
|
-
* @param level - The level of the message.
|
|
4678
|
-
* @param data - The data to log.
|
|
4679
|
-
*/
|
|
4680
|
-
log(message, level = "info", data) {
|
|
4681
|
-
const currentPath = this.getCurrentLogPath();
|
|
4682
|
-
const workspacePath = WorkspaceService.getWorkspaceFolderPath();
|
|
4683
|
-
if (workspacePath && this.lastKnownPath !== workspacePath) {
|
|
4684
|
-
const unknownPath = `${this.host}:unknown-${this.unknownPathSuffix}`;
|
|
4685
|
-
const knownPath = `${this.host}:${workspacePath}`;
|
|
4686
|
-
if (this.lastKnownPath === null || this.lastKnownPath.includes("unknown-")) {
|
|
4687
|
-
this.migrateLogs(unknownPath, knownPath);
|
|
4688
|
-
}
|
|
4689
|
-
this.lastKnownPath = workspacePath;
|
|
4690
|
-
}
|
|
4691
|
-
const logMessage = {
|
|
4692
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4693
|
-
level,
|
|
4694
|
-
message,
|
|
4695
|
-
data
|
|
4696
|
-
};
|
|
4697
|
-
const logs = this.mobbConfigStore.get(currentPath) ?? [];
|
|
4698
|
-
if (logs.length >= MAX_LOGS_SIZE) {
|
|
4699
|
-
logs.shift();
|
|
4700
|
-
}
|
|
4701
|
-
this.mobbConfigStore.set(currentPath, [...logs, logMessage]);
|
|
4702
|
-
}
|
|
4703
|
-
};
|
|
4704
|
-
var logger = new Logger();
|
|
4705
|
-
var logError = (message, data) => logger.log(message, "error", data);
|
|
4706
|
-
var logDebug = (message, data) => logger.log(message, "debug", data);
|
|
4707
|
-
var log = logger.log.bind(logger);
|
|
4708
|
-
|
|
4709
|
-
// src/mcp/types.ts
|
|
4710
|
-
import { z as z26 } from "zod";
|
|
4711
|
-
var ScanAndFixVulnerabilitiesToolSchema = z26.object({
|
|
4712
|
-
path: z26.string()
|
|
4713
|
-
});
|
|
4714
|
-
var VulnerabilityReportIssueTagSchema = z26.object({
|
|
4715
|
-
vulnerability_report_issue_tag_value: z26.nativeEnum(
|
|
4716
|
-
Vulnerability_Report_Issue_Tag_Enum
|
|
4717
|
-
)
|
|
4718
|
-
});
|
|
4719
|
-
var VulnerabilityReportIssueSchema = z26.object({
|
|
4720
|
-
category: z26.any().optional().nullable(),
|
|
4721
|
-
parsedIssueType: z26.nativeEnum(IssueType_Enum).nullable().optional(),
|
|
4722
|
-
parsedSeverity: z26.nativeEnum(Vulnerability_Severity_Enum).nullable().optional(),
|
|
4723
|
-
vulnerabilityReportIssueTags: z26.array(VulnerabilityReportIssueTagSchema)
|
|
4724
|
-
});
|
|
4725
|
-
var SharedStateSchema = z26.object({
|
|
4726
|
-
__typename: z26.literal("fix_shared_state").optional(),
|
|
4727
|
-
id: z26.any(),
|
|
4728
|
-
// GraphQL uses `any` type for UUID
|
|
4729
|
-
downloadedBy: z26.array(z26.any().nullable()).optional().nullable()
|
|
4730
|
-
});
|
|
4731
|
-
var UnstructuredFixExtraContextSchema = z26.object({
|
|
4732
|
-
__typename: z26.literal("UnstructuredFixExtraContext").optional(),
|
|
4733
|
-
key: z26.string(),
|
|
4734
|
-
value: z26.any()
|
|
4735
|
-
// GraphQL JSON type
|
|
4736
|
-
});
|
|
4737
|
-
var FixExtraContextResponseSchema = z26.object({
|
|
4738
|
-
__typename: z26.literal("FixExtraContextResponse").optional(),
|
|
4739
|
-
extraContext: z26.array(UnstructuredFixExtraContextSchema),
|
|
4740
|
-
fixDescription: z26.string()
|
|
4741
|
-
});
|
|
4742
|
-
var FixDataSchema = z26.object({
|
|
4743
|
-
__typename: z26.literal("FixData"),
|
|
4744
|
-
patch: z26.string(),
|
|
4745
|
-
patchOriginalEncodingBase64: z26.string(),
|
|
4746
|
-
extraContext: FixExtraContextResponseSchema
|
|
4747
|
-
});
|
|
4748
|
-
var GetFixNoFixErrorSchema = z26.object({
|
|
4749
|
-
__typename: z26.literal("GetFixNoFixError")
|
|
4750
|
-
});
|
|
4751
|
-
var PatchAndQuestionsSchema = z26.union([FixDataSchema, GetFixNoFixErrorSchema]);
|
|
4752
|
-
var McpFixSchema = z26.object({
|
|
4753
|
-
__typename: z26.literal("fix").optional(),
|
|
4754
|
-
id: z26.any(),
|
|
4755
|
-
// GraphQL uses `any` type for UUID
|
|
4756
|
-
confidence: z26.number(),
|
|
4757
|
-
safeIssueType: z26.string().nullable(),
|
|
4758
|
-
severityText: z26.string().nullable(),
|
|
4759
|
-
gitBlameLogin: z26.string().nullable().optional(),
|
|
4760
|
-
// Optional in GraphQL
|
|
4761
|
-
severityValue: z26.number().nullable(),
|
|
4762
|
-
vulnerabilityReportIssues: z26.array(VulnerabilityReportIssueSchema),
|
|
4763
|
-
sharedState: SharedStateSchema.nullable().optional(),
|
|
4764
|
-
// Optional in GraphQL
|
|
4765
|
-
patchAndQuestions: PatchAndQuestionsSchema,
|
|
4766
|
-
// Additional field added by the client
|
|
4767
|
-
fixUrl: z26.string().optional()
|
|
4768
|
-
});
|
|
4769
|
-
var FixAggregateSchema = z26.object({
|
|
4770
|
-
__typename: z26.literal("fix_aggregate").optional(),
|
|
4771
|
-
aggregate: z26.object({
|
|
4772
|
-
__typename: z26.literal("fix_aggregate_fields").optional(),
|
|
4773
|
-
count: z26.number()
|
|
4774
|
-
}).nullable()
|
|
4775
|
-
});
|
|
4776
|
-
var VulnerabilityReportIssueAggregateSchema = z26.object({
|
|
4777
|
-
__typename: z26.literal("vulnerability_report_issue_aggregate").optional(),
|
|
4778
|
-
aggregate: z26.object({
|
|
4779
|
-
__typename: z26.literal("vulnerability_report_issue_aggregate_fields").optional(),
|
|
4780
|
-
count: z26.number()
|
|
4781
|
-
}).nullable()
|
|
4782
|
-
});
|
|
4783
|
-
var RepoSchema = z26.object({
|
|
4784
|
-
__typename: z26.literal("repo").optional(),
|
|
4785
|
-
originalUrl: z26.string()
|
|
4786
|
-
});
|
|
4787
|
-
var ProjectSchema = z26.object({
|
|
4788
|
-
id: z26.any(),
|
|
4789
|
-
// GraphQL uses `any` type for UUID
|
|
4790
|
-
organizationId: z26.any()
|
|
4791
|
-
// GraphQL uses `any` type for UUID
|
|
4792
|
-
});
|
|
4793
|
-
var VulnerabilityReportSchema = z26.object({
|
|
4794
|
-
scanDate: z26.any().nullable(),
|
|
4795
|
-
// GraphQL uses `any` type for timestamp
|
|
4796
|
-
vendor: z26.string(),
|
|
4797
|
-
// GraphQL generates as string, not enum
|
|
4798
|
-
projectId: z26.any().optional(),
|
|
4799
|
-
// GraphQL uses `any` type for UUID
|
|
4800
|
-
project: ProjectSchema,
|
|
4801
|
-
totalVulnerabilityReportIssuesCount: VulnerabilityReportIssueAggregateSchema,
|
|
4802
|
-
notFixableVulnerabilityReportIssuesCount: VulnerabilityReportIssueAggregateSchema
|
|
4803
|
-
});
|
|
4804
|
-
var FixReportSummarySchema = z26.object({
|
|
4805
|
-
__typename: z26.literal("fixReport").optional(),
|
|
4806
|
-
id: z26.any(),
|
|
4807
|
-
// GraphQL uses `any` type for UUID
|
|
4808
|
-
createdOn: z26.any(),
|
|
4809
|
-
// GraphQL uses `any` type for timestamp
|
|
4810
|
-
repo: RepoSchema.nullable(),
|
|
4811
|
-
issueTypes: z26.any().nullable(),
|
|
4812
|
-
// GraphQL uses `any` type for JSON
|
|
4813
|
-
CRITICAL: FixAggregateSchema,
|
|
4814
|
-
HIGH: FixAggregateSchema,
|
|
4815
|
-
MEDIUM: FixAggregateSchema,
|
|
4816
|
-
LOW: FixAggregateSchema,
|
|
4817
|
-
fixes: z26.array(McpFixSchema),
|
|
4818
|
-
userFixes: z26.array(McpFixSchema).optional(),
|
|
4819
|
-
// Present in some responses but can be omitted
|
|
4820
|
-
filteredFixesCount: FixAggregateSchema,
|
|
4821
|
-
totalFixesCount: FixAggregateSchema,
|
|
4822
|
-
vulnerabilityReport: VulnerabilityReportSchema
|
|
4823
|
-
});
|
|
4824
|
-
var ExpiredReportSchema = z26.object({
|
|
4825
|
-
__typename: z26.literal("fixReport").optional(),
|
|
4826
|
-
id: z26.any(),
|
|
4827
|
-
// GraphQL uses `any` type for UUID
|
|
4828
|
-
expirationOn: z26.any().nullable()
|
|
4829
|
-
// GraphQL uses `any` type for timestamp
|
|
4830
|
-
});
|
|
4831
|
-
var GetLatestReportByRepoUrlResponseSchema = z26.object({
|
|
4832
|
-
__typename: z26.literal("query_root").optional(),
|
|
4833
|
-
fixReport: z26.array(FixReportSummarySchema),
|
|
4834
|
-
expiredReport: z26.array(ExpiredReportSchema)
|
|
4835
|
-
});
|
|
4836
|
-
|
|
4837
|
-
// src/mcp/services/ConfigStoreService.ts
|
|
4838
|
-
import Configstore2 from "configstore";
|
|
4839
|
-
init_configs();
|
|
4840
|
-
function createConfigStore(defaultValues = { apiToken: "" }) {
|
|
4841
|
-
const API_URL2 = process.env["API_URL"] || MCP_DEFAULT_API_URL;
|
|
4842
|
-
let domain = "";
|
|
4565
|
+
var fetchWithProxy = (url, options = {}) => {
|
|
4843
4566
|
try {
|
|
4844
|
-
const
|
|
4845
|
-
|
|
4846
|
-
|
|
4847
|
-
|
|
4848
|
-
|
|
4849
|
-
|
|
4850
|
-
return new Configstore2(
|
|
4851
|
-
`${packageJson.name}-${sanitizedDomain}`,
|
|
4852
|
-
defaultValues
|
|
4853
|
-
);
|
|
4854
|
-
}
|
|
4855
|
-
function getConfigStore() {
|
|
4856
|
-
return createConfigStore();
|
|
4857
|
-
}
|
|
4858
|
-
var configStore = getConfigStore();
|
|
4859
|
-
|
|
4860
|
-
// src/mcp/services/McpAuthService.ts
|
|
4861
|
-
import crypto from "crypto";
|
|
4862
|
-
import os from "os";
|
|
4863
|
-
import open from "open";
|
|
4864
|
-
init_configs();
|
|
4865
|
-
var McpAuthService = class {
|
|
4866
|
-
constructor(client) {
|
|
4867
|
-
__publicField(this, "client");
|
|
4868
|
-
__publicField(this, "lastBrowserOpenTime", 0);
|
|
4869
|
-
this.client = client;
|
|
4870
|
-
}
|
|
4871
|
-
/**
|
|
4872
|
-
* Opens a browser window for authentication
|
|
4873
|
-
* @param url URL to open in browser
|
|
4874
|
-
* @param isBackgoundCall Whether this is called from tools context
|
|
4875
|
-
*/
|
|
4876
|
-
async openBrowser(url, isBackgoundCall) {
|
|
4877
|
-
if (isBackgoundCall) {
|
|
4878
|
-
const now = Date.now();
|
|
4879
|
-
if (now - this.lastBrowserOpenTime < MCP_TOOLS_BROWSER_COOLDOWN_MS) {
|
|
4880
|
-
logDebug(`browser cooldown active, skipping open for ${url}`);
|
|
4881
|
-
return;
|
|
4882
|
-
}
|
|
4883
|
-
}
|
|
4884
|
-
logDebug(`opening browser url ${url}`);
|
|
4885
|
-
await open(url);
|
|
4886
|
-
this.lastBrowserOpenTime = Date.now();
|
|
4887
|
-
}
|
|
4888
|
-
/**
|
|
4889
|
-
* Handles the complete authentication flow
|
|
4890
|
-
* @param isBackgoundCall Whether this is called from tools context
|
|
4891
|
-
* @returns Authenticated API token
|
|
4892
|
-
*/
|
|
4893
|
-
async authenticate(isBackgoundCall = false) {
|
|
4894
|
-
const { publicKey, privateKey } = crypto.generateKeyPairSync("rsa", {
|
|
4895
|
-
modulusLength: 2048
|
|
4896
|
-
});
|
|
4897
|
-
logDebug("creating cli login");
|
|
4898
|
-
const loginId = await this.client.createCliLogin({
|
|
4899
|
-
publicKey: publicKey.export({ format: "pem", type: "pkcs1" }).toString()
|
|
4900
|
-
});
|
|
4901
|
-
if (!loginId) {
|
|
4902
|
-
throw new CliLoginError("Error: createCliLogin failed");
|
|
4903
|
-
}
|
|
4904
|
-
logDebug(`cli login created ${loginId}`);
|
|
4905
|
-
const webLoginUrl = `${WEB_APP_URL}/mvs-login`;
|
|
4906
|
-
const browserUrl = `${webLoginUrl}/${loginId}?hostname=${os.hostname()}`;
|
|
4907
|
-
await this.openBrowser(browserUrl, isBackgoundCall);
|
|
4908
|
-
logDebug(`waiting for login to complete`);
|
|
4909
|
-
let newApiToken = null;
|
|
4910
|
-
for (let i = 0; i < MCP_LOGIN_MAX_WAIT / MCP_LOGIN_CHECK_DELAY; i++) {
|
|
4911
|
-
const encryptedApiToken = await this.client.getEncryptedApiToken({
|
|
4912
|
-
loginId
|
|
4567
|
+
const agent = getProxyAgent(url.toString());
|
|
4568
|
+
if (agent) {
|
|
4569
|
+
return fetchOrig(url, {
|
|
4570
|
+
...options,
|
|
4571
|
+
// @ts-expect-error Node-fetch doesn't type 'agent', but it's valid
|
|
4572
|
+
agent
|
|
4913
4573
|
});
|
|
4914
|
-
if (encryptedApiToken) {
|
|
4915
|
-
logDebug("encrypted API token received");
|
|
4916
|
-
newApiToken = crypto.privateDecrypt(privateKey, Buffer.from(encryptedApiToken, "base64")).toString("utf-8");
|
|
4917
|
-
logDebug("API token decrypted");
|
|
4918
|
-
break;
|
|
4919
|
-
}
|
|
4920
|
-
await sleep(MCP_LOGIN_CHECK_DELAY);
|
|
4921
|
-
}
|
|
4922
|
-
if (!newApiToken) {
|
|
4923
|
-
throw new FailedToGetApiTokenError(
|
|
4924
|
-
"Error: failed to get encrypted api token"
|
|
4925
|
-
);
|
|
4926
|
-
}
|
|
4927
|
-
const verifyClient = new McpGQLClient({
|
|
4928
|
-
apiKey: newApiToken,
|
|
4929
|
-
type: "apiKey"
|
|
4930
|
-
});
|
|
4931
|
-
const loginSuccess = await verifyClient.validateUserToken();
|
|
4932
|
-
if (!loginSuccess) {
|
|
4933
|
-
throw new AuthenticationError("Invalid API token");
|
|
4934
4574
|
}
|
|
4935
|
-
|
|
4575
|
+
} catch (err) {
|
|
4576
|
+
debug7(`Skipping proxy for ${url}. Reason: ${err.message}`);
|
|
4936
4577
|
}
|
|
4578
|
+
return fetchOrig(url, options);
|
|
4937
4579
|
};
|
|
4938
|
-
|
|
4939
|
-
// src/mcp/services/McpGQLClient.ts
|
|
4940
|
-
var McpGQLClient = class {
|
|
4580
|
+
var GQLClient = class {
|
|
4941
4581
|
constructor(args) {
|
|
4942
|
-
__publicField(this, "
|
|
4943
|
-
__publicField(this, "
|
|
4582
|
+
__publicField(this, "_client");
|
|
4583
|
+
__publicField(this, "_clientSdk");
|
|
4944
4584
|
__publicField(this, "_auth");
|
|
4945
|
-
|
|
4946
|
-
__publicField(this, "apiUrl");
|
|
4585
|
+
debug7(`init with ${args}`);
|
|
4947
4586
|
this._auth = args;
|
|
4948
|
-
this.
|
|
4949
|
-
|
|
4950
|
-
args
|
|
4951
|
-
});
|
|
4952
|
-
this.client = new GraphQLClient2(this.apiUrl, {
|
|
4953
|
-
headers: args.type === "apiKey" ? { [MCP_API_KEY_HEADER_NAME]: args.apiKey || "" } : {
|
|
4587
|
+
this._client = new GraphQLClient(API_URL, {
|
|
4588
|
+
headers: args.type === "apiKey" ? { [API_KEY_HEADER_NAME]: args.apiKey || "" } : {
|
|
4954
4589
|
Authorization: `Bearer ${args.token}`
|
|
4955
4590
|
},
|
|
4591
|
+
fetch: fetchWithProxy,
|
|
4956
4592
|
requestMiddleware: (request) => {
|
|
4957
|
-
const requestId =
|
|
4593
|
+
const requestId = uuidv4();
|
|
4594
|
+
debug7(
|
|
4595
|
+
`sending API request with id: ${requestId} and with request: ${request.body}`
|
|
4596
|
+
);
|
|
4958
4597
|
return {
|
|
4959
4598
|
...request,
|
|
4960
4599
|
headers: {
|
|
@@ -4964,654 +4603,521 @@ var McpGQLClient = class {
|
|
|
4964
4603
|
};
|
|
4965
4604
|
}
|
|
4966
4605
|
});
|
|
4967
|
-
this.
|
|
4968
|
-
}
|
|
4969
|
-
getErrorContext() {
|
|
4970
|
-
return {
|
|
4971
|
-
endpoint: this.apiUrl,
|
|
4972
|
-
apiKey: this._auth.type === "apiKey" ? this._auth.apiKey : "",
|
|
4973
|
-
headers: {
|
|
4974
|
-
[MCP_API_KEY_HEADER_NAME]: this._auth.type === "apiKey" ? "[REDACTED]" : "undefined",
|
|
4975
|
-
"x-hasura-request-id": "[DYNAMIC]"
|
|
4976
|
-
}
|
|
4977
|
-
};
|
|
4606
|
+
this._clientSdk = getSdk(this._client);
|
|
4978
4607
|
}
|
|
4979
|
-
async
|
|
4980
|
-
|
|
4608
|
+
async getUserInfo() {
|
|
4609
|
+
const { me } = await this._clientSdk.Me();
|
|
4610
|
+
return me;
|
|
4981
4611
|
}
|
|
4982
|
-
async
|
|
4983
|
-
|
|
4612
|
+
async createCliLogin(variables) {
|
|
4613
|
+
const res = await this._clientSdk.CreateCliLogin(variables, {
|
|
4614
|
+
// We may have outdated API key in the config storage. Avoid using it for the login request.
|
|
4615
|
+
[API_KEY_HEADER_NAME]: ""
|
|
4616
|
+
});
|
|
4617
|
+
return res.insert_cli_login_one?.id || "";
|
|
4984
4618
|
}
|
|
4985
|
-
async
|
|
4619
|
+
async verifyApiConnection() {
|
|
4986
4620
|
try {
|
|
4987
|
-
|
|
4988
|
-
const result = await this.getUserInfo();
|
|
4989
|
-
logDebug("[GraphQL] Me query successful", { result });
|
|
4990
|
-
return true;
|
|
4621
|
+
await this.getUserInfo();
|
|
4991
4622
|
} catch (e) {
|
|
4992
|
-
|
|
4993
|
-
|
|
4994
|
-
if (error?.toString().includes("FetchError")) {
|
|
4995
|
-
logError("[GraphQL] API connection verification failed", { error });
|
|
4623
|
+
if (e?.toString().startsWith("FetchError")) {
|
|
4624
|
+
debug7("verify connection failed %o", e);
|
|
4996
4625
|
return false;
|
|
4997
4626
|
}
|
|
4998
4627
|
}
|
|
4999
4628
|
return true;
|
|
5000
4629
|
}
|
|
5001
|
-
|
|
5002
|
-
|
|
5003
|
-
|
|
5004
|
-
*/
|
|
5005
|
-
async verifyApiConnection() {
|
|
5006
|
-
const isReachable = await this.isApiEndpointReachable();
|
|
5007
|
-
if (!isReachable) {
|
|
5008
|
-
return false;
|
|
5009
|
-
}
|
|
4630
|
+
async validateUserToken() {
|
|
4631
|
+
await this.createCommunityUser();
|
|
4632
|
+
let info;
|
|
5010
4633
|
try {
|
|
5011
|
-
await this.
|
|
5012
|
-
return true;
|
|
4634
|
+
info = await this.getUserInfo();
|
|
5013
4635
|
} catch (e) {
|
|
5014
|
-
|
|
4636
|
+
debug7("verify token failed %o", e);
|
|
5015
4637
|
return false;
|
|
5016
4638
|
}
|
|
4639
|
+
return info?.email || true;
|
|
5017
4640
|
}
|
|
5018
|
-
async
|
|
5019
|
-
|
|
5020
|
-
|
|
5021
|
-
|
|
5022
|
-
|
|
5023
|
-
});
|
|
5024
|
-
logDebug("[GraphQL] uploadS3BucketInfo successful", { result });
|
|
5025
|
-
return result;
|
|
5026
|
-
} catch (e) {
|
|
5027
|
-
logError("[GraphQL] uploadS3BucketInfo failed", {
|
|
5028
|
-
error: e,
|
|
5029
|
-
...this.getErrorContext()
|
|
5030
|
-
});
|
|
5031
|
-
throw e;
|
|
4641
|
+
async getLastOrgAndNamedProject(params) {
|
|
4642
|
+
const me = await this.getUserInfo();
|
|
4643
|
+
const email = me?.email;
|
|
4644
|
+
if (!email) {
|
|
4645
|
+
throw new Error("User email not found");
|
|
5032
4646
|
}
|
|
5033
|
-
|
|
5034
|
-
|
|
5035
|
-
|
|
5036
|
-
logDebug("[GraphQL] Calling getAnalysis query", { analysisId });
|
|
5037
|
-
const res = await this.clientSdk.getAnalysis({
|
|
5038
|
-
analysisId
|
|
5039
|
-
});
|
|
5040
|
-
logDebug("[GraphQL] getAnalysis successful", { result: res });
|
|
5041
|
-
if (!res.analysis) {
|
|
5042
|
-
throw new Error(`Analysis not found: ${analysisId}`);
|
|
5043
|
-
}
|
|
5044
|
-
return res.analysis;
|
|
5045
|
-
} catch (e) {
|
|
5046
|
-
logError("[GraphQL] getAnalysis failed", {
|
|
5047
|
-
error: e,
|
|
5048
|
-
analysisId,
|
|
5049
|
-
...this.getErrorContext()
|
|
5050
|
-
});
|
|
5051
|
-
throw e;
|
|
4647
|
+
const { projectName, userDefinedOrganizationId } = params;
|
|
4648
|
+
if (!projectName) {
|
|
4649
|
+
throw new Error("Project name is required");
|
|
5052
4650
|
}
|
|
5053
|
-
|
|
5054
|
-
|
|
5055
|
-
|
|
5056
|
-
|
|
5057
|
-
|
|
5058
|
-
|
|
5059
|
-
|
|
5060
|
-
|
|
5061
|
-
return result;
|
|
5062
|
-
} catch (e) {
|
|
5063
|
-
logError("[GraphQL] SubmitVulnerabilityReport failed", {
|
|
5064
|
-
error: e,
|
|
5065
|
-
variables,
|
|
5066
|
-
...this.getErrorContext()
|
|
5067
|
-
});
|
|
5068
|
-
throw e;
|
|
4651
|
+
const orgAndProjectRes = await this._clientSdk.getLastOrgAndNamedProject({
|
|
4652
|
+
email,
|
|
4653
|
+
projectName
|
|
4654
|
+
});
|
|
4655
|
+
if (!orgAndProjectRes.user?.[0]?.userOrganizationsAndUserOrganizationRoles?.[0]?.organization?.id) {
|
|
4656
|
+
throw new Error(
|
|
4657
|
+
`The user with email:${email} is not associated with any organization`
|
|
4658
|
+
);
|
|
5069
4659
|
}
|
|
5070
|
-
|
|
5071
|
-
|
|
5072
|
-
|
|
5073
|
-
|
|
5074
|
-
|
|
5075
|
-
|
|
5076
|
-
|
|
5077
|
-
|
|
5078
|
-
const result = await subscribe(
|
|
5079
|
-
GetAnalysisSubscriptionDocument,
|
|
5080
|
-
params.subscribeToAnalysisParams,
|
|
5081
|
-
async (resolve, reject, data) => {
|
|
5082
|
-
logDebug(
|
|
5083
|
-
`[${scanContext}] GraphQL: GetAnalysis subscription data received ${data.analysis?.state}`,
|
|
5084
|
-
{ data }
|
|
5085
|
-
);
|
|
5086
|
-
if (!data.analysis?.state || data.analysis?.state === "Failed" /* Failed */) {
|
|
5087
|
-
const errorMessage = data.analysis?.failReason || `Analysis failed with id: ${data.analysis?.id}`;
|
|
5088
|
-
logError(`[${scanContext}] GraphQL: Analysis failed`, {
|
|
5089
|
-
analysisId: data.analysis?.id,
|
|
5090
|
-
state: data.analysis?.state,
|
|
5091
|
-
failReason: data.analysis?.failReason,
|
|
5092
|
-
...this.getErrorContext()
|
|
5093
|
-
});
|
|
5094
|
-
reject(new Error(errorMessage));
|
|
5095
|
-
return;
|
|
5096
|
-
}
|
|
5097
|
-
if (callbackStates.includes(data.analysis?.state)) {
|
|
5098
|
-
logDebug(
|
|
5099
|
-
`[${scanContext}] GraphQL: Analysis state matches callback states: ${data.analysis.state}`,
|
|
5100
|
-
{
|
|
5101
|
-
analysisId: data.analysis.id,
|
|
5102
|
-
state: data.analysis.state,
|
|
5103
|
-
callbackStates
|
|
5104
|
-
}
|
|
5105
|
-
);
|
|
5106
|
-
await params.callback(data.analysis.id);
|
|
5107
|
-
resolve(data);
|
|
5108
|
-
}
|
|
5109
|
-
},
|
|
5110
|
-
this._auth.type === "apiKey" ? {
|
|
5111
|
-
apiKey: this._auth.apiKey,
|
|
5112
|
-
type: "apiKey",
|
|
5113
|
-
timeoutInMs: params.timeoutInMs
|
|
5114
|
-
} : {
|
|
5115
|
-
token: this._auth.token,
|
|
5116
|
-
type: "token",
|
|
5117
|
-
timeoutInMs: params.timeoutInMs
|
|
5118
|
-
}
|
|
4660
|
+
const organization = orgAndProjectRes.user?.at(0)?.userOrganizationsAndUserOrganizationRoles.map(
|
|
4661
|
+
(org) => org.organization
|
|
4662
|
+
).filter(
|
|
4663
|
+
(org) => userDefinedOrganizationId ? org.id === userDefinedOrganizationId : true
|
|
4664
|
+
)?.at(0);
|
|
4665
|
+
if (!organization) {
|
|
4666
|
+
throw new Error(
|
|
4667
|
+
`Organization with id:${userDefinedOrganizationId} not found`
|
|
5119
4668
|
);
|
|
5120
|
-
logDebug(`[${scanContext}] GraphQL: GetAnalysis subscription completed`, {
|
|
5121
|
-
result
|
|
5122
|
-
});
|
|
5123
|
-
return result;
|
|
5124
|
-
} catch (e) {
|
|
5125
|
-
logError(`[${scanContext}] GraphQL: GetAnalysis subscription failed`, {
|
|
5126
|
-
error: e,
|
|
5127
|
-
params: params.subscribeToAnalysisParams,
|
|
5128
|
-
...this.getErrorContext()
|
|
5129
|
-
});
|
|
5130
|
-
throw e;
|
|
5131
4669
|
}
|
|
5132
|
-
|
|
5133
|
-
|
|
5134
|
-
|
|
5135
|
-
const me = await this.getUserInfo();
|
|
5136
|
-
if (!me) {
|
|
5137
|
-
throw new Error("User not found");
|
|
5138
|
-
}
|
|
5139
|
-
const userEmail = me.email;
|
|
5140
|
-
if (!userEmail) {
|
|
5141
|
-
throw new Error("User email not found");
|
|
5142
|
-
}
|
|
5143
|
-
const shortEmailHash = crypto2.createHash("sha256").update(userEmail).digest("hex").slice(0, 8).toUpperCase();
|
|
5144
|
-
const projectName = `MCP Scans ${shortEmailHash}`;
|
|
5145
|
-
logDebug("[GraphQL] Calling getLastOrgAndNamedProject query", {
|
|
5146
|
-
projectName
|
|
5147
|
-
});
|
|
5148
|
-
const orgAndProjectRes = await this.clientSdk.getLastOrgAndNamedProject({
|
|
5149
|
-
email: userEmail,
|
|
5150
|
-
projectName
|
|
5151
|
-
});
|
|
5152
|
-
logDebug("[GraphQL] getLastOrgAndNamedProject successful", {
|
|
5153
|
-
result: orgAndProjectRes
|
|
5154
|
-
});
|
|
5155
|
-
if (!orgAndProjectRes.user?.[0]?.userOrganizationsAndUserOrganizationRoles?.[0]?.organization?.id) {
|
|
5156
|
-
throw new Error(
|
|
5157
|
-
`The user with email:${userEmail} is not associated with any organization`
|
|
5158
|
-
);
|
|
5159
|
-
}
|
|
5160
|
-
const organization = orgAndProjectRes.user?.[0]?.userOrganizationsAndUserOrganizationRoles?.[0]?.organization;
|
|
5161
|
-
const projectId = organization?.projects?.[0]?.id;
|
|
5162
|
-
if (projectId) {
|
|
5163
|
-
logDebug("[GraphQL] Found existing project", {
|
|
5164
|
-
projectId,
|
|
5165
|
-
projectName
|
|
5166
|
-
});
|
|
5167
|
-
return projectId;
|
|
5168
|
-
}
|
|
5169
|
-
logDebug("[GraphQL] Project not found, creating new project", {
|
|
4670
|
+
let projectId = organization?.projects?.[0]?.id;
|
|
4671
|
+
if (!projectId) {
|
|
4672
|
+
const createdProject = await this._clientSdk.CreateProject({
|
|
5170
4673
|
organizationId: organization.id,
|
|
5171
|
-
projectName
|
|
5172
|
-
});
|
|
5173
|
-
try {
|
|
5174
|
-
const createdProject = await this.clientSdk.CreateProject({
|
|
5175
|
-
organizationId: organization.id,
|
|
5176
|
-
projectName
|
|
5177
|
-
});
|
|
5178
|
-
logDebug("[GraphQL] CreateProject successful", {
|
|
5179
|
-
result: createdProject
|
|
5180
|
-
});
|
|
5181
|
-
return createdProject.createProject.projectId;
|
|
5182
|
-
} catch (createError) {
|
|
5183
|
-
const errorMessage = createError instanceof Error ? createError.message : String(createError);
|
|
5184
|
-
const isConstraintViolation = errorMessage.includes(
|
|
5185
|
-
"duplicate key value violates unique constraint"
|
|
5186
|
-
) && errorMessage.includes("project_name_organization_id_key");
|
|
5187
|
-
if (isConstraintViolation) {
|
|
5188
|
-
logDebug(
|
|
5189
|
-
"[GraphQL] Project creation failed due to constraint violation, retrying fetch",
|
|
5190
|
-
{
|
|
5191
|
-
organizationId: organization.id,
|
|
5192
|
-
projectName,
|
|
5193
|
-
error: errorMessage
|
|
5194
|
-
}
|
|
5195
|
-
);
|
|
5196
|
-
const retryOrgAndProjectRes = await this.clientSdk.getLastOrgAndNamedProject({
|
|
5197
|
-
email: userEmail,
|
|
5198
|
-
projectName
|
|
5199
|
-
});
|
|
5200
|
-
const retryProjectId = retryOrgAndProjectRes.user?.[0]?.userOrganizationsAndUserOrganizationRoles?.[0]?.organization?.projects?.[0]?.id;
|
|
5201
|
-
if (retryProjectId) {
|
|
5202
|
-
logDebug(
|
|
5203
|
-
"[GraphQL] Successfully found existing project after constraint violation",
|
|
5204
|
-
{
|
|
5205
|
-
projectId: retryProjectId,
|
|
5206
|
-
projectName
|
|
5207
|
-
}
|
|
5208
|
-
);
|
|
5209
|
-
return retryProjectId;
|
|
5210
|
-
}
|
|
5211
|
-
logError(
|
|
5212
|
-
"[GraphQL] Failed to find project even after constraint violation retry",
|
|
5213
|
-
{
|
|
5214
|
-
organizationId: organization.id,
|
|
5215
|
-
projectName,
|
|
5216
|
-
retryResult: retryOrgAndProjectRes
|
|
5217
|
-
}
|
|
5218
|
-
);
|
|
5219
|
-
}
|
|
5220
|
-
throw createError;
|
|
5221
|
-
}
|
|
5222
|
-
} catch (e) {
|
|
5223
|
-
logError("[GraphQL] getProjectId failed", {
|
|
5224
|
-
error: e,
|
|
5225
|
-
...this.getErrorContext()
|
|
4674
|
+
projectName: projectName || "My project"
|
|
5226
4675
|
});
|
|
5227
|
-
|
|
4676
|
+
projectId = createdProject.createProject.projectId;
|
|
5228
4677
|
}
|
|
5229
|
-
|
|
5230
|
-
|
|
5231
|
-
const { me } = await this.clientSdk.Me();
|
|
5232
|
-
this.currentUser = me;
|
|
5233
|
-
return me;
|
|
5234
|
-
}
|
|
5235
|
-
getCurrentUser() {
|
|
5236
|
-
return this.currentUser;
|
|
5237
|
-
}
|
|
5238
|
-
async validateUserToken() {
|
|
5239
|
-
logDebug("[GraphQL] Validating user token");
|
|
5240
|
-
try {
|
|
5241
|
-
await this.clientSdk.CreateCommunityUser();
|
|
5242
|
-
const info = await this.getUserInfo();
|
|
5243
|
-
logDebug("[GraphQL] User token validated successfully");
|
|
5244
|
-
return info?.email || true;
|
|
5245
|
-
} catch (e) {
|
|
5246
|
-
logError("[GraphQL] User token validation failed");
|
|
5247
|
-
return false;
|
|
5248
|
-
}
|
|
5249
|
-
}
|
|
5250
|
-
async createCliLogin(variables) {
|
|
5251
|
-
try {
|
|
5252
|
-
const res = await this.clientSdk.CreateCliLogin(variables, {
|
|
5253
|
-
// We may have outdated API key in the config storage. Avoid using it for the login request.
|
|
5254
|
-
[MCP_API_KEY_HEADER_NAME]: ""
|
|
5255
|
-
});
|
|
5256
|
-
const loginId = res.insert_cli_login_one?.id || "";
|
|
5257
|
-
if (!loginId) {
|
|
5258
|
-
logError("[GraphQL] Create cli login failed - no login ID returned");
|
|
5259
|
-
return "";
|
|
5260
|
-
}
|
|
5261
|
-
return loginId;
|
|
5262
|
-
} catch (e) {
|
|
5263
|
-
logError("[GraphQL] Create cli login failed", { error: e });
|
|
5264
|
-
return "";
|
|
4678
|
+
if (!projectId) {
|
|
4679
|
+
throw new Error("Project not found");
|
|
5265
4680
|
}
|
|
4681
|
+
return {
|
|
4682
|
+
organizationId: organization.id,
|
|
4683
|
+
projectId
|
|
4684
|
+
};
|
|
5266
4685
|
}
|
|
5267
4686
|
async getEncryptedApiToken(variables) {
|
|
4687
|
+
const res = await this._clientSdk.GetEncryptedApiToken(variables, {
|
|
4688
|
+
// We may have outdated API key in the config storage. Avoid using it for the login request.
|
|
4689
|
+
[API_KEY_HEADER_NAME]: ""
|
|
4690
|
+
});
|
|
4691
|
+
return res?.cli_login_by_pk?.encryptedApiToken || null;
|
|
4692
|
+
}
|
|
4693
|
+
async createCommunityUser() {
|
|
5268
4694
|
try {
|
|
5269
|
-
|
|
5270
|
-
// We may have outdated API key in the config storage. Avoid using it for the login request.
|
|
5271
|
-
[MCP_API_KEY_HEADER_NAME]: ""
|
|
5272
|
-
});
|
|
5273
|
-
return res?.cli_login_by_pk?.encryptedApiToken || null;
|
|
4695
|
+
await this._clientSdk.CreateCommunityUser();
|
|
5274
4696
|
} catch (e) {
|
|
5275
|
-
|
|
5276
|
-
return null;
|
|
5277
|
-
}
|
|
5278
|
-
}
|
|
5279
|
-
generateFixUrl({
|
|
5280
|
-
fixId,
|
|
5281
|
-
organizationId,
|
|
5282
|
-
projectId,
|
|
5283
|
-
reportId
|
|
5284
|
-
}) {
|
|
5285
|
-
if (!organizationId || !projectId || !reportId) {
|
|
5286
|
-
return void 0;
|
|
5287
|
-
}
|
|
5288
|
-
const appBaseUrl = this.apiUrl.replace("/v1/graphql", "").replace("api.", "");
|
|
5289
|
-
return `${appBaseUrl}/organization/${organizationId}/project/${projectId}/report/${reportId}/fix/${fixId}`;
|
|
5290
|
-
}
|
|
5291
|
-
mergeUserAndSystemFixes({
|
|
5292
|
-
reportData,
|
|
5293
|
-
limit
|
|
5294
|
-
}) {
|
|
5295
|
-
if (!reportData) return [];
|
|
5296
|
-
const reportMetadata = {
|
|
5297
|
-
id: reportData.id,
|
|
5298
|
-
organizationId: reportData.vulnerabilityReport?.project?.organizationId,
|
|
5299
|
-
projectId: reportData.vulnerabilityReport?.projectId
|
|
5300
|
-
};
|
|
5301
|
-
const { userFixes = [], fixes = [] } = reportData;
|
|
5302
|
-
const fixMap = /* @__PURE__ */ new Map();
|
|
5303
|
-
for (const fix of userFixes) {
|
|
5304
|
-
if (fix.id) {
|
|
5305
|
-
const fixWithUrl = {
|
|
5306
|
-
...fix,
|
|
5307
|
-
fixUrl: this.generateFixUrl({
|
|
5308
|
-
fixId: fix.id,
|
|
5309
|
-
organizationId: reportMetadata?.organizationId,
|
|
5310
|
-
projectId: reportMetadata?.projectId,
|
|
5311
|
-
reportId: reportMetadata?.id
|
|
5312
|
-
})
|
|
5313
|
-
};
|
|
5314
|
-
fixMap.set(fix.id, fixWithUrl);
|
|
5315
|
-
}
|
|
5316
|
-
}
|
|
5317
|
-
for (const fix of fixes) {
|
|
5318
|
-
if (fix.id && !fixMap.has(fix.id)) {
|
|
5319
|
-
const fixWithUrl = {
|
|
5320
|
-
...fix,
|
|
5321
|
-
fixUrl: this.generateFixUrl({
|
|
5322
|
-
fixId: fix.id,
|
|
5323
|
-
organizationId: reportMetadata?.organizationId,
|
|
5324
|
-
projectId: reportMetadata?.projectId,
|
|
5325
|
-
reportId: reportMetadata?.id
|
|
5326
|
-
})
|
|
5327
|
-
};
|
|
5328
|
-
fixMap.set(fix.id, fixWithUrl);
|
|
5329
|
-
}
|
|
4697
|
+
debug7("create community user failed %o", e);
|
|
5330
4698
|
}
|
|
5331
|
-
return Array.from(fixMap.values()).slice(0, limit);
|
|
5332
4699
|
}
|
|
5333
|
-
async
|
|
5334
|
-
|
|
5335
|
-
|
|
5336
|
-
|
|
5337
|
-
|
|
5338
|
-
|
|
5339
|
-
|
|
5340
|
-
|
|
5341
|
-
|
|
5342
|
-
|
|
5343
|
-
} else {
|
|
5344
|
-
logDebug("[GraphQL] No fixes found to update download status");
|
|
5345
|
-
}
|
|
5346
|
-
}
|
|
5347
|
-
async updateAutoAppliedFixesStatus(fixIds) {
|
|
5348
|
-
if (fixIds.length > 0) {
|
|
5349
|
-
const resUpdate = await this.clientSdk.updateDownloadedFixData({
|
|
5350
|
-
fixIds,
|
|
5351
|
-
source: "AUTO_MVS" /* AutoMvs */
|
|
5352
|
-
});
|
|
5353
|
-
logDebug("[GraphQL] updateAutoAppliedFixesStatus successful", {
|
|
5354
|
-
result: resUpdate,
|
|
5355
|
-
fixIds,
|
|
5356
|
-
note: "Auto-applied via MVS automation"
|
|
5357
|
-
});
|
|
5358
|
-
} else {
|
|
5359
|
-
logDebug("[GraphQL] No auto-applied fixes to update status");
|
|
5360
|
-
}
|
|
4700
|
+
async updateScmToken(args) {
|
|
4701
|
+
const { scmType, url, token, org, refreshToken } = args;
|
|
4702
|
+
const updateScmTokenResult = await this._clientSdk.updateScmToken({
|
|
4703
|
+
scmType,
|
|
4704
|
+
url,
|
|
4705
|
+
token,
|
|
4706
|
+
org,
|
|
4707
|
+
refreshToken
|
|
4708
|
+
});
|
|
4709
|
+
return updateScmTokenResult;
|
|
5361
4710
|
}
|
|
5362
|
-
async
|
|
5363
|
-
|
|
5364
|
-
|
|
5365
|
-
|
|
5366
|
-
|
|
5367
|
-
logDebug("[Environment] Using MVS_AUTO_FIX override", {
|
|
5368
|
-
envValue: envOverride,
|
|
5369
|
-
resolvedValue: overrideValue
|
|
5370
|
-
});
|
|
5371
|
-
return overrideValue;
|
|
5372
|
-
}
|
|
5373
|
-
const userInfo = await this.getUserInfo();
|
|
5374
|
-
if (!userInfo?.email) {
|
|
5375
|
-
throw new Error("User email not found");
|
|
5376
|
-
}
|
|
5377
|
-
logDebug("[GraphQL] Calling GetUserMvsAutoFix query", {
|
|
5378
|
-
userEmail: userInfo.email
|
|
5379
|
-
});
|
|
5380
|
-
const result = await this.clientSdk.GetUserMvsAutoFix({
|
|
5381
|
-
userEmail: userInfo.email
|
|
5382
|
-
});
|
|
5383
|
-
logDebug("[GraphQL] GetUserMvsAutoFix successful", { result });
|
|
5384
|
-
return result.user_email_notification_settings?.[0]?.mvs_auto_fix ?? true;
|
|
5385
|
-
} catch (e) {
|
|
5386
|
-
logError("[GraphQL] GetUserMvsAutoFix failed", {
|
|
5387
|
-
error: e,
|
|
5388
|
-
...this.getErrorContext()
|
|
5389
|
-
});
|
|
5390
|
-
throw e;
|
|
5391
|
-
}
|
|
4711
|
+
async uploadS3BucketInfo() {
|
|
4712
|
+
const uploadS3BucketInfoResult = await this._clientSdk.uploadS3BucketInfo({
|
|
4713
|
+
fileName: REPORT_DEFAULT_FILE_NAME
|
|
4714
|
+
});
|
|
4715
|
+
return uploadS3BucketInfoResult;
|
|
5392
4716
|
}
|
|
5393
|
-
async
|
|
5394
|
-
|
|
5395
|
-
|
|
5396
|
-
offset = 0,
|
|
5397
|
-
fileFilter
|
|
4717
|
+
async getVulByNodesMetadata({
|
|
4718
|
+
hunks,
|
|
4719
|
+
vulnerabilityReportId
|
|
5398
4720
|
}) {
|
|
5399
|
-
|
|
5400
|
-
|
|
5401
|
-
|
|
5402
|
-
|
|
5403
|
-
|
|
5404
|
-
|
|
5405
|
-
|
|
5406
|
-
|
|
5407
|
-
|
|
5408
|
-
|
|
5409
|
-
|
|
5410
|
-
|
|
5411
|
-
|
|
5412
|
-
|
|
5413
|
-
|
|
5414
|
-
|
|
5415
|
-
|
|
5416
|
-
|
|
5417
|
-
|
|
5418
|
-
|
|
5419
|
-
|
|
5420
|
-
|
|
5421
|
-
};
|
|
4721
|
+
const filters = hunks.map((hunk) => {
|
|
4722
|
+
const filter = {
|
|
4723
|
+
path: { _eq: hunk.path },
|
|
4724
|
+
_or: hunk.ranges.flatMap(({ endLine, startLine }) => {
|
|
4725
|
+
return [
|
|
4726
|
+
{ startLine: { _gte: startLine, _lte: endLine } },
|
|
4727
|
+
{ endLine: { _gte: startLine, _lte: endLine } }
|
|
4728
|
+
];
|
|
4729
|
+
})
|
|
4730
|
+
};
|
|
4731
|
+
return filter;
|
|
4732
|
+
});
|
|
4733
|
+
const getVulByNodesMetadataRes = await this._clientSdk.getVulByNodesMetadata({
|
|
4734
|
+
filters: { _or: filters },
|
|
4735
|
+
vulnerabilityReportId
|
|
4736
|
+
});
|
|
4737
|
+
const parsedGetVulByNodesMetadataRes = GetVulByNodesMetadataZ.parse(
|
|
4738
|
+
getVulByNodesMetadataRes
|
|
4739
|
+
);
|
|
4740
|
+
const uniqueVulByNodesMetadata = parsedGetVulByNodesMetadataRes.vulnerabilityReportIssueCodeNodes.reduce((acc, vulnerabilityReportIssueCodeNode) => {
|
|
4741
|
+
if (acc[vulnerabilityReportIssueCodeNode.vulnerabilityReportIssueId]) {
|
|
4742
|
+
return acc;
|
|
5422
4743
|
}
|
|
5423
|
-
const resp = await this.clientSdk.GetLatestReportByRepoUrl({
|
|
5424
|
-
repoUrl,
|
|
5425
|
-
limit,
|
|
5426
|
-
offset,
|
|
5427
|
-
currentUserEmail,
|
|
5428
|
-
filters
|
|
5429
|
-
});
|
|
5430
|
-
logDebug("[GraphQL] GetLatestReportByRepoUrl successful", {
|
|
5431
|
-
result: resp,
|
|
5432
|
-
reportCount: resp.fixReport?.length || 0
|
|
5433
|
-
});
|
|
5434
|
-
const latestReport = resp.fixReport?.[0] && FixReportSummarySchema.parse(resp.fixReport?.[0]);
|
|
5435
|
-
const fixes = this.mergeUserAndSystemFixes({
|
|
5436
|
-
reportData: latestReport,
|
|
5437
|
-
limit
|
|
5438
|
-
});
|
|
5439
4744
|
return {
|
|
5440
|
-
|
|
5441
|
-
|
|
5442
|
-
fixes
|
|
5443
|
-
} : null,
|
|
5444
|
-
expiredReport: resp.expiredReport?.[0] || null
|
|
4745
|
+
...acc,
|
|
4746
|
+
[vulnerabilityReportIssueCodeNode.vulnerabilityReportIssueId]: vulnerabilityReportIssueCodeNode
|
|
5445
4747
|
};
|
|
5446
|
-
}
|
|
5447
|
-
|
|
5448
|
-
|
|
5449
|
-
|
|
5450
|
-
|
|
5451
|
-
|
|
5452
|
-
|
|
5453
|
-
|
|
4748
|
+
}, {});
|
|
4749
|
+
const nonFixablePrVuls = parsedGetVulByNodesMetadataRes.nonFixablePrVuls.aggregate.count;
|
|
4750
|
+
const fixablePrVuls = parsedGetVulByNodesMetadataRes.fixablePrVuls.aggregate.count;
|
|
4751
|
+
const totalScanVulnerabilities = parsedGetVulByNodesMetadataRes.totalScanVulnerabilities.aggregate.count;
|
|
4752
|
+
const vulnerabilitiesOutsidePr = totalScanVulnerabilities - nonFixablePrVuls - fixablePrVuls;
|
|
4753
|
+
const totalPrVulnerabilities = nonFixablePrVuls + fixablePrVuls;
|
|
4754
|
+
const irrelevantVulnerabilityReportIssues = parsedGetVulByNodesMetadataRes.irrelevantVulnerabilityReportIssue?.[0]?.vulnerabilityReportIssues ?? [];
|
|
4755
|
+
return {
|
|
4756
|
+
vulnerabilityReportIssueCodeNodes: Object.values(
|
|
4757
|
+
uniqueVulByNodesMetadata
|
|
4758
|
+
),
|
|
4759
|
+
nonFixablePrVuls,
|
|
4760
|
+
fixablePrVuls,
|
|
4761
|
+
totalScanVulnerabilities,
|
|
4762
|
+
vulnerabilitiesOutsidePr,
|
|
4763
|
+
totalPrVulnerabilities,
|
|
4764
|
+
irrelevantVulnerabilityReportIssues
|
|
4765
|
+
};
|
|
5454
4766
|
}
|
|
5455
|
-
async
|
|
5456
|
-
|
|
5457
|
-
|
|
5458
|
-
|
|
5459
|
-
|
|
5460
|
-
|
|
5461
|
-
|
|
4767
|
+
async digestVulnerabilityReport({
|
|
4768
|
+
fixReportId,
|
|
4769
|
+
projectId,
|
|
4770
|
+
scanSource,
|
|
4771
|
+
repoUrl,
|
|
4772
|
+
reference,
|
|
4773
|
+
sha,
|
|
4774
|
+
shouldScan
|
|
5462
4775
|
}) {
|
|
5463
|
-
const
|
|
5464
|
-
|
|
5465
|
-
|
|
5466
|
-
|
|
5467
|
-
|
|
5468
|
-
|
|
4776
|
+
const res = await this._clientSdk.DigestVulnerabilityReport({
|
|
4777
|
+
fixReportId,
|
|
4778
|
+
vulnerabilityReportFileName: shouldScan ? void 0 : REPORT_DEFAULT_FILE_NAME,
|
|
4779
|
+
projectId,
|
|
4780
|
+
scanSource,
|
|
4781
|
+
repoUrl,
|
|
4782
|
+
reference,
|
|
4783
|
+
sha
|
|
4784
|
+
});
|
|
4785
|
+
if (res.digestVulnerabilityReport.__typename !== "VulnerabilityReport") {
|
|
4786
|
+
throw new Error("Digesting vulnerability report failed");
|
|
5469
4787
|
}
|
|
5470
|
-
|
|
5471
|
-
|
|
5472
|
-
|
|
5473
|
-
|
|
4788
|
+
return res.digestVulnerabilityReport;
|
|
4789
|
+
}
|
|
4790
|
+
async submitVulnerabilityReport(params) {
|
|
4791
|
+
const {
|
|
4792
|
+
fixReportId,
|
|
4793
|
+
repoUrl,
|
|
4794
|
+
reference,
|
|
4795
|
+
projectId,
|
|
4796
|
+
sha,
|
|
4797
|
+
experimentalEnabled,
|
|
4798
|
+
vulnerabilityReportFileName,
|
|
4799
|
+
pullRequest
|
|
4800
|
+
} = params;
|
|
4801
|
+
return await this._clientSdk.SubmitVulnerabilityReport({
|
|
4802
|
+
fixReportId,
|
|
4803
|
+
repoUrl,
|
|
4804
|
+
reference,
|
|
4805
|
+
vulnerabilityReportFileName,
|
|
4806
|
+
projectId,
|
|
4807
|
+
pullRequest,
|
|
4808
|
+
sha: sha || "",
|
|
4809
|
+
experimentalEnabled: !!experimentalEnabled,
|
|
4810
|
+
scanSource: params.scanSource,
|
|
4811
|
+
scanContext: ScanContext.BUGSY
|
|
4812
|
+
});
|
|
4813
|
+
}
|
|
4814
|
+
async getFixReportState(fixReportId) {
|
|
4815
|
+
const res = await this._clientSdk.FixReportState({ id: fixReportId });
|
|
4816
|
+
return res?.fixReport_by_pk?.state || "Created" /* Created */;
|
|
4817
|
+
}
|
|
4818
|
+
async waitFixReportInit(fixReportId, includeDigested = false) {
|
|
4819
|
+
const FINAL_STATES = [
|
|
4820
|
+
"Finished" /* Finished */,
|
|
4821
|
+
"Failed" /* Failed */
|
|
4822
|
+
];
|
|
4823
|
+
let lastState = "Created" /* Created */;
|
|
4824
|
+
let attempts = 100;
|
|
4825
|
+
if (includeDigested) {
|
|
4826
|
+
FINAL_STATES.push("Digested" /* Digested */);
|
|
5474
4827
|
}
|
|
5475
|
-
|
|
5476
|
-
|
|
5477
|
-
|
|
5478
|
-
|
|
5479
|
-
|
|
5480
|
-
|
|
5481
|
-
|
|
5482
|
-
|
|
5483
|
-
|
|
5484
|
-
|
|
5485
|
-
|
|
5486
|
-
|
|
5487
|
-
|
|
5488
|
-
|
|
5489
|
-
|
|
4828
|
+
do {
|
|
4829
|
+
await sleep(REPORT_STATE_CHECK_DELAY);
|
|
4830
|
+
lastState = await this.getFixReportState(fixReportId);
|
|
4831
|
+
} while (!FINAL_STATES.includes(
|
|
4832
|
+
lastState
|
|
4833
|
+
// wait for final the state of the fix report
|
|
4834
|
+
) && attempts-- > 0);
|
|
4835
|
+
return lastState;
|
|
4836
|
+
}
|
|
4837
|
+
async getVulnerabilityReportPaths(vulnerabilityReportId) {
|
|
4838
|
+
const res = await this._clientSdk.GetVulnerabilityReportPaths({
|
|
4839
|
+
vulnerabilityReportId
|
|
4840
|
+
});
|
|
4841
|
+
return res.vulnerability_report_path.map((p) => p.path);
|
|
4842
|
+
}
|
|
4843
|
+
async subscribeToAnalysis(params) {
|
|
4844
|
+
const { callbackStates } = params;
|
|
4845
|
+
return subscribe(
|
|
4846
|
+
GetAnalysisSubscriptionDocument,
|
|
4847
|
+
params.subscribeToAnalysisParams,
|
|
4848
|
+
async (resolve, reject, data) => {
|
|
4849
|
+
if (!data.analysis?.state || data.analysis?.state === "Failed" /* Failed */) {
|
|
4850
|
+
const errorMessage = data.analysis?.failReason || `Analysis failed with id: ${data.analysis?.id}`;
|
|
4851
|
+
reject(
|
|
4852
|
+
new ReportDigestError(errorMessage, data.analysis?.failReason ?? "")
|
|
4853
|
+
);
|
|
4854
|
+
return;
|
|
5490
4855
|
}
|
|
5491
|
-
|
|
5492
|
-
|
|
5493
|
-
|
|
5494
|
-
}
|
|
5495
|
-
}
|
|
5496
|
-
|
|
5497
|
-
|
|
5498
|
-
|
|
5499
|
-
|
|
5500
|
-
|
|
5501
|
-
|
|
5502
|
-
|
|
5503
|
-
|
|
5504
|
-
result: res,
|
|
5505
|
-
fixCount: res.fixReport?.[0]?.fixes?.length || 0,
|
|
5506
|
-
totalCount: res.fixReport?.[0]?.filteredFixesCount?.aggregate?.count || 0
|
|
5507
|
-
});
|
|
5508
|
-
if (res.fixReport.length === 0) {
|
|
5509
|
-
return null;
|
|
4856
|
+
if (callbackStates.includes(data.analysis?.state)) {
|
|
4857
|
+
await params.callback(data.analysis.id);
|
|
4858
|
+
resolve(data);
|
|
4859
|
+
}
|
|
4860
|
+
},
|
|
4861
|
+
this._auth.type === "apiKey" ? {
|
|
4862
|
+
apiKey: this._auth.apiKey,
|
|
4863
|
+
type: "apiKey",
|
|
4864
|
+
timeoutInMs: params.timeoutInMs
|
|
4865
|
+
} : {
|
|
4866
|
+
token: this._auth.token,
|
|
4867
|
+
type: "token",
|
|
4868
|
+
timeoutInMs: params.timeoutInMs
|
|
5510
4869
|
}
|
|
5511
|
-
|
|
5512
|
-
|
|
5513
|
-
|
|
5514
|
-
|
|
5515
|
-
|
|
5516
|
-
|
|
5517
|
-
|
|
5518
|
-
|
|
5519
|
-
|
|
5520
|
-
|
|
5521
|
-
|
|
5522
|
-
|
|
5523
|
-
|
|
5524
|
-
|
|
5525
|
-
} : void 0
|
|
5526
|
-
};
|
|
5527
|
-
} catch (e) {
|
|
5528
|
-
logError("[GraphQL] GetReportFixes failed", {
|
|
5529
|
-
error: e,
|
|
5530
|
-
reportId,
|
|
5531
|
-
...this.getErrorContext()
|
|
5532
|
-
});
|
|
5533
|
-
throw e;
|
|
4870
|
+
);
|
|
4871
|
+
}
|
|
4872
|
+
async getFixReportsByRepoUrl({ repoUrl }) {
|
|
4873
|
+
const res = await this._clientSdk.GetFixReportsByRepoUrl({
|
|
4874
|
+
repoUrl
|
|
4875
|
+
});
|
|
4876
|
+
return res;
|
|
4877
|
+
}
|
|
4878
|
+
async getAnalysis(analysisId) {
|
|
4879
|
+
const res = await this._clientSdk.getAnalysis({
|
|
4880
|
+
analysisId
|
|
4881
|
+
});
|
|
4882
|
+
if (!res.analysis) {
|
|
4883
|
+
throw new Error(`Analysis not found: ${analysisId}`);
|
|
5534
4884
|
}
|
|
4885
|
+
return res.analysis;
|
|
4886
|
+
}
|
|
4887
|
+
async autoPrAnalysis({
|
|
4888
|
+
analysisId,
|
|
4889
|
+
commitDirectly,
|
|
4890
|
+
prId,
|
|
4891
|
+
prStrategy
|
|
4892
|
+
}) {
|
|
4893
|
+
return this._clientSdk.autoPrAnalysis({
|
|
4894
|
+
analysisId,
|
|
4895
|
+
commitDirectly,
|
|
4896
|
+
prId,
|
|
4897
|
+
prStrategy
|
|
4898
|
+
});
|
|
4899
|
+
}
|
|
4900
|
+
async getFixes(fixIds) {
|
|
4901
|
+
const res = await this._clientSdk.getFixes({
|
|
4902
|
+
filters: { id: { _in: fixIds } }
|
|
4903
|
+
});
|
|
4904
|
+
return res;
|
|
4905
|
+
}
|
|
4906
|
+
async validateRepoUrl(args) {
|
|
4907
|
+
return this._clientSdk.validateRepoUrl(args);
|
|
4908
|
+
}
|
|
4909
|
+
async getReferenceData(args) {
|
|
4910
|
+
return this._clientSdk.gitReference(args);
|
|
4911
|
+
}
|
|
4912
|
+
async getFalsePositive(args) {
|
|
4913
|
+
return this._clientSdk.getFalsePositive(args);
|
|
4914
|
+
}
|
|
4915
|
+
async uploadAIBlameInferencesInitRaw(variables) {
|
|
4916
|
+
return await this._clientSdk.UploadAIBlameInferencesInit(variables);
|
|
4917
|
+
}
|
|
4918
|
+
async finalizeAIBlameInferencesUploadRaw(variables) {
|
|
4919
|
+
return await this._clientSdk.FinalizeAIBlameInferencesUpload(variables);
|
|
5535
4920
|
}
|
|
5536
4921
|
};
|
|
5537
|
-
|
|
5538
|
-
|
|
5539
|
-
|
|
5540
|
-
|
|
5541
|
-
|
|
4922
|
+
|
|
4923
|
+
// src/commands/handleMobbLogin.ts
|
|
4924
|
+
var debug8 = Debug7("mobbdev:commands");
|
|
4925
|
+
var LOGIN_MAX_WAIT = 10 * 60 * 1e3;
|
|
4926
|
+
var LOGIN_CHECK_DELAY = 5 * 1e3;
|
|
4927
|
+
var webLoginUrl = `${WEB_APP_URL}/cli-login`;
|
|
4928
|
+
var MOBB_LOGIN_REQUIRED_MSG = `\u{1F513} Login to Mobb is Required, you will be redirected to our login page, once the authorization is complete return to this prompt, ${chalk2.bgBlue(
|
|
4929
|
+
"press any key to continue"
|
|
4930
|
+
)};`;
|
|
4931
|
+
var config2 = new Configstore(packageJson.name, { apiToken: "" });
|
|
4932
|
+
async function handleMobbLogin({
|
|
4933
|
+
inGqlClient,
|
|
4934
|
+
apiKey,
|
|
4935
|
+
skipPrompts
|
|
4936
|
+
}) {
|
|
4937
|
+
const { createSpinner } = Spinner({ ci: skipPrompts });
|
|
4938
|
+
const isConnected = await inGqlClient.verifyApiConnection();
|
|
4939
|
+
if (!isConnected) {
|
|
4940
|
+
createSpinner().start().error({
|
|
4941
|
+
text: "\u{1F513} Connection to Mobb: failed to connect to the Mobb server"
|
|
4942
|
+
});
|
|
4943
|
+
throw new CliError(
|
|
4944
|
+
"Connection to Mobb: failed to connect to the Mobb server"
|
|
4945
|
+
);
|
|
4946
|
+
}
|
|
4947
|
+
createSpinner().start().success({
|
|
4948
|
+
text: `\u{1F513} Connection to Mobb: succeeded`
|
|
5542
4949
|
});
|
|
5543
|
-
const
|
|
5544
|
-
|
|
5545
|
-
|
|
5546
|
-
|
|
4950
|
+
const userVerify = await inGqlClient.validateUserToken();
|
|
4951
|
+
if (userVerify) {
|
|
4952
|
+
createSpinner().start().success({
|
|
4953
|
+
text: `\u{1F513} Login to Mobb succeeded. ${typeof userVerify === "string" ? `Logged in as ${userVerify}` : ""}`
|
|
4954
|
+
});
|
|
4955
|
+
return inGqlClient;
|
|
4956
|
+
} else if (apiKey) {
|
|
4957
|
+
createSpinner().start().error({
|
|
4958
|
+
text: "\u{1F513} Login to Mobb failed: The provided API key does not match any configured API key on the system"
|
|
4959
|
+
});
|
|
4960
|
+
throw new CliError(
|
|
4961
|
+
"Login to Mobb failed: The provided API key does not match any configured API key on the system"
|
|
4962
|
+
);
|
|
4963
|
+
}
|
|
4964
|
+
const loginSpinner = createSpinner().start();
|
|
4965
|
+
if (!skipPrompts) {
|
|
4966
|
+
loginSpinner.update({ text: MOBB_LOGIN_REQUIRED_MSG });
|
|
4967
|
+
await keypress();
|
|
4968
|
+
}
|
|
4969
|
+
loginSpinner.update({
|
|
4970
|
+
text: "\u{1F513} Waiting for Mobb login..."
|
|
4971
|
+
});
|
|
4972
|
+
const { publicKey, privateKey } = crypto.generateKeyPairSync("rsa", {
|
|
4973
|
+
modulusLength: 2048
|
|
4974
|
+
});
|
|
4975
|
+
const loginId = await inGqlClient.createCliLogin({
|
|
4976
|
+
publicKey: publicKey.export({ format: "pem", type: "pkcs1" }).toString()
|
|
5547
4977
|
});
|
|
5548
|
-
const
|
|
5549
|
-
|
|
5550
|
-
|
|
5551
|
-
|
|
4978
|
+
const browserUrl = `${webLoginUrl}/${loginId}?hostname=${os.hostname()}`;
|
|
4979
|
+
!skipPrompts && console.log(
|
|
4980
|
+
`If the page does not open automatically, kindly access it through ${browserUrl}.`
|
|
4981
|
+
);
|
|
4982
|
+
await open(browserUrl);
|
|
4983
|
+
let newApiToken = null;
|
|
4984
|
+
for (let i = 0; i < LOGIN_MAX_WAIT / LOGIN_CHECK_DELAY; i++) {
|
|
4985
|
+
const encryptedApiToken = await inGqlClient.getEncryptedApiToken({
|
|
4986
|
+
loginId
|
|
4987
|
+
});
|
|
4988
|
+
loginSpinner.spin();
|
|
4989
|
+
if (encryptedApiToken) {
|
|
4990
|
+
debug8("encrypted API token received %s", encryptedApiToken);
|
|
4991
|
+
newApiToken = crypto.privateDecrypt(privateKey, Buffer.from(encryptedApiToken, "base64")).toString("utf-8");
|
|
4992
|
+
debug8("API token decrypted");
|
|
4993
|
+
break;
|
|
4994
|
+
}
|
|
4995
|
+
await sleep(LOGIN_CHECK_DELAY);
|
|
5552
4996
|
}
|
|
5553
|
-
|
|
5554
|
-
|
|
5555
|
-
|
|
5556
|
-
|
|
4997
|
+
if (!newApiToken) {
|
|
4998
|
+
loginSpinner.error({
|
|
4999
|
+
text: "Login timeout error"
|
|
5000
|
+
});
|
|
5001
|
+
throw new CliError();
|
|
5002
|
+
}
|
|
5003
|
+
const newGqlClient = new GQLClient({ apiKey: newApiToken, type: "apiKey" });
|
|
5004
|
+
const loginSuccess = await newGqlClient.validateUserToken();
|
|
5005
|
+
if (loginSuccess) {
|
|
5006
|
+
debug8(`set api token ${newApiToken}`);
|
|
5007
|
+
config2.set("apiToken", newApiToken);
|
|
5008
|
+
loginSpinner.success({
|
|
5009
|
+
text: `\u{1F513} Login to Mobb successful! ${typeof loginSpinner === "string" ? `Logged in as ${loginSuccess}` : ""}`
|
|
5010
|
+
});
|
|
5011
|
+
} else {
|
|
5012
|
+
loginSpinner.error({
|
|
5013
|
+
text: "Something went wrong, API token is invalid."
|
|
5014
|
+
});
|
|
5015
|
+
throw new CliError();
|
|
5016
|
+
}
|
|
5017
|
+
return newGqlClient;
|
|
5018
|
+
}
|
|
5019
|
+
|
|
5020
|
+
// src/features/analysis/upload-file.ts
|
|
5021
|
+
import Debug8 from "debug";
|
|
5022
|
+
import fetch3, { File, fileFrom, FormData } from "node-fetch";
|
|
5023
|
+
var debug9 = Debug8("mobbdev:upload-file");
|
|
5024
|
+
async function uploadFile({
|
|
5025
|
+
file,
|
|
5026
|
+
url,
|
|
5027
|
+
uploadKey,
|
|
5028
|
+
uploadFields,
|
|
5029
|
+
logger
|
|
5030
|
+
}) {
|
|
5031
|
+
const logInfo = logger || ((_message, _data) => {
|
|
5032
|
+
});
|
|
5033
|
+
logInfo(`FileUpload: upload file start ${url}`);
|
|
5034
|
+
logInfo(`FileUpload: upload fields`, uploadFields);
|
|
5035
|
+
logInfo(`FileUpload: upload key ${uploadKey}`);
|
|
5036
|
+
debug9("upload file start %s", url);
|
|
5037
|
+
debug9("upload fields %o", uploadFields);
|
|
5038
|
+
debug9("upload key %s", uploadKey);
|
|
5039
|
+
const form = new FormData();
|
|
5040
|
+
Object.entries(uploadFields).forEach(([key, value]) => {
|
|
5041
|
+
form.append(key, value);
|
|
5042
|
+
});
|
|
5043
|
+
if (!form.has("key")) {
|
|
5044
|
+
form.append("key", uploadKey);
|
|
5045
|
+
}
|
|
5046
|
+
if (typeof file === "string") {
|
|
5047
|
+
debug9("upload file from path %s", file);
|
|
5048
|
+
logInfo(`FileUpload: upload file from path ${file}`);
|
|
5049
|
+
form.append("file", await fileFrom(file));
|
|
5050
|
+
} else {
|
|
5051
|
+
debug9("upload file from buffer");
|
|
5052
|
+
logInfo(`FileUpload: upload file from buffer`);
|
|
5053
|
+
form.append("file", new File([new Uint8Array(file)], "file"));
|
|
5054
|
+
}
|
|
5055
|
+
const agent = getProxyAgent(url);
|
|
5056
|
+
const response = await fetch3(url, {
|
|
5057
|
+
method: "POST",
|
|
5058
|
+
body: form,
|
|
5059
|
+
agent
|
|
5060
|
+
});
|
|
5061
|
+
if (!response.ok) {
|
|
5062
|
+
debug9("error from S3 %s %s", response.body, response.status);
|
|
5063
|
+
logInfo(`FileUpload: error from S3 ${response.body} ${response.status}`);
|
|
5064
|
+
throw new Error(`Failed to upload the file: ${response.status}`);
|
|
5557
5065
|
}
|
|
5558
|
-
|
|
5559
|
-
|
|
5560
|
-
configStore.set("apiToken", newApiToken);
|
|
5561
|
-
return new McpGQLClient({ apiKey: newApiToken, type: "apiKey" });
|
|
5066
|
+
debug9("upload file done");
|
|
5067
|
+
logInfo(`FileUpload: upload file done`);
|
|
5562
5068
|
}
|
|
5563
5069
|
|
|
5564
5070
|
// src/args/commands/upload_ai_blame.ts
|
|
5565
|
-
var PromptItemZ =
|
|
5566
|
-
type:
|
|
5567
|
-
attachedFiles:
|
|
5568
|
-
|
|
5569
|
-
relativePath:
|
|
5570
|
-
startLine:
|
|
5071
|
+
var PromptItemZ = z26.object({
|
|
5072
|
+
type: z26.enum(["USER_PROMPT", "AI_RESPONSE", "TOOL_EXECUTION", "AI_THINKING"]),
|
|
5073
|
+
attachedFiles: z26.array(
|
|
5074
|
+
z26.object({
|
|
5075
|
+
relativePath: z26.string(),
|
|
5076
|
+
startLine: z26.number().optional()
|
|
5571
5077
|
})
|
|
5572
5078
|
).optional(),
|
|
5573
|
-
tokens:
|
|
5574
|
-
inputCount:
|
|
5575
|
-
outputCount:
|
|
5079
|
+
tokens: z26.object({
|
|
5080
|
+
inputCount: z26.number(),
|
|
5081
|
+
outputCount: z26.number()
|
|
5576
5082
|
}).optional(),
|
|
5577
|
-
text:
|
|
5578
|
-
date:
|
|
5579
|
-
tool:
|
|
5580
|
-
name:
|
|
5581
|
-
parameters:
|
|
5582
|
-
result:
|
|
5583
|
-
rawArguments:
|
|
5584
|
-
accepted:
|
|
5083
|
+
text: z26.string().optional(),
|
|
5084
|
+
date: z26.date().optional(),
|
|
5085
|
+
tool: z26.object({
|
|
5086
|
+
name: z26.string(),
|
|
5087
|
+
parameters: z26.string(),
|
|
5088
|
+
result: z26.string(),
|
|
5089
|
+
rawArguments: z26.string().optional(),
|
|
5090
|
+
accepted: z26.boolean().optional()
|
|
5585
5091
|
}).optional()
|
|
5586
5092
|
});
|
|
5587
|
-
var PromptItemArrayZ =
|
|
5093
|
+
var PromptItemArrayZ = z26.array(PromptItemZ);
|
|
5588
5094
|
function uploadAiBlameBuilder(args) {
|
|
5589
5095
|
return args.option("prompt", {
|
|
5590
5096
|
type: "string",
|
|
5591
5097
|
array: true,
|
|
5592
5098
|
demandOption: true,
|
|
5593
|
-
describe:
|
|
5099
|
+
describe: chalk3.bold("Path(s) to prompt artifact(s) (one per session)")
|
|
5594
5100
|
}).option("inference", {
|
|
5595
5101
|
type: "string",
|
|
5596
5102
|
array: true,
|
|
5597
5103
|
demandOption: true,
|
|
5598
|
-
describe:
|
|
5104
|
+
describe: chalk3.bold(
|
|
5599
5105
|
"Path(s) to inference artifact(s) (one per session)"
|
|
5600
5106
|
)
|
|
5601
5107
|
}).option("ai-response-at", {
|
|
5602
5108
|
type: "string",
|
|
5603
5109
|
array: true,
|
|
5604
|
-
describe:
|
|
5110
|
+
describe: chalk3.bold(
|
|
5605
5111
|
"ISO timestamp(s) for AI response (one per session, defaults to now)"
|
|
5606
5112
|
)
|
|
5607
5113
|
}).option("model", {
|
|
5608
5114
|
type: "string",
|
|
5609
5115
|
array: true,
|
|
5610
|
-
describe:
|
|
5116
|
+
describe: chalk3.bold("AI model name(s) (optional, one per session)")
|
|
5611
5117
|
}).option("tool-name", {
|
|
5612
5118
|
type: "string",
|
|
5613
5119
|
array: true,
|
|
5614
|
-
describe:
|
|
5120
|
+
describe: chalk3.bold("Tool/IDE name(s) (optional, one per session)")
|
|
5615
5121
|
}).strict();
|
|
5616
5122
|
}
|
|
5617
5123
|
async function uploadAiBlameHandlerFromExtension(args) {
|
|
@@ -5639,6 +5145,18 @@ async function uploadAiBlameHandlerFromExtension(args) {
|
|
|
5639
5145
|
});
|
|
5640
5146
|
});
|
|
5641
5147
|
}
|
|
5148
|
+
var config3 = new Configstore2(packageJson.name, { apiToken: "" });
|
|
5149
|
+
async function getAuthenticatedGQLClientForIdeExtension() {
|
|
5150
|
+
let gqlClient = new GQLClient({
|
|
5151
|
+
apiKey: config3.get("apiToken") ?? "",
|
|
5152
|
+
type: "apiKey"
|
|
5153
|
+
});
|
|
5154
|
+
gqlClient = await handleMobbLogin({
|
|
5155
|
+
inGqlClient: gqlClient,
|
|
5156
|
+
skipPrompts: true
|
|
5157
|
+
});
|
|
5158
|
+
return gqlClient;
|
|
5159
|
+
}
|
|
5642
5160
|
async function uploadAiBlameHandler(args, exitOnError = true) {
|
|
5643
5161
|
const prompts = args.prompt || [];
|
|
5644
5162
|
const inferences = args.inference || [];
|
|
@@ -5647,7 +5165,7 @@ async function uploadAiBlameHandler(args, exitOnError = true) {
|
|
|
5647
5165
|
const responseTimes = args.aiResponseAt || args["ai-response-at"] || [];
|
|
5648
5166
|
if (prompts.length !== inferences.length) {
|
|
5649
5167
|
const errorMsg = "prompt and inference must have the same number of entries";
|
|
5650
|
-
console.error(
|
|
5168
|
+
console.error(chalk3.red(errorMsg));
|
|
5651
5169
|
if (exitOnError) {
|
|
5652
5170
|
process.exit(1);
|
|
5653
5171
|
}
|
|
@@ -5665,7 +5183,7 @@ async function uploadAiBlameHandler(args, exitOnError = true) {
|
|
|
5665
5183
|
]);
|
|
5666
5184
|
} catch {
|
|
5667
5185
|
const errorMsg = `File not found for session ${i + 1}`;
|
|
5668
|
-
console.error(
|
|
5186
|
+
console.error(chalk3.red(errorMsg));
|
|
5669
5187
|
if (exitOnError) {
|
|
5670
5188
|
process.exit(1);
|
|
5671
5189
|
}
|
|
@@ -5679,12 +5197,14 @@ async function uploadAiBlameHandler(args, exitOnError = true) {
|
|
|
5679
5197
|
toolName: tools[i]
|
|
5680
5198
|
});
|
|
5681
5199
|
}
|
|
5682
|
-
const
|
|
5683
|
-
const initRes = await
|
|
5200
|
+
const authenticatedClient = await getAuthenticatedGQLClientForIdeExtension();
|
|
5201
|
+
const initRes = await authenticatedClient.uploadAIBlameInferencesInitRaw({
|
|
5202
|
+
sessions
|
|
5203
|
+
});
|
|
5684
5204
|
const uploadSessions = initRes.uploadAIBlameInferencesInit?.uploadSessions ?? [];
|
|
5685
5205
|
if (uploadSessions.length !== sessions.length) {
|
|
5686
5206
|
const errorMsg = "Init failed to return expected number of sessions";
|
|
5687
|
-
console.error(
|
|
5207
|
+
console.error(chalk3.red(errorMsg));
|
|
5688
5208
|
if (exitOnError) {
|
|
5689
5209
|
process.exit(1);
|
|
5690
5210
|
}
|
|
@@ -5718,21 +5238,22 @@ async function uploadAiBlameHandler(args, exitOnError = true) {
|
|
|
5718
5238
|
toolName: s.toolName
|
|
5719
5239
|
};
|
|
5720
5240
|
});
|
|
5721
|
-
const finRes = await
|
|
5241
|
+
const finRes = await authenticatedClient.finalizeAIBlameInferencesUploadRaw({
|
|
5722
5242
|
sessions: finalizeSessions
|
|
5723
5243
|
});
|
|
5724
5244
|
const status = finRes?.finalizeAIBlameInferencesUpload?.status;
|
|
5725
5245
|
if (status !== "OK") {
|
|
5726
5246
|
const errorMsg = finRes?.finalizeAIBlameInferencesUpload?.error || "unknown error";
|
|
5727
|
-
console.error(
|
|
5247
|
+
console.error(chalk3.red(errorMsg));
|
|
5728
5248
|
if (exitOnError) {
|
|
5729
5249
|
process.exit(1);
|
|
5730
5250
|
}
|
|
5731
5251
|
throw new Error(errorMsg);
|
|
5732
5252
|
}
|
|
5733
|
-
console.log(
|
|
5253
|
+
console.log(chalk3.green("AI Blame uploads finalized successfully"));
|
|
5734
5254
|
}
|
|
5735
5255
|
export {
|
|
5256
|
+
getAuthenticatedGQLClientForIdeExtension,
|
|
5736
5257
|
uploadAiBlameBuilder,
|
|
5737
5258
|
uploadAiBlameHandler,
|
|
5738
5259
|
uploadAiBlameHandlerFromExtension
|