mobbdev 1.0.210 → 1.0.212
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/args/commands/upload_ai_blame.d.mts +30 -28
- package/dist/args/commands/upload_ai_blame.mjs +1 -1
- package/dist/index.mjs +2203 -364
- package/package.json +11 -11
package/dist/index.mjs
CHANGED
|
@@ -51,7 +51,7 @@ 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;
|
|
54
|
+
MCP_PERIODIC_TRACK_INTERVAL = 24 * 60 * 60 * 1e3;
|
|
55
55
|
MCP_DEFAULT_REST_API_URL = "https://api.mobb.ai/api/rest/mcp/track";
|
|
56
56
|
MCP_SYSTEM_FIND_TIMEOUT_MS = 15 * 60 * 1e3;
|
|
57
57
|
}
|
|
@@ -6224,7 +6224,7 @@ async function getAdoSdk(params) {
|
|
|
6224
6224
|
const url = new URL(repoUrl);
|
|
6225
6225
|
const origin2 = url.origin.toLowerCase().endsWith(".visualstudio.com") ? DEFUALT_ADO_ORIGIN : url.origin.toLowerCase();
|
|
6226
6226
|
const params2 = `path=/&versionDescriptor[versionOptions]=0&versionDescriptor[versionType]=commit&versionDescriptor[version]=${branch}&resolveLfs=true&$format=zip&api-version=5.0&download=true`;
|
|
6227
|
-
const
|
|
6227
|
+
const path18 = [
|
|
6228
6228
|
prefixPath,
|
|
6229
6229
|
owner,
|
|
6230
6230
|
projectName,
|
|
@@ -6235,7 +6235,7 @@ async function getAdoSdk(params) {
|
|
|
6235
6235
|
"items",
|
|
6236
6236
|
"items"
|
|
6237
6237
|
].filter(Boolean).join("/");
|
|
6238
|
-
return new URL(`${
|
|
6238
|
+
return new URL(`${path18}?${params2}`, origin2).toString();
|
|
6239
6239
|
},
|
|
6240
6240
|
async getAdoBranchList({ repoUrl }) {
|
|
6241
6241
|
try {
|
|
@@ -6809,7 +6809,7 @@ function getBitbucketSdk(params) {
|
|
|
6809
6809
|
return repoRes.map((repo) => ({
|
|
6810
6810
|
repoIsPublic: !repo.is_private,
|
|
6811
6811
|
repoName: repo.name || "unknown repo name",
|
|
6812
|
-
repoOwner: repo.owner?.username || "unknown owner",
|
|
6812
|
+
repoOwner: repo.owner?.["username"] || "unknown owner",
|
|
6813
6813
|
repoLanguages: repo.language ? [repo.language] : [],
|
|
6814
6814
|
repoUpdatedAt: repo.updated_on ? repo.updated_on : (/* @__PURE__ */ new Date()).toISOString(),
|
|
6815
6815
|
repoUrl: repo.links?.html?.href || ""
|
|
@@ -7209,10 +7209,10 @@ var BitbucketSCMLib = class extends SCMLib {
|
|
|
7209
7209
|
async _getUsernameForAuthUrl() {
|
|
7210
7210
|
this._validateAccessTokenAndUrl();
|
|
7211
7211
|
const user = await this.bitbucketSdk.getUser();
|
|
7212
|
-
if (!user
|
|
7212
|
+
if (!user["username"]) {
|
|
7213
7213
|
throw new Error("no username found");
|
|
7214
7214
|
}
|
|
7215
|
-
return user
|
|
7215
|
+
return user["username"];
|
|
7216
7216
|
}
|
|
7217
7217
|
async getIsRemoteBranch(branch) {
|
|
7218
7218
|
this._validateAccessTokenAndUrl();
|
|
@@ -7233,7 +7233,7 @@ var BitbucketSCMLib = class extends SCMLib {
|
|
|
7233
7233
|
async getUsername() {
|
|
7234
7234
|
this._validateAccessToken();
|
|
7235
7235
|
const res = await this.bitbucketSdk.getUser();
|
|
7236
|
-
return z20.string().parse(res
|
|
7236
|
+
return z20.string().parse(res["username"]);
|
|
7237
7237
|
}
|
|
7238
7238
|
async getSubmitRequestStatus(_scmSubmitRequestId) {
|
|
7239
7239
|
this._validateAccessTokenAndUrl();
|
|
@@ -7564,13 +7564,33 @@ function getGithubSdk(params = {}) {
|
|
|
7564
7564
|
const { username, repoUrl } = params2;
|
|
7565
7565
|
try {
|
|
7566
7566
|
const { owner, repo } = parseGithubOwnerAndRepo(repoUrl);
|
|
7567
|
-
|
|
7568
|
-
|
|
7569
|
-
|
|
7570
|
-
|
|
7571
|
-
|
|
7572
|
-
|
|
7573
|
-
|
|
7567
|
+
try {
|
|
7568
|
+
const res = await octokit.rest.repos.checkCollaborator({
|
|
7569
|
+
owner,
|
|
7570
|
+
repo,
|
|
7571
|
+
username
|
|
7572
|
+
});
|
|
7573
|
+
if (res.status === 204) {
|
|
7574
|
+
return true;
|
|
7575
|
+
}
|
|
7576
|
+
} catch (collaboratorError) {
|
|
7577
|
+
try {
|
|
7578
|
+
const permissionRes = await octokit.rest.repos.getCollaboratorPermissionLevel({
|
|
7579
|
+
owner,
|
|
7580
|
+
repo,
|
|
7581
|
+
username
|
|
7582
|
+
});
|
|
7583
|
+
if (permissionRes.data.permission !== "none") {
|
|
7584
|
+
return true;
|
|
7585
|
+
}
|
|
7586
|
+
} catch (permissionError) {
|
|
7587
|
+
try {
|
|
7588
|
+
await octokit.rest.repos.get({ owner, repo });
|
|
7589
|
+
return true;
|
|
7590
|
+
} catch (repoError) {
|
|
7591
|
+
return false;
|
|
7592
|
+
}
|
|
7593
|
+
}
|
|
7574
7594
|
}
|
|
7575
7595
|
} catch (e) {
|
|
7576
7596
|
return false;
|
|
@@ -7645,6 +7665,9 @@ function getGithubSdk(params = {}) {
|
|
|
7645
7665
|
const repos = await octokit.rest.repos.get({ repo, owner });
|
|
7646
7666
|
return repos.data.default_branch;
|
|
7647
7667
|
},
|
|
7668
|
+
async getRepository({ owner, repo }) {
|
|
7669
|
+
return octokit.rest.repos.get({ repo, owner });
|
|
7670
|
+
},
|
|
7648
7671
|
async getGithubReferenceData({
|
|
7649
7672
|
ref,
|
|
7650
7673
|
gitHubUrl
|
|
@@ -7759,14 +7782,14 @@ function getGithubSdk(params = {}) {
|
|
|
7759
7782
|
};
|
|
7760
7783
|
},
|
|
7761
7784
|
async getGithubBlameRanges(params2) {
|
|
7762
|
-
const { ref, gitHubUrl, path:
|
|
7785
|
+
const { ref, gitHubUrl, path: path18 } = params2;
|
|
7763
7786
|
const { owner, repo } = parseGithubOwnerAndRepo(gitHubUrl);
|
|
7764
7787
|
const res = await octokit.graphql(
|
|
7765
7788
|
GET_BLAME_DOCUMENT,
|
|
7766
7789
|
{
|
|
7767
7790
|
owner,
|
|
7768
7791
|
repo,
|
|
7769
|
-
path:
|
|
7792
|
+
path: path18,
|
|
7770
7793
|
ref
|
|
7771
7794
|
}
|
|
7772
7795
|
);
|
|
@@ -7904,11 +7927,12 @@ function getGithubSdk(params = {}) {
|
|
|
7904
7927
|
return octokit.request(GET_USER);
|
|
7905
7928
|
},
|
|
7906
7929
|
async getPrCommits(params2) {
|
|
7907
|
-
|
|
7930
|
+
const data = await octokit.paginate(octokit.rest.pulls.listCommits, {
|
|
7908
7931
|
owner: params2.owner,
|
|
7909
7932
|
repo: params2.repo,
|
|
7910
7933
|
pull_number: params2.pull_number
|
|
7911
7934
|
});
|
|
7935
|
+
return { data };
|
|
7912
7936
|
},
|
|
7913
7937
|
async getUserRepos() {
|
|
7914
7938
|
return octokit.rest.repos.listForAuthenticatedUser({
|
|
@@ -7929,12 +7953,12 @@ function getGithubSdk(params = {}) {
|
|
|
7929
7953
|
});
|
|
7930
7954
|
},
|
|
7931
7955
|
async listPRFiles(params2) {
|
|
7932
|
-
|
|
7956
|
+
const data = await octokit.paginate(octokit.rest.pulls.listFiles, {
|
|
7933
7957
|
owner: params2.owner,
|
|
7934
7958
|
repo: params2.repo,
|
|
7935
|
-
pull_number: params2.pull_number
|
|
7936
|
-
per_page: 100
|
|
7959
|
+
pull_number: params2.pull_number
|
|
7937
7960
|
});
|
|
7961
|
+
return { data };
|
|
7938
7962
|
}
|
|
7939
7963
|
};
|
|
7940
7964
|
}
|
|
@@ -8107,11 +8131,11 @@ var GithubSCMLib = class extends SCMLib {
|
|
|
8107
8131
|
markdownComment: comment
|
|
8108
8132
|
});
|
|
8109
8133
|
}
|
|
8110
|
-
async getRepoBlameRanges(ref,
|
|
8134
|
+
async getRepoBlameRanges(ref, path18) {
|
|
8111
8135
|
this._validateUrl();
|
|
8112
8136
|
return await this.githubSdk.getGithubBlameRanges({
|
|
8113
8137
|
ref,
|
|
8114
|
-
path:
|
|
8138
|
+
path: path18,
|
|
8115
8139
|
gitHubUrl: this.url
|
|
8116
8140
|
});
|
|
8117
8141
|
}
|
|
@@ -8204,13 +8228,54 @@ var GithubSCMLib = class extends SCMLib {
|
|
|
8204
8228
|
commitSha
|
|
8205
8229
|
});
|
|
8206
8230
|
const commitTimestamp = commit.commit.committer?.date ? new Date(commit.commit.committer.date) : new Date(commit.commit.author?.date || Date.now());
|
|
8231
|
+
let parentCommits;
|
|
8232
|
+
if (commit.parents && commit.parents.length > 0) {
|
|
8233
|
+
try {
|
|
8234
|
+
parentCommits = await Promise.all(
|
|
8235
|
+
commit.parents.map(async (parent) => {
|
|
8236
|
+
const parentCommit = await this.githubSdk.getCommit({
|
|
8237
|
+
owner,
|
|
8238
|
+
repo,
|
|
8239
|
+
commitSha: parent.sha
|
|
8240
|
+
});
|
|
8241
|
+
const parentTimestamp = parentCommit.data.committer?.date ? new Date(parentCommit.data.committer.date) : new Date(Date.now());
|
|
8242
|
+
return {
|
|
8243
|
+
sha: parent.sha,
|
|
8244
|
+
timestamp: parentTimestamp
|
|
8245
|
+
};
|
|
8246
|
+
})
|
|
8247
|
+
);
|
|
8248
|
+
} catch (error) {
|
|
8249
|
+
console.error("Failed to fetch parent commit timestamps", {
|
|
8250
|
+
error,
|
|
8251
|
+
commitSha,
|
|
8252
|
+
owner,
|
|
8253
|
+
repo
|
|
8254
|
+
});
|
|
8255
|
+
parentCommits = void 0;
|
|
8256
|
+
}
|
|
8257
|
+
}
|
|
8258
|
+
let repositoryCreatedAt;
|
|
8259
|
+
try {
|
|
8260
|
+
const repoData = await this.githubSdk.getRepository({ owner, repo });
|
|
8261
|
+
repositoryCreatedAt = repoData.data.created_at ? new Date(repoData.data.created_at) : void 0;
|
|
8262
|
+
} catch (error) {
|
|
8263
|
+
console.error("Failed to fetch repository creation date", {
|
|
8264
|
+
error,
|
|
8265
|
+
owner,
|
|
8266
|
+
repo
|
|
8267
|
+
});
|
|
8268
|
+
repositoryCreatedAt = void 0;
|
|
8269
|
+
}
|
|
8207
8270
|
return {
|
|
8208
8271
|
diff,
|
|
8209
8272
|
commitTimestamp,
|
|
8210
8273
|
commitSha: commit.sha,
|
|
8211
8274
|
authorName: commit.commit.author?.name,
|
|
8212
8275
|
authorEmail: commit.commit.author?.email,
|
|
8213
|
-
message: commit.commit.message
|
|
8276
|
+
message: commit.commit.message,
|
|
8277
|
+
parentCommits,
|
|
8278
|
+
repositoryCreatedAt
|
|
8214
8279
|
};
|
|
8215
8280
|
}
|
|
8216
8281
|
async getSubmitRequestDiff(submitRequestId) {
|
|
@@ -8750,13 +8815,13 @@ function parseGitlabOwnerAndRepo(gitlabUrl) {
|
|
|
8750
8815
|
const { organization, repoName, projectPath } = parsingResult;
|
|
8751
8816
|
return { owner: organization, repo: repoName, projectPath };
|
|
8752
8817
|
}
|
|
8753
|
-
async function getGitlabBlameRanges({ ref, gitlabUrl, path:
|
|
8818
|
+
async function getGitlabBlameRanges({ ref, gitlabUrl, path: path18 }, options) {
|
|
8754
8819
|
const { projectPath } = parseGitlabOwnerAndRepo(gitlabUrl);
|
|
8755
8820
|
const api2 = getGitBeaker({
|
|
8756
8821
|
url: gitlabUrl,
|
|
8757
8822
|
gitlabAuthToken: options?.gitlabAuthToken
|
|
8758
8823
|
});
|
|
8759
|
-
const resp = await api2.RepositoryFiles.allFileBlames(projectPath,
|
|
8824
|
+
const resp = await api2.RepositoryFiles.allFileBlames(projectPath, path18, ref);
|
|
8760
8825
|
let lineNumber = 1;
|
|
8761
8826
|
return resp.filter((range) => range.lines).map((range) => {
|
|
8762
8827
|
const oldLineNumber = lineNumber;
|
|
@@ -8933,10 +8998,10 @@ var GitlabSCMLib = class extends SCMLib {
|
|
|
8933
8998
|
markdownComment: comment
|
|
8934
8999
|
});
|
|
8935
9000
|
}
|
|
8936
|
-
async getRepoBlameRanges(ref,
|
|
9001
|
+
async getRepoBlameRanges(ref, path18) {
|
|
8937
9002
|
this._validateUrl();
|
|
8938
9003
|
return await getGitlabBlameRanges(
|
|
8939
|
-
{ ref, path:
|
|
9004
|
+
{ ref, path: path18, gitlabUrl: this.url },
|
|
8940
9005
|
{
|
|
8941
9006
|
url: this.url,
|
|
8942
9007
|
gitlabAuthToken: this.accessToken
|
|
@@ -10968,7 +11033,7 @@ async function postIssueComment(params) {
|
|
|
10968
11033
|
fpDescription
|
|
10969
11034
|
} = params;
|
|
10970
11035
|
const {
|
|
10971
|
-
path:
|
|
11036
|
+
path: path18,
|
|
10972
11037
|
startLine,
|
|
10973
11038
|
vulnerabilityReportIssue: {
|
|
10974
11039
|
vulnerabilityReportIssueTags,
|
|
@@ -10983,7 +11048,7 @@ async function postIssueComment(params) {
|
|
|
10983
11048
|
Refresh the page in order to see the changes.`,
|
|
10984
11049
|
pull_number: pullRequest,
|
|
10985
11050
|
commit_id: commitSha,
|
|
10986
|
-
path:
|
|
11051
|
+
path: path18,
|
|
10987
11052
|
line: startLine
|
|
10988
11053
|
});
|
|
10989
11054
|
const commentId = commentRes.data.id;
|
|
@@ -11017,7 +11082,7 @@ async function postFixComment(params) {
|
|
|
11017
11082
|
scanner
|
|
11018
11083
|
} = params;
|
|
11019
11084
|
const {
|
|
11020
|
-
path:
|
|
11085
|
+
path: path18,
|
|
11021
11086
|
startLine,
|
|
11022
11087
|
vulnerabilityReportIssue: { fixId, vulnerabilityReportIssueTags, category },
|
|
11023
11088
|
vulnerabilityReportIssueId
|
|
@@ -11035,7 +11100,7 @@ async function postFixComment(params) {
|
|
|
11035
11100
|
Refresh the page in order to see the changes.`,
|
|
11036
11101
|
pull_number: pullRequest,
|
|
11037
11102
|
commit_id: commitSha,
|
|
11038
|
-
path:
|
|
11103
|
+
path: path18,
|
|
11039
11104
|
line: startLine
|
|
11040
11105
|
});
|
|
11041
11106
|
const commentId = commentRes.data.id;
|
|
@@ -12779,6 +12844,8 @@ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
|
12779
12844
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
12780
12845
|
import {
|
|
12781
12846
|
CallToolRequestSchema,
|
|
12847
|
+
GetPromptRequestSchema,
|
|
12848
|
+
ListPromptsRequestSchema,
|
|
12782
12849
|
ListToolsRequestSchema
|
|
12783
12850
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
12784
12851
|
|
|
@@ -12791,8 +12858,8 @@ var WorkspaceService = class {
|
|
|
12791
12858
|
* Sets a known workspace path that was discovered through successful validation
|
|
12792
12859
|
* @param path The validated workspace path to store
|
|
12793
12860
|
*/
|
|
12794
|
-
static setKnownWorkspacePath(
|
|
12795
|
-
this.knownWorkspacePath =
|
|
12861
|
+
static setKnownWorkspacePath(path18) {
|
|
12862
|
+
this.knownWorkspacePath = path18;
|
|
12796
12863
|
}
|
|
12797
12864
|
/**
|
|
12798
12865
|
* Gets the known workspace path that was previously validated
|
|
@@ -14040,10 +14107,10 @@ var getHostInfo = (additionalMcpList) => {
|
|
|
14040
14107
|
const ideConfigPaths = /* @__PURE__ */ new Set();
|
|
14041
14108
|
for (const ide of IDEs) {
|
|
14042
14109
|
const configPaths = getMCPConfigPaths(ide);
|
|
14043
|
-
configPaths.forEach((
|
|
14110
|
+
configPaths.forEach((path18) => ideConfigPaths.add(path18));
|
|
14044
14111
|
}
|
|
14045
14112
|
const uniqueAdditionalPaths = additionalMcpList.filter(
|
|
14046
|
-
(
|
|
14113
|
+
(path18) => !ideConfigPaths.has(path18)
|
|
14047
14114
|
);
|
|
14048
14115
|
for (const ide of IDEs) {
|
|
14049
14116
|
const cfg = readMCPConfig(ide);
|
|
@@ -14163,78 +14230,68 @@ init_configs();
|
|
|
14163
14230
|
|
|
14164
14231
|
// src/mcp/services/McpUsageService/system.ts
|
|
14165
14232
|
init_configs();
|
|
14166
|
-
import
|
|
14233
|
+
import fs12 from "fs";
|
|
14167
14234
|
import os4 from "os";
|
|
14235
|
+
import path12 from "path";
|
|
14236
|
+
var MAX_DEPTH = 2;
|
|
14237
|
+
var patterns = ["mcp", "claude"];
|
|
14238
|
+
var isFileMatch = (fileName) => {
|
|
14239
|
+
const lowerName = fileName.toLowerCase();
|
|
14240
|
+
return lowerName.endsWith(".json") && patterns.some((p) => lowerName.includes(p.toLowerCase()));
|
|
14241
|
+
};
|
|
14242
|
+
var safeAccess = async (filePath) => {
|
|
14243
|
+
try {
|
|
14244
|
+
await fs12.promises.access(filePath, fs12.constants.R_OK);
|
|
14245
|
+
return true;
|
|
14246
|
+
} catch {
|
|
14247
|
+
return false;
|
|
14248
|
+
}
|
|
14249
|
+
};
|
|
14250
|
+
var searchDir = async (dir, depth = 0) => {
|
|
14251
|
+
const results = [];
|
|
14252
|
+
if (depth > MAX_DEPTH) return results;
|
|
14253
|
+
const entries = await fs12.promises.readdir(dir, { withFileTypes: true }).catch(() => []);
|
|
14254
|
+
for (const entry of entries) {
|
|
14255
|
+
const fullPath = path12.join(dir, entry.name);
|
|
14256
|
+
if (entry.isFile() && isFileMatch(entry.name)) {
|
|
14257
|
+
results.push(fullPath);
|
|
14258
|
+
} else if (entry.isDirectory()) {
|
|
14259
|
+
if (await safeAccess(fullPath)) {
|
|
14260
|
+
const subResults = await searchDir(fullPath, depth + 1);
|
|
14261
|
+
results.push(...subResults);
|
|
14262
|
+
}
|
|
14263
|
+
}
|
|
14264
|
+
}
|
|
14265
|
+
return results;
|
|
14266
|
+
};
|
|
14168
14267
|
var findSystemMCPConfigs = async () => {
|
|
14169
14268
|
try {
|
|
14269
|
+
const home = os4.homedir();
|
|
14170
14270
|
const platform = os4.platform();
|
|
14171
|
-
|
|
14172
|
-
|
|
14173
|
-
|
|
14174
|
-
|
|
14175
|
-
|
|
14176
|
-
|
|
14177
|
-
|
|
14178
|
-
|
|
14179
|
-
|
|
14180
|
-
|
|
14181
|
-
|
|
14182
|
-
|
|
14183
|
-
args = [
|
|
14184
|
-
home,
|
|
14185
|
-
"-type",
|
|
14186
|
-
"f",
|
|
14187
|
-
"(",
|
|
14188
|
-
"-iname",
|
|
14189
|
-
"*mcp*.json",
|
|
14190
|
-
"-o",
|
|
14191
|
-
"-iname",
|
|
14192
|
-
"*claude*.json",
|
|
14193
|
-
")"
|
|
14194
|
-
];
|
|
14195
|
-
}
|
|
14196
|
-
return await new Promise((resolve) => {
|
|
14197
|
-
const child = spawn(command, args, {
|
|
14198
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
14199
|
-
shell: platform === "win32"
|
|
14200
|
-
// needed for PowerShell
|
|
14201
|
-
});
|
|
14202
|
-
let output = "";
|
|
14203
|
-
let errorOutput = "";
|
|
14204
|
-
const timer = setTimeout(() => {
|
|
14205
|
-
child.kill("SIGTERM");
|
|
14271
|
+
const knownDirs = platform === "win32" ? [
|
|
14272
|
+
path12.join(home, ".cursor"),
|
|
14273
|
+
path12.join(home, "Documents"),
|
|
14274
|
+
path12.join(home, "Downloads")
|
|
14275
|
+
] : [
|
|
14276
|
+
path12.join(home, ".cursor"),
|
|
14277
|
+
process.env["XDG_CONFIG_HOME"] || path12.join(home, ".config"),
|
|
14278
|
+
path12.join(home, "Documents"),
|
|
14279
|
+
path12.join(home, "Downloads")
|
|
14280
|
+
];
|
|
14281
|
+
const timeoutPromise = new Promise(
|
|
14282
|
+
(resolve) => setTimeout(() => {
|
|
14206
14283
|
logWarn(
|
|
14207
14284
|
`MCP config search timed out after ${MCP_SYSTEM_FIND_TIMEOUT_MS / 1e3}s`
|
|
14208
14285
|
);
|
|
14209
14286
|
resolve([]);
|
|
14210
|
-
}, MCP_SYSTEM_FIND_TIMEOUT_MS)
|
|
14211
|
-
|
|
14212
|
-
|
|
14213
|
-
|
|
14214
|
-
|
|
14215
|
-
|
|
14216
|
-
|
|
14217
|
-
|
|
14218
|
-
}
|
|
14219
|
-
});
|
|
14220
|
-
child.on("error", (err) => {
|
|
14221
|
-
clearTimeout(timer);
|
|
14222
|
-
logWarn("MCP config search failed to start", { err });
|
|
14223
|
-
resolve([]);
|
|
14224
|
-
});
|
|
14225
|
-
child.on("close", (code) => {
|
|
14226
|
-
clearTimeout(timer);
|
|
14227
|
-
if (code === 0 || output.trim().length > 0) {
|
|
14228
|
-
const files = output.split(/\r?\n/).map((f) => f.trim()).filter(Boolean);
|
|
14229
|
-
resolve(files);
|
|
14230
|
-
} else {
|
|
14231
|
-
if (errorOutput.trim().length > 0) {
|
|
14232
|
-
logWarn("MCP config search finished with warnings", { errorOutput });
|
|
14233
|
-
}
|
|
14234
|
-
resolve([]);
|
|
14235
|
-
}
|
|
14236
|
-
});
|
|
14237
|
-
});
|
|
14287
|
+
}, MCP_SYSTEM_FIND_TIMEOUT_MS)
|
|
14288
|
+
);
|
|
14289
|
+
const searchPromise = Promise.all(
|
|
14290
|
+
knownDirs.map(
|
|
14291
|
+
(dir) => fs12.existsSync(dir) ? searchDir(dir) : Promise.resolve([])
|
|
14292
|
+
)
|
|
14293
|
+
).then((results) => results.flat());
|
|
14294
|
+
return await Promise.race([timeoutPromise, searchPromise]);
|
|
14238
14295
|
} catch (err) {
|
|
14239
14296
|
logWarn("MCP config search unexpected error", { err });
|
|
14240
14297
|
return [];
|
|
@@ -14409,6 +14466,45 @@ var MCP_TOOL_CHECKER = "mcp_checker";
|
|
|
14409
14466
|
// src/mcp/core/McpServer.ts
|
|
14410
14467
|
init_configs();
|
|
14411
14468
|
|
|
14469
|
+
// src/mcp/core/PromptRegistry.ts
|
|
14470
|
+
var PromptRegistry = class {
|
|
14471
|
+
constructor() {
|
|
14472
|
+
__publicField(this, "prompts", /* @__PURE__ */ new Map());
|
|
14473
|
+
}
|
|
14474
|
+
registerPrompt(prompt) {
|
|
14475
|
+
if (this.prompts.has(prompt.name)) {
|
|
14476
|
+
logWarn(`Prompt ${prompt.name} is already registered, overwriting`, {
|
|
14477
|
+
promptName: prompt.name
|
|
14478
|
+
});
|
|
14479
|
+
}
|
|
14480
|
+
this.prompts.set(prompt.name, prompt);
|
|
14481
|
+
logDebug(`Prompt registered: ${prompt.name}`, {
|
|
14482
|
+
promptName: prompt.name,
|
|
14483
|
+
description: prompt.description
|
|
14484
|
+
});
|
|
14485
|
+
}
|
|
14486
|
+
getPrompt(name) {
|
|
14487
|
+
return this.prompts.get(name);
|
|
14488
|
+
}
|
|
14489
|
+
getPromptDefinition(name) {
|
|
14490
|
+
return this.prompts.get(name)?.getDefinition();
|
|
14491
|
+
}
|
|
14492
|
+
getAllPrompts() {
|
|
14493
|
+
return Array.from(this.prompts.values()).map(
|
|
14494
|
+
(prompt) => prompt.getDefinition()
|
|
14495
|
+
);
|
|
14496
|
+
}
|
|
14497
|
+
getPromptNames() {
|
|
14498
|
+
return Array.from(this.prompts.keys());
|
|
14499
|
+
}
|
|
14500
|
+
hasPrompt(name) {
|
|
14501
|
+
return this.prompts.has(name);
|
|
14502
|
+
}
|
|
14503
|
+
getPromptCount() {
|
|
14504
|
+
return this.prompts.size;
|
|
14505
|
+
}
|
|
14506
|
+
};
|
|
14507
|
+
|
|
14412
14508
|
// src/mcp/core/ToolRegistry.ts
|
|
14413
14509
|
var ToolRegistry = class {
|
|
14414
14510
|
constructor() {
|
|
@@ -14451,6 +14547,7 @@ var McpServer = class {
|
|
|
14451
14547
|
constructor(config6, govOrgId = "") {
|
|
14452
14548
|
__publicField(this, "server");
|
|
14453
14549
|
__publicField(this, "toolRegistry");
|
|
14550
|
+
__publicField(this, "promptRegistry");
|
|
14454
14551
|
__publicField(this, "isEventHandlersSetup", false);
|
|
14455
14552
|
__publicField(this, "eventHandlers", /* @__PURE__ */ new Map());
|
|
14456
14553
|
__publicField(this, "parentProcessCheckInterval");
|
|
@@ -14466,11 +14563,13 @@ var McpServer = class {
|
|
|
14466
14563
|
},
|
|
14467
14564
|
{
|
|
14468
14565
|
capabilities: {
|
|
14469
|
-
tools: {}
|
|
14566
|
+
tools: {},
|
|
14567
|
+
prompts: {}
|
|
14470
14568
|
}
|
|
14471
14569
|
}
|
|
14472
14570
|
);
|
|
14473
14571
|
this.toolRegistry = new ToolRegistry();
|
|
14572
|
+
this.promptRegistry = new PromptRegistry();
|
|
14474
14573
|
this.setupHandlers();
|
|
14475
14574
|
this.setupProcessEventHandlers();
|
|
14476
14575
|
this.setupParentProcessMonitoring();
|
|
@@ -14787,6 +14886,62 @@ var McpServer = class {
|
|
|
14787
14886
|
throw error;
|
|
14788
14887
|
}
|
|
14789
14888
|
}
|
|
14889
|
+
async handleListPromptsRequest(request) {
|
|
14890
|
+
const mcpCheckerTool = this.toolRegistry.getToolDefinition(MCP_TOOL_CHECKER);
|
|
14891
|
+
if (mcpCheckerTool) {
|
|
14892
|
+
return {
|
|
14893
|
+
prompts: []
|
|
14894
|
+
};
|
|
14895
|
+
}
|
|
14896
|
+
logInfo("Received list_prompts request");
|
|
14897
|
+
logDebug("list_prompts request", {
|
|
14898
|
+
request: JSON.parse(JSON.stringify(request))
|
|
14899
|
+
});
|
|
14900
|
+
const promptDefinitions = this.promptRegistry.getAllPrompts();
|
|
14901
|
+
const response = {
|
|
14902
|
+
prompts: promptDefinitions.map((prompt) => ({
|
|
14903
|
+
name: prompt.name,
|
|
14904
|
+
description: prompt.description,
|
|
14905
|
+
arguments: prompt.arguments
|
|
14906
|
+
}))
|
|
14907
|
+
};
|
|
14908
|
+
logDebug("Returning list_prompts response", { response });
|
|
14909
|
+
return response;
|
|
14910
|
+
}
|
|
14911
|
+
async handleGetPromptRequest(request) {
|
|
14912
|
+
const { name, arguments: args } = request.params;
|
|
14913
|
+
logInfo(`Received get_prompt request for ${name}`);
|
|
14914
|
+
logDebug("get_prompt request", {
|
|
14915
|
+
request: JSON.parse(JSON.stringify(request))
|
|
14916
|
+
});
|
|
14917
|
+
try {
|
|
14918
|
+
const prompt = this.promptRegistry.getPrompt(name);
|
|
14919
|
+
if (!prompt) {
|
|
14920
|
+
const errorMsg = `Unknown prompt: ${name}`;
|
|
14921
|
+
logWarn(errorMsg, {
|
|
14922
|
+
name,
|
|
14923
|
+
availablePrompts: this.promptRegistry.getPromptNames()
|
|
14924
|
+
});
|
|
14925
|
+
throw new Error(errorMsg);
|
|
14926
|
+
}
|
|
14927
|
+
logInfo(`Generating prompt: ${name}`);
|
|
14928
|
+
const response = await prompt.getPrompt(args);
|
|
14929
|
+
logInfo(`Prompt ${name} generated successfully`);
|
|
14930
|
+
logDebug(`Prompt ${name} generated successfully`, {
|
|
14931
|
+
hasMessages: !!response.messages,
|
|
14932
|
+
messageCount: response.messages?.length
|
|
14933
|
+
});
|
|
14934
|
+
return response;
|
|
14935
|
+
} catch (error) {
|
|
14936
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
14937
|
+
logError(`Error generating prompt ${name}: ${errorMessage}`, {
|
|
14938
|
+
error,
|
|
14939
|
+
promptName: name,
|
|
14940
|
+
args
|
|
14941
|
+
});
|
|
14942
|
+
throw error;
|
|
14943
|
+
}
|
|
14944
|
+
}
|
|
14790
14945
|
setupHandlers() {
|
|
14791
14946
|
this.server.setRequestHandler(
|
|
14792
14947
|
ListToolsRequestSchema,
|
|
@@ -14796,12 +14951,24 @@ var McpServer = class {
|
|
|
14796
14951
|
CallToolRequestSchema,
|
|
14797
14952
|
(request) => this.handleCallToolRequest(request)
|
|
14798
14953
|
);
|
|
14954
|
+
this.server.setRequestHandler(
|
|
14955
|
+
ListPromptsRequestSchema,
|
|
14956
|
+
(request) => this.handleListPromptsRequest(request)
|
|
14957
|
+
);
|
|
14958
|
+
this.server.setRequestHandler(
|
|
14959
|
+
GetPromptRequestSchema,
|
|
14960
|
+
(request) => this.handleGetPromptRequest(request)
|
|
14961
|
+
);
|
|
14799
14962
|
logInfo("MCP server handlers registered");
|
|
14800
14963
|
}
|
|
14801
14964
|
registerTool(tool) {
|
|
14802
14965
|
this.toolRegistry.registerTool(tool);
|
|
14803
14966
|
logInfo(`Tool registered: ${tool.name}`);
|
|
14804
14967
|
}
|
|
14968
|
+
registerPrompt(prompt) {
|
|
14969
|
+
this.promptRegistry.registerPrompt(prompt);
|
|
14970
|
+
logInfo(`Prompt registered: ${prompt.name}`);
|
|
14971
|
+
}
|
|
14805
14972
|
getParentProcessId() {
|
|
14806
14973
|
return this.parentPid;
|
|
14807
14974
|
}
|
|
@@ -14865,117 +15032,43 @@ var McpServer = class {
|
|
|
14865
15032
|
}
|
|
14866
15033
|
};
|
|
14867
15034
|
|
|
14868
|
-
// src/mcp/
|
|
14869
|
-
import { z as
|
|
14870
|
-
|
|
14871
|
-
// src/mcp/services/PathValidation.ts
|
|
14872
|
-
import fs12 from "fs";
|
|
14873
|
-
import path12 from "path";
|
|
14874
|
-
async function validatePath(inputPath) {
|
|
14875
|
-
logDebug("Validating MCP path", { inputPath });
|
|
14876
|
-
if (/^\/[a-zA-Z]:\//.test(inputPath)) {
|
|
14877
|
-
inputPath = inputPath.slice(1);
|
|
14878
|
-
}
|
|
14879
|
-
if (inputPath === "." || inputPath === "./") {
|
|
14880
|
-
const workspaceFolderPath = WorkspaceService.getWorkspaceFolderPath();
|
|
14881
|
-
if (workspaceFolderPath) {
|
|
14882
|
-
logDebug("Fallback to workspace folder path", {
|
|
14883
|
-
inputPath,
|
|
14884
|
-
workspaceFolderPaths: [workspaceFolderPath]
|
|
14885
|
-
});
|
|
14886
|
-
WorkspaceService.setKnownWorkspacePath(workspaceFolderPath);
|
|
14887
|
-
logDebug("Stored workspace folder path as known path", {
|
|
14888
|
-
workspaceFolderPath
|
|
14889
|
-
});
|
|
14890
|
-
return {
|
|
14891
|
-
isValid: true,
|
|
14892
|
-
path: workspaceFolderPath
|
|
14893
|
-
};
|
|
14894
|
-
} else {
|
|
14895
|
-
const error = `"." is not a valid path, please provide a full localpath to the repository`;
|
|
14896
|
-
logError(error);
|
|
14897
|
-
return { isValid: false, error, path: inputPath };
|
|
14898
|
-
}
|
|
14899
|
-
}
|
|
14900
|
-
if (inputPath.includes("..")) {
|
|
14901
|
-
const error = `Path contains path traversal patterns: ${inputPath}`;
|
|
14902
|
-
logError(error);
|
|
14903
|
-
return { isValid: false, error, path: inputPath };
|
|
14904
|
-
}
|
|
14905
|
-
const normalizedPath = path12.normalize(inputPath);
|
|
14906
|
-
if (normalizedPath.includes("..")) {
|
|
14907
|
-
const error = `Normalized path contains path traversal patterns: ${inputPath}`;
|
|
14908
|
-
logError(error);
|
|
14909
|
-
return { isValid: false, error, path: inputPath };
|
|
14910
|
-
}
|
|
14911
|
-
let decodedPath;
|
|
14912
|
-
try {
|
|
14913
|
-
decodedPath = decodeURIComponent(inputPath);
|
|
14914
|
-
} catch (err) {
|
|
14915
|
-
const error = `Failed to decode path: ${inputPath}`;
|
|
14916
|
-
logError(error, { err });
|
|
14917
|
-
return { isValid: false, error, path: inputPath };
|
|
14918
|
-
}
|
|
14919
|
-
if (decodedPath.includes("..") || decodedPath !== inputPath) {
|
|
14920
|
-
const error = `Path contains encoded traversal attempts: ${inputPath}`;
|
|
14921
|
-
logError(error);
|
|
14922
|
-
return { isValid: false, error, path: inputPath };
|
|
14923
|
-
}
|
|
14924
|
-
if (inputPath.includes("\0") || inputPath.includes("\0")) {
|
|
14925
|
-
const error = `Path contains dangerous characters: ${inputPath}`;
|
|
14926
|
-
logError(error);
|
|
14927
|
-
return { isValid: false, error, path: inputPath };
|
|
14928
|
-
}
|
|
14929
|
-
logDebug("Path validation successful", { inputPath });
|
|
14930
|
-
logDebug("Checking path existence", { inputPath });
|
|
14931
|
-
try {
|
|
14932
|
-
await fs12.promises.access(inputPath);
|
|
14933
|
-
logDebug("Path exists and is accessible", { inputPath });
|
|
14934
|
-
WorkspaceService.setKnownWorkspacePath(inputPath);
|
|
14935
|
-
logDebug("Stored validated path in WorkspaceService", { inputPath });
|
|
14936
|
-
return { isValid: true, path: inputPath };
|
|
14937
|
-
} catch (error) {
|
|
14938
|
-
const errorMessage = `Path does not exist or is not accessible: ${inputPath}`;
|
|
14939
|
-
logError(errorMessage, { error });
|
|
14940
|
-
return { isValid: false, error: errorMessage, path: inputPath };
|
|
14941
|
-
}
|
|
14942
|
-
}
|
|
15035
|
+
// src/mcp/prompts/CheckForNewVulnerabilitiesPrompt.ts
|
|
15036
|
+
import { z as z33 } from "zod";
|
|
14943
15037
|
|
|
14944
|
-
// src/mcp/
|
|
15038
|
+
// src/mcp/prompts/base/BasePrompt.ts
|
|
14945
15039
|
import { z as z32 } from "zod";
|
|
14946
|
-
var
|
|
15040
|
+
var BasePrompt = class {
|
|
14947
15041
|
getDefinition() {
|
|
14948
15042
|
return {
|
|
14949
15043
|
name: this.name,
|
|
14950
|
-
display_name: this.displayName,
|
|
14951
15044
|
description: this.description,
|
|
14952
|
-
|
|
15045
|
+
arguments: this.arguments
|
|
14953
15046
|
};
|
|
14954
15047
|
}
|
|
14955
|
-
async
|
|
14956
|
-
|
|
14957
|
-
|
|
14958
|
-
|
|
14959
|
-
|
|
14960
|
-
|
|
15048
|
+
async getPrompt(args) {
|
|
15049
|
+
let validatedArgs = args;
|
|
15050
|
+
if (this.argumentsValidationSchema) {
|
|
15051
|
+
validatedArgs = this.validateArguments(args);
|
|
15052
|
+
logDebug(`Prompt ${this.name} arguments validation successful`, {
|
|
15053
|
+
validatedArgs
|
|
15054
|
+
});
|
|
14961
15055
|
}
|
|
14962
|
-
const
|
|
14963
|
-
logDebug(`
|
|
14964
|
-
validatedArgs
|
|
14965
|
-
});
|
|
14966
|
-
logInfo(`Executing tool: ${this.name}`);
|
|
14967
|
-
const result = await this.executeInternal(validatedArgs);
|
|
14968
|
-
logInfo(`Tool ${this.name} executed successfully`);
|
|
15056
|
+
const result = await this.generatePrompt(validatedArgs);
|
|
15057
|
+
logDebug(`Prompt ${this.name} generated successfully`);
|
|
14969
15058
|
return result;
|
|
14970
15059
|
}
|
|
14971
|
-
|
|
15060
|
+
validateArguments(args) {
|
|
15061
|
+
if (!this.argumentsValidationSchema) {
|
|
15062
|
+
return args;
|
|
15063
|
+
}
|
|
14972
15064
|
try {
|
|
14973
|
-
|
|
15065
|
+
const argsToValidate = args === void 0 ? {} : args;
|
|
15066
|
+
return this.argumentsValidationSchema.parse(argsToValidate);
|
|
14974
15067
|
} catch (error) {
|
|
14975
15068
|
if (error instanceof z32.ZodError) {
|
|
14976
15069
|
const errorDetails = error.errors.map((e) => {
|
|
14977
15070
|
const fieldPath = e.path.length > 0 ? e.path.join(".") : "root";
|
|
14978
|
-
const message = e.message === "Required" ? `Missing required
|
|
15071
|
+
const message = e.message === "Required" ? `Missing required argument '${fieldPath}'` : `Invalid value for '${fieldPath}': ${e.message}`;
|
|
14979
15072
|
return message;
|
|
14980
15073
|
});
|
|
14981
15074
|
const errorMessage = `Invalid arguments: ${errorDetails.join(", ")}`;
|
|
@@ -14984,53 +15077,1786 @@ var BaseTool = class {
|
|
|
14984
15077
|
throw error;
|
|
14985
15078
|
}
|
|
14986
15079
|
}
|
|
14987
|
-
|
|
15080
|
+
createUserMessage(text) {
|
|
14988
15081
|
return {
|
|
14989
|
-
|
|
15082
|
+
description: this.description,
|
|
15083
|
+
messages: [
|
|
14990
15084
|
{
|
|
14991
|
-
|
|
14992
|
-
|
|
15085
|
+
role: "user",
|
|
15086
|
+
content: {
|
|
15087
|
+
type: "text",
|
|
15088
|
+
text
|
|
15089
|
+
}
|
|
14993
15090
|
}
|
|
14994
15091
|
]
|
|
14995
15092
|
};
|
|
14996
15093
|
}
|
|
14997
15094
|
};
|
|
14998
15095
|
|
|
14999
|
-
// src/mcp/
|
|
15000
|
-
|
|
15096
|
+
// src/mcp/prompts/CheckForNewVulnerabilitiesPrompt.ts
|
|
15097
|
+
var CheckForNewVulnerabilitiesArgsSchema = z33.object({
|
|
15098
|
+
path: z33.string().optional()
|
|
15099
|
+
});
|
|
15100
|
+
var CheckForNewVulnerabilitiesPrompt = class extends BasePrompt {
|
|
15101
|
+
constructor() {
|
|
15102
|
+
super(...arguments);
|
|
15103
|
+
__publicField(this, "name", "check-for-new-vulnerabilities");
|
|
15104
|
+
__publicField(this, "description", "Guide for enabling continuous security monitoring to detect new vulnerabilities");
|
|
15105
|
+
__publicField(this, "arguments", [
|
|
15106
|
+
{
|
|
15107
|
+
name: "path",
|
|
15108
|
+
description: "Optional: Full local path to the git repository to monitor",
|
|
15109
|
+
required: false
|
|
15110
|
+
}
|
|
15111
|
+
]);
|
|
15112
|
+
__publicField(this, "argumentsValidationSchema", CheckForNewVulnerabilitiesArgsSchema);
|
|
15113
|
+
}
|
|
15114
|
+
async generatePrompt(validatedArgs) {
|
|
15115
|
+
const args = validatedArgs;
|
|
15116
|
+
const promptText = `# Continuous Security Monitoring Setup
|
|
15001
15117
|
|
|
15002
|
-
|
|
15003
|
-
init_configs();
|
|
15004
|
-
function friendlyType(s) {
|
|
15005
|
-
const withoutUnderscores = s.replace(/_/g, " ");
|
|
15006
|
-
const result = withoutUnderscores.replace(/([a-z])([A-Z])/g, "$1 $2");
|
|
15007
|
-
return result.charAt(0).toUpperCase() + result.slice(1);
|
|
15008
|
-
}
|
|
15009
|
-
var noFixesReturnedForParameters = `No fixes returned for the given offset and limit parameters.
|
|
15010
|
-
`;
|
|
15011
|
-
var noFixesReturnedForParametersWithGuidance = ({
|
|
15012
|
-
offset,
|
|
15013
|
-
limit,
|
|
15014
|
-
totalCount,
|
|
15015
|
-
currentTool
|
|
15016
|
-
}) => `## No Fixes Returned for Current Parameters
|
|
15118
|
+
This workflow sets up ongoing security monitoring to detect new vulnerabilities as code changes.
|
|
15017
15119
|
|
|
15018
|
-
|
|
15019
|
-
- **Page:** ${Math.floor(offset / limit) + 1}
|
|
15020
|
-
- **Offset:** ${offset}
|
|
15021
|
-
- **Limit:** ${limit}
|
|
15120
|
+
## Purpose
|
|
15022
15121
|
|
|
15023
|
-
|
|
15122
|
+
The \`check_for_new_available_fixes\` tool provides:
|
|
15123
|
+
- Lightweight background security monitoring
|
|
15124
|
+
- Detection of newly introduced vulnerabilities
|
|
15125
|
+
- Periodic checks without heavy scanning overhead
|
|
15126
|
+
- Notifications when new fixes become available
|
|
15024
15127
|
|
|
15025
|
-
|
|
15128
|
+
## When to Use
|
|
15026
15129
|
|
|
15027
|
-
|
|
15130
|
+
Call this tool:
|
|
15131
|
+
\u2713 At the end of a coding session
|
|
15132
|
+
\u2713 After completing a series of edits
|
|
15133
|
+
\u2713 After applying security fixes (to verify no new issues)
|
|
15134
|
+
\u2713 Before committing code changes
|
|
15135
|
+
\u2713 As part of a continuous security workflow
|
|
15136
|
+
\u2713 When setting up a project for security monitoring
|
|
15028
15137
|
|
|
15029
|
-
|
|
15138
|
+
## Workflow Steps
|
|
15030
15139
|
|
|
15031
|
-
1
|
|
15032
|
-
|
|
15033
|
-
|
|
15140
|
+
### Step 1: Determine Repository Path
|
|
15141
|
+
${args?.path ? `\u2713 Repository path provided: \`${args.path}\`` : `Get the full local path to the git repository to monitor.`}
|
|
15142
|
+
|
|
15143
|
+
### Step 2: Call check_for_new_available_fixes
|
|
15144
|
+
|
|
15145
|
+
Use the tool with minimal parameters:
|
|
15146
|
+
|
|
15147
|
+
\`\`\`json
|
|
15148
|
+
{
|
|
15149
|
+
"path": "${args?.path || "<repository-path>"}"
|
|
15150
|
+
}
|
|
15151
|
+
\`\`\`
|
|
15152
|
+
|
|
15153
|
+
This tool is designed to be lightweight and non-intrusive.
|
|
15154
|
+
|
|
15155
|
+
### Step 3: Interpret Results
|
|
15156
|
+
|
|
15157
|
+
The tool will return one of several possible outcomes:
|
|
15158
|
+
|
|
15159
|
+
#### New Vulnerabilities Detected
|
|
15160
|
+
|
|
15161
|
+
If new security issues are found:
|
|
15162
|
+
|
|
15163
|
+
1. **Alert the user promptly:**
|
|
15164
|
+
"\u26A0\uFE0F New security vulnerabilities detected!"
|
|
15165
|
+
|
|
15166
|
+
2. **Provide summary:**
|
|
15167
|
+
- Number of new vulnerabilities
|
|
15168
|
+
- Severity breakdown
|
|
15169
|
+
- Files affected
|
|
15170
|
+
|
|
15171
|
+
3. **Recommend immediate action:**
|
|
15172
|
+
- For Critical/High: "I recommend reviewing these immediately"
|
|
15173
|
+
- For Medium/Low: "These should be addressed when convenient"
|
|
15174
|
+
|
|
15175
|
+
4. **Offer next steps:**
|
|
15176
|
+
- "Would you like to scan and see the details?"
|
|
15177
|
+
- "Should I fetch the available fixes?"
|
|
15178
|
+
- Suggest calling \`scan_and_fix_vulnerabilities\` or \`fetch_available_fixes\`
|
|
15179
|
+
|
|
15180
|
+
#### No New Vulnerabilities
|
|
15181
|
+
|
|
15182
|
+
"\u2713 Monitoring active. No new security vulnerabilities detected."
|
|
15183
|
+
|
|
15184
|
+
Optional follow-up:
|
|
15185
|
+
- Confirm monitoring is now enabled
|
|
15186
|
+
- Mention that checks will continue periodically
|
|
15187
|
+
- Reassure the user their code remains secure
|
|
15188
|
+
|
|
15189
|
+
#### Monitoring Enabled
|
|
15190
|
+
|
|
15191
|
+
"\u2713 Continuous security monitoring has been enabled for this repository."
|
|
15192
|
+
|
|
15193
|
+
Explain what this means:
|
|
15194
|
+
- Periodic background checks will run
|
|
15195
|
+
- User will be notified of new vulnerabilities
|
|
15196
|
+
- No action required from user right now
|
|
15197
|
+
|
|
15198
|
+
### Step 4: Handle User Response
|
|
15199
|
+
|
|
15200
|
+
**If new vulnerabilities were found:**
|
|
15201
|
+
|
|
15202
|
+
Guide the user to take appropriate action:
|
|
15203
|
+
|
|
15204
|
+
1. **Immediate threats (Critical/High):**
|
|
15205
|
+
- Strongly recommend scanning now
|
|
15206
|
+
- Offer to fetch and display fixes
|
|
15207
|
+
- Suggest not committing until fixed
|
|
15208
|
+
|
|
15209
|
+
2. **Medium priority:**
|
|
15210
|
+
- Add to todo list or backlog
|
|
15211
|
+
- Schedule time to address
|
|
15212
|
+
- Can proceed with current work
|
|
15213
|
+
|
|
15214
|
+
3. **Low priority:**
|
|
15215
|
+
- Track for future maintenance
|
|
15216
|
+
- Can be addressed in next refactoring
|
|
15217
|
+
- No immediate action required
|
|
15218
|
+
|
|
15219
|
+
**If no issues found:**
|
|
15220
|
+
|
|
15221
|
+
- Congratulate the user on maintaining security
|
|
15222
|
+
- Remind them monitoring will continue
|
|
15223
|
+
- Suggest they can continue their work confidently
|
|
15224
|
+
|
|
15225
|
+
### Step 5: Integration into Workflow
|
|
15226
|
+
|
|
15227
|
+
This tool should be called **automatically** in certain scenarios:
|
|
15228
|
+
|
|
15229
|
+
1. **End-of-session cleanup:**
|
|
15230
|
+
After a user completes a significant amount of work
|
|
15231
|
+
|
|
15232
|
+
2. **Post-fix verification:**
|
|
15233
|
+
After applying security fixes to ensure no new issues
|
|
15234
|
+
|
|
15235
|
+
3. **Pre-commit hook simulation:**
|
|
15236
|
+
Before suggesting the user commit their changes
|
|
15237
|
+
|
|
15238
|
+
4. **Periodic checks:**
|
|
15239
|
+
During long-running IDE sessions (every 15-30 minutes)
|
|
15240
|
+
|
|
15241
|
+
## Best Practices
|
|
15242
|
+
|
|
15243
|
+
### DO:
|
|
15244
|
+
\u2713 Call this tool frequently and automatically
|
|
15245
|
+
\u2713 Make it part of your regular workflow
|
|
15246
|
+
\u2713 Alert users immediately when issues are found
|
|
15247
|
+
\u2713 Provide clear severity context
|
|
15248
|
+
\u2713 Offer actionable next steps
|
|
15249
|
+
\u2713 Keep the messaging positive and non-alarming
|
|
15250
|
+
|
|
15251
|
+
### DON'T:
|
|
15252
|
+
\u2717 Make this tool intrusive or annoying
|
|
15253
|
+
\u2717 Overwhelm users with constant notifications
|
|
15254
|
+
\u2717 Ignore Critical/High severity findings
|
|
15255
|
+
\u2717 Forget to explain what monitoring means
|
|
15256
|
+
\u2717 Skip this step at the end of sessions
|
|
15257
|
+
|
|
15258
|
+
## Monitoring vs. Scanning
|
|
15259
|
+
|
|
15260
|
+
It's important to understand the difference:
|
|
15261
|
+
|
|
15262
|
+
| Feature | check_for_new_available_fixes | scan_and_fix_vulnerabilities |
|
|
15263
|
+
|---------|------------------------------|------------------------------|
|
|
15264
|
+
| Purpose | Continuous monitoring | Full security scan |
|
|
15265
|
+
| Speed | Very fast | Slower (minutes) |
|
|
15266
|
+
| Depth | Lightweight check | Comprehensive analysis |
|
|
15267
|
+
| When | Frequently, automatically | On-demand, deliberately |
|
|
15268
|
+
| Results | Binary (new issues yes/no) | Detailed vulnerability reports |
|
|
15269
|
+
| Resource usage | Minimal | Higher |
|
|
15270
|
+
|
|
15271
|
+
**Strategy:** Use monitoring frequently, trigger full scans only when needed.
|
|
15272
|
+
|
|
15273
|
+
## Example Usage
|
|
15274
|
+
|
|
15275
|
+
### Scenario 1: End of Coding Session
|
|
15276
|
+
|
|
15277
|
+
\`\`\`
|
|
15278
|
+
AI: "I'm running a final security check on your changes..."
|
|
15279
|
+
|
|
15280
|
+
[Calls check_for_new_available_fixes]
|
|
15281
|
+
|
|
15282
|
+
AI: "\u2713 All clear! No new security vulnerabilities detected. Your code is safe to commit."
|
|
15283
|
+
\`\`\`
|
|
15284
|
+
|
|
15285
|
+
### Scenario 2: New Vulnerabilities Found
|
|
15286
|
+
|
|
15287
|
+
\`\`\`
|
|
15288
|
+
AI: "Running continuous security monitoring..."
|
|
15289
|
+
|
|
15290
|
+
[Calls check_for_new_available_fixes]
|
|
15291
|
+
|
|
15292
|
+
AI: "\u26A0\uFE0F I detected 2 new security vulnerabilities:
|
|
15293
|
+
- 1 High severity
|
|
15294
|
+
- 1 Medium severity
|
|
15295
|
+
|
|
15296
|
+
Would you like me to run a full scan to see the details and available fixes?"
|
|
15297
|
+
|
|
15298
|
+
User: "Yes, please"
|
|
15299
|
+
|
|
15300
|
+
[AI proceeds to call scan_and_fix_vulnerabilities]
|
|
15301
|
+
\`\`\`
|
|
15302
|
+
|
|
15303
|
+
### Scenario 3: After Applying Fixes
|
|
15304
|
+
|
|
15305
|
+
\`\`\`
|
|
15306
|
+
AI: "I've applied the security fixes. Let me verify no new issues were introduced..."
|
|
15307
|
+
|
|
15308
|
+
[Calls check_for_new_available_fixes]
|
|
15309
|
+
|
|
15310
|
+
AI: "\u2713 Perfect! The fixes resolved the issues and no new vulnerabilities were introduced. Your code is now more secure."
|
|
15311
|
+
\`\`\`
|
|
15312
|
+
|
|
15313
|
+
## Silent vs. Announced Monitoring
|
|
15314
|
+
|
|
15315
|
+
**Silent monitoring** (recommended for background checks):
|
|
15316
|
+
- Call the tool without announcing it
|
|
15317
|
+
- Only notify user if issues are found
|
|
15318
|
+
- Keeps the experience smooth and non-intrusive
|
|
15319
|
+
|
|
15320
|
+
**Announced monitoring** (use when setting up or after significant changes):
|
|
15321
|
+
- Tell the user monitoring is running
|
|
15322
|
+
- Confirm when monitoring is enabled
|
|
15323
|
+
- Provides transparency and confidence
|
|
15324
|
+
|
|
15325
|
+
## Technical Details
|
|
15326
|
+
|
|
15327
|
+
The tool:
|
|
15328
|
+
- Connects to Mobb's backend API
|
|
15329
|
+
- Checks for new vulnerability data
|
|
15330
|
+
- Compares against last known state
|
|
15331
|
+
- Returns summary of new findings
|
|
15332
|
+
- Maintains minimal overhead
|
|
15333
|
+
|
|
15334
|
+
## Ready to Monitor
|
|
15335
|
+
|
|
15336
|
+
Call the \`check_for_new_available_fixes\` tool now${args?.path ? ` for ${args.path}` : ""} to enable continuous security monitoring. This is a best practice that helps catch vulnerabilities early and maintain code security over time.
|
|
15337
|
+
`;
|
|
15338
|
+
return this.createUserMessage(promptText);
|
|
15339
|
+
}
|
|
15340
|
+
};
|
|
15341
|
+
|
|
15342
|
+
// src/mcp/prompts/FullSecurityAuditPrompt.ts
|
|
15343
|
+
import { z as z34 } from "zod";
|
|
15344
|
+
var FullSecurityAuditArgsSchema = z34.object({
|
|
15345
|
+
path: z34.string().optional()
|
|
15346
|
+
});
|
|
15347
|
+
var FullSecurityAuditPrompt = class extends BasePrompt {
|
|
15348
|
+
constructor() {
|
|
15349
|
+
super(...arguments);
|
|
15350
|
+
__publicField(this, "name", "full-security-audit");
|
|
15351
|
+
__publicField(this, "description", "Complete end-to-end security audit workflow: scan \u2192 review \u2192 fix \u2192 verify \u2192 monitor");
|
|
15352
|
+
__publicField(this, "arguments", [
|
|
15353
|
+
{
|
|
15354
|
+
name: "path",
|
|
15355
|
+
description: "Optional: Full local path to the git repository to audit",
|
|
15356
|
+
required: false
|
|
15357
|
+
}
|
|
15358
|
+
]);
|
|
15359
|
+
__publicField(this, "argumentsValidationSchema", FullSecurityAuditArgsSchema);
|
|
15360
|
+
}
|
|
15361
|
+
async generatePrompt(validatedArgs) {
|
|
15362
|
+
const args = validatedArgs;
|
|
15363
|
+
const promptText = `# Complete Security Audit Workflow
|
|
15364
|
+
|
|
15365
|
+
This is a comprehensive, end-to-end security audit process that will scan, review, fix, verify, and set up monitoring for a repository.
|
|
15366
|
+
|
|
15367
|
+
## Audit Overview
|
|
15368
|
+
|
|
15369
|
+
This workflow includes:
|
|
15370
|
+
1. **Initial Assessment** - Understand the repository
|
|
15371
|
+
2. **Comprehensive Scan** - Full security analysis
|
|
15372
|
+
3. **Issue Review** - Categorize and prioritize vulnerabilities
|
|
15373
|
+
4. **Fix Application** - Apply security patches systematically
|
|
15374
|
+
5. **Verification** - Confirm fixes work correctly
|
|
15375
|
+
6. **Continuous Monitoring** - Set up ongoing security checks
|
|
15376
|
+
7. **Final Report** - Document all actions taken
|
|
15377
|
+
|
|
15378
|
+
**Estimated Time:** 10-30 minutes depending on repository size and issue count
|
|
15379
|
+
|
|
15380
|
+
## Prerequisites
|
|
15381
|
+
|
|
15382
|
+
Before starting:
|
|
15383
|
+
- Repository should be in a clean git state (or user is aware of uncommitted changes)
|
|
15384
|
+
- Tests should be available and passing
|
|
15385
|
+
- User has time to review and address issues
|
|
15386
|
+
- Backup or branch created (recommended for first-time users)
|
|
15387
|
+
|
|
15388
|
+
## Phase 1: Initial Assessment
|
|
15389
|
+
|
|
15390
|
+
### Step 1.1: Gather Repository Information
|
|
15391
|
+
${args?.path ? `\u2713 Repository path: \`${args.path}\`` : `- Request repository path from user
|
|
15392
|
+
- Ask: "What is the full path to the repository you want to audit?"`}
|
|
15393
|
+
|
|
15394
|
+
### Step 1.2: Set Expectations
|
|
15395
|
+
|
|
15396
|
+
Inform the user:
|
|
15397
|
+
|
|
15398
|
+
\`\`\`
|
|
15399
|
+
"I'll perform a complete security audit of your repository. This will:
|
|
15400
|
+
- Scan all code for security vulnerabilities
|
|
15401
|
+
- Identify issues across all severity levels
|
|
15402
|
+
- Provide automatic fixes where possible
|
|
15403
|
+
- Set up continuous monitoring
|
|
15404
|
+
|
|
15405
|
+
This process will take a few minutes. I'll guide you through each step and explain my findings.
|
|
15406
|
+
|
|
15407
|
+
Ready to begin?"
|
|
15408
|
+
\`\`\`
|
|
15409
|
+
|
|
15410
|
+
### Step 1.3: Check Repository Status
|
|
15411
|
+
|
|
15412
|
+
Recommend running git status:
|
|
15413
|
+
\`\`\`bash
|
|
15414
|
+
git status
|
|
15415
|
+
\`\`\`
|
|
15416
|
+
|
|
15417
|
+
If there are uncommitted changes, suggest:
|
|
15418
|
+
- "I see uncommitted changes. Would you like to commit or stash them first?"
|
|
15419
|
+
- "We can proceed, but I recommend committing current work first."
|
|
15420
|
+
|
|
15421
|
+
## Phase 2: Comprehensive Scan
|
|
15422
|
+
|
|
15423
|
+
### Step 2.1: Initial Full Scan
|
|
15424
|
+
|
|
15425
|
+
Call \`scan_and_fix_vulnerabilities\`:
|
|
15426
|
+
|
|
15427
|
+
\`\`\`json
|
|
15428
|
+
{
|
|
15429
|
+
"path": "${args?.path || "<repository-path>"}",
|
|
15430
|
+
"limit": 10,
|
|
15431
|
+
"maxFiles": 50
|
|
15432
|
+
}
|
|
15433
|
+
\`\`\`
|
|
15434
|
+
|
|
15435
|
+
Larger limits for comprehensive audit.
|
|
15436
|
+
|
|
15437
|
+
### Step 2.2: Initial Results Analysis
|
|
15438
|
+
|
|
15439
|
+
When results arrive, analyze and present:
|
|
15440
|
+
|
|
15441
|
+
1. **Executive Summary:**
|
|
15442
|
+
\`\`\`
|
|
15443
|
+
Security Scan Complete
|
|
15444
|
+
----------------------
|
|
15445
|
+
Total Vulnerabilities Found: [N]
|
|
15446
|
+
|
|
15447
|
+
By Severity:
|
|
15448
|
+
- \u{1F534} Critical: [N] (immediate action required)
|
|
15449
|
+
- \u{1F7E0} High: [N] (urgent)
|
|
15450
|
+
- \u{1F7E1} Medium: [N] (important)
|
|
15451
|
+
- \u{1F535} Low: [N] (maintenance)
|
|
15452
|
+
|
|
15453
|
+
By Category:
|
|
15454
|
+
- [List top 3-5 vulnerability types found]
|
|
15455
|
+
|
|
15456
|
+
Fixable: [N] vulnerabilities have automatic fixes available
|
|
15457
|
+
\`\`\`
|
|
15458
|
+
|
|
15459
|
+
2. **Initial Recommendation:**
|
|
15460
|
+
Based on findings, recommend:
|
|
15461
|
+
- If Critical exists: "Address critical issues immediately"
|
|
15462
|
+
- If mostly High/Medium: "Systematic fix approach recommended"
|
|
15463
|
+
- If only Low: "Good security posture, minor improvements available"
|
|
15464
|
+
|
|
15465
|
+
## Phase 3: Issue Review & Prioritization
|
|
15466
|
+
|
|
15467
|
+
### Step 3.1: Detailed Issue Presentation
|
|
15468
|
+
|
|
15469
|
+
Present issues in priority order:
|
|
15470
|
+
|
|
15471
|
+
**For each Critical vulnerability:**
|
|
15472
|
+
\`\`\`
|
|
15473
|
+
\u{1F534} CRITICAL: [Type]
|
|
15474
|
+
Location: [file:line]
|
|
15475
|
+
Risk Level: Severe Security Threat
|
|
15476
|
+
|
|
15477
|
+
Description: [What the vulnerability is]
|
|
15478
|
+
Attack Vector: [How it could be exploited]
|
|
15479
|
+
Impact: [What an attacker could do]
|
|
15480
|
+
|
|
15481
|
+
Proposed Fix: [Summary of the fix]
|
|
15482
|
+
[Show diff/patch preview]
|
|
15483
|
+
|
|
15484
|
+
Last modified by: [git blame]
|
|
15485
|
+
\`\`\`
|
|
15486
|
+
|
|
15487
|
+
Continue for High, Medium, Low...
|
|
15488
|
+
|
|
15489
|
+
### Step 3.2: Create Fix Plan
|
|
15490
|
+
|
|
15491
|
+
Generate a structured fix plan:
|
|
15492
|
+
|
|
15493
|
+
\`\`\`markdown
|
|
15494
|
+
## Security Fix Plan
|
|
15495
|
+
|
|
15496
|
+
### Phase 1: Critical Fixes (Do First)
|
|
15497
|
+
1. [Vulnerability type] in [file]
|
|
15498
|
+
2. [Vulnerability type] in [file]
|
|
15499
|
+
...
|
|
15500
|
+
|
|
15501
|
+
### Phase 2: High Severity Fixes
|
|
15502
|
+
1. [Vulnerability type] in [file]
|
|
15503
|
+
2. [Vulnerability type] in [file]
|
|
15504
|
+
...
|
|
15505
|
+
|
|
15506
|
+
### Phase 3: Medium Severity Fixes
|
|
15507
|
+
[Can be done in follow-up session]
|
|
15508
|
+
|
|
15509
|
+
### Phase 4: Low Severity Fixes
|
|
15510
|
+
[Add to maintenance backlog]
|
|
15511
|
+
\`\`\`
|
|
15512
|
+
|
|
15513
|
+
### Step 3.3: Get User Approval
|
|
15514
|
+
|
|
15515
|
+
Ask user how they want to proceed:
|
|
15516
|
+
|
|
15517
|
+
"I've identified the security issues and created a fix plan. How would you like to proceed?
|
|
15518
|
+
|
|
15519
|
+
1. **Comprehensive Fix** - Fix all Critical and High issues now (recommended)
|
|
15520
|
+
2. **Critical Only** - Fix only Critical issues now
|
|
15521
|
+
3. **Selective Fix** - Review and choose which fixes to apply
|
|
15522
|
+
4. **Report Only** - Generate report without applying fixes (for review)
|
|
15523
|
+
|
|
15524
|
+
Recommendation: Option 1 for best security posture."
|
|
15525
|
+
|
|
15526
|
+
## Phase 4: Fix Application
|
|
15527
|
+
|
|
15528
|
+
Based on user choice, systematically apply fixes:
|
|
15529
|
+
|
|
15530
|
+
### Step 4.1: Apply Critical Fixes
|
|
15531
|
+
|
|
15532
|
+
For each Critical fix:
|
|
15533
|
+
1. Show what will be fixed
|
|
15534
|
+
2. Apply the patch
|
|
15535
|
+
3. Confirm application: "\u2713 Fixed: [vulnerability] in [file]"
|
|
15536
|
+
4. Track progress: "[N/Total] Critical fixes applied"
|
|
15537
|
+
|
|
15538
|
+
### Step 4.2: Apply High Severity Fixes
|
|
15539
|
+
|
|
15540
|
+
Same process as Critical, but can be done in batches.
|
|
15541
|
+
|
|
15542
|
+
### Step 4.3: Handle Fix Failures
|
|
15543
|
+
|
|
15544
|
+
If a fix fails to apply:
|
|
15545
|
+
1. Note the failure
|
|
15546
|
+
2. Show the conflict or error
|
|
15547
|
+
3. Mark for manual review
|
|
15548
|
+
4. Continue with remaining fixes
|
|
15549
|
+
5. Summarize failed fixes at the end
|
|
15550
|
+
|
|
15551
|
+
## Phase 5: Verification
|
|
15552
|
+
|
|
15553
|
+
### Step 5.1: Verify Patches Applied
|
|
15554
|
+
|
|
15555
|
+
Check each modified file:
|
|
15556
|
+
\`\`\`bash
|
|
15557
|
+
git status
|
|
15558
|
+
git diff
|
|
15559
|
+
\`\`\`
|
|
15560
|
+
|
|
15561
|
+
Confirm:
|
|
15562
|
+
- Expected files were modified
|
|
15563
|
+
- No unexpected changes
|
|
15564
|
+
- No merge conflicts
|
|
15565
|
+
|
|
15566
|
+
### Step 5.2: Run Test Suite
|
|
15567
|
+
|
|
15568
|
+
If tests exist:
|
|
15569
|
+
|
|
15570
|
+
\`\`\`bash
|
|
15571
|
+
# Run appropriate test command
|
|
15572
|
+
npm test
|
|
15573
|
+
# or
|
|
15574
|
+
pytest
|
|
15575
|
+
# or
|
|
15576
|
+
mvn test
|
|
15577
|
+
\`\`\`
|
|
15578
|
+
|
|
15579
|
+
**If tests pass:**
|
|
15580
|
+
"\u2705 All tests passed! Security fixes did not break functionality."
|
|
15581
|
+
|
|
15582
|
+
**If tests fail:**
|
|
15583
|
+
"\u26A0\uFE0F Some tests are failing after applying fixes:
|
|
15584
|
+
[List failing tests]
|
|
15585
|
+
|
|
15586
|
+
This could mean:
|
|
15587
|
+
1. Tests need to be updated (common for security fixes)
|
|
15588
|
+
2. A fix introduced an issue (less common)
|
|
15589
|
+
|
|
15590
|
+
Would you like me to:
|
|
15591
|
+
1. Review the failing tests
|
|
15592
|
+
2. Revert specific fixes
|
|
15593
|
+
3. Continue anyway (tests may need updates)"
|
|
15594
|
+
|
|
15595
|
+
### Step 5.3: Re-scan for Verification
|
|
15596
|
+
|
|
15597
|
+
Call \`scan_and_fix_vulnerabilities\` again with \`rescan: true\`:
|
|
15598
|
+
|
|
15599
|
+
\`\`\`json
|
|
15600
|
+
{
|
|
15601
|
+
"path": "${args?.path || "<repository-path>"}",
|
|
15602
|
+
"rescan": true,
|
|
15603
|
+
"limit": 10
|
|
15604
|
+
}
|
|
15605
|
+
\`\`\`
|
|
15606
|
+
|
|
15607
|
+
Compare before/after:
|
|
15608
|
+
- Confirm fixed vulnerabilities are gone
|
|
15609
|
+
- Check no new vulnerabilities were introduced
|
|
15610
|
+
- Verify severity counts decreased as expected
|
|
15611
|
+
|
|
15612
|
+
## Phase 6: Continuous Monitoring Setup
|
|
15613
|
+
|
|
15614
|
+
### Step 6.1: Enable Monitoring
|
|
15615
|
+
|
|
15616
|
+
Call \`check_for_new_available_fixes\`:
|
|
15617
|
+
|
|
15618
|
+
\`\`\`json
|
|
15619
|
+
{
|
|
15620
|
+
"path": "${args?.path || "<repository-path>"}"
|
|
15621
|
+
}
|
|
15622
|
+
\`\`\`
|
|
15623
|
+
|
|
15624
|
+
### Step 6.2: Explain Monitoring
|
|
15625
|
+
|
|
15626
|
+
"\u2705 Continuous security monitoring is now enabled for this repository.
|
|
15627
|
+
|
|
15628
|
+
What this means:
|
|
15629
|
+
- Periodic background checks for new vulnerabilities
|
|
15630
|
+
- Notifications when security issues are detected
|
|
15631
|
+
- Ongoing protection as code evolves
|
|
15632
|
+
|
|
15633
|
+
This helps maintain the security improvements we just made."
|
|
15634
|
+
|
|
15635
|
+
## Phase 7: Final Report
|
|
15636
|
+
|
|
15637
|
+
### Step 7.1: Generate Comprehensive Report
|
|
15638
|
+
|
|
15639
|
+
Create a detailed report:
|
|
15640
|
+
|
|
15641
|
+
\`\`\`markdown
|
|
15642
|
+
# Security Audit Report
|
|
15643
|
+
Repository: [name/path]
|
|
15644
|
+
Date: [date]
|
|
15645
|
+
Audited by: Mobb AI Security Assistant
|
|
15646
|
+
|
|
15647
|
+
## Executive Summary
|
|
15648
|
+
- Total vulnerabilities found: [N]
|
|
15649
|
+
- Vulnerabilities fixed: [N]
|
|
15650
|
+
- Files modified: [N]
|
|
15651
|
+
- Test status: [Pass/Fail/Not Run]
|
|
15652
|
+
|
|
15653
|
+
## Vulnerabilities Fixed
|
|
15654
|
+
|
|
15655
|
+
### Critical (\u{1F534})
|
|
15656
|
+
1. [Type] in [file:line] - FIXED \u2705
|
|
15657
|
+
- Risk: [description]
|
|
15658
|
+
- Fix: [description]
|
|
15659
|
+
|
|
15660
|
+
2. [Type] in [file:line] - FIXED \u2705
|
|
15661
|
+
...
|
|
15662
|
+
|
|
15663
|
+
### High (\u{1F7E0})
|
|
15664
|
+
[Similar format]
|
|
15665
|
+
|
|
15666
|
+
### Medium (\u{1F7E1})
|
|
15667
|
+
[List - note which were fixed]
|
|
15668
|
+
|
|
15669
|
+
### Low (\u{1F535})
|
|
15670
|
+
[List - note which were fixed]
|
|
15671
|
+
|
|
15672
|
+
## Files Modified
|
|
15673
|
+
- [list all modified files with change descriptions]
|
|
15674
|
+
|
|
15675
|
+
## Verification Results
|
|
15676
|
+
\u2705 All fixes applied successfully
|
|
15677
|
+
\u2705 Tests passing
|
|
15678
|
+
\u2705 Re-scan confirms vulnerabilities resolved
|
|
15679
|
+
\u2705 No new vulnerabilities introduced
|
|
15680
|
+
|
|
15681
|
+
## Remaining Items
|
|
15682
|
+
- [N] Medium severity issues (recommended to fix soon)
|
|
15683
|
+
- [N] Low severity issues (maintenance backlog)
|
|
15684
|
+
|
|
15685
|
+
## Recommendations
|
|
15686
|
+
1. Commit these security improvements
|
|
15687
|
+
2. Deploy to staging environment for testing
|
|
15688
|
+
3. Schedule follow-up for remaining Medium issues
|
|
15689
|
+
4. Review security practices to prevent future issues
|
|
15690
|
+
5. Keep continuous monitoring enabled
|
|
15691
|
+
|
|
15692
|
+
## Next Steps
|
|
15693
|
+
1. Review the changes: git diff
|
|
15694
|
+
2. Run additional tests if needed
|
|
15695
|
+
3. Commit: git add . && git commit -m "Security fixes: addressed [N] critical and high severity vulnerabilities"
|
|
15696
|
+
4. Push to remote repository
|
|
15697
|
+
5. Deploy with confidence
|
|
15698
|
+
|
|
15699
|
+
---
|
|
15700
|
+
\u{1F512} Security Level: [Excellent/Good/Fair] (based on remaining issues)
|
|
15701
|
+
\`\`\`
|
|
15702
|
+
|
|
15703
|
+
### Step 7.2: Provide Next Steps
|
|
15704
|
+
|
|
15705
|
+
Give clear guidance:
|
|
15706
|
+
|
|
15707
|
+
"## What to do next:
|
|
15708
|
+
|
|
15709
|
+
**Immediate (Do now):**
|
|
15710
|
+
1. Review the changes made (git diff)
|
|
15711
|
+
2. Commit the security fixes
|
|
15712
|
+
3. Push to your repository
|
|
15713
|
+
|
|
15714
|
+
**Soon (This week):**
|
|
15715
|
+
1. Address remaining Medium severity issues ([N] items)
|
|
15716
|
+
2. Review security best practices for your framework
|
|
15717
|
+
3. Share this report with your team
|
|
15718
|
+
|
|
15719
|
+
**Ongoing:**
|
|
15720
|
+
1. Continuous monitoring is active
|
|
15721
|
+
2. Run security scans after major changes
|
|
15722
|
+
3. Keep dependencies updated
|
|
15723
|
+
|
|
15724
|
+
**Questions?**
|
|
15725
|
+
- Need help with any specific fix?
|
|
15726
|
+
- Want to understand a vulnerability better?
|
|
15727
|
+
- Need guidance on preventing similar issues?
|
|
15728
|
+
|
|
15729
|
+
Ask me anything!"
|
|
15730
|
+
|
|
15731
|
+
## Important Guidelines
|
|
15732
|
+
|
|
15733
|
+
### Communication Throughout
|
|
15734
|
+
|
|
15735
|
+
**Be:**
|
|
15736
|
+
- Professional and clear
|
|
15737
|
+
- Patient and thorough
|
|
15738
|
+
- Encouraging and supportive
|
|
15739
|
+
- Transparent about what you're doing
|
|
15740
|
+
|
|
15741
|
+
**Tone:**
|
|
15742
|
+
- Security issues are serious but fixable
|
|
15743
|
+
- Congratulate progress
|
|
15744
|
+
- Celebrate improvements
|
|
15745
|
+
- Don't blame or shame
|
|
15746
|
+
|
|
15747
|
+
### DO:
|
|
15748
|
+
\u2705 Follow all phases systematically
|
|
15749
|
+
\u2705 Explain each step clearly
|
|
15750
|
+
\u2705 Get user approval before major actions
|
|
15751
|
+
\u2705 Verify all changes
|
|
15752
|
+
\u2705 Provide comprehensive documentation
|
|
15753
|
+
\u2705 Enable monitoring
|
|
15754
|
+
\u2705 Give clear next steps
|
|
15755
|
+
|
|
15756
|
+
### DON'T:
|
|
15757
|
+
\u274C Rush through the process
|
|
15758
|
+
\u274C Skip verification steps
|
|
15759
|
+
\u274C Apply fixes without explanation
|
|
15760
|
+
\u274C Forget to check for new issues
|
|
15761
|
+
\u274C Leave user without next steps
|
|
15762
|
+
\u274C Create alarm - be solution-focused
|
|
15763
|
+
|
|
15764
|
+
## Time Management
|
|
15765
|
+
|
|
15766
|
+
For large repositories with many issues:
|
|
15767
|
+
- Take breaks between phases
|
|
15768
|
+
- Offer to pause and resume later
|
|
15769
|
+
- Batch fixes appropriately
|
|
15770
|
+
- Don't overwhelm the user
|
|
15771
|
+
|
|
15772
|
+
Suggest: "We've fixed [N] critical issues. Would you like to continue with High severity, or take a break and resume later?"
|
|
15773
|
+
|
|
15774
|
+
## Success Criteria
|
|
15775
|
+
|
|
15776
|
+
Audit is successful when:
|
|
15777
|
+
\u2705 All Critical vulnerabilities are fixed
|
|
15778
|
+
\u2705 Most High severity issues addressed
|
|
15779
|
+
\u2705 All fixes verified and tested
|
|
15780
|
+
\u2705 No new vulnerabilities introduced
|
|
15781
|
+
\u2705 Continuous monitoring enabled
|
|
15782
|
+
\u2705 Comprehensive report provided
|
|
15783
|
+
\u2705 User understands next steps
|
|
15784
|
+
|
|
15785
|
+
## Ready to Begin
|
|
15786
|
+
|
|
15787
|
+
This is a comprehensive security audit that will significantly improve the security posture of the repository. Follow each phase carefully, communicate clearly, and celebrate the improvements made.
|
|
15788
|
+
|
|
15789
|
+
Begin the audit now${args?.path ? ` for ${args.path}` : ""}.
|
|
15790
|
+
`;
|
|
15791
|
+
return this.createUserMessage(promptText);
|
|
15792
|
+
}
|
|
15793
|
+
};
|
|
15794
|
+
|
|
15795
|
+
// src/mcp/prompts/ReviewAndFixCriticalPrompt.ts
|
|
15796
|
+
import { z as z35 } from "zod";
|
|
15797
|
+
var ReviewAndFixCriticalArgsSchema = z35.object({
|
|
15798
|
+
path: z35.string().optional()
|
|
15799
|
+
});
|
|
15800
|
+
var ReviewAndFixCriticalPrompt = class extends BasePrompt {
|
|
15801
|
+
constructor() {
|
|
15802
|
+
super(...arguments);
|
|
15803
|
+
__publicField(this, "name", "review-and-fix-critical");
|
|
15804
|
+
__publicField(this, "description", "Focused workflow for identifying and fixing Critical and High severity security vulnerabilities");
|
|
15805
|
+
__publicField(this, "arguments", [
|
|
15806
|
+
{
|
|
15807
|
+
name: "path",
|
|
15808
|
+
description: "Optional: Full local path to the git repository to scan and fix",
|
|
15809
|
+
required: false
|
|
15810
|
+
}
|
|
15811
|
+
]);
|
|
15812
|
+
__publicField(this, "argumentsValidationSchema", ReviewAndFixCriticalArgsSchema);
|
|
15813
|
+
}
|
|
15814
|
+
async generatePrompt(validatedArgs) {
|
|
15815
|
+
const args = validatedArgs;
|
|
15816
|
+
const promptText = `# Critical Security Vulnerabilities - Review and Fix
|
|
15817
|
+
|
|
15818
|
+
This is a focused workflow for identifying and addressing Critical and High severity security vulnerabilities that require immediate attention.
|
|
15819
|
+
|
|
15820
|
+
## Workflow Purpose
|
|
15821
|
+
|
|
15822
|
+
Use this workflow when:
|
|
15823
|
+
- Security is a high priority
|
|
15824
|
+
- Preparing for production deployment
|
|
15825
|
+
- Security audit or compliance review is needed
|
|
15826
|
+
- You want to address the most severe issues first
|
|
15827
|
+
- Time is limited and you need to focus on critical threats
|
|
15828
|
+
|
|
15829
|
+
## Severity Priority
|
|
15830
|
+
|
|
15831
|
+
**CRITICAL** \u{1F534}
|
|
15832
|
+
- Immediate security risk
|
|
15833
|
+
- Can lead to complete system compromise
|
|
15834
|
+
- Examples: Remote Code Execution, Authentication Bypass, SQL Injection with data exposure
|
|
15835
|
+
- **Action: FIX IMMEDIATELY**
|
|
15836
|
+
|
|
15837
|
+
**HIGH** \u{1F7E0}
|
|
15838
|
+
- Significant security vulnerability
|
|
15839
|
+
- Can lead to data breaches or unauthorized access
|
|
15840
|
+
- Examples: XSS attacks, Privilege Escalation, Exposed Sensitive Data
|
|
15841
|
+
- **Action: FIX URGENTLY**
|
|
15842
|
+
|
|
15843
|
+
Medium and Low severity issues will be noted but not prioritized in this workflow.
|
|
15844
|
+
|
|
15845
|
+
## Workflow Steps
|
|
15846
|
+
|
|
15847
|
+
### Step 1: Initial Scan
|
|
15848
|
+
${args?.path ? `Scanning repository at: \`${args.path}\`` : `Obtain the repository path from the user.`}
|
|
15849
|
+
|
|
15850
|
+
Call \`scan_and_fix_vulnerabilities\`:
|
|
15851
|
+
|
|
15852
|
+
\`\`\`json
|
|
15853
|
+
{
|
|
15854
|
+
"path": "${args?.path || "<repository-path>"}",
|
|
15855
|
+
"limit": 10,
|
|
15856
|
+
"maxFiles": 20
|
|
15857
|
+
}
|
|
15858
|
+
\`\`\`
|
|
15859
|
+
|
|
15860
|
+
Higher limits to ensure we catch all critical issues.
|
|
15861
|
+
|
|
15862
|
+
### Step 2: Filter and Present Critical Issues
|
|
15863
|
+
|
|
15864
|
+
When results arrive:
|
|
15865
|
+
|
|
15866
|
+
1. **Count vulnerabilities by severity:**
|
|
15867
|
+
- Critical count
|
|
15868
|
+
- High count
|
|
15869
|
+
- Medium count (mention but don't focus)
|
|
15870
|
+
- Low count (mention but don't focus)
|
|
15871
|
+
|
|
15872
|
+
2. **Present ONLY Critical and High severity issues:**
|
|
15873
|
+
|
|
15874
|
+
For each Critical/High vulnerability:
|
|
15875
|
+
|
|
15876
|
+
\`\`\`
|
|
15877
|
+
\u{1F534} CRITICAL: [Vulnerability Type]
|
|
15878
|
+
|
|
15879
|
+
File: [path/to/file.ext:line]
|
|
15880
|
+
Last modified by: [git blame user]
|
|
15881
|
+
|
|
15882
|
+
Risk: [Explain the security risk in simple terms]
|
|
15883
|
+
|
|
15884
|
+
Proposed Fix:
|
|
15885
|
+
[Show the diff/patch]
|
|
15886
|
+
|
|
15887
|
+
Impact: [What this fix does and why it's necessary]
|
|
15888
|
+
\`\`\`
|
|
15889
|
+
|
|
15890
|
+
3. **Provide clear summary:**
|
|
15891
|
+
"Found X critical and Y high severity vulnerabilities that require immediate attention."
|
|
15892
|
+
|
|
15893
|
+
### Step 3: Prioritize Fixes
|
|
15894
|
+
|
|
15895
|
+
Create a fix priority list:
|
|
15896
|
+
|
|
15897
|
+
**Phase 1 - Critical (DO FIRST):**
|
|
15898
|
+
- List all Critical issues
|
|
15899
|
+
- Sort by risk level
|
|
15900
|
+
- Recommend fixing ALL before any High issues
|
|
15901
|
+
|
|
15902
|
+
**Phase 2 - High (DO SECOND):**
|
|
15903
|
+
- List all High issues
|
|
15904
|
+
- Can be addressed after Critical are resolved
|
|
15905
|
+
|
|
15906
|
+
**Ask the user:**
|
|
15907
|
+
"I recommend we fix these in priority order. Would you like me to:
|
|
15908
|
+
1. Apply ALL critical fixes automatically (recommended)
|
|
15909
|
+
2. Review each critical fix individually
|
|
15910
|
+
3. See the full details before proceeding"
|
|
15911
|
+
|
|
15912
|
+
### Step 4: Apply Fixes
|
|
15913
|
+
|
|
15914
|
+
Based on user choice:
|
|
15915
|
+
|
|
15916
|
+
#### Option 1: Apply All Critical Automatically
|
|
15917
|
+
|
|
15918
|
+
\`\`\`
|
|
15919
|
+
"I'll apply all [N] critical fixes now. This will modify [X] files."
|
|
15920
|
+
|
|
15921
|
+
For each fix:
|
|
15922
|
+
1. Apply the patch
|
|
15923
|
+
2. Verify it applied successfully
|
|
15924
|
+
3. Show brief confirmation: "\u2713 Fixed: [vulnerability type] in [file]"
|
|
15925
|
+
|
|
15926
|
+
"All critical fixes applied. Running verification..."
|
|
15927
|
+
[Call check_for_new_available_fixes to verify]
|
|
15928
|
+
|
|
15929
|
+
"Next, I can address the [N] high severity issues. Continue?"
|
|
15930
|
+
\`\`\`
|
|
15931
|
+
|
|
15932
|
+
#### Option 2: Review Each Fix Individually
|
|
15933
|
+
|
|
15934
|
+
For each Critical fix:
|
|
15935
|
+
1. Show the vulnerability details
|
|
15936
|
+
2. Show the exact code changes
|
|
15937
|
+
3. Explain the security improvement
|
|
15938
|
+
4. Ask: "Apply this fix? (yes/no/skip)"
|
|
15939
|
+
5. Apply if approved
|
|
15940
|
+
6. Move to next
|
|
15941
|
+
|
|
15942
|
+
#### Option 3: Provide Full Details First
|
|
15943
|
+
|
|
15944
|
+
- Show comprehensive analysis of each vulnerability
|
|
15945
|
+
- Include CVE references if available
|
|
15946
|
+
- Explain attack vectors
|
|
15947
|
+
- Demonstrate how the fix prevents the attack
|
|
15948
|
+
- Then proceed to fixing phase
|
|
15949
|
+
|
|
15950
|
+
### Step 5: Verification
|
|
15951
|
+
|
|
15952
|
+
After applying fixes:
|
|
15953
|
+
|
|
15954
|
+
1. **Verify fixes applied correctly:**
|
|
15955
|
+
- Check files were modified
|
|
15956
|
+
- No merge conflicts
|
|
15957
|
+
- Code syntax is valid
|
|
15958
|
+
|
|
15959
|
+
2. **Run tests if available:**
|
|
15960
|
+
\`\`\`bash
|
|
15961
|
+
npm test
|
|
15962
|
+
# or
|
|
15963
|
+
pytest
|
|
15964
|
+
# or appropriate test command
|
|
15965
|
+
\`\`\`
|
|
15966
|
+
|
|
15967
|
+
3. **Re-scan to confirm:**
|
|
15968
|
+
Call \`scan_and_fix_vulnerabilities\` again with \`rescan: true\`
|
|
15969
|
+
|
|
15970
|
+
Verify:
|
|
15971
|
+
- Critical issues are resolved
|
|
15972
|
+
- No new issues were introduced
|
|
15973
|
+
- High severity count decreased (if those were also fixed)
|
|
15974
|
+
|
|
15975
|
+
### Step 6: Summary Report
|
|
15976
|
+
|
|
15977
|
+
Provide a comprehensive summary:
|
|
15978
|
+
|
|
15979
|
+
\`\`\`markdown
|
|
15980
|
+
## Security Fix Summary
|
|
15981
|
+
|
|
15982
|
+
### Fixed
|
|
15983
|
+
- \u2705 [N] Critical vulnerabilities resolved
|
|
15984
|
+
- \u2705 [N] High severity vulnerabilities resolved
|
|
15985
|
+
|
|
15986
|
+
### Files Modified
|
|
15987
|
+
- [list of modified files]
|
|
15988
|
+
|
|
15989
|
+
### Remaining Issues
|
|
15990
|
+
- \u26A0\uFE0F [N] Medium severity (can be addressed later)
|
|
15991
|
+
- \u2139\uFE0F [N] Low severity (maintenance backlog)
|
|
15992
|
+
|
|
15993
|
+
### Recommendations
|
|
15994
|
+
1. Run your test suite to ensure functionality
|
|
15995
|
+
2. Review the changes before committing
|
|
15996
|
+
3. Consider addressing remaining High severity issues
|
|
15997
|
+
4. Schedule time for Medium/Low issues
|
|
15998
|
+
5. Enable continuous monitoring
|
|
15999
|
+
|
|
16000
|
+
### Next Steps
|
|
16001
|
+
- Commit these security fixes
|
|
16002
|
+
- Deploy to staging for testing
|
|
16003
|
+
- Schedule follow-up for remaining issues
|
|
16004
|
+
\`\`\`
|
|
16005
|
+
|
|
16006
|
+
## Important Guidelines
|
|
16007
|
+
|
|
16008
|
+
### Communication Style
|
|
16009
|
+
|
|
16010
|
+
**For Critical Issues:**
|
|
16011
|
+
- Use urgent but calm language
|
|
16012
|
+
- Clearly explain the risk
|
|
16013
|
+
- Don't create panic, but convey seriousness
|
|
16014
|
+
- Be direct about the need to fix immediately
|
|
16015
|
+
|
|
16016
|
+
**For High Issues:**
|
|
16017
|
+
- Emphasize importance but not emergency
|
|
16018
|
+
- Explain impact on security posture
|
|
16019
|
+
- Recommend fixing soon but not necessarily right now
|
|
16020
|
+
|
|
16021
|
+
### DO:
|
|
16022
|
+
\u2705 Fix ALL Critical issues before moving to High
|
|
16023
|
+
\u2705 Explain each vulnerability clearly
|
|
16024
|
+
\u2705 Show exact code changes
|
|
16025
|
+
\u2705 Verify fixes were applied successfully
|
|
16026
|
+
\u2705 Run tests after applying fixes
|
|
16027
|
+
\u2705 Create a clear summary of actions taken
|
|
16028
|
+
\u2705 Recommend continuous monitoring
|
|
16029
|
+
|
|
16030
|
+
### DON'T:
|
|
16031
|
+
\u274C Apply fixes without user approval (except if explicitly requested)
|
|
16032
|
+
\u274C Minimize the importance of Critical issues
|
|
16033
|
+
\u274C Get distracted by Medium/Low issues during this workflow
|
|
16034
|
+
\u274C Skip verification steps
|
|
16035
|
+
\u274C Forget to check for new issues after applying fixes
|
|
16036
|
+
\u274C Rush through explanations
|
|
16037
|
+
|
|
16038
|
+
## Example Interaction
|
|
16039
|
+
|
|
16040
|
+
\`\`\`
|
|
16041
|
+
AI: "Scanning repository for critical security vulnerabilities..."
|
|
16042
|
+
|
|
16043
|
+
[Scans]
|
|
16044
|
+
|
|
16045
|
+
AI: "\u26A0\uFE0F **Security Alert: Critical Issues Found**
|
|
16046
|
+
|
|
16047
|
+
I found 3 critical and 5 high severity vulnerabilities:
|
|
16048
|
+
|
|
16049
|
+
\u{1F534} **CRITICAL ISSUES** (Must fix immediately):
|
|
16050
|
+
|
|
16051
|
+
1. **SQL Injection** in src/api/users.ts:67
|
|
16052
|
+
- Risk: Attacker can access entire database
|
|
16053
|
+
- Last modified by: john@example.com
|
|
16054
|
+
- Fix: Use parameterized queries
|
|
16055
|
+
|
|
16056
|
+
2. **Authentication Bypass** in src/auth/middleware.ts:23
|
|
16057
|
+
- Risk: Unauthorized access to admin functions
|
|
16058
|
+
- Last modified by: jane@example.com
|
|
16059
|
+
- Fix: Validate JWT signature properly
|
|
16060
|
+
|
|
16061
|
+
3. **Remote Code Execution** in src/utils/processor.ts:45
|
|
16062
|
+
- Risk: Attacker can execute arbitrary code on server
|
|
16063
|
+
- Last modified by: bob@example.com
|
|
16064
|
+
- Fix: Sanitize eval() input
|
|
16065
|
+
|
|
16066
|
+
\u{1F7E0} **HIGH SEVERITY** (Fix urgently):
|
|
16067
|
+
[Lists 5 high issues...]
|
|
16068
|
+
|
|
16069
|
+
**Recommendation:** Fix all 3 critical issues immediately. Would you like me to:
|
|
16070
|
+
1. Apply ALL critical fixes now (recommended) \u2190 [DEFAULT]
|
|
16071
|
+
2. Review each fix individually
|
|
16072
|
+
3. See detailed analysis first"
|
|
16073
|
+
|
|
16074
|
+
User: "Apply all critical fixes"
|
|
16075
|
+
|
|
16076
|
+
AI: "Applying all critical fixes...
|
|
16077
|
+
|
|
16078
|
+
\u2713 Fixed: SQL Injection in src/api/users.ts
|
|
16079
|
+
\u2713 Fixed: Authentication Bypass in src/auth/middleware.ts
|
|
16080
|
+
\u2713 Fixed: Remote Code Execution in src/utils/processor.ts
|
|
16081
|
+
|
|
16082
|
+
All critical vulnerabilities resolved! Running verification...
|
|
16083
|
+
|
|
16084
|
+
\u2713 Verification complete - no new issues introduced.
|
|
16085
|
+
|
|
16086
|
+
3 files modified, 0 critical issues remaining.
|
|
16087
|
+
|
|
16088
|
+
Would you like to proceed with fixing the 5 high severity issues?"
|
|
16089
|
+
\`\`\`
|
|
16090
|
+
|
|
16091
|
+
## Ready to Begin
|
|
16092
|
+
|
|
16093
|
+
This workflow focuses exclusively on the most dangerous vulnerabilities. Follow the steps above to systematically eliminate critical security threats from the codebase.
|
|
16094
|
+
|
|
16095
|
+
Start by scanning${args?.path ? ` ${args.path}` : " the repository"} and prioritizing Critical and High severity issues.
|
|
16096
|
+
`;
|
|
16097
|
+
return this.createUserMessage(promptText);
|
|
16098
|
+
}
|
|
16099
|
+
};
|
|
16100
|
+
|
|
16101
|
+
// src/mcp/prompts/ScanRecentChangesPrompt.ts
|
|
16102
|
+
import { z as z36 } from "zod";
|
|
16103
|
+
var ScanRecentChangesArgsSchema = z36.object({
|
|
16104
|
+
path: z36.string().optional()
|
|
16105
|
+
});
|
|
16106
|
+
var ScanRecentChangesPrompt = class extends BasePrompt {
|
|
16107
|
+
constructor() {
|
|
16108
|
+
super(...arguments);
|
|
16109
|
+
__publicField(this, "name", "scan-recent-changes");
|
|
16110
|
+
__publicField(this, "description", "Guide for scanning only recently modified files for new security vulnerabilities");
|
|
16111
|
+
__publicField(this, "arguments", [
|
|
16112
|
+
{
|
|
16113
|
+
name: "path",
|
|
16114
|
+
description: "Optional: Full local path to the git repository to scan",
|
|
16115
|
+
required: false
|
|
16116
|
+
}
|
|
16117
|
+
]);
|
|
16118
|
+
__publicField(this, "argumentsValidationSchema", ScanRecentChangesArgsSchema);
|
|
16119
|
+
}
|
|
16120
|
+
async generatePrompt(validatedArgs) {
|
|
16121
|
+
const args = validatedArgs;
|
|
16122
|
+
const promptText = `# Scan Recent Changes for Security Issues
|
|
16123
|
+
|
|
16124
|
+
This workflow helps you quickly scan only the files that have been recently modified, making security checks fast and targeted.
|
|
16125
|
+
|
|
16126
|
+
## When to Use This Workflow
|
|
16127
|
+
|
|
16128
|
+
Use this approach when:
|
|
16129
|
+
- You've just made code changes and want to check for new vulnerabilities
|
|
16130
|
+
- You want a quick security check without scanning the entire repository
|
|
16131
|
+
- You're working in a specific area of the codebase
|
|
16132
|
+
- You want faster scan results
|
|
16133
|
+
- You're doing iterative development and want continuous security feedback
|
|
16134
|
+
|
|
16135
|
+
## Workflow Steps
|
|
16136
|
+
|
|
16137
|
+
### Step 1: Determine Repository Path
|
|
16138
|
+
${args?.path ? `\u2713 Repository path provided: \`${args.path}\`` : `Ask the user for the full local path to the git repository.`}
|
|
16139
|
+
|
|
16140
|
+
### Step 2: Call scan_and_fix_vulnerabilities with Recent Changes Flag
|
|
16141
|
+
|
|
16142
|
+
Use the \`scan_and_fix_vulnerabilities\` tool with the \`scanRecentlyChangedFiles\` parameter:
|
|
16143
|
+
|
|
16144
|
+
\`\`\`json
|
|
16145
|
+
{
|
|
16146
|
+
"path": "${args?.path || "<repository-path>"}",
|
|
16147
|
+
"scanRecentlyChangedFiles": true,
|
|
16148
|
+
"limit": 5
|
|
16149
|
+
}
|
|
16150
|
+
\`\`\`
|
|
16151
|
+
|
|
16152
|
+
**Key parameters:**
|
|
16153
|
+
- \`scanRecentlyChangedFiles: true\` - Only scans files modified recently
|
|
16154
|
+
- \`limit: 5\` - Return up to 5 fixes (adjustable based on user needs)
|
|
16155
|
+
|
|
16156
|
+
### Step 3: Present Results
|
|
16157
|
+
|
|
16158
|
+
When you receive results:
|
|
16159
|
+
|
|
16160
|
+
#### If new vulnerabilities found:
|
|
16161
|
+
|
|
16162
|
+
1. **Alert the user:**
|
|
16163
|
+
"\u26A0\uFE0F Security issues detected in recently modified files!"
|
|
16164
|
+
|
|
16165
|
+
2. **Provide context:**
|
|
16166
|
+
- Number of new vulnerabilities introduced
|
|
16167
|
+
- Which files are affected
|
|
16168
|
+
- Severity breakdown
|
|
16169
|
+
- Who made the changes (git blame)
|
|
16170
|
+
|
|
16171
|
+
3. **Show each vulnerability:**
|
|
16172
|
+
- File and line number
|
|
16173
|
+
- Type of vulnerability
|
|
16174
|
+
- Severity level
|
|
16175
|
+
- Proposed fix with diff preview
|
|
16176
|
+
|
|
16177
|
+
4. **Recommend immediate action:**
|
|
16178
|
+
For Critical/High severity:
|
|
16179
|
+
- "I strongly recommend addressing these issues before committing/merging"
|
|
16180
|
+
- "Would you like me to apply the fixes now?"
|
|
16181
|
+
|
|
16182
|
+
#### If no vulnerabilities found:
|
|
16183
|
+
|
|
16184
|
+
"\u2713 Great! No new security issues detected in your recent changes."
|
|
16185
|
+
|
|
16186
|
+
Optional suggestions:
|
|
16187
|
+
- Continue with your work
|
|
16188
|
+
- Commit your changes
|
|
16189
|
+
- Consider enabling continuous monitoring
|
|
16190
|
+
|
|
16191
|
+
#### If no recently changed files:
|
|
16192
|
+
|
|
16193
|
+
"No recently modified files detected. This could mean:
|
|
16194
|
+
- No uncommitted changes exist
|
|
16195
|
+
- No files were modified recently
|
|
16196
|
+
- The repository has no git history
|
|
16197
|
+
|
|
16198
|
+
Would you like to:
|
|
16199
|
+
1. Perform a full repository scan instead?
|
|
16200
|
+
2. Check the repository status?"
|
|
16201
|
+
|
|
16202
|
+
### Step 4: Handle User Decisions
|
|
16203
|
+
|
|
16204
|
+
**If user wants to apply fixes:**
|
|
16205
|
+
- Confirm each fix before applying
|
|
16206
|
+
- Show the exact changes
|
|
16207
|
+
- Apply patches sequentially
|
|
16208
|
+
- Verify each application succeeded
|
|
16209
|
+
- Run tests if available
|
|
16210
|
+
|
|
16211
|
+
**If user wants to see more details:**
|
|
16212
|
+
- Explain the vulnerability type
|
|
16213
|
+
- Show the vulnerable code pattern
|
|
16214
|
+
- Explain how the fix improves security
|
|
16215
|
+
- Provide references or documentation links
|
|
16216
|
+
|
|
16217
|
+
**If user wants to continue without fixing:**
|
|
16218
|
+
- Warn about the risks (especially for Critical/High)
|
|
16219
|
+
- Suggest creating an issue to track the vulnerability
|
|
16220
|
+
- Remind them to fix before merging to production
|
|
16221
|
+
|
|
16222
|
+
### Step 5: Post-Scan Recommendations
|
|
16223
|
+
|
|
16224
|
+
After handling vulnerabilities:
|
|
16225
|
+
|
|
16226
|
+
1. **If fixes were applied:**
|
|
16227
|
+
- Verify the code still works (run tests)
|
|
16228
|
+
- Review the changes
|
|
16229
|
+
- Update commit message to mention security fixes
|
|
16230
|
+
- Consider running a full scan to check for other issues
|
|
16231
|
+
|
|
16232
|
+
2. **If fixes were deferred:**
|
|
16233
|
+
- Create tracking issues for the vulnerabilities
|
|
16234
|
+
- Add TODO comments in the code
|
|
16235
|
+
- Schedule time to address them
|
|
16236
|
+
|
|
16237
|
+
3. **Enable continuous monitoring:**
|
|
16238
|
+
Call \`check_for_new_available_fixes\`:
|
|
16239
|
+
\`\`\`json
|
|
16240
|
+
{
|
|
16241
|
+
"path": "${args?.path || "<repository-path>"}"
|
|
16242
|
+
}
|
|
16243
|
+
\`\`\`
|
|
16244
|
+
|
|
16245
|
+
## Advantages of Scanning Recent Changes
|
|
16246
|
+
|
|
16247
|
+
\u2713 **Fast**: Only scans modified files
|
|
16248
|
+
\u2713 **Targeted**: Focuses on your current work
|
|
16249
|
+
\u2713 **Immediate feedback**: Catch issues before they're committed
|
|
16250
|
+
\u2713 **Less overwhelming**: Smaller result set
|
|
16251
|
+
\u2713 **Continuous security**: Integrates into development workflow
|
|
16252
|
+
|
|
16253
|
+
## Important Notes
|
|
16254
|
+
|
|
16255
|
+
### DO:
|
|
16256
|
+
\u2713 Run this scan after making changes but before committing
|
|
16257
|
+
\u2713 Address Critical/High severity issues immediately
|
|
16258
|
+
\u2713 Explain security risks clearly to the user
|
|
16259
|
+
\u2713 Offer to apply fixes automatically
|
|
16260
|
+
\u2713 Provide context about what changed and why it's vulnerable
|
|
16261
|
+
|
|
16262
|
+
### DON'T:
|
|
16263
|
+
\u2717 Skip Critical/High severity warnings
|
|
16264
|
+
\u2717 Apply fixes without showing the user
|
|
16265
|
+
\u2717 Ignore the vulnerability just because the scan is quick
|
|
16266
|
+
\u2717 Forget to run tests after applying fixes
|
|
16267
|
+
\u2717 Assume all recent changes have vulnerabilities
|
|
16268
|
+
|
|
16269
|
+
## Integration with Development Workflow
|
|
16270
|
+
|
|
16271
|
+
This scan type integrates well with:
|
|
16272
|
+
- **Pre-commit hooks**: Scan before each commit
|
|
16273
|
+
- **IDE integration**: Scan on file save or periodically
|
|
16274
|
+
- **CI/CD pipelines**: Fast security check in pull requests
|
|
16275
|
+
- **Iterative development**: Continuous security feedback
|
|
16276
|
+
|
|
16277
|
+
## Example Usage
|
|
16278
|
+
|
|
16279
|
+
\`\`\`
|
|
16280
|
+
User: "I just added a new API endpoint for user data. Can you check if it's secure?"
|
|
16281
|
+
|
|
16282
|
+
AI: "I'll scan your recent changes for security vulnerabilities..."
|
|
16283
|
+
|
|
16284
|
+
[Calls scan_and_fix_vulnerabilities with scanRecentlyChangedFiles: true]
|
|
16285
|
+
|
|
16286
|
+
AI: "\u26A0\uFE0F Found 1 security issue in your recent changes:
|
|
16287
|
+
|
|
16288
|
+
**SQL Injection Vulnerability** (Critical)
|
|
16289
|
+
- File: src/api/user-data.ts:34
|
|
16290
|
+
- Your new endpoint is vulnerable to SQL injection
|
|
16291
|
+
|
|
16292
|
+
The issue is in this code:
|
|
16293
|
+
\`\`\`typescript
|
|
16294
|
+
const query = \`SELECT * FROM users WHERE id = \${req.params.id}\`
|
|
16295
|
+
\`\`\`
|
|
16296
|
+
|
|
16297
|
+
Recommended fix: Use parameterized queries
|
|
16298
|
+
\`\`\`typescript
|
|
16299
|
+
const query = 'SELECT * FROM users WHERE id = $1'
|
|
16300
|
+
const result = await db.query(query, [req.params.id])
|
|
16301
|
+
\`\`\`
|
|
16302
|
+
|
|
16303
|
+
This is a Critical severity issue. I strongly recommend fixing it before committing. Would you like me to apply this fix automatically?"
|
|
16304
|
+
\`\`\`
|
|
16305
|
+
|
|
16306
|
+
## Ready to Scan
|
|
16307
|
+
|
|
16308
|
+
You now have the guidance needed to perform a fast, targeted security scan of recent changes. Follow the workflow above to help users catch security issues early in their development process.
|
|
16309
|
+
`;
|
|
16310
|
+
return this.createUserMessage(promptText);
|
|
16311
|
+
}
|
|
16312
|
+
};
|
|
16313
|
+
|
|
16314
|
+
// src/mcp/prompts/ScanRepositoryPrompt.ts
|
|
16315
|
+
import { z as z37 } from "zod";
|
|
16316
|
+
var ScanRepositoryArgsSchema = z37.object({
|
|
16317
|
+
path: z37.string().optional()
|
|
16318
|
+
});
|
|
16319
|
+
var ScanRepositoryPrompt = class extends BasePrompt {
|
|
16320
|
+
constructor() {
|
|
16321
|
+
super(...arguments);
|
|
16322
|
+
__publicField(this, "name", "scan-repository");
|
|
16323
|
+
__publicField(this, "description", "Guide for performing an initial security scan of a repository using Mobb tools");
|
|
16324
|
+
__publicField(this, "arguments", [
|
|
16325
|
+
{
|
|
16326
|
+
name: "path",
|
|
16327
|
+
description: "Optional: Full local path to the git repository to scan",
|
|
16328
|
+
required: false
|
|
16329
|
+
}
|
|
16330
|
+
]);
|
|
16331
|
+
__publicField(this, "argumentsValidationSchema", ScanRepositoryArgsSchema);
|
|
16332
|
+
}
|
|
16333
|
+
async generatePrompt(validatedArgs) {
|
|
16334
|
+
const args = validatedArgs;
|
|
16335
|
+
const pathInfo = args?.path ? `for repository at: ${args.path}` : "for the current repository";
|
|
16336
|
+
const promptText = `# Security Repository Scan Workflow
|
|
16337
|
+
|
|
16338
|
+
You are about to perform a security scan ${pathInfo}. Follow this workflow to scan the repository for vulnerabilities and present the findings to the user.
|
|
16339
|
+
|
|
16340
|
+
## Workflow Steps
|
|
16341
|
+
|
|
16342
|
+
### Step 1: Determine Repository Path
|
|
16343
|
+
${args?.path ? `\u2713 Repository path provided: \`${args.path}\`` : `- The user should provide the full local path to the git repository
|
|
16344
|
+
- Ask: "What is the full path to the repository you want to scan?"
|
|
16345
|
+
- Example: /Users/username/projects/my-app`}
|
|
16346
|
+
|
|
16347
|
+
### Step 2: Call scan_and_fix_vulnerabilities Tool
|
|
16348
|
+
|
|
16349
|
+
Use the \`scan_and_fix_vulnerabilities\` tool with these parameters:
|
|
16350
|
+
|
|
16351
|
+
\`\`\`json
|
|
16352
|
+
{
|
|
16353
|
+
"path": "${args?.path || "<repository-path>"}",
|
|
16354
|
+
"limit": 3,
|
|
16355
|
+
"maxFiles": 10
|
|
16356
|
+
}
|
|
16357
|
+
\`\`\`
|
|
16358
|
+
|
|
16359
|
+
**Why these defaults?**
|
|
16360
|
+
- \`limit: 3\` - Start with top 3 most severe vulnerabilities
|
|
16361
|
+
- \`maxFiles: 10\` - Reasonable initial scan scope
|
|
16362
|
+
|
|
16363
|
+
**Optional parameters** (use if user specifies):
|
|
16364
|
+
- \`rescan: true\` - Force a fresh scan (if user wants to override cached results)
|
|
16365
|
+
- \`scanRecentlyChangedFiles: true\` - Only scan recently modified files (faster)
|
|
16366
|
+
|
|
16367
|
+
### Step 3: Process and Present Results
|
|
16368
|
+
|
|
16369
|
+
When you receive the scan results:
|
|
16370
|
+
|
|
16371
|
+
#### If vulnerabilities are found:
|
|
16372
|
+
|
|
16373
|
+
1. **Provide a summary:**
|
|
16374
|
+
- Total number of vulnerabilities found
|
|
16375
|
+
- Breakdown by severity (Critical, High, Medium, Low)
|
|
16376
|
+
- Number of fixes available
|
|
16377
|
+
|
|
16378
|
+
2. **Present the top fixes:**
|
|
16379
|
+
- Show each fix with:
|
|
16380
|
+
* Severity level
|
|
16381
|
+
* Vulnerability type (e.g., "SQL Injection", "XSS", "Insecure Dependency")
|
|
16382
|
+
* Affected file(s)
|
|
16383
|
+
* Who last modified the vulnerable code (git blame)
|
|
16384
|
+
* Brief description from the fix
|
|
16385
|
+
|
|
16386
|
+
3. **Show the fix preview:**
|
|
16387
|
+
- Display the git diff/patch for each fix
|
|
16388
|
+
- Explain what changes will be made
|
|
16389
|
+
- Highlight the security improvement
|
|
16390
|
+
|
|
16391
|
+
4. **Ask for user preference:**
|
|
16392
|
+
- "Would you like to apply these fixes automatically?"
|
|
16393
|
+
- "Would you like to see more vulnerabilities?" (if more exist)
|
|
16394
|
+
- "Would you like to focus on a specific severity level?"
|
|
16395
|
+
|
|
16396
|
+
#### If no vulnerabilities are found:
|
|
16397
|
+
|
|
16398
|
+
Congratulate the user! Their repository appears to be secure. Suggest:
|
|
16399
|
+
- Running periodic scans as code changes
|
|
16400
|
+
- Enabling continuous monitoring with \`check_for_new_available_fixes\`
|
|
16401
|
+
|
|
16402
|
+
#### If report is expired:
|
|
16403
|
+
|
|
16404
|
+
Inform the user that a previous scan is too old. Ask:
|
|
16405
|
+
- "A previous scan exists but is outdated. Would you like to run a fresh scan?"
|
|
16406
|
+
- If yes, call \`scan_and_fix_vulnerabilities\` with \`rescan: true\`
|
|
16407
|
+
|
|
16408
|
+
### Step 4: Handle User Actions
|
|
16409
|
+
|
|
16410
|
+
Based on user response:
|
|
16411
|
+
|
|
16412
|
+
**If user wants to apply fixes:**
|
|
16413
|
+
- Confirm which fixes to apply (all, or specific ones)
|
|
16414
|
+
- Apply each fix patch using standard git apply workflow
|
|
16415
|
+
- Verify the changes
|
|
16416
|
+
- Run tests if available
|
|
16417
|
+
- Create a commit with the fixes
|
|
16418
|
+
|
|
16419
|
+
**If user wants to see more:**
|
|
16420
|
+
- Call \`fetch_available_fixes\` with:
|
|
16421
|
+
\`\`\`json
|
|
16422
|
+
{
|
|
16423
|
+
"path": "${args?.path || "<repository-path>"}",
|
|
16424
|
+
"offset": 3,
|
|
16425
|
+
"limit": 5
|
|
16426
|
+
}
|
|
16427
|
+
\`\`\`
|
|
16428
|
+
- Present the additional fixes following the same format
|
|
16429
|
+
|
|
16430
|
+
**If user wants to filter by severity:**
|
|
16431
|
+
- The results are already sorted by severity (Critical \u2192 High \u2192 Medium \u2192 Low)
|
|
16432
|
+
- Explain the severity of issues found
|
|
16433
|
+
- Focus on the most critical issues first
|
|
16434
|
+
|
|
16435
|
+
### Step 5: Post-Scan Actions
|
|
16436
|
+
|
|
16437
|
+
After completing the scan and any fixes:
|
|
16438
|
+
|
|
16439
|
+
1. **Summary of actions taken:**
|
|
16440
|
+
- Number of fixes applied
|
|
16441
|
+
- Remaining vulnerabilities (if any)
|
|
16442
|
+
- Files modified
|
|
16443
|
+
|
|
16444
|
+
2. **Recommendations:**
|
|
16445
|
+
- Run tests to ensure fixes don't break functionality
|
|
16446
|
+
- Review the changes before committing
|
|
16447
|
+
- Consider addressing remaining Medium/Low severity issues
|
|
16448
|
+
- Set up continuous monitoring
|
|
16449
|
+
|
|
16450
|
+
3. **Call monitoring tool:**
|
|
16451
|
+
Call \`check_for_new_available_fixes\` to enable ongoing security monitoring:
|
|
16452
|
+
\`\`\`json
|
|
16453
|
+
{
|
|
16454
|
+
"path": "${args?.path || "<repository-path>"}"
|
|
16455
|
+
}
|
|
16456
|
+
\`\`\`
|
|
16457
|
+
|
|
16458
|
+
## Important Reminders
|
|
16459
|
+
|
|
16460
|
+
### DO:
|
|
16461
|
+
\u2713 Present vulnerabilities clearly with severity context
|
|
16462
|
+
\u2713 Ask for user confirmation before applying fixes
|
|
16463
|
+
\u2713 Explain what each fix does
|
|
16464
|
+
\u2713 Start with critical/high severity issues
|
|
16465
|
+
\u2713 Provide clear next steps
|
|
16466
|
+
\u2713 Mention git blame information (shows responsibility)
|
|
16467
|
+
|
|
16468
|
+
### DON'T:
|
|
16469
|
+
\u2717 Apply fixes automatically without user approval
|
|
16470
|
+
\u2717 Overwhelm user with all vulnerabilities at once
|
|
16471
|
+
\u2717 Skip severity information
|
|
16472
|
+
\u2717 Forget to call monitoring tool at the end
|
|
16473
|
+
\u2717 Assume the user wants to fix everything immediately
|
|
16474
|
+
|
|
16475
|
+
## Error Handling
|
|
16476
|
+
|
|
16477
|
+
- **Authentication error**: Guide user to authenticate with Mobb
|
|
16478
|
+
- **Path not found**: Verify the path is correct and is a git repository
|
|
16479
|
+
- **Scan timeout**: Suggest scanning fewer files or recent changes only
|
|
16480
|
+
- **No report found**: This is expected for first-time scans, proceed normally
|
|
16481
|
+
|
|
16482
|
+
## Example Conversation Flow
|
|
16483
|
+
|
|
16484
|
+
\`\`\`
|
|
16485
|
+
AI: "I'll scan your repository for security vulnerabilities. This may take a moment..."
|
|
16486
|
+
|
|
16487
|
+
[Calls scan_and_fix_vulnerabilities]
|
|
16488
|
+
|
|
16489
|
+
AI: "Scan complete! I found 12 security vulnerabilities:
|
|
16490
|
+
- 2 Critical severity
|
|
16491
|
+
- 5 High severity
|
|
16492
|
+
- 4 Medium severity
|
|
16493
|
+
- 1 Low severity
|
|
16494
|
+
|
|
16495
|
+
Here are the top 3 most critical issues:
|
|
16496
|
+
|
|
16497
|
+
1. **SQL Injection** (Critical)
|
|
16498
|
+
- File: src/database/users.ts:45
|
|
16499
|
+
- Last modified by: john@example.com
|
|
16500
|
+
- Fix: Parameterize SQL query to prevent injection
|
|
16501
|
+
|
|
16502
|
+
[Shows diff preview]
|
|
16503
|
+
|
|
16504
|
+
2. **Cross-Site Scripting (XSS)** (Critical)
|
|
16505
|
+
- File: src/components/UserProfile.tsx:122
|
|
16506
|
+
- Last modified by: jane@example.com
|
|
16507
|
+
- Fix: Sanitize user input before rendering
|
|
16508
|
+
|
|
16509
|
+
[Shows diff preview]
|
|
16510
|
+
|
|
16511
|
+
3. **Insecure Dependency** (High)
|
|
16512
|
+
- Package: lodash@4.17.15
|
|
16513
|
+
- Fix: Upgrade to lodash@4.17.21 (fixes CVE-2021-23337)
|
|
16514
|
+
|
|
16515
|
+
Would you like to:
|
|
16516
|
+
1. Apply these fixes automatically
|
|
16517
|
+
2. See more vulnerabilities
|
|
16518
|
+
3. Focus on specific issues"
|
|
16519
|
+
\`\`\`
|
|
16520
|
+
|
|
16521
|
+
## Ready to Begin
|
|
16522
|
+
|
|
16523
|
+
You now have all the information needed to perform a security scan. Follow the steps above, call the appropriate tools, and guide the user through the process professionally and clearly.
|
|
16524
|
+
`;
|
|
16525
|
+
return this.createUserMessage(promptText);
|
|
16526
|
+
}
|
|
16527
|
+
};
|
|
16528
|
+
|
|
16529
|
+
// src/mcp/prompts/SecurityToolsOverviewPrompt.ts
|
|
16530
|
+
var SecurityToolsOverviewPrompt = class extends BasePrompt {
|
|
16531
|
+
constructor() {
|
|
16532
|
+
super(...arguments);
|
|
16533
|
+
__publicField(this, "name", "security-tools-overview");
|
|
16534
|
+
__publicField(this, "description", "Provides an overview of available Mobb security tools and guidance on when to use each tool");
|
|
16535
|
+
__publicField(this, "arguments");
|
|
16536
|
+
__publicField(this, "argumentsValidationSchema");
|
|
16537
|
+
}
|
|
16538
|
+
async generatePrompt() {
|
|
16539
|
+
const promptText = `# Mobb Security Tools Overview
|
|
16540
|
+
|
|
16541
|
+
You have access to powerful security scanning and auto-fixing tools from Mobb. Here's a comprehensive guide to the available tools and when to use them:
|
|
16542
|
+
|
|
16543
|
+
## Available Tools
|
|
16544
|
+
|
|
16545
|
+
### 1. **scan_and_fix_vulnerabilities**
|
|
16546
|
+
**Purpose:** Scans a local repository for security vulnerabilities and returns automatically-generated fixes.
|
|
16547
|
+
|
|
16548
|
+
**When to use:**
|
|
16549
|
+
- First-time security scan of a repository
|
|
16550
|
+
- Comprehensive security audit needed
|
|
16551
|
+
- User explicitly requests a security scan
|
|
16552
|
+
- After major code changes or refactoring
|
|
16553
|
+
|
|
16554
|
+
**Key features:**
|
|
16555
|
+
- Scans the entire repository or specific files
|
|
16556
|
+
- Identifies vulnerabilities across multiple categories (XSS, SQL injection, insecure dependencies, etc.)
|
|
16557
|
+
- Provides detailed fix information including severity levels
|
|
16558
|
+
- Returns git-compatible patches that can be directly applied
|
|
16559
|
+
- Shows who last modified vulnerable code (git blame integration)
|
|
16560
|
+
|
|
16561
|
+
**Parameters:**
|
|
16562
|
+
- \`path\` (required): Full local path to the git repository
|
|
16563
|
+
- \`offset\`: Pagination offset for results (default: 0)
|
|
16564
|
+
- \`limit\`: Number of fixes to return (default: 3)
|
|
16565
|
+
- \`maxFiles\`: Maximum files to scan (default: 10)
|
|
16566
|
+
- \`rescan\`: Force a new scan even if recent report exists
|
|
16567
|
+
- \`scanRecentlyChangedFiles\`: Only scan recently modified files
|
|
16568
|
+
|
|
16569
|
+
**Important notes:**
|
|
16570
|
+
- This tool requires authentication
|
|
16571
|
+
- Scans may take time for large repositories
|
|
16572
|
+
- Results are cached - use \`rescan: true\` to force a fresh scan
|
|
16573
|
+
- The tool returns fixes in order of severity (Critical \u2192 High \u2192 Medium \u2192 Low)
|
|
16574
|
+
|
|
16575
|
+
### 2. **fetch_available_fixes**
|
|
16576
|
+
**Purpose:** Retrieves pre-generated fixes from previous scans without triggering a new scan.
|
|
16577
|
+
|
|
16578
|
+
**When to use:**
|
|
16579
|
+
- Checking for existing fixes without scanning
|
|
16580
|
+
- Retrieving additional fixes from a paginated result set
|
|
16581
|
+
- User wants to see more fixes beyond the initial set
|
|
16582
|
+
- Fetching fixes for specific files
|
|
16583
|
+
|
|
16584
|
+
**Key features:**
|
|
16585
|
+
- Fast retrieval of existing fix data
|
|
16586
|
+
- No scanning overhead
|
|
16587
|
+
- Supports file filtering
|
|
16588
|
+
- Pagination for large result sets
|
|
16589
|
+
|
|
16590
|
+
**Parameters:**
|
|
16591
|
+
- \`path\` (required): Full local path to the git repository
|
|
16592
|
+
- \`offset\`: Pagination offset
|
|
16593
|
+
- \`limit\`: Number of fixes to return
|
|
16594
|
+
- \`fileFilter\`: Filter by specific file path
|
|
16595
|
+
- \`fetchFixesFromAnyFile\`: Fetch fixes across all files
|
|
16596
|
+
|
|
16597
|
+
**Important notes:**
|
|
16598
|
+
- Returns an error if no previous scan exists
|
|
16599
|
+
- Does NOT trigger a new scan
|
|
16600
|
+
- Use this when you want to avoid re-scanning
|
|
16601
|
+
|
|
16602
|
+
### 3. **check_for_new_available_fixes**
|
|
16603
|
+
**Purpose:** Monitors code for new security vulnerabilities and notifies when fixes are available.
|
|
16604
|
+
|
|
16605
|
+
**When to use:**
|
|
16606
|
+
- Continuous security monitoring
|
|
16607
|
+
- After completing a series of edits
|
|
16608
|
+
- End of a coding session
|
|
16609
|
+
- User requests ongoing security checks
|
|
16610
|
+
|
|
16611
|
+
**Key features:**
|
|
16612
|
+
- Lightweight background checking
|
|
16613
|
+
- Detects new vulnerabilities introduced by code changes
|
|
16614
|
+
- Non-intrusive monitoring
|
|
16615
|
+
|
|
16616
|
+
**Parameters:**
|
|
16617
|
+
- \`path\` (required): Full local path to the git repository
|
|
16618
|
+
|
|
16619
|
+
**Important notes:**
|
|
16620
|
+
- This is typically called automatically at the end of operations
|
|
16621
|
+
- Much lighter weight than full scans
|
|
16622
|
+
- Part of Mobb's continuous monitoring workflow
|
|
16623
|
+
|
|
16624
|
+
## Best Practices
|
|
16625
|
+
|
|
16626
|
+
### Tool Selection Guidelines
|
|
16627
|
+
|
|
16628
|
+
1. **Starting fresh?** \u2192 Use \`scan_and_fix_vulnerabilities\`
|
|
16629
|
+
2. **Already scanned, need more results?** \u2192 Use \`fetch_available_fixes\`
|
|
16630
|
+
3. **Continuous monitoring?** \u2192 Use \`check_for_new_available_fixes\`
|
|
16631
|
+
|
|
16632
|
+
### User Interaction Patterns
|
|
16633
|
+
|
|
16634
|
+
**When to ask for user confirmation:**
|
|
16635
|
+
- Before applying fixes automatically
|
|
16636
|
+
- Before running a full repository scan (can be time-consuming)
|
|
16637
|
+
- Before re-scanning when a recent scan exists
|
|
16638
|
+
- When multiple high-severity issues are found
|
|
16639
|
+
|
|
16640
|
+
**When to proceed automatically:**
|
|
16641
|
+
- Fetching additional fixes from existing scans
|
|
16642
|
+
- Running background monitoring checks
|
|
16643
|
+
- Displaying vulnerability information
|
|
16644
|
+
- Showing fix previews
|
|
16645
|
+
|
|
16646
|
+
### Severity Levels
|
|
16647
|
+
|
|
16648
|
+
Vulnerabilities are categorized by severity:
|
|
16649
|
+
- **CRITICAL**: Immediate action required - severe security risk
|
|
16650
|
+
- **HIGH**: Important security issue - should be fixed soon
|
|
16651
|
+
- **MEDIUM**: Moderate security concern - fix when feasible
|
|
16652
|
+
- **LOW**: Minor security issue - fix during regular maintenance
|
|
16653
|
+
|
|
16654
|
+
**Recommended approach:**
|
|
16655
|
+
1. Address CRITICAL issues immediately
|
|
16656
|
+
2. Review and fix HIGH severity issues
|
|
16657
|
+
3. Plan fixes for MEDIUM issues
|
|
16658
|
+
4. Address LOW issues during regular maintenance
|
|
16659
|
+
|
|
16660
|
+
### Workflow Example
|
|
16661
|
+
|
|
16662
|
+
\`\`\`
|
|
16663
|
+
1. User opens a repository
|
|
16664
|
+
2. Call scan_and_fix_vulnerabilities with default parameters
|
|
16665
|
+
3. Review the returned fixes (typically top 3 by severity)
|
|
16666
|
+
4. Present fixes to user with severity breakdown
|
|
16667
|
+
5. If user wants to see more: call fetch_available_fixes with appropriate offset
|
|
16668
|
+
6. When user approves fixes: apply the patches using git apply
|
|
16669
|
+
7. After session: call check_for_new_available_fixes for monitoring
|
|
16670
|
+
\`\`\`
|
|
16671
|
+
|
|
16672
|
+
## Authentication
|
|
16673
|
+
|
|
16674
|
+
All tools require authentication via the Mobb API. The tools will handle authentication automatically and prompt if credentials are needed.
|
|
16675
|
+
|
|
16676
|
+
## Error Handling
|
|
16677
|
+
|
|
16678
|
+
Common scenarios:
|
|
16679
|
+
- **No fixes found**: Repository has no vulnerabilities or they're not fixable
|
|
16680
|
+
- **Report expired**: Previous scan is too old, need to rescan
|
|
16681
|
+
- **No report found**: No previous scan exists, run scan_and_fix_vulnerabilities
|
|
16682
|
+
- **Authentication required**: User needs to authenticate with Mobb
|
|
16683
|
+
|
|
16684
|
+
## Next Steps
|
|
16685
|
+
|
|
16686
|
+
To get started with scanning a repository, use the \`scan-repository\` prompt which will guide you through the scanning workflow.
|
|
16687
|
+
|
|
16688
|
+
For a complete security audit workflow, use the \`full-security-audit\` prompt.
|
|
16689
|
+
`;
|
|
16690
|
+
return this.createUserMessage(promptText);
|
|
16691
|
+
}
|
|
16692
|
+
};
|
|
16693
|
+
|
|
16694
|
+
// src/mcp/tools/checkForNewAvailableFixes/CheckForNewAvailableFixesTool.ts
|
|
16695
|
+
import { z as z40 } from "zod";
|
|
16696
|
+
|
|
16697
|
+
// src/mcp/services/PathValidation.ts
|
|
16698
|
+
import fs13 from "fs";
|
|
16699
|
+
import path13 from "path";
|
|
16700
|
+
async function validatePath(inputPath) {
|
|
16701
|
+
logDebug("Validating MCP path", { inputPath });
|
|
16702
|
+
if (/^\/[a-zA-Z]:\//.test(inputPath)) {
|
|
16703
|
+
inputPath = inputPath.slice(1);
|
|
16704
|
+
}
|
|
16705
|
+
if (inputPath === "." || inputPath === "./") {
|
|
16706
|
+
const workspaceFolderPath = WorkspaceService.getWorkspaceFolderPath();
|
|
16707
|
+
if (workspaceFolderPath) {
|
|
16708
|
+
logDebug("Fallback to workspace folder path", {
|
|
16709
|
+
inputPath,
|
|
16710
|
+
workspaceFolderPaths: [workspaceFolderPath]
|
|
16711
|
+
});
|
|
16712
|
+
WorkspaceService.setKnownWorkspacePath(workspaceFolderPath);
|
|
16713
|
+
logDebug("Stored workspace folder path as known path", {
|
|
16714
|
+
workspaceFolderPath
|
|
16715
|
+
});
|
|
16716
|
+
return {
|
|
16717
|
+
isValid: true,
|
|
16718
|
+
path: workspaceFolderPath
|
|
16719
|
+
};
|
|
16720
|
+
} else {
|
|
16721
|
+
const error = `"." is not a valid path, please provide a full localpath to the repository`;
|
|
16722
|
+
logError(error);
|
|
16723
|
+
return { isValid: false, error, path: inputPath };
|
|
16724
|
+
}
|
|
16725
|
+
}
|
|
16726
|
+
if (inputPath.includes("..")) {
|
|
16727
|
+
const error = `Path contains path traversal patterns: ${inputPath}`;
|
|
16728
|
+
logError(error);
|
|
16729
|
+
return { isValid: false, error, path: inputPath };
|
|
16730
|
+
}
|
|
16731
|
+
const normalizedPath = path13.normalize(inputPath);
|
|
16732
|
+
if (normalizedPath.includes("..")) {
|
|
16733
|
+
const error = `Normalized path contains path traversal patterns: ${inputPath}`;
|
|
16734
|
+
logError(error);
|
|
16735
|
+
return { isValid: false, error, path: inputPath };
|
|
16736
|
+
}
|
|
16737
|
+
let decodedPath;
|
|
16738
|
+
try {
|
|
16739
|
+
decodedPath = decodeURIComponent(inputPath);
|
|
16740
|
+
} catch (err) {
|
|
16741
|
+
const error = `Failed to decode path: ${inputPath}`;
|
|
16742
|
+
logError(error, { err });
|
|
16743
|
+
return { isValid: false, error, path: inputPath };
|
|
16744
|
+
}
|
|
16745
|
+
if (decodedPath.includes("..") || decodedPath !== inputPath) {
|
|
16746
|
+
const error = `Path contains encoded traversal attempts: ${inputPath}`;
|
|
16747
|
+
logError(error);
|
|
16748
|
+
return { isValid: false, error, path: inputPath };
|
|
16749
|
+
}
|
|
16750
|
+
if (inputPath.includes("\0") || inputPath.includes("\0")) {
|
|
16751
|
+
const error = `Path contains dangerous characters: ${inputPath}`;
|
|
16752
|
+
logError(error);
|
|
16753
|
+
return { isValid: false, error, path: inputPath };
|
|
16754
|
+
}
|
|
16755
|
+
logDebug("Path validation successful", { inputPath });
|
|
16756
|
+
logDebug("Checking path existence", { inputPath });
|
|
16757
|
+
try {
|
|
16758
|
+
await fs13.promises.access(inputPath);
|
|
16759
|
+
logDebug("Path exists and is accessible", { inputPath });
|
|
16760
|
+
WorkspaceService.setKnownWorkspacePath(inputPath);
|
|
16761
|
+
logDebug("Stored validated path in WorkspaceService", { inputPath });
|
|
16762
|
+
return { isValid: true, path: inputPath };
|
|
16763
|
+
} catch (error) {
|
|
16764
|
+
const errorMessage = `Path does not exist or is not accessible: ${inputPath}`;
|
|
16765
|
+
logError(errorMessage, { error });
|
|
16766
|
+
return { isValid: false, error: errorMessage, path: inputPath };
|
|
16767
|
+
}
|
|
16768
|
+
}
|
|
16769
|
+
|
|
16770
|
+
// src/mcp/tools/base/BaseTool.ts
|
|
16771
|
+
import { z as z38 } from "zod";
|
|
16772
|
+
var BaseTool = class {
|
|
16773
|
+
getDefinition() {
|
|
16774
|
+
return {
|
|
16775
|
+
name: this.name,
|
|
16776
|
+
display_name: this.displayName,
|
|
16777
|
+
description: this.description,
|
|
16778
|
+
inputSchema: this.inputSchema
|
|
16779
|
+
};
|
|
16780
|
+
}
|
|
16781
|
+
async execute(args) {
|
|
16782
|
+
if (this.hasAuthentication) {
|
|
16783
|
+
logDebug(`Authenticating tool: ${this.name}`, { args });
|
|
16784
|
+
const mcpGqlClient = await createAuthenticatedMcpGQLClient();
|
|
16785
|
+
const userInfo = await mcpGqlClient.getUserInfo();
|
|
16786
|
+
logDebug("User authenticated successfully", { userInfo });
|
|
16787
|
+
}
|
|
16788
|
+
const validatedArgs = this.validateInput(args);
|
|
16789
|
+
logDebug(`Tool ${this.name} input validation successful`, {
|
|
16790
|
+
validatedArgs
|
|
16791
|
+
});
|
|
16792
|
+
logInfo(`Executing tool: ${this.name}`);
|
|
16793
|
+
const result = await this.executeInternal(validatedArgs);
|
|
16794
|
+
logInfo(`Tool ${this.name} executed successfully`);
|
|
16795
|
+
return result;
|
|
16796
|
+
}
|
|
16797
|
+
validateInput(args) {
|
|
16798
|
+
try {
|
|
16799
|
+
return this.inputValidationSchema.parse(args);
|
|
16800
|
+
} catch (error) {
|
|
16801
|
+
if (error instanceof z38.ZodError) {
|
|
16802
|
+
const errorDetails = error.errors.map((e) => {
|
|
16803
|
+
const fieldPath = e.path.length > 0 ? e.path.join(".") : "root";
|
|
16804
|
+
const message = e.message === "Required" ? `Missing required parameter '${fieldPath}'` : `Invalid value for '${fieldPath}': ${e.message}`;
|
|
16805
|
+
return message;
|
|
16806
|
+
});
|
|
16807
|
+
const errorMessage = `Invalid arguments: ${errorDetails.join(", ")}`;
|
|
16808
|
+
throw new Error(errorMessage);
|
|
16809
|
+
}
|
|
16810
|
+
throw error;
|
|
16811
|
+
}
|
|
16812
|
+
}
|
|
16813
|
+
createSuccessResponse(text) {
|
|
16814
|
+
return {
|
|
16815
|
+
content: [
|
|
16816
|
+
{
|
|
16817
|
+
type: "text",
|
|
16818
|
+
text
|
|
16819
|
+
}
|
|
16820
|
+
]
|
|
16821
|
+
};
|
|
16822
|
+
}
|
|
16823
|
+
};
|
|
16824
|
+
|
|
16825
|
+
// src/mcp/tools/checkForNewAvailableFixes/CheckForNewAvailableFixesService.ts
|
|
16826
|
+
init_configs();
|
|
16827
|
+
|
|
16828
|
+
// src/mcp/core/prompts.ts
|
|
16829
|
+
init_configs();
|
|
16830
|
+
function friendlyType(s) {
|
|
16831
|
+
const withoutUnderscores = s.replace(/_/g, " ");
|
|
16832
|
+
const result = withoutUnderscores.replace(/([a-z])([A-Z])/g, "$1 $2");
|
|
16833
|
+
return result.charAt(0).toUpperCase() + result.slice(1);
|
|
16834
|
+
}
|
|
16835
|
+
var noFixesReturnedForParameters = `No fixes returned for the given offset and limit parameters.
|
|
16836
|
+
`;
|
|
16837
|
+
var noFixesReturnedForParametersWithGuidance = ({
|
|
16838
|
+
offset,
|
|
16839
|
+
limit,
|
|
16840
|
+
totalCount,
|
|
16841
|
+
currentTool
|
|
16842
|
+
}) => `## No Fixes Returned for Current Parameters
|
|
16843
|
+
|
|
16844
|
+
**\u{1F4C4} Current Request:**
|
|
16845
|
+
- **Page:** ${Math.floor(offset / limit) + 1}
|
|
16846
|
+
- **Offset:** ${offset}
|
|
16847
|
+
- **Limit:** ${limit}
|
|
16848
|
+
|
|
16849
|
+
**\u274C Result:** No fixes returned for the given offset and limit parameters.
|
|
16850
|
+
|
|
16851
|
+
**\u2139\uFE0F Available Fixes:** ${totalCount} total fixes are available, but your current offset (${offset}) is beyond the available range.
|
|
16852
|
+
|
|
16853
|
+
**\u2705 How to Get the Fixes:**
|
|
16854
|
+
|
|
16855
|
+
To retrieve the available fixes, use one of these approaches:
|
|
16856
|
+
|
|
16857
|
+
1. **Start from the beginning:**
|
|
16858
|
+
\`\`\`
|
|
16859
|
+
offset: 0
|
|
15034
16860
|
\`\`\`
|
|
15035
16861
|
|
|
15036
16862
|
2. **Go to the first page:**
|
|
@@ -15553,10 +17379,10 @@ If you wish to scan files that were recently changed in your git history call th
|
|
|
15553
17379
|
init_FileUtils();
|
|
15554
17380
|
init_GitService();
|
|
15555
17381
|
init_configs();
|
|
15556
|
-
import
|
|
17382
|
+
import fs14 from "fs/promises";
|
|
15557
17383
|
import nodePath from "path";
|
|
15558
17384
|
var getLocalFiles = async ({
|
|
15559
|
-
path:
|
|
17385
|
+
path: path18,
|
|
15560
17386
|
maxFileSize = MCP_MAX_FILE_SIZE,
|
|
15561
17387
|
maxFiles,
|
|
15562
17388
|
isAllFilesScan,
|
|
@@ -15564,17 +17390,17 @@ var getLocalFiles = async ({
|
|
|
15564
17390
|
scanRecentlyChangedFiles
|
|
15565
17391
|
}) => {
|
|
15566
17392
|
logDebug(`[${scanContext}] Starting getLocalFiles`, {
|
|
15567
|
-
path:
|
|
17393
|
+
path: path18,
|
|
15568
17394
|
maxFileSize,
|
|
15569
17395
|
maxFiles,
|
|
15570
17396
|
isAllFilesScan,
|
|
15571
17397
|
scanRecentlyChangedFiles
|
|
15572
17398
|
});
|
|
15573
17399
|
try {
|
|
15574
|
-
const resolvedRepoPath = await
|
|
17400
|
+
const resolvedRepoPath = await fs14.realpath(path18);
|
|
15575
17401
|
logDebug(`[${scanContext}] Resolved repository path`, {
|
|
15576
17402
|
resolvedRepoPath,
|
|
15577
|
-
originalPath:
|
|
17403
|
+
originalPath: path18
|
|
15578
17404
|
});
|
|
15579
17405
|
const gitService = new GitService(resolvedRepoPath, log);
|
|
15580
17406
|
const gitValidation = await gitService.validateRepository();
|
|
@@ -15587,7 +17413,7 @@ var getLocalFiles = async ({
|
|
|
15587
17413
|
if (!gitValidation.isValid || isAllFilesScan) {
|
|
15588
17414
|
try {
|
|
15589
17415
|
files = await FileUtils.getLastChangedFiles({
|
|
15590
|
-
dir:
|
|
17416
|
+
dir: path18,
|
|
15591
17417
|
maxFileSize,
|
|
15592
17418
|
maxFiles,
|
|
15593
17419
|
isAllFilesScan
|
|
@@ -15651,7 +17477,7 @@ var getLocalFiles = async ({
|
|
|
15651
17477
|
absoluteFilePath
|
|
15652
17478
|
);
|
|
15653
17479
|
try {
|
|
15654
|
-
const fileStat = await
|
|
17480
|
+
const fileStat = await fs14.stat(absoluteFilePath);
|
|
15655
17481
|
return {
|
|
15656
17482
|
filename: nodePath.basename(absoluteFilePath),
|
|
15657
17483
|
relativePath,
|
|
@@ -15679,23 +17505,23 @@ var getLocalFiles = async ({
|
|
|
15679
17505
|
logError(`${scanContext}Unexpected error in getLocalFiles`, {
|
|
15680
17506
|
error: error instanceof Error ? error.message : String(error),
|
|
15681
17507
|
stack: error instanceof Error ? error.stack : void 0,
|
|
15682
|
-
path:
|
|
17508
|
+
path: path18
|
|
15683
17509
|
});
|
|
15684
17510
|
throw error;
|
|
15685
17511
|
}
|
|
15686
17512
|
};
|
|
15687
17513
|
|
|
15688
17514
|
// src/mcp/services/LocalMobbFolderService.ts
|
|
15689
|
-
import
|
|
15690
|
-
import
|
|
15691
|
-
import { z as
|
|
17515
|
+
import fs15 from "fs";
|
|
17516
|
+
import path14 from "path";
|
|
17517
|
+
import { z as z39 } from "zod";
|
|
15692
17518
|
init_GitService();
|
|
15693
17519
|
function extractPathFromPatch(patch) {
|
|
15694
17520
|
const match = patch?.match(/diff --git a\/([^\s]+) b\//);
|
|
15695
17521
|
return match?.[1] ?? null;
|
|
15696
17522
|
}
|
|
15697
17523
|
function parsedIssueTypeRes(issueType) {
|
|
15698
|
-
return
|
|
17524
|
+
return z39.nativeEnum(IssueType_Enum).safeParse(issueType);
|
|
15699
17525
|
}
|
|
15700
17526
|
var LocalMobbFolderService = class {
|
|
15701
17527
|
/**
|
|
@@ -15774,19 +17600,19 @@ var LocalMobbFolderService = class {
|
|
|
15774
17600
|
"[LocalMobbFolderService] Non-git repository detected, skipping .gitignore operations"
|
|
15775
17601
|
);
|
|
15776
17602
|
}
|
|
15777
|
-
const mobbFolderPath =
|
|
17603
|
+
const mobbFolderPath = path14.join(
|
|
15778
17604
|
this.repoPath,
|
|
15779
17605
|
this.defaultMobbFolderName
|
|
15780
17606
|
);
|
|
15781
|
-
if (!
|
|
17607
|
+
if (!fs15.existsSync(mobbFolderPath)) {
|
|
15782
17608
|
logInfo("[LocalMobbFolderService] Creating .mobb folder", {
|
|
15783
17609
|
mobbFolderPath
|
|
15784
17610
|
});
|
|
15785
|
-
|
|
17611
|
+
fs15.mkdirSync(mobbFolderPath, { recursive: true });
|
|
15786
17612
|
} else {
|
|
15787
17613
|
logDebug("[LocalMobbFolderService] .mobb folder already exists");
|
|
15788
17614
|
}
|
|
15789
|
-
const stats =
|
|
17615
|
+
const stats = fs15.statSync(mobbFolderPath);
|
|
15790
17616
|
if (!stats.isDirectory()) {
|
|
15791
17617
|
throw new Error(`Path exists but is not a directory: ${mobbFolderPath}`);
|
|
15792
17618
|
}
|
|
@@ -15827,13 +17653,13 @@ var LocalMobbFolderService = class {
|
|
|
15827
17653
|
logDebug("[LocalMobbFolderService] Git repository validated successfully");
|
|
15828
17654
|
} else {
|
|
15829
17655
|
try {
|
|
15830
|
-
const stats =
|
|
17656
|
+
const stats = fs15.statSync(this.repoPath);
|
|
15831
17657
|
if (!stats.isDirectory()) {
|
|
15832
17658
|
throw new Error(
|
|
15833
17659
|
`Path exists but is not a directory: ${this.repoPath}`
|
|
15834
17660
|
);
|
|
15835
17661
|
}
|
|
15836
|
-
|
|
17662
|
+
fs15.accessSync(this.repoPath, fs15.constants.R_OK | fs15.constants.W_OK);
|
|
15837
17663
|
logDebug(
|
|
15838
17664
|
"[LocalMobbFolderService] Non-git directory validated successfully"
|
|
15839
17665
|
);
|
|
@@ -15946,8 +17772,8 @@ var LocalMobbFolderService = class {
|
|
|
15946
17772
|
mobbFolderPath,
|
|
15947
17773
|
baseFileName
|
|
15948
17774
|
);
|
|
15949
|
-
const filePath =
|
|
15950
|
-
await
|
|
17775
|
+
const filePath = path14.join(mobbFolderPath, uniqueFileName);
|
|
17776
|
+
await fs15.promises.writeFile(filePath, patch, "utf8");
|
|
15951
17777
|
logInfo("[LocalMobbFolderService] Patch saved successfully", {
|
|
15952
17778
|
filePath,
|
|
15953
17779
|
fileName: uniqueFileName,
|
|
@@ -16004,11 +17830,11 @@ var LocalMobbFolderService = class {
|
|
|
16004
17830
|
* @returns Unique filename that doesn't conflict with existing files
|
|
16005
17831
|
*/
|
|
16006
17832
|
getUniqueFileName(folderPath, baseFileName) {
|
|
16007
|
-
const baseName =
|
|
16008
|
-
const extension =
|
|
17833
|
+
const baseName = path14.parse(baseFileName).name;
|
|
17834
|
+
const extension = path14.parse(baseFileName).ext;
|
|
16009
17835
|
let uniqueFileName = baseFileName;
|
|
16010
17836
|
let index = 1;
|
|
16011
|
-
while (
|
|
17837
|
+
while (fs15.existsSync(path14.join(folderPath, uniqueFileName))) {
|
|
16012
17838
|
uniqueFileName = `${baseName}-${index}${extension}`;
|
|
16013
17839
|
index++;
|
|
16014
17840
|
if (index > 1e3) {
|
|
@@ -16039,18 +17865,18 @@ var LocalMobbFolderService = class {
|
|
|
16039
17865
|
logDebug("[LocalMobbFolderService] Logging patch info", { fixId: fix.id });
|
|
16040
17866
|
try {
|
|
16041
17867
|
const mobbFolderPath = await this.getFolder();
|
|
16042
|
-
const patchInfoPath =
|
|
17868
|
+
const patchInfoPath = path14.join(mobbFolderPath, "patchInfo.md");
|
|
16043
17869
|
const markdownContent = this.generateFixMarkdown(fix, savedPatchFileName);
|
|
16044
17870
|
let existingContent = "";
|
|
16045
|
-
if (
|
|
16046
|
-
existingContent = await
|
|
17871
|
+
if (fs15.existsSync(patchInfoPath)) {
|
|
17872
|
+
existingContent = await fs15.promises.readFile(patchInfoPath, "utf8");
|
|
16047
17873
|
logDebug("[LocalMobbFolderService] Existing patchInfo.md found");
|
|
16048
17874
|
} else {
|
|
16049
17875
|
logDebug("[LocalMobbFolderService] Creating new patchInfo.md file");
|
|
16050
17876
|
}
|
|
16051
17877
|
const separator = existingContent ? "\n\n================================================================================\n\n" : "";
|
|
16052
17878
|
const updatedContent = `${markdownContent}${separator}${existingContent}`;
|
|
16053
|
-
await
|
|
17879
|
+
await fs15.promises.writeFile(patchInfoPath, updatedContent, "utf8");
|
|
16054
17880
|
logInfo("[LocalMobbFolderService] Patch info logged successfully", {
|
|
16055
17881
|
patchInfoPath,
|
|
16056
17882
|
fixId: fix.id,
|
|
@@ -16081,7 +17907,7 @@ var LocalMobbFolderService = class {
|
|
|
16081
17907
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
16082
17908
|
const patch = this.extractPatchFromFix(fix);
|
|
16083
17909
|
const relativePatchedFilePath = patch ? extractPathFromPatch(patch) : null;
|
|
16084
|
-
const patchedFilePath = relativePatchedFilePath ?
|
|
17910
|
+
const patchedFilePath = relativePatchedFilePath ? path14.resolve(this.repoPath, relativePatchedFilePath) : null;
|
|
16085
17911
|
const fixIdentifier = savedPatchFileName ? savedPatchFileName.replace(".patch", "") : fix.id;
|
|
16086
17912
|
let markdown = `# Fix ${fixIdentifier}
|
|
16087
17913
|
|
|
@@ -16423,16 +18249,16 @@ import {
|
|
|
16423
18249
|
unlinkSync,
|
|
16424
18250
|
writeFileSync
|
|
16425
18251
|
} from "fs";
|
|
16426
|
-
import
|
|
18252
|
+
import fs16 from "fs/promises";
|
|
16427
18253
|
import parseDiff2 from "parse-diff";
|
|
16428
|
-
import
|
|
18254
|
+
import path15 from "path";
|
|
16429
18255
|
var PatchApplicationService = class {
|
|
16430
18256
|
/**
|
|
16431
18257
|
* Gets the appropriate comment syntax for a file based on its extension
|
|
16432
18258
|
*/
|
|
16433
18259
|
static getCommentSyntax(filePath) {
|
|
16434
|
-
const ext =
|
|
16435
|
-
const basename2 =
|
|
18260
|
+
const ext = path15.extname(filePath).toLowerCase();
|
|
18261
|
+
const basename2 = path15.basename(filePath);
|
|
16436
18262
|
const commentMap = {
|
|
16437
18263
|
// C-style languages (single line comments)
|
|
16438
18264
|
".js": "//",
|
|
@@ -16635,7 +18461,7 @@ var PatchApplicationService = class {
|
|
|
16635
18461
|
}
|
|
16636
18462
|
);
|
|
16637
18463
|
}
|
|
16638
|
-
const dirPath =
|
|
18464
|
+
const dirPath = path15.dirname(filePath);
|
|
16639
18465
|
mkdirSync(dirPath, { recursive: true });
|
|
16640
18466
|
writeFileSync(filePath, finalContent, "utf8");
|
|
16641
18467
|
return filePath;
|
|
@@ -16919,9 +18745,9 @@ var PatchApplicationService = class {
|
|
|
16919
18745
|
continue;
|
|
16920
18746
|
}
|
|
16921
18747
|
try {
|
|
16922
|
-
const absolutePath =
|
|
18748
|
+
const absolutePath = path15.resolve(repositoryPath, targetFile);
|
|
16923
18749
|
if (existsSync2(absolutePath)) {
|
|
16924
|
-
const stats = await
|
|
18750
|
+
const stats = await fs16.stat(absolutePath);
|
|
16925
18751
|
const fileModTime = stats.mtime.getTime();
|
|
16926
18752
|
if (fileModTime > scanStartTime) {
|
|
16927
18753
|
logError(
|
|
@@ -16962,7 +18788,7 @@ var PatchApplicationService = class {
|
|
|
16962
18788
|
const appliedFixes = [];
|
|
16963
18789
|
const failedFixes = [];
|
|
16964
18790
|
const skippedFixes = [];
|
|
16965
|
-
const resolvedRepoPath = await
|
|
18791
|
+
const resolvedRepoPath = await fs16.realpath(repositoryPath);
|
|
16966
18792
|
logInfo(
|
|
16967
18793
|
`[${scanContext}] Starting patch application for ${fixes.length} fixes`,
|
|
16968
18794
|
{
|
|
@@ -17110,11 +18936,11 @@ var PatchApplicationService = class {
|
|
|
17110
18936
|
}) {
|
|
17111
18937
|
const sanitizedRepoPath = String(repositoryPath || "").replace("\0", "").replace(/^(\.\.(\/|\\))+/, "");
|
|
17112
18938
|
const sanitizedTargetFile = String(targetFile || "").replace("\0", "").replace(/^(\.\.(\/|\\))+/, "");
|
|
17113
|
-
const absoluteFilePath =
|
|
18939
|
+
const absoluteFilePath = path15.resolve(
|
|
17114
18940
|
sanitizedRepoPath,
|
|
17115
18941
|
sanitizedTargetFile
|
|
17116
18942
|
);
|
|
17117
|
-
const relativePath =
|
|
18943
|
+
const relativePath = path15.relative(sanitizedRepoPath, absoluteFilePath);
|
|
17118
18944
|
if (relativePath.startsWith("..")) {
|
|
17119
18945
|
throw new Error(
|
|
17120
18946
|
`Security violation: target file ${targetFile} resolves outside repository`
|
|
@@ -17148,7 +18974,7 @@ var PatchApplicationService = class {
|
|
|
17148
18974
|
fix,
|
|
17149
18975
|
scanContext
|
|
17150
18976
|
});
|
|
17151
|
-
appliedFiles.push(
|
|
18977
|
+
appliedFiles.push(path15.relative(repositoryPath, actualPath));
|
|
17152
18978
|
logDebug(`[${scanContext}] Created new file: ${relativePath}`);
|
|
17153
18979
|
}
|
|
17154
18980
|
/**
|
|
@@ -17196,7 +19022,7 @@ var PatchApplicationService = class {
|
|
|
17196
19022
|
fix,
|
|
17197
19023
|
scanContext
|
|
17198
19024
|
});
|
|
17199
|
-
appliedFiles.push(
|
|
19025
|
+
appliedFiles.push(path15.relative(repositoryPath, actualPath));
|
|
17200
19026
|
logDebug(`[${scanContext}] Modified file: ${relativePath}`);
|
|
17201
19027
|
}
|
|
17202
19028
|
}
|
|
@@ -17391,8 +19217,8 @@ init_configs();
|
|
|
17391
19217
|
|
|
17392
19218
|
// src/mcp/services/FileOperations.ts
|
|
17393
19219
|
init_FileUtils();
|
|
17394
|
-
import
|
|
17395
|
-
import
|
|
19220
|
+
import fs17 from "fs";
|
|
19221
|
+
import path16 from "path";
|
|
17396
19222
|
import AdmZip2 from "adm-zip";
|
|
17397
19223
|
var FileOperations = class {
|
|
17398
19224
|
/**
|
|
@@ -17412,10 +19238,10 @@ var FileOperations = class {
|
|
|
17412
19238
|
let packedFilesCount = 0;
|
|
17413
19239
|
const packedFiles = [];
|
|
17414
19240
|
const excludedFiles = [];
|
|
17415
|
-
const resolvedRepoPath =
|
|
19241
|
+
const resolvedRepoPath = path16.resolve(repositoryPath);
|
|
17416
19242
|
for (const filepath of fileList) {
|
|
17417
|
-
const absoluteFilepath =
|
|
17418
|
-
const resolvedFilePath =
|
|
19243
|
+
const absoluteFilepath = path16.join(repositoryPath, filepath);
|
|
19244
|
+
const resolvedFilePath = path16.resolve(absoluteFilepath);
|
|
17419
19245
|
if (!resolvedFilePath.startsWith(resolvedRepoPath)) {
|
|
17420
19246
|
const reason = "potential path traversal security risk";
|
|
17421
19247
|
logDebug(`[FileOperations] Skipping ${filepath} due to ${reason}`);
|
|
@@ -17462,11 +19288,11 @@ var FileOperations = class {
|
|
|
17462
19288
|
fileList,
|
|
17463
19289
|
repositoryPath
|
|
17464
19290
|
}) {
|
|
17465
|
-
const resolvedRepoPath =
|
|
19291
|
+
const resolvedRepoPath = path16.resolve(repositoryPath);
|
|
17466
19292
|
const validatedPaths = [];
|
|
17467
19293
|
for (const filepath of fileList) {
|
|
17468
|
-
const absoluteFilepath =
|
|
17469
|
-
const resolvedFilePath =
|
|
19294
|
+
const absoluteFilepath = path16.join(repositoryPath, filepath);
|
|
19295
|
+
const resolvedFilePath = path16.resolve(absoluteFilepath);
|
|
17470
19296
|
if (!resolvedFilePath.startsWith(resolvedRepoPath)) {
|
|
17471
19297
|
logDebug(
|
|
17472
19298
|
`[FileOperations] Rejecting ${filepath} - path traversal attempt detected`
|
|
@@ -17474,7 +19300,7 @@ var FileOperations = class {
|
|
|
17474
19300
|
continue;
|
|
17475
19301
|
}
|
|
17476
19302
|
try {
|
|
17477
|
-
await
|
|
19303
|
+
await fs17.promises.access(absoluteFilepath, fs17.constants.R_OK);
|
|
17478
19304
|
validatedPaths.push(filepath);
|
|
17479
19305
|
} catch (error) {
|
|
17480
19306
|
logDebug(
|
|
@@ -17493,8 +19319,8 @@ var FileOperations = class {
|
|
|
17493
19319
|
const fileDataArray = [];
|
|
17494
19320
|
for (const absolutePath of filePaths) {
|
|
17495
19321
|
try {
|
|
17496
|
-
const content = await
|
|
17497
|
-
const relativePath =
|
|
19322
|
+
const content = await fs17.promises.readFile(absolutePath);
|
|
19323
|
+
const relativePath = path16.basename(absolutePath);
|
|
17498
19324
|
fileDataArray.push({
|
|
17499
19325
|
relativePath,
|
|
17500
19326
|
absolutePath,
|
|
@@ -17519,7 +19345,7 @@ var FileOperations = class {
|
|
|
17519
19345
|
relativeFilepath
|
|
17520
19346
|
}) {
|
|
17521
19347
|
try {
|
|
17522
|
-
return await
|
|
19348
|
+
return await fs17.promises.readFile(absoluteFilepath);
|
|
17523
19349
|
} catch (fsError) {
|
|
17524
19350
|
logError(
|
|
17525
19351
|
`[FileOperations] Failed to read ${relativeFilepath} from filesystem: ${fsError}`
|
|
@@ -17806,14 +19632,14 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
17806
19632
|
* since the last scan.
|
|
17807
19633
|
*/
|
|
17808
19634
|
async scanForSecurityVulnerabilities({
|
|
17809
|
-
path:
|
|
19635
|
+
path: path18,
|
|
17810
19636
|
isAllDetectionRulesScan,
|
|
17811
19637
|
isAllFilesScan,
|
|
17812
19638
|
scanContext
|
|
17813
19639
|
}) {
|
|
17814
19640
|
this.hasAuthenticationFailed = false;
|
|
17815
19641
|
logDebug(`[${scanContext}] Scanning for new security vulnerabilities`, {
|
|
17816
|
-
path:
|
|
19642
|
+
path: path18
|
|
17817
19643
|
});
|
|
17818
19644
|
if (!this.gqlClient) {
|
|
17819
19645
|
logInfo(`[${scanContext}] No GQL client found, skipping scan`);
|
|
@@ -17829,11 +19655,11 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
17829
19655
|
}
|
|
17830
19656
|
logDebug(
|
|
17831
19657
|
`[${scanContext}] Connected to the API, assembling list of files to scan`,
|
|
17832
|
-
{ path:
|
|
19658
|
+
{ path: path18 }
|
|
17833
19659
|
);
|
|
17834
19660
|
const isBackgroundScan = scanContext === ScanContext.BACKGROUND_INITIAL || scanContext === ScanContext.BACKGROUND_PERIODIC;
|
|
17835
19661
|
const files = await getLocalFiles({
|
|
17836
|
-
path:
|
|
19662
|
+
path: path18,
|
|
17837
19663
|
isAllFilesScan,
|
|
17838
19664
|
scanContext,
|
|
17839
19665
|
scanRecentlyChangedFiles: !isBackgroundScan
|
|
@@ -17859,13 +19685,13 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
17859
19685
|
});
|
|
17860
19686
|
const { fixReportId, projectId } = await scanFiles({
|
|
17861
19687
|
fileList: filesToScan.map((file) => file.relativePath),
|
|
17862
|
-
repositoryPath:
|
|
19688
|
+
repositoryPath: path18,
|
|
17863
19689
|
gqlClient: this.gqlClient,
|
|
17864
19690
|
isAllDetectionRulesScan,
|
|
17865
19691
|
scanContext
|
|
17866
19692
|
});
|
|
17867
19693
|
logInfo(
|
|
17868
|
-
`[${scanContext}] Security scan completed for ${
|
|
19694
|
+
`[${scanContext}] Security scan completed for ${path18} reportId: ${fixReportId} projectId: ${projectId}`
|
|
17869
19695
|
);
|
|
17870
19696
|
if (isAllFilesScan) {
|
|
17871
19697
|
return;
|
|
@@ -18159,13 +19985,13 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
18159
19985
|
});
|
|
18160
19986
|
return scannedFiles.some((file) => file.relativePath === fixFile);
|
|
18161
19987
|
}
|
|
18162
|
-
async getFreshFixes({ path:
|
|
19988
|
+
async getFreshFixes({ path: path18 }) {
|
|
18163
19989
|
const scanContext = ScanContext.USER_REQUEST;
|
|
18164
|
-
logDebug(`[${scanContext}] Getting fresh fixes`, { path:
|
|
18165
|
-
if (this.path !==
|
|
18166
|
-
this.path =
|
|
19990
|
+
logDebug(`[${scanContext}] Getting fresh fixes`, { path: path18 });
|
|
19991
|
+
if (this.path !== path18) {
|
|
19992
|
+
this.path = path18;
|
|
18167
19993
|
this.reset();
|
|
18168
|
-
logInfo(`[${scanContext}] Reset service state for new path`, { path:
|
|
19994
|
+
logInfo(`[${scanContext}] Reset service state for new path`, { path: path18 });
|
|
18169
19995
|
}
|
|
18170
19996
|
try {
|
|
18171
19997
|
this.gqlClient = await createAuthenticatedMcpGQLClient();
|
|
@@ -18183,7 +20009,7 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
18183
20009
|
}
|
|
18184
20010
|
throw error;
|
|
18185
20011
|
}
|
|
18186
|
-
this.triggerScan({ path:
|
|
20012
|
+
this.triggerScan({ path: path18, gqlClient: this.gqlClient });
|
|
18187
20013
|
let isMvsAutoFixEnabled = null;
|
|
18188
20014
|
try {
|
|
18189
20015
|
isMvsAutoFixEnabled = await this.gqlClient.getMvsAutoFixSettings();
|
|
@@ -18217,33 +20043,33 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
18217
20043
|
return noFreshFixesPrompt;
|
|
18218
20044
|
}
|
|
18219
20045
|
triggerScan({
|
|
18220
|
-
path:
|
|
20046
|
+
path: path18,
|
|
18221
20047
|
gqlClient
|
|
18222
20048
|
}) {
|
|
18223
|
-
if (this.path !==
|
|
18224
|
-
this.path =
|
|
20049
|
+
if (this.path !== path18) {
|
|
20050
|
+
this.path = path18;
|
|
18225
20051
|
this.reset();
|
|
18226
|
-
logInfo(`Reset service state for new path in triggerScan`, { path:
|
|
20052
|
+
logInfo(`Reset service state for new path in triggerScan`, { path: path18 });
|
|
18227
20053
|
}
|
|
18228
20054
|
this.gqlClient = gqlClient;
|
|
18229
20055
|
if (!this.intervalId) {
|
|
18230
|
-
this.startPeriodicScanning(
|
|
18231
|
-
this.executeInitialScan(
|
|
18232
|
-
void this.executeInitialFullScan(
|
|
20056
|
+
this.startPeriodicScanning(path18);
|
|
20057
|
+
this.executeInitialScan(path18);
|
|
20058
|
+
void this.executeInitialFullScan(path18);
|
|
18233
20059
|
}
|
|
18234
20060
|
}
|
|
18235
|
-
startPeriodicScanning(
|
|
20061
|
+
startPeriodicScanning(path18) {
|
|
18236
20062
|
const scanContext = ScanContext.BACKGROUND_PERIODIC;
|
|
18237
20063
|
logDebug(
|
|
18238
20064
|
`[${scanContext}] Starting periodic scan for new security vulnerabilities`,
|
|
18239
20065
|
{
|
|
18240
|
-
path:
|
|
20066
|
+
path: path18
|
|
18241
20067
|
}
|
|
18242
20068
|
);
|
|
18243
20069
|
this.intervalId = setInterval(() => {
|
|
18244
|
-
logDebug(`[${scanContext}] Triggering periodic security scan`, { path:
|
|
20070
|
+
logDebug(`[${scanContext}] Triggering periodic security scan`, { path: path18 });
|
|
18245
20071
|
this.scanForSecurityVulnerabilities({
|
|
18246
|
-
path:
|
|
20072
|
+
path: path18,
|
|
18247
20073
|
scanContext
|
|
18248
20074
|
}).catch((error) => {
|
|
18249
20075
|
logError(`[${scanContext}] Error during periodic security scan`, {
|
|
@@ -18252,45 +20078,45 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
18252
20078
|
});
|
|
18253
20079
|
}, MCP_PERIODIC_CHECK_INTERVAL);
|
|
18254
20080
|
}
|
|
18255
|
-
async executeInitialFullScan(
|
|
20081
|
+
async executeInitialFullScan(path18) {
|
|
18256
20082
|
const scanContext = ScanContext.FULL_SCAN;
|
|
18257
|
-
logDebug(`[${scanContext}] Triggering initial full security scan`, { path:
|
|
20083
|
+
logDebug(`[${scanContext}] Triggering initial full security scan`, { path: path18 });
|
|
18258
20084
|
logDebug(`[${scanContext}] Full scan paths scanned`, {
|
|
18259
20085
|
fullScanPathsScanned: this.fullScanPathsScanned
|
|
18260
20086
|
});
|
|
18261
|
-
if (this.fullScanPathsScanned.includes(
|
|
20087
|
+
if (this.fullScanPathsScanned.includes(path18)) {
|
|
18262
20088
|
logDebug(`[${scanContext}] Full scan already executed for this path`, {
|
|
18263
|
-
path:
|
|
20089
|
+
path: path18
|
|
18264
20090
|
});
|
|
18265
20091
|
return;
|
|
18266
20092
|
}
|
|
18267
20093
|
configStore.set("fullScanPathsScanned", [
|
|
18268
20094
|
...this.fullScanPathsScanned,
|
|
18269
|
-
|
|
20095
|
+
path18
|
|
18270
20096
|
]);
|
|
18271
20097
|
try {
|
|
18272
20098
|
await this.scanForSecurityVulnerabilities({
|
|
18273
|
-
path:
|
|
20099
|
+
path: path18,
|
|
18274
20100
|
isAllFilesScan: true,
|
|
18275
20101
|
isAllDetectionRulesScan: true,
|
|
18276
20102
|
scanContext: ScanContext.FULL_SCAN
|
|
18277
20103
|
});
|
|
18278
|
-
if (!this.fullScanPathsScanned.includes(
|
|
18279
|
-
this.fullScanPathsScanned.push(
|
|
20104
|
+
if (!this.fullScanPathsScanned.includes(path18)) {
|
|
20105
|
+
this.fullScanPathsScanned.push(path18);
|
|
18280
20106
|
configStore.set("fullScanPathsScanned", this.fullScanPathsScanned);
|
|
18281
20107
|
}
|
|
18282
|
-
logInfo(`[${scanContext}] Full scan completed`, { path:
|
|
20108
|
+
logInfo(`[${scanContext}] Full scan completed`, { path: path18 });
|
|
18283
20109
|
} catch (error) {
|
|
18284
20110
|
logError(`[${scanContext}] Error during initial full security scan`, {
|
|
18285
20111
|
error
|
|
18286
20112
|
});
|
|
18287
20113
|
}
|
|
18288
20114
|
}
|
|
18289
|
-
executeInitialScan(
|
|
20115
|
+
executeInitialScan(path18) {
|
|
18290
20116
|
const scanContext = ScanContext.BACKGROUND_INITIAL;
|
|
18291
|
-
logDebug(`[${scanContext}] Triggering initial security scan`, { path:
|
|
20117
|
+
logDebug(`[${scanContext}] Triggering initial security scan`, { path: path18 });
|
|
18292
20118
|
this.scanForSecurityVulnerabilities({
|
|
18293
|
-
path:
|
|
20119
|
+
path: path18,
|
|
18294
20120
|
scanContext: ScanContext.BACKGROUND_INITIAL
|
|
18295
20121
|
}).catch((error) => {
|
|
18296
20122
|
logError(`[${scanContext}] Error during initial security scan`, { error });
|
|
@@ -18369,8 +20195,8 @@ Example payload:
|
|
|
18369
20195
|
},
|
|
18370
20196
|
required: ["path"]
|
|
18371
20197
|
});
|
|
18372
|
-
__publicField(this, "inputValidationSchema",
|
|
18373
|
-
path:
|
|
20198
|
+
__publicField(this, "inputValidationSchema", z40.object({
|
|
20199
|
+
path: z40.string().describe(
|
|
18374
20200
|
"Full local path to the cloned git repository to check for new available fixes"
|
|
18375
20201
|
)
|
|
18376
20202
|
}));
|
|
@@ -18387,9 +20213,9 @@ Example payload:
|
|
|
18387
20213
|
`Invalid path: potential security risk detected in path: ${pathValidationResult.error}`
|
|
18388
20214
|
);
|
|
18389
20215
|
}
|
|
18390
|
-
const
|
|
20216
|
+
const path18 = pathValidationResult.path;
|
|
18391
20217
|
const resultText = await this.newFixesService.getFreshFixes({
|
|
18392
|
-
path:
|
|
20218
|
+
path: path18
|
|
18393
20219
|
});
|
|
18394
20220
|
logInfo("CheckForNewAvailableFixesTool execution completed", {
|
|
18395
20221
|
resultText
|
|
@@ -18400,7 +20226,7 @@ Example payload:
|
|
|
18400
20226
|
|
|
18401
20227
|
// src/mcp/tools/fetchAvailableFixes/FetchAvailableFixesTool.ts
|
|
18402
20228
|
init_GitService();
|
|
18403
|
-
import { z as
|
|
20229
|
+
import { z as z41 } from "zod";
|
|
18404
20230
|
|
|
18405
20231
|
// src/mcp/tools/fetchAvailableFixes/FetchAvailableFixesService.ts
|
|
18406
20232
|
init_configs();
|
|
@@ -18542,16 +20368,16 @@ Call this tool instead of ${MCP_TOOL_SCAN_AND_FIX_VULNERABILITIES} when you only
|
|
|
18542
20368
|
},
|
|
18543
20369
|
required: ["path"]
|
|
18544
20370
|
});
|
|
18545
|
-
__publicField(this, "inputValidationSchema",
|
|
18546
|
-
path:
|
|
20371
|
+
__publicField(this, "inputValidationSchema", z41.object({
|
|
20372
|
+
path: z41.string().describe(
|
|
18547
20373
|
"Full local path to the cloned git repository to check for available fixes"
|
|
18548
20374
|
),
|
|
18549
|
-
offset:
|
|
18550
|
-
limit:
|
|
18551
|
-
fileFilter:
|
|
20375
|
+
offset: z41.number().optional().describe("Optional offset for pagination"),
|
|
20376
|
+
limit: z41.number().optional().describe("Optional maximum number of fixes to return"),
|
|
20377
|
+
fileFilter: z41.array(z41.string()).optional().describe(
|
|
18552
20378
|
"Optional list of file paths relative to the path parameter to filter fixes by. INCOMPATIBLE with fetchFixesFromAnyFile"
|
|
18553
20379
|
),
|
|
18554
|
-
fetchFixesFromAnyFile:
|
|
20380
|
+
fetchFixesFromAnyFile: z41.boolean().optional().describe(
|
|
18555
20381
|
"Optional boolean to fetch fixes for all files. INCOMPATIBLE with fileFilter"
|
|
18556
20382
|
)
|
|
18557
20383
|
}));
|
|
@@ -18566,8 +20392,8 @@ Call this tool instead of ${MCP_TOOL_SCAN_AND_FIX_VULNERABILITIES} when you only
|
|
|
18566
20392
|
`Invalid path: potential security risk detected in path: ${pathValidationResult.error}`
|
|
18567
20393
|
);
|
|
18568
20394
|
}
|
|
18569
|
-
const
|
|
18570
|
-
const gitService = new GitService(
|
|
20395
|
+
const path18 = pathValidationResult.path;
|
|
20396
|
+
const gitService = new GitService(path18, log);
|
|
18571
20397
|
const gitValidation = await gitService.validateRepository();
|
|
18572
20398
|
if (!gitValidation.isValid) {
|
|
18573
20399
|
throw new Error(`Invalid git repository: ${gitValidation.error}`);
|
|
@@ -18620,7 +20446,7 @@ Call this tool instead of ${MCP_TOOL_SCAN_AND_FIX_VULNERABILITIES} when you only
|
|
|
18620
20446
|
};
|
|
18621
20447
|
|
|
18622
20448
|
// src/mcp/tools/mcpChecker/mcpCheckerTool.ts
|
|
18623
|
-
import
|
|
20449
|
+
import z42 from "zod";
|
|
18624
20450
|
|
|
18625
20451
|
// src/mcp/tools/mcpChecker/mcpCheckerService.ts
|
|
18626
20452
|
var _McpCheckerService = class _McpCheckerService {
|
|
@@ -18681,7 +20507,7 @@ var McpCheckerTool = class extends BaseTool {
|
|
|
18681
20507
|
__publicField(this, "displayName", "MCP Checker");
|
|
18682
20508
|
// A detailed description to guide the LLM on when and how to invoke this tool.
|
|
18683
20509
|
__publicField(this, "description", "Check the MCP servers running on this IDE against organization policies.");
|
|
18684
|
-
__publicField(this, "inputValidationSchema",
|
|
20510
|
+
__publicField(this, "inputValidationSchema", z42.object({}));
|
|
18685
20511
|
__publicField(this, "inputSchema", {
|
|
18686
20512
|
type: "object",
|
|
18687
20513
|
properties: {},
|
|
@@ -18707,7 +20533,7 @@ var McpCheckerTool = class extends BaseTool {
|
|
|
18707
20533
|
};
|
|
18708
20534
|
|
|
18709
20535
|
// src/mcp/tools/scanAndFixVulnerabilities/ScanAndFixVulnerabilitiesTool.ts
|
|
18710
|
-
import
|
|
20536
|
+
import z43 from "zod";
|
|
18711
20537
|
init_configs();
|
|
18712
20538
|
|
|
18713
20539
|
// src/mcp/tools/scanAndFixVulnerabilities/ScanAndFixVulnerabilitiesService.ts
|
|
@@ -18894,17 +20720,17 @@ Example payload:
|
|
|
18894
20720
|
"rescan": false
|
|
18895
20721
|
}`);
|
|
18896
20722
|
__publicField(this, "hasAuthentication", true);
|
|
18897
|
-
__publicField(this, "inputValidationSchema",
|
|
18898
|
-
path:
|
|
20723
|
+
__publicField(this, "inputValidationSchema", z43.object({
|
|
20724
|
+
path: z43.string().describe(
|
|
18899
20725
|
"Full local path to repository to scan and fix vulnerabilities"
|
|
18900
20726
|
),
|
|
18901
|
-
offset:
|
|
18902
|
-
limit:
|
|
18903
|
-
maxFiles:
|
|
20727
|
+
offset: z43.number().optional().describe("Optional offset for pagination"),
|
|
20728
|
+
limit: z43.number().optional().describe("Optional maximum number of results to return"),
|
|
20729
|
+
maxFiles: z43.number().optional().describe(
|
|
18904
20730
|
`Optional maximum number of files to scan (default: ${MCP_DEFAULT_MAX_FILES_TO_SCAN}). Increase for comprehensive scans of larger codebases or decrease for faster focused scans.`
|
|
18905
20731
|
),
|
|
18906
|
-
rescan:
|
|
18907
|
-
scanRecentlyChangedFiles:
|
|
20732
|
+
rescan: z43.boolean().optional().describe("Optional whether to rescan the repository"),
|
|
20733
|
+
scanRecentlyChangedFiles: z43.boolean().optional().describe(
|
|
18908
20734
|
"Optional whether to automatically scan recently changed files when no changed files are found in git status. If false, the tool will prompt the user instead."
|
|
18909
20735
|
)
|
|
18910
20736
|
}));
|
|
@@ -18955,9 +20781,9 @@ Example payload:
|
|
|
18955
20781
|
`Invalid path: potential security risk detected in path: ${pathValidationResult.error}`
|
|
18956
20782
|
);
|
|
18957
20783
|
}
|
|
18958
|
-
const
|
|
20784
|
+
const path18 = pathValidationResult.path;
|
|
18959
20785
|
const files = await getLocalFiles({
|
|
18960
|
-
path:
|
|
20786
|
+
path: path18,
|
|
18961
20787
|
maxFileSize: MCP_MAX_FILE_SIZE,
|
|
18962
20788
|
maxFiles: args.maxFiles,
|
|
18963
20789
|
scanContext: ScanContext.USER_REQUEST,
|
|
@@ -18977,7 +20803,7 @@ Example payload:
|
|
|
18977
20803
|
try {
|
|
18978
20804
|
const fixResult = await this.vulnerabilityFixService.processVulnerabilities({
|
|
18979
20805
|
fileList: files.map((file) => file.relativePath),
|
|
18980
|
-
repositoryPath:
|
|
20806
|
+
repositoryPath: path18,
|
|
18981
20807
|
offset: args.offset,
|
|
18982
20808
|
limit: args.limit,
|
|
18983
20809
|
isRescan: args.rescan || !!args.maxFiles
|
|
@@ -19032,6 +20858,19 @@ function createMcpServer(govOrgId) {
|
|
|
19032
20858
|
const mcpCheckerTool = new McpCheckerTool(govOrgId);
|
|
19033
20859
|
registerIfEnabled(mcpCheckerTool);
|
|
19034
20860
|
}
|
|
20861
|
+
logDebug("Registering MCP prompts");
|
|
20862
|
+
const prompts = [
|
|
20863
|
+
new SecurityToolsOverviewPrompt(),
|
|
20864
|
+
new ScanRepositoryPrompt(),
|
|
20865
|
+
new ScanRecentChangesPrompt(),
|
|
20866
|
+
new CheckForNewVulnerabilitiesPrompt(),
|
|
20867
|
+
new ReviewAndFixCriticalPrompt(),
|
|
20868
|
+
new FullSecurityAuditPrompt()
|
|
20869
|
+
];
|
|
20870
|
+
prompts.forEach((prompt) => {
|
|
20871
|
+
server.registerPrompt(prompt);
|
|
20872
|
+
logDebug(`Registered prompt: ${prompt.name}`);
|
|
20873
|
+
});
|
|
19035
20874
|
logInfo("MCP server created and configured");
|
|
19036
20875
|
return server;
|
|
19037
20876
|
}
|
|
@@ -19068,7 +20907,7 @@ var mcpHandler = async (_args) => {
|
|
|
19068
20907
|
};
|
|
19069
20908
|
|
|
19070
20909
|
// src/args/commands/review.ts
|
|
19071
|
-
import
|
|
20910
|
+
import fs18 from "fs";
|
|
19072
20911
|
import chalk9 from "chalk";
|
|
19073
20912
|
function reviewBuilder(yargs2) {
|
|
19074
20913
|
return yargs2.option("f", {
|
|
@@ -19105,7 +20944,7 @@ function reviewBuilder(yargs2) {
|
|
|
19105
20944
|
).help();
|
|
19106
20945
|
}
|
|
19107
20946
|
function validateReviewOptions(argv) {
|
|
19108
|
-
if (!
|
|
20947
|
+
if (!fs18.existsSync(argv.f)) {
|
|
19109
20948
|
throw new CliError(`
|
|
19110
20949
|
Can't access ${chalk9.bold(argv.f)}`);
|
|
19111
20950
|
}
|
|
@@ -19179,34 +21018,34 @@ async function addScmTokenHandler(args) {
|
|
|
19179
21018
|
|
|
19180
21019
|
// src/args/commands/upload_ai_blame.ts
|
|
19181
21020
|
import fsPromises3 from "fs/promises";
|
|
19182
|
-
import
|
|
21021
|
+
import path17 from "path";
|
|
19183
21022
|
import chalk10 from "chalk";
|
|
19184
21023
|
import Configstore6 from "configstore";
|
|
19185
21024
|
import { withFile } from "tmp-promise";
|
|
19186
|
-
import
|
|
19187
|
-
var PromptItemZ =
|
|
19188
|
-
type:
|
|
19189
|
-
attachedFiles:
|
|
19190
|
-
|
|
19191
|
-
relativePath:
|
|
19192
|
-
startLine:
|
|
21025
|
+
import z44 from "zod";
|
|
21026
|
+
var PromptItemZ = z44.object({
|
|
21027
|
+
type: z44.enum(["USER_PROMPT", "AI_RESPONSE", "TOOL_EXECUTION", "AI_THINKING"]),
|
|
21028
|
+
attachedFiles: z44.array(
|
|
21029
|
+
z44.object({
|
|
21030
|
+
relativePath: z44.string(),
|
|
21031
|
+
startLine: z44.number().optional()
|
|
19193
21032
|
})
|
|
19194
21033
|
).optional(),
|
|
19195
|
-
tokens:
|
|
19196
|
-
inputCount:
|
|
19197
|
-
outputCount:
|
|
21034
|
+
tokens: z44.object({
|
|
21035
|
+
inputCount: z44.number(),
|
|
21036
|
+
outputCount: z44.number()
|
|
19198
21037
|
}).optional(),
|
|
19199
|
-
text:
|
|
19200
|
-
date:
|
|
19201
|
-
tool:
|
|
19202
|
-
name:
|
|
19203
|
-
parameters:
|
|
19204
|
-
result:
|
|
19205
|
-
rawArguments:
|
|
19206
|
-
accepted:
|
|
21038
|
+
text: z44.string().optional(),
|
|
21039
|
+
date: z44.date().optional(),
|
|
21040
|
+
tool: z44.object({
|
|
21041
|
+
name: z44.string(),
|
|
21042
|
+
parameters: z44.string(),
|
|
21043
|
+
result: z44.string(),
|
|
21044
|
+
rawArguments: z44.string().optional(),
|
|
21045
|
+
accepted: z44.boolean().optional()
|
|
19207
21046
|
}).optional()
|
|
19208
21047
|
});
|
|
19209
|
-
var PromptItemArrayZ =
|
|
21048
|
+
var PromptItemArrayZ = z44.array(PromptItemZ);
|
|
19210
21049
|
function uploadAiBlameBuilder(args) {
|
|
19211
21050
|
return args.option("prompt", {
|
|
19212
21051
|
type: "string",
|
|
@@ -19281,8 +21120,8 @@ async function uploadAiBlameHandler(args, exitOnError = true) {
|
|
|
19281
21120
|
throw new Error(errorMsg);
|
|
19282
21121
|
}
|
|
19283
21122
|
sessions.push({
|
|
19284
|
-
promptFileName:
|
|
19285
|
-
inferenceFileName:
|
|
21123
|
+
promptFileName: path17.basename(promptPath),
|
|
21124
|
+
inferenceFileName: path17.basename(inferencePath),
|
|
19286
21125
|
aiResponseAt: responseTimes[i] || nowIso,
|
|
19287
21126
|
model: models[i],
|
|
19288
21127
|
toolName: tools[i]
|