mobbdev 1.0.177 → 1.0.178
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/index.mjs +547 -155
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -32,7 +32,7 @@ var init_env = __esm({
|
|
|
32
32
|
});
|
|
33
33
|
|
|
34
34
|
// src/mcp/core/configs.ts
|
|
35
|
-
var MCP_DEFAULT_API_URL, MCP_API_KEY_HEADER_NAME, MCP_LOGIN_MAX_WAIT, MCP_LOGIN_CHECK_DELAY, MCP_VUL_REPORT_DIGEST_TIMEOUT_MS, MCP_MAX_FILE_SIZE, MCP_PERIODIC_CHECK_INTERVAL, MCP_DEFAULT_MAX_FILES_TO_SCAN, MCP_REPORT_ID_EXPIRATION_MS, MCP_TOOLS_BROWSER_COOLDOWN_MS, MCP_DEFAULT_LIMIT, isAutoScan, MVS_AUTO_FIX_OVERRIDE, MCP_AUTO_FIX_DEBUG_MODE;
|
|
35
|
+
var MCP_DEFAULT_API_URL, MCP_API_KEY_HEADER_NAME, MCP_LOGIN_MAX_WAIT, MCP_LOGIN_CHECK_DELAY, MCP_VUL_REPORT_DIGEST_TIMEOUT_MS, MCP_MAX_FILE_SIZE, MCP_PERIODIC_CHECK_INTERVAL, MCP_DEFAULT_MAX_FILES_TO_SCAN, MCP_REPORT_ID_EXPIRATION_MS, MCP_TOOLS_BROWSER_COOLDOWN_MS, MCP_DEFAULT_LIMIT, isAutoScan, MVS_AUTO_FIX_OVERRIDE, MCP_AUTO_FIX_DEBUG_MODE, MCP_PERIODIC_TRACK_INTERVAL, MCP_DEFAULT_REST_API_URL;
|
|
36
36
|
var init_configs = __esm({
|
|
37
37
|
"src/mcp/core/configs.ts"() {
|
|
38
38
|
"use strict";
|
|
@@ -51,6 +51,8 @@ var init_configs = __esm({
|
|
|
51
51
|
isAutoScan = process.env["AUTO_SCAN"] !== "false";
|
|
52
52
|
MVS_AUTO_FIX_OVERRIDE = process.env["MVS_AUTO_FIX"];
|
|
53
53
|
MCP_AUTO_FIX_DEBUG_MODE = true;
|
|
54
|
+
MCP_PERIODIC_TRACK_INTERVAL = 60 * 60 * 1e3;
|
|
55
|
+
MCP_DEFAULT_REST_API_URL = "https://api.mobb.ai/api/rest/mcp/track";
|
|
54
56
|
}
|
|
55
57
|
});
|
|
56
58
|
|
|
@@ -6373,7 +6375,7 @@ async function getAdoSdk(params) {
|
|
|
6373
6375
|
const url = new URL(repoUrl);
|
|
6374
6376
|
const origin2 = url.origin.toLowerCase().endsWith(".visualstudio.com") ? DEFUALT_ADO_ORIGIN : url.origin.toLowerCase();
|
|
6375
6377
|
const params2 = `path=/&versionDescriptor[versionOptions]=0&versionDescriptor[versionType]=commit&versionDescriptor[version]=${branch}&resolveLfs=true&$format=zip&api-version=5.0&download=true`;
|
|
6376
|
-
const
|
|
6378
|
+
const path16 = [
|
|
6377
6379
|
prefixPath,
|
|
6378
6380
|
owner,
|
|
6379
6381
|
projectName,
|
|
@@ -6384,7 +6386,7 @@ async function getAdoSdk(params) {
|
|
|
6384
6386
|
"items",
|
|
6385
6387
|
"items"
|
|
6386
6388
|
].filter(Boolean).join("/");
|
|
6387
|
-
return new URL(`${
|
|
6389
|
+
return new URL(`${path16}?${params2}`, origin2).toString();
|
|
6388
6390
|
},
|
|
6389
6391
|
async getAdoBranchList({ repoUrl }) {
|
|
6390
6392
|
try {
|
|
@@ -7839,14 +7841,14 @@ function getGithubSdk(params = {}) {
|
|
|
7839
7841
|
};
|
|
7840
7842
|
},
|
|
7841
7843
|
async getGithubBlameRanges(params2) {
|
|
7842
|
-
const { ref, gitHubUrl, path:
|
|
7844
|
+
const { ref, gitHubUrl, path: path16 } = params2;
|
|
7843
7845
|
const { owner, repo } = parseGithubOwnerAndRepo(gitHubUrl);
|
|
7844
7846
|
const res = await octokit.graphql(
|
|
7845
7847
|
GET_BLAME_DOCUMENT,
|
|
7846
7848
|
{
|
|
7847
7849
|
owner,
|
|
7848
7850
|
repo,
|
|
7849
|
-
path:
|
|
7851
|
+
path: path16,
|
|
7850
7852
|
ref
|
|
7851
7853
|
}
|
|
7852
7854
|
);
|
|
@@ -8153,11 +8155,11 @@ var GithubSCMLib = class extends SCMLib {
|
|
|
8153
8155
|
markdownComment: comment
|
|
8154
8156
|
});
|
|
8155
8157
|
}
|
|
8156
|
-
async getRepoBlameRanges(ref,
|
|
8158
|
+
async getRepoBlameRanges(ref, path16) {
|
|
8157
8159
|
this._validateUrl();
|
|
8158
8160
|
return await this.githubSdk.getGithubBlameRanges({
|
|
8159
8161
|
ref,
|
|
8160
|
-
path:
|
|
8162
|
+
path: path16,
|
|
8161
8163
|
gitHubUrl: this.url
|
|
8162
8164
|
});
|
|
8163
8165
|
}
|
|
@@ -8571,13 +8573,13 @@ function parseGitlabOwnerAndRepo(gitlabUrl) {
|
|
|
8571
8573
|
const { organization, repoName, projectPath } = parsingResult;
|
|
8572
8574
|
return { owner: organization, repo: repoName, projectPath };
|
|
8573
8575
|
}
|
|
8574
|
-
async function getGitlabBlameRanges({ ref, gitlabUrl, path:
|
|
8576
|
+
async function getGitlabBlameRanges({ ref, gitlabUrl, path: path16 }, options) {
|
|
8575
8577
|
const { projectPath } = parseGitlabOwnerAndRepo(gitlabUrl);
|
|
8576
8578
|
const api2 = getGitBeaker({
|
|
8577
8579
|
url: gitlabUrl,
|
|
8578
8580
|
gitlabAuthToken: options?.gitlabAuthToken
|
|
8579
8581
|
});
|
|
8580
|
-
const resp = await api2.RepositoryFiles.allFileBlames(projectPath,
|
|
8582
|
+
const resp = await api2.RepositoryFiles.allFileBlames(projectPath, path16, ref);
|
|
8581
8583
|
let lineNumber = 1;
|
|
8582
8584
|
return resp.filter((range) => range.lines).map((range) => {
|
|
8583
8585
|
const oldLineNumber = lineNumber;
|
|
@@ -8753,10 +8755,10 @@ var GitlabSCMLib = class extends SCMLib {
|
|
|
8753
8755
|
markdownComment: comment
|
|
8754
8756
|
});
|
|
8755
8757
|
}
|
|
8756
|
-
async getRepoBlameRanges(ref,
|
|
8758
|
+
async getRepoBlameRanges(ref, path16) {
|
|
8757
8759
|
this._validateUrl();
|
|
8758
8760
|
return await getGitlabBlameRanges(
|
|
8759
|
-
{ ref, path:
|
|
8761
|
+
{ ref, path: path16, gitlabUrl: this.url },
|
|
8760
8762
|
{
|
|
8761
8763
|
url: this.url,
|
|
8762
8764
|
gitlabAuthToken: this.accessToken
|
|
@@ -9834,7 +9836,7 @@ async function postIssueComment(params) {
|
|
|
9834
9836
|
fpDescription
|
|
9835
9837
|
} = params;
|
|
9836
9838
|
const {
|
|
9837
|
-
path:
|
|
9839
|
+
path: path16,
|
|
9838
9840
|
startLine,
|
|
9839
9841
|
vulnerabilityReportIssue: {
|
|
9840
9842
|
vulnerabilityReportIssueTags,
|
|
@@ -9849,7 +9851,7 @@ async function postIssueComment(params) {
|
|
|
9849
9851
|
Refresh the page in order to see the changes.`,
|
|
9850
9852
|
pull_number: pullRequest,
|
|
9851
9853
|
commit_id: commitSha,
|
|
9852
|
-
path:
|
|
9854
|
+
path: path16,
|
|
9853
9855
|
line: startLine
|
|
9854
9856
|
});
|
|
9855
9857
|
const commentId = commentRes.data.id;
|
|
@@ -9883,7 +9885,7 @@ async function postFixComment(params) {
|
|
|
9883
9885
|
scanner
|
|
9884
9886
|
} = params;
|
|
9885
9887
|
const {
|
|
9886
|
-
path:
|
|
9888
|
+
path: path16,
|
|
9887
9889
|
startLine,
|
|
9888
9890
|
vulnerabilityReportIssue: { fixId, vulnerabilityReportIssueTags, category },
|
|
9889
9891
|
vulnerabilityReportIssueId
|
|
@@ -9901,7 +9903,7 @@ async function postFixComment(params) {
|
|
|
9901
9903
|
Refresh the page in order to see the changes.`,
|
|
9902
9904
|
pull_number: pullRequest,
|
|
9903
9905
|
commit_id: commitSha,
|
|
9904
|
-
path:
|
|
9906
|
+
path: path16,
|
|
9905
9907
|
line: startLine
|
|
9906
9908
|
});
|
|
9907
9909
|
const commentId = commentRes.data.id;
|
|
@@ -10198,10 +10200,10 @@ async function getGitInfo(srcDirPath) {
|
|
|
10198
10200
|
repoUrl: void 0
|
|
10199
10201
|
};
|
|
10200
10202
|
}
|
|
10201
|
-
const
|
|
10203
|
+
const gitInfo2 = await gitService.getGitInfo();
|
|
10202
10204
|
return {
|
|
10203
10205
|
success: true,
|
|
10204
|
-
...
|
|
10206
|
+
...gitInfo2
|
|
10205
10207
|
};
|
|
10206
10208
|
} catch (e) {
|
|
10207
10209
|
if (e instanceof Error) {
|
|
@@ -10995,8 +10997,8 @@ import path8 from "path";
|
|
|
10995
10997
|
var debug15 = Debug15("mobbdev:checkmarx");
|
|
10996
10998
|
var require2 = createRequire(import.meta.url);
|
|
10997
10999
|
var getCheckmarxPath = () => {
|
|
10998
|
-
const
|
|
10999
|
-
const cxFileName =
|
|
11000
|
+
const os5 = type();
|
|
11001
|
+
const cxFileName = os5 === "Windows_NT" ? "cx.exe" : "cx";
|
|
11000
11002
|
try {
|
|
11001
11003
|
return require2.resolve(`.bin/${cxFileName}`);
|
|
11002
11004
|
} catch (e) {
|
|
@@ -11671,7 +11673,7 @@ async function _scan(params, { skipPrompts = false } = {}) {
|
|
|
11671
11673
|
text: "\u{1F4C1} Uploading Report successful!"
|
|
11672
11674
|
});
|
|
11673
11675
|
}
|
|
11674
|
-
let
|
|
11676
|
+
let gitInfo2 = { success: false };
|
|
11675
11677
|
if (reportPath) {
|
|
11676
11678
|
const vulnFiles = await _digestReport({
|
|
11677
11679
|
gqlClient,
|
|
@@ -11687,7 +11689,7 @@ async function _scan(params, { skipPrompts = false } = {}) {
|
|
|
11687
11689
|
repoUploadInfo,
|
|
11688
11690
|
isIncludeAllFiles: false
|
|
11689
11691
|
});
|
|
11690
|
-
|
|
11692
|
+
gitInfo2 = res.gitInfo;
|
|
11691
11693
|
} else {
|
|
11692
11694
|
const res = await _zipAndUploadRepo({
|
|
11693
11695
|
srcPath,
|
|
@@ -11695,7 +11697,7 @@ async function _scan(params, { skipPrompts = false } = {}) {
|
|
|
11695
11697
|
repoUploadInfo,
|
|
11696
11698
|
isIncludeAllFiles: true
|
|
11697
11699
|
});
|
|
11698
|
-
|
|
11700
|
+
gitInfo2 = res.gitInfo;
|
|
11699
11701
|
await _digestReport({
|
|
11700
11702
|
gqlClient,
|
|
11701
11703
|
fixReportId: reportUploadInfo.fixReportId,
|
|
@@ -11713,9 +11715,9 @@ async function _scan(params, { skipPrompts = false } = {}) {
|
|
|
11713
11715
|
submitVulnerabilityReportVariables: {
|
|
11714
11716
|
fixReportId: reportUploadInfo.fixReportId,
|
|
11715
11717
|
projectId,
|
|
11716
|
-
repoUrl: repo ||
|
|
11717
|
-
reference: ref ||
|
|
11718
|
-
sha: commitHash ||
|
|
11718
|
+
repoUrl: repo || gitInfo2.repoUrl || getTopLevelDirName(srcPath),
|
|
11719
|
+
reference: ref || gitInfo2.reference || "no-branch",
|
|
11720
|
+
sha: commitHash || gitInfo2.hash || "0123456789abcdef",
|
|
11719
11721
|
scanSource: _getScanSource(command, ci),
|
|
11720
11722
|
pullRequest: params.pullRequest,
|
|
11721
11723
|
experimentalEnabled: !!experimentalEnabled,
|
|
@@ -11761,11 +11763,11 @@ async function _zipAndUploadRepo({
|
|
|
11761
11763
|
const srcFileStatus = await fsPromises2.lstat(srcPath);
|
|
11762
11764
|
const zippingSpinner = createSpinner4("\u{1F4E6} Zipping repo").start();
|
|
11763
11765
|
let zipBuffer;
|
|
11764
|
-
let
|
|
11766
|
+
let gitInfo2 = { success: false };
|
|
11765
11767
|
if (srcFileStatus.isFile() && path9.extname(srcPath).toLowerCase() === ".fpr") {
|
|
11766
11768
|
zipBuffer = await repackFpr(srcPath);
|
|
11767
11769
|
} else {
|
|
11768
|
-
|
|
11770
|
+
gitInfo2 = await getGitInfo(srcPath);
|
|
11769
11771
|
zipBuffer = await pack(srcPath, vulnFiles, isIncludeAllFiles);
|
|
11770
11772
|
}
|
|
11771
11773
|
zippingSpinner.success({ text: "\u{1F4E6} Zipping repo successful!" });
|
|
@@ -11782,7 +11784,7 @@ async function _zipAndUploadRepo({
|
|
|
11782
11784
|
throw e;
|
|
11783
11785
|
}
|
|
11784
11786
|
uploadRepoSpinner.success({ text: "\u{1F4C1} Uploading Repo successful!" });
|
|
11785
|
-
return { gitInfo };
|
|
11787
|
+
return { gitInfo: gitInfo2 };
|
|
11786
11788
|
}
|
|
11787
11789
|
async function _digestReport({
|
|
11788
11790
|
gqlClient,
|
|
@@ -12283,6 +12285,29 @@ var logWarn = (message, data) => logger.log(message, "warn", data);
|
|
|
12283
12285
|
var logDebug = (message, data) => logger.log(message, "debug", data);
|
|
12284
12286
|
var log = logger.log.bind(logger);
|
|
12285
12287
|
|
|
12288
|
+
// src/mcp/services/ConfigStoreService.ts
|
|
12289
|
+
init_configs();
|
|
12290
|
+
import Configstore4 from "configstore";
|
|
12291
|
+
function createConfigStore(defaultValues = { apiToken: "" }) {
|
|
12292
|
+
const API_URL2 = process.env["API_URL"] || MCP_DEFAULT_API_URL;
|
|
12293
|
+
let domain = "";
|
|
12294
|
+
try {
|
|
12295
|
+
const url = new URL(API_URL2);
|
|
12296
|
+
domain = url.hostname;
|
|
12297
|
+
} catch (e) {
|
|
12298
|
+
domain = API_URL2.replace(/^https?:\/\//, "").replace(/\/.*$/, "").replace(/:\d+$/, "");
|
|
12299
|
+
}
|
|
12300
|
+
const sanitizedDomain = domain.replace(/\./g, "_");
|
|
12301
|
+
return new Configstore4(
|
|
12302
|
+
`${packageJson.name}-${sanitizedDomain}`,
|
|
12303
|
+
defaultValues
|
|
12304
|
+
);
|
|
12305
|
+
}
|
|
12306
|
+
function getConfigStore() {
|
|
12307
|
+
return createConfigStore();
|
|
12308
|
+
}
|
|
12309
|
+
var configStore = getConfigStore();
|
|
12310
|
+
|
|
12286
12311
|
// src/mcp/services/McpGQLClient.ts
|
|
12287
12312
|
import crypto3 from "crypto";
|
|
12288
12313
|
import { GraphQLClient as GraphQLClient2 } from "graphql-request";
|
|
@@ -12415,29 +12440,6 @@ var GetLatestReportByRepoUrlResponseSchema = z31.object({
|
|
|
12415
12440
|
expiredReport: z31.array(ExpiredReportSchema)
|
|
12416
12441
|
});
|
|
12417
12442
|
|
|
12418
|
-
// src/mcp/services/ConfigStoreService.ts
|
|
12419
|
-
init_configs();
|
|
12420
|
-
import Configstore4 from "configstore";
|
|
12421
|
-
function createConfigStore(defaultValues = { apiToken: "" }) {
|
|
12422
|
-
const API_URL2 = process.env["API_URL"] || MCP_DEFAULT_API_URL;
|
|
12423
|
-
let domain = "";
|
|
12424
|
-
try {
|
|
12425
|
-
const url = new URL(API_URL2);
|
|
12426
|
-
domain = url.hostname;
|
|
12427
|
-
} catch (e) {
|
|
12428
|
-
domain = API_URL2.replace(/^https?:\/\//, "").replace(/\/.*$/, "").replace(/:\d+$/, "");
|
|
12429
|
-
}
|
|
12430
|
-
const sanitizedDomain = domain.replace(/\./g, "_");
|
|
12431
|
-
return new Configstore4(
|
|
12432
|
-
`${packageJson.name}-${sanitizedDomain}`,
|
|
12433
|
-
defaultValues
|
|
12434
|
-
);
|
|
12435
|
-
}
|
|
12436
|
-
function getConfigStore() {
|
|
12437
|
-
return createConfigStore();
|
|
12438
|
-
}
|
|
12439
|
-
var configStore = getConfigStore();
|
|
12440
|
-
|
|
12441
12443
|
// src/mcp/services/McpAuthService.ts
|
|
12442
12444
|
import crypto2 from "crypto";
|
|
12443
12445
|
import os2 from "os";
|
|
@@ -13119,6 +13121,366 @@ async function createAuthenticatedMcpGQLClient({
|
|
|
13119
13121
|
return new McpGQLClient({ apiKey: newApiToken, type: "apiKey" });
|
|
13120
13122
|
}
|
|
13121
13123
|
|
|
13124
|
+
// src/mcp/services/McpUsageService.ts
|
|
13125
|
+
init_configs();
|
|
13126
|
+
import fetch5 from "node-fetch";
|
|
13127
|
+
import os4 from "os";
|
|
13128
|
+
import { v4 as uuidv43, v5 as uuidv5 } from "uuid";
|
|
13129
|
+
|
|
13130
|
+
// src/mcp/core/host.ts
|
|
13131
|
+
import { execSync } from "child_process";
|
|
13132
|
+
import fs10 from "fs";
|
|
13133
|
+
import os3 from "os";
|
|
13134
|
+
import path11 from "path";
|
|
13135
|
+
var IDEs = ["cursor", "windsurf", "webstorm", "vscode"];
|
|
13136
|
+
var runCommand = (cmd) => {
|
|
13137
|
+
try {
|
|
13138
|
+
return execSync(cmd, { encoding: "utf8" }).trim();
|
|
13139
|
+
} catch {
|
|
13140
|
+
return "";
|
|
13141
|
+
}
|
|
13142
|
+
};
|
|
13143
|
+
var gitInfo = {
|
|
13144
|
+
name: runCommand("git config user.name"),
|
|
13145
|
+
email: runCommand("git config user.email")
|
|
13146
|
+
};
|
|
13147
|
+
var getMCPConfigPath = (hostName) => {
|
|
13148
|
+
const home = os3.homedir();
|
|
13149
|
+
switch (hostName.toLowerCase()) {
|
|
13150
|
+
case "cursor":
|
|
13151
|
+
return path11.join(home, ".cursor", "mcp.json");
|
|
13152
|
+
case "windsurf":
|
|
13153
|
+
return path11.join(home, ".codeium", "windsurf", "mcp_config.json");
|
|
13154
|
+
case "webstorm":
|
|
13155
|
+
return "";
|
|
13156
|
+
case "visualstudiocode":
|
|
13157
|
+
case "vscode":
|
|
13158
|
+
return process.platform === "win32" ? path11.join(home, "AppData", "Roaming", "Code", "User", "mcp.json") : path11.join(
|
|
13159
|
+
home,
|
|
13160
|
+
"Library",
|
|
13161
|
+
"Application Support",
|
|
13162
|
+
"Code",
|
|
13163
|
+
"User",
|
|
13164
|
+
"mcp.json"
|
|
13165
|
+
);
|
|
13166
|
+
default:
|
|
13167
|
+
throw new Error(`Unknown hostName: ${hostName}`);
|
|
13168
|
+
}
|
|
13169
|
+
};
|
|
13170
|
+
var readMCPConfig = (hostName) => {
|
|
13171
|
+
const filePath = getMCPConfigPath(hostName);
|
|
13172
|
+
if (!fs10.existsSync(filePath)) return null;
|
|
13173
|
+
return JSON.parse(fs10.readFileSync(filePath, "utf8"));
|
|
13174
|
+
};
|
|
13175
|
+
var getRunningProcesses = () => {
|
|
13176
|
+
try {
|
|
13177
|
+
return os3.platform() === "win32" ? execSync("tasklist", { encoding: "utf8" }) : execSync("ps aux", { encoding: "utf8" });
|
|
13178
|
+
} catch {
|
|
13179
|
+
return "";
|
|
13180
|
+
}
|
|
13181
|
+
};
|
|
13182
|
+
var knownHosts = {
|
|
13183
|
+
webstorm: "WebStorm",
|
|
13184
|
+
cursor: "Cursor",
|
|
13185
|
+
windsurf: "Windsurf",
|
|
13186
|
+
code: "Vscode"
|
|
13187
|
+
};
|
|
13188
|
+
var versionCommands = {
|
|
13189
|
+
WebStorm: {
|
|
13190
|
+
darwin: [
|
|
13191
|
+
`grep -m1 '"version"' /Applications/WebStorm.app/Contents/Resources/product-info.json | cut -d'"' -f4`
|
|
13192
|
+
],
|
|
13193
|
+
win32: []
|
|
13194
|
+
},
|
|
13195
|
+
Cursor: {
|
|
13196
|
+
darwin: [
|
|
13197
|
+
"grep -A1 CFBundleVersion /Applications/Cursor.app/Contents/Info.plist | grep '<string>' | sed -E 's/.*<string>(.*)<\\/string>.*/\\1/'",
|
|
13198
|
+
"cursor --version"
|
|
13199
|
+
],
|
|
13200
|
+
win32: [
|
|
13201
|
+
'(Get-Item "$env:LOCALAPPDATA\\Programs\\cursor\\Cursor.exe").VersionInfo.ProductVersion'
|
|
13202
|
+
]
|
|
13203
|
+
},
|
|
13204
|
+
Windsurf: {
|
|
13205
|
+
darwin: [
|
|
13206
|
+
"grep -A1 CFBundleVersion /Applications/Windsurf.app/Contents/Info.plist | grep '<string>' | sed -E 's/.*<string>(.*)<\\/string>.*/\\1/'",
|
|
13207
|
+
"windsurf --version"
|
|
13208
|
+
],
|
|
13209
|
+
win32: [
|
|
13210
|
+
`(Get-Item "$env:LOCALAPPDATA\\Programs\\Windsurf\\Windsurf.exe").VersionInfo.ProductVersion`
|
|
13211
|
+
]
|
|
13212
|
+
},
|
|
13213
|
+
Vscode: {
|
|
13214
|
+
darwin: [
|
|
13215
|
+
`grep -A1 CFBundleVersion "/Applications/Visual Studio Code.app/Contents/Info.plist" | grep '<string>' | sed -E 's/.*<string>(.*)<\\/string>.*/\\1/'`,
|
|
13216
|
+
process.env["TERM_PROGRAM_VERSION"] || "Unknown"
|
|
13217
|
+
],
|
|
13218
|
+
win32: [
|
|
13219
|
+
`(Get-Item "$env:LOCALAPPDATA\\Programs\\Microsoft VS Code\\Code.exe").VersionInfo.ProductVersion`
|
|
13220
|
+
]
|
|
13221
|
+
}
|
|
13222
|
+
};
|
|
13223
|
+
var getProcessInfo = (pid) => {
|
|
13224
|
+
const platform = os3.platform();
|
|
13225
|
+
try {
|
|
13226
|
+
if (platform === "linux" || platform === "darwin") {
|
|
13227
|
+
const output = execSync(`ps -o pid=,ppid=,comm= -p ${pid}`, {
|
|
13228
|
+
stdio: ["pipe", "pipe", "ignore"]
|
|
13229
|
+
}).toString().trim();
|
|
13230
|
+
if (!output) return null;
|
|
13231
|
+
const [pidStr, ppid, ...cmd] = output.trim().split(/\s+/);
|
|
13232
|
+
return { pid: pidStr ?? "", ppid: ppid ?? "", cmd: cmd.join(" ") };
|
|
13233
|
+
} else if (platform === "win32") {
|
|
13234
|
+
const output = execSync(
|
|
13235
|
+
`powershell -Command "Get-CimInstance Win32_Process -Filter 'ProcessId=${pid}' | Select-Object ProcessId,ParentProcessId,Name | Format-Table -HideTableHeaders"`,
|
|
13236
|
+
{ stdio: ["pipe", "pipe", "ignore"] }
|
|
13237
|
+
).toString().trim();
|
|
13238
|
+
if (!output) return null;
|
|
13239
|
+
const parts = output.split(/\s+/);
|
|
13240
|
+
const pidStr = parts[0];
|
|
13241
|
+
const ppid = parts[1];
|
|
13242
|
+
const cmd = parts.slice(2).join(" ");
|
|
13243
|
+
return { pid: pidStr ?? "", ppid: ppid ?? "", cmd };
|
|
13244
|
+
} else {
|
|
13245
|
+
logWarn(`Unsupported platform: ${platform}`);
|
|
13246
|
+
return null;
|
|
13247
|
+
}
|
|
13248
|
+
} catch {
|
|
13249
|
+
return null;
|
|
13250
|
+
}
|
|
13251
|
+
};
|
|
13252
|
+
var getHostInfo = () => {
|
|
13253
|
+
const runningProcesses = getRunningProcesses().toLowerCase();
|
|
13254
|
+
const results = [];
|
|
13255
|
+
const allConfigs = {};
|
|
13256
|
+
for (const ide of IDEs) {
|
|
13257
|
+
const cfg = readMCPConfig(ide);
|
|
13258
|
+
if (cfg) allConfigs[ide] = cfg;
|
|
13259
|
+
}
|
|
13260
|
+
const servers = [];
|
|
13261
|
+
for (const [ide, cfg] of Object.entries(allConfigs)) {
|
|
13262
|
+
for (const [name, server] of Object.entries(
|
|
13263
|
+
cfg.mcpServers || cfg.servers || {}
|
|
13264
|
+
)) {
|
|
13265
|
+
servers.push({
|
|
13266
|
+
ide,
|
|
13267
|
+
name,
|
|
13268
|
+
command: server.command || "",
|
|
13269
|
+
isRunning: false
|
|
13270
|
+
});
|
|
13271
|
+
}
|
|
13272
|
+
}
|
|
13273
|
+
const runningLines = runningProcesses.split("\n");
|
|
13274
|
+
for (const line of runningLines) {
|
|
13275
|
+
if (line.includes("mcp")) {
|
|
13276
|
+
const cmdLower = line.toLowerCase();
|
|
13277
|
+
const existingServer = servers.find(
|
|
13278
|
+
(s) => s.command && cmdLower.includes(s.command.toLowerCase())
|
|
13279
|
+
);
|
|
13280
|
+
if (existingServer) {
|
|
13281
|
+
existingServer.isRunning = true;
|
|
13282
|
+
} else {
|
|
13283
|
+
let ideName = "Unknown";
|
|
13284
|
+
const foundHostKey = Object.keys(knownHosts).find(
|
|
13285
|
+
(key) => cmdLower.includes(key)
|
|
13286
|
+
);
|
|
13287
|
+
if (foundHostKey) {
|
|
13288
|
+
ideName = knownHosts[foundHostKey] || "Unknown";
|
|
13289
|
+
} else {
|
|
13290
|
+
const pidMatch = line.trim().split(/\s+/)[1];
|
|
13291
|
+
const pid = parseInt(String(pidMatch), 10);
|
|
13292
|
+
if (!isNaN(pid)) {
|
|
13293
|
+
let currentPid = pid;
|
|
13294
|
+
while (currentPid && currentPid !== 0) {
|
|
13295
|
+
const proc = getProcessInfo(currentPid);
|
|
13296
|
+
if (!proc) break;
|
|
13297
|
+
const cmdProc = proc.cmd.toLowerCase();
|
|
13298
|
+
const found = Object.keys(knownHosts).find(
|
|
13299
|
+
(key) => cmdProc.includes(key)
|
|
13300
|
+
);
|
|
13301
|
+
if (found) {
|
|
13302
|
+
ideName = knownHosts[found] || "Unknown";
|
|
13303
|
+
break;
|
|
13304
|
+
}
|
|
13305
|
+
currentPid = parseInt(proc.ppid, 10);
|
|
13306
|
+
}
|
|
13307
|
+
}
|
|
13308
|
+
}
|
|
13309
|
+
servers.push({
|
|
13310
|
+
ide: ideName.toLowerCase(),
|
|
13311
|
+
name: "unknown",
|
|
13312
|
+
command: line.trim(),
|
|
13313
|
+
isRunning: true
|
|
13314
|
+
});
|
|
13315
|
+
}
|
|
13316
|
+
}
|
|
13317
|
+
}
|
|
13318
|
+
for (const { ide, name, command, isRunning } of servers) {
|
|
13319
|
+
const config4 = allConfigs[ide] || null;
|
|
13320
|
+
const ideName = ide.charAt(0).toUpperCase() + ide.slice(1) || "Unknown";
|
|
13321
|
+
let ideVersion = "Unknown";
|
|
13322
|
+
const platform = os3.platform();
|
|
13323
|
+
const cmds = versionCommands[ideName]?.[platform] ?? [];
|
|
13324
|
+
for (const cmd of cmds) {
|
|
13325
|
+
try {
|
|
13326
|
+
const versionOutput = cmd.includes("grep") || cmd.includes("--version") || cmd.includes("sed") ? execSync(cmd, { stdio: ["pipe", "pipe", "ignore"] }).toString().split("\n")[0] ?? "" : cmd;
|
|
13327
|
+
if (versionOutput && versionOutput !== "Unknown") {
|
|
13328
|
+
ideVersion = versionOutput;
|
|
13329
|
+
break;
|
|
13330
|
+
}
|
|
13331
|
+
} catch {
|
|
13332
|
+
continue;
|
|
13333
|
+
}
|
|
13334
|
+
}
|
|
13335
|
+
let mcpConfigObj = {};
|
|
13336
|
+
if (config4) {
|
|
13337
|
+
const allServers = config4.mcpServers || config4.servers || {};
|
|
13338
|
+
if (name in allServers && allServers[name]) {
|
|
13339
|
+
mcpConfigObj = allServers[name];
|
|
13340
|
+
}
|
|
13341
|
+
}
|
|
13342
|
+
results.push({
|
|
13343
|
+
mcpName: name || command,
|
|
13344
|
+
mcpConfiguration: JSON.stringify(mcpConfigObj),
|
|
13345
|
+
ideName: ideName || "Unknown",
|
|
13346
|
+
ideVersion: ideVersion || "Unknown",
|
|
13347
|
+
isRunning
|
|
13348
|
+
});
|
|
13349
|
+
}
|
|
13350
|
+
return { mcps: results, user: gitInfo };
|
|
13351
|
+
};
|
|
13352
|
+
|
|
13353
|
+
// src/mcp/services/McpUsageService.ts
|
|
13354
|
+
var McpUsageService = class {
|
|
13355
|
+
constructor() {
|
|
13356
|
+
__publicField(this, "configKey", "mcpUsage");
|
|
13357
|
+
__publicField(this, "intervalId", null);
|
|
13358
|
+
__publicField(this, "REST_API_URL", MCP_DEFAULT_REST_API_URL);
|
|
13359
|
+
this.startPeriodicTracking();
|
|
13360
|
+
if (process.env["API_URL"]) {
|
|
13361
|
+
const url = new URL(process.env["API_URL"]);
|
|
13362
|
+
const domain = `${url.protocol}//${url.host}`;
|
|
13363
|
+
this.REST_API_URL = `${domain}/api/rest/mcp/track`;
|
|
13364
|
+
}
|
|
13365
|
+
}
|
|
13366
|
+
startPeriodicTracking() {
|
|
13367
|
+
const scanContext = ScanContext.BACKGROUND_PERIODIC;
|
|
13368
|
+
logDebug(`[${scanContext}] Starting periodic tracking for mcps`, {});
|
|
13369
|
+
this.intervalId = setInterval(async () => {
|
|
13370
|
+
logDebug(`[${scanContext}] Triggering periodic security scan`, {
|
|
13371
|
+
MCP_PERIODIC_TRACK_INTERVAL
|
|
13372
|
+
});
|
|
13373
|
+
await mcpUsageService.trackServerStart();
|
|
13374
|
+
}, 1e4);
|
|
13375
|
+
}
|
|
13376
|
+
generateHostId() {
|
|
13377
|
+
const stored = configStore.get(this.configKey);
|
|
13378
|
+
if (stored?.mcpHostId) return stored.mcpHostId;
|
|
13379
|
+
const interfaces = os4.networkInterfaces();
|
|
13380
|
+
const macs = [];
|
|
13381
|
+
for (const iface of Object.values(interfaces)) {
|
|
13382
|
+
if (!iface) continue;
|
|
13383
|
+
for (const net of iface) {
|
|
13384
|
+
if (net.mac && net.mac !== "00:00:00:00:00:00") macs.push(net.mac);
|
|
13385
|
+
}
|
|
13386
|
+
}
|
|
13387
|
+
const macString = macs.length ? macs.sort().join(",") : `${os4.hostname()}-${uuidv43()}`;
|
|
13388
|
+
const hostId = uuidv5(macString, uuidv5.DNS);
|
|
13389
|
+
logDebug("Generated new host ID", { hostId });
|
|
13390
|
+
return hostId;
|
|
13391
|
+
}
|
|
13392
|
+
getOrganizationId() {
|
|
13393
|
+
const organizationId = configStore.get("GOV-ORG-ID") || "";
|
|
13394
|
+
if (organizationId) {
|
|
13395
|
+
logDebug("Using stored organization ID", {
|
|
13396
|
+
organizationId
|
|
13397
|
+
});
|
|
13398
|
+
return organizationId;
|
|
13399
|
+
}
|
|
13400
|
+
return "";
|
|
13401
|
+
}
|
|
13402
|
+
createUsageData(mcpHostId, organizationId, status) {
|
|
13403
|
+
const { user, mcps } = getHostInfo();
|
|
13404
|
+
return {
|
|
13405
|
+
mcpHostId,
|
|
13406
|
+
organizationId,
|
|
13407
|
+
mcpVersion: packageJson.version,
|
|
13408
|
+
mcpOsName: os4.platform(),
|
|
13409
|
+
mcps: JSON.stringify(mcps),
|
|
13410
|
+
status,
|
|
13411
|
+
userName: user.name,
|
|
13412
|
+
userEmail: user.email,
|
|
13413
|
+
date: String((/* @__PURE__ */ new Date()).toISOString().split("T")[0])
|
|
13414
|
+
// it's used to make sure we track the mcp usage daily
|
|
13415
|
+
};
|
|
13416
|
+
}
|
|
13417
|
+
async trackUsage(status) {
|
|
13418
|
+
try {
|
|
13419
|
+
const hostId = this.generateHostId();
|
|
13420
|
+
const organizationId = this.getOrganizationId();
|
|
13421
|
+
if (!organizationId) {
|
|
13422
|
+
logError("Cannot track MCP usage - organization ID not available");
|
|
13423
|
+
return;
|
|
13424
|
+
}
|
|
13425
|
+
const usageData = this.createUsageData(hostId, organizationId, status);
|
|
13426
|
+
const stored = configStore.get(this.configKey);
|
|
13427
|
+
const hasChanges = !stored || Object.keys(usageData).some(
|
|
13428
|
+
(key) => usageData[key] !== stored[key]
|
|
13429
|
+
);
|
|
13430
|
+
if (!hasChanges) {
|
|
13431
|
+
logDebug(`Skipping ${status} usage tracking - no changes`);
|
|
13432
|
+
return;
|
|
13433
|
+
}
|
|
13434
|
+
logDebug("Before", { usageData });
|
|
13435
|
+
try {
|
|
13436
|
+
const res = await fetch5(this.REST_API_URL, {
|
|
13437
|
+
method: "POST",
|
|
13438
|
+
headers: {
|
|
13439
|
+
Accept: "application/json"
|
|
13440
|
+
},
|
|
13441
|
+
body: JSON.stringify({
|
|
13442
|
+
organizationId,
|
|
13443
|
+
mcps: usageData.mcps,
|
|
13444
|
+
status,
|
|
13445
|
+
osName: usageData.mcpOsName,
|
|
13446
|
+
userFullName: usageData.userName,
|
|
13447
|
+
userEmail: usageData.userEmail
|
|
13448
|
+
})
|
|
13449
|
+
});
|
|
13450
|
+
const authResult = await res.json();
|
|
13451
|
+
logDebug("Success usage data", { authResult });
|
|
13452
|
+
} catch (err) {
|
|
13453
|
+
logDebug("Error usage data", { err });
|
|
13454
|
+
}
|
|
13455
|
+
logDebug("Saving usage data", { usageData });
|
|
13456
|
+
configStore.set(this.configKey, usageData);
|
|
13457
|
+
logInfo(
|
|
13458
|
+
`MCP server ${status === "ACTIVE" ? "start" : "stop"} tracked successfully`
|
|
13459
|
+
);
|
|
13460
|
+
} catch (error) {
|
|
13461
|
+
configStore.set(this.configKey, { status: "FAILED" });
|
|
13462
|
+
logError(
|
|
13463
|
+
`Failed to track MCP server ${status === "ACTIVE" ? "start" : "stop"}`,
|
|
13464
|
+
{ error }
|
|
13465
|
+
);
|
|
13466
|
+
}
|
|
13467
|
+
}
|
|
13468
|
+
async trackServerStart() {
|
|
13469
|
+
await this.trackUsage("ACTIVE");
|
|
13470
|
+
}
|
|
13471
|
+
async trackServerStop() {
|
|
13472
|
+
await this.trackUsage("INACTIVE");
|
|
13473
|
+
}
|
|
13474
|
+
reset() {
|
|
13475
|
+
if (!this.intervalId) {
|
|
13476
|
+
return;
|
|
13477
|
+
}
|
|
13478
|
+
clearInterval(this.intervalId);
|
|
13479
|
+
this.intervalId = null;
|
|
13480
|
+
}
|
|
13481
|
+
};
|
|
13482
|
+
var mcpUsageService = new McpUsageService();
|
|
13483
|
+
|
|
13122
13484
|
// src/mcp/tools/toolNames.ts
|
|
13123
13485
|
var MCP_TOOL_CHECK_FOR_NEW_AVAILABLE_FIXES = "check_for_new_available_fixes";
|
|
13124
13486
|
var MCP_TOOL_FETCH_AVAILABLE_FIXES = "fetch_available_fixes";
|
|
@@ -13185,7 +13547,23 @@ var McpServer = class {
|
|
|
13185
13547
|
logInfo("MCP server instance created");
|
|
13186
13548
|
logDebug("MCP server instance config", { config: config4 });
|
|
13187
13549
|
}
|
|
13188
|
-
|
|
13550
|
+
async trackServerUsage(action, signalOrError) {
|
|
13551
|
+
try {
|
|
13552
|
+
if (action === "start") {
|
|
13553
|
+
await mcpUsageService.trackServerStart();
|
|
13554
|
+
}
|
|
13555
|
+
if (action === "stop") {
|
|
13556
|
+
await mcpUsageService.trackServerStop();
|
|
13557
|
+
mcpUsageService.reset();
|
|
13558
|
+
}
|
|
13559
|
+
} catch (usageError) {
|
|
13560
|
+
logWarn(`Failed to track MCP server ${action}`, {
|
|
13561
|
+
error: usageError,
|
|
13562
|
+
signalOrError
|
|
13563
|
+
});
|
|
13564
|
+
}
|
|
13565
|
+
}
|
|
13566
|
+
async handleProcessSignal({
|
|
13189
13567
|
signal,
|
|
13190
13568
|
error
|
|
13191
13569
|
}) {
|
|
@@ -13223,9 +13601,11 @@ var McpServer = class {
|
|
|
13223
13601
|
logDebug(message, { signal });
|
|
13224
13602
|
}
|
|
13225
13603
|
if (signal === "SIGINT" || signal === "SIGTERM") {
|
|
13604
|
+
await this.trackServerUsage("stop", signal);
|
|
13226
13605
|
process.exit(0);
|
|
13227
13606
|
}
|
|
13228
13607
|
if (signal === "uncaughtException") {
|
|
13608
|
+
await this.trackServerUsage("stop", signal);
|
|
13229
13609
|
process.exit(1);
|
|
13230
13610
|
}
|
|
13231
13611
|
}
|
|
@@ -13243,8 +13623,8 @@ var McpServer = class {
|
|
|
13243
13623
|
"warning"
|
|
13244
13624
|
];
|
|
13245
13625
|
signals.forEach((signal) => {
|
|
13246
|
-
const handler = (error) => {
|
|
13247
|
-
this.handleProcessSignal({ signal, error });
|
|
13626
|
+
const handler = async (error) => {
|
|
13627
|
+
await this.handleProcessSignal({ signal, error });
|
|
13248
13628
|
};
|
|
13249
13629
|
this.eventHandlers.set(signal, handler);
|
|
13250
13630
|
process.on(signal, handler);
|
|
@@ -13303,6 +13683,12 @@ var McpServer = class {
|
|
|
13303
13683
|
}
|
|
13304
13684
|
}
|
|
13305
13685
|
async handleListToolsRequest(request) {
|
|
13686
|
+
const govOrgId = configStore.get("GOV-ORG-ID") || "";
|
|
13687
|
+
if (govOrgId) {
|
|
13688
|
+
return {
|
|
13689
|
+
tools: []
|
|
13690
|
+
};
|
|
13691
|
+
}
|
|
13306
13692
|
logInfo("Received list_tools request");
|
|
13307
13693
|
logDebug("list_tools request", {
|
|
13308
13694
|
request: JSON.parse(JSON.stringify(request))
|
|
@@ -13390,6 +13776,7 @@ var McpServer = class {
|
|
|
13390
13776
|
const transport = new StdioServerTransport();
|
|
13391
13777
|
await this.server.connect(transport);
|
|
13392
13778
|
logDebug("MCP server is running on stdin/stdout");
|
|
13779
|
+
await this.trackServerUsage("start");
|
|
13393
13780
|
process.stdin.resume();
|
|
13394
13781
|
await this.createShutdownPromise();
|
|
13395
13782
|
await this.stop();
|
|
@@ -13400,6 +13787,7 @@ var McpServer = class {
|
|
|
13400
13787
|
}
|
|
13401
13788
|
async stop() {
|
|
13402
13789
|
logDebug("MCP server shutting down");
|
|
13790
|
+
await this.trackServerUsage("stop");
|
|
13403
13791
|
this.eventHandlers.forEach((handler, signal) => {
|
|
13404
13792
|
process.removeListener(signal, handler);
|
|
13405
13793
|
});
|
|
@@ -13413,8 +13801,8 @@ var McpServer = class {
|
|
|
13413
13801
|
import { z as z34 } from "zod";
|
|
13414
13802
|
|
|
13415
13803
|
// src/mcp/services/PathValidation.ts
|
|
13416
|
-
import
|
|
13417
|
-
import
|
|
13804
|
+
import fs11 from "fs";
|
|
13805
|
+
import path12 from "path";
|
|
13418
13806
|
async function validatePath(inputPath) {
|
|
13419
13807
|
logDebug("Validating MCP path", { inputPath });
|
|
13420
13808
|
if (/^\/[a-zA-Z]:\//.test(inputPath)) {
|
|
@@ -13441,7 +13829,7 @@ async function validatePath(inputPath) {
|
|
|
13441
13829
|
logError(error);
|
|
13442
13830
|
return { isValid: false, error, path: inputPath };
|
|
13443
13831
|
}
|
|
13444
|
-
const normalizedPath =
|
|
13832
|
+
const normalizedPath = path12.normalize(inputPath);
|
|
13445
13833
|
if (normalizedPath.includes("..")) {
|
|
13446
13834
|
const error = `Normalized path contains path traversal patterns: ${inputPath}`;
|
|
13447
13835
|
logError(error);
|
|
@@ -13468,7 +13856,7 @@ async function validatePath(inputPath) {
|
|
|
13468
13856
|
logDebug("Path validation successful", { inputPath });
|
|
13469
13857
|
logDebug("Checking path existence", { inputPath });
|
|
13470
13858
|
try {
|
|
13471
|
-
await
|
|
13859
|
+
await fs11.promises.access(inputPath);
|
|
13472
13860
|
logDebug("Path exists and is accessible", { inputPath });
|
|
13473
13861
|
return { isValid: true, path: inputPath };
|
|
13474
13862
|
} catch (error) {
|
|
@@ -14030,26 +14418,26 @@ ${whatHappensNextSection}`;
|
|
|
14030
14418
|
init_FileUtils();
|
|
14031
14419
|
init_GitService();
|
|
14032
14420
|
init_configs();
|
|
14033
|
-
import
|
|
14421
|
+
import fs12 from "fs/promises";
|
|
14034
14422
|
import nodePath from "path";
|
|
14035
14423
|
var getLocalFiles = async ({
|
|
14036
|
-
path:
|
|
14424
|
+
path: path16,
|
|
14037
14425
|
maxFileSize = MCP_MAX_FILE_SIZE,
|
|
14038
14426
|
maxFiles,
|
|
14039
14427
|
isAllFilesScan,
|
|
14040
14428
|
scanContext
|
|
14041
14429
|
}) => {
|
|
14042
14430
|
logDebug(`[${scanContext}] Starting getLocalFiles`, {
|
|
14043
|
-
path:
|
|
14431
|
+
path: path16,
|
|
14044
14432
|
maxFileSize,
|
|
14045
14433
|
maxFiles,
|
|
14046
14434
|
isAllFilesScan
|
|
14047
14435
|
});
|
|
14048
14436
|
try {
|
|
14049
|
-
const resolvedRepoPath = await
|
|
14437
|
+
const resolvedRepoPath = await fs12.realpath(path16);
|
|
14050
14438
|
logDebug(`[${scanContext}] Resolved repository path`, {
|
|
14051
14439
|
resolvedRepoPath,
|
|
14052
|
-
originalPath:
|
|
14440
|
+
originalPath: path16
|
|
14053
14441
|
});
|
|
14054
14442
|
const gitService = new GitService(resolvedRepoPath, log);
|
|
14055
14443
|
const gitValidation = await gitService.validateRepository();
|
|
@@ -14062,7 +14450,7 @@ var getLocalFiles = async ({
|
|
|
14062
14450
|
if (!gitValidation.isValid || isAllFilesScan) {
|
|
14063
14451
|
try {
|
|
14064
14452
|
files = await FileUtils.getLastChangedFiles({
|
|
14065
|
-
dir:
|
|
14453
|
+
dir: path16,
|
|
14066
14454
|
maxFileSize,
|
|
14067
14455
|
maxFiles,
|
|
14068
14456
|
isAllFilesScan
|
|
@@ -14126,7 +14514,7 @@ var getLocalFiles = async ({
|
|
|
14126
14514
|
absoluteFilePath
|
|
14127
14515
|
);
|
|
14128
14516
|
try {
|
|
14129
|
-
const fileStat = await
|
|
14517
|
+
const fileStat = await fs12.stat(absoluteFilePath);
|
|
14130
14518
|
return {
|
|
14131
14519
|
filename: nodePath.basename(absoluteFilePath),
|
|
14132
14520
|
relativePath,
|
|
@@ -14154,15 +14542,15 @@ var getLocalFiles = async ({
|
|
|
14154
14542
|
logError(`${scanContext}Unexpected error in getLocalFiles`, {
|
|
14155
14543
|
error: error instanceof Error ? error.message : String(error),
|
|
14156
14544
|
stack: error instanceof Error ? error.stack : void 0,
|
|
14157
|
-
path:
|
|
14545
|
+
path: path16
|
|
14158
14546
|
});
|
|
14159
14547
|
throw error;
|
|
14160
14548
|
}
|
|
14161
14549
|
};
|
|
14162
14550
|
|
|
14163
14551
|
// src/mcp/services/LocalMobbFolderService.ts
|
|
14164
|
-
import
|
|
14165
|
-
import
|
|
14552
|
+
import fs13 from "fs";
|
|
14553
|
+
import path13 from "path";
|
|
14166
14554
|
import { z as z33 } from "zod";
|
|
14167
14555
|
init_GitService();
|
|
14168
14556
|
function extractPathFromPatch(patch) {
|
|
@@ -14249,19 +14637,19 @@ var LocalMobbFolderService = class {
|
|
|
14249
14637
|
"[LocalMobbFolderService] Non-git repository detected, skipping .gitignore operations"
|
|
14250
14638
|
);
|
|
14251
14639
|
}
|
|
14252
|
-
const mobbFolderPath =
|
|
14640
|
+
const mobbFolderPath = path13.join(
|
|
14253
14641
|
this.repoPath,
|
|
14254
14642
|
this.defaultMobbFolderName
|
|
14255
14643
|
);
|
|
14256
|
-
if (!
|
|
14644
|
+
if (!fs13.existsSync(mobbFolderPath)) {
|
|
14257
14645
|
logInfo("[LocalMobbFolderService] Creating .mobb folder", {
|
|
14258
14646
|
mobbFolderPath
|
|
14259
14647
|
});
|
|
14260
|
-
|
|
14648
|
+
fs13.mkdirSync(mobbFolderPath, { recursive: true });
|
|
14261
14649
|
} else {
|
|
14262
14650
|
logDebug("[LocalMobbFolderService] .mobb folder already exists");
|
|
14263
14651
|
}
|
|
14264
|
-
const stats =
|
|
14652
|
+
const stats = fs13.statSync(mobbFolderPath);
|
|
14265
14653
|
if (!stats.isDirectory()) {
|
|
14266
14654
|
throw new Error(`Path exists but is not a directory: ${mobbFolderPath}`);
|
|
14267
14655
|
}
|
|
@@ -14302,13 +14690,13 @@ var LocalMobbFolderService = class {
|
|
|
14302
14690
|
logDebug("[LocalMobbFolderService] Git repository validated successfully");
|
|
14303
14691
|
} else {
|
|
14304
14692
|
try {
|
|
14305
|
-
const stats =
|
|
14693
|
+
const stats = fs13.statSync(this.repoPath);
|
|
14306
14694
|
if (!stats.isDirectory()) {
|
|
14307
14695
|
throw new Error(
|
|
14308
14696
|
`Path exists but is not a directory: ${this.repoPath}`
|
|
14309
14697
|
);
|
|
14310
14698
|
}
|
|
14311
|
-
|
|
14699
|
+
fs13.accessSync(this.repoPath, fs13.constants.R_OK | fs13.constants.W_OK);
|
|
14312
14700
|
logDebug(
|
|
14313
14701
|
"[LocalMobbFolderService] Non-git directory validated successfully"
|
|
14314
14702
|
);
|
|
@@ -14421,8 +14809,8 @@ var LocalMobbFolderService = class {
|
|
|
14421
14809
|
mobbFolderPath,
|
|
14422
14810
|
baseFileName
|
|
14423
14811
|
);
|
|
14424
|
-
const filePath =
|
|
14425
|
-
await
|
|
14812
|
+
const filePath = path13.join(mobbFolderPath, uniqueFileName);
|
|
14813
|
+
await fs13.promises.writeFile(filePath, patch, "utf8");
|
|
14426
14814
|
logInfo("[LocalMobbFolderService] Patch saved successfully", {
|
|
14427
14815
|
filePath,
|
|
14428
14816
|
fileName: uniqueFileName,
|
|
@@ -14479,11 +14867,11 @@ var LocalMobbFolderService = class {
|
|
|
14479
14867
|
* @returns Unique filename that doesn't conflict with existing files
|
|
14480
14868
|
*/
|
|
14481
14869
|
getUniqueFileName(folderPath, baseFileName) {
|
|
14482
|
-
const baseName =
|
|
14483
|
-
const extension =
|
|
14870
|
+
const baseName = path13.parse(baseFileName).name;
|
|
14871
|
+
const extension = path13.parse(baseFileName).ext;
|
|
14484
14872
|
let uniqueFileName = baseFileName;
|
|
14485
14873
|
let index = 1;
|
|
14486
|
-
while (
|
|
14874
|
+
while (fs13.existsSync(path13.join(folderPath, uniqueFileName))) {
|
|
14487
14875
|
uniqueFileName = `${baseName}-${index}${extension}`;
|
|
14488
14876
|
index++;
|
|
14489
14877
|
if (index > 1e3) {
|
|
@@ -14514,18 +14902,18 @@ var LocalMobbFolderService = class {
|
|
|
14514
14902
|
logDebug("[LocalMobbFolderService] Logging patch info", { fixId: fix.id });
|
|
14515
14903
|
try {
|
|
14516
14904
|
const mobbFolderPath = await this.getFolder();
|
|
14517
|
-
const patchInfoPath =
|
|
14905
|
+
const patchInfoPath = path13.join(mobbFolderPath, "patchInfo.md");
|
|
14518
14906
|
const markdownContent = this.generateFixMarkdown(fix, savedPatchFileName);
|
|
14519
14907
|
let existingContent = "";
|
|
14520
|
-
if (
|
|
14521
|
-
existingContent = await
|
|
14908
|
+
if (fs13.existsSync(patchInfoPath)) {
|
|
14909
|
+
existingContent = await fs13.promises.readFile(patchInfoPath, "utf8");
|
|
14522
14910
|
logDebug("[LocalMobbFolderService] Existing patchInfo.md found");
|
|
14523
14911
|
} else {
|
|
14524
14912
|
logDebug("[LocalMobbFolderService] Creating new patchInfo.md file");
|
|
14525
14913
|
}
|
|
14526
14914
|
const separator = existingContent ? "\n\n================================================================================\n\n" : "";
|
|
14527
14915
|
const updatedContent = `${markdownContent}${separator}${existingContent}`;
|
|
14528
|
-
await
|
|
14916
|
+
await fs13.promises.writeFile(patchInfoPath, updatedContent, "utf8");
|
|
14529
14917
|
logInfo("[LocalMobbFolderService] Patch info logged successfully", {
|
|
14530
14918
|
patchInfoPath,
|
|
14531
14919
|
fixId: fix.id,
|
|
@@ -14556,7 +14944,7 @@ var LocalMobbFolderService = class {
|
|
|
14556
14944
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
14557
14945
|
const patch = this.extractPatchFromFix(fix);
|
|
14558
14946
|
const relativePatchedFilePath = patch ? extractPathFromPatch(patch) : null;
|
|
14559
|
-
const patchedFilePath = relativePatchedFilePath ?
|
|
14947
|
+
const patchedFilePath = relativePatchedFilePath ? path13.resolve(this.repoPath, relativePatchedFilePath) : null;
|
|
14560
14948
|
const fixIdentifier = savedPatchFileName ? savedPatchFileName.replace(".patch", "") : fix.id;
|
|
14561
14949
|
let markdown = `# Fix ${fixIdentifier}
|
|
14562
14950
|
|
|
@@ -14898,16 +15286,16 @@ import {
|
|
|
14898
15286
|
unlinkSync,
|
|
14899
15287
|
writeFileSync
|
|
14900
15288
|
} from "fs";
|
|
14901
|
-
import
|
|
15289
|
+
import fs14 from "fs/promises";
|
|
14902
15290
|
import parseDiff2 from "parse-diff";
|
|
14903
|
-
import
|
|
15291
|
+
import path14 from "path";
|
|
14904
15292
|
var PatchApplicationService = class {
|
|
14905
15293
|
/**
|
|
14906
15294
|
* Gets the appropriate comment syntax for a file based on its extension
|
|
14907
15295
|
*/
|
|
14908
15296
|
static getCommentSyntax(filePath) {
|
|
14909
|
-
const ext =
|
|
14910
|
-
const basename2 =
|
|
15297
|
+
const ext = path14.extname(filePath).toLowerCase();
|
|
15298
|
+
const basename2 = path14.basename(filePath);
|
|
14911
15299
|
const commentMap = {
|
|
14912
15300
|
// C-style languages (single line comments)
|
|
14913
15301
|
".js": "//",
|
|
@@ -15117,7 +15505,7 @@ var PatchApplicationService = class {
|
|
|
15117
15505
|
}
|
|
15118
15506
|
);
|
|
15119
15507
|
}
|
|
15120
|
-
const dirPath =
|
|
15508
|
+
const dirPath = path14.dirname(filePath);
|
|
15121
15509
|
mkdirSync(dirPath, { recursive: true });
|
|
15122
15510
|
writeFileSync(filePath, finalContent, "utf8");
|
|
15123
15511
|
return filePath;
|
|
@@ -15401,9 +15789,9 @@ var PatchApplicationService = class {
|
|
|
15401
15789
|
continue;
|
|
15402
15790
|
}
|
|
15403
15791
|
try {
|
|
15404
|
-
const absolutePath =
|
|
15792
|
+
const absolutePath = path14.resolve(repositoryPath, targetFile);
|
|
15405
15793
|
if (existsSync2(absolutePath)) {
|
|
15406
|
-
const stats = await
|
|
15794
|
+
const stats = await fs14.stat(absolutePath);
|
|
15407
15795
|
const fileModTime = stats.mtime.getTime();
|
|
15408
15796
|
if (fileModTime > scanStartTime) {
|
|
15409
15797
|
logError(
|
|
@@ -15444,7 +15832,7 @@ var PatchApplicationService = class {
|
|
|
15444
15832
|
const appliedFixes = [];
|
|
15445
15833
|
const failedFixes = [];
|
|
15446
15834
|
const skippedFixes = [];
|
|
15447
|
-
const resolvedRepoPath = await
|
|
15835
|
+
const resolvedRepoPath = await fs14.realpath(repositoryPath);
|
|
15448
15836
|
logInfo(
|
|
15449
15837
|
`[${scanContext}] Starting patch application for ${fixes.length} fixes`,
|
|
15450
15838
|
{
|
|
@@ -15592,11 +15980,11 @@ var PatchApplicationService = class {
|
|
|
15592
15980
|
}) {
|
|
15593
15981
|
const sanitizedRepoPath = String(repositoryPath || "").replace("\0", "").replace(/^(\.\.(\/|\\))+/, "");
|
|
15594
15982
|
const sanitizedTargetFile = String(targetFile || "").replace("\0", "").replace(/^(\.\.(\/|\\))+/, "");
|
|
15595
|
-
const absoluteFilePath =
|
|
15983
|
+
const absoluteFilePath = path14.resolve(
|
|
15596
15984
|
sanitizedRepoPath,
|
|
15597
15985
|
sanitizedTargetFile
|
|
15598
15986
|
);
|
|
15599
|
-
const relativePath =
|
|
15987
|
+
const relativePath = path14.relative(sanitizedRepoPath, absoluteFilePath);
|
|
15600
15988
|
if (relativePath.startsWith("..")) {
|
|
15601
15989
|
throw new Error(
|
|
15602
15990
|
`Security violation: target file ${targetFile} resolves outside repository`
|
|
@@ -15630,7 +16018,7 @@ var PatchApplicationService = class {
|
|
|
15630
16018
|
fix,
|
|
15631
16019
|
scanContext
|
|
15632
16020
|
});
|
|
15633
|
-
appliedFiles.push(
|
|
16021
|
+
appliedFiles.push(path14.relative(repositoryPath, actualPath));
|
|
15634
16022
|
logDebug(`[${scanContext}] Created new file: ${relativePath}`);
|
|
15635
16023
|
}
|
|
15636
16024
|
/**
|
|
@@ -15678,7 +16066,7 @@ var PatchApplicationService = class {
|
|
|
15678
16066
|
fix,
|
|
15679
16067
|
scanContext
|
|
15680
16068
|
});
|
|
15681
|
-
appliedFiles.push(
|
|
16069
|
+
appliedFiles.push(path14.relative(repositoryPath, actualPath));
|
|
15682
16070
|
logDebug(`[${scanContext}] Modified file: ${relativePath}`);
|
|
15683
16071
|
}
|
|
15684
16072
|
}
|
|
@@ -15873,8 +16261,8 @@ init_configs();
|
|
|
15873
16261
|
|
|
15874
16262
|
// src/mcp/services/FileOperations.ts
|
|
15875
16263
|
init_FileUtils();
|
|
15876
|
-
import
|
|
15877
|
-
import
|
|
16264
|
+
import fs15 from "fs";
|
|
16265
|
+
import path15 from "path";
|
|
15878
16266
|
import AdmZip2 from "adm-zip";
|
|
15879
16267
|
var FileOperations = class {
|
|
15880
16268
|
/**
|
|
@@ -15894,10 +16282,10 @@ var FileOperations = class {
|
|
|
15894
16282
|
let packedFilesCount = 0;
|
|
15895
16283
|
const packedFiles = [];
|
|
15896
16284
|
const excludedFiles = [];
|
|
15897
|
-
const resolvedRepoPath =
|
|
16285
|
+
const resolvedRepoPath = path15.resolve(repositoryPath);
|
|
15898
16286
|
for (const filepath of fileList) {
|
|
15899
|
-
const absoluteFilepath =
|
|
15900
|
-
const resolvedFilePath =
|
|
16287
|
+
const absoluteFilepath = path15.join(repositoryPath, filepath);
|
|
16288
|
+
const resolvedFilePath = path15.resolve(absoluteFilepath);
|
|
15901
16289
|
if (!resolvedFilePath.startsWith(resolvedRepoPath)) {
|
|
15902
16290
|
const reason = "potential path traversal security risk";
|
|
15903
16291
|
logDebug(`[FileOperations] Skipping ${filepath} due to ${reason}`);
|
|
@@ -15944,11 +16332,11 @@ var FileOperations = class {
|
|
|
15944
16332
|
fileList,
|
|
15945
16333
|
repositoryPath
|
|
15946
16334
|
}) {
|
|
15947
|
-
const resolvedRepoPath =
|
|
16335
|
+
const resolvedRepoPath = path15.resolve(repositoryPath);
|
|
15948
16336
|
const validatedPaths = [];
|
|
15949
16337
|
for (const filepath of fileList) {
|
|
15950
|
-
const absoluteFilepath =
|
|
15951
|
-
const resolvedFilePath =
|
|
16338
|
+
const absoluteFilepath = path15.join(repositoryPath, filepath);
|
|
16339
|
+
const resolvedFilePath = path15.resolve(absoluteFilepath);
|
|
15952
16340
|
if (!resolvedFilePath.startsWith(resolvedRepoPath)) {
|
|
15953
16341
|
logDebug(
|
|
15954
16342
|
`[FileOperations] Rejecting ${filepath} - path traversal attempt detected`
|
|
@@ -15956,7 +16344,7 @@ var FileOperations = class {
|
|
|
15956
16344
|
continue;
|
|
15957
16345
|
}
|
|
15958
16346
|
try {
|
|
15959
|
-
await
|
|
16347
|
+
await fs15.promises.access(absoluteFilepath, fs15.constants.R_OK);
|
|
15960
16348
|
validatedPaths.push(filepath);
|
|
15961
16349
|
} catch (error) {
|
|
15962
16350
|
logDebug(
|
|
@@ -15975,8 +16363,8 @@ var FileOperations = class {
|
|
|
15975
16363
|
const fileDataArray = [];
|
|
15976
16364
|
for (const absolutePath of filePaths) {
|
|
15977
16365
|
try {
|
|
15978
|
-
const content = await
|
|
15979
|
-
const relativePath =
|
|
16366
|
+
const content = await fs15.promises.readFile(absolutePath);
|
|
16367
|
+
const relativePath = path15.basename(absolutePath);
|
|
15980
16368
|
fileDataArray.push({
|
|
15981
16369
|
relativePath,
|
|
15982
16370
|
absolutePath,
|
|
@@ -16001,7 +16389,7 @@ var FileOperations = class {
|
|
|
16001
16389
|
relativeFilepath
|
|
16002
16390
|
}) {
|
|
16003
16391
|
try {
|
|
16004
|
-
return await
|
|
16392
|
+
return await fs15.promises.readFile(absoluteFilepath);
|
|
16005
16393
|
} catch (fsError) {
|
|
16006
16394
|
logError(
|
|
16007
16395
|
`[FileOperations] Failed to read ${relativeFilepath} from filesystem: ${fsError}`
|
|
@@ -16288,14 +16676,14 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
16288
16676
|
* since the last scan.
|
|
16289
16677
|
*/
|
|
16290
16678
|
async scanForSecurityVulnerabilities({
|
|
16291
|
-
path:
|
|
16679
|
+
path: path16,
|
|
16292
16680
|
isAllDetectionRulesScan,
|
|
16293
16681
|
isAllFilesScan,
|
|
16294
16682
|
scanContext
|
|
16295
16683
|
}) {
|
|
16296
16684
|
this.hasAuthenticationFailed = false;
|
|
16297
16685
|
logDebug(`[${scanContext}] Scanning for new security vulnerabilities`, {
|
|
16298
|
-
path:
|
|
16686
|
+
path: path16
|
|
16299
16687
|
});
|
|
16300
16688
|
if (!this.gqlClient) {
|
|
16301
16689
|
logInfo(`[${scanContext}] No GQL client found, skipping scan`);
|
|
@@ -16311,10 +16699,10 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
16311
16699
|
}
|
|
16312
16700
|
logDebug(
|
|
16313
16701
|
`[${scanContext}] Connected to the API, assembling list of files to scan`,
|
|
16314
|
-
{ path:
|
|
16702
|
+
{ path: path16 }
|
|
16315
16703
|
);
|
|
16316
16704
|
const files = await getLocalFiles({
|
|
16317
|
-
path:
|
|
16705
|
+
path: path16,
|
|
16318
16706
|
isAllFilesScan,
|
|
16319
16707
|
scanContext
|
|
16320
16708
|
});
|
|
@@ -16339,13 +16727,13 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
16339
16727
|
});
|
|
16340
16728
|
const { fixReportId, projectId } = await scanFiles({
|
|
16341
16729
|
fileList: filesToScan.map((file) => file.relativePath),
|
|
16342
|
-
repositoryPath:
|
|
16730
|
+
repositoryPath: path16,
|
|
16343
16731
|
gqlClient: this.gqlClient,
|
|
16344
16732
|
isAllDetectionRulesScan,
|
|
16345
16733
|
scanContext
|
|
16346
16734
|
});
|
|
16347
16735
|
logInfo(
|
|
16348
|
-
`[${scanContext}] Security scan completed for ${
|
|
16736
|
+
`[${scanContext}] Security scan completed for ${path16} reportId: ${fixReportId} projectId: ${projectId}`
|
|
16349
16737
|
);
|
|
16350
16738
|
if (isAllFilesScan) {
|
|
16351
16739
|
return;
|
|
@@ -16639,13 +17027,13 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
16639
17027
|
});
|
|
16640
17028
|
return scannedFiles.some((file) => file.relativePath === fixFile);
|
|
16641
17029
|
}
|
|
16642
|
-
async getFreshFixes({ path:
|
|
17030
|
+
async getFreshFixes({ path: path16 }) {
|
|
16643
17031
|
const scanContext = ScanContext.USER_REQUEST;
|
|
16644
|
-
logDebug(`[${scanContext}] Getting fresh fixes`, { path:
|
|
16645
|
-
if (this.path !==
|
|
16646
|
-
this.path =
|
|
17032
|
+
logDebug(`[${scanContext}] Getting fresh fixes`, { path: path16 });
|
|
17033
|
+
if (this.path !== path16) {
|
|
17034
|
+
this.path = path16;
|
|
16647
17035
|
this.reset();
|
|
16648
|
-
logInfo(`[${scanContext}] Reset service state for new path`, { path:
|
|
17036
|
+
logInfo(`[${scanContext}] Reset service state for new path`, { path: path16 });
|
|
16649
17037
|
}
|
|
16650
17038
|
try {
|
|
16651
17039
|
this.gqlClient = await createAuthenticatedMcpGQLClient();
|
|
@@ -16663,7 +17051,7 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
16663
17051
|
}
|
|
16664
17052
|
throw error;
|
|
16665
17053
|
}
|
|
16666
|
-
this.triggerScan({ path:
|
|
17054
|
+
this.triggerScan({ path: path16, gqlClient: this.gqlClient });
|
|
16667
17055
|
let isMvsAutoFixEnabled = null;
|
|
16668
17056
|
try {
|
|
16669
17057
|
isMvsAutoFixEnabled = await this.gqlClient.getMvsAutoFixSettings();
|
|
@@ -16697,33 +17085,33 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
16697
17085
|
return noFreshFixesPrompt;
|
|
16698
17086
|
}
|
|
16699
17087
|
triggerScan({
|
|
16700
|
-
path:
|
|
17088
|
+
path: path16,
|
|
16701
17089
|
gqlClient
|
|
16702
17090
|
}) {
|
|
16703
|
-
if (this.path !==
|
|
16704
|
-
this.path =
|
|
17091
|
+
if (this.path !== path16) {
|
|
17092
|
+
this.path = path16;
|
|
16705
17093
|
this.reset();
|
|
16706
|
-
logInfo(`Reset service state for new path in triggerScan`, { path:
|
|
17094
|
+
logInfo(`Reset service state for new path in triggerScan`, { path: path16 });
|
|
16707
17095
|
}
|
|
16708
17096
|
this.gqlClient = gqlClient;
|
|
16709
17097
|
if (!this.intervalId) {
|
|
16710
|
-
this.startPeriodicScanning(
|
|
16711
|
-
this.executeInitialScan(
|
|
16712
|
-
void this.executeInitialFullScan(
|
|
17098
|
+
this.startPeriodicScanning(path16);
|
|
17099
|
+
this.executeInitialScan(path16);
|
|
17100
|
+
void this.executeInitialFullScan(path16);
|
|
16713
17101
|
}
|
|
16714
17102
|
}
|
|
16715
|
-
startPeriodicScanning(
|
|
17103
|
+
startPeriodicScanning(path16) {
|
|
16716
17104
|
const scanContext = ScanContext.BACKGROUND_PERIODIC;
|
|
16717
17105
|
logDebug(
|
|
16718
17106
|
`[${scanContext}] Starting periodic scan for new security vulnerabilities`,
|
|
16719
17107
|
{
|
|
16720
|
-
path:
|
|
17108
|
+
path: path16
|
|
16721
17109
|
}
|
|
16722
17110
|
);
|
|
16723
17111
|
this.intervalId = setInterval(() => {
|
|
16724
|
-
logDebug(`[${scanContext}] Triggering periodic security scan`, { path:
|
|
17112
|
+
logDebug(`[${scanContext}] Triggering periodic security scan`, { path: path16 });
|
|
16725
17113
|
this.scanForSecurityVulnerabilities({
|
|
16726
|
-
path:
|
|
17114
|
+
path: path16,
|
|
16727
17115
|
scanContext
|
|
16728
17116
|
}).catch((error) => {
|
|
16729
17117
|
logError(`[${scanContext}] Error during periodic security scan`, {
|
|
@@ -16732,45 +17120,45 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
16732
17120
|
});
|
|
16733
17121
|
}, MCP_PERIODIC_CHECK_INTERVAL);
|
|
16734
17122
|
}
|
|
16735
|
-
async executeInitialFullScan(
|
|
17123
|
+
async executeInitialFullScan(path16) {
|
|
16736
17124
|
const scanContext = ScanContext.FULL_SCAN;
|
|
16737
|
-
logDebug(`[${scanContext}] Triggering initial full security scan`, { path:
|
|
17125
|
+
logDebug(`[${scanContext}] Triggering initial full security scan`, { path: path16 });
|
|
16738
17126
|
logDebug(`[${scanContext}] Full scan paths scanned`, {
|
|
16739
17127
|
fullScanPathsScanned: this.fullScanPathsScanned
|
|
16740
17128
|
});
|
|
16741
|
-
if (this.fullScanPathsScanned.includes(
|
|
17129
|
+
if (this.fullScanPathsScanned.includes(path16)) {
|
|
16742
17130
|
logDebug(`[${scanContext}] Full scan already executed for this path`, {
|
|
16743
|
-
path:
|
|
17131
|
+
path: path16
|
|
16744
17132
|
});
|
|
16745
17133
|
return;
|
|
16746
17134
|
}
|
|
16747
17135
|
configStore.set("fullScanPathsScanned", [
|
|
16748
17136
|
...this.fullScanPathsScanned,
|
|
16749
|
-
|
|
17137
|
+
path16
|
|
16750
17138
|
]);
|
|
16751
17139
|
try {
|
|
16752
17140
|
await this.scanForSecurityVulnerabilities({
|
|
16753
|
-
path:
|
|
17141
|
+
path: path16,
|
|
16754
17142
|
isAllFilesScan: true,
|
|
16755
17143
|
isAllDetectionRulesScan: true,
|
|
16756
17144
|
scanContext: ScanContext.FULL_SCAN
|
|
16757
17145
|
});
|
|
16758
|
-
if (!this.fullScanPathsScanned.includes(
|
|
16759
|
-
this.fullScanPathsScanned.push(
|
|
17146
|
+
if (!this.fullScanPathsScanned.includes(path16)) {
|
|
17147
|
+
this.fullScanPathsScanned.push(path16);
|
|
16760
17148
|
configStore.set("fullScanPathsScanned", this.fullScanPathsScanned);
|
|
16761
17149
|
}
|
|
16762
|
-
logInfo(`[${scanContext}] Full scan completed`, { path:
|
|
17150
|
+
logInfo(`[${scanContext}] Full scan completed`, { path: path16 });
|
|
16763
17151
|
} catch (error) {
|
|
16764
17152
|
logError(`[${scanContext}] Error during initial full security scan`, {
|
|
16765
17153
|
error
|
|
16766
17154
|
});
|
|
16767
17155
|
}
|
|
16768
17156
|
}
|
|
16769
|
-
executeInitialScan(
|
|
17157
|
+
executeInitialScan(path16) {
|
|
16770
17158
|
const scanContext = ScanContext.BACKGROUND_INITIAL;
|
|
16771
|
-
logDebug(`[${scanContext}] Triggering initial security scan`, { path:
|
|
17159
|
+
logDebug(`[${scanContext}] Triggering initial security scan`, { path: path16 });
|
|
16772
17160
|
this.scanForSecurityVulnerabilities({
|
|
16773
|
-
path:
|
|
17161
|
+
path: path16,
|
|
16774
17162
|
scanContext: ScanContext.BACKGROUND_INITIAL
|
|
16775
17163
|
}).catch((error) => {
|
|
16776
17164
|
logError(`[${scanContext}] Error during initial security scan`, { error });
|
|
@@ -16866,9 +17254,9 @@ Example payload:
|
|
|
16866
17254
|
`Invalid path: potential security risk detected in path: ${pathValidationResult.error}`
|
|
16867
17255
|
);
|
|
16868
17256
|
}
|
|
16869
|
-
const
|
|
17257
|
+
const path16 = pathValidationResult.path;
|
|
16870
17258
|
const resultText = await this.newFixesService.getFreshFixes({
|
|
16871
|
-
path:
|
|
17259
|
+
path: path16
|
|
16872
17260
|
});
|
|
16873
17261
|
logInfo("CheckForNewAvailableFixesTool execution completed", {
|
|
16874
17262
|
resultText
|
|
@@ -17016,8 +17404,8 @@ Call this tool instead of ${MCP_TOOL_SCAN_AND_FIX_VULNERABILITIES} when you only
|
|
|
17016
17404
|
`Invalid path: potential security risk detected in path: ${pathValidationResult.error}`
|
|
17017
17405
|
);
|
|
17018
17406
|
}
|
|
17019
|
-
const
|
|
17020
|
-
const gitService = new GitService(
|
|
17407
|
+
const path16 = pathValidationResult.path;
|
|
17408
|
+
const gitService = new GitService(path16, log);
|
|
17021
17409
|
const gitValidation = await gitService.validateRepository();
|
|
17022
17410
|
if (!gitValidation.isValid) {
|
|
17023
17411
|
throw new Error(`Invalid git repository: ${gitValidation.error}`);
|
|
@@ -17283,9 +17671,9 @@ Example payload:
|
|
|
17283
17671
|
`Invalid path: potential security risk detected in path: ${pathValidationResult.error}`
|
|
17284
17672
|
);
|
|
17285
17673
|
}
|
|
17286
|
-
const
|
|
17674
|
+
const path16 = pathValidationResult.path;
|
|
17287
17675
|
const files = await getLocalFiles({
|
|
17288
|
-
path:
|
|
17676
|
+
path: path16,
|
|
17289
17677
|
maxFileSize: MCP_MAX_FILE_SIZE,
|
|
17290
17678
|
maxFiles: args.maxFiles,
|
|
17291
17679
|
scanContext: ScanContext.USER_REQUEST
|
|
@@ -17304,7 +17692,7 @@ Example payload:
|
|
|
17304
17692
|
try {
|
|
17305
17693
|
const fixResult = await this.vulnerabilityFixService.processVulnerabilities({
|
|
17306
17694
|
fileList: files.map((file) => file.relativePath),
|
|
17307
|
-
repositoryPath:
|
|
17695
|
+
repositoryPath: path16,
|
|
17308
17696
|
offset: args.offset,
|
|
17309
17697
|
limit: args.limit,
|
|
17310
17698
|
isRescan: args.rescan || !!args.maxFiles
|
|
@@ -17355,9 +17743,12 @@ function createMcpServer() {
|
|
|
17355
17743
|
logInfo("MCP server created and configured");
|
|
17356
17744
|
return server;
|
|
17357
17745
|
}
|
|
17358
|
-
async function startMcpServer(
|
|
17746
|
+
async function startMcpServer({
|
|
17747
|
+
govOrgId = ""
|
|
17748
|
+
}) {
|
|
17359
17749
|
try {
|
|
17360
17750
|
logDebug("Initializing MCP server");
|
|
17751
|
+
configStore.set("GOV-ORG-ID", govOrgId);
|
|
17361
17752
|
const server = createMcpServer();
|
|
17362
17753
|
await server.start();
|
|
17363
17754
|
} catch (error) {
|
|
@@ -17368,7 +17759,7 @@ async function startMcpServer() {
|
|
|
17368
17759
|
|
|
17369
17760
|
// src/args/commands/mcp.ts
|
|
17370
17761
|
var mcpBuilder = (yargs2) => {
|
|
17371
|
-
return yargs2.example("$0 mcp", "Launch the MCP server").option("debug", {
|
|
17762
|
+
return yargs2.example("$0 mcp", "Launch the MCP server").option("gov-org-id", organizationIdOptions).option("debug", {
|
|
17372
17763
|
alias: "d",
|
|
17373
17764
|
type: "boolean",
|
|
17374
17765
|
description: "Run in debug mode with communication logging",
|
|
@@ -17377,7 +17768,8 @@ var mcpBuilder = (yargs2) => {
|
|
|
17377
17768
|
};
|
|
17378
17769
|
var mcpHandler = async (_args) => {
|
|
17379
17770
|
try {
|
|
17380
|
-
|
|
17771
|
+
validateOrganizationId(_args.govOrgId);
|
|
17772
|
+
await startMcpServer({ govOrgId: _args.govOrgId });
|
|
17381
17773
|
} catch (error) {
|
|
17382
17774
|
console.error("Failed to start MCP server:", error);
|
|
17383
17775
|
process.exit(1);
|
|
@@ -17385,7 +17777,7 @@ var mcpHandler = async (_args) => {
|
|
|
17385
17777
|
};
|
|
17386
17778
|
|
|
17387
17779
|
// src/args/commands/review.ts
|
|
17388
|
-
import
|
|
17780
|
+
import fs16 from "fs";
|
|
17389
17781
|
import chalk9 from "chalk";
|
|
17390
17782
|
function reviewBuilder(yargs2) {
|
|
17391
17783
|
return yargs2.option("f", {
|
|
@@ -17422,7 +17814,7 @@ function reviewBuilder(yargs2) {
|
|
|
17422
17814
|
).help();
|
|
17423
17815
|
}
|
|
17424
17816
|
function validateReviewOptions(argv) {
|
|
17425
|
-
if (!
|
|
17817
|
+
if (!fs16.existsSync(argv.f)) {
|
|
17426
17818
|
throw new CliError(`
|
|
17427
17819
|
Can't access ${chalk9.bold(argv.f)}`);
|
|
17428
17820
|
}
|