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
package/dist/index.mjs
CHANGED
|
@@ -9953,13 +9953,8 @@ import fs10 from "fs";
|
|
|
9953
9953
|
import chalk8 from "chalk";
|
|
9954
9954
|
|
|
9955
9955
|
// src/commands/index.ts
|
|
9956
|
-
import crypto from "crypto";
|
|
9957
|
-
import os from "os";
|
|
9958
|
-
import chalk6 from "chalk";
|
|
9959
9956
|
import chalkAnimation from "chalk-animation";
|
|
9960
|
-
import
|
|
9961
|
-
import Debug19 from "debug";
|
|
9962
|
-
import open3 from "open";
|
|
9957
|
+
import Configstore3 from "configstore";
|
|
9963
9958
|
|
|
9964
9959
|
// src/features/analysis/index.ts
|
|
9965
9960
|
import fs9 from "fs";
|
|
@@ -9967,16 +9962,32 @@ import fsPromises2 from "fs/promises";
|
|
|
9967
9962
|
import path9 from "path";
|
|
9968
9963
|
import { env as env2 } from "process";
|
|
9969
9964
|
import { pipeline } from "stream/promises";
|
|
9970
|
-
import
|
|
9971
|
-
import
|
|
9972
|
-
import
|
|
9965
|
+
import chalk6 from "chalk";
|
|
9966
|
+
import Configstore2 from "configstore";
|
|
9967
|
+
import Debug19 from "debug";
|
|
9973
9968
|
import extract from "extract-zip";
|
|
9974
9969
|
import { createSpinner as createSpinner4 } from "nanospinner";
|
|
9975
9970
|
import fetch4 from "node-fetch";
|
|
9976
|
-
import
|
|
9971
|
+
import open3 from "open";
|
|
9977
9972
|
import tmp2 from "tmp";
|
|
9978
9973
|
import { z as z29 } from "zod";
|
|
9979
9974
|
|
|
9975
|
+
// src/commands/handleMobbLogin.ts
|
|
9976
|
+
import crypto from "crypto";
|
|
9977
|
+
import os from "os";
|
|
9978
|
+
import chalk3 from "chalk";
|
|
9979
|
+
import Configstore from "configstore";
|
|
9980
|
+
import Debug7 from "debug";
|
|
9981
|
+
import open from "open";
|
|
9982
|
+
|
|
9983
|
+
// src/features/analysis/graphql/gql.ts
|
|
9984
|
+
import fetchOrig from "cross-fetch";
|
|
9985
|
+
import Debug6 from "debug";
|
|
9986
|
+
import { GraphQLClient } from "graphql-request";
|
|
9987
|
+
import { HttpProxyAgent } from "http-proxy-agent";
|
|
9988
|
+
import { HttpsProxyAgent as HttpsProxyAgent2 } from "https-proxy-agent";
|
|
9989
|
+
import { v4 as uuidv4 } from "uuid";
|
|
9990
|
+
|
|
9980
9991
|
// src/mcp/core/Errors.ts
|
|
9981
9992
|
var ApiConnectionError = class extends Error {
|
|
9982
9993
|
constructor(message = "Failed to connect to the API") {
|
|
@@ -10049,1218 +10060,1313 @@ var _ReportDigestError = class _ReportDigestError extends Error {
|
|
|
10049
10060
|
__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.");
|
|
10050
10061
|
var ReportDigestError = _ReportDigestError;
|
|
10051
10062
|
|
|
10052
|
-
// src/features/analysis/
|
|
10053
|
-
import Debug8 from "debug";
|
|
10054
|
-
|
|
10055
|
-
// src/features/analysis/add_fix_comments_for_pr/utils/utils.ts
|
|
10056
|
-
import Debug7 from "debug";
|
|
10057
|
-
import parseDiff from "parse-diff";
|
|
10058
|
-
import { z as z26 } from "zod";
|
|
10059
|
-
|
|
10060
|
-
// src/features/analysis/utils/by_key.ts
|
|
10061
|
-
function keyBy(array, keyBy2) {
|
|
10062
|
-
return array.reduce((acc, item) => {
|
|
10063
|
-
return { ...acc, [item[keyBy2]]: item };
|
|
10064
|
-
}, {});
|
|
10065
|
-
}
|
|
10066
|
-
|
|
10067
|
-
// src/features/analysis/utils/send_report.ts
|
|
10063
|
+
// src/features/analysis/graphql/subscribe.ts
|
|
10068
10064
|
import Debug5 from "debug";
|
|
10069
|
-
|
|
10070
|
-
|
|
10071
|
-
|
|
10072
|
-
|
|
10073
|
-
|
|
10074
|
-
|
|
10075
|
-
|
|
10076
|
-
|
|
10077
|
-
|
|
10078
|
-
|
|
10079
|
-
|
|
10080
|
-
|
|
10081
|
-
|
|
10065
|
+
import { createClient } from "graphql-ws";
|
|
10066
|
+
import { HttpsProxyAgent } from "https-proxy-agent";
|
|
10067
|
+
import WebSocket from "ws";
|
|
10068
|
+
var DEFAULT_API_URL = "https://api.mobb.ai/v1/graphql";
|
|
10069
|
+
var debug6 = Debug5("mobbdev:subscribe");
|
|
10070
|
+
var SUBSCRIPTION_TIMEOUT_MS = 30 * 60 * 1e3;
|
|
10071
|
+
function createWSClient(options) {
|
|
10072
|
+
const proxy = options.url.startsWith("wss://") && process.env["HTTPS_PROXY"] ? new HttpsProxyAgent(process.env["HTTPS_PROXY"]) : options.url.startsWith("ws://") && process.env["HTTP_PROXY"] ? new HttpsProxyAgent(process.env["HTTP_PROXY"]) : null;
|
|
10073
|
+
debug6(
|
|
10074
|
+
`Using proxy: ${proxy ? "yes" : "no"} with url: ${options.url} and with proxy: ${process.env["HTTP_PROXY"]} for the websocket connection`
|
|
10075
|
+
);
|
|
10076
|
+
const CustomWebSocket = class extends WebSocket {
|
|
10077
|
+
constructor(address, protocols) {
|
|
10078
|
+
super(
|
|
10079
|
+
address,
|
|
10080
|
+
protocols,
|
|
10081
|
+
proxy ? { agent: proxy } : void 0
|
|
10082
|
+
);
|
|
10082
10083
|
}
|
|
10083
|
-
|
|
10084
|
-
|
|
10085
|
-
|
|
10086
|
-
|
|
10087
|
-
|
|
10088
|
-
|
|
10089
|
-
|
|
10090
|
-
|
|
10091
|
-
|
|
10092
|
-
"
|
|
10093
|
-
|
|
10094
|
-
|
|
10095
|
-
|
|
10084
|
+
};
|
|
10085
|
+
return createClient({
|
|
10086
|
+
//this is needed to prevent AWS from killing the connection
|
|
10087
|
+
//currently our load balancer has a 29s idle timeout
|
|
10088
|
+
keepAlive: 1e4,
|
|
10089
|
+
url: options.url,
|
|
10090
|
+
webSocketImpl: proxy ? CustomWebSocket : options.websocket || WebSocket,
|
|
10091
|
+
connectionParams: () => {
|
|
10092
|
+
return {
|
|
10093
|
+
headers: options.type === "apiKey" ? {
|
|
10094
|
+
[API_KEY_HEADER_NAME]: options.apiKey
|
|
10095
|
+
} : { authorization: `Bearer ${options.token}` }
|
|
10096
|
+
};
|
|
10097
|
+
}
|
|
10098
|
+
});
|
|
10099
|
+
}
|
|
10100
|
+
function subscribe(query, variables, callback, wsClientOptions) {
|
|
10101
|
+
return new Promise((resolve, reject) => {
|
|
10102
|
+
let timer = null;
|
|
10103
|
+
const { timeoutInMs = SUBSCRIPTION_TIMEOUT_MS } = wsClientOptions;
|
|
10104
|
+
const API_URL2 = process.env["API_URL"] || DEFAULT_API_URL;
|
|
10105
|
+
const client = createWSClient({
|
|
10106
|
+
...wsClientOptions,
|
|
10107
|
+
websocket: WebSocket,
|
|
10108
|
+
url: API_URL2.replace("http", "ws")
|
|
10096
10109
|
});
|
|
10097
|
-
|
|
10098
|
-
|
|
10099
|
-
|
|
10100
|
-
|
|
10101
|
-
|
|
10110
|
+
const unsubscribe = client.subscribe(
|
|
10111
|
+
{ query, variables },
|
|
10112
|
+
{
|
|
10113
|
+
next: (data) => {
|
|
10114
|
+
function callbackResolve(data2) {
|
|
10115
|
+
unsubscribe();
|
|
10116
|
+
if (timer) {
|
|
10117
|
+
clearTimeout(timer);
|
|
10118
|
+
}
|
|
10119
|
+
resolve(data2);
|
|
10120
|
+
}
|
|
10121
|
+
function callbackReject(data2) {
|
|
10122
|
+
unsubscribe();
|
|
10123
|
+
if (timer) {
|
|
10124
|
+
clearTimeout(timer);
|
|
10125
|
+
}
|
|
10126
|
+
reject(data2);
|
|
10127
|
+
}
|
|
10128
|
+
if (!data.data) {
|
|
10129
|
+
reject(
|
|
10130
|
+
new Error(
|
|
10131
|
+
`Broken data object from graphQL subscribe: ${JSON.stringify(
|
|
10132
|
+
data
|
|
10133
|
+
)} for query: ${query}`
|
|
10134
|
+
)
|
|
10135
|
+
);
|
|
10136
|
+
} else {
|
|
10137
|
+
callback(callbackResolve, callbackReject, data.data);
|
|
10138
|
+
}
|
|
10139
|
+
},
|
|
10140
|
+
error: (error) => {
|
|
10141
|
+
if (timer) {
|
|
10142
|
+
clearTimeout(timer);
|
|
10143
|
+
}
|
|
10144
|
+
reject(error);
|
|
10145
|
+
},
|
|
10146
|
+
complete: () => {
|
|
10147
|
+
return;
|
|
10148
|
+
}
|
|
10149
|
+
}
|
|
10150
|
+
);
|
|
10151
|
+
if (typeof timeoutInMs === "number") {
|
|
10152
|
+
timer = setTimeout(() => {
|
|
10153
|
+
unsubscribe();
|
|
10154
|
+
reject(
|
|
10155
|
+
new Error(
|
|
10156
|
+
`Timeout expired for graphQL subscribe query: ${query} with timeout: ${timeoutInMs}`
|
|
10157
|
+
)
|
|
10158
|
+
);
|
|
10159
|
+
}, timeoutInMs);
|
|
10160
|
+
}
|
|
10161
|
+
});
|
|
10102
10162
|
}
|
|
10103
10163
|
|
|
10104
|
-
// src/features/analysis/
|
|
10105
|
-
|
|
10106
|
-
|
|
10107
|
-
|
|
10108
|
-
|
|
10164
|
+
// src/features/analysis/graphql/types.ts
|
|
10165
|
+
import { z as z25 } from "zod";
|
|
10166
|
+
var VulnerabilityReportIssueCodeNodeZ = z25.object({
|
|
10167
|
+
vulnerabilityReportIssueId: z25.string(),
|
|
10168
|
+
path: z25.string(),
|
|
10169
|
+
startLine: z25.number(),
|
|
10170
|
+
vulnerabilityReportIssue: z25.object({
|
|
10171
|
+
fixId: z25.string(),
|
|
10172
|
+
category: z25.nativeEnum(Vulnerability_Report_Issue_Category_Enum),
|
|
10173
|
+
safeIssueType: z25.string(),
|
|
10174
|
+
vulnerabilityReportIssueTags: z25.array(
|
|
10175
|
+
z25.object({
|
|
10176
|
+
tag: z25.nativeEnum(Vulnerability_Report_Issue_Tag_Enum)
|
|
10177
|
+
})
|
|
10178
|
+
)
|
|
10179
|
+
})
|
|
10180
|
+
});
|
|
10181
|
+
var VulnerabilityReportIssueNoFixCodeNodeZ = z25.object({
|
|
10182
|
+
vulnerabilityReportIssues: z25.array(
|
|
10183
|
+
z25.object({
|
|
10184
|
+
id: z25.string(),
|
|
10185
|
+
fixId: z25.string().nullable(),
|
|
10186
|
+
category: z25.nativeEnum(Vulnerability_Report_Issue_Category_Enum),
|
|
10187
|
+
safeIssueType: z25.string(),
|
|
10188
|
+
fpId: z25.string().uuid().nullable(),
|
|
10189
|
+
codeNodes: z25.array(
|
|
10190
|
+
z25.object({
|
|
10191
|
+
path: z25.string(),
|
|
10192
|
+
startLine: z25.number()
|
|
10193
|
+
})
|
|
10194
|
+
),
|
|
10195
|
+
vulnerabilityReportIssueTags: z25.array(
|
|
10196
|
+
z25.object({
|
|
10197
|
+
tag: z25.nativeEnum(Vulnerability_Report_Issue_Tag_Enum)
|
|
10198
|
+
})
|
|
10199
|
+
)
|
|
10200
|
+
})
|
|
10201
|
+
)
|
|
10202
|
+
});
|
|
10203
|
+
var GetVulByNodesMetadataZ = z25.object({
|
|
10204
|
+
vulnerabilityReportIssueCodeNodes: z25.array(VulnerabilityReportIssueCodeNodeZ),
|
|
10205
|
+
nonFixablePrVuls: z25.object({
|
|
10206
|
+
aggregate: z25.object({
|
|
10207
|
+
count: z25.number()
|
|
10208
|
+
})
|
|
10209
|
+
}),
|
|
10210
|
+
fixablePrVuls: z25.object({
|
|
10211
|
+
aggregate: z25.object({
|
|
10212
|
+
count: z25.number()
|
|
10213
|
+
})
|
|
10214
|
+
}),
|
|
10215
|
+
totalScanVulnerabilities: z25.object({
|
|
10216
|
+
aggregate: z25.object({
|
|
10217
|
+
count: z25.number()
|
|
10218
|
+
})
|
|
10219
|
+
}),
|
|
10220
|
+
irrelevantVulnerabilityReportIssue: z25.array(
|
|
10221
|
+
VulnerabilityReportIssueNoFixCodeNodeZ
|
|
10222
|
+
)
|
|
10223
|
+
});
|
|
10224
|
+
|
|
10225
|
+
// src/features/analysis/graphql/gql.ts
|
|
10226
|
+
var debug7 = Debug6("mobbdev:gql");
|
|
10227
|
+
var API_KEY_HEADER_NAME = "x-mobb-key";
|
|
10228
|
+
var REPORT_STATE_CHECK_DELAY = 5 * 1e3;
|
|
10229
|
+
function getProxyAgent(url) {
|
|
10230
|
+
try {
|
|
10231
|
+
const parsedUrl = new URL(url);
|
|
10232
|
+
const isHttp = parsedUrl.protocol === "http:";
|
|
10233
|
+
const isHttps = parsedUrl.protocol === "https:";
|
|
10234
|
+
const proxy = isHttps ? HTTPS_PROXY : isHttp ? HTTP_PROXY : null;
|
|
10235
|
+
if (proxy) {
|
|
10236
|
+
debug7("Using proxy %s", proxy);
|
|
10237
|
+
debug7("Proxy agent %o", proxy);
|
|
10238
|
+
return isHttps ? new HttpsProxyAgent2(proxy) : new HttpProxyAgent(proxy);
|
|
10109
10239
|
}
|
|
10110
|
-
|
|
10111
|
-
|
|
10240
|
+
} catch (err) {
|
|
10241
|
+
debug7(`Skipping proxy for ${url}. Reason: ${err.message}`);
|
|
10242
|
+
}
|
|
10243
|
+
return void 0;
|
|
10112
10244
|
}
|
|
10113
|
-
|
|
10114
|
-
|
|
10115
|
-
|
|
10116
|
-
|
|
10117
|
-
|
|
10118
|
-
|
|
10119
|
-
|
|
10120
|
-
|
|
10121
|
-
|
|
10122
|
-
|
|
10123
|
-
|
|
10124
|
-
|
|
10125
|
-
|
|
10126
|
-
|
|
10245
|
+
var fetchWithProxy = (url, options = {}) => {
|
|
10246
|
+
try {
|
|
10247
|
+
const agent = getProxyAgent(url.toString());
|
|
10248
|
+
if (agent) {
|
|
10249
|
+
return fetchOrig(url, {
|
|
10250
|
+
...options,
|
|
10251
|
+
// @ts-expect-error Node-fetch doesn't type 'agent', but it's valid
|
|
10252
|
+
agent
|
|
10253
|
+
});
|
|
10254
|
+
}
|
|
10255
|
+
} catch (err) {
|
|
10256
|
+
debug7(`Skipping proxy for ${url}. Reason: ${err.message}`);
|
|
10257
|
+
}
|
|
10258
|
+
return fetchOrig(url, options);
|
|
10127
10259
|
};
|
|
10128
|
-
|
|
10129
|
-
|
|
10130
|
-
|
|
10131
|
-
|
|
10132
|
-
|
|
10133
|
-
|
|
10134
|
-
|
|
10135
|
-
|
|
10136
|
-
|
|
10137
|
-
|
|
10138
|
-
|
|
10139
|
-
|
|
10140
|
-
|
|
10141
|
-
|
|
10142
|
-
|
|
10143
|
-
|
|
10144
|
-
|
|
10145
|
-
|
|
10146
|
-
|
|
10147
|
-
|
|
10148
|
-
|
|
10149
|
-
|
|
10150
|
-
|
|
10151
|
-
|
|
10152
|
-
|
|
10153
|
-
|
|
10154
|
-
|
|
10155
|
-
commentId
|
|
10156
|
-
}) : getCommitUrl({
|
|
10157
|
-
appBaseUrl: WEB_APP_URL,
|
|
10158
|
-
fixId,
|
|
10159
|
-
projectId,
|
|
10160
|
-
analysisId,
|
|
10161
|
-
organizationId,
|
|
10162
|
-
redirectUrl: commentUrl,
|
|
10163
|
-
commentId
|
|
10164
|
-
});
|
|
10165
|
-
const fixUrl = isIrrelevantIssueWithTags ? getIssueUrlWithRedirect({
|
|
10166
|
-
appBaseUrl: WEB_APP_URL,
|
|
10167
|
-
issueId,
|
|
10168
|
-
projectId,
|
|
10169
|
-
analysisId,
|
|
10170
|
-
organizationId,
|
|
10171
|
-
redirectUrl: commentUrl,
|
|
10172
|
-
commentId
|
|
10173
|
-
}) : getFixUrlWithRedirect({
|
|
10174
|
-
appBaseUrl: WEB_APP_URL,
|
|
10175
|
-
fixId,
|
|
10176
|
-
projectId,
|
|
10177
|
-
analysisId,
|
|
10178
|
-
organizationId,
|
|
10179
|
-
redirectUrl: commentUrl,
|
|
10180
|
-
commentId
|
|
10181
|
-
});
|
|
10182
|
-
const issueType = getIssueTypeFriendlyString(fix.safeIssueType);
|
|
10183
|
-
const title = `# ${MobbIconMarkdown} ${issueType} fix is ready`;
|
|
10184
|
-
const validFixParseRes = z25.object({
|
|
10185
|
-
patchAndQuestions: PatchAndQuestionsZ,
|
|
10186
|
-
safeIssueLanguage: z25.nativeEnum(IssueLanguage_Enum),
|
|
10187
|
-
severityText: z25.nativeEnum(Vulnerability_Severity_Enum),
|
|
10188
|
-
safeIssueType: z25.nativeEnum(IssueType_Enum)
|
|
10189
|
-
}).safeParse(fix);
|
|
10190
|
-
if (!validFixParseRes.success) {
|
|
10191
|
-
debug7(
|
|
10192
|
-
`fix ${fixId} has custom issue type or language, therefore the commit description will not be added`,
|
|
10193
|
-
validFixParseRes.error
|
|
10194
|
-
);
|
|
10260
|
+
var GQLClient = class {
|
|
10261
|
+
constructor(args) {
|
|
10262
|
+
__publicField(this, "_client");
|
|
10263
|
+
__publicField(this, "_clientSdk");
|
|
10264
|
+
__publicField(this, "_auth");
|
|
10265
|
+
debug7(`init with ${args}`);
|
|
10266
|
+
this._auth = args;
|
|
10267
|
+
this._client = new GraphQLClient(API_URL, {
|
|
10268
|
+
headers: args.type === "apiKey" ? { [API_KEY_HEADER_NAME]: args.apiKey || "" } : {
|
|
10269
|
+
Authorization: `Bearer ${args.token}`
|
|
10270
|
+
},
|
|
10271
|
+
fetch: fetchWithProxy,
|
|
10272
|
+
requestMiddleware: (request) => {
|
|
10273
|
+
const requestId = uuidv4();
|
|
10274
|
+
debug7(
|
|
10275
|
+
`sending API request with id: ${requestId} and with request: ${request.body}`
|
|
10276
|
+
);
|
|
10277
|
+
return {
|
|
10278
|
+
...request,
|
|
10279
|
+
headers: {
|
|
10280
|
+
...request.headers,
|
|
10281
|
+
"x-hasura-request-id": requestId
|
|
10282
|
+
}
|
|
10283
|
+
};
|
|
10284
|
+
}
|
|
10285
|
+
});
|
|
10286
|
+
this._clientSdk = getSdk(this._client);
|
|
10195
10287
|
}
|
|
10196
|
-
|
|
10197
|
-
|
|
10198
|
-
|
|
10199
|
-
severity: validFixParseRes.data.severityText,
|
|
10200
|
-
guidances: getGuidances({
|
|
10201
|
-
questions: validFixParseRes.data.patchAndQuestions.questions.map(toQuestion),
|
|
10202
|
-
issueType: validFixParseRes.data.safeIssueType,
|
|
10203
|
-
issueLanguage: validFixParseRes.data.safeIssueLanguage,
|
|
10204
|
-
fixExtraContext: validFixParseRes.data.patchAndQuestions.extraContext
|
|
10205
|
-
}),
|
|
10206
|
-
irrelevantIssueWithTags
|
|
10207
|
-
}) : "";
|
|
10208
|
-
const diff = `\`\`\`diff
|
|
10209
|
-
${patch}
|
|
10210
|
-
\`\`\``;
|
|
10211
|
-
const fixPageLink = `[Learn more and fine tune the fix](${fixUrl})`;
|
|
10212
|
-
return `${title}
|
|
10213
|
-
${subTitle}
|
|
10214
|
-
${diff}
|
|
10215
|
-
${getCommitFixButton(
|
|
10216
|
-
commitUrl
|
|
10217
|
-
)}
|
|
10218
|
-
${fixPageLink}`;
|
|
10219
|
-
}
|
|
10220
|
-
function buildIssueCommentBody({
|
|
10221
|
-
issueId,
|
|
10222
|
-
commentId,
|
|
10223
|
-
commentUrl,
|
|
10224
|
-
scanner,
|
|
10225
|
-
issueType,
|
|
10226
|
-
projectId,
|
|
10227
|
-
analysisId,
|
|
10228
|
-
organizationId,
|
|
10229
|
-
irrelevantIssueWithTags,
|
|
10230
|
-
fpDescription
|
|
10231
|
-
}) {
|
|
10232
|
-
const issueUrl = getIssueUrlWithRedirect({
|
|
10233
|
-
appBaseUrl: WEB_APP_URL,
|
|
10234
|
-
issueId,
|
|
10235
|
-
projectId,
|
|
10236
|
-
analysisId,
|
|
10237
|
-
organizationId,
|
|
10238
|
-
redirectUrl: commentUrl,
|
|
10239
|
-
commentId
|
|
10240
|
-
});
|
|
10241
|
-
const title = `# ${MobbIconMarkdown} Irrelevant issues were spotted - no action required \u{1F9F9}`;
|
|
10242
|
-
const subTitle = getCommitIssueDescription({
|
|
10243
|
-
issueType,
|
|
10244
|
-
vendor: scannerToVulnerabilityReportVendorEnum[scanner],
|
|
10245
|
-
irrelevantIssueWithTags,
|
|
10246
|
-
fpDescription
|
|
10247
|
-
});
|
|
10248
|
-
const issuePageLink = `[Learn more about this issue](${issueUrl})`;
|
|
10249
|
-
return `${title}
|
|
10250
|
-
${subTitle}
|
|
10251
|
-
${issuePageLink}`;
|
|
10252
|
-
}
|
|
10253
|
-
|
|
10254
|
-
// src/features/analysis/add_fix_comments_for_pr/utils/utils.ts
|
|
10255
|
-
var debug8 = Debug7("mobbdev:handle-finished-analysis");
|
|
10256
|
-
function calculateRanges(integers) {
|
|
10257
|
-
if (integers.length === 0) {
|
|
10258
|
-
return [];
|
|
10288
|
+
async getUserInfo() {
|
|
10289
|
+
const { me } = await this._clientSdk.Me();
|
|
10290
|
+
return me;
|
|
10259
10291
|
}
|
|
10260
|
-
|
|
10261
|
-
|
|
10262
|
-
|
|
10263
|
-
|
|
10264
|
-
|
|
10265
|
-
|
|
10266
|
-
|
|
10267
|
-
|
|
10268
|
-
if (current === end + 1) {
|
|
10269
|
-
currentRange[1] = current;
|
|
10270
|
-
} else {
|
|
10271
|
-
result.push([current, current]);
|
|
10272
|
-
}
|
|
10273
|
-
return result;
|
|
10274
|
-
},
|
|
10275
|
-
[]
|
|
10276
|
-
);
|
|
10277
|
-
return ranges;
|
|
10278
|
-
}
|
|
10279
|
-
function deleteAllPreviousComments({
|
|
10280
|
-
comments,
|
|
10281
|
-
scm
|
|
10282
|
-
}) {
|
|
10283
|
-
return comments.data.filter((comment) => {
|
|
10284
|
-
return comment.body.includes(MOBB_ICON_IMG);
|
|
10285
|
-
}).map((comment) => {
|
|
10292
|
+
async createCliLogin(variables) {
|
|
10293
|
+
const res = await this._clientSdk.CreateCliLogin(variables, {
|
|
10294
|
+
// We may have outdated API key in the config storage. Avoid using it for the login request.
|
|
10295
|
+
[API_KEY_HEADER_NAME]: ""
|
|
10296
|
+
});
|
|
10297
|
+
return res.insert_cli_login_one?.id || "";
|
|
10298
|
+
}
|
|
10299
|
+
async verifyApiConnection() {
|
|
10286
10300
|
try {
|
|
10287
|
-
|
|
10301
|
+
await this.getUserInfo();
|
|
10288
10302
|
} catch (e) {
|
|
10289
|
-
|
|
10290
|
-
|
|
10303
|
+
if (e?.toString().startsWith("FetchError")) {
|
|
10304
|
+
debug7("verify connection failed %o", e);
|
|
10305
|
+
return false;
|
|
10306
|
+
}
|
|
10291
10307
|
}
|
|
10292
|
-
|
|
10293
|
-
}
|
|
10294
|
-
|
|
10295
|
-
|
|
10296
|
-
|
|
10297
|
-
|
|
10308
|
+
return true;
|
|
10309
|
+
}
|
|
10310
|
+
async validateUserToken() {
|
|
10311
|
+
await this.createCommunityUser();
|
|
10312
|
+
let info;
|
|
10313
|
+
try {
|
|
10314
|
+
info = await this.getUserInfo();
|
|
10315
|
+
} catch (e) {
|
|
10316
|
+
debug7("verify token failed %o", e);
|
|
10298
10317
|
return false;
|
|
10299
10318
|
}
|
|
10300
|
-
return
|
|
10301
|
-
}
|
|
10319
|
+
return info?.email || true;
|
|
10320
|
+
}
|
|
10321
|
+
async getLastOrgAndNamedProject(params) {
|
|
10322
|
+
const me = await this.getUserInfo();
|
|
10323
|
+
const email = me?.email;
|
|
10324
|
+
if (!email) {
|
|
10325
|
+
throw new Error("User email not found");
|
|
10326
|
+
}
|
|
10327
|
+
const { projectName, userDefinedOrganizationId } = params;
|
|
10328
|
+
if (!projectName) {
|
|
10329
|
+
throw new Error("Project name is required");
|
|
10330
|
+
}
|
|
10331
|
+
const orgAndProjectRes = await this._clientSdk.getLastOrgAndNamedProject({
|
|
10332
|
+
email,
|
|
10333
|
+
projectName
|
|
10334
|
+
});
|
|
10335
|
+
if (!orgAndProjectRes.user?.[0]?.userOrganizationsAndUserOrganizationRoles?.[0]?.organization?.id) {
|
|
10336
|
+
throw new Error(
|
|
10337
|
+
`The user with email:${email} is not associated with any organization`
|
|
10338
|
+
);
|
|
10339
|
+
}
|
|
10340
|
+
const organization = orgAndProjectRes.user?.at(0)?.userOrganizationsAndUserOrganizationRoles.map(
|
|
10341
|
+
(org) => org.organization
|
|
10342
|
+
).filter(
|
|
10343
|
+
(org) => userDefinedOrganizationId ? org.id === userDefinedOrganizationId : true
|
|
10344
|
+
)?.at(0);
|
|
10345
|
+
if (!organization) {
|
|
10346
|
+
throw new Error(
|
|
10347
|
+
`Organization with id:${userDefinedOrganizationId} not found`
|
|
10348
|
+
);
|
|
10349
|
+
}
|
|
10350
|
+
let projectId = organization?.projects?.[0]?.id;
|
|
10351
|
+
if (!projectId) {
|
|
10352
|
+
const createdProject = await this._clientSdk.CreateProject({
|
|
10353
|
+
organizationId: organization.id,
|
|
10354
|
+
projectName: projectName || "My project"
|
|
10355
|
+
});
|
|
10356
|
+
projectId = createdProject.createProject.projectId;
|
|
10357
|
+
}
|
|
10358
|
+
if (!projectId) {
|
|
10359
|
+
throw new Error("Project not found");
|
|
10360
|
+
}
|
|
10361
|
+
return {
|
|
10362
|
+
organizationId: organization.id,
|
|
10363
|
+
projectId
|
|
10364
|
+
};
|
|
10365
|
+
}
|
|
10366
|
+
async getEncryptedApiToken(variables) {
|
|
10367
|
+
const res = await this._clientSdk.GetEncryptedApiToken(variables, {
|
|
10368
|
+
// We may have outdated API key in the config storage. Avoid using it for the login request.
|
|
10369
|
+
[API_KEY_HEADER_NAME]: ""
|
|
10370
|
+
});
|
|
10371
|
+
return res?.cli_login_by_pk?.encryptedApiToken || null;
|
|
10372
|
+
}
|
|
10373
|
+
async createCommunityUser() {
|
|
10302
10374
|
try {
|
|
10303
|
-
|
|
10375
|
+
await this._clientSdk.CreateCommunityUser();
|
|
10304
10376
|
} catch (e) {
|
|
10305
|
-
|
|
10306
|
-
return Promise.resolve();
|
|
10377
|
+
debug7("create community user failed %o", e);
|
|
10307
10378
|
}
|
|
10308
|
-
}
|
|
10309
|
-
|
|
10310
|
-
|
|
10311
|
-
|
|
10312
|
-
|
|
10313
|
-
|
|
10314
|
-
|
|
10315
|
-
|
|
10316
|
-
|
|
10317
|
-
|
|
10318
|
-
|
|
10319
|
-
|
|
10320
|
-
|
|
10321
|
-
|
|
10322
|
-
|
|
10323
|
-
|
|
10324
|
-
|
|
10325
|
-
|
|
10326
|
-
|
|
10327
|
-
|
|
10328
|
-
|
|
10329
|
-
|
|
10330
|
-
|
|
10331
|
-
|
|
10332
|
-
|
|
10333
|
-
|
|
10334
|
-
|
|
10335
|
-
|
|
10336
|
-
|
|
10337
|
-
|
|
10338
|
-
|
|
10339
|
-
|
|
10340
|
-
|
|
10341
|
-
|
|
10342
|
-
|
|
10343
|
-
|
|
10344
|
-
|
|
10345
|
-
|
|
10346
|
-
|
|
10347
|
-
|
|
10348
|
-
|
|
10349
|
-
|
|
10350
|
-
|
|
10351
|
-
|
|
10352
|
-
fpDescription
|
|
10353
|
-
});
|
|
10354
|
-
return await scm.updatePrComment({
|
|
10355
|
-
body: commentBody,
|
|
10356
|
-
comment_id: commentId
|
|
10357
|
-
});
|
|
10358
|
-
}
|
|
10359
|
-
async function postFixComment(params) {
|
|
10360
|
-
const {
|
|
10361
|
-
vulnerabilityReportIssueCodeNode,
|
|
10362
|
-
projectId,
|
|
10363
|
-
analysisId,
|
|
10364
|
-
organizationId,
|
|
10365
|
-
fixesById,
|
|
10366
|
-
scm,
|
|
10367
|
-
commitSha,
|
|
10368
|
-
pullRequest,
|
|
10369
|
-
scanner
|
|
10370
|
-
} = params;
|
|
10371
|
-
const {
|
|
10372
|
-
path: path17,
|
|
10373
|
-
startLine,
|
|
10374
|
-
vulnerabilityReportIssue: { fixId, vulnerabilityReportIssueTags, category },
|
|
10375
|
-
vulnerabilityReportIssueId
|
|
10376
|
-
} = vulnerabilityReportIssueCodeNode;
|
|
10377
|
-
const irrelevantIssueWithTags = mapCategoryToBucket[category] === "irrelevant" && vulnerabilityReportIssueTags?.length > 0 ? vulnerabilityReportIssueTags : [];
|
|
10378
|
-
const fix = fixesById[fixId];
|
|
10379
|
-
if (!fix || fix.patchAndQuestions.__typename !== "FixData") {
|
|
10380
|
-
throw new Error(`fix ${fixId} not found`);
|
|
10381
|
-
}
|
|
10382
|
-
const {
|
|
10383
|
-
patchAndQuestions: { patch }
|
|
10384
|
-
} = fix;
|
|
10385
|
-
const commentRes = await scm.postPrComment({
|
|
10386
|
-
body: `# ${MobbIconMarkdown} Your fix is ready!
|
|
10387
|
-
Refresh the page in order to see the changes.`,
|
|
10388
|
-
pull_number: pullRequest,
|
|
10389
|
-
commit_id: commitSha,
|
|
10390
|
-
path: path17,
|
|
10391
|
-
line: startLine
|
|
10392
|
-
});
|
|
10393
|
-
const commentId = commentRes.data.id;
|
|
10394
|
-
const commentBody = buildFixCommentBody({
|
|
10395
|
-
fix,
|
|
10396
|
-
issueId: vulnerabilityReportIssueId,
|
|
10397
|
-
irrelevantIssueWithTags,
|
|
10398
|
-
commentId,
|
|
10399
|
-
commentUrl: commentRes.data.html_url,
|
|
10400
|
-
scanner,
|
|
10401
|
-
fixId,
|
|
10402
|
-
projectId,
|
|
10403
|
-
analysisId,
|
|
10404
|
-
organizationId,
|
|
10405
|
-
patch
|
|
10406
|
-
});
|
|
10407
|
-
return await scm.updatePrComment({
|
|
10408
|
-
body: commentBody,
|
|
10409
|
-
comment_id: commentId
|
|
10410
|
-
});
|
|
10411
|
-
}
|
|
10412
|
-
async function getRelevantVulenrabilitiesFromDiff(params) {
|
|
10413
|
-
const { gqlClient, diff, vulnerabilityReportId } = params;
|
|
10414
|
-
const parsedDiff = parseDiff(diff);
|
|
10415
|
-
const fileHunks = parsedDiff.map((file) => {
|
|
10416
|
-
const fileNumbers = file.chunks.flatMap((chunk) => chunk.changes).filter((change) => change.type === "add").map((_change) => {
|
|
10417
|
-
const change = _change;
|
|
10418
|
-
return change.ln;
|
|
10419
|
-
});
|
|
10420
|
-
const lineAddedRanges = calculateRanges(fileNumbers);
|
|
10421
|
-
const fileFilter = {
|
|
10422
|
-
path: z26.string().parse(file.to),
|
|
10423
|
-
ranges: lineAddedRanges.map(([startLine, endLine]) => ({
|
|
10424
|
-
endLine,
|
|
10425
|
-
startLine
|
|
10426
|
-
}))
|
|
10427
|
-
};
|
|
10428
|
-
return fileFilter;
|
|
10429
|
-
});
|
|
10430
|
-
return gqlClient.getVulByNodesMetadata({
|
|
10431
|
-
hunks: fileHunks,
|
|
10432
|
-
vulnerabilityReportId
|
|
10433
|
-
});
|
|
10434
|
-
}
|
|
10435
|
-
async function getFixesData(params) {
|
|
10436
|
-
const { gqlClient, fixesId } = params;
|
|
10437
|
-
const { fixes } = await gqlClient.getFixes(fixesId);
|
|
10438
|
-
return keyBy(fixes, "id");
|
|
10439
|
-
}
|
|
10440
|
-
async function postAnalysisInsightComment(params) {
|
|
10441
|
-
const { prVulenrabilities, pullRequest, scanner, scm } = params;
|
|
10442
|
-
const scanerString = scannerToFriendlyString[scanner];
|
|
10443
|
-
const {
|
|
10444
|
-
totalPrVulnerabilities,
|
|
10445
|
-
vulnerabilitiesOutsidePr,
|
|
10446
|
-
fixablePrVuls,
|
|
10447
|
-
nonFixablePrVuls
|
|
10448
|
-
} = prVulenrabilities;
|
|
10449
|
-
debug8({
|
|
10450
|
-
fixablePrVuls,
|
|
10451
|
-
nonFixablePrVuls,
|
|
10452
|
-
vulnerabilitiesOutsidePr,
|
|
10453
|
-
totalPrVulnerabilities
|
|
10454
|
-
});
|
|
10455
|
-
if (totalPrVulnerabilities === 0 && vulnerabilitiesOutsidePr === 0) {
|
|
10456
|
-
const body = `Awesome! No vulnerabilities were found by **${scanerString}**`;
|
|
10457
|
-
const noVulsFoundComment = `${noVulnerabilitiesFoundTitle}
|
|
10458
|
-
${body}`;
|
|
10459
|
-
await scm.postGeneralPrComment({
|
|
10460
|
-
body: noVulsFoundComment,
|
|
10461
|
-
prNumber: pullRequest
|
|
10462
|
-
});
|
|
10463
|
-
return;
|
|
10464
|
-
}
|
|
10465
|
-
if (totalPrVulnerabilities === 0 && vulnerabilitiesOutsidePr > 0) {
|
|
10466
|
-
const body = `Awesome! No vulnerabilities were found by **${scanerString}** in the changes made as part of this PR.`;
|
|
10467
|
-
const body2 = `Please notice there are issues in this repo that are unrelated to this PR.`;
|
|
10468
|
-
const noVulsFoundComment = `${noVulnerabilitiesFoundTitle}
|
|
10469
|
-
${body}
|
|
10470
|
-
${body2}`;
|
|
10471
|
-
await scm.postGeneralPrComment({
|
|
10472
|
-
body: noVulsFoundComment,
|
|
10473
|
-
prNumber: pullRequest
|
|
10474
|
-
});
|
|
10475
|
-
return;
|
|
10476
|
-
}
|
|
10477
|
-
if (fixablePrVuls === 0 && nonFixablePrVuls > 0) {
|
|
10478
|
-
const title = `# ${MobbIconMarkdown} We couldn't fix the issues detected by **${scanerString}**`;
|
|
10479
|
-
const body = `Mobb Fixer gets better and better every day, but unfortunately your current issues aren't supported yet.`;
|
|
10480
|
-
const noFixableVulsComment = `${title}
|
|
10481
|
-
${body}
|
|
10482
|
-
${contactUsMarkdown}`;
|
|
10483
|
-
await scm.postGeneralPrComment({
|
|
10484
|
-
body: noFixableVulsComment,
|
|
10485
|
-
prNumber: pullRequest
|
|
10486
|
-
});
|
|
10487
|
-
return;
|
|
10488
|
-
}
|
|
10489
|
-
if (fixablePrVuls < nonFixablePrVuls && fixablePrVuls > 0) {
|
|
10490
|
-
const title = `# ${MobbIconMarkdown} We couldn't fix some of the issues detected by **${scanerString}**`;
|
|
10491
|
-
const body = "Mobb Fixer gets better and better every day, but unfortunately your current issues aren't supported yet.";
|
|
10492
|
-
const fixableVulsComment = `${title}
|
|
10493
|
-
${body}
|
|
10494
|
-
${contactUsMarkdown}`;
|
|
10495
|
-
await scm.postGeneralPrComment({
|
|
10496
|
-
body: fixableVulsComment,
|
|
10497
|
-
prNumber: pullRequest
|
|
10498
|
-
});
|
|
10499
|
-
return;
|
|
10500
|
-
}
|
|
10501
|
-
}
|
|
10502
|
-
|
|
10503
|
-
// src/features/analysis/add_fix_comments_for_pr/add_fix_comments_for_pr.ts
|
|
10504
|
-
var debug9 = Debug8("mobbdev:handle-finished-analysis");
|
|
10505
|
-
async function addFixCommentsForPr({
|
|
10506
|
-
analysisId,
|
|
10507
|
-
scm: _scm,
|
|
10508
|
-
gqlClient,
|
|
10509
|
-
scanner
|
|
10510
|
-
}) {
|
|
10511
|
-
if (!(_scm instanceof GithubSCMLib)) {
|
|
10512
|
-
return;
|
|
10513
|
-
}
|
|
10514
|
-
const scm = _scm;
|
|
10515
|
-
const getAnalysisRes = await gqlClient.getAnalysis(analysisId);
|
|
10516
|
-
debug9("getAnalysis %o", getAnalysisRes);
|
|
10517
|
-
const {
|
|
10518
|
-
vulnerabilityReport: {
|
|
10519
|
-
projectId,
|
|
10520
|
-
project: {
|
|
10521
|
-
organizationId,
|
|
10522
|
-
organization: { ghFixerNoFixComments }
|
|
10523
|
-
}
|
|
10524
|
-
}
|
|
10525
|
-
} = getAnalysisRes;
|
|
10526
|
-
if (!getAnalysisRes.repo?.commitSha || !getAnalysisRes.repo.pullRequest) {
|
|
10527
|
-
throw new Error("repo not found");
|
|
10528
|
-
}
|
|
10529
|
-
const { commitSha, pullRequest } = getAnalysisRes.repo;
|
|
10530
|
-
const diff = await scm.getPrDiff({ pull_number: pullRequest });
|
|
10531
|
-
const prVulenrabilities = await getRelevantVulenrabilitiesFromDiff({
|
|
10532
|
-
diff,
|
|
10533
|
-
gqlClient,
|
|
10534
|
-
vulnerabilityReportId: getAnalysisRes.vulnerabilityReportId
|
|
10535
|
-
});
|
|
10536
|
-
const {
|
|
10537
|
-
vulnerabilityReportIssueCodeNodes,
|
|
10538
|
-
irrelevantVulnerabilityReportIssues
|
|
10539
|
-
} = prVulenrabilities;
|
|
10540
|
-
const fixesId = vulnerabilityReportIssueCodeNodes.map(
|
|
10541
|
-
({ vulnerabilityReportIssue: { fixId } }) => fixId
|
|
10542
|
-
);
|
|
10543
|
-
const fixesById = await getFixesData({ fixesId, gqlClient });
|
|
10544
|
-
const [comments, generalPrComments] = await Promise.all([
|
|
10545
|
-
scm.getPrComments({ pull_number: pullRequest }),
|
|
10546
|
-
scm.getGeneralPrComments({ prNumber: pullRequest })
|
|
10547
|
-
]);
|
|
10548
|
-
await Promise.all([
|
|
10549
|
-
...deleteAllPreviousComments({ comments, scm }),
|
|
10550
|
-
...deleteAllPreviousGeneralPrComments({ generalPrComments, scm })
|
|
10551
|
-
]);
|
|
10552
|
-
await Promise.all(
|
|
10553
|
-
[
|
|
10554
|
-
...prVulenrabilities.vulnerabilityReportIssueCodeNodes.map(
|
|
10555
|
-
(vulnerabilityReportIssueCodeNode) => {
|
|
10556
|
-
return postFixComment({
|
|
10557
|
-
vulnerabilityReportIssueCodeNode,
|
|
10558
|
-
projectId,
|
|
10559
|
-
analysisId,
|
|
10560
|
-
organizationId,
|
|
10561
|
-
fixesById,
|
|
10562
|
-
scm,
|
|
10563
|
-
pullRequest,
|
|
10564
|
-
scanner,
|
|
10565
|
-
commitSha
|
|
10566
|
-
});
|
|
10567
|
-
}
|
|
10568
|
-
),
|
|
10569
|
-
...irrelevantVulnerabilityReportIssues.map(
|
|
10570
|
-
async (vulnerabilityReportIssue) => {
|
|
10571
|
-
let fpDescription = null;
|
|
10572
|
-
if (vulnerabilityReportIssue.fpId) {
|
|
10573
|
-
const fpRes = await gqlClient.getFalsePositive({
|
|
10574
|
-
fpId: vulnerabilityReportIssue.fpId
|
|
10575
|
-
});
|
|
10576
|
-
const parsedFpRes = await FalsePositivePartsZ.parseAsync(
|
|
10577
|
-
fpRes?.getFalsePositive
|
|
10578
|
-
);
|
|
10579
|
-
const { description, contextString } = getParsedFalsePositiveMessage(parsedFpRes);
|
|
10580
|
-
fpDescription = contextString ? `${description}
|
|
10581
|
-
|
|
10582
|
-
${contextString}` : description;
|
|
10583
|
-
}
|
|
10584
|
-
return await Promise.all(
|
|
10585
|
-
vulnerabilityReportIssue.codeNodes.map(
|
|
10586
|
-
async (vulnerabilityReportIssueCodeNode) => {
|
|
10587
|
-
return await postIssueComment({
|
|
10588
|
-
vulnerabilityReportIssueCodeNode: {
|
|
10589
|
-
path: vulnerabilityReportIssueCodeNode.path,
|
|
10590
|
-
startLine: vulnerabilityReportIssueCodeNode.startLine,
|
|
10591
|
-
vulnerabilityReportIssue: {
|
|
10592
|
-
fixId: "",
|
|
10593
|
-
safeIssueType: vulnerabilityReportIssue.safeIssueType,
|
|
10594
|
-
vulnerabilityReportIssueTags: vulnerabilityReportIssue.vulnerabilityReportIssueTags,
|
|
10595
|
-
category: vulnerabilityReportIssue.category
|
|
10596
|
-
},
|
|
10597
|
-
vulnerabilityReportIssueId: vulnerabilityReportIssue.id
|
|
10598
|
-
},
|
|
10599
|
-
projectId,
|
|
10600
|
-
analysisId,
|
|
10601
|
-
organizationId,
|
|
10602
|
-
fixesById,
|
|
10603
|
-
scm,
|
|
10604
|
-
pullRequest,
|
|
10605
|
-
scanner,
|
|
10606
|
-
commitSha,
|
|
10607
|
-
fpDescription
|
|
10608
|
-
});
|
|
10609
|
-
}
|
|
10610
|
-
)
|
|
10611
|
-
);
|
|
10612
|
-
}
|
|
10613
|
-
),
|
|
10614
|
-
!ghFixerNoFixComments && postAnalysisInsightComment({
|
|
10615
|
-
prVulenrabilities,
|
|
10616
|
-
pullRequest,
|
|
10617
|
-
scanner,
|
|
10618
|
-
scm
|
|
10619
|
-
})
|
|
10620
|
-
].filter(Boolean)
|
|
10621
|
-
);
|
|
10622
|
-
}
|
|
10623
|
-
|
|
10624
|
-
// src/features/analysis/auto_pr_handler.ts
|
|
10625
|
-
import Debug9 from "debug";
|
|
10626
|
-
var debug10 = Debug9("mobbdev:handleAutoPr");
|
|
10627
|
-
async function handleAutoPr(params) {
|
|
10628
|
-
const {
|
|
10629
|
-
gqlClient,
|
|
10630
|
-
analysisId,
|
|
10631
|
-
commitDirectly,
|
|
10632
|
-
prId,
|
|
10633
|
-
createSpinner: createSpinner5,
|
|
10634
|
-
createOnePr
|
|
10635
|
-
} = params;
|
|
10636
|
-
const createAutoPrSpinner = createSpinner5(
|
|
10637
|
-
"\u{1F504} Waiting for the analysis to finish before initiating automatic pull request creation"
|
|
10638
|
-
).start();
|
|
10639
|
-
return await gqlClient.subscribeToAnalysis({
|
|
10640
|
-
subscribeToAnalysisParams: {
|
|
10641
|
-
analysisId
|
|
10642
|
-
},
|
|
10643
|
-
callback: async (analysisId2) => {
|
|
10644
|
-
const autoPrAnalysisRes = await gqlClient.autoPrAnalysis({
|
|
10645
|
-
analysisId: analysisId2,
|
|
10646
|
-
commitDirectly,
|
|
10647
|
-
prId,
|
|
10648
|
-
prStrategy: createOnePr ? "CONDENSE" /* Condense */ : "SPREAD" /* Spread */
|
|
10649
|
-
});
|
|
10650
|
-
debug10("auto pr analysis res %o", autoPrAnalysisRes);
|
|
10651
|
-
if (autoPrAnalysisRes.autoPrAnalysis?.__typename === "AutoPrError") {
|
|
10652
|
-
createAutoPrSpinner.error({
|
|
10653
|
-
text: `\u{1F504} Automatic pull request failed - ${autoPrAnalysisRes.autoPrAnalysis.error}`
|
|
10654
|
-
});
|
|
10655
|
-
return;
|
|
10656
|
-
}
|
|
10657
|
-
if (autoPrAnalysisRes.autoPrAnalysis?.__typename === "AutoPrSuccess") {
|
|
10658
|
-
const { appliedAutoPrIssueTypes } = autoPrAnalysisRes.autoPrAnalysis;
|
|
10659
|
-
if (appliedAutoPrIssueTypes.length === 0) {
|
|
10660
|
-
createAutoPrSpinner.success({
|
|
10661
|
-
text: "\u{1F504} Automatic pull request did not find any new fixes to open a pull request for"
|
|
10662
|
-
});
|
|
10663
|
-
return;
|
|
10664
|
-
}
|
|
10665
|
-
createAutoPrSpinner.success({
|
|
10666
|
-
text: `\u{1F504} Automatic pull request creation initiated successfully for the following issue types: ${appliedAutoPrIssueTypes}`
|
|
10667
|
-
});
|
|
10379
|
+
}
|
|
10380
|
+
async updateScmToken(args) {
|
|
10381
|
+
const { scmType, url, token, org, refreshToken } = args;
|
|
10382
|
+
const updateScmTokenResult = await this._clientSdk.updateScmToken({
|
|
10383
|
+
scmType,
|
|
10384
|
+
url,
|
|
10385
|
+
token,
|
|
10386
|
+
org,
|
|
10387
|
+
refreshToken
|
|
10388
|
+
});
|
|
10389
|
+
return updateScmTokenResult;
|
|
10390
|
+
}
|
|
10391
|
+
async uploadS3BucketInfo() {
|
|
10392
|
+
const uploadS3BucketInfoResult = await this._clientSdk.uploadS3BucketInfo({
|
|
10393
|
+
fileName: REPORT_DEFAULT_FILE_NAME
|
|
10394
|
+
});
|
|
10395
|
+
return uploadS3BucketInfoResult;
|
|
10396
|
+
}
|
|
10397
|
+
async getVulByNodesMetadata({
|
|
10398
|
+
hunks,
|
|
10399
|
+
vulnerabilityReportId
|
|
10400
|
+
}) {
|
|
10401
|
+
const filters = hunks.map((hunk) => {
|
|
10402
|
+
const filter = {
|
|
10403
|
+
path: { _eq: hunk.path },
|
|
10404
|
+
_or: hunk.ranges.flatMap(({ endLine, startLine }) => {
|
|
10405
|
+
return [
|
|
10406
|
+
{ startLine: { _gte: startLine, _lte: endLine } },
|
|
10407
|
+
{ endLine: { _gte: startLine, _lte: endLine } }
|
|
10408
|
+
];
|
|
10409
|
+
})
|
|
10410
|
+
};
|
|
10411
|
+
return filter;
|
|
10412
|
+
});
|
|
10413
|
+
const getVulByNodesMetadataRes = await this._clientSdk.getVulByNodesMetadata({
|
|
10414
|
+
filters: { _or: filters },
|
|
10415
|
+
vulnerabilityReportId
|
|
10416
|
+
});
|
|
10417
|
+
const parsedGetVulByNodesMetadataRes = GetVulByNodesMetadataZ.parse(
|
|
10418
|
+
getVulByNodesMetadataRes
|
|
10419
|
+
);
|
|
10420
|
+
const uniqueVulByNodesMetadata = parsedGetVulByNodesMetadataRes.vulnerabilityReportIssueCodeNodes.reduce((acc, vulnerabilityReportIssueCodeNode) => {
|
|
10421
|
+
if (acc[vulnerabilityReportIssueCodeNode.vulnerabilityReportIssueId]) {
|
|
10422
|
+
return acc;
|
|
10668
10423
|
}
|
|
10669
|
-
},
|
|
10670
|
-
callbackStates: ["Finished" /* Finished */]
|
|
10671
|
-
});
|
|
10672
|
-
}
|
|
10673
|
-
|
|
10674
|
-
// src/features/analysis/git.ts
|
|
10675
|
-
init_GitService();
|
|
10676
|
-
import Debug10 from "debug";
|
|
10677
|
-
var debug11 = Debug10("mobbdev:git");
|
|
10678
|
-
async function getGitInfo(srcDirPath) {
|
|
10679
|
-
debug11("getting git info for %s", srcDirPath);
|
|
10680
|
-
const gitService = new GitService(srcDirPath);
|
|
10681
|
-
try {
|
|
10682
|
-
const validationResult = await gitService.validateRepository();
|
|
10683
|
-
if (!validationResult.isValid) {
|
|
10684
|
-
debug11("folder is not a git repo");
|
|
10685
10424
|
return {
|
|
10686
|
-
|
|
10687
|
-
|
|
10688
|
-
reference: void 0,
|
|
10689
|
-
repoUrl: void 0
|
|
10425
|
+
...acc,
|
|
10426
|
+
[vulnerabilityReportIssueCodeNode.vulnerabilityReportIssueId]: vulnerabilityReportIssueCodeNode
|
|
10690
10427
|
};
|
|
10691
|
-
}
|
|
10692
|
-
const
|
|
10428
|
+
}, {});
|
|
10429
|
+
const nonFixablePrVuls = parsedGetVulByNodesMetadataRes.nonFixablePrVuls.aggregate.count;
|
|
10430
|
+
const fixablePrVuls = parsedGetVulByNodesMetadataRes.fixablePrVuls.aggregate.count;
|
|
10431
|
+
const totalScanVulnerabilities = parsedGetVulByNodesMetadataRes.totalScanVulnerabilities.aggregate.count;
|
|
10432
|
+
const vulnerabilitiesOutsidePr = totalScanVulnerabilities - nonFixablePrVuls - fixablePrVuls;
|
|
10433
|
+
const totalPrVulnerabilities = nonFixablePrVuls + fixablePrVuls;
|
|
10434
|
+
const irrelevantVulnerabilityReportIssues = parsedGetVulByNodesMetadataRes.irrelevantVulnerabilityReportIssue?.[0]?.vulnerabilityReportIssues ?? [];
|
|
10693
10435
|
return {
|
|
10694
|
-
|
|
10695
|
-
|
|
10436
|
+
vulnerabilityReportIssueCodeNodes: Object.values(
|
|
10437
|
+
uniqueVulByNodesMetadata
|
|
10438
|
+
),
|
|
10439
|
+
nonFixablePrVuls,
|
|
10440
|
+
fixablePrVuls,
|
|
10441
|
+
totalScanVulnerabilities,
|
|
10442
|
+
vulnerabilitiesOutsidePr,
|
|
10443
|
+
totalPrVulnerabilities,
|
|
10444
|
+
irrelevantVulnerabilityReportIssues
|
|
10696
10445
|
};
|
|
10697
|
-
} catch (e) {
|
|
10698
|
-
if (e instanceof Error) {
|
|
10699
|
-
debug11("failed to run git %o", e);
|
|
10700
|
-
if (e.message.includes(" spawn ")) {
|
|
10701
|
-
debug11("git cli not installed");
|
|
10702
|
-
} else {
|
|
10703
|
-
throw e;
|
|
10704
|
-
}
|
|
10705
|
-
}
|
|
10706
|
-
throw e;
|
|
10707
10446
|
}
|
|
10708
|
-
|
|
10709
|
-
|
|
10710
|
-
|
|
10711
|
-
|
|
10712
|
-
|
|
10713
|
-
|
|
10714
|
-
|
|
10715
|
-
|
|
10716
|
-
|
|
10717
|
-
|
|
10718
|
-
|
|
10719
|
-
|
|
10720
|
-
|
|
10721
|
-
|
|
10722
|
-
|
|
10723
|
-
|
|
10724
|
-
|
|
10725
|
-
|
|
10726
|
-
|
|
10727
|
-
|
|
10728
|
-
debug12(
|
|
10729
|
-
`Using proxy: ${proxy ? "yes" : "no"} with url: ${options.url} and with proxy: ${process.env["HTTP_PROXY"]} for the websocket connection`
|
|
10730
|
-
);
|
|
10731
|
-
const CustomWebSocket = class extends WebSocket {
|
|
10732
|
-
constructor(address, protocols) {
|
|
10733
|
-
super(
|
|
10734
|
-
address,
|
|
10735
|
-
protocols,
|
|
10736
|
-
proxy ? { agent: proxy } : void 0
|
|
10737
|
-
);
|
|
10447
|
+
async digestVulnerabilityReport({
|
|
10448
|
+
fixReportId,
|
|
10449
|
+
projectId,
|
|
10450
|
+
scanSource,
|
|
10451
|
+
repoUrl,
|
|
10452
|
+
reference,
|
|
10453
|
+
sha,
|
|
10454
|
+
shouldScan
|
|
10455
|
+
}) {
|
|
10456
|
+
const res = await this._clientSdk.DigestVulnerabilityReport({
|
|
10457
|
+
fixReportId,
|
|
10458
|
+
vulnerabilityReportFileName: shouldScan ? void 0 : REPORT_DEFAULT_FILE_NAME,
|
|
10459
|
+
projectId,
|
|
10460
|
+
scanSource,
|
|
10461
|
+
repoUrl,
|
|
10462
|
+
reference,
|
|
10463
|
+
sha
|
|
10464
|
+
});
|
|
10465
|
+
if (res.digestVulnerabilityReport.__typename !== "VulnerabilityReport") {
|
|
10466
|
+
throw new Error("Digesting vulnerability report failed");
|
|
10738
10467
|
}
|
|
10739
|
-
|
|
10740
|
-
|
|
10741
|
-
|
|
10742
|
-
|
|
10743
|
-
|
|
10744
|
-
|
|
10745
|
-
|
|
10746
|
-
|
|
10747
|
-
|
|
10748
|
-
|
|
10749
|
-
|
|
10750
|
-
|
|
10751
|
-
|
|
10468
|
+
return res.digestVulnerabilityReport;
|
|
10469
|
+
}
|
|
10470
|
+
async submitVulnerabilityReport(params) {
|
|
10471
|
+
const {
|
|
10472
|
+
fixReportId,
|
|
10473
|
+
repoUrl,
|
|
10474
|
+
reference,
|
|
10475
|
+
projectId,
|
|
10476
|
+
sha,
|
|
10477
|
+
experimentalEnabled,
|
|
10478
|
+
vulnerabilityReportFileName,
|
|
10479
|
+
pullRequest
|
|
10480
|
+
} = params;
|
|
10481
|
+
return await this._clientSdk.SubmitVulnerabilityReport({
|
|
10482
|
+
fixReportId,
|
|
10483
|
+
repoUrl,
|
|
10484
|
+
reference,
|
|
10485
|
+
vulnerabilityReportFileName,
|
|
10486
|
+
projectId,
|
|
10487
|
+
pullRequest,
|
|
10488
|
+
sha: sha || "",
|
|
10489
|
+
experimentalEnabled: !!experimentalEnabled,
|
|
10490
|
+
scanSource: params.scanSource,
|
|
10491
|
+
scanContext: ScanContext.BUGSY
|
|
10492
|
+
});
|
|
10493
|
+
}
|
|
10494
|
+
async getFixReportState(fixReportId) {
|
|
10495
|
+
const res = await this._clientSdk.FixReportState({ id: fixReportId });
|
|
10496
|
+
return res?.fixReport_by_pk?.state || "Created" /* Created */;
|
|
10497
|
+
}
|
|
10498
|
+
async waitFixReportInit(fixReportId, includeDigested = false) {
|
|
10499
|
+
const FINAL_STATES = [
|
|
10500
|
+
"Finished" /* Finished */,
|
|
10501
|
+
"Failed" /* Failed */
|
|
10502
|
+
];
|
|
10503
|
+
let lastState = "Created" /* Created */;
|
|
10504
|
+
let attempts = 100;
|
|
10505
|
+
if (includeDigested) {
|
|
10506
|
+
FINAL_STATES.push("Digested" /* Digested */);
|
|
10752
10507
|
}
|
|
10753
|
-
|
|
10754
|
-
|
|
10755
|
-
|
|
10756
|
-
|
|
10757
|
-
|
|
10758
|
-
|
|
10759
|
-
|
|
10760
|
-
|
|
10761
|
-
|
|
10762
|
-
|
|
10763
|
-
|
|
10508
|
+
do {
|
|
10509
|
+
await sleep(REPORT_STATE_CHECK_DELAY);
|
|
10510
|
+
lastState = await this.getFixReportState(fixReportId);
|
|
10511
|
+
} while (!FINAL_STATES.includes(
|
|
10512
|
+
lastState
|
|
10513
|
+
// wait for final the state of the fix report
|
|
10514
|
+
) && attempts-- > 0);
|
|
10515
|
+
return lastState;
|
|
10516
|
+
}
|
|
10517
|
+
async getVulnerabilityReportPaths(vulnerabilityReportId) {
|
|
10518
|
+
const res = await this._clientSdk.GetVulnerabilityReportPaths({
|
|
10519
|
+
vulnerabilityReportId
|
|
10764
10520
|
});
|
|
10765
|
-
|
|
10766
|
-
|
|
10767
|
-
|
|
10768
|
-
|
|
10769
|
-
|
|
10770
|
-
|
|
10771
|
-
|
|
10772
|
-
|
|
10773
|
-
|
|
10774
|
-
|
|
10775
|
-
|
|
10776
|
-
|
|
10777
|
-
|
|
10778
|
-
if (timer) {
|
|
10779
|
-
clearTimeout(timer);
|
|
10780
|
-
}
|
|
10781
|
-
reject(data2);
|
|
10782
|
-
}
|
|
10783
|
-
if (!data.data) {
|
|
10784
|
-
reject(
|
|
10785
|
-
new Error(
|
|
10786
|
-
`Broken data object from graphQL subscribe: ${JSON.stringify(
|
|
10787
|
-
data
|
|
10788
|
-
)} for query: ${query}`
|
|
10789
|
-
)
|
|
10790
|
-
);
|
|
10791
|
-
} else {
|
|
10792
|
-
callback(callbackResolve, callbackReject, data.data);
|
|
10793
|
-
}
|
|
10794
|
-
},
|
|
10795
|
-
error: (error) => {
|
|
10796
|
-
if (timer) {
|
|
10797
|
-
clearTimeout(timer);
|
|
10798
|
-
}
|
|
10799
|
-
reject(error);
|
|
10800
|
-
},
|
|
10801
|
-
complete: () => {
|
|
10521
|
+
return res.vulnerability_report_path.map((p) => p.path);
|
|
10522
|
+
}
|
|
10523
|
+
async subscribeToAnalysis(params) {
|
|
10524
|
+
const { callbackStates } = params;
|
|
10525
|
+
return subscribe(
|
|
10526
|
+
GetAnalysisSubscriptionDocument,
|
|
10527
|
+
params.subscribeToAnalysisParams,
|
|
10528
|
+
async (resolve, reject, data) => {
|
|
10529
|
+
if (!data.analysis?.state || data.analysis?.state === "Failed" /* Failed */) {
|
|
10530
|
+
const errorMessage = data.analysis?.failReason || `Analysis failed with id: ${data.analysis?.id}`;
|
|
10531
|
+
reject(
|
|
10532
|
+
new ReportDigestError(errorMessage, data.analysis?.failReason ?? "")
|
|
10533
|
+
);
|
|
10802
10534
|
return;
|
|
10803
10535
|
}
|
|
10536
|
+
if (callbackStates.includes(data.analysis?.state)) {
|
|
10537
|
+
await params.callback(data.analysis.id);
|
|
10538
|
+
resolve(data);
|
|
10539
|
+
}
|
|
10540
|
+
},
|
|
10541
|
+
this._auth.type === "apiKey" ? {
|
|
10542
|
+
apiKey: this._auth.apiKey,
|
|
10543
|
+
type: "apiKey",
|
|
10544
|
+
timeoutInMs: params.timeoutInMs
|
|
10545
|
+
} : {
|
|
10546
|
+
token: this._auth.token,
|
|
10547
|
+
type: "token",
|
|
10548
|
+
timeoutInMs: params.timeoutInMs
|
|
10804
10549
|
}
|
|
10805
10550
|
);
|
|
10806
|
-
|
|
10807
|
-
|
|
10808
|
-
|
|
10809
|
-
|
|
10810
|
-
|
|
10811
|
-
|
|
10812
|
-
|
|
10813
|
-
|
|
10814
|
-
|
|
10551
|
+
}
|
|
10552
|
+
async getFixReportsByRepoUrl({ repoUrl }) {
|
|
10553
|
+
const res = await this._clientSdk.GetFixReportsByRepoUrl({
|
|
10554
|
+
repoUrl
|
|
10555
|
+
});
|
|
10556
|
+
return res;
|
|
10557
|
+
}
|
|
10558
|
+
async getAnalysis(analysisId) {
|
|
10559
|
+
const res = await this._clientSdk.getAnalysis({
|
|
10560
|
+
analysisId
|
|
10561
|
+
});
|
|
10562
|
+
if (!res.analysis) {
|
|
10563
|
+
throw new Error(`Analysis not found: ${analysisId}`);
|
|
10815
10564
|
}
|
|
10565
|
+
return res.analysis;
|
|
10566
|
+
}
|
|
10567
|
+
async autoPrAnalysis({
|
|
10568
|
+
analysisId,
|
|
10569
|
+
commitDirectly,
|
|
10570
|
+
prId,
|
|
10571
|
+
prStrategy
|
|
10572
|
+
}) {
|
|
10573
|
+
return this._clientSdk.autoPrAnalysis({
|
|
10574
|
+
analysisId,
|
|
10575
|
+
commitDirectly,
|
|
10576
|
+
prId,
|
|
10577
|
+
prStrategy
|
|
10578
|
+
});
|
|
10579
|
+
}
|
|
10580
|
+
async getFixes(fixIds) {
|
|
10581
|
+
const res = await this._clientSdk.getFixes({
|
|
10582
|
+
filters: { id: { _in: fixIds } }
|
|
10583
|
+
});
|
|
10584
|
+
return res;
|
|
10585
|
+
}
|
|
10586
|
+
async validateRepoUrl(args) {
|
|
10587
|
+
return this._clientSdk.validateRepoUrl(args);
|
|
10588
|
+
}
|
|
10589
|
+
async getReferenceData(args) {
|
|
10590
|
+
return this._clientSdk.gitReference(args);
|
|
10591
|
+
}
|
|
10592
|
+
async getFalsePositive(args) {
|
|
10593
|
+
return this._clientSdk.getFalsePositive(args);
|
|
10594
|
+
}
|
|
10595
|
+
async uploadAIBlameInferencesInitRaw(variables) {
|
|
10596
|
+
return await this._clientSdk.UploadAIBlameInferencesInit(variables);
|
|
10597
|
+
}
|
|
10598
|
+
async finalizeAIBlameInferencesUploadRaw(variables) {
|
|
10599
|
+
return await this._clientSdk.FinalizeAIBlameInferencesUpload(variables);
|
|
10600
|
+
}
|
|
10601
|
+
};
|
|
10602
|
+
|
|
10603
|
+
// src/commands/handleMobbLogin.ts
|
|
10604
|
+
var debug8 = Debug7("mobbdev:commands");
|
|
10605
|
+
var LOGIN_MAX_WAIT = 10 * 60 * 1e3;
|
|
10606
|
+
var LOGIN_CHECK_DELAY = 5 * 1e3;
|
|
10607
|
+
var webLoginUrl = `${WEB_APP_URL}/cli-login`;
|
|
10608
|
+
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, ${chalk3.bgBlue(
|
|
10609
|
+
"press any key to continue"
|
|
10610
|
+
)};`;
|
|
10611
|
+
var config2 = new Configstore(packageJson.name, { apiToken: "" });
|
|
10612
|
+
async function handleMobbLogin({
|
|
10613
|
+
inGqlClient,
|
|
10614
|
+
apiKey,
|
|
10615
|
+
skipPrompts
|
|
10616
|
+
}) {
|
|
10617
|
+
const { createSpinner: createSpinner5 } = Spinner({ ci: skipPrompts });
|
|
10618
|
+
const isConnected = await inGqlClient.verifyApiConnection();
|
|
10619
|
+
if (!isConnected) {
|
|
10620
|
+
createSpinner5().start().error({
|
|
10621
|
+
text: "\u{1F513} Connection to Mobb: failed to connect to the Mobb server"
|
|
10622
|
+
});
|
|
10623
|
+
throw new CliError(
|
|
10624
|
+
"Connection to Mobb: failed to connect to the Mobb server"
|
|
10625
|
+
);
|
|
10626
|
+
}
|
|
10627
|
+
createSpinner5().start().success({
|
|
10628
|
+
text: `\u{1F513} Connection to Mobb: succeeded`
|
|
10629
|
+
});
|
|
10630
|
+
const userVerify = await inGqlClient.validateUserToken();
|
|
10631
|
+
if (userVerify) {
|
|
10632
|
+
createSpinner5().start().success({
|
|
10633
|
+
text: `\u{1F513} Login to Mobb succeeded. ${typeof userVerify === "string" ? `Logged in as ${userVerify}` : ""}`
|
|
10634
|
+
});
|
|
10635
|
+
return inGqlClient;
|
|
10636
|
+
} else if (apiKey) {
|
|
10637
|
+
createSpinner5().start().error({
|
|
10638
|
+
text: "\u{1F513} Login to Mobb failed: The provided API key does not match any configured API key on the system"
|
|
10639
|
+
});
|
|
10640
|
+
throw new CliError(
|
|
10641
|
+
"Login to Mobb failed: The provided API key does not match any configured API key on the system"
|
|
10642
|
+
);
|
|
10643
|
+
}
|
|
10644
|
+
const loginSpinner = createSpinner5().start();
|
|
10645
|
+
if (!skipPrompts) {
|
|
10646
|
+
loginSpinner.update({ text: MOBB_LOGIN_REQUIRED_MSG });
|
|
10647
|
+
await keypress();
|
|
10648
|
+
}
|
|
10649
|
+
loginSpinner.update({
|
|
10650
|
+
text: "\u{1F513} Waiting for Mobb login..."
|
|
10651
|
+
});
|
|
10652
|
+
const { publicKey, privateKey } = crypto.generateKeyPairSync("rsa", {
|
|
10653
|
+
modulusLength: 2048
|
|
10816
10654
|
});
|
|
10655
|
+
const loginId = await inGqlClient.createCliLogin({
|
|
10656
|
+
publicKey: publicKey.export({ format: "pem", type: "pkcs1" }).toString()
|
|
10657
|
+
});
|
|
10658
|
+
const browserUrl = `${webLoginUrl}/${loginId}?hostname=${os.hostname()}`;
|
|
10659
|
+
!skipPrompts && console.log(
|
|
10660
|
+
`If the page does not open automatically, kindly access it through ${browserUrl}.`
|
|
10661
|
+
);
|
|
10662
|
+
await open(browserUrl);
|
|
10663
|
+
let newApiToken = null;
|
|
10664
|
+
for (let i = 0; i < LOGIN_MAX_WAIT / LOGIN_CHECK_DELAY; i++) {
|
|
10665
|
+
const encryptedApiToken = await inGqlClient.getEncryptedApiToken({
|
|
10666
|
+
loginId
|
|
10667
|
+
});
|
|
10668
|
+
loginSpinner.spin();
|
|
10669
|
+
if (encryptedApiToken) {
|
|
10670
|
+
debug8("encrypted API token received %s", encryptedApiToken);
|
|
10671
|
+
newApiToken = crypto.privateDecrypt(privateKey, Buffer.from(encryptedApiToken, "base64")).toString("utf-8");
|
|
10672
|
+
debug8("API token decrypted");
|
|
10673
|
+
break;
|
|
10674
|
+
}
|
|
10675
|
+
await sleep(LOGIN_CHECK_DELAY);
|
|
10676
|
+
}
|
|
10677
|
+
if (!newApiToken) {
|
|
10678
|
+
loginSpinner.error({
|
|
10679
|
+
text: "Login timeout error"
|
|
10680
|
+
});
|
|
10681
|
+
throw new CliError();
|
|
10682
|
+
}
|
|
10683
|
+
const newGqlClient = new GQLClient({ apiKey: newApiToken, type: "apiKey" });
|
|
10684
|
+
const loginSuccess = await newGqlClient.validateUserToken();
|
|
10685
|
+
if (loginSuccess) {
|
|
10686
|
+
debug8(`set api token ${newApiToken}`);
|
|
10687
|
+
config2.set("apiToken", newApiToken);
|
|
10688
|
+
loginSpinner.success({
|
|
10689
|
+
text: `\u{1F513} Login to Mobb successful! ${typeof loginSpinner === "string" ? `Logged in as ${loginSuccess}` : ""}`
|
|
10690
|
+
});
|
|
10691
|
+
} else {
|
|
10692
|
+
loginSpinner.error({
|
|
10693
|
+
text: "Something went wrong, API token is invalid."
|
|
10694
|
+
});
|
|
10695
|
+
throw new CliError();
|
|
10696
|
+
}
|
|
10697
|
+
return newGqlClient;
|
|
10817
10698
|
}
|
|
10818
10699
|
|
|
10819
|
-
// src/features/analysis/
|
|
10700
|
+
// src/features/analysis/add_fix_comments_for_pr/add_fix_comments_for_pr.ts
|
|
10701
|
+
import Debug11 from "debug";
|
|
10702
|
+
|
|
10703
|
+
// src/features/analysis/add_fix_comments_for_pr/utils/utils.ts
|
|
10704
|
+
import Debug10 from "debug";
|
|
10705
|
+
import parseDiff from "parse-diff";
|
|
10820
10706
|
import { z as z27 } from "zod";
|
|
10821
|
-
var VulnerabilityReportIssueCodeNodeZ = z27.object({
|
|
10822
|
-
vulnerabilityReportIssueId: z27.string(),
|
|
10823
|
-
path: z27.string(),
|
|
10824
|
-
startLine: z27.number(),
|
|
10825
|
-
vulnerabilityReportIssue: z27.object({
|
|
10826
|
-
fixId: z27.string(),
|
|
10827
|
-
category: z27.nativeEnum(Vulnerability_Report_Issue_Category_Enum),
|
|
10828
|
-
safeIssueType: z27.string(),
|
|
10829
|
-
vulnerabilityReportIssueTags: z27.array(
|
|
10830
|
-
z27.object({
|
|
10831
|
-
tag: z27.nativeEnum(Vulnerability_Report_Issue_Tag_Enum)
|
|
10832
|
-
})
|
|
10833
|
-
)
|
|
10834
|
-
})
|
|
10835
|
-
});
|
|
10836
|
-
var VulnerabilityReportIssueNoFixCodeNodeZ = z27.object({
|
|
10837
|
-
vulnerabilityReportIssues: z27.array(
|
|
10838
|
-
z27.object({
|
|
10839
|
-
id: z27.string(),
|
|
10840
|
-
fixId: z27.string().nullable(),
|
|
10841
|
-
category: z27.nativeEnum(Vulnerability_Report_Issue_Category_Enum),
|
|
10842
|
-
safeIssueType: z27.string(),
|
|
10843
|
-
fpId: z27.string().uuid().nullable(),
|
|
10844
|
-
codeNodes: z27.array(
|
|
10845
|
-
z27.object({
|
|
10846
|
-
path: z27.string(),
|
|
10847
|
-
startLine: z27.number()
|
|
10848
|
-
})
|
|
10849
|
-
),
|
|
10850
|
-
vulnerabilityReportIssueTags: z27.array(
|
|
10851
|
-
z27.object({
|
|
10852
|
-
tag: z27.nativeEnum(Vulnerability_Report_Issue_Tag_Enum)
|
|
10853
|
-
})
|
|
10854
|
-
)
|
|
10855
|
-
})
|
|
10856
|
-
)
|
|
10857
|
-
});
|
|
10858
|
-
var GetVulByNodesMetadataZ = z27.object({
|
|
10859
|
-
vulnerabilityReportIssueCodeNodes: z27.array(VulnerabilityReportIssueCodeNodeZ),
|
|
10860
|
-
nonFixablePrVuls: z27.object({
|
|
10861
|
-
aggregate: z27.object({
|
|
10862
|
-
count: z27.number()
|
|
10863
|
-
})
|
|
10864
|
-
}),
|
|
10865
|
-
fixablePrVuls: z27.object({
|
|
10866
|
-
aggregate: z27.object({
|
|
10867
|
-
count: z27.number()
|
|
10868
|
-
})
|
|
10869
|
-
}),
|
|
10870
|
-
totalScanVulnerabilities: z27.object({
|
|
10871
|
-
aggregate: z27.object({
|
|
10872
|
-
count: z27.number()
|
|
10873
|
-
})
|
|
10874
|
-
}),
|
|
10875
|
-
irrelevantVulnerabilityReportIssue: z27.array(
|
|
10876
|
-
VulnerabilityReportIssueNoFixCodeNodeZ
|
|
10877
|
-
)
|
|
10878
|
-
});
|
|
10879
10707
|
|
|
10880
|
-
// src/features/analysis/
|
|
10881
|
-
|
|
10882
|
-
|
|
10883
|
-
|
|
10884
|
-
|
|
10885
|
-
try {
|
|
10886
|
-
const parsedUrl = new URL(url);
|
|
10887
|
-
const isHttp = parsedUrl.protocol === "http:";
|
|
10888
|
-
const isHttps = parsedUrl.protocol === "https:";
|
|
10889
|
-
const proxy = isHttps ? HTTPS_PROXY : isHttp ? HTTP_PROXY : null;
|
|
10890
|
-
if (proxy) {
|
|
10891
|
-
debug13("Using proxy %s", proxy);
|
|
10892
|
-
debug13("Proxy agent %o", proxy);
|
|
10893
|
-
return isHttps ? new HttpsProxyAgent2(proxy) : new HttpProxyAgent(proxy);
|
|
10894
|
-
}
|
|
10895
|
-
} catch (err) {
|
|
10896
|
-
debug13(`Skipping proxy for ${url}. Reason: ${err.message}`);
|
|
10897
|
-
}
|
|
10898
|
-
return void 0;
|
|
10708
|
+
// src/features/analysis/utils/by_key.ts
|
|
10709
|
+
function keyBy(array, keyBy2) {
|
|
10710
|
+
return array.reduce((acc, item) => {
|
|
10711
|
+
return { ...acc, [item[keyBy2]]: item };
|
|
10712
|
+
}, {});
|
|
10899
10713
|
}
|
|
10900
|
-
|
|
10714
|
+
|
|
10715
|
+
// src/features/analysis/utils/send_report.ts
|
|
10716
|
+
import Debug8 from "debug";
|
|
10717
|
+
var debug9 = Debug8("mobbdev:index");
|
|
10718
|
+
async function sendReport({
|
|
10719
|
+
spinner,
|
|
10720
|
+
submitVulnerabilityReportVariables,
|
|
10721
|
+
gqlClient
|
|
10722
|
+
}) {
|
|
10901
10723
|
try {
|
|
10902
|
-
const
|
|
10903
|
-
|
|
10904
|
-
|
|
10905
|
-
|
|
10906
|
-
|
|
10907
|
-
|
|
10908
|
-
});
|
|
10724
|
+
const submitRes = await gqlClient.submitVulnerabilityReport(
|
|
10725
|
+
submitVulnerabilityReportVariables
|
|
10726
|
+
);
|
|
10727
|
+
if (submitRes.submitVulnerabilityReport.__typename !== "VulnerabilityReport") {
|
|
10728
|
+
debug9("error submit vul report %s", submitRes);
|
|
10729
|
+
throw new Error("\u{1F575}\uFE0F\u200D\u2642\uFE0F Mobb analysis failed");
|
|
10909
10730
|
}
|
|
10910
|
-
|
|
10911
|
-
|
|
10912
|
-
|
|
10913
|
-
|
|
10914
|
-
};
|
|
10915
|
-
var GQLClient = class {
|
|
10916
|
-
constructor(args) {
|
|
10917
|
-
__publicField(this, "_client");
|
|
10918
|
-
__publicField(this, "_clientSdk");
|
|
10919
|
-
__publicField(this, "_auth");
|
|
10920
|
-
debug13(`init with ${args}`);
|
|
10921
|
-
this._auth = args;
|
|
10922
|
-
this._client = new GraphQLClient(API_URL, {
|
|
10923
|
-
headers: args.type === "apiKey" ? { [API_KEY_HEADER_NAME]: args.apiKey || "" } : {
|
|
10924
|
-
Authorization: `Bearer ${args.token}`
|
|
10731
|
+
spinner.update({ text: progressMassages.processingVulnerabilityReport });
|
|
10732
|
+
await gqlClient.subscribeToAnalysis({
|
|
10733
|
+
subscribeToAnalysisParams: {
|
|
10734
|
+
analysisId: submitRes.submitVulnerabilityReport.fixReportId
|
|
10925
10735
|
},
|
|
10926
|
-
|
|
10927
|
-
|
|
10928
|
-
|
|
10929
|
-
|
|
10930
|
-
|
|
10931
|
-
|
|
10932
|
-
|
|
10933
|
-
|
|
10934
|
-
headers: {
|
|
10935
|
-
...request.headers,
|
|
10936
|
-
"x-hasura-request-id": requestId
|
|
10937
|
-
}
|
|
10938
|
-
};
|
|
10939
|
-
}
|
|
10736
|
+
callback: () => spinner.update({
|
|
10737
|
+
text: "\u2699\uFE0F Vulnerability report processed successfully"
|
|
10738
|
+
}),
|
|
10739
|
+
callbackStates: [
|
|
10740
|
+
"Digested" /* Digested */,
|
|
10741
|
+
"Finished" /* Finished */
|
|
10742
|
+
],
|
|
10743
|
+
timeoutInMs: VUL_REPORT_DIGEST_TIMEOUT_MS
|
|
10940
10744
|
});
|
|
10941
|
-
|
|
10745
|
+
return submitRes;
|
|
10746
|
+
} catch (e) {
|
|
10747
|
+
spinner.error({ text: "\u{1F575}\uFE0F\u200D\u2642\uFE0F Mobb analysis failed" });
|
|
10748
|
+
throw e;
|
|
10942
10749
|
}
|
|
10943
|
-
|
|
10944
|
-
|
|
10945
|
-
|
|
10750
|
+
}
|
|
10751
|
+
|
|
10752
|
+
// src/features/analysis/utils/index.ts
|
|
10753
|
+
function getFromArraySafe(array) {
|
|
10754
|
+
return array.reduce((acc, nullableItem) => {
|
|
10755
|
+
if (nullableItem) {
|
|
10756
|
+
acc.push(nullableItem);
|
|
10757
|
+
}
|
|
10758
|
+
return acc;
|
|
10759
|
+
}, []);
|
|
10760
|
+
}
|
|
10761
|
+
|
|
10762
|
+
// src/features/analysis/add_fix_comments_for_pr/constants.ts
|
|
10763
|
+
var contactUsMarkdown = `For specific requests [contact us](https://content.mobb.ai/contact) and we'll do the most to answer your need quickly.`;
|
|
10764
|
+
var MobbIconMarkdown = ``;
|
|
10765
|
+
var noVulnerabilitiesFoundTitle = `# ${MobbIconMarkdown} No security issues were found \u2705`;
|
|
10766
|
+
var COMMIT_FIX_SVG = `https://app.mobb.ai/gh-action/commit-button.svg`;
|
|
10767
|
+
var scannerToFriendlyString = {
|
|
10768
|
+
checkmarx: "Checkmarx",
|
|
10769
|
+
codeql: "CodeQL",
|
|
10770
|
+
fortify: "Fortify",
|
|
10771
|
+
snyk: "Snyk",
|
|
10772
|
+
sonarqube: "Sonarqube",
|
|
10773
|
+
semgrep: "Semgrep",
|
|
10774
|
+
datadog: "Datadog"
|
|
10775
|
+
};
|
|
10776
|
+
|
|
10777
|
+
// src/features/analysis/add_fix_comments_for_pr/utils/buildCommentBody.ts
|
|
10778
|
+
import Debug9 from "debug";
|
|
10779
|
+
import { z as z26 } from "zod";
|
|
10780
|
+
var debug10 = Debug9("mobbdev:handle-finished-analysis");
|
|
10781
|
+
var getCommitFixButton = (commitUrl) => `<a href="${commitUrl}"><img src=${COMMIT_FIX_SVG}></a>`;
|
|
10782
|
+
function buildFixCommentBody({
|
|
10783
|
+
fix,
|
|
10784
|
+
issueId,
|
|
10785
|
+
commentId,
|
|
10786
|
+
commentUrl,
|
|
10787
|
+
scanner,
|
|
10788
|
+
fixId,
|
|
10789
|
+
projectId,
|
|
10790
|
+
analysisId,
|
|
10791
|
+
organizationId,
|
|
10792
|
+
patch,
|
|
10793
|
+
irrelevantIssueWithTags
|
|
10794
|
+
}) {
|
|
10795
|
+
const isIrrelevantIssueWithTags = irrelevantIssueWithTags?.[0]?.tag;
|
|
10796
|
+
const commitUrl = isIrrelevantIssueWithTags ? getCommitIssueUrl({
|
|
10797
|
+
appBaseUrl: WEB_APP_URL,
|
|
10798
|
+
issueId,
|
|
10799
|
+
projectId,
|
|
10800
|
+
analysisId,
|
|
10801
|
+
organizationId,
|
|
10802
|
+
redirectUrl: commentUrl,
|
|
10803
|
+
commentId
|
|
10804
|
+
}) : getCommitUrl({
|
|
10805
|
+
appBaseUrl: WEB_APP_URL,
|
|
10806
|
+
fixId,
|
|
10807
|
+
projectId,
|
|
10808
|
+
analysisId,
|
|
10809
|
+
organizationId,
|
|
10810
|
+
redirectUrl: commentUrl,
|
|
10811
|
+
commentId
|
|
10812
|
+
});
|
|
10813
|
+
const fixUrl = isIrrelevantIssueWithTags ? getIssueUrlWithRedirect({
|
|
10814
|
+
appBaseUrl: WEB_APP_URL,
|
|
10815
|
+
issueId,
|
|
10816
|
+
projectId,
|
|
10817
|
+
analysisId,
|
|
10818
|
+
organizationId,
|
|
10819
|
+
redirectUrl: commentUrl,
|
|
10820
|
+
commentId
|
|
10821
|
+
}) : getFixUrlWithRedirect({
|
|
10822
|
+
appBaseUrl: WEB_APP_URL,
|
|
10823
|
+
fixId,
|
|
10824
|
+
projectId,
|
|
10825
|
+
analysisId,
|
|
10826
|
+
organizationId,
|
|
10827
|
+
redirectUrl: commentUrl,
|
|
10828
|
+
commentId
|
|
10829
|
+
});
|
|
10830
|
+
const issueType = getIssueTypeFriendlyString(fix.safeIssueType);
|
|
10831
|
+
const title = `# ${MobbIconMarkdown} ${issueType} fix is ready`;
|
|
10832
|
+
const validFixParseRes = z26.object({
|
|
10833
|
+
patchAndQuestions: PatchAndQuestionsZ,
|
|
10834
|
+
safeIssueLanguage: z26.nativeEnum(IssueLanguage_Enum),
|
|
10835
|
+
severityText: z26.nativeEnum(Vulnerability_Severity_Enum),
|
|
10836
|
+
safeIssueType: z26.nativeEnum(IssueType_Enum)
|
|
10837
|
+
}).safeParse(fix);
|
|
10838
|
+
if (!validFixParseRes.success) {
|
|
10839
|
+
debug10(
|
|
10840
|
+
`fix ${fixId} has custom issue type or language, therefore the commit description will not be added`,
|
|
10841
|
+
validFixParseRes.error
|
|
10842
|
+
);
|
|
10946
10843
|
}
|
|
10947
|
-
|
|
10948
|
-
|
|
10949
|
-
|
|
10950
|
-
|
|
10951
|
-
|
|
10952
|
-
|
|
10844
|
+
const subTitle = validFixParseRes.success ? getCommitDescription({
|
|
10845
|
+
issueType: validFixParseRes.data.safeIssueType,
|
|
10846
|
+
vendor: scannerToVulnerabilityReportVendorEnum[scanner],
|
|
10847
|
+
severity: validFixParseRes.data.severityText,
|
|
10848
|
+
guidances: getGuidances({
|
|
10849
|
+
questions: validFixParseRes.data.patchAndQuestions.questions.map(toQuestion),
|
|
10850
|
+
issueType: validFixParseRes.data.safeIssueType,
|
|
10851
|
+
issueLanguage: validFixParseRes.data.safeIssueLanguage,
|
|
10852
|
+
fixExtraContext: validFixParseRes.data.patchAndQuestions.extraContext
|
|
10853
|
+
}),
|
|
10854
|
+
irrelevantIssueWithTags
|
|
10855
|
+
}) : "";
|
|
10856
|
+
const diff = `\`\`\`diff
|
|
10857
|
+
${patch}
|
|
10858
|
+
\`\`\``;
|
|
10859
|
+
const fixPageLink = `[Learn more and fine tune the fix](${fixUrl})`;
|
|
10860
|
+
return `${title}
|
|
10861
|
+
${subTitle}
|
|
10862
|
+
${diff}
|
|
10863
|
+
${getCommitFixButton(
|
|
10864
|
+
commitUrl
|
|
10865
|
+
)}
|
|
10866
|
+
${fixPageLink}`;
|
|
10867
|
+
}
|
|
10868
|
+
function buildIssueCommentBody({
|
|
10869
|
+
issueId,
|
|
10870
|
+
commentId,
|
|
10871
|
+
commentUrl,
|
|
10872
|
+
scanner,
|
|
10873
|
+
issueType,
|
|
10874
|
+
projectId,
|
|
10875
|
+
analysisId,
|
|
10876
|
+
organizationId,
|
|
10877
|
+
irrelevantIssueWithTags,
|
|
10878
|
+
fpDescription
|
|
10879
|
+
}) {
|
|
10880
|
+
const issueUrl = getIssueUrlWithRedirect({
|
|
10881
|
+
appBaseUrl: WEB_APP_URL,
|
|
10882
|
+
issueId,
|
|
10883
|
+
projectId,
|
|
10884
|
+
analysisId,
|
|
10885
|
+
organizationId,
|
|
10886
|
+
redirectUrl: commentUrl,
|
|
10887
|
+
commentId
|
|
10888
|
+
});
|
|
10889
|
+
const title = `# ${MobbIconMarkdown} Irrelevant issues were spotted - no action required \u{1F9F9}`;
|
|
10890
|
+
const subTitle = getCommitIssueDescription({
|
|
10891
|
+
issueType,
|
|
10892
|
+
vendor: scannerToVulnerabilityReportVendorEnum[scanner],
|
|
10893
|
+
irrelevantIssueWithTags,
|
|
10894
|
+
fpDescription
|
|
10895
|
+
});
|
|
10896
|
+
const issuePageLink = `[Learn more about this issue](${issueUrl})`;
|
|
10897
|
+
return `${title}
|
|
10898
|
+
${subTitle}
|
|
10899
|
+
${issuePageLink}`;
|
|
10900
|
+
}
|
|
10901
|
+
|
|
10902
|
+
// src/features/analysis/add_fix_comments_for_pr/utils/utils.ts
|
|
10903
|
+
var debug11 = Debug10("mobbdev:handle-finished-analysis");
|
|
10904
|
+
function calculateRanges(integers) {
|
|
10905
|
+
if (integers.length === 0) {
|
|
10906
|
+
return [];
|
|
10953
10907
|
}
|
|
10954
|
-
|
|
10955
|
-
|
|
10956
|
-
|
|
10957
|
-
|
|
10958
|
-
|
|
10959
|
-
debug13("verify connection failed %o", e);
|
|
10960
|
-
return false;
|
|
10908
|
+
integers.sort((a, b) => a - b);
|
|
10909
|
+
const ranges = integers.reduce(
|
|
10910
|
+
(result, current, index) => {
|
|
10911
|
+
if (index === 0) {
|
|
10912
|
+
return [...result, [current, current]];
|
|
10961
10913
|
}
|
|
10962
|
-
|
|
10963
|
-
|
|
10964
|
-
|
|
10965
|
-
|
|
10966
|
-
|
|
10967
|
-
|
|
10914
|
+
const currentRange = result[result.length - 1];
|
|
10915
|
+
const [_start, end] = currentRange;
|
|
10916
|
+
if (current === end + 1) {
|
|
10917
|
+
currentRange[1] = current;
|
|
10918
|
+
} else {
|
|
10919
|
+
result.push([current, current]);
|
|
10920
|
+
}
|
|
10921
|
+
return result;
|
|
10922
|
+
},
|
|
10923
|
+
[]
|
|
10924
|
+
);
|
|
10925
|
+
return ranges;
|
|
10926
|
+
}
|
|
10927
|
+
function deleteAllPreviousComments({
|
|
10928
|
+
comments,
|
|
10929
|
+
scm
|
|
10930
|
+
}) {
|
|
10931
|
+
return comments.data.filter((comment) => {
|
|
10932
|
+
return comment.body.includes(MOBB_ICON_IMG);
|
|
10933
|
+
}).map((comment) => {
|
|
10968
10934
|
try {
|
|
10969
|
-
|
|
10935
|
+
return scm.deleteComment({ comment_id: comment.id });
|
|
10970
10936
|
} catch (e) {
|
|
10971
|
-
|
|
10972
|
-
return
|
|
10973
|
-
}
|
|
10974
|
-
return info?.email || true;
|
|
10975
|
-
}
|
|
10976
|
-
async getLastOrgAndNamedProject(params) {
|
|
10977
|
-
const me = await this.getUserInfo();
|
|
10978
|
-
const email = me?.email;
|
|
10979
|
-
if (!email) {
|
|
10980
|
-
throw new Error("User email not found");
|
|
10981
|
-
}
|
|
10982
|
-
const { projectName, userDefinedOrganizationId } = params;
|
|
10983
|
-
if (!projectName) {
|
|
10984
|
-
throw new Error("Project name is required");
|
|
10985
|
-
}
|
|
10986
|
-
const orgAndProjectRes = await this._clientSdk.getLastOrgAndNamedProject({
|
|
10987
|
-
email,
|
|
10988
|
-
projectName
|
|
10989
|
-
});
|
|
10990
|
-
if (!orgAndProjectRes.user?.[0]?.userOrganizationsAndUserOrganizationRoles?.[0]?.organization?.id) {
|
|
10991
|
-
throw new Error(
|
|
10992
|
-
`The user with email:${email} is not associated with any organization`
|
|
10993
|
-
);
|
|
10994
|
-
}
|
|
10995
|
-
const organization = orgAndProjectRes.user?.at(0)?.userOrganizationsAndUserOrganizationRoles.map(
|
|
10996
|
-
(org) => org.organization
|
|
10997
|
-
).filter(
|
|
10998
|
-
(org) => userDefinedOrganizationId ? org.id === userDefinedOrganizationId : true
|
|
10999
|
-
)?.at(0);
|
|
11000
|
-
if (!organization) {
|
|
11001
|
-
throw new Error(
|
|
11002
|
-
`Organization with id:${userDefinedOrganizationId} not found`
|
|
11003
|
-
);
|
|
11004
|
-
}
|
|
11005
|
-
let projectId = organization?.projects?.[0]?.id;
|
|
11006
|
-
if (!projectId) {
|
|
11007
|
-
const createdProject = await this._clientSdk.CreateProject({
|
|
11008
|
-
organizationId: organization.id,
|
|
11009
|
-
projectName: projectName || "My project"
|
|
11010
|
-
});
|
|
11011
|
-
projectId = createdProject.createProject.projectId;
|
|
10937
|
+
debug11("delete comment failed %s", e);
|
|
10938
|
+
return Promise.resolve();
|
|
11012
10939
|
}
|
|
11013
|
-
|
|
11014
|
-
|
|
10940
|
+
});
|
|
10941
|
+
}
|
|
10942
|
+
function deleteAllPreviousGeneralPrComments(params) {
|
|
10943
|
+
const { generalPrComments, scm } = params;
|
|
10944
|
+
return generalPrComments.data.filter((comment) => {
|
|
10945
|
+
if (!comment.body) {
|
|
10946
|
+
return false;
|
|
11015
10947
|
}
|
|
11016
|
-
return
|
|
11017
|
-
|
|
11018
|
-
projectId
|
|
11019
|
-
};
|
|
11020
|
-
}
|
|
11021
|
-
async getEncryptedApiToken(variables) {
|
|
11022
|
-
const res = await this._clientSdk.GetEncryptedApiToken(variables, {
|
|
11023
|
-
// We may have outdated API key in the config storage. Avoid using it for the login request.
|
|
11024
|
-
[API_KEY_HEADER_NAME]: ""
|
|
11025
|
-
});
|
|
11026
|
-
return res?.cli_login_by_pk?.encryptedApiToken || null;
|
|
11027
|
-
}
|
|
11028
|
-
async createCommunityUser() {
|
|
10948
|
+
return comment.body.includes(MOBB_ICON_IMG);
|
|
10949
|
+
}).map((comment) => {
|
|
11029
10950
|
try {
|
|
11030
|
-
|
|
10951
|
+
return scm.deleteGeneralPrComment({ commentId: comment.id });
|
|
11031
10952
|
} catch (e) {
|
|
11032
|
-
|
|
10953
|
+
debug11("delete comment failed %s", e);
|
|
10954
|
+
return Promise.resolve();
|
|
11033
10955
|
}
|
|
10956
|
+
});
|
|
10957
|
+
}
|
|
10958
|
+
async function postIssueComment(params) {
|
|
10959
|
+
const {
|
|
10960
|
+
vulnerabilityReportIssueCodeNode,
|
|
10961
|
+
projectId,
|
|
10962
|
+
analysisId,
|
|
10963
|
+
organizationId,
|
|
10964
|
+
scm,
|
|
10965
|
+
commitSha,
|
|
10966
|
+
pullRequest,
|
|
10967
|
+
scanner,
|
|
10968
|
+
fpDescription
|
|
10969
|
+
} = params;
|
|
10970
|
+
const {
|
|
10971
|
+
path: path17,
|
|
10972
|
+
startLine,
|
|
10973
|
+
vulnerabilityReportIssue: {
|
|
10974
|
+
vulnerabilityReportIssueTags,
|
|
10975
|
+
category,
|
|
10976
|
+
safeIssueType
|
|
10977
|
+
},
|
|
10978
|
+
vulnerabilityReportIssueId
|
|
10979
|
+
} = vulnerabilityReportIssueCodeNode;
|
|
10980
|
+
const irrelevantIssueWithTags = mapCategoryToBucket[category] === "irrelevant" && vulnerabilityReportIssueTags?.length > 0 ? vulnerabilityReportIssueTags : [];
|
|
10981
|
+
const commentRes = await scm.postPrComment({
|
|
10982
|
+
body: `# ${MobbIconMarkdown} Your fix is ready!
|
|
10983
|
+
Refresh the page in order to see the changes.`,
|
|
10984
|
+
pull_number: pullRequest,
|
|
10985
|
+
commit_id: commitSha,
|
|
10986
|
+
path: path17,
|
|
10987
|
+
line: startLine
|
|
10988
|
+
});
|
|
10989
|
+
const commentId = commentRes.data.id;
|
|
10990
|
+
const commentBody = buildIssueCommentBody({
|
|
10991
|
+
issueId: vulnerabilityReportIssueId,
|
|
10992
|
+
issueType: safeIssueType,
|
|
10993
|
+
irrelevantIssueWithTags,
|
|
10994
|
+
commentId,
|
|
10995
|
+
commentUrl: commentRes.data.html_url,
|
|
10996
|
+
scanner,
|
|
10997
|
+
projectId,
|
|
10998
|
+
analysisId,
|
|
10999
|
+
organizationId,
|
|
11000
|
+
fpDescription
|
|
11001
|
+
});
|
|
11002
|
+
return await scm.updatePrComment({
|
|
11003
|
+
body: commentBody,
|
|
11004
|
+
comment_id: commentId
|
|
11005
|
+
});
|
|
11006
|
+
}
|
|
11007
|
+
async function postFixComment(params) {
|
|
11008
|
+
const {
|
|
11009
|
+
vulnerabilityReportIssueCodeNode,
|
|
11010
|
+
projectId,
|
|
11011
|
+
analysisId,
|
|
11012
|
+
organizationId,
|
|
11013
|
+
fixesById,
|
|
11014
|
+
scm,
|
|
11015
|
+
commitSha,
|
|
11016
|
+
pullRequest,
|
|
11017
|
+
scanner
|
|
11018
|
+
} = params;
|
|
11019
|
+
const {
|
|
11020
|
+
path: path17,
|
|
11021
|
+
startLine,
|
|
11022
|
+
vulnerabilityReportIssue: { fixId, vulnerabilityReportIssueTags, category },
|
|
11023
|
+
vulnerabilityReportIssueId
|
|
11024
|
+
} = vulnerabilityReportIssueCodeNode;
|
|
11025
|
+
const irrelevantIssueWithTags = mapCategoryToBucket[category] === "irrelevant" && vulnerabilityReportIssueTags?.length > 0 ? vulnerabilityReportIssueTags : [];
|
|
11026
|
+
const fix = fixesById[fixId];
|
|
11027
|
+
if (!fix || fix.patchAndQuestions.__typename !== "FixData") {
|
|
11028
|
+
throw new Error(`fix ${fixId} not found`);
|
|
11034
11029
|
}
|
|
11035
|
-
|
|
11036
|
-
|
|
11037
|
-
|
|
11038
|
-
|
|
11039
|
-
|
|
11040
|
-
|
|
11041
|
-
|
|
11042
|
-
|
|
11043
|
-
|
|
11044
|
-
|
|
11045
|
-
}
|
|
11046
|
-
|
|
11047
|
-
|
|
11048
|
-
|
|
11030
|
+
const {
|
|
11031
|
+
patchAndQuestions: { patch }
|
|
11032
|
+
} = fix;
|
|
11033
|
+
const commentRes = await scm.postPrComment({
|
|
11034
|
+
body: `# ${MobbIconMarkdown} Your fix is ready!
|
|
11035
|
+
Refresh the page in order to see the changes.`,
|
|
11036
|
+
pull_number: pullRequest,
|
|
11037
|
+
commit_id: commitSha,
|
|
11038
|
+
path: path17,
|
|
11039
|
+
line: startLine
|
|
11040
|
+
});
|
|
11041
|
+
const commentId = commentRes.data.id;
|
|
11042
|
+
const commentBody = buildFixCommentBody({
|
|
11043
|
+
fix,
|
|
11044
|
+
issueId: vulnerabilityReportIssueId,
|
|
11045
|
+
irrelevantIssueWithTags,
|
|
11046
|
+
commentId,
|
|
11047
|
+
commentUrl: commentRes.data.html_url,
|
|
11048
|
+
scanner,
|
|
11049
|
+
fixId,
|
|
11050
|
+
projectId,
|
|
11051
|
+
analysisId,
|
|
11052
|
+
organizationId,
|
|
11053
|
+
patch
|
|
11054
|
+
});
|
|
11055
|
+
return await scm.updatePrComment({
|
|
11056
|
+
body: commentBody,
|
|
11057
|
+
comment_id: commentId
|
|
11058
|
+
});
|
|
11059
|
+
}
|
|
11060
|
+
async function getRelevantVulenrabilitiesFromDiff(params) {
|
|
11061
|
+
const { gqlClient, diff, vulnerabilityReportId } = params;
|
|
11062
|
+
const parsedDiff = parseDiff(diff);
|
|
11063
|
+
const fileHunks = parsedDiff.map((file) => {
|
|
11064
|
+
const fileNumbers = file.chunks.flatMap((chunk) => chunk.changes).filter((change) => change.type === "add").map((_change) => {
|
|
11065
|
+
const change = _change;
|
|
11066
|
+
return change.ln;
|
|
11049
11067
|
});
|
|
11050
|
-
|
|
11051
|
-
|
|
11052
|
-
|
|
11053
|
-
|
|
11068
|
+
const lineAddedRanges = calculateRanges(fileNumbers);
|
|
11069
|
+
const fileFilter = {
|
|
11070
|
+
path: z27.string().parse(file.to),
|
|
11071
|
+
ranges: lineAddedRanges.map(([startLine, endLine]) => ({
|
|
11072
|
+
endLine,
|
|
11073
|
+
startLine
|
|
11074
|
+
}))
|
|
11075
|
+
};
|
|
11076
|
+
return fileFilter;
|
|
11077
|
+
});
|
|
11078
|
+
return gqlClient.getVulByNodesMetadata({
|
|
11079
|
+
hunks: fileHunks,
|
|
11054
11080
|
vulnerabilityReportId
|
|
11055
|
-
})
|
|
11056
|
-
|
|
11057
|
-
|
|
11058
|
-
|
|
11059
|
-
|
|
11060
|
-
|
|
11061
|
-
|
|
11062
|
-
|
|
11063
|
-
|
|
11064
|
-
|
|
11065
|
-
|
|
11066
|
-
|
|
11081
|
+
});
|
|
11082
|
+
}
|
|
11083
|
+
async function getFixesData(params) {
|
|
11084
|
+
const { gqlClient, fixesId } = params;
|
|
11085
|
+
const { fixes } = await gqlClient.getFixes(fixesId);
|
|
11086
|
+
return keyBy(fixes, "id");
|
|
11087
|
+
}
|
|
11088
|
+
async function postAnalysisInsightComment(params) {
|
|
11089
|
+
const { prVulenrabilities, pullRequest, scanner, scm } = params;
|
|
11090
|
+
const scanerString = scannerToFriendlyString[scanner];
|
|
11091
|
+
const {
|
|
11092
|
+
totalPrVulnerabilities,
|
|
11093
|
+
vulnerabilitiesOutsidePr,
|
|
11094
|
+
fixablePrVuls,
|
|
11095
|
+
nonFixablePrVuls
|
|
11096
|
+
} = prVulenrabilities;
|
|
11097
|
+
debug11({
|
|
11098
|
+
fixablePrVuls,
|
|
11099
|
+
nonFixablePrVuls,
|
|
11100
|
+
vulnerabilitiesOutsidePr,
|
|
11101
|
+
totalPrVulnerabilities
|
|
11102
|
+
});
|
|
11103
|
+
if (totalPrVulnerabilities === 0 && vulnerabilitiesOutsidePr === 0) {
|
|
11104
|
+
const body = `Awesome! No vulnerabilities were found by **${scanerString}**`;
|
|
11105
|
+
const noVulsFoundComment = `${noVulnerabilitiesFoundTitle}
|
|
11106
|
+
${body}`;
|
|
11107
|
+
await scm.postGeneralPrComment({
|
|
11108
|
+
body: noVulsFoundComment,
|
|
11109
|
+
prNumber: pullRequest
|
|
11067
11110
|
});
|
|
11068
|
-
|
|
11069
|
-
|
|
11070
|
-
|
|
11111
|
+
return;
|
|
11112
|
+
}
|
|
11113
|
+
if (totalPrVulnerabilities === 0 && vulnerabilitiesOutsidePr > 0) {
|
|
11114
|
+
const body = `Awesome! No vulnerabilities were found by **${scanerString}** in the changes made as part of this PR.`;
|
|
11115
|
+
const body2 = `Please notice there are issues in this repo that are unrelated to this PR.`;
|
|
11116
|
+
const noVulsFoundComment = `${noVulnerabilitiesFoundTitle}
|
|
11117
|
+
${body}
|
|
11118
|
+
${body2}`;
|
|
11119
|
+
await scm.postGeneralPrComment({
|
|
11120
|
+
body: noVulsFoundComment,
|
|
11121
|
+
prNumber: pullRequest
|
|
11071
11122
|
});
|
|
11072
|
-
|
|
11073
|
-
getVulByNodesMetadataRes
|
|
11074
|
-
);
|
|
11075
|
-
const uniqueVulByNodesMetadata = parsedGetVulByNodesMetadataRes.vulnerabilityReportIssueCodeNodes.reduce((acc, vulnerabilityReportIssueCodeNode) => {
|
|
11076
|
-
if (acc[vulnerabilityReportIssueCodeNode.vulnerabilityReportIssueId]) {
|
|
11077
|
-
return acc;
|
|
11078
|
-
}
|
|
11079
|
-
return {
|
|
11080
|
-
...acc,
|
|
11081
|
-
[vulnerabilityReportIssueCodeNode.vulnerabilityReportIssueId]: vulnerabilityReportIssueCodeNode
|
|
11082
|
-
};
|
|
11083
|
-
}, {});
|
|
11084
|
-
const nonFixablePrVuls = parsedGetVulByNodesMetadataRes.nonFixablePrVuls.aggregate.count;
|
|
11085
|
-
const fixablePrVuls = parsedGetVulByNodesMetadataRes.fixablePrVuls.aggregate.count;
|
|
11086
|
-
const totalScanVulnerabilities = parsedGetVulByNodesMetadataRes.totalScanVulnerabilities.aggregate.count;
|
|
11087
|
-
const vulnerabilitiesOutsidePr = totalScanVulnerabilities - nonFixablePrVuls - fixablePrVuls;
|
|
11088
|
-
const totalPrVulnerabilities = nonFixablePrVuls + fixablePrVuls;
|
|
11089
|
-
const irrelevantVulnerabilityReportIssues = parsedGetVulByNodesMetadataRes.irrelevantVulnerabilityReportIssue?.[0]?.vulnerabilityReportIssues ?? [];
|
|
11090
|
-
return {
|
|
11091
|
-
vulnerabilityReportIssueCodeNodes: Object.values(
|
|
11092
|
-
uniqueVulByNodesMetadata
|
|
11093
|
-
),
|
|
11094
|
-
nonFixablePrVuls,
|
|
11095
|
-
fixablePrVuls,
|
|
11096
|
-
totalScanVulnerabilities,
|
|
11097
|
-
vulnerabilitiesOutsidePr,
|
|
11098
|
-
totalPrVulnerabilities,
|
|
11099
|
-
irrelevantVulnerabilityReportIssues
|
|
11100
|
-
};
|
|
11123
|
+
return;
|
|
11101
11124
|
}
|
|
11102
|
-
|
|
11103
|
-
|
|
11104
|
-
|
|
11105
|
-
|
|
11106
|
-
|
|
11107
|
-
|
|
11108
|
-
|
|
11109
|
-
|
|
11110
|
-
|
|
11111
|
-
const res = await this._clientSdk.DigestVulnerabilityReport({
|
|
11112
|
-
fixReportId,
|
|
11113
|
-
vulnerabilityReportFileName: shouldScan ? void 0 : REPORT_DEFAULT_FILE_NAME,
|
|
11114
|
-
projectId,
|
|
11115
|
-
scanSource,
|
|
11116
|
-
repoUrl,
|
|
11117
|
-
reference,
|
|
11118
|
-
sha
|
|
11125
|
+
if (fixablePrVuls === 0 && nonFixablePrVuls > 0) {
|
|
11126
|
+
const title = `# ${MobbIconMarkdown} We couldn't fix the issues detected by **${scanerString}**`;
|
|
11127
|
+
const body = `Mobb Fixer gets better and better every day, but unfortunately your current issues aren't supported yet.`;
|
|
11128
|
+
const noFixableVulsComment = `${title}
|
|
11129
|
+
${body}
|
|
11130
|
+
${contactUsMarkdown}`;
|
|
11131
|
+
await scm.postGeneralPrComment({
|
|
11132
|
+
body: noFixableVulsComment,
|
|
11133
|
+
prNumber: pullRequest
|
|
11119
11134
|
});
|
|
11120
|
-
|
|
11121
|
-
throw new Error("Digesting vulnerability report failed");
|
|
11122
|
-
}
|
|
11123
|
-
return res.digestVulnerabilityReport;
|
|
11135
|
+
return;
|
|
11124
11136
|
}
|
|
11125
|
-
|
|
11126
|
-
const {
|
|
11127
|
-
|
|
11128
|
-
|
|
11129
|
-
|
|
11130
|
-
|
|
11131
|
-
|
|
11132
|
-
|
|
11133
|
-
|
|
11134
|
-
pullRequest
|
|
11135
|
-
} = params;
|
|
11136
|
-
return await this._clientSdk.SubmitVulnerabilityReport({
|
|
11137
|
-
fixReportId,
|
|
11138
|
-
repoUrl,
|
|
11139
|
-
reference,
|
|
11140
|
-
vulnerabilityReportFileName,
|
|
11141
|
-
projectId,
|
|
11142
|
-
pullRequest,
|
|
11143
|
-
sha: sha || "",
|
|
11144
|
-
experimentalEnabled: !!experimentalEnabled,
|
|
11145
|
-
scanSource: params.scanSource,
|
|
11146
|
-
scanContext: ScanContext.BUGSY
|
|
11137
|
+
if (fixablePrVuls < nonFixablePrVuls && fixablePrVuls > 0) {
|
|
11138
|
+
const title = `# ${MobbIconMarkdown} We couldn't fix some of the issues detected by **${scanerString}**`;
|
|
11139
|
+
const body = "Mobb Fixer gets better and better every day, but unfortunately your current issues aren't supported yet.";
|
|
11140
|
+
const fixableVulsComment = `${title}
|
|
11141
|
+
${body}
|
|
11142
|
+
${contactUsMarkdown}`;
|
|
11143
|
+
await scm.postGeneralPrComment({
|
|
11144
|
+
body: fixableVulsComment,
|
|
11145
|
+
prNumber: pullRequest
|
|
11147
11146
|
});
|
|
11147
|
+
return;
|
|
11148
11148
|
}
|
|
11149
|
-
|
|
11150
|
-
|
|
11151
|
-
|
|
11149
|
+
}
|
|
11150
|
+
|
|
11151
|
+
// src/features/analysis/add_fix_comments_for_pr/add_fix_comments_for_pr.ts
|
|
11152
|
+
var debug12 = Debug11("mobbdev:handle-finished-analysis");
|
|
11153
|
+
async function addFixCommentsForPr({
|
|
11154
|
+
analysisId,
|
|
11155
|
+
scm: _scm,
|
|
11156
|
+
gqlClient,
|
|
11157
|
+
scanner
|
|
11158
|
+
}) {
|
|
11159
|
+
if (!(_scm instanceof GithubSCMLib)) {
|
|
11160
|
+
return;
|
|
11152
11161
|
}
|
|
11153
|
-
|
|
11154
|
-
|
|
11155
|
-
|
|
11156
|
-
|
|
11157
|
-
|
|
11158
|
-
|
|
11159
|
-
|
|
11160
|
-
|
|
11161
|
-
|
|
11162
|
+
const scm = _scm;
|
|
11163
|
+
const getAnalysisRes = await gqlClient.getAnalysis(analysisId);
|
|
11164
|
+
debug12("getAnalysis %o", getAnalysisRes);
|
|
11165
|
+
const {
|
|
11166
|
+
vulnerabilityReport: {
|
|
11167
|
+
projectId,
|
|
11168
|
+
project: {
|
|
11169
|
+
organizationId,
|
|
11170
|
+
organization: { ghFixerNoFixComments }
|
|
11171
|
+
}
|
|
11162
11172
|
}
|
|
11163
|
-
|
|
11164
|
-
|
|
11165
|
-
|
|
11166
|
-
} while (!FINAL_STATES.includes(
|
|
11167
|
-
lastState
|
|
11168
|
-
// wait for final the state of the fix report
|
|
11169
|
-
) && attempts-- > 0);
|
|
11170
|
-
return lastState;
|
|
11171
|
-
}
|
|
11172
|
-
async getVulnerabilityReportPaths(vulnerabilityReportId) {
|
|
11173
|
-
const res = await this._clientSdk.GetVulnerabilityReportPaths({
|
|
11174
|
-
vulnerabilityReportId
|
|
11175
|
-
});
|
|
11176
|
-
return res.vulnerability_report_path.map((p) => p.path);
|
|
11173
|
+
} = getAnalysisRes;
|
|
11174
|
+
if (!getAnalysisRes.repo?.commitSha || !getAnalysisRes.repo.pullRequest) {
|
|
11175
|
+
throw new Error("repo not found");
|
|
11177
11176
|
}
|
|
11178
|
-
|
|
11179
|
-
|
|
11180
|
-
|
|
11181
|
-
|
|
11182
|
-
|
|
11183
|
-
|
|
11184
|
-
|
|
11185
|
-
|
|
11186
|
-
|
|
11187
|
-
|
|
11177
|
+
const { commitSha, pullRequest } = getAnalysisRes.repo;
|
|
11178
|
+
const diff = await scm.getPrDiff({ pull_number: pullRequest });
|
|
11179
|
+
const prVulenrabilities = await getRelevantVulenrabilitiesFromDiff({
|
|
11180
|
+
diff,
|
|
11181
|
+
gqlClient,
|
|
11182
|
+
vulnerabilityReportId: getAnalysisRes.vulnerabilityReportId
|
|
11183
|
+
});
|
|
11184
|
+
const {
|
|
11185
|
+
vulnerabilityReportIssueCodeNodes,
|
|
11186
|
+
irrelevantVulnerabilityReportIssues
|
|
11187
|
+
} = prVulenrabilities;
|
|
11188
|
+
const fixesId = vulnerabilityReportIssueCodeNodes.map(
|
|
11189
|
+
({ vulnerabilityReportIssue: { fixId } }) => fixId
|
|
11190
|
+
);
|
|
11191
|
+
const fixesById = await getFixesData({ fixesId, gqlClient });
|
|
11192
|
+
const [comments, generalPrComments] = await Promise.all([
|
|
11193
|
+
scm.getPrComments({ pull_number: pullRequest }),
|
|
11194
|
+
scm.getGeneralPrComments({ prNumber: pullRequest })
|
|
11195
|
+
]);
|
|
11196
|
+
await Promise.all([
|
|
11197
|
+
...deleteAllPreviousComments({ comments, scm }),
|
|
11198
|
+
...deleteAllPreviousGeneralPrComments({ generalPrComments, scm })
|
|
11199
|
+
]);
|
|
11200
|
+
await Promise.all(
|
|
11201
|
+
[
|
|
11202
|
+
...prVulenrabilities.vulnerabilityReportIssueCodeNodes.map(
|
|
11203
|
+
(vulnerabilityReportIssueCodeNode) => {
|
|
11204
|
+
return postFixComment({
|
|
11205
|
+
vulnerabilityReportIssueCodeNode,
|
|
11206
|
+
projectId,
|
|
11207
|
+
analysisId,
|
|
11208
|
+
organizationId,
|
|
11209
|
+
fixesById,
|
|
11210
|
+
scm,
|
|
11211
|
+
pullRequest,
|
|
11212
|
+
scanner,
|
|
11213
|
+
commitSha
|
|
11214
|
+
});
|
|
11215
|
+
}
|
|
11216
|
+
),
|
|
11217
|
+
...irrelevantVulnerabilityReportIssues.map(
|
|
11218
|
+
async (vulnerabilityReportIssue) => {
|
|
11219
|
+
let fpDescription = null;
|
|
11220
|
+
if (vulnerabilityReportIssue.fpId) {
|
|
11221
|
+
const fpRes = await gqlClient.getFalsePositive({
|
|
11222
|
+
fpId: vulnerabilityReportIssue.fpId
|
|
11223
|
+
});
|
|
11224
|
+
const parsedFpRes = await FalsePositivePartsZ.parseAsync(
|
|
11225
|
+
fpRes?.getFalsePositive
|
|
11226
|
+
);
|
|
11227
|
+
const { description, contextString } = getParsedFalsePositiveMessage(parsedFpRes);
|
|
11228
|
+
fpDescription = contextString ? `${description}
|
|
11229
|
+
|
|
11230
|
+
${contextString}` : description;
|
|
11231
|
+
}
|
|
11232
|
+
return await Promise.all(
|
|
11233
|
+
vulnerabilityReportIssue.codeNodes.map(
|
|
11234
|
+
async (vulnerabilityReportIssueCodeNode) => {
|
|
11235
|
+
return await postIssueComment({
|
|
11236
|
+
vulnerabilityReportIssueCodeNode: {
|
|
11237
|
+
path: vulnerabilityReportIssueCodeNode.path,
|
|
11238
|
+
startLine: vulnerabilityReportIssueCodeNode.startLine,
|
|
11239
|
+
vulnerabilityReportIssue: {
|
|
11240
|
+
fixId: "",
|
|
11241
|
+
safeIssueType: vulnerabilityReportIssue.safeIssueType,
|
|
11242
|
+
vulnerabilityReportIssueTags: vulnerabilityReportIssue.vulnerabilityReportIssueTags,
|
|
11243
|
+
category: vulnerabilityReportIssue.category
|
|
11244
|
+
},
|
|
11245
|
+
vulnerabilityReportIssueId: vulnerabilityReportIssue.id
|
|
11246
|
+
},
|
|
11247
|
+
projectId,
|
|
11248
|
+
analysisId,
|
|
11249
|
+
organizationId,
|
|
11250
|
+
fixesById,
|
|
11251
|
+
scm,
|
|
11252
|
+
pullRequest,
|
|
11253
|
+
scanner,
|
|
11254
|
+
commitSha,
|
|
11255
|
+
fpDescription
|
|
11256
|
+
});
|
|
11257
|
+
}
|
|
11258
|
+
)
|
|
11188
11259
|
);
|
|
11260
|
+
}
|
|
11261
|
+
),
|
|
11262
|
+
!ghFixerNoFixComments && postAnalysisInsightComment({
|
|
11263
|
+
prVulenrabilities,
|
|
11264
|
+
pullRequest,
|
|
11265
|
+
scanner,
|
|
11266
|
+
scm
|
|
11267
|
+
})
|
|
11268
|
+
].filter(Boolean)
|
|
11269
|
+
);
|
|
11270
|
+
}
|
|
11271
|
+
|
|
11272
|
+
// src/features/analysis/auto_pr_handler.ts
|
|
11273
|
+
import Debug12 from "debug";
|
|
11274
|
+
var debug13 = Debug12("mobbdev:handleAutoPr");
|
|
11275
|
+
async function handleAutoPr(params) {
|
|
11276
|
+
const {
|
|
11277
|
+
gqlClient,
|
|
11278
|
+
analysisId,
|
|
11279
|
+
commitDirectly,
|
|
11280
|
+
prId,
|
|
11281
|
+
createSpinner: createSpinner5,
|
|
11282
|
+
createOnePr
|
|
11283
|
+
} = params;
|
|
11284
|
+
const createAutoPrSpinner = createSpinner5(
|
|
11285
|
+
"\u{1F504} Waiting for the analysis to finish before initiating automatic pull request creation"
|
|
11286
|
+
).start();
|
|
11287
|
+
return await gqlClient.subscribeToAnalysis({
|
|
11288
|
+
subscribeToAnalysisParams: {
|
|
11289
|
+
analysisId
|
|
11290
|
+
},
|
|
11291
|
+
callback: async (analysisId2) => {
|
|
11292
|
+
const autoPrAnalysisRes = await gqlClient.autoPrAnalysis({
|
|
11293
|
+
analysisId: analysisId2,
|
|
11294
|
+
commitDirectly,
|
|
11295
|
+
prId,
|
|
11296
|
+
prStrategy: createOnePr ? "CONDENSE" /* Condense */ : "SPREAD" /* Spread */
|
|
11297
|
+
});
|
|
11298
|
+
debug13("auto pr analysis res %o", autoPrAnalysisRes);
|
|
11299
|
+
if (autoPrAnalysisRes.autoPrAnalysis?.__typename === "AutoPrError") {
|
|
11300
|
+
createAutoPrSpinner.error({
|
|
11301
|
+
text: `\u{1F504} Automatic pull request failed - ${autoPrAnalysisRes.autoPrAnalysis.error}`
|
|
11302
|
+
});
|
|
11303
|
+
return;
|
|
11304
|
+
}
|
|
11305
|
+
if (autoPrAnalysisRes.autoPrAnalysis?.__typename === "AutoPrSuccess") {
|
|
11306
|
+
const { appliedAutoPrIssueTypes } = autoPrAnalysisRes.autoPrAnalysis;
|
|
11307
|
+
if (appliedAutoPrIssueTypes.length === 0) {
|
|
11308
|
+
createAutoPrSpinner.success({
|
|
11309
|
+
text: "\u{1F504} Automatic pull request did not find any new fixes to open a pull request for"
|
|
11310
|
+
});
|
|
11189
11311
|
return;
|
|
11190
11312
|
}
|
|
11191
|
-
|
|
11192
|
-
|
|
11193
|
-
|
|
11194
|
-
}
|
|
11195
|
-
},
|
|
11196
|
-
this._auth.type === "apiKey" ? {
|
|
11197
|
-
apiKey: this._auth.apiKey,
|
|
11198
|
-
type: "apiKey",
|
|
11199
|
-
timeoutInMs: params.timeoutInMs
|
|
11200
|
-
} : {
|
|
11201
|
-
token: this._auth.token,
|
|
11202
|
-
type: "token",
|
|
11203
|
-
timeoutInMs: params.timeoutInMs
|
|
11313
|
+
createAutoPrSpinner.success({
|
|
11314
|
+
text: `\u{1F504} Automatic pull request creation initiated successfully for the following issue types: ${appliedAutoPrIssueTypes}`
|
|
11315
|
+
});
|
|
11204
11316
|
}
|
|
11205
|
-
|
|
11206
|
-
|
|
11207
|
-
|
|
11208
|
-
|
|
11209
|
-
|
|
11210
|
-
|
|
11211
|
-
|
|
11212
|
-
|
|
11213
|
-
|
|
11214
|
-
|
|
11215
|
-
|
|
11216
|
-
|
|
11217
|
-
|
|
11218
|
-
|
|
11317
|
+
},
|
|
11318
|
+
callbackStates: ["Finished" /* Finished */]
|
|
11319
|
+
});
|
|
11320
|
+
}
|
|
11321
|
+
|
|
11322
|
+
// src/features/analysis/git.ts
|
|
11323
|
+
init_GitService();
|
|
11324
|
+
import Debug13 from "debug";
|
|
11325
|
+
var debug14 = Debug13("mobbdev:git");
|
|
11326
|
+
async function getGitInfo(srcDirPath) {
|
|
11327
|
+
debug14("getting git info for %s", srcDirPath);
|
|
11328
|
+
const gitService = new GitService(srcDirPath);
|
|
11329
|
+
try {
|
|
11330
|
+
const validationResult = await gitService.validateRepository();
|
|
11331
|
+
if (!validationResult.isValid) {
|
|
11332
|
+
debug14("folder is not a git repo");
|
|
11333
|
+
return {
|
|
11334
|
+
success: false,
|
|
11335
|
+
hash: void 0,
|
|
11336
|
+
reference: void 0,
|
|
11337
|
+
repoUrl: void 0
|
|
11338
|
+
};
|
|
11219
11339
|
}
|
|
11220
|
-
|
|
11221
|
-
|
|
11222
|
-
|
|
11223
|
-
|
|
11224
|
-
|
|
11225
|
-
|
|
11226
|
-
|
|
11227
|
-
|
|
11228
|
-
|
|
11229
|
-
|
|
11230
|
-
|
|
11231
|
-
|
|
11232
|
-
|
|
11233
|
-
}
|
|
11234
|
-
|
|
11235
|
-
async getFixes(fixIds) {
|
|
11236
|
-
const res = await this._clientSdk.getFixes({
|
|
11237
|
-
filters: { id: { _in: fixIds } }
|
|
11238
|
-
});
|
|
11239
|
-
return res;
|
|
11240
|
-
}
|
|
11241
|
-
async validateRepoUrl(args) {
|
|
11242
|
-
return this._clientSdk.validateRepoUrl(args);
|
|
11243
|
-
}
|
|
11244
|
-
async getReferenceData(args) {
|
|
11245
|
-
return this._clientSdk.gitReference(args);
|
|
11246
|
-
}
|
|
11247
|
-
async getFalsePositive(args) {
|
|
11248
|
-
return this._clientSdk.getFalsePositive(args);
|
|
11340
|
+
const gitInfo2 = await gitService.getGitInfo();
|
|
11341
|
+
return {
|
|
11342
|
+
success: true,
|
|
11343
|
+
...gitInfo2
|
|
11344
|
+
};
|
|
11345
|
+
} catch (e) {
|
|
11346
|
+
if (e instanceof Error) {
|
|
11347
|
+
debug14("failed to run git %o", e);
|
|
11348
|
+
if (e.message.includes(" spawn ")) {
|
|
11349
|
+
debug14("git cli not installed");
|
|
11350
|
+
} else {
|
|
11351
|
+
throw e;
|
|
11352
|
+
}
|
|
11353
|
+
}
|
|
11354
|
+
throw e;
|
|
11249
11355
|
}
|
|
11250
|
-
}
|
|
11356
|
+
}
|
|
11251
11357
|
|
|
11252
11358
|
// src/features/analysis/pack.ts
|
|
11253
11359
|
init_configs();
|
|
11254
11360
|
import fs8 from "fs";
|
|
11255
11361
|
import path7 from "path";
|
|
11256
11362
|
import AdmZip from "adm-zip";
|
|
11257
|
-
import
|
|
11363
|
+
import Debug14 from "debug";
|
|
11258
11364
|
import { globby } from "globby";
|
|
11259
11365
|
import { isBinary as isBinary2 } from "istextorbinary";
|
|
11260
11366
|
import { simpleGit as simpleGit2 } from "simple-git";
|
|
11261
11367
|
import { parseStringPromise } from "xml2js";
|
|
11262
11368
|
import { z as z28 } from "zod";
|
|
11263
|
-
var
|
|
11369
|
+
var debug15 = Debug14("mobbdev:pack");
|
|
11264
11370
|
var FPR_SOURCE_CODE_FILE_MAPPING_SCHEMA = z28.object({
|
|
11265
11371
|
properties: z28.object({
|
|
11266
11372
|
entry: z28.array(
|
|
@@ -11282,7 +11388,7 @@ function getManifestFilesSuffixes() {
|
|
|
11282
11388
|
return ["package.json", "pom.xml"];
|
|
11283
11389
|
}
|
|
11284
11390
|
async function pack(srcDirPath, vulnFiles, isIncludeAllFiles = false) {
|
|
11285
|
-
|
|
11391
|
+
debug15("pack folder %s", srcDirPath);
|
|
11286
11392
|
let git = void 0;
|
|
11287
11393
|
try {
|
|
11288
11394
|
git = simpleGit2({
|
|
@@ -11292,13 +11398,13 @@ async function pack(srcDirPath, vulnFiles, isIncludeAllFiles = false) {
|
|
|
11292
11398
|
});
|
|
11293
11399
|
await git.status();
|
|
11294
11400
|
} catch (e) {
|
|
11295
|
-
|
|
11401
|
+
debug15("failed to run git %o", e);
|
|
11296
11402
|
git = void 0;
|
|
11297
11403
|
if (e instanceof Error) {
|
|
11298
11404
|
if (e.message.includes(" spawn ")) {
|
|
11299
|
-
|
|
11405
|
+
debug15("git cli not installed");
|
|
11300
11406
|
} else if (e.message.includes("not a git repository")) {
|
|
11301
|
-
|
|
11407
|
+
debug15("folder is not a git repo");
|
|
11302
11408
|
} else {
|
|
11303
11409
|
throw e;
|
|
11304
11410
|
}
|
|
@@ -11313,9 +11419,9 @@ async function pack(srcDirPath, vulnFiles, isIncludeAllFiles = false) {
|
|
|
11313
11419
|
followSymbolicLinks: false,
|
|
11314
11420
|
dot: true
|
|
11315
11421
|
});
|
|
11316
|
-
|
|
11422
|
+
debug15("files found %d", filepaths.length);
|
|
11317
11423
|
const zip = new AdmZip();
|
|
11318
|
-
|
|
11424
|
+
debug15("compressing files");
|
|
11319
11425
|
for (const filepath of filepaths) {
|
|
11320
11426
|
const absFilepath = path7.join(srcDirPath, filepath.toString());
|
|
11321
11427
|
if (!isIncludeAllFiles) {
|
|
@@ -11324,26 +11430,26 @@ async function pack(srcDirPath, vulnFiles, isIncludeAllFiles = false) {
|
|
|
11324
11430
|
absFilepath.toString().replaceAll(path7.win32.sep, path7.posix.sep),
|
|
11325
11431
|
vulnFiles
|
|
11326
11432
|
)) {
|
|
11327
|
-
|
|
11433
|
+
debug15("ignoring %s because it is not a vulnerability file", filepath);
|
|
11328
11434
|
continue;
|
|
11329
11435
|
}
|
|
11330
11436
|
}
|
|
11331
11437
|
if (fs8.lstatSync(absFilepath).size > MCP_MAX_FILE_SIZE) {
|
|
11332
|
-
|
|
11438
|
+
debug15("ignoring %s because the size is > 5MB", filepath);
|
|
11333
11439
|
continue;
|
|
11334
11440
|
}
|
|
11335
11441
|
const data = git ? await git.showBuffer([`HEAD:./${filepath}`]) : fs8.readFileSync(absFilepath);
|
|
11336
11442
|
if (isBinary2(null, data)) {
|
|
11337
|
-
|
|
11443
|
+
debug15("ignoring %s because is seems to be a binary file", filepath);
|
|
11338
11444
|
continue;
|
|
11339
11445
|
}
|
|
11340
11446
|
zip.addFile(filepath.toString(), data);
|
|
11341
11447
|
}
|
|
11342
|
-
|
|
11448
|
+
debug15("get zip file buffer");
|
|
11343
11449
|
return zip.toBuffer();
|
|
11344
11450
|
}
|
|
11345
11451
|
async function repackFpr(fprPath) {
|
|
11346
|
-
|
|
11452
|
+
debug15("repack fpr file %s", fprPath);
|
|
11347
11453
|
const zipIn = new AdmZip(fprPath);
|
|
11348
11454
|
const zipOut = new AdmZip();
|
|
11349
11455
|
const mappingXML = zipIn.readAsText("src-archive/index.xml", "utf-8");
|
|
@@ -11358,7 +11464,7 @@ async function repackFpr(fprPath) {
|
|
|
11358
11464
|
zipOut.addFile(realPath, buf);
|
|
11359
11465
|
}
|
|
11360
11466
|
}
|
|
11361
|
-
|
|
11467
|
+
debug15("get repacked zip file buffer");
|
|
11362
11468
|
return zipOut.toBuffer();
|
|
11363
11469
|
}
|
|
11364
11470
|
|
|
@@ -11428,8 +11534,8 @@ async function snykArticlePrompt() {
|
|
|
11428
11534
|
|
|
11429
11535
|
// src/features/analysis/scanners/checkmarx.ts
|
|
11430
11536
|
import { createRequire } from "module";
|
|
11431
|
-
import
|
|
11432
|
-
import
|
|
11537
|
+
import chalk4 from "chalk";
|
|
11538
|
+
import Debug16 from "debug";
|
|
11433
11539
|
import { existsSync } from "fs";
|
|
11434
11540
|
import { createSpinner as createSpinner2 } from "nanospinner";
|
|
11435
11541
|
import { type } from "os";
|
|
@@ -11441,7 +11547,7 @@ var cxOperatingSystemSupportMessage = `Your operating system does not support ch
|
|
|
11441
11547
|
|
|
11442
11548
|
// src/utils/child_process.ts
|
|
11443
11549
|
import cp from "child_process";
|
|
11444
|
-
import
|
|
11550
|
+
import Debug15 from "debug";
|
|
11445
11551
|
import * as process2 from "process";
|
|
11446
11552
|
function createFork({ args, processPath, name }, options) {
|
|
11447
11553
|
const child = cp.fork(processPath, args, {
|
|
@@ -11459,7 +11565,7 @@ function createSpawn({ args, processPath, name, cwd }, options) {
|
|
|
11459
11565
|
return createChildProcess({ childProcess: child, name }, options);
|
|
11460
11566
|
}
|
|
11461
11567
|
function createChildProcess({ childProcess, name }, options) {
|
|
11462
|
-
const debug21 =
|
|
11568
|
+
const debug21 = Debug15(`mobbdev:${name}`);
|
|
11463
11569
|
const { display } = options;
|
|
11464
11570
|
return new Promise((resolve, reject) => {
|
|
11465
11571
|
let out = "";
|
|
@@ -11489,7 +11595,7 @@ function createChildProcess({ childProcess, name }, options) {
|
|
|
11489
11595
|
}
|
|
11490
11596
|
|
|
11491
11597
|
// src/features/analysis/scanners/checkmarx.ts
|
|
11492
|
-
var
|
|
11598
|
+
var debug16 = Debug16("mobbdev:checkmarx");
|
|
11493
11599
|
var moduleUrl;
|
|
11494
11600
|
if (typeof __filename !== "undefined") {
|
|
11495
11601
|
moduleUrl = __filename;
|
|
@@ -11548,14 +11654,14 @@ function validateCheckmarxInstallation() {
|
|
|
11548
11654
|
existsSync(getCheckmarxPath());
|
|
11549
11655
|
}
|
|
11550
11656
|
async function forkCheckmarx(args, { display }) {
|
|
11551
|
-
|
|
11657
|
+
debug16("fork checkmarx with args %o %s", args.join(" "), display);
|
|
11552
11658
|
return createSpawn(
|
|
11553
11659
|
{ args, processPath: getCheckmarxPath(), name: "checkmarx" },
|
|
11554
11660
|
{ display }
|
|
11555
11661
|
);
|
|
11556
11662
|
}
|
|
11557
11663
|
async function getCheckmarxReport({ reportPath, repositoryRoot, branch, projectName }, { skipPrompts = false }) {
|
|
11558
|
-
|
|
11664
|
+
debug16("get checkmarx report start %s %s", reportPath, repositoryRoot);
|
|
11559
11665
|
const { code: loginCode } = await forkCheckmarx(VALIDATE_COMMAND, {
|
|
11560
11666
|
display: false
|
|
11561
11667
|
});
|
|
@@ -11594,7 +11700,7 @@ async function throwCheckmarxConfigError() {
|
|
|
11594
11700
|
await createSpinner2("\u{1F513} Checkmarx is not configued correctly").start().error();
|
|
11595
11701
|
throw new CliError(
|
|
11596
11702
|
`Checkmarx is not configued correctly
|
|
11597
|
-
you can configure it by using the ${
|
|
11703
|
+
you can configure it by using the ${chalk4.bold(
|
|
11598
11704
|
"cx configure"
|
|
11599
11705
|
)} command`
|
|
11600
11706
|
);
|
|
@@ -11602,8 +11708,8 @@ async function throwCheckmarxConfigError() {
|
|
|
11602
11708
|
async function validateCheckamxCredentials() {
|
|
11603
11709
|
console.log(`
|
|
11604
11710
|
Here's a suggestion for checkmarx configuation:
|
|
11605
|
-
${
|
|
11606
|
-
${
|
|
11711
|
+
${chalk4.bold("AST Base URI:")} https://ast.checkmarx.net
|
|
11712
|
+
${chalk4.bold("AST Base Auth URI (IAM):")} https://iam.checkmarx.net
|
|
11607
11713
|
`);
|
|
11608
11714
|
await forkCheckmarx(CONFIGURE_COMMAND, { display: true });
|
|
11609
11715
|
const { code: loginCode } = await forkCheckmarx(VALIDATE_COMMAND, {
|
|
@@ -11622,11 +11728,11 @@ async function validateCheckamxCredentials() {
|
|
|
11622
11728
|
|
|
11623
11729
|
// src/features/analysis/scanners/snyk.ts
|
|
11624
11730
|
import { createRequire as createRequire2 } from "module";
|
|
11625
|
-
import
|
|
11626
|
-
import
|
|
11731
|
+
import chalk5 from "chalk";
|
|
11732
|
+
import Debug17 from "debug";
|
|
11627
11733
|
import { createSpinner as createSpinner3 } from "nanospinner";
|
|
11628
|
-
import
|
|
11629
|
-
var
|
|
11734
|
+
import open2 from "open";
|
|
11735
|
+
var debug17 = Debug17("mobbdev:snyk");
|
|
11630
11736
|
var moduleUrl2;
|
|
11631
11737
|
if (typeof __filename !== "undefined") {
|
|
11632
11738
|
moduleUrl2 = __filename;
|
|
@@ -11648,15 +11754,15 @@ if (typeof __filename !== "undefined") {
|
|
|
11648
11754
|
var costumeRequire2 = createRequire2(moduleUrl2);
|
|
11649
11755
|
var SNYK_PATH = costumeRequire2.resolve("snyk/bin/snyk");
|
|
11650
11756
|
var SNYK_ARTICLE_URL = "https://docs.snyk.io/scan-using-snyk/snyk-code/configure-snyk-code#enable-snyk-code";
|
|
11651
|
-
|
|
11757
|
+
debug17("snyk executable path %s", SNYK_PATH);
|
|
11652
11758
|
async function forkSnyk(args, { display }) {
|
|
11653
|
-
|
|
11759
|
+
debug17("fork snyk with args %o %s", args, display);
|
|
11654
11760
|
return createFork({ args, processPath: SNYK_PATH, name: "snyk" }, { display });
|
|
11655
11761
|
}
|
|
11656
11762
|
async function getSnykReport(reportPath, repoRoot, { skipPrompts = false }) {
|
|
11657
|
-
|
|
11658
|
-
const
|
|
11659
|
-
const { message: configMessage } =
|
|
11763
|
+
debug17("get snyk report start %s %s", reportPath, repoRoot);
|
|
11764
|
+
const config6 = await forkSnyk(["config"], { display: false });
|
|
11765
|
+
const { message: configMessage } = config6;
|
|
11660
11766
|
if (!configMessage.includes("api: ")) {
|
|
11661
11767
|
const snykLoginSpinner = createSpinner3().start();
|
|
11662
11768
|
if (!skipPrompts) {
|
|
@@ -11668,7 +11774,7 @@ async function getSnykReport(reportPath, repoRoot, { skipPrompts = false }) {
|
|
|
11668
11774
|
snykLoginSpinner.update({
|
|
11669
11775
|
text: "\u{1F513} Waiting for Snyk login to complete"
|
|
11670
11776
|
});
|
|
11671
|
-
|
|
11777
|
+
debug17("no token in the config %s", config6);
|
|
11672
11778
|
await forkSnyk(["auth"], { display: true });
|
|
11673
11779
|
snykLoginSpinner.success({ text: "\u{1F513} Login to Snyk Successful" });
|
|
11674
11780
|
}
|
|
@@ -11678,16 +11784,16 @@ async function getSnykReport(reportPath, repoRoot, { skipPrompts = false }) {
|
|
|
11678
11784
|
{ display: true }
|
|
11679
11785
|
);
|
|
11680
11786
|
if (scanOutput.includes("Snyk Code is not supported for org")) {
|
|
11681
|
-
|
|
11787
|
+
debug17("snyk code is not enabled %s", scanOutput);
|
|
11682
11788
|
snykSpinner.error({ text: "\u{1F50D} Snyk configuration needed" });
|
|
11683
11789
|
const answer = await snykArticlePrompt();
|
|
11684
|
-
|
|
11790
|
+
debug17("answer %s", answer);
|
|
11685
11791
|
if (answer) {
|
|
11686
|
-
|
|
11687
|
-
await
|
|
11792
|
+
debug17("opening the browser");
|
|
11793
|
+
await open2(SNYK_ARTICLE_URL);
|
|
11688
11794
|
}
|
|
11689
11795
|
console.log(
|
|
11690
|
-
|
|
11796
|
+
chalk5.bgBlue(
|
|
11691
11797
|
"\nPlease enable Snyk Code in your Snyk account and try again."
|
|
11692
11798
|
)
|
|
11693
11799
|
);
|
|
@@ -11698,9 +11804,9 @@ async function getSnykReport(reportPath, repoRoot, { skipPrompts = false }) {
|
|
|
11698
11804
|
}
|
|
11699
11805
|
|
|
11700
11806
|
// src/features/analysis/upload-file.ts
|
|
11701
|
-
import
|
|
11807
|
+
import Debug18 from "debug";
|
|
11702
11808
|
import fetch3, { File, fileFrom, FormData } from "node-fetch";
|
|
11703
|
-
var
|
|
11809
|
+
var debug18 = Debug18("mobbdev:upload-file");
|
|
11704
11810
|
async function uploadFile({
|
|
11705
11811
|
file,
|
|
11706
11812
|
url,
|
|
@@ -11713,9 +11819,9 @@ async function uploadFile({
|
|
|
11713
11819
|
logInfo2(`FileUpload: upload file start ${url}`);
|
|
11714
11820
|
logInfo2(`FileUpload: upload fields`, uploadFields);
|
|
11715
11821
|
logInfo2(`FileUpload: upload key ${uploadKey}`);
|
|
11716
|
-
|
|
11717
|
-
|
|
11718
|
-
|
|
11822
|
+
debug18("upload file start %s", url);
|
|
11823
|
+
debug18("upload fields %o", uploadFields);
|
|
11824
|
+
debug18("upload key %s", uploadKey);
|
|
11719
11825
|
const form = new FormData();
|
|
11720
11826
|
Object.entries(uploadFields).forEach(([key, value]) => {
|
|
11721
11827
|
form.append(key, value);
|
|
@@ -11724,11 +11830,11 @@ async function uploadFile({
|
|
|
11724
11830
|
form.append("key", uploadKey);
|
|
11725
11831
|
}
|
|
11726
11832
|
if (typeof file === "string") {
|
|
11727
|
-
|
|
11833
|
+
debug18("upload file from path %s", file);
|
|
11728
11834
|
logInfo2(`FileUpload: upload file from path ${file}`);
|
|
11729
11835
|
form.append("file", await fileFrom(file));
|
|
11730
11836
|
} else {
|
|
11731
|
-
|
|
11837
|
+
debug18("upload file from buffer");
|
|
11732
11838
|
logInfo2(`FileUpload: upload file from buffer`);
|
|
11733
11839
|
form.append("file", new File([new Uint8Array(file)], "file"));
|
|
11734
11840
|
}
|
|
@@ -11739,11 +11845,11 @@ async function uploadFile({
|
|
|
11739
11845
|
agent
|
|
11740
11846
|
});
|
|
11741
11847
|
if (!response.ok) {
|
|
11742
|
-
|
|
11848
|
+
debug18("error from S3 %s %s", response.body, response.status);
|
|
11743
11849
|
logInfo2(`FileUpload: error from S3 ${response.body} ${response.status}`);
|
|
11744
11850
|
throw new Error(`Failed to upload the file: ${response.status}`);
|
|
11745
11851
|
}
|
|
11746
|
-
|
|
11852
|
+
debug18("upload file done");
|
|
11747
11853
|
logInfo2(`FileUpload: upload file done`);
|
|
11748
11854
|
}
|
|
11749
11855
|
|
|
@@ -11778,9 +11884,9 @@ async function downloadRepo({
|
|
|
11778
11884
|
}) {
|
|
11779
11885
|
const { createSpinner: createSpinner5 } = Spinner2({ ci });
|
|
11780
11886
|
const repoSpinner = createSpinner5("\u{1F4BE} Downloading Repo").start();
|
|
11781
|
-
|
|
11887
|
+
debug19("download repo %s %s %s", repoUrl, dirname);
|
|
11782
11888
|
const zipFilePath = path9.join(dirname, "repo.zip");
|
|
11783
|
-
|
|
11889
|
+
debug19("download URL: %s auth headers: %o", downloadUrl, authHeaders);
|
|
11784
11890
|
const response = await fetch4(downloadUrl, {
|
|
11785
11891
|
method: "GET",
|
|
11786
11892
|
headers: {
|
|
@@ -11788,9 +11894,9 @@ async function downloadRepo({
|
|
|
11788
11894
|
}
|
|
11789
11895
|
});
|
|
11790
11896
|
if (!response.ok) {
|
|
11791
|
-
|
|
11897
|
+
debug19("SCM zipball request failed %s %s", response.body, response.status);
|
|
11792
11898
|
repoSpinner.error({ text: "\u{1F4BE} Repo download failed" });
|
|
11793
|
-
throw new Error(`Can't access ${
|
|
11899
|
+
throw new Error(`Can't access ${chalk6.bold(repoUrl)}`);
|
|
11794
11900
|
}
|
|
11795
11901
|
const fileWriterStream = fs9.createWriteStream(zipFilePath);
|
|
11796
11902
|
if (!response.body) {
|
|
@@ -11802,7 +11908,7 @@ async function downloadRepo({
|
|
|
11802
11908
|
if (!repoRoot) {
|
|
11803
11909
|
throw new Error("Repo root not found");
|
|
11804
11910
|
}
|
|
11805
|
-
|
|
11911
|
+
debug19("repo root %s", repoRoot);
|
|
11806
11912
|
repoSpinner.success({ text: "\u{1F4BE} Repo downloaded successfully" });
|
|
11807
11913
|
return path9.join(dirname, repoRoot);
|
|
11808
11914
|
}
|
|
@@ -11811,9 +11917,9 @@ var getReportUrl = ({
|
|
|
11811
11917
|
projectId,
|
|
11812
11918
|
fixReportId
|
|
11813
11919
|
}) => `${WEB_APP_URL}/organization/${organizationId}/project/${projectId}/report/${fixReportId}`;
|
|
11814
|
-
var
|
|
11815
|
-
var
|
|
11816
|
-
|
|
11920
|
+
var debug19 = Debug19("mobbdev:index");
|
|
11921
|
+
var config3 = new Configstore2(packageJson.name, { apiToken: "" });
|
|
11922
|
+
debug19("config %o", config3);
|
|
11817
11923
|
async function runAnalysis(params, options) {
|
|
11818
11924
|
const tmpObj = tmp2.dirSync({
|
|
11819
11925
|
unsafeCleanup: true
|
|
@@ -11958,11 +12064,11 @@ async function _scan(params, { skipPrompts = false } = {}) {
|
|
|
11958
12064
|
commitDirectly,
|
|
11959
12065
|
pullRequest
|
|
11960
12066
|
} = params;
|
|
11961
|
-
|
|
12067
|
+
debug19("start %s %s", dirname, repo);
|
|
11962
12068
|
const { createSpinner: createSpinner5 } = Spinner2({ ci });
|
|
11963
12069
|
skipPrompts = skipPrompts || ci;
|
|
11964
12070
|
let gqlClient = new GQLClient({
|
|
11965
|
-
apiKey: apiKey ??
|
|
12071
|
+
apiKey: apiKey ?? config3.get("apiToken") ?? "",
|
|
11966
12072
|
type: "apiKey"
|
|
11967
12073
|
});
|
|
11968
12074
|
gqlClient = await handleMobbLogin({
|
|
@@ -12032,8 +12138,8 @@ async function _scan(params, { skipPrompts = false } = {}) {
|
|
|
12032
12138
|
);
|
|
12033
12139
|
}
|
|
12034
12140
|
const { sha } = getReferenceDataRes.gitReference;
|
|
12035
|
-
|
|
12036
|
-
|
|
12141
|
+
debug19("project id %s", projectId);
|
|
12142
|
+
debug19("default branch %s", reference);
|
|
12037
12143
|
if (command === "scan") {
|
|
12038
12144
|
reportPath = await getReport(
|
|
12039
12145
|
{
|
|
@@ -12131,11 +12237,11 @@ async function _scan(params, { skipPrompts = false } = {}) {
|
|
|
12131
12237
|
fixReportId: reportUploadInfo.fixReportId
|
|
12132
12238
|
});
|
|
12133
12239
|
!ci && console.log("You can access the analysis at: \n");
|
|
12134
|
-
console.log(
|
|
12240
|
+
console.log(chalk6.bold(reportUrl));
|
|
12135
12241
|
!skipPrompts && await mobbAnalysisPrompt();
|
|
12136
|
-
!ci &&
|
|
12242
|
+
!ci && open3(reportUrl);
|
|
12137
12243
|
!ci && console.log(
|
|
12138
|
-
|
|
12244
|
+
chalk6.bgBlue("\n\n My work here is done for now, see you soon! \u{1F575}\uFE0F\u200D\u2642\uFE0F ")
|
|
12139
12245
|
);
|
|
12140
12246
|
}
|
|
12141
12247
|
async function handleScmIntegration(oldToken, scmAuthUrl2, repoUrl) {
|
|
@@ -12152,7 +12258,7 @@ async function _scan(params, { skipPrompts = false } = {}) {
|
|
|
12152
12258
|
console.log(
|
|
12153
12259
|
`If the page does not open automatically, kindly access it through ${scmAuthUrl2}.`
|
|
12154
12260
|
);
|
|
12155
|
-
await
|
|
12261
|
+
await open3(scmAuthUrl2);
|
|
12156
12262
|
for (let i = 0; i < LOGIN_MAX_WAIT / LOGIN_CHECK_DELAY; i++) {
|
|
12157
12263
|
const userInfo = await gqlClient.getUserInfo();
|
|
12158
12264
|
if (!userInfo) {
|
|
@@ -12410,7 +12516,6 @@ async function waitForAnaysisAndReviewPr({
|
|
|
12410
12516
|
}
|
|
12411
12517
|
|
|
12412
12518
|
// src/commands/index.ts
|
|
12413
|
-
var debug19 = Debug19("mobbdev:commands");
|
|
12414
12519
|
async function review(params, { skipPrompts = true } = {}) {
|
|
12415
12520
|
const {
|
|
12416
12521
|
repo,
|
|
@@ -12479,11 +12584,11 @@ async function analyze({
|
|
|
12479
12584
|
{ skipPrompts }
|
|
12480
12585
|
);
|
|
12481
12586
|
}
|
|
12482
|
-
var
|
|
12587
|
+
var config4 = new Configstore3(packageJson.name, { apiToken: "" });
|
|
12483
12588
|
async function addScmToken(addScmTokenOptions) {
|
|
12484
12589
|
const { apiKey, token, organization, scmType, url, refreshToken, ci } = addScmTokenOptions;
|
|
12485
12590
|
let gqlClient = new GQLClient({
|
|
12486
|
-
apiKey: apiKey ??
|
|
12591
|
+
apiKey: apiKey ?? config4.get("apiToken") ?? "",
|
|
12487
12592
|
type: "apiKey"
|
|
12488
12593
|
});
|
|
12489
12594
|
gqlClient = await handleMobbLogin({
|
|
@@ -12537,99 +12642,6 @@ async function showWelcomeMessage(skipPrompts = false) {
|
|
|
12537
12642
|
skipPrompts ? await sleep(100) : await sleep(2e3);
|
|
12538
12643
|
welcome.stop();
|
|
12539
12644
|
}
|
|
12540
|
-
var LOGIN_MAX_WAIT = 10 * 60 * 1e3;
|
|
12541
|
-
var LOGIN_CHECK_DELAY = 5 * 1e3;
|
|
12542
|
-
var webLoginUrl = `${WEB_APP_URL}/cli-login`;
|
|
12543
|
-
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, ${chalk6.bgBlue(
|
|
12544
|
-
"press any key to continue"
|
|
12545
|
-
)};`;
|
|
12546
|
-
async function handleMobbLogin({
|
|
12547
|
-
inGqlClient,
|
|
12548
|
-
apiKey,
|
|
12549
|
-
skipPrompts
|
|
12550
|
-
}) {
|
|
12551
|
-
const { createSpinner: createSpinner5 } = Spinner({ ci: skipPrompts });
|
|
12552
|
-
const isConnected = await inGqlClient.verifyApiConnection();
|
|
12553
|
-
if (!isConnected) {
|
|
12554
|
-
createSpinner5().start().error({
|
|
12555
|
-
text: "\u{1F513} Connection to Mobb: failed to connect to the Mobb server"
|
|
12556
|
-
});
|
|
12557
|
-
throw new CliError(
|
|
12558
|
-
"Connection to Mobb: failed to connect to the Mobb server"
|
|
12559
|
-
);
|
|
12560
|
-
}
|
|
12561
|
-
createSpinner5().start().success({
|
|
12562
|
-
text: `\u{1F513} Connection to Mobb: succeeded`
|
|
12563
|
-
});
|
|
12564
|
-
const userVerify = await inGqlClient.validateUserToken();
|
|
12565
|
-
if (userVerify) {
|
|
12566
|
-
createSpinner5().start().success({
|
|
12567
|
-
text: `\u{1F513} Login to Mobb succeeded. ${typeof userVerify === "string" ? `Logged in as ${userVerify}` : ""}`
|
|
12568
|
-
});
|
|
12569
|
-
return inGqlClient;
|
|
12570
|
-
} else if (apiKey) {
|
|
12571
|
-
createSpinner5().start().error({
|
|
12572
|
-
text: "\u{1F513} Login to Mobb failed: The provided API key does not match any configured API key on the system"
|
|
12573
|
-
});
|
|
12574
|
-
throw new CliError(
|
|
12575
|
-
"Login to Mobb failed: The provided API key does not match any configured API key on the system"
|
|
12576
|
-
);
|
|
12577
|
-
}
|
|
12578
|
-
const loginSpinner = createSpinner5().start();
|
|
12579
|
-
if (!skipPrompts) {
|
|
12580
|
-
loginSpinner.update({ text: MOBB_LOGIN_REQUIRED_MSG });
|
|
12581
|
-
await keypress();
|
|
12582
|
-
}
|
|
12583
|
-
loginSpinner.update({
|
|
12584
|
-
text: "\u{1F513} Waiting for Mobb login..."
|
|
12585
|
-
});
|
|
12586
|
-
const { publicKey, privateKey } = crypto.generateKeyPairSync("rsa", {
|
|
12587
|
-
modulusLength: 2048
|
|
12588
|
-
});
|
|
12589
|
-
const loginId = await inGqlClient.createCliLogin({
|
|
12590
|
-
publicKey: publicKey.export({ format: "pem", type: "pkcs1" }).toString()
|
|
12591
|
-
});
|
|
12592
|
-
const browserUrl = `${webLoginUrl}/${loginId}?hostname=${os.hostname()}`;
|
|
12593
|
-
!skipPrompts && console.log(
|
|
12594
|
-
`If the page does not open automatically, kindly access it through ${browserUrl}.`
|
|
12595
|
-
);
|
|
12596
|
-
await open3(browserUrl);
|
|
12597
|
-
let newApiToken = null;
|
|
12598
|
-
for (let i = 0; i < LOGIN_MAX_WAIT / LOGIN_CHECK_DELAY; i++) {
|
|
12599
|
-
const encryptedApiToken = await inGqlClient.getEncryptedApiToken({
|
|
12600
|
-
loginId
|
|
12601
|
-
});
|
|
12602
|
-
loginSpinner.spin();
|
|
12603
|
-
if (encryptedApiToken) {
|
|
12604
|
-
debug19("encrypted API token received %s", encryptedApiToken);
|
|
12605
|
-
newApiToken = crypto.privateDecrypt(privateKey, Buffer.from(encryptedApiToken, "base64")).toString("utf-8");
|
|
12606
|
-
debug19("API token decrypted");
|
|
12607
|
-
break;
|
|
12608
|
-
}
|
|
12609
|
-
await sleep(LOGIN_CHECK_DELAY);
|
|
12610
|
-
}
|
|
12611
|
-
if (!newApiToken) {
|
|
12612
|
-
loginSpinner.error({
|
|
12613
|
-
text: "Login timeout error"
|
|
12614
|
-
});
|
|
12615
|
-
throw new CliError();
|
|
12616
|
-
}
|
|
12617
|
-
const newGqlClient = new GQLClient({ apiKey: newApiToken, type: "apiKey" });
|
|
12618
|
-
const loginSuccess = await newGqlClient.validateUserToken();
|
|
12619
|
-
if (loginSuccess) {
|
|
12620
|
-
debug19(`set api token ${newApiToken}`);
|
|
12621
|
-
config3.set("apiToken", newApiToken);
|
|
12622
|
-
loginSpinner.success({
|
|
12623
|
-
text: `\u{1F513} Login to Mobb successful! ${typeof loginSpinner === "string" ? `Logged in as ${loginSuccess}` : ""}`
|
|
12624
|
-
});
|
|
12625
|
-
} else {
|
|
12626
|
-
loginSpinner.error({
|
|
12627
|
-
text: "Something went wrong, API token is invalid."
|
|
12628
|
-
});
|
|
12629
|
-
throw new CliError();
|
|
12630
|
-
}
|
|
12631
|
-
return newGqlClient;
|
|
12632
|
-
}
|
|
12633
12645
|
|
|
12634
12646
|
// src/args/validation.ts
|
|
12635
12647
|
import chalk7 from "chalk";
|
|
@@ -12771,7 +12783,7 @@ import {
|
|
|
12771
12783
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
12772
12784
|
|
|
12773
12785
|
// src/mcp/Logger.ts
|
|
12774
|
-
import
|
|
12786
|
+
import Configstore4 from "configstore";
|
|
12775
12787
|
|
|
12776
12788
|
// src/mcp/services/WorkspaceService.ts
|
|
12777
12789
|
var WorkspaceService = class {
|
|
@@ -12857,7 +12869,7 @@ var Logger = class {
|
|
|
12857
12869
|
__publicField(this, "lastKnownPath", null);
|
|
12858
12870
|
this.host = WorkspaceService.getHost();
|
|
12859
12871
|
this.unknownPathSuffix = Math.floor(1e3 + Math.random() * 9e3).toString();
|
|
12860
|
-
this.mobbConfigStore = new
|
|
12872
|
+
this.mobbConfigStore = new Configstore4("mobb-logs", {});
|
|
12861
12873
|
this.mobbConfigStore.set("version", packageJson.version);
|
|
12862
12874
|
}
|
|
12863
12875
|
/**
|
|
@@ -13055,7 +13067,7 @@ var GetLatestReportByRepoUrlResponseSchema = z31.object({
|
|
|
13055
13067
|
});
|
|
13056
13068
|
|
|
13057
13069
|
// src/mcp/services/ConfigStoreService.ts
|
|
13058
|
-
import
|
|
13070
|
+
import Configstore5 from "configstore";
|
|
13059
13071
|
init_configs();
|
|
13060
13072
|
function createConfigStore(defaultValues = { apiToken: "" }) {
|
|
13061
13073
|
const API_URL2 = process.env["API_URL"] || MCP_DEFAULT_API_URL;
|
|
@@ -13067,7 +13079,7 @@ function createConfigStore(defaultValues = { apiToken: "" }) {
|
|
|
13067
13079
|
domain = API_URL2.replace(/^https?:\/\//, "").replace(/\/.*$/, "").replace(/:\d+$/, "");
|
|
13068
13080
|
}
|
|
13069
13081
|
const sanitizedDomain = domain.replace(/\./g, "_");
|
|
13070
|
-
return new
|
|
13082
|
+
return new Configstore5(
|
|
13071
13083
|
`${packageJson.name}-${sanitizedDomain}`,
|
|
13072
13084
|
defaultValues
|
|
13073
13085
|
);
|
|
@@ -13884,34 +13896,34 @@ var readConfigFile = (filePath) => {
|
|
|
13884
13896
|
return null;
|
|
13885
13897
|
}
|
|
13886
13898
|
};
|
|
13887
|
-
var mergeConfigIntoResult = (
|
|
13888
|
-
if (
|
|
13899
|
+
var mergeConfigIntoResult = (config6, mergedConfig) => {
|
|
13900
|
+
if (config6?.projects) {
|
|
13889
13901
|
const allMcpServers = {};
|
|
13890
|
-
for (const projectPath in
|
|
13891
|
-
const project =
|
|
13902
|
+
for (const projectPath in config6.projects) {
|
|
13903
|
+
const project = config6.projects[projectPath];
|
|
13892
13904
|
if (project?.mcpServers) {
|
|
13893
13905
|
Object.assign(allMcpServers, project.mcpServers);
|
|
13894
13906
|
}
|
|
13895
13907
|
}
|
|
13896
13908
|
mergedConfig.mcpServers = { ...mergedConfig.mcpServers, ...allMcpServers };
|
|
13897
13909
|
}
|
|
13898
|
-
if (
|
|
13910
|
+
if (config6?.mcpServers) {
|
|
13899
13911
|
mergedConfig.mcpServers = {
|
|
13900
13912
|
...mergedConfig.mcpServers,
|
|
13901
|
-
...
|
|
13913
|
+
...config6.mcpServers
|
|
13902
13914
|
};
|
|
13903
13915
|
}
|
|
13904
|
-
if (
|
|
13905
|
-
mergedConfig.servers = { ...mergedConfig.servers, ...
|
|
13916
|
+
if (config6?.servers) {
|
|
13917
|
+
mergedConfig.servers = { ...mergedConfig.servers, ...config6.servers };
|
|
13906
13918
|
}
|
|
13907
13919
|
};
|
|
13908
13920
|
var readMCPConfig = (hostName) => {
|
|
13909
13921
|
const configPaths = getMCPConfigPaths(hostName);
|
|
13910
13922
|
const mergedConfig = {};
|
|
13911
13923
|
for (const configPath of configPaths) {
|
|
13912
|
-
const
|
|
13913
|
-
if (
|
|
13914
|
-
mergeConfigIntoResult(
|
|
13924
|
+
const config6 = readConfigFile(configPath);
|
|
13925
|
+
if (config6) {
|
|
13926
|
+
mergeConfigIntoResult(config6, mergedConfig);
|
|
13915
13927
|
}
|
|
13916
13928
|
}
|
|
13917
13929
|
return Object.keys(mergedConfig).length > 0 ? mergedConfig : null;
|
|
@@ -14038,10 +14050,10 @@ var getHostInfo = (additionalMcpList) => {
|
|
|
14038
14050
|
if (cfg) allConfigs[ide] = cfg;
|
|
14039
14051
|
}
|
|
14040
14052
|
for (const additionalPath of uniqueAdditionalPaths) {
|
|
14041
|
-
const
|
|
14042
|
-
if (!
|
|
14053
|
+
const config6 = readConfigFile(additionalPath);
|
|
14054
|
+
if (!config6) continue;
|
|
14043
14055
|
const mergedConfig = {};
|
|
14044
|
-
mergeConfigIntoResult(
|
|
14056
|
+
mergeConfigIntoResult(config6, mergedConfig);
|
|
14045
14057
|
if (Object.keys(mergedConfig).length > 0) {
|
|
14046
14058
|
allConfigs["system"] = mergedConfig;
|
|
14047
14059
|
}
|
|
@@ -14109,7 +14121,7 @@ var getHostInfo = (additionalMcpList) => {
|
|
|
14109
14121
|
}
|
|
14110
14122
|
}
|
|
14111
14123
|
for (const { ide, name, command, isRunning } of servers) {
|
|
14112
|
-
const
|
|
14124
|
+
const config6 = allConfigs[ide] || null;
|
|
14113
14125
|
const ideName = ide.charAt(0).toUpperCase() + ide.slice(1) || "Unknown";
|
|
14114
14126
|
let ideVersion = "Unknown";
|
|
14115
14127
|
const platform = os3.platform();
|
|
@@ -14126,8 +14138,8 @@ var getHostInfo = (additionalMcpList) => {
|
|
|
14126
14138
|
}
|
|
14127
14139
|
}
|
|
14128
14140
|
let mcpConfigObj = {};
|
|
14129
|
-
if (
|
|
14130
|
-
const allServers =
|
|
14141
|
+
if (config6) {
|
|
14142
|
+
const allServers = config6.mcpServers || config6.servers || {};
|
|
14131
14143
|
if (name in allServers && allServers[name]) {
|
|
14132
14144
|
mcpConfigObj = allServers[name];
|
|
14133
14145
|
}
|
|
@@ -14436,7 +14448,7 @@ var ToolRegistry = class {
|
|
|
14436
14448
|
|
|
14437
14449
|
// src/mcp/core/McpServer.ts
|
|
14438
14450
|
var McpServer = class {
|
|
14439
|
-
constructor(
|
|
14451
|
+
constructor(config6, govOrgId = "") {
|
|
14440
14452
|
__publicField(this, "server");
|
|
14441
14453
|
__publicField(this, "toolRegistry");
|
|
14442
14454
|
__publicField(this, "isEventHandlersSetup", false);
|
|
@@ -14449,8 +14461,8 @@ var McpServer = class {
|
|
|
14449
14461
|
this.mcpUsageService = govOrgId ? new McpUsageService(govOrgId) : null;
|
|
14450
14462
|
this.server = new Server(
|
|
14451
14463
|
{
|
|
14452
|
-
name:
|
|
14453
|
-
version:
|
|
14464
|
+
name: config6.name,
|
|
14465
|
+
version: config6.version
|
|
14454
14466
|
},
|
|
14455
14467
|
{
|
|
14456
14468
|
capabilities: {
|
|
@@ -14464,7 +14476,7 @@ var McpServer = class {
|
|
|
14464
14476
|
this.setupParentProcessMonitoring();
|
|
14465
14477
|
logInfo("MCP server instance created");
|
|
14466
14478
|
logDebug("MCP server instance config", {
|
|
14467
|
-
config:
|
|
14479
|
+
config: config6,
|
|
14468
14480
|
parentPid: this.parentPid
|
|
14469
14481
|
});
|
|
14470
14482
|
}
|
|
@@ -19169,6 +19181,7 @@ async function addScmTokenHandler(args) {
|
|
|
19169
19181
|
import fsPromises3 from "fs/promises";
|
|
19170
19182
|
import path16 from "path";
|
|
19171
19183
|
import chalk10 from "chalk";
|
|
19184
|
+
import Configstore6 from "configstore";
|
|
19172
19185
|
import { withFile } from "tmp-promise";
|
|
19173
19186
|
import z38 from "zod";
|
|
19174
19187
|
var PromptItemZ = z38.object({
|
|
@@ -19223,6 +19236,18 @@ function uploadAiBlameBuilder(args) {
|
|
|
19223
19236
|
describe: chalk10.bold("Tool/IDE name(s) (optional, one per session)")
|
|
19224
19237
|
}).strict();
|
|
19225
19238
|
}
|
|
19239
|
+
var config5 = new Configstore6(packageJson.name, { apiToken: "" });
|
|
19240
|
+
async function getAuthenticatedGQLClientForIdeExtension() {
|
|
19241
|
+
let gqlClient = new GQLClient({
|
|
19242
|
+
apiKey: config5.get("apiToken") ?? "",
|
|
19243
|
+
type: "apiKey"
|
|
19244
|
+
});
|
|
19245
|
+
gqlClient = await handleMobbLogin({
|
|
19246
|
+
inGqlClient: gqlClient,
|
|
19247
|
+
skipPrompts: true
|
|
19248
|
+
});
|
|
19249
|
+
return gqlClient;
|
|
19250
|
+
}
|
|
19226
19251
|
async function uploadAiBlameHandler(args, exitOnError = true) {
|
|
19227
19252
|
const prompts = args.prompt || [];
|
|
19228
19253
|
const inferences = args.inference || [];
|
|
@@ -19263,8 +19288,10 @@ async function uploadAiBlameHandler(args, exitOnError = true) {
|
|
|
19263
19288
|
toolName: tools[i]
|
|
19264
19289
|
});
|
|
19265
19290
|
}
|
|
19266
|
-
const
|
|
19267
|
-
const initRes = await
|
|
19291
|
+
const authenticatedClient = await getAuthenticatedGQLClientForIdeExtension();
|
|
19292
|
+
const initRes = await authenticatedClient.uploadAIBlameInferencesInitRaw({
|
|
19293
|
+
sessions
|
|
19294
|
+
});
|
|
19268
19295
|
const uploadSessions = initRes.uploadAIBlameInferencesInit?.uploadSessions ?? [];
|
|
19269
19296
|
if (uploadSessions.length !== sessions.length) {
|
|
19270
19297
|
const errorMsg = "Init failed to return expected number of sessions";
|
|
@@ -19302,7 +19329,7 @@ async function uploadAiBlameHandler(args, exitOnError = true) {
|
|
|
19302
19329
|
toolName: s.toolName
|
|
19303
19330
|
};
|
|
19304
19331
|
});
|
|
19305
|
-
const finRes = await
|
|
19332
|
+
const finRes = await authenticatedClient.finalizeAIBlameInferencesUploadRaw({
|
|
19306
19333
|
sessions: finalizeSessions
|
|
19307
19334
|
});
|
|
19308
19335
|
const status = finRes?.finalizeAIBlameInferencesUpload?.status;
|