mobbdev 1.2.27 → 1.2.29
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.mjs +118 -88
- package/dist/index.mjs +214 -220
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -3908,7 +3908,7 @@ ${rootContent}`;
|
|
|
3908
3908
|
});
|
|
3909
3909
|
|
|
3910
3910
|
// src/index.ts
|
|
3911
|
-
import
|
|
3911
|
+
import Debug20 from "debug";
|
|
3912
3912
|
import { hideBin } from "yargs/helpers";
|
|
3913
3913
|
|
|
3914
3914
|
// src/args/yargs.ts
|
|
@@ -6244,6 +6244,23 @@ function parseLinearTicket(url, name) {
|
|
|
6244
6244
|
const title = titleSlug.replace(/-/g, " ");
|
|
6245
6245
|
return { name, title, url };
|
|
6246
6246
|
}
|
|
6247
|
+
function isLinearBotComment(comment) {
|
|
6248
|
+
if (!comment.author) return false;
|
|
6249
|
+
const login = comment.author.login.toLowerCase();
|
|
6250
|
+
if (login === "linear[bot]" || login === "linear") return true;
|
|
6251
|
+
if (comment.author.type === "Bot" && login.includes("linear")) return true;
|
|
6252
|
+
return false;
|
|
6253
|
+
}
|
|
6254
|
+
function extractLinearTicketsFromComments(comments) {
|
|
6255
|
+
const tickets = [];
|
|
6256
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6257
|
+
for (const comment of comments) {
|
|
6258
|
+
if (isLinearBotComment(comment)) {
|
|
6259
|
+
tickets.push(...extractLinearTicketsFromBody(comment.body || "", seen));
|
|
6260
|
+
}
|
|
6261
|
+
}
|
|
6262
|
+
return tickets;
|
|
6263
|
+
}
|
|
6247
6264
|
var userNamePattern = /^(https?:\/\/)([^@]+@)?([^/]+\/.+)$/;
|
|
6248
6265
|
var sshPattern = /^git@([\w.-]+):([\w./-]+)$/;
|
|
6249
6266
|
function normalizeUrl(repoUrl) {
|
|
@@ -7127,11 +7144,11 @@ var SCMLib = class {
|
|
|
7127
7144
|
}
|
|
7128
7145
|
/**
|
|
7129
7146
|
* Extract Linear ticket links from PR/MR comments.
|
|
7130
|
-
*
|
|
7147
|
+
* Uses shared isLinearBotComment() for unified bot detection across all providers.
|
|
7131
7148
|
* Public so it can be reused by backend services.
|
|
7132
7149
|
*/
|
|
7133
|
-
extractLinearTicketsFromComments(
|
|
7134
|
-
return
|
|
7150
|
+
extractLinearTicketsFromComments(comments) {
|
|
7151
|
+
return extractLinearTicketsFromComments(comments);
|
|
7135
7152
|
}
|
|
7136
7153
|
_validateAccessTokenAndUrl() {
|
|
7137
7154
|
this._validateAccessToken();
|
|
@@ -8832,7 +8849,7 @@ function determinePrStatus(state, isDraft) {
|
|
|
8832
8849
|
return isDraft ? "DRAFT" /* Draft */ : "ACTIVE" /* Active */;
|
|
8833
8850
|
}
|
|
8834
8851
|
}
|
|
8835
|
-
var GithubSCMLib = class
|
|
8852
|
+
var GithubSCMLib = class extends SCMLib {
|
|
8836
8853
|
// we don't always need a url, what's important is that we have an access token
|
|
8837
8854
|
constructor(url, accessToken, scmOrg) {
|
|
8838
8855
|
super(url, accessToken, scmOrg);
|
|
@@ -9304,27 +9321,6 @@ var GithubSCMLib = class _GithubSCMLib extends SCMLib {
|
|
|
9304
9321
|
commentIds
|
|
9305
9322
|
};
|
|
9306
9323
|
}
|
|
9307
|
-
/**
|
|
9308
|
-
* Extract Linear ticket links from pre-fetched comments (pure function, no API calls)
|
|
9309
|
-
* Instance method that overrides base class - can also be called statically for backwards compatibility.
|
|
9310
|
-
*/
|
|
9311
|
-
extractLinearTicketsFromComments(comments) {
|
|
9312
|
-
return _GithubSCMLib._extractLinearTicketsFromCommentsImpl(comments);
|
|
9313
|
-
}
|
|
9314
|
-
/**
|
|
9315
|
-
* Static implementation for backwards compatibility and reuse.
|
|
9316
|
-
* Called by both the instance method and direct static calls.
|
|
9317
|
-
*/
|
|
9318
|
-
static _extractLinearTicketsFromCommentsImpl(comments) {
|
|
9319
|
-
const tickets = [];
|
|
9320
|
-
const seen = /* @__PURE__ */ new Set();
|
|
9321
|
-
for (const comment of comments) {
|
|
9322
|
-
if (comment.author?.login === "linear[bot]" || comment.author?.type === "Bot") {
|
|
9323
|
-
tickets.push(...extractLinearTicketsFromBody(comment.body || "", seen));
|
|
9324
|
-
}
|
|
9325
|
-
}
|
|
9326
|
-
return tickets;
|
|
9327
|
-
}
|
|
9328
9324
|
};
|
|
9329
9325
|
|
|
9330
9326
|
// src/features/analysis/scm/gitlab/gitlab.ts
|
|
@@ -9814,7 +9810,7 @@ async function getGitlabMrDataBatch({
|
|
|
9814
9810
|
const comments = notes.map((note) => ({
|
|
9815
9811
|
author: note.author ? {
|
|
9816
9812
|
login: note.author.username,
|
|
9817
|
-
type: note.author.username.endsWith("[bot]")
|
|
9813
|
+
type: note.author.username.endsWith("[bot]") ? "Bot" : "User"
|
|
9818
9814
|
} : null,
|
|
9819
9815
|
body: note.body
|
|
9820
9816
|
}));
|
|
@@ -10443,23 +10439,6 @@ var GitlabSCMLib = class extends SCMLib {
|
|
|
10443
10439
|
accessToken: this.accessToken
|
|
10444
10440
|
});
|
|
10445
10441
|
}
|
|
10446
|
-
/**
|
|
10447
|
-
* Extract Linear ticket links from pre-fetched comments (pure function, no API calls).
|
|
10448
|
-
* Linear bot uses the same comment format on GitLab as on GitHub.
|
|
10449
|
-
* Bot username may be 'linear' or 'linear[bot]' on GitLab.
|
|
10450
|
-
*/
|
|
10451
|
-
extractLinearTicketsFromComments(comments) {
|
|
10452
|
-
const tickets = [];
|
|
10453
|
-
const seen = /* @__PURE__ */ new Set();
|
|
10454
|
-
for (const comment of comments) {
|
|
10455
|
-
const authorLogin = comment.author?.login?.toLowerCase() || "";
|
|
10456
|
-
const isLinearBot = authorLogin === "linear" || authorLogin === "linear[bot]" || comment.author?.type === "Bot" && authorLogin.includes("linear");
|
|
10457
|
-
if (isLinearBot) {
|
|
10458
|
-
tickets.push(...extractLinearTicketsFromBody(comment.body || "", seen));
|
|
10459
|
-
}
|
|
10460
|
-
}
|
|
10461
|
-
return tickets;
|
|
10462
|
-
}
|
|
10463
10442
|
};
|
|
10464
10443
|
|
|
10465
10444
|
// src/features/analysis/scm/scmFactory.ts
|
|
@@ -11490,7 +11469,7 @@ import path9 from "path";
|
|
|
11490
11469
|
import { env as env2 } from "process";
|
|
11491
11470
|
import { pipeline } from "stream/promises";
|
|
11492
11471
|
import chalk6 from "chalk";
|
|
11493
|
-
import
|
|
11472
|
+
import Debug19 from "debug";
|
|
11494
11473
|
import extract from "extract-zip";
|
|
11495
11474
|
import { createSpinner as createSpinner4 } from "nanospinner";
|
|
11496
11475
|
import fetch4 from "node-fetch";
|
|
@@ -11500,7 +11479,7 @@ import { z as z29 } from "zod";
|
|
|
11500
11479
|
|
|
11501
11480
|
// src/commands/handleMobbLogin.ts
|
|
11502
11481
|
import chalk3 from "chalk";
|
|
11503
|
-
import
|
|
11482
|
+
import Debug7 from "debug";
|
|
11504
11483
|
|
|
11505
11484
|
// src/commands/AuthManager.ts
|
|
11506
11485
|
import crypto from "crypto";
|
|
@@ -11508,10 +11487,8 @@ import os from "os";
|
|
|
11508
11487
|
import open from "open";
|
|
11509
11488
|
|
|
11510
11489
|
// src/features/analysis/graphql/gql.ts
|
|
11511
|
-
import
|
|
11512
|
-
import Debug5 from "debug";
|
|
11490
|
+
import Debug6 from "debug";
|
|
11513
11491
|
import { GraphQLClient } from "graphql-request";
|
|
11514
|
-
import { HttpsProxyAgent } from "https-proxy-agent";
|
|
11515
11492
|
import { v4 as uuidv4 } from "uuid";
|
|
11516
11493
|
|
|
11517
11494
|
// src/mcp/core/Errors.ts
|
|
@@ -11586,6 +11563,71 @@ var _ReportDigestError = class _ReportDigestError extends Error {
|
|
|
11586
11563
|
__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.");
|
|
11587
11564
|
var ReportDigestError = _ReportDigestError;
|
|
11588
11565
|
|
|
11566
|
+
// src/utils/proxy.ts
|
|
11567
|
+
import fetchOrig from "cross-fetch";
|
|
11568
|
+
import Debug5 from "debug";
|
|
11569
|
+
import { HttpsProxyAgent } from "https-proxy-agent";
|
|
11570
|
+
|
|
11571
|
+
// src/utils/url.ts
|
|
11572
|
+
function httpToWsUrl(url) {
|
|
11573
|
+
const parsed = new URL(url);
|
|
11574
|
+
parsed.protocol = parsed.protocol === "https:" ? "wss:" : "ws:";
|
|
11575
|
+
return parsed.toString();
|
|
11576
|
+
}
|
|
11577
|
+
|
|
11578
|
+
// src/utils/proxy.ts
|
|
11579
|
+
var debug6 = Debug5("mobbdev:proxy");
|
|
11580
|
+
function getHttpProxy() {
|
|
11581
|
+
return process.env["HTTPS_PROXY"] || process.env["HTTP_PROXY"] || "";
|
|
11582
|
+
}
|
|
11583
|
+
function getHttpProxyOnly() {
|
|
11584
|
+
return process.env["HTTP_PROXY"] || "";
|
|
11585
|
+
}
|
|
11586
|
+
function getProxyAgent(url) {
|
|
11587
|
+
try {
|
|
11588
|
+
const parsedUrl = new URL(url);
|
|
11589
|
+
const hostname = parsedUrl.hostname.toLowerCase();
|
|
11590
|
+
if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1" || hostname === "[::1]") {
|
|
11591
|
+
debug6("Skipping proxy for localhost URL: %s", url);
|
|
11592
|
+
return void 0;
|
|
11593
|
+
}
|
|
11594
|
+
const noProxy = process.env["NO_PROXY"] || process.env["no_proxy"];
|
|
11595
|
+
if (noProxy) {
|
|
11596
|
+
const noProxyList = noProxy.split(",").map((h) => h.trim().toLowerCase());
|
|
11597
|
+
if (noProxyList.includes(hostname) || noProxyList.includes("*")) {
|
|
11598
|
+
debug6("Skipping proxy due to NO_PROXY for: %s", url);
|
|
11599
|
+
return void 0;
|
|
11600
|
+
}
|
|
11601
|
+
}
|
|
11602
|
+
const isHttp = parsedUrl.protocol === "http:";
|
|
11603
|
+
const isHttps = parsedUrl.protocol === "https:";
|
|
11604
|
+
const proxy = isHttps ? getHttpProxy() : isHttp ? getHttpProxyOnly() : null;
|
|
11605
|
+
if (proxy) {
|
|
11606
|
+
debug6("Using proxy %s", proxy);
|
|
11607
|
+
debug6("Proxy agent %o", proxy);
|
|
11608
|
+
return new HttpsProxyAgent(proxy);
|
|
11609
|
+
}
|
|
11610
|
+
} catch (err) {
|
|
11611
|
+
debug6(`Skipping proxy for ${url}. Reason: ${err.message}`);
|
|
11612
|
+
}
|
|
11613
|
+
return void 0;
|
|
11614
|
+
}
|
|
11615
|
+
var fetchWithProxy = (url, options = {}) => {
|
|
11616
|
+
try {
|
|
11617
|
+
const agent = getProxyAgent(url.toString());
|
|
11618
|
+
if (agent) {
|
|
11619
|
+
return fetchOrig(url, {
|
|
11620
|
+
...options,
|
|
11621
|
+
// @ts-expect-error Node-fetch doesn't type 'agent', but it's valid
|
|
11622
|
+
agent
|
|
11623
|
+
});
|
|
11624
|
+
}
|
|
11625
|
+
} catch (err) {
|
|
11626
|
+
debug6(`Skipping proxy for ${url}. Reason: ${err.message}`);
|
|
11627
|
+
}
|
|
11628
|
+
return fetchOrig(url, options);
|
|
11629
|
+
};
|
|
11630
|
+
|
|
11589
11631
|
// src/utils/subscribe/subscribe.ts
|
|
11590
11632
|
import { createClient } from "graphql-ws";
|
|
11591
11633
|
import WebsocketNode from "isomorphic-ws";
|
|
@@ -11614,11 +11656,11 @@ function getGraphQlHeaders(options) {
|
|
|
11614
11656
|
}
|
|
11615
11657
|
|
|
11616
11658
|
// src/utils/subscribe/subscribe.ts
|
|
11617
|
-
var DEFAULT_API_URL2 = "
|
|
11659
|
+
var DEFAULT_API_URL2 = "wss://api.mobb.ai/v1/graphql";
|
|
11618
11660
|
var SUBSCRIPTION_TIMEOUT_MS = 30 * 60 * 1e3;
|
|
11619
11661
|
function createWSClient(options) {
|
|
11620
|
-
const url = options.url || (process.env["API_URL"]
|
|
11621
|
-
const websocketImpl = options.websocket ||
|
|
11662
|
+
const url = options.url || (process.env["API_URL"] ? httpToWsUrl(process.env["API_URL"]) : DEFAULT_API_URL2);
|
|
11663
|
+
const websocketImpl = options.websocket || WebsocketNode;
|
|
11622
11664
|
const CustomWebSocket = options.proxyAgent ? (
|
|
11623
11665
|
// biome-ignore lint/suspicious/noExplicitAny: Dynamic WebSocket extension requires any cast for cross-platform compatibility
|
|
11624
11666
|
class extends websocketImpl {
|
|
@@ -11782,63 +11824,19 @@ var GetVulByNodesMetadataZ = z25.object({
|
|
|
11782
11824
|
});
|
|
11783
11825
|
|
|
11784
11826
|
// src/features/analysis/graphql/gql.ts
|
|
11785
|
-
var
|
|
11827
|
+
var debug7 = Debug6("mobbdev:gql");
|
|
11786
11828
|
var API_KEY_HEADER_NAME = "x-mobb-key";
|
|
11787
11829
|
var REPORT_STATE_CHECK_DELAY = 5 * 1e3;
|
|
11788
|
-
function getProxyAgent(url) {
|
|
11789
|
-
try {
|
|
11790
|
-
const parsedUrl = new URL(url);
|
|
11791
|
-
const hostname = parsedUrl.hostname.toLowerCase();
|
|
11792
|
-
if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1" || hostname === "[::1]") {
|
|
11793
|
-
debug6("Skipping proxy for localhost URL: %s", url);
|
|
11794
|
-
return void 0;
|
|
11795
|
-
}
|
|
11796
|
-
const noProxy = process.env["NO_PROXY"] || process.env["no_proxy"];
|
|
11797
|
-
if (noProxy) {
|
|
11798
|
-
const noProxyList = noProxy.split(",").map((h) => h.trim().toLowerCase());
|
|
11799
|
-
if (noProxyList.includes(hostname) || noProxyList.includes("*")) {
|
|
11800
|
-
debug6("Skipping proxy due to NO_PROXY for: %s", url);
|
|
11801
|
-
return void 0;
|
|
11802
|
-
}
|
|
11803
|
-
}
|
|
11804
|
-
const isHttp = parsedUrl.protocol === "http:";
|
|
11805
|
-
const isHttps = parsedUrl.protocol === "https:";
|
|
11806
|
-
const proxy = isHttps ? HTTPS_PROXY || HTTP_PROXY : isHttp ? HTTP_PROXY : null;
|
|
11807
|
-
if (proxy) {
|
|
11808
|
-
debug6("Using proxy %s", proxy);
|
|
11809
|
-
debug6("Proxy agent %o", proxy);
|
|
11810
|
-
return new HttpsProxyAgent(proxy);
|
|
11811
|
-
}
|
|
11812
|
-
} catch (err) {
|
|
11813
|
-
debug6(`Skipping proxy for ${url}. Reason: ${err.message}`);
|
|
11814
|
-
}
|
|
11815
|
-
return void 0;
|
|
11816
|
-
}
|
|
11817
|
-
var fetchWithProxy = (url, options = {}) => {
|
|
11818
|
-
try {
|
|
11819
|
-
const agent = getProxyAgent(url.toString());
|
|
11820
|
-
if (agent) {
|
|
11821
|
-
return fetchOrig(url, {
|
|
11822
|
-
...options,
|
|
11823
|
-
// @ts-expect-error Node-fetch doesn't type 'agent', but it's valid
|
|
11824
|
-
agent
|
|
11825
|
-
});
|
|
11826
|
-
}
|
|
11827
|
-
} catch (err) {
|
|
11828
|
-
debug6(`Skipping proxy for ${url}. Reason: ${err.message}`);
|
|
11829
|
-
}
|
|
11830
|
-
return fetchOrig(url, options);
|
|
11831
|
-
};
|
|
11832
11830
|
var GQLClient = class {
|
|
11833
11831
|
constructor(args) {
|
|
11834
11832
|
__publicField(this, "_client");
|
|
11835
11833
|
__publicField(this, "_clientSdk");
|
|
11836
11834
|
__publicField(this, "_apiUrl");
|
|
11837
11835
|
__publicField(this, "_auth");
|
|
11838
|
-
|
|
11836
|
+
debug7(`init with ${args}`);
|
|
11839
11837
|
this._auth = args;
|
|
11840
11838
|
this._apiUrl = args.apiUrl || API_URL;
|
|
11841
|
-
|
|
11839
|
+
debug7(
|
|
11842
11840
|
"GQLClient constructor: resolved apiUrl=%s (from param: %s)",
|
|
11843
11841
|
this._apiUrl,
|
|
11844
11842
|
args.apiUrl || "fallback to API_URL constant"
|
|
@@ -11850,7 +11848,7 @@ var GQLClient = class {
|
|
|
11850
11848
|
fetch: fetchWithProxy,
|
|
11851
11849
|
requestMiddleware: (request) => {
|
|
11852
11850
|
const requestId = uuidv4();
|
|
11853
|
-
|
|
11851
|
+
debug7(
|
|
11854
11852
|
`sending API request with id: ${requestId} and with request: ${request.body}`
|
|
11855
11853
|
);
|
|
11856
11854
|
return {
|
|
@@ -11887,7 +11885,7 @@ var GQLClient = class {
|
|
|
11887
11885
|
await this.getUserInfo();
|
|
11888
11886
|
} catch (e) {
|
|
11889
11887
|
if (e?.toString().startsWith("FetchError")) {
|
|
11890
|
-
|
|
11888
|
+
debug7("verify connection failed %o", e);
|
|
11891
11889
|
return false;
|
|
11892
11890
|
}
|
|
11893
11891
|
}
|
|
@@ -11899,7 +11897,7 @@ var GQLClient = class {
|
|
|
11899
11897
|
try {
|
|
11900
11898
|
info = await this.getUserInfo();
|
|
11901
11899
|
} catch (e) {
|
|
11902
|
-
|
|
11900
|
+
debug7("verify token failed %o", e);
|
|
11903
11901
|
return false;
|
|
11904
11902
|
}
|
|
11905
11903
|
return info?.email || true;
|
|
@@ -11960,7 +11958,7 @@ var GQLClient = class {
|
|
|
11960
11958
|
try {
|
|
11961
11959
|
await this._clientSdk.CreateCommunityUser();
|
|
11962
11960
|
} catch (e) {
|
|
11963
|
-
|
|
11961
|
+
debug7("create community user failed %o", e);
|
|
11964
11962
|
}
|
|
11965
11963
|
}
|
|
11966
11964
|
async updateScmToken(args) {
|
|
@@ -12140,11 +12138,13 @@ var GQLClient = class {
|
|
|
12140
12138
|
this._auth.type === "apiKey" ? {
|
|
12141
12139
|
apiKey: this._auth.apiKey,
|
|
12142
12140
|
type: "apiKey",
|
|
12141
|
+
url: httpToWsUrl(this._apiUrl),
|
|
12143
12142
|
timeoutInMs: params.timeoutInMs,
|
|
12144
12143
|
proxyAgent: getProxyAgent(this._apiUrl)
|
|
12145
12144
|
} : {
|
|
12146
12145
|
token: this._auth.token,
|
|
12147
12146
|
type: "token",
|
|
12147
|
+
url: httpToWsUrl(this._apiUrl),
|
|
12148
12148
|
timeoutInMs: params.timeoutInMs,
|
|
12149
12149
|
proxyAgent: getProxyAgent(this._apiUrl)
|
|
12150
12150
|
}
|
|
@@ -12157,7 +12157,7 @@ var GQLClient = class {
|
|
|
12157
12157
|
const startTime = Date.now();
|
|
12158
12158
|
const maxDuration = timeoutInMs ?? 30 * 60 * 1e3;
|
|
12159
12159
|
const pollingIntervalSec = REPORT_STATE_CHECK_DELAY / 1e3;
|
|
12160
|
-
|
|
12160
|
+
debug7(
|
|
12161
12161
|
`[pollForAnalysisState] Starting polling for analysis ${analysisId}, target states: ${callbackStates.join(", ")}, interval: ${pollingIntervalSec}s`
|
|
12162
12162
|
);
|
|
12163
12163
|
let isPolling = true;
|
|
@@ -12166,7 +12166,7 @@ var GQLClient = class {
|
|
|
12166
12166
|
pollCount++;
|
|
12167
12167
|
const elapsedSec = Math.round((Date.now() - startTime) / 1e3);
|
|
12168
12168
|
if (Date.now() - startTime > maxDuration) {
|
|
12169
|
-
|
|
12169
|
+
debug7(
|
|
12170
12170
|
`[pollForAnalysisState] Timeout expired after ${pollCount} polls (${elapsedSec}s)`
|
|
12171
12171
|
);
|
|
12172
12172
|
throw new ReportDigestError(
|
|
@@ -12174,20 +12174,20 @@ var GQLClient = class {
|
|
|
12174
12174
|
`Analysis timed out after ${Math.round(maxDuration / 6e4)} minutes. Please try again or check the Mobb platform for status.`
|
|
12175
12175
|
);
|
|
12176
12176
|
}
|
|
12177
|
-
|
|
12177
|
+
debug7(
|
|
12178
12178
|
`[pollForAnalysisState] Poll #${pollCount} (elapsed: ${elapsedSec}s) - fetching analysis state...`
|
|
12179
12179
|
);
|
|
12180
12180
|
const analysis = await this.getAnalysis(analysisId);
|
|
12181
|
-
|
|
12181
|
+
debug7(
|
|
12182
12182
|
`[pollForAnalysisState] Poll #${pollCount} - current state: ${analysis.state}`
|
|
12183
12183
|
);
|
|
12184
12184
|
if (!analysis.state || analysis.state === "Failed" /* Failed */) {
|
|
12185
12185
|
const errorMessage = analysis.failReason || `Analysis failed with id: ${analysis.id}`;
|
|
12186
|
-
|
|
12186
|
+
debug7(`[pollForAnalysisState] Analysis failed: ${errorMessage}`);
|
|
12187
12187
|
throw new ReportDigestError(errorMessage, analysis.failReason ?? "");
|
|
12188
12188
|
}
|
|
12189
12189
|
if (callbackStates.includes(analysis.state)) {
|
|
12190
|
-
|
|
12190
|
+
debug7(
|
|
12191
12191
|
`[pollForAnalysisState] Target state reached: ${analysis.state} after ${pollCount} polls (${elapsedSec}s)`
|
|
12192
12192
|
);
|
|
12193
12193
|
await callback(analysis.id);
|
|
@@ -12200,7 +12200,7 @@ var GQLClient = class {
|
|
|
12200
12200
|
}
|
|
12201
12201
|
};
|
|
12202
12202
|
}
|
|
12203
|
-
|
|
12203
|
+
debug7(
|
|
12204
12204
|
`[pollForAnalysisState] State ${analysis.state} not in target states, waiting ${pollingIntervalSec}s before next poll...`
|
|
12205
12205
|
);
|
|
12206
12206
|
await sleep(REPORT_STATE_CHECK_DELAY);
|
|
@@ -12489,7 +12489,7 @@ var AuthManager = class {
|
|
|
12489
12489
|
};
|
|
12490
12490
|
|
|
12491
12491
|
// src/commands/handleMobbLogin.ts
|
|
12492
|
-
var
|
|
12492
|
+
var debug8 = Debug7("mobbdev:commands");
|
|
12493
12493
|
var LOGIN_MAX_WAIT2 = 10 * 60 * 1e3;
|
|
12494
12494
|
var LOGIN_CHECK_DELAY2 = 5 * 1e3;
|
|
12495
12495
|
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(
|
|
@@ -12501,7 +12501,7 @@ async function getAuthenticatedGQLClient({
|
|
|
12501
12501
|
apiUrl,
|
|
12502
12502
|
webAppUrl
|
|
12503
12503
|
}) {
|
|
12504
|
-
|
|
12504
|
+
debug8(
|
|
12505
12505
|
"getAuthenticatedGQLClient called with: apiUrl=%s, webAppUrl=%s",
|
|
12506
12506
|
apiUrl || "undefined",
|
|
12507
12507
|
webAppUrl || "undefined"
|
|
@@ -12524,7 +12524,7 @@ async function handleMobbLogin({
|
|
|
12524
12524
|
webAppUrl,
|
|
12525
12525
|
loginContext
|
|
12526
12526
|
}) {
|
|
12527
|
-
|
|
12527
|
+
debug8(
|
|
12528
12528
|
"handleMobbLogin: resolved URLs - apiUrl=%s (from param: %s), webAppUrl=%s (from param: %s)",
|
|
12529
12529
|
apiUrl || "fallback",
|
|
12530
12530
|
apiUrl || "fallback",
|
|
@@ -12543,7 +12543,7 @@ async function handleMobbLogin({
|
|
|
12543
12543
|
return authManager.getGQLClient();
|
|
12544
12544
|
}
|
|
12545
12545
|
} catch (error) {
|
|
12546
|
-
|
|
12546
|
+
debug8("Authentication check failed:", error);
|
|
12547
12547
|
}
|
|
12548
12548
|
if (apiKey) {
|
|
12549
12549
|
createSpinner5().start().error({
|
|
@@ -12590,10 +12590,10 @@ async function handleMobbLogin({
|
|
|
12590
12590
|
}
|
|
12591
12591
|
|
|
12592
12592
|
// src/features/analysis/add_fix_comments_for_pr/add_fix_comments_for_pr.ts
|
|
12593
|
-
import
|
|
12593
|
+
import Debug11 from "debug";
|
|
12594
12594
|
|
|
12595
12595
|
// src/features/analysis/add_fix_comments_for_pr/utils/utils.ts
|
|
12596
|
-
import
|
|
12596
|
+
import Debug10 from "debug";
|
|
12597
12597
|
import parseDiff from "parse-diff";
|
|
12598
12598
|
import { z as z27 } from "zod";
|
|
12599
12599
|
|
|
@@ -12605,9 +12605,9 @@ function keyBy(array, keyBy2) {
|
|
|
12605
12605
|
}
|
|
12606
12606
|
|
|
12607
12607
|
// src/features/analysis/utils/send_report.ts
|
|
12608
|
-
import
|
|
12608
|
+
import Debug8 from "debug";
|
|
12609
12609
|
init_client_generates();
|
|
12610
|
-
var
|
|
12610
|
+
var debug9 = Debug8("mobbdev:index");
|
|
12611
12611
|
async function sendReport({
|
|
12612
12612
|
spinner,
|
|
12613
12613
|
submitVulnerabilityReportVariables,
|
|
@@ -12619,7 +12619,7 @@ async function sendReport({
|
|
|
12619
12619
|
submitVulnerabilityReportVariables
|
|
12620
12620
|
);
|
|
12621
12621
|
if (submitRes.submitVulnerabilityReport.__typename !== "VulnerabilityReport") {
|
|
12622
|
-
|
|
12622
|
+
debug9("error submit vul report %s", submitRes);
|
|
12623
12623
|
throw new Error("\u{1F575}\uFE0F\u200D\u2642\uFE0F Mobb analysis failed");
|
|
12624
12624
|
}
|
|
12625
12625
|
spinner.update({ text: progressMassages.processingVulnerabilityReport });
|
|
@@ -12631,7 +12631,7 @@ async function sendReport({
|
|
|
12631
12631
|
"Finished" /* Finished */
|
|
12632
12632
|
];
|
|
12633
12633
|
if (polling) {
|
|
12634
|
-
|
|
12634
|
+
debug9("[sendReport] Using POLLING mode for analysis state updates");
|
|
12635
12635
|
await gqlClient.pollForAnalysisState({
|
|
12636
12636
|
analysisId: submitRes.submitVulnerabilityReport.fixReportId,
|
|
12637
12637
|
callback,
|
|
@@ -12639,7 +12639,7 @@ async function sendReport({
|
|
|
12639
12639
|
timeoutInMs: VUL_REPORT_DIGEST_TIMEOUT_MS
|
|
12640
12640
|
});
|
|
12641
12641
|
} else {
|
|
12642
|
-
|
|
12642
|
+
debug9("[sendReport] Using WEBSOCKET mode for analysis state updates");
|
|
12643
12643
|
await gqlClient.subscribeToAnalysis({
|
|
12644
12644
|
subscribeToAnalysisParams: {
|
|
12645
12645
|
analysisId: submitRes.submitVulnerabilityReport.fixReportId
|
|
@@ -12682,10 +12682,10 @@ var scannerToFriendlyString = {
|
|
|
12682
12682
|
};
|
|
12683
12683
|
|
|
12684
12684
|
// src/features/analysis/add_fix_comments_for_pr/utils/buildCommentBody.ts
|
|
12685
|
-
import
|
|
12685
|
+
import Debug9 from "debug";
|
|
12686
12686
|
import { z as z26 } from "zod";
|
|
12687
12687
|
init_client_generates();
|
|
12688
|
-
var
|
|
12688
|
+
var debug10 = Debug9("mobbdev:handle-finished-analysis");
|
|
12689
12689
|
var getCommitFixButton = (commitUrl) => `<a href="${commitUrl}"><img src=${COMMIT_FIX_SVG}></a>`;
|
|
12690
12690
|
function buildFixCommentBody({
|
|
12691
12691
|
fix,
|
|
@@ -12744,7 +12744,7 @@ function buildFixCommentBody({
|
|
|
12744
12744
|
safeIssueType: z26.nativeEnum(IssueType_Enum)
|
|
12745
12745
|
}).safeParse(fix);
|
|
12746
12746
|
if (!validFixParseRes.success) {
|
|
12747
|
-
|
|
12747
|
+
debug10(
|
|
12748
12748
|
`fix ${fixId} has custom issue type or language, therefore the commit description will not be added`,
|
|
12749
12749
|
validFixParseRes.error
|
|
12750
12750
|
);
|
|
@@ -12808,7 +12808,7 @@ ${issuePageLink}`;
|
|
|
12808
12808
|
}
|
|
12809
12809
|
|
|
12810
12810
|
// src/features/analysis/add_fix_comments_for_pr/utils/utils.ts
|
|
12811
|
-
var
|
|
12811
|
+
var debug11 = Debug10("mobbdev:handle-finished-analysis");
|
|
12812
12812
|
function calculateRanges(integers) {
|
|
12813
12813
|
if (integers.length === 0) {
|
|
12814
12814
|
return [];
|
|
@@ -12842,7 +12842,7 @@ function deleteAllPreviousComments({
|
|
|
12842
12842
|
try {
|
|
12843
12843
|
return scm.deleteComment({ comment_id: comment.id });
|
|
12844
12844
|
} catch (e) {
|
|
12845
|
-
|
|
12845
|
+
debug11("delete comment failed %s", e);
|
|
12846
12846
|
return Promise.resolve();
|
|
12847
12847
|
}
|
|
12848
12848
|
});
|
|
@@ -12858,7 +12858,7 @@ function deleteAllPreviousGeneralPrComments(params) {
|
|
|
12858
12858
|
try {
|
|
12859
12859
|
return scm.deleteGeneralPrComment({ commentId: comment.id });
|
|
12860
12860
|
} catch (e) {
|
|
12861
|
-
|
|
12861
|
+
debug11("delete comment failed %s", e);
|
|
12862
12862
|
return Promise.resolve();
|
|
12863
12863
|
}
|
|
12864
12864
|
});
|
|
@@ -13002,7 +13002,7 @@ async function postAnalysisInsightComment(params) {
|
|
|
13002
13002
|
fixablePrVuls,
|
|
13003
13003
|
nonFixablePrVuls
|
|
13004
13004
|
} = prVulenrabilities;
|
|
13005
|
-
|
|
13005
|
+
debug11({
|
|
13006
13006
|
fixablePrVuls,
|
|
13007
13007
|
nonFixablePrVuls,
|
|
13008
13008
|
vulnerabilitiesOutsidePr,
|
|
@@ -13057,7 +13057,7 @@ ${contactUsMarkdown}`;
|
|
|
13057
13057
|
}
|
|
13058
13058
|
|
|
13059
13059
|
// src/features/analysis/add_fix_comments_for_pr/add_fix_comments_for_pr.ts
|
|
13060
|
-
var
|
|
13060
|
+
var debug12 = Debug11("mobbdev:handle-finished-analysis");
|
|
13061
13061
|
async function addFixCommentsForPr({
|
|
13062
13062
|
analysisId,
|
|
13063
13063
|
scm: _scm,
|
|
@@ -13069,7 +13069,7 @@ async function addFixCommentsForPr({
|
|
|
13069
13069
|
}
|
|
13070
13070
|
const scm = _scm;
|
|
13071
13071
|
const getAnalysisRes = await gqlClient.getAnalysis(analysisId);
|
|
13072
|
-
|
|
13072
|
+
debug12("getAnalysis %o", getAnalysisRes);
|
|
13073
13073
|
const {
|
|
13074
13074
|
vulnerabilityReport: {
|
|
13075
13075
|
projectId,
|
|
@@ -13179,8 +13179,8 @@ ${contextString}` : description;
|
|
|
13179
13179
|
|
|
13180
13180
|
// src/features/analysis/auto_pr_handler.ts
|
|
13181
13181
|
init_client_generates();
|
|
13182
|
-
import
|
|
13183
|
-
var
|
|
13182
|
+
import Debug12 from "debug";
|
|
13183
|
+
var debug13 = Debug12("mobbdev:handleAutoPr");
|
|
13184
13184
|
async function handleAutoPr(params) {
|
|
13185
13185
|
const {
|
|
13186
13186
|
gqlClient,
|
|
@@ -13201,7 +13201,7 @@ async function handleAutoPr(params) {
|
|
|
13201
13201
|
prId,
|
|
13202
13202
|
prStrategy: createOnePr ? "CONDENSE" /* Condense */ : "SPREAD" /* Spread */
|
|
13203
13203
|
});
|
|
13204
|
-
|
|
13204
|
+
debug13("auto pr analysis res %o", autoPrAnalysisRes);
|
|
13205
13205
|
if (autoPrAnalysisRes.autoPrAnalysis?.__typename === "AutoPrError") {
|
|
13206
13206
|
createAutoPrSpinner.error({
|
|
13207
13207
|
text: `\u{1F504} Automatic pull request failed - ${autoPrAnalysisRes.autoPrAnalysis.error}`
|
|
@@ -13223,14 +13223,14 @@ async function handleAutoPr(params) {
|
|
|
13223
13223
|
};
|
|
13224
13224
|
const callbackStates = ["Finished" /* Finished */];
|
|
13225
13225
|
if (polling) {
|
|
13226
|
-
|
|
13226
|
+
debug13("[handleAutoPr] Using POLLING mode for analysis state updates");
|
|
13227
13227
|
return await gqlClient.pollForAnalysisState({
|
|
13228
13228
|
analysisId,
|
|
13229
13229
|
callback,
|
|
13230
13230
|
callbackStates
|
|
13231
13231
|
});
|
|
13232
13232
|
} else {
|
|
13233
|
-
|
|
13233
|
+
debug13("[handleAutoPr] Using WEBSOCKET mode for analysis state updates");
|
|
13234
13234
|
return await gqlClient.subscribeToAnalysis({
|
|
13235
13235
|
subscribeToAnalysisParams: {
|
|
13236
13236
|
analysisId
|
|
@@ -13243,15 +13243,15 @@ async function handleAutoPr(params) {
|
|
|
13243
13243
|
|
|
13244
13244
|
// src/features/analysis/git.ts
|
|
13245
13245
|
init_GitService();
|
|
13246
|
-
import
|
|
13247
|
-
var
|
|
13246
|
+
import Debug13 from "debug";
|
|
13247
|
+
var debug14 = Debug13("mobbdev:git");
|
|
13248
13248
|
async function getGitInfo(srcDirPath) {
|
|
13249
|
-
|
|
13249
|
+
debug14("getting git info for %s", srcDirPath);
|
|
13250
13250
|
const gitService = new GitService(srcDirPath);
|
|
13251
13251
|
try {
|
|
13252
13252
|
const validationResult = await gitService.validateRepository();
|
|
13253
13253
|
if (!validationResult.isValid) {
|
|
13254
|
-
|
|
13254
|
+
debug14("folder is not a git repo");
|
|
13255
13255
|
return {
|
|
13256
13256
|
success: false,
|
|
13257
13257
|
hash: void 0,
|
|
@@ -13266,9 +13266,9 @@ async function getGitInfo(srcDirPath) {
|
|
|
13266
13266
|
};
|
|
13267
13267
|
} catch (e) {
|
|
13268
13268
|
if (e instanceof Error) {
|
|
13269
|
-
|
|
13269
|
+
debug14("failed to run git %o", e);
|
|
13270
13270
|
if (e.message.includes(" spawn ")) {
|
|
13271
|
-
|
|
13271
|
+
debug14("git cli not installed");
|
|
13272
13272
|
} else {
|
|
13273
13273
|
throw e;
|
|
13274
13274
|
}
|
|
@@ -13282,13 +13282,13 @@ init_configs();
|
|
|
13282
13282
|
import fs9 from "fs";
|
|
13283
13283
|
import path7 from "path";
|
|
13284
13284
|
import AdmZip from "adm-zip";
|
|
13285
|
-
import
|
|
13285
|
+
import Debug14 from "debug";
|
|
13286
13286
|
import { globby } from "globby";
|
|
13287
13287
|
import { isBinary as isBinary2 } from "istextorbinary";
|
|
13288
13288
|
import { simpleGit as simpleGit3 } from "simple-git";
|
|
13289
13289
|
import { parseStringPromise } from "xml2js";
|
|
13290
13290
|
import { z as z28 } from "zod";
|
|
13291
|
-
var
|
|
13291
|
+
var debug15 = Debug14("mobbdev:pack");
|
|
13292
13292
|
var FPR_SOURCE_CODE_FILE_MAPPING_SCHEMA = z28.object({
|
|
13293
13293
|
properties: z28.object({
|
|
13294
13294
|
entry: z28.array(
|
|
@@ -13310,7 +13310,7 @@ function getManifestFilesSuffixes() {
|
|
|
13310
13310
|
return ["package.json", "pom.xml"];
|
|
13311
13311
|
}
|
|
13312
13312
|
async function pack(srcDirPath, vulnFiles, isIncludeAllFiles = false) {
|
|
13313
|
-
|
|
13313
|
+
debug15("pack folder %s", srcDirPath);
|
|
13314
13314
|
let git = void 0;
|
|
13315
13315
|
try {
|
|
13316
13316
|
git = simpleGit3({
|
|
@@ -13320,13 +13320,13 @@ async function pack(srcDirPath, vulnFiles, isIncludeAllFiles = false) {
|
|
|
13320
13320
|
});
|
|
13321
13321
|
await git.status();
|
|
13322
13322
|
} catch (e) {
|
|
13323
|
-
|
|
13323
|
+
debug15("failed to run git %o", e);
|
|
13324
13324
|
git = void 0;
|
|
13325
13325
|
if (e instanceof Error) {
|
|
13326
13326
|
if (e.message.includes(" spawn ")) {
|
|
13327
|
-
|
|
13327
|
+
debug15("git cli not installed");
|
|
13328
13328
|
} else if (e.message.includes("not a git repository")) {
|
|
13329
|
-
|
|
13329
|
+
debug15("folder is not a git repo");
|
|
13330
13330
|
} else {
|
|
13331
13331
|
throw e;
|
|
13332
13332
|
}
|
|
@@ -13341,9 +13341,9 @@ async function pack(srcDirPath, vulnFiles, isIncludeAllFiles = false) {
|
|
|
13341
13341
|
followSymbolicLinks: false,
|
|
13342
13342
|
dot: true
|
|
13343
13343
|
});
|
|
13344
|
-
|
|
13344
|
+
debug15("files found %d", filepaths.length);
|
|
13345
13345
|
const zip = new AdmZip();
|
|
13346
|
-
|
|
13346
|
+
debug15("compressing files");
|
|
13347
13347
|
for (const filepath of filepaths) {
|
|
13348
13348
|
const absFilepath = path7.join(srcDirPath, filepath.toString());
|
|
13349
13349
|
if (!isIncludeAllFiles) {
|
|
@@ -13352,12 +13352,12 @@ async function pack(srcDirPath, vulnFiles, isIncludeAllFiles = false) {
|
|
|
13352
13352
|
absFilepath.toString().replaceAll(path7.win32.sep, path7.posix.sep),
|
|
13353
13353
|
vulnFiles
|
|
13354
13354
|
)) {
|
|
13355
|
-
|
|
13355
|
+
debug15("ignoring %s because it is not a vulnerability file", filepath);
|
|
13356
13356
|
continue;
|
|
13357
13357
|
}
|
|
13358
13358
|
}
|
|
13359
13359
|
if (fs9.lstatSync(absFilepath).size > MCP_MAX_FILE_SIZE) {
|
|
13360
|
-
|
|
13360
|
+
debug15("ignoring %s because the size is > 5MB", filepath);
|
|
13361
13361
|
continue;
|
|
13362
13362
|
}
|
|
13363
13363
|
let data;
|
|
@@ -13371,16 +13371,16 @@ async function pack(srcDirPath, vulnFiles, isIncludeAllFiles = false) {
|
|
|
13371
13371
|
data = fs9.readFileSync(absFilepath);
|
|
13372
13372
|
}
|
|
13373
13373
|
if (isBinary2(null, data)) {
|
|
13374
|
-
|
|
13374
|
+
debug15("ignoring %s because is seems to be a binary file", filepath);
|
|
13375
13375
|
continue;
|
|
13376
13376
|
}
|
|
13377
13377
|
zip.addFile(filepath.toString(), data);
|
|
13378
13378
|
}
|
|
13379
|
-
|
|
13379
|
+
debug15("get zip file buffer");
|
|
13380
13380
|
return zip.toBuffer();
|
|
13381
13381
|
}
|
|
13382
13382
|
async function repackFpr(fprPath) {
|
|
13383
|
-
|
|
13383
|
+
debug15("repack fpr file %s", fprPath);
|
|
13384
13384
|
const zipIn = new AdmZip(fprPath);
|
|
13385
13385
|
const zipOut = new AdmZip();
|
|
13386
13386
|
const mappingXML = zipIn.readAsText("src-archive/index.xml", "utf-8");
|
|
@@ -13395,7 +13395,7 @@ async function repackFpr(fprPath) {
|
|
|
13395
13395
|
zipOut.addFile(realPath, buf);
|
|
13396
13396
|
}
|
|
13397
13397
|
}
|
|
13398
|
-
|
|
13398
|
+
debug15("get repacked zip file buffer");
|
|
13399
13399
|
return zipOut.toBuffer();
|
|
13400
13400
|
}
|
|
13401
13401
|
|
|
@@ -13466,7 +13466,7 @@ async function snykArticlePrompt() {
|
|
|
13466
13466
|
// src/features/analysis/scanners/checkmarx.ts
|
|
13467
13467
|
import { createRequire } from "module";
|
|
13468
13468
|
import chalk4 from "chalk";
|
|
13469
|
-
import
|
|
13469
|
+
import Debug16 from "debug";
|
|
13470
13470
|
import { existsSync } from "fs";
|
|
13471
13471
|
import { createSpinner as createSpinner2 } from "nanospinner";
|
|
13472
13472
|
import { type } from "os";
|
|
@@ -13478,7 +13478,7 @@ var cxOperatingSystemSupportMessage = `Your operating system does not support ch
|
|
|
13478
13478
|
|
|
13479
13479
|
// src/utils/child_process.ts
|
|
13480
13480
|
import cp from "child_process";
|
|
13481
|
-
import
|
|
13481
|
+
import Debug15 from "debug";
|
|
13482
13482
|
import * as process2 from "process";
|
|
13483
13483
|
function createFork({ args, processPath, name }, options) {
|
|
13484
13484
|
const child = cp.fork(processPath, args, {
|
|
@@ -13496,16 +13496,16 @@ function createSpawn({ args, processPath, name, cwd }, options) {
|
|
|
13496
13496
|
return createChildProcess({ childProcess: child, name }, options);
|
|
13497
13497
|
}
|
|
13498
13498
|
function createChildProcess({ childProcess, name }, options) {
|
|
13499
|
-
const
|
|
13499
|
+
const debug21 = Debug15(`mobbdev:${name}`);
|
|
13500
13500
|
const { display } = options;
|
|
13501
13501
|
return new Promise((resolve, reject) => {
|
|
13502
13502
|
let out = "";
|
|
13503
13503
|
const onData = (chunk) => {
|
|
13504
|
-
|
|
13504
|
+
debug21(`chunk received from ${name} std ${chunk}`);
|
|
13505
13505
|
out += chunk;
|
|
13506
13506
|
};
|
|
13507
13507
|
if (!childProcess?.stdout || !childProcess?.stderr) {
|
|
13508
|
-
|
|
13508
|
+
debug21(`unable to fork ${name}`);
|
|
13509
13509
|
reject(new Error(`unable to fork ${name}`));
|
|
13510
13510
|
}
|
|
13511
13511
|
childProcess.stdout?.on("data", onData);
|
|
@@ -13515,18 +13515,18 @@ function createChildProcess({ childProcess, name }, options) {
|
|
|
13515
13515
|
childProcess.stderr?.pipe(process2.stderr);
|
|
13516
13516
|
}
|
|
13517
13517
|
childProcess.on("exit", (code) => {
|
|
13518
|
-
|
|
13518
|
+
debug21(`${name} exit code ${code}`);
|
|
13519
13519
|
resolve({ message: out, code });
|
|
13520
13520
|
});
|
|
13521
13521
|
childProcess.on("error", (err) => {
|
|
13522
|
-
|
|
13522
|
+
debug21(`${name} error %o`, err);
|
|
13523
13523
|
reject(err);
|
|
13524
13524
|
});
|
|
13525
13525
|
});
|
|
13526
13526
|
}
|
|
13527
13527
|
|
|
13528
13528
|
// src/features/analysis/scanners/checkmarx.ts
|
|
13529
|
-
var
|
|
13529
|
+
var debug16 = Debug16("mobbdev:checkmarx");
|
|
13530
13530
|
var moduleUrl;
|
|
13531
13531
|
if (typeof __filename !== "undefined") {
|
|
13532
13532
|
moduleUrl = __filename;
|
|
@@ -13585,14 +13585,14 @@ function validateCheckmarxInstallation() {
|
|
|
13585
13585
|
existsSync(getCheckmarxPath());
|
|
13586
13586
|
}
|
|
13587
13587
|
async function forkCheckmarx(args, { display }) {
|
|
13588
|
-
|
|
13588
|
+
debug16("fork checkmarx with args %o %s", args.join(" "), display);
|
|
13589
13589
|
return createSpawn(
|
|
13590
13590
|
{ args, processPath: getCheckmarxPath(), name: "checkmarx" },
|
|
13591
13591
|
{ display }
|
|
13592
13592
|
);
|
|
13593
13593
|
}
|
|
13594
13594
|
async function getCheckmarxReport({ reportPath, repositoryRoot, branch, projectName }, { skipPrompts = false }) {
|
|
13595
|
-
|
|
13595
|
+
debug16("get checkmarx report start %s %s", reportPath, repositoryRoot);
|
|
13596
13596
|
const { code: loginCode } = await forkCheckmarx(VALIDATE_COMMAND, {
|
|
13597
13597
|
display: false
|
|
13598
13598
|
});
|
|
@@ -13660,10 +13660,10 @@ async function validateCheckamxCredentials() {
|
|
|
13660
13660
|
// src/features/analysis/scanners/snyk.ts
|
|
13661
13661
|
import { createRequire as createRequire2 } from "module";
|
|
13662
13662
|
import chalk5 from "chalk";
|
|
13663
|
-
import
|
|
13663
|
+
import Debug17 from "debug";
|
|
13664
13664
|
import { createSpinner as createSpinner3 } from "nanospinner";
|
|
13665
13665
|
import open2 from "open";
|
|
13666
|
-
var
|
|
13666
|
+
var debug17 = Debug17("mobbdev:snyk");
|
|
13667
13667
|
var moduleUrl2;
|
|
13668
13668
|
if (typeof __filename !== "undefined") {
|
|
13669
13669
|
moduleUrl2 = __filename;
|
|
@@ -13685,13 +13685,13 @@ if (typeof __filename !== "undefined") {
|
|
|
13685
13685
|
var costumeRequire2 = createRequire2(moduleUrl2);
|
|
13686
13686
|
var SNYK_PATH = costumeRequire2.resolve("snyk/bin/snyk");
|
|
13687
13687
|
var SNYK_ARTICLE_URL = "https://docs.snyk.io/scan-using-snyk/snyk-code/configure-snyk-code#enable-snyk-code";
|
|
13688
|
-
|
|
13688
|
+
debug17("snyk executable path %s", SNYK_PATH);
|
|
13689
13689
|
async function forkSnyk(args, { display }) {
|
|
13690
|
-
|
|
13690
|
+
debug17("fork snyk with args %o %s", args, display);
|
|
13691
13691
|
return createFork({ args, processPath: SNYK_PATH, name: "snyk" }, { display });
|
|
13692
13692
|
}
|
|
13693
13693
|
async function getSnykReport(reportPath, repoRoot, { skipPrompts = false }) {
|
|
13694
|
-
|
|
13694
|
+
debug17("get snyk report start %s %s", reportPath, repoRoot);
|
|
13695
13695
|
const config2 = await forkSnyk(["config"], { display: false });
|
|
13696
13696
|
const { message: configMessage } = config2;
|
|
13697
13697
|
if (!configMessage.includes("api: ")) {
|
|
@@ -13705,7 +13705,7 @@ async function getSnykReport(reportPath, repoRoot, { skipPrompts = false }) {
|
|
|
13705
13705
|
snykLoginSpinner.update({
|
|
13706
13706
|
text: "\u{1F513} Waiting for Snyk login to complete"
|
|
13707
13707
|
});
|
|
13708
|
-
|
|
13708
|
+
debug17("no token in the config %s", config2);
|
|
13709
13709
|
await forkSnyk(["auth"], { display: true });
|
|
13710
13710
|
snykLoginSpinner.success({ text: "\u{1F513} Login to Snyk Successful" });
|
|
13711
13711
|
}
|
|
@@ -13715,12 +13715,12 @@ async function getSnykReport(reportPath, repoRoot, { skipPrompts = false }) {
|
|
|
13715
13715
|
{ display: true }
|
|
13716
13716
|
);
|
|
13717
13717
|
if (scanOutput.includes("Snyk Code is not supported for org")) {
|
|
13718
|
-
|
|
13718
|
+
debug17("snyk code is not enabled %s", scanOutput);
|
|
13719
13719
|
snykSpinner.error({ text: "\u{1F50D} Snyk configuration needed" });
|
|
13720
13720
|
const answer = await snykArticlePrompt();
|
|
13721
|
-
|
|
13721
|
+
debug17("answer %s", answer);
|
|
13722
13722
|
if (answer) {
|
|
13723
|
-
|
|
13723
|
+
debug17("opening the browser");
|
|
13724
13724
|
await open2(SNYK_ARTICLE_URL);
|
|
13725
13725
|
}
|
|
13726
13726
|
console.log(
|
|
@@ -13738,9 +13738,9 @@ async function getSnykReport(reportPath, repoRoot, { skipPrompts = false }) {
|
|
|
13738
13738
|
init_client_generates();
|
|
13739
13739
|
|
|
13740
13740
|
// src/features/analysis/upload-file.ts
|
|
13741
|
-
import
|
|
13741
|
+
import Debug18 from "debug";
|
|
13742
13742
|
import fetch3, { File, fileFrom, FormData } from "node-fetch";
|
|
13743
|
-
var
|
|
13743
|
+
var debug18 = Debug18("mobbdev:upload-file");
|
|
13744
13744
|
async function uploadFile({
|
|
13745
13745
|
file,
|
|
13746
13746
|
url,
|
|
@@ -13753,9 +13753,9 @@ async function uploadFile({
|
|
|
13753
13753
|
logInfo2(`FileUpload: upload file start ${url}`);
|
|
13754
13754
|
logInfo2(`FileUpload: upload fields`, uploadFields);
|
|
13755
13755
|
logInfo2(`FileUpload: upload key ${uploadKey}`);
|
|
13756
|
-
|
|
13757
|
-
|
|
13758
|
-
|
|
13756
|
+
debug18("upload file start %s", url);
|
|
13757
|
+
debug18("upload fields %o", uploadFields);
|
|
13758
|
+
debug18("upload key %s", uploadKey);
|
|
13759
13759
|
const form = new FormData();
|
|
13760
13760
|
Object.entries(uploadFields).forEach(([key, value]) => {
|
|
13761
13761
|
form.append(key, value);
|
|
@@ -13764,11 +13764,11 @@ async function uploadFile({
|
|
|
13764
13764
|
form.append("key", uploadKey);
|
|
13765
13765
|
}
|
|
13766
13766
|
if (typeof file === "string") {
|
|
13767
|
-
|
|
13767
|
+
debug18("upload file from path %s", file);
|
|
13768
13768
|
logInfo2(`FileUpload: upload file from path ${file}`);
|
|
13769
13769
|
form.append("file", await fileFrom(file));
|
|
13770
13770
|
} else {
|
|
13771
|
-
|
|
13771
|
+
debug18("upload file from buffer");
|
|
13772
13772
|
logInfo2(`FileUpload: upload file from buffer`);
|
|
13773
13773
|
form.append("file", new File([new Uint8Array(file)], "file"));
|
|
13774
13774
|
}
|
|
@@ -13779,11 +13779,11 @@ async function uploadFile({
|
|
|
13779
13779
|
agent
|
|
13780
13780
|
});
|
|
13781
13781
|
if (!response.ok) {
|
|
13782
|
-
|
|
13782
|
+
debug18("error from S3 %s %s", response.body, response.status);
|
|
13783
13783
|
logInfo2(`FileUpload: error from S3 ${response.body} ${response.status}`);
|
|
13784
13784
|
throw new Error(`Failed to upload the file: ${response.status}`);
|
|
13785
13785
|
}
|
|
13786
|
-
|
|
13786
|
+
debug18("upload file done");
|
|
13787
13787
|
logInfo2(`FileUpload: upload file done`);
|
|
13788
13788
|
}
|
|
13789
13789
|
|
|
@@ -13818,9 +13818,9 @@ async function downloadRepo({
|
|
|
13818
13818
|
}) {
|
|
13819
13819
|
const { createSpinner: createSpinner5 } = Spinner2({ ci });
|
|
13820
13820
|
const repoSpinner = createSpinner5("\u{1F4BE} Downloading Repo").start();
|
|
13821
|
-
|
|
13821
|
+
debug19("download repo %s %s %s", repoUrl, dirname);
|
|
13822
13822
|
const zipFilePath = path9.join(dirname, "repo.zip");
|
|
13823
|
-
|
|
13823
|
+
debug19("download URL: %s auth headers: %o", downloadUrl, authHeaders);
|
|
13824
13824
|
const response = await fetch4(downloadUrl, {
|
|
13825
13825
|
method: "GET",
|
|
13826
13826
|
headers: {
|
|
@@ -13828,7 +13828,7 @@ async function downloadRepo({
|
|
|
13828
13828
|
}
|
|
13829
13829
|
});
|
|
13830
13830
|
if (!response.ok) {
|
|
13831
|
-
|
|
13831
|
+
debug19("SCM zipball request failed %s %s", response.body, response.status);
|
|
13832
13832
|
repoSpinner.error({ text: "\u{1F4BE} Repo download failed" });
|
|
13833
13833
|
throw new Error(`Can't access ${chalk6.bold(repoUrl)}`);
|
|
13834
13834
|
}
|
|
@@ -13842,7 +13842,7 @@ async function downloadRepo({
|
|
|
13842
13842
|
if (!repoRoot) {
|
|
13843
13843
|
throw new Error("Repo root not found");
|
|
13844
13844
|
}
|
|
13845
|
-
|
|
13845
|
+
debug19("repo root %s", repoRoot);
|
|
13846
13846
|
repoSpinner.success({ text: "\u{1F4BE} Repo downloaded successfully" });
|
|
13847
13847
|
return path9.join(dirname, repoRoot);
|
|
13848
13848
|
}
|
|
@@ -13851,7 +13851,7 @@ var getReportUrl = ({
|
|
|
13851
13851
|
projectId,
|
|
13852
13852
|
fixReportId
|
|
13853
13853
|
}) => `${WEB_APP_URL}/organization/${organizationId}/project/${projectId}/report/${fixReportId}`;
|
|
13854
|
-
var
|
|
13854
|
+
var debug19 = Debug19("mobbdev:index");
|
|
13855
13855
|
async function runAnalysis(params, options) {
|
|
13856
13856
|
const tmpObj = tmp2.dirSync({
|
|
13857
13857
|
unsafeCleanup: true
|
|
@@ -13997,7 +13997,7 @@ async function _scan(params, { skipPrompts = false } = {}) {
|
|
|
13997
13997
|
pullRequest,
|
|
13998
13998
|
polling
|
|
13999
13999
|
} = params;
|
|
14000
|
-
|
|
14000
|
+
debug19("start %s %s", dirname, repo);
|
|
14001
14001
|
const { createSpinner: createSpinner5 } = Spinner2({ ci });
|
|
14002
14002
|
skipPrompts = skipPrompts || ci;
|
|
14003
14003
|
const gqlClient = await getAuthenticatedGQLClient({
|
|
@@ -14066,8 +14066,8 @@ async function _scan(params, { skipPrompts = false } = {}) {
|
|
|
14066
14066
|
);
|
|
14067
14067
|
}
|
|
14068
14068
|
const { sha } = getReferenceDataRes.gitReference;
|
|
14069
|
-
|
|
14070
|
-
|
|
14069
|
+
debug19("project id %s", projectId);
|
|
14070
|
+
debug19("default branch %s", reference);
|
|
14071
14071
|
if (command === "scan") {
|
|
14072
14072
|
reportPath = await getReport(
|
|
14073
14073
|
{
|
|
@@ -14395,7 +14395,7 @@ async function _digestReport({
|
|
|
14395
14395
|
text: progressMassages.processingVulnerabilityReportSuccess
|
|
14396
14396
|
});
|
|
14397
14397
|
if (polling) {
|
|
14398
|
-
|
|
14398
|
+
debug19(
|
|
14399
14399
|
"[_digestReport] Using POLLING mode for analysis state updates (--polling flag enabled)"
|
|
14400
14400
|
);
|
|
14401
14401
|
console.log(
|
|
@@ -14410,7 +14410,7 @@ async function _digestReport({
|
|
|
14410
14410
|
timeoutInMs: VUL_REPORT_DIGEST_TIMEOUT_MS
|
|
14411
14411
|
});
|
|
14412
14412
|
} else {
|
|
14413
|
-
|
|
14413
|
+
debug19(
|
|
14414
14414
|
"[_digestReport] Using WEBSOCKET mode for analysis state updates (default)"
|
|
14415
14415
|
);
|
|
14416
14416
|
console.log(
|
|
@@ -14474,7 +14474,7 @@ async function waitForAnaysisAndReviewPr({
|
|
|
14474
14474
|
});
|
|
14475
14475
|
};
|
|
14476
14476
|
if (polling) {
|
|
14477
|
-
|
|
14477
|
+
debug19(
|
|
14478
14478
|
"[waitForAnaysisAndReviewPr] Using POLLING mode for analysis state updates"
|
|
14479
14479
|
);
|
|
14480
14480
|
console.log(
|
|
@@ -14488,7 +14488,7 @@ async function waitForAnaysisAndReviewPr({
|
|
|
14488
14488
|
callbackStates: ["Finished" /* Finished */]
|
|
14489
14489
|
});
|
|
14490
14490
|
} else {
|
|
14491
|
-
|
|
14491
|
+
debug19(
|
|
14492
14492
|
"[waitForAnaysisAndReviewPr] Using WEBSOCKET mode for analysis state updates"
|
|
14493
14493
|
);
|
|
14494
14494
|
console.log(
|
|
@@ -15050,8 +15050,8 @@ var openRedaction = new OpenRedaction({
|
|
|
15050
15050
|
"MONERO_ADDRESS",
|
|
15051
15051
|
"RIPPLE_ADDRESS",
|
|
15052
15052
|
// Medical Data (removed PRESCRIPTION_NUMBER - too broad, matches words containing "ription")
|
|
15053
|
+
// Removed MEDICAL_RECORD_NUMBER - too broad, "MR" prefix matches "Merge Request" in SCM contexts (e.g. "MR branches" → "MR br****es")
|
|
15053
15054
|
"NHS_NUMBER",
|
|
15054
|
-
"MEDICAL_RECORD_NUMBER",
|
|
15055
15055
|
"AUSTRALIAN_MEDICARE",
|
|
15056
15056
|
"HEALTH_PLAN_NUMBER",
|
|
15057
15057
|
"PATIENT_ID",
|
|
@@ -15095,10 +15095,10 @@ var openRedaction = new OpenRedaction({
|
|
|
15095
15095
|
"DOCKER_AUTH",
|
|
15096
15096
|
"KUBERNETES_SECRET",
|
|
15097
15097
|
// Government & Legal
|
|
15098
|
+
// Removed CLIENT_ID - too broad, "client" is ubiquitous in code (npm packages like @scope/client-*, class names like ClientSdkOptions)
|
|
15098
15099
|
"POLICE_REPORT_NUMBER",
|
|
15099
15100
|
"IMMIGRATION_NUMBER",
|
|
15100
|
-
"COURT_REPORTER_LICENSE"
|
|
15101
|
-
"CLIENT_ID"
|
|
15101
|
+
"COURT_REPORTER_LICENSE"
|
|
15102
15102
|
]
|
|
15103
15103
|
});
|
|
15104
15104
|
function maskString(str, showStart = 2, showEnd = 2) {
|
|
@@ -15121,6 +15121,15 @@ async function sanitizeDataWithCounts(obj) {
|
|
|
15121
15121
|
...piiDetections.low
|
|
15122
15122
|
];
|
|
15123
15123
|
for (const detection of allDetections) {
|
|
15124
|
+
if (detection.type === "CREDIT_CARD") {
|
|
15125
|
+
const start = detection.position[0];
|
|
15126
|
+
const end = detection.position[1];
|
|
15127
|
+
const charBefore = (start > 0 ? str[start - 1] : "") ?? "";
|
|
15128
|
+
const charAfter = str[end] ?? "";
|
|
15129
|
+
if (charBefore === "." || charBefore >= "0" && charBefore <= "9" || charAfter >= "0" && charAfter <= "9") {
|
|
15130
|
+
continue;
|
|
15131
|
+
}
|
|
15132
|
+
}
|
|
15124
15133
|
counts.detections.total++;
|
|
15125
15134
|
if (detection.severity === "high") counts.detections.high++;
|
|
15126
15135
|
else if (detection.severity === "medium") counts.detections.medium++;
|
|
@@ -16103,7 +16112,6 @@ var log = logger.log.bind(logger);
|
|
|
16103
16112
|
// src/mcp/services/McpGQLClient.ts
|
|
16104
16113
|
import crypto3 from "crypto";
|
|
16105
16114
|
import { GraphQLClient as GraphQLClient2 } from "graphql-request";
|
|
16106
|
-
import { HttpsProxyAgent as HttpsProxyAgent2 } from "https-proxy-agent";
|
|
16107
16115
|
import { v4 as uuidv42 } from "uuid";
|
|
16108
16116
|
init_client_generates();
|
|
16109
16117
|
init_configs();
|
|
@@ -16318,23 +16326,6 @@ var McpAuthService = class {
|
|
|
16318
16326
|
};
|
|
16319
16327
|
|
|
16320
16328
|
// src/mcp/services/McpGQLClient.ts
|
|
16321
|
-
function getProxyAgent2(url) {
|
|
16322
|
-
try {
|
|
16323
|
-
const parsedUrl = new URL(url);
|
|
16324
|
-
const isHttp = parsedUrl.protocol === "http:";
|
|
16325
|
-
const isHttps = parsedUrl.protocol === "https:";
|
|
16326
|
-
const proxy = isHttps ? HTTPS_PROXY || HTTP_PROXY : isHttp ? HTTP_PROXY : null;
|
|
16327
|
-
if (proxy) {
|
|
16328
|
-
logDebug("[GraphQL] Using proxy for websocket subscriptions", { proxy });
|
|
16329
|
-
return new HttpsProxyAgent2(proxy);
|
|
16330
|
-
}
|
|
16331
|
-
} catch (err) {
|
|
16332
|
-
logDebug(`[GraphQL] Skipping proxy for ${url}`, {
|
|
16333
|
-
error: err.message
|
|
16334
|
-
});
|
|
16335
|
-
}
|
|
16336
|
-
return void 0;
|
|
16337
|
-
}
|
|
16338
16329
|
var McpGQLClient = class {
|
|
16339
16330
|
constructor(args) {
|
|
16340
16331
|
__publicField(this, "client");
|
|
@@ -16351,6 +16342,7 @@ var McpGQLClient = class {
|
|
|
16351
16342
|
headers: args.type === "apiKey" ? { [MCP_API_KEY_HEADER_NAME]: args.apiKey || "" } : {
|
|
16352
16343
|
Authorization: `Bearer ${args.token}`
|
|
16353
16344
|
},
|
|
16345
|
+
fetch: fetchWithProxy,
|
|
16354
16346
|
requestMiddleware: (request) => {
|
|
16355
16347
|
const requestId = uuidv42();
|
|
16356
16348
|
return {
|
|
@@ -16533,13 +16525,15 @@ var McpGQLClient = class {
|
|
|
16533
16525
|
this._auth.type === "apiKey" ? {
|
|
16534
16526
|
apiKey: this._auth.apiKey,
|
|
16535
16527
|
type: "apiKey",
|
|
16528
|
+
url: httpToWsUrl(this.apiUrl),
|
|
16536
16529
|
timeoutInMs: params.timeoutInMs,
|
|
16537
|
-
proxyAgent:
|
|
16530
|
+
proxyAgent: getProxyAgent(this.apiUrl)
|
|
16538
16531
|
} : {
|
|
16539
16532
|
token: this._auth.token,
|
|
16540
16533
|
type: "token",
|
|
16534
|
+
url: httpToWsUrl(this.apiUrl),
|
|
16541
16535
|
timeoutInMs: params.timeoutInMs,
|
|
16542
|
-
proxyAgent:
|
|
16536
|
+
proxyAgent: getProxyAgent(this.apiUrl)
|
|
16543
16537
|
}
|
|
16544
16538
|
);
|
|
16545
16539
|
}
|
|
@@ -24732,13 +24726,13 @@ var parseArgs = async (args) => {
|
|
|
24732
24726
|
};
|
|
24733
24727
|
|
|
24734
24728
|
// src/index.ts
|
|
24735
|
-
var
|
|
24729
|
+
var debug20 = Debug20("mobbdev:index");
|
|
24736
24730
|
async function run() {
|
|
24737
24731
|
return parseArgs(hideBin(process.argv));
|
|
24738
24732
|
}
|
|
24739
24733
|
(async () => {
|
|
24740
24734
|
try {
|
|
24741
|
-
|
|
24735
|
+
debug20("Bugsy CLI v%s running...", packageJson.version);
|
|
24742
24736
|
await run();
|
|
24743
24737
|
process.exit(0);
|
|
24744
24738
|
} catch (err) {
|