mobbdev 1.0.95 → 1.0.98

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.
Files changed (2) hide show
  1. package/dist/index.mjs +671 -169
  2. package/package.json +11 -11
package/dist/index.mjs CHANGED
@@ -370,6 +370,7 @@ var IssueType_Enum = /* @__PURE__ */ ((IssueType_Enum2) => {
370
370
  IssueType_Enum2["DangerousFunctionOverflow"] = "DANGEROUS_FUNCTION_OVERFLOW";
371
371
  IssueType_Enum2["DeadCodeUnusedField"] = "DEAD_CODE_UNUSED_FIELD";
372
372
  IssueType_Enum2["DebugEnabled"] = "DEBUG_ENABLED";
373
+ IssueType_Enum2["DeclareVariableExplicitly"] = "DECLARE_VARIABLE_EXPLICITLY";
373
374
  IssueType_Enum2["DefaultRightsInObjDefinition"] = "DEFAULT_RIGHTS_IN_OBJ_DEFINITION";
374
375
  IssueType_Enum2["DeprecatedFunction"] = "DEPRECATED_FUNCTION";
375
376
  IssueType_Enum2["DosStringBuilder"] = "DOS_STRING_BUILDER";
@@ -417,6 +418,7 @@ var IssueType_Enum = /* @__PURE__ */ ((IssueType_Enum2) => {
417
418
  IssueType_Enum2["NonReadonlyField"] = "NON_READONLY_FIELD";
418
419
  IssueType_Enum2["NoEquivalenceMethod"] = "NO_EQUIVALENCE_METHOD";
419
420
  IssueType_Enum2["NoLimitsOrThrottling"] = "NO_LIMITS_OR_THROTTLING";
421
+ IssueType_Enum2["NoNestedTry"] = "NO_NESTED_TRY";
420
422
  IssueType_Enum2["NoOpOverhead"] = "NO_OP_OVERHEAD";
421
423
  IssueType_Enum2["NoPrintStatement"] = "NO_PRINT_STATEMENT";
422
424
  IssueType_Enum2["NoReturnInFinally"] = "NO_RETURN_IN_FINALLY";
@@ -444,6 +446,7 @@ var IssueType_Enum = /* @__PURE__ */ ((IssueType_Enum2) => {
444
446
  IssueType_Enum2["TrustBoundaryViolation"] = "TRUST_BOUNDARY_VIOLATION";
445
447
  IssueType_Enum2["TypeConfusion"] = "TYPE_CONFUSION";
446
448
  IssueType_Enum2["UncheckedLoopCondition"] = "UNCHECKED_LOOP_CONDITION";
449
+ IssueType_Enum2["UnnecessaryImports"] = "UNNECESSARY_IMPORTS";
447
450
  IssueType_Enum2["UnsafeDeserialization"] = "UNSAFE_DESERIALIZATION";
448
451
  IssueType_Enum2["UnsafeTargetBlank"] = "UNSAFE_TARGET_BLANK";
449
452
  IssueType_Enum2["UnsafeWebThread"] = "UNSAFE_WEB_THREAD";
@@ -485,6 +488,7 @@ var Vulnerability_Report_Issue_State_Enum = /* @__PURE__ */ ((Vulnerability_Repo
485
488
  Vulnerability_Report_Issue_State_Enum2["Fixed"] = "Fixed";
486
489
  Vulnerability_Report_Issue_State_Enum2["NoFix"] = "NoFix";
487
490
  Vulnerability_Report_Issue_State_Enum2["Pending"] = "Pending";
491
+ Vulnerability_Report_Issue_State_Enum2["Unfixable"] = "Unfixable";
488
492
  Vulnerability_Report_Issue_State_Enum2["Unsupported"] = "Unsupported";
489
493
  return Vulnerability_Report_Issue_State_Enum2;
490
494
  })(Vulnerability_Report_Issue_State_Enum || {});
@@ -493,6 +497,7 @@ var Vulnerability_Report_Issue_Tag_Enum = /* @__PURE__ */ ((Vulnerability_Report
493
497
  Vulnerability_Report_Issue_Tag_Enum3["AuxiliaryCode"] = "AUXILIARY_CODE";
494
498
  Vulnerability_Report_Issue_Tag_Enum3["FalsePositive"] = "FALSE_POSITIVE";
495
499
  Vulnerability_Report_Issue_Tag_Enum3["TestCode"] = "TEST_CODE";
500
+ Vulnerability_Report_Issue_Tag_Enum3["Unfixable"] = "UNFIXABLE";
496
501
  Vulnerability_Report_Issue_Tag_Enum3["VendorCode"] = "VENDOR_CODE";
497
502
  return Vulnerability_Report_Issue_Tag_Enum3;
498
503
  })(Vulnerability_Report_Issue_Tag_Enum || {});
@@ -516,6 +521,35 @@ var Vulnerability_Severity_Enum = /* @__PURE__ */ ((Vulnerability_Severity_Enum2
516
521
  Vulnerability_Severity_Enum2["Medium"] = "medium";
517
522
  return Vulnerability_Severity_Enum2;
518
523
  })(Vulnerability_Severity_Enum || {});
524
+ var FixDetailsFragmentDoc = `
525
+ fragment FixDetails on fix {
526
+ id
527
+ confidence
528
+ safeIssueType
529
+ severityText
530
+ vulnerabilityReportIssues {
531
+ parsedIssueType
532
+ parsedSeverity
533
+ vulnerabilityReportIssueTags {
534
+ vulnerability_report_issue_tag_value
535
+ }
536
+ }
537
+ patchAndQuestions {
538
+ __typename
539
+ ... on FixData {
540
+ patch
541
+ patchOriginalEncodingBase64
542
+ extraContext {
543
+ extraContext {
544
+ key
545
+ value
546
+ }
547
+ fixDescription
548
+ }
549
+ }
550
+ }
551
+ }
552
+ `;
519
553
  var MeDocument = `
520
554
  query Me {
521
555
  me {
@@ -714,7 +748,7 @@ var GetVulByNodesMetadataDocument = `
714
748
  where: {id: {_eq: $vulnerabilityReportId}}
715
749
  ) {
716
750
  vulnerabilityReportIssues(
717
- where: {fixId: {_is_null: true}, _or: [{category: {_eq: "Irrelevant"}}, {category: {_eq: "FalsePositive"}}]}
751
+ where: {fixId: {_is_null: true}, _or: [{category: {_eq: "Irrelevant"}}, {category: {_eq: "FalsePositive"}}, {category: {_eq: "Filtered"}}]}
718
752
  ) {
719
753
  id
720
754
  safeIssueType
@@ -948,34 +982,77 @@ var AutoPrAnalysisDocument = `
948
982
  var GetMcpFixesDocument = `
949
983
  query GetMCPFixes($fixReportId: uuid!) {
950
984
  fix(where: {fixReportId: {_eq: $fixReportId}}) {
985
+ ...FixDetails
986
+ }
987
+ }
988
+ ${FixDetailsFragmentDoc}`;
989
+ var GetLatestReportByRepoUrlDocument = `
990
+ query GetLatestReportByRepoUrl($repoUrl: String!, $limit: Int = 3) {
991
+ fixReport(
992
+ where: {repo: {originalUrl: {_eq: $repoUrl}}}
993
+ order_by: {createdOn: desc}
994
+ limit: 1
995
+ ) {
951
996
  id
952
- confidence
953
- safeIssueType
954
- severityText
955
- vulnerabilityReportIssues {
956
- parsedIssueType
957
- parsedSeverity
958
- vulnerabilityReportIssueTags {
959
- vulnerability_report_issue_tag_value
997
+ createdOn
998
+ repo {
999
+ originalUrl
1000
+ }
1001
+ issueTypes
1002
+ fixes_aggregate(
1003
+ where: {vulnerabilityReportIssues: {category: {_eq: "Fixable"}}}
1004
+ ) {
1005
+ aggregate {
1006
+ count
960
1007
  }
961
1008
  }
962
- patchAndQuestions {
963
- __typename
964
- ... on FixData {
965
- patch
966
- patchOriginalEncodingBase64
967
- extraContext {
968
- extraContext {
969
- key
970
- value
971
- }
972
- fixDescription
1009
+ CRITICAL: fixes_aggregate(
1010
+ where: {_and: [{vulnerabilityReportIssues: {category: {_eq: "Fixable"}}}, {severityText: {_eq: "critical"}}]}
1011
+ ) {
1012
+ aggregate {
1013
+ count
1014
+ }
1015
+ }
1016
+ HIGH: fixes_aggregate(
1017
+ where: {_and: [{vulnerabilityReportIssues: {category: {_eq: "Fixable"}}}, {severityText: {_eq: "high"}}]}
1018
+ ) {
1019
+ aggregate {
1020
+ count
1021
+ }
1022
+ }
1023
+ MEDIUM: fixes_aggregate(
1024
+ where: {_and: [{vulnerabilityReportIssues: {category: {_eq: "Fixable"}}}, {severityText: {_eq: "medium"}}]}
1025
+ ) {
1026
+ aggregate {
1027
+ count
1028
+ }
1029
+ }
1030
+ LOW: fixes_aggregate(
1031
+ where: {_and: [{vulnerabilityReportIssues: {category: {_eq: "Fixable"}}}, {severityText: {_eq: "low"}}]}
1032
+ ) {
1033
+ aggregate {
1034
+ count
1035
+ }
1036
+ }
1037
+ fixes(
1038
+ where: {vulnerabilityReportIssues: {category: {_eq: "Fixable"}}}
1039
+ order_by: {severityValue: desc}
1040
+ limit: $limit
1041
+ ) {
1042
+ ...FixDetails
1043
+ }
1044
+ vulnerabilityReport {
1045
+ scanDate
1046
+ vendor
1047
+ vulnerabilityReportIssues_aggregate(where: {category: {_eq: "Fixable"}}) {
1048
+ aggregate {
1049
+ count
973
1050
  }
974
1051
  }
975
1052
  }
976
1053
  }
977
1054
  }
978
- `;
1055
+ ${FixDetailsFragmentDoc}`;
979
1056
  var defaultWrapper = (action, _operationName, _operationType, _variables) => action();
980
1057
  function getSdk(client, withWrapper = defaultWrapper) {
981
1058
  return {
@@ -1044,6 +1121,9 @@ function getSdk(client, withWrapper = defaultWrapper) {
1044
1121
  },
1045
1122
  GetMCPFixes(variables, requestHeaders, signal) {
1046
1123
  return withWrapper((wrappedRequestHeaders) => client.request({ document: GetMcpFixesDocument, variables, requestHeaders: { ...requestHeaders, ...wrappedRequestHeaders }, signal }), "GetMCPFixes", "query", variables);
1124
+ },
1125
+ GetLatestReportByRepoUrl(variables, requestHeaders, signal) {
1126
+ return withWrapper((wrappedRequestHeaders) => client.request({ document: GetLatestReportByRepoUrlDocument, variables, requestHeaders: { ...requestHeaders, ...wrappedRequestHeaders }, signal }), "GetLatestReportByRepoUrl", "query", variables);
1047
1127
  }
1048
1128
  };
1049
1129
  }
@@ -1248,14 +1328,16 @@ var CATEGORY = {
1248
1328
  Unsupported: "Unsupported",
1249
1329
  Irrelevant: "Irrelevant",
1250
1330
  FalsePositive: "FalsePositive",
1251
- Fixable: "Fixable"
1331
+ Fixable: "Fixable",
1332
+ Filtered: "Filtered"
1252
1333
  };
1253
1334
  var ValidCategoriesZ = z4.union([
1254
1335
  z4.literal(CATEGORY.NoFix),
1255
1336
  z4.literal(CATEGORY.Unsupported),
1256
1337
  z4.literal(CATEGORY.Irrelevant),
1257
1338
  z4.literal(CATEGORY.FalsePositive),
1258
- z4.literal(CATEGORY.Fixable)
1339
+ z4.literal(CATEGORY.Fixable),
1340
+ z4.literal(CATEGORY.Filtered)
1259
1341
  ]);
1260
1342
  var VulnerabilityReportIssueSharedStateZ = z4.object({
1261
1343
  id: z4.string().uuid(),
@@ -1337,7 +1419,8 @@ var GeneralIssueZ = BaseIssuePartsZ.merge(
1337
1419
  category: z4.union([
1338
1420
  z4.literal(CATEGORY.NoFix),
1339
1421
  z4.literal(CATEGORY.Unsupported),
1340
- z4.literal(CATEGORY.Fixable)
1422
+ z4.literal(CATEGORY.Fixable),
1423
+ z4.literal(CATEGORY.Filtered)
1341
1424
  ])
1342
1425
  })
1343
1426
  );
@@ -1367,7 +1450,8 @@ var mapCategoryToBucket = {
1367
1450
  Irrelevant: "irrelevant",
1368
1451
  NoFix: "remaining",
1369
1452
  Unsupported: "remaining",
1370
- Fixable: "fixable"
1453
+ Fixable: "fixable",
1454
+ Filtered: "remaining"
1371
1455
  };
1372
1456
 
1373
1457
  // src/features/analysis/scm/shared/src/types/types.ts
@@ -1482,7 +1566,10 @@ var issueTypeMap = {
1482
1566
  ["MISSING_WHITESPACE" /* MissingWhitespace */]: "Missing Whitespace",
1483
1567
  ["NO_PRINT_STATEMENT" /* NoPrintStatement */]: 'Python 2 "print" Statement Is Obsolete',
1484
1568
  ["NO_OP_OVERHEAD" /* NoOpOverhead */]: "Expensive Arguments in Conditional Methods",
1485
- ["DO_NOT_RAISE_EXCEPTION" /* DoNotRaiseException */]: "Do Not Raise Exception"
1569
+ ["DO_NOT_RAISE_EXCEPTION" /* DoNotRaiseException */]: "Do Not Raise Exception",
1570
+ ["DECLARE_VARIABLE_EXPLICITLY" /* DeclareVariableExplicitly */]: "Declare Variable Explicitly",
1571
+ ["NO_NESTED_TRY" /* NoNestedTry */]: "No Nested Try",
1572
+ ["UNNECESSARY_IMPORTS" /* UnnecessaryImports */]: "Unnecessary Imports"
1486
1573
  };
1487
1574
  var issueTypeZ = z5.nativeEnum(IssueType_Enum);
1488
1575
  var getIssueTypeFriendlyString = (issueType) => {
@@ -1503,17 +1590,20 @@ function getTagTooltip(tag) {
1503
1590
  case "AUTOGENERATED_CODE":
1504
1591
  return "Code created by tools or frameworks, not manually written";
1505
1592
  case "AUXILIARY_CODE":
1506
- return "Issue found in supporting files that don\u2019t impact core functionality";
1593
+ return "Issue found in supporting files that don't impact core functionality";
1594
+ case "Filtered":
1595
+ return "Issue was filtered by user in the Fix Policy";
1507
1596
  default:
1508
1597
  return tag;
1509
1598
  }
1510
1599
  }
1511
1600
  var issueDescription = {
1512
1601
  ["AUTOGENERATED_CODE" /* AutogeneratedCode */]: "The flagged code is generated automatically by tools or frameworks as part of the build or runtime process. This categorization highlights that **the issue resides in non-manual code**, which often requires tool-specific solutions or exemptions.",
1513
- ["AUXILIARY_CODE" /* AuxiliaryCode */]: "The flagged code is auxiliary or supporting code, such as configuration files, build scripts, or other non-application logic. This categorization indicates that the issue is not directly related to the application\u2019s core functionality.",
1514
- ["FALSE_POSITIVE" /* FalsePositive */]: "The flagged code **does not represent an actual vulnerability within the application\u2019s context.** This categorization indicates that the issue is either misidentified by the scanner or deemed irrelevant to the application\u2019s functionality.",
1602
+ ["AUXILIARY_CODE" /* AuxiliaryCode */]: "The flagged code is auxiliary or supporting code, such as configuration files, build scripts, or other non-application logic. This categorization indicates that the issue is not directly related to the application's core functionality.",
1603
+ ["FALSE_POSITIVE" /* FalsePositive */]: "The flagged code **does not represent an actual vulnerability within the application's context.** This categorization indicates that the issue is either misidentified by the scanner or deemed irrelevant to the application's functionality.",
1515
1604
  ["TEST_CODE" /* TestCode */]: "The flagged code resides in a test-specific path or context. This categorization indicates that **it supports testing scenarios and is isolated from production use**.",
1516
- ["VENDOR_CODE" /* VendorCode */]: "The flagged code originates from a third-party library or dependency maintained externally. This categorization suggests that **the issue lies outside the application\u2019s direct control** and should be addressed by the vendor if necessary."
1605
+ ["UNFIXABLE" /* Unfixable */]: "The flagged code cannot be fixed",
1606
+ ["VENDOR_CODE" /* VendorCode */]: "The flagged code originates from a third-party library or dependency maintained externally. This categorization suggests that **the issue lies outside the application's direct control** and should be addressed by the vendor if necessary."
1517
1607
  };
1518
1608
  function replaceKeysWithValues(fixDescription, extraContext) {
1519
1609
  let result = fixDescription;
@@ -1644,7 +1734,8 @@ var ReportQueryResultZ = z7.object({
1644
1734
  z7.object({
1645
1735
  id: z7.string().uuid(),
1646
1736
  issueType: z7.string(),
1647
- issueLanguage: z7.string()
1737
+ issueLanguage: z7.string(),
1738
+ category: z7.string()
1648
1739
  })
1649
1740
  )
1650
1741
  // scmSubmitFixRequests: ScmSubmitFixRequestsZ,
@@ -1769,6 +1860,7 @@ var VulnerabilityReportIssueZ = z7.object({
1769
1860
  parsedSeverity: ParsedSeverityZ,
1770
1861
  severity: z7.string(),
1771
1862
  severityValue: z7.number(),
1863
+ category: z7.string(),
1772
1864
  codeNodes: z7.array(z7.object({ path: z7.string() })),
1773
1865
  vulnerabilityReportIssueTags: z7.array(
1774
1866
  z7.object({
@@ -2220,7 +2312,10 @@ var fixDetailsData = {
2220
2312
  ["MISSING_WHITESPACE" /* MissingWhitespace */]: void 0,
2221
2313
  ["NO_PRINT_STATEMENT" /* NoPrintStatement */]: void 0,
2222
2314
  ["NO_OP_OVERHEAD" /* NoOpOverhead */]: void 0,
2223
- ["DO_NOT_RAISE_EXCEPTION" /* DoNotRaiseException */]: void 0
2315
+ ["DO_NOT_RAISE_EXCEPTION" /* DoNotRaiseException */]: void 0,
2316
+ ["DECLARE_VARIABLE_EXPLICITLY" /* DeclareVariableExplicitly */]: void 0,
2317
+ ["UNNECESSARY_IMPORTS" /* UnnecessaryImports */]: void 0,
2318
+ ["NO_NESTED_TRY" /* NoNestedTry */]: void 0
2224
2319
  };
2225
2320
 
2226
2321
  // src/features/analysis/scm/shared/src/commitDescriptionMarkup.ts
@@ -5429,6 +5524,92 @@ var GitService = class {
5429
5524
  throw new Error(errorMessage);
5430
5525
  }
5431
5526
  }
5527
+ /**
5528
+ * Normalizes a Git URL to HTTPS format for various Git hosting platforms
5529
+ * @param url The Git URL to normalize
5530
+ * @returns The normalized HTTPS URL
5531
+ */
5532
+ normalizeGitUrl(url) {
5533
+ let normalizedUrl = url;
5534
+ if (normalizedUrl.endsWith(".git")) {
5535
+ normalizedUrl = normalizedUrl.slice(0, -".git".length);
5536
+ }
5537
+ const sshToHttpsMappings = [
5538
+ // GitHub
5539
+ { pattern: "git@github.com:", replacement: "https://github.com/" },
5540
+ // GitLab
5541
+ { pattern: "git@gitlab.com:", replacement: "https://gitlab.com/" },
5542
+ // Bitbucket
5543
+ { pattern: "git@bitbucket.org:", replacement: "https://bitbucket.org/" },
5544
+ // Azure DevOps (SSH format)
5545
+ {
5546
+ pattern: "git@ssh.dev.azure.com:",
5547
+ replacement: "https://dev.azure.com/"
5548
+ },
5549
+ // Azure DevOps (alternative SSH format)
5550
+ {
5551
+ pattern: /git@([^:]+):v3\/([^/]+)\/([^/]+)\/([^/]+)/,
5552
+ replacement: "https://$1/$2/_git/$4"
5553
+ }
5554
+ ];
5555
+ for (const mapping of sshToHttpsMappings) {
5556
+ if (typeof mapping.pattern === "string") {
5557
+ if (normalizedUrl.startsWith(mapping.pattern)) {
5558
+ normalizedUrl = normalizedUrl.replace(
5559
+ mapping.pattern,
5560
+ mapping.replacement
5561
+ );
5562
+ break;
5563
+ }
5564
+ } else {
5565
+ const match = normalizedUrl.match(mapping.pattern);
5566
+ if (match) {
5567
+ normalizedUrl = normalizedUrl.replace(
5568
+ mapping.pattern,
5569
+ mapping.replacement
5570
+ );
5571
+ break;
5572
+ }
5573
+ }
5574
+ }
5575
+ return normalizedUrl;
5576
+ }
5577
+ /**
5578
+ * Gets all remote repository URLs (equivalent to 'git remote -v')
5579
+ */
5580
+ async getRepoUrls() {
5581
+ this.log("Getting all remote repository URLs", "debug");
5582
+ try {
5583
+ const remotes = await this.git.remote(["-v"]);
5584
+ if (!remotes) {
5585
+ return {};
5586
+ }
5587
+ const remoteMap = {};
5588
+ remotes.split("\n").forEach((line) => {
5589
+ if (!line.trim()) return;
5590
+ const [remoteName, url, type2] = line.split(/\s+/);
5591
+ if (!remoteName || !url || !type2) return;
5592
+ if (!remoteMap[remoteName]) {
5593
+ remoteMap[remoteName] = { fetch: "", push: "" };
5594
+ }
5595
+ const normalizedUrl = this.normalizeGitUrl(url);
5596
+ const remote = remoteMap[remoteName];
5597
+ if (type2 === "(fetch)") {
5598
+ remote.fetch = normalizedUrl;
5599
+ } else if (type2 === "(push)") {
5600
+ remote.push = normalizedUrl;
5601
+ }
5602
+ });
5603
+ this.log("Remote repository URLs retrieved", "debug", {
5604
+ remotes: remoteMap
5605
+ });
5606
+ return remoteMap;
5607
+ } catch (error) {
5608
+ const errorMessage = `Failed to get remote repository URLs: ${error.message}`;
5609
+ this.log(errorMessage, "error", { error });
5610
+ throw new Error(errorMessage);
5611
+ }
5612
+ }
5432
5613
  };
5433
5614
 
5434
5615
  // src/features/analysis/scm/scmSubmit/index.ts
@@ -6830,7 +7011,7 @@ var GithubSCMLib = class extends SCMLib {
6830
7011
  }
6831
7012
  async forkRepo(repoUrl) {
6832
7013
  this._validateAccessToken();
6833
- return this.githubSdk.forkRepo({
7014
+ return await this.githubSdk.forkRepo({
6834
7015
  repoUrl
6835
7016
  });
6836
7017
  }
@@ -6840,7 +7021,7 @@ var GithubSCMLib = class extends SCMLib {
6840
7021
  const { data: repositoryPublicKeyResponse } = await this.githubSdk.getRepositoryPublicKey({ owner, repo });
6841
7022
  const { key_id, key } = repositoryPublicKeyResponse;
6842
7023
  const encryptedValue = await encryptSecret(params.value, key);
6843
- return this.githubSdk.createOrUpdateRepositorySecret({
7024
+ return await this.githubSdk.createOrUpdateRepositorySecret({
6844
7025
  encrypted_value: encryptedValue,
6845
7026
  secret_name: params.name,
6846
7027
  key_id,
@@ -6859,12 +7040,12 @@ var GithubSCMLib = class extends SCMLib {
6859
7040
  return { pull_request_url };
6860
7041
  }
6861
7042
  async validateParams() {
6862
- return githubValidateParams(this.url, this.accessToken);
7043
+ return await githubValidateParams(this.url, this.accessToken);
6863
7044
  }
6864
7045
  async postPrComment(params) {
6865
7046
  this._validateAccessTokenAndUrl();
6866
7047
  const { owner, repo } = parseGithubOwnerAndRepo(this.url);
6867
- return this.githubSdk.postPrComment({
7048
+ return await this.githubSdk.postPrComment({
6868
7049
  ...params,
6869
7050
  owner,
6870
7051
  repo
@@ -6873,7 +7054,7 @@ var GithubSCMLib = class extends SCMLib {
6873
7054
  async updatePrComment(params) {
6874
7055
  this._validateAccessTokenAndUrl();
6875
7056
  const { owner, repo } = parseGithubOwnerAndRepo(this.url);
6876
- return this.githubSdk.updatePrComment({
7057
+ return await this.githubSdk.updatePrComment({
6877
7058
  ...params,
6878
7059
  owner,
6879
7060
  repo
@@ -6882,7 +7063,7 @@ var GithubSCMLib = class extends SCMLib {
6882
7063
  async deleteComment(params) {
6883
7064
  this._validateAccessTokenAndUrl();
6884
7065
  const { owner, repo } = parseGithubOwnerAndRepo(this.url);
6885
- return this.githubSdk.deleteComment({
7066
+ return await this.githubSdk.deleteComment({
6886
7067
  ...params,
6887
7068
  owner,
6888
7069
  repo
@@ -6891,7 +7072,7 @@ var GithubSCMLib = class extends SCMLib {
6891
7072
  async getPrComments(params) {
6892
7073
  this._validateAccessTokenAndUrl();
6893
7074
  const { owner, repo } = parseGithubOwnerAndRepo(this.url);
6894
- return this.githubSdk.getPrComments({
7075
+ return await this.githubSdk.getPrComments({
6895
7076
  per_page: 100,
6896
7077
  ...params,
6897
7078
  owner,
@@ -6910,7 +7091,7 @@ var GithubSCMLib = class extends SCMLib {
6910
7091
  }
6911
7092
  async getRepoList(_scmOrg) {
6912
7093
  this._validateAccessToken();
6913
- return this.githubSdk.getGithubRepoList();
7094
+ return await this.githubSdk.getGithubRepoList();
6914
7095
  }
6915
7096
  async getBranchList() {
6916
7097
  this._validateAccessTokenAndUrl();
@@ -6937,27 +7118,30 @@ var GithubSCMLib = class extends SCMLib {
6937
7118
  return Promise.resolve(downloadUrl);
6938
7119
  }
6939
7120
  async _getUsernameForAuthUrl() {
6940
- return this.getUsername();
7121
+ return await this.getUsername();
6941
7122
  }
6942
7123
  async getIsRemoteBranch(branch) {
6943
7124
  this._validateUrl();
6944
- return this.githubSdk.getGithubIsRemoteBranch({ branch, repoUrl: this.url });
7125
+ return await this.githubSdk.getGithubIsRemoteBranch({
7126
+ branch,
7127
+ repoUrl: this.url
7128
+ });
6945
7129
  }
6946
7130
  async getUserHasAccessToRepo() {
6947
7131
  this._validateAccessTokenAndUrl();
6948
7132
  const username = await this.getUsername();
6949
- return this.githubSdk.getGithubIsUserCollaborator({
7133
+ return await this.githubSdk.getGithubIsUserCollaborator({
6950
7134
  repoUrl: this.url,
6951
7135
  username
6952
7136
  });
6953
7137
  }
6954
7138
  async getUsername() {
6955
7139
  this._validateAccessToken();
6956
- return this.githubSdk.getGithubUsername();
7140
+ return await this.githubSdk.getGithubUsername();
6957
7141
  }
6958
7142
  async getSubmitRequestStatus(scmSubmitRequestId) {
6959
7143
  this._validateAccessTokenAndUrl();
6960
- return this.githubSdk.getGithubPullRequestStatus({
7144
+ return await this.githubSdk.getGithubPullRequestStatus({
6961
7145
  repoUrl: this.url,
6962
7146
  prNumber: Number(scmSubmitRequestId)
6963
7147
  });
@@ -6980,7 +7164,10 @@ var GithubSCMLib = class extends SCMLib {
6980
7164
  }
6981
7165
  async getReferenceData(ref) {
6982
7166
  this._validateUrl();
6983
- return this.githubSdk.getGithubReferenceData({ ref, gitHubUrl: this.url });
7167
+ return await this.githubSdk.getGithubReferenceData({
7168
+ ref,
7169
+ gitHubUrl: this.url
7170
+ });
6984
7171
  }
6985
7172
  async getPrComment(commentId) {
6986
7173
  this._validateUrl();
@@ -7049,7 +7236,7 @@ var GithubSCMLib = class extends SCMLib {
7049
7236
  }) {
7050
7237
  this._validateAccessTokenAndUrl();
7051
7238
  const { owner, repo } = parseGithubOwnerAndRepo(this.url);
7052
- return this.githubSdk.deleteGeneralPrComment({
7239
+ return await this.githubSdk.deleteGeneralPrComment({
7053
7240
  owner,
7054
7241
  repo,
7055
7242
  comment_id: commentId
@@ -8817,31 +9004,33 @@ async function addFixCommentsForPr({
8817
9004
 
8818
9005
  ${contextString}` : description2;
8819
9006
  }
8820
- return vulnerabilityReportIssue.codeNodes.map(
8821
- (vulnerabilityReportIssueCodeNode) => {
8822
- return postIssueComment({
8823
- vulnerabilityReportIssueCodeNode: {
8824
- path: vulnerabilityReportIssueCodeNode.path,
8825
- startLine: vulnerabilityReportIssueCodeNode.startLine,
8826
- vulnerabilityReportIssue: {
8827
- fixId: "",
8828
- safeIssueType: vulnerabilityReportIssue.safeIssueType,
8829
- vulnerabilityReportIssueTags: vulnerabilityReportIssue.vulnerabilityReportIssueTags,
8830
- category: vulnerabilityReportIssue.category
9007
+ return await Promise.all(
9008
+ vulnerabilityReportIssue.codeNodes.map(
9009
+ async (vulnerabilityReportIssueCodeNode) => {
9010
+ return await postIssueComment({
9011
+ vulnerabilityReportIssueCodeNode: {
9012
+ path: vulnerabilityReportIssueCodeNode.path,
9013
+ startLine: vulnerabilityReportIssueCodeNode.startLine,
9014
+ vulnerabilityReportIssue: {
9015
+ fixId: "",
9016
+ safeIssueType: vulnerabilityReportIssue.safeIssueType,
9017
+ vulnerabilityReportIssueTags: vulnerabilityReportIssue.vulnerabilityReportIssueTags,
9018
+ category: vulnerabilityReportIssue.category
9019
+ },
9020
+ vulnerabilityReportIssueId: vulnerabilityReportIssue.id
8831
9021
  },
8832
- vulnerabilityReportIssueId: vulnerabilityReportIssue.id
8833
- },
8834
- projectId,
8835
- analysisId,
8836
- organizationId,
8837
- fixesById,
8838
- scm,
8839
- pullRequest,
8840
- scanner,
8841
- commitSha,
8842
- fpDescription
8843
- });
8844
- }
9022
+ projectId,
9023
+ analysisId,
9024
+ organizationId,
9025
+ fixesById,
9026
+ scm,
9027
+ pullRequest,
9028
+ scanner,
9029
+ commitSha,
9030
+ fpDescription
9031
+ });
9032
+ }
9033
+ )
8845
9034
  );
8846
9035
  }
8847
9036
  ),
@@ -11306,6 +11495,30 @@ var McpGQLClient = class {
11306
11495
  return null;
11307
11496
  }
11308
11497
  }
11498
+ async getLatestReportByRepoUrl(repoUrl, limit) {
11499
+ try {
11500
+ logDebug("GraphQL: Calling GetLatestReportByRepoUrl query", {
11501
+ repoUrl,
11502
+ limit
11503
+ });
11504
+ const res = await this.clientSdk.GetLatestReportByRepoUrl({
11505
+ repoUrl,
11506
+ limit
11507
+ });
11508
+ logInfo("GraphQL: GetLatestReportByRepoUrl successful", {
11509
+ result: res,
11510
+ reportCount: res.fixReport?.length || 0
11511
+ });
11512
+ return res.fixReport?.[0] || null;
11513
+ } catch (e) {
11514
+ logError("GraphQL: GetLatestReportByRepoUrl failed", {
11515
+ error: e,
11516
+ repoUrl,
11517
+ ...this.getErrorContext()
11518
+ });
11519
+ throw e;
11520
+ }
11521
+ }
11309
11522
  };
11310
11523
  async function openBrowser(url) {
11311
11524
  const now = Date.now();
@@ -11478,21 +11691,12 @@ var McpServer = class {
11478
11691
  }
11479
11692
  async handleListToolsRequest(request) {
11480
11693
  logInfo("Received list_tools request", { params: request.params });
11481
- try {
11482
- await getMcpGQLClient();
11483
- } catch (error) {
11484
- logError("Failed to get MCPGQLClient", { error });
11485
- const authError = new Error(
11486
- "Please authorize this client by visiting: https://mobb.ai"
11487
- );
11488
- authError.name = "AuthorizationRequired";
11489
- throw authError;
11490
- }
11694
+ void getMcpGQLClient();
11491
11695
  const tools = this.toolRegistry.getAllTools();
11492
- return {
11696
+ const response = {
11493
11697
  tools: tools.map((tool) => ({
11494
11698
  name: tool.name,
11495
- display_name: tool.name,
11699
+ display_name: tool.display_name || tool.name,
11496
11700
  description: tool.description || "",
11497
11701
  inputSchema: {
11498
11702
  type: "object",
@@ -11501,6 +11705,8 @@ var McpServer = class {
11501
11705
  }
11502
11706
  }))
11503
11707
  };
11708
+ logInfo("Returning list_tools response", { response });
11709
+ return response;
11504
11710
  }
11505
11711
  async handleCallToolRequest(request) {
11506
11712
  const { name, arguments: args } = request.params;
@@ -11571,6 +11777,9 @@ var McpServer = class {
11571
11777
  }
11572
11778
  };
11573
11779
 
11780
+ // src/mcp/tools/checkForAvailableFixes/AvailableFixesTool.ts
11781
+ import { z as z32 } from "zod";
11782
+
11574
11783
  // src/mcp/services/PathValidation.ts
11575
11784
  import fs9 from "fs";
11576
11785
  import path11 from "path";
@@ -11616,6 +11825,369 @@ var PathValidation = class {
11616
11825
  }
11617
11826
  };
11618
11827
 
11828
+ // src/mcp/tools/base/BaseTool.ts
11829
+ import { z as z31 } from "zod";
11830
+ var BaseTool = class {
11831
+ getDefinition() {
11832
+ return {
11833
+ name: this.name,
11834
+ display_name: this.displayName,
11835
+ description: this.description,
11836
+ inputSchema: {
11837
+ type: "object",
11838
+ properties: {
11839
+ path: {
11840
+ type: "string",
11841
+ description: "The path to the local git repository"
11842
+ }
11843
+ },
11844
+ required: ["path"]
11845
+ }
11846
+ };
11847
+ }
11848
+ async execute(args) {
11849
+ logInfo(`Executing tool: ${this.name}`, { args });
11850
+ const validatedArgs = this.validateInput(args);
11851
+ logDebug(`Tool ${this.name} input validation successful`, {
11852
+ validatedArgs
11853
+ });
11854
+ await this.validateAdditional(validatedArgs);
11855
+ try {
11856
+ const result = await this.executeInternal(validatedArgs);
11857
+ logInfo(`Tool ${this.name} executed successfully`);
11858
+ return result;
11859
+ } catch (error) {
11860
+ const errorMessage = error instanceof Error ? error.message : String(error);
11861
+ logError(`Tool ${this.name} execution failed: ${errorMessage}`, {
11862
+ error,
11863
+ args
11864
+ });
11865
+ return this.createErrorResponse(errorMessage);
11866
+ }
11867
+ }
11868
+ validateInput(args) {
11869
+ try {
11870
+ return this.inputSchema.parse(args);
11871
+ } catch (error) {
11872
+ if (error instanceof z31.ZodError) {
11873
+ const errorDetails = error.errors.map((e) => {
11874
+ const fieldPath = e.path.length > 0 ? e.path.join(".") : "root";
11875
+ const message = e.message === "Required" ? `Missing required parameter '${fieldPath}'` : `Invalid value for '${fieldPath}': ${e.message}`;
11876
+ return message;
11877
+ });
11878
+ const errorMessage = `Invalid arguments: ${errorDetails.join(", ")}`;
11879
+ throw new Error(errorMessage);
11880
+ }
11881
+ throw error;
11882
+ }
11883
+ }
11884
+ /**
11885
+ * Additional validation that should bubble up as MCP errors
11886
+ * Override this method in subclasses to add custom validation
11887
+ */
11888
+ async validateAdditional(_validatedArgs) {
11889
+ }
11890
+ createSuccessResponse(text) {
11891
+ return {
11892
+ content: [
11893
+ {
11894
+ type: "text",
11895
+ text
11896
+ }
11897
+ ]
11898
+ };
11899
+ }
11900
+ createErrorResponse(error) {
11901
+ return {
11902
+ content: [
11903
+ {
11904
+ type: "text",
11905
+ text: error
11906
+ }
11907
+ ]
11908
+ };
11909
+ }
11910
+ };
11911
+
11912
+ // src/mcp/tools/base/prompts.ts
11913
+ function frienlyType(s) {
11914
+ const withoutUnderscores = s.replace(/_/g, " ");
11915
+ const result = withoutUnderscores.replace(/([a-z])([A-Z])/g, "$1 $2");
11916
+ return result.charAt(0).toUpperCase() + result.slice(1);
11917
+ }
11918
+ var applyFixesPrompt = (fixes) => {
11919
+ const fixList = fixes.map((fix) => {
11920
+ const vulnerabilityType = frienlyType(fix.safeIssueType);
11921
+ const vulnerabilityDescription = fix.patchAndQuestions?.__typename === "FixData" ? fix.patchAndQuestions.extraContext?.fixDescription : void 0;
11922
+ const patch = fix.patchAndQuestions?.__typename === "FixData" ? fix.patchAndQuestions.patch : void 0;
11923
+ return {
11924
+ vulnerabilityType,
11925
+ vulnerabilityDescription,
11926
+ patch
11927
+ };
11928
+ });
11929
+ return `## CRITICAL INSTRUCTIONS - READ CAREFULLY
11930
+
11931
+ You are an AI code assistant tasked with applying security vulnerability fixes. Follow these instructions EXACTLY:
11932
+
11933
+ ### 1. IMMEDIATE ACTION REQUIRED
11934
+ - **DO NOT ask for permission** - Apply the patches immediately
11935
+ - **DO NOT explain first** - Apply the patch, then explain what you did
11936
+ - **DO NOT modify any other code** - Only apply the exact changes shown in each patch
11937
+
11938
+ ### 2. HOW TO APPLY EACH PATCH
11939
+ For each fix below:
11940
+ 1. **Identify the target file** from the patch header (e.g., \`src/database/queries.js\`)
11941
+ 2. **Locate the exact lines** shown in the patch context
11942
+ 3. **Remove lines** that start with \`-\` (minus sign)
11943
+ 4. **Add lines** that start with \`+\` (plus sign)
11944
+ 5. **Keep unchanged lines** exactly as they are (lines without +/- prefix)
11945
+ 6. **Preserve indentation and formatting** exactly as shown
11946
+
11947
+ ### 3. PATCH FORMAT EXPLANATION
11948
+ - \`@@\` lines show line numbers and context
11949
+ - Lines starting with \`-\` should be REMOVED
11950
+ - Lines starting with \`+\` should be ADDED
11951
+ - Lines with no prefix should remain UNCHANGED
11952
+ - The patch shows surrounding context to help you locate the right place
11953
+
11954
+ ### 4. VALIDATION STEPS
11955
+ After applying each patch:
11956
+ 1. Verify the file syntax is correct
11957
+ 2. Ensure no unrelated code was modified
11958
+ 3. Confirm the vulnerability is addressed
11959
+
11960
+ ### 5. ERROR HANDLING
11961
+ If you cannot apply a patch:
11962
+ 1. Explain specifically what went wrong
11963
+ 2. Show the current state of the target lines
11964
+ 3. Ask for clarification on the specific issue
11965
+
11966
+ ---
11967
+
11968
+ # SECURITY FIXES TO APPLY
11969
+
11970
+ ${fixList.map(
11971
+ (fix, index) => `
11972
+ ## Fix ${index + 1}: ${fix.vulnerabilityType}
11973
+
11974
+ **\u{1F3AF} Target:** Apply this patch to fix a ${fix.vulnerabilityType.toLowerCase()} vulnerability
11975
+
11976
+ **\u{1F4DD} Description:** ${fix.vulnerabilityDescription || "Security vulnerability fix"}
11977
+
11978
+ **\u{1F527} Action Required:** Apply the following patch exactly as shown
11979
+
11980
+ **\u{1F4C1} Patch to Apply:**
11981
+ \`\`\`diff
11982
+ ${fix.patch || "No patch available"}
11983
+ \`\`\`
11984
+
11985
+ **\u2705 Expected Result:** The vulnerability will be fixed and the code will be more secure
11986
+
11987
+ ---`
11988
+ ).join("\n")}
11989
+
11990
+ ## FINAL REMINDER
11991
+ - Apply ALL patches above in order
11992
+ - Do NOT ask for permission
11993
+ - Explain what you did AFTER applying the patches
11994
+ - If any patch fails, continue with the others and report issues at the end
11995
+ `;
11996
+ };
11997
+
11998
+ // src/mcp/tools/checkForAvailableFixes/helpers/AvailableFixesResponsePrompts.ts
11999
+ var noReportFoundPrompt = `\u{1F50D} **MOBB SECURITY SCAN STATUS**
12000
+
12001
+ ## No Vulnerability Report Found
12002
+
12003
+ We were unable to find a previous vulnerability report for this repository. This could be due to several reasons:
12004
+
12005
+ ### \u{1F4CB} Possible Reasons
12006
+ - This is a new repository that hasn't been scanned yet
12007
+ - The repository URL might not match our records
12008
+ - The repository might be private or not accessible
12009
+ - Previous scans might have been deleted or expired
12010
+
12011
+ ### \u{1F3AF} Recommended Actions
12012
+ 1. **Run a new security scan** to analyze your codebase
12013
+ - Use the \`fix_vulnerabilities\` tool to start a fresh scan
12014
+ - This will analyze your current code for security issues
12015
+
12016
+ 2. **Verify repository access**
12017
+ - Ensure the repository is properly connected to Mobb
12018
+ - Check that you have the necessary permissions
12019
+
12020
+ 3. **Check repository URL**
12021
+ - Confirm the repository URL matches your remote origin
12022
+ - Verify the URL format is correct (e.g., https://github.com/org/repo)
12023
+
12024
+ ### \u{1F680} Next Steps
12025
+ To get started with security scanning:
12026
+ 1. Run \`fix_vulnerabilities\` to perform a new scan
12027
+ 2. Review the results and apply any suggested fixes
12028
+ 3. Set up regular scanning to maintain security
12029
+
12030
+ ### \u{1F4A1} Additional Information
12031
+ - New scans typically take a few minutes to complete
12032
+ - You'll receive detailed results including:
12033
+ - Vulnerability types and severities
12034
+ - Specific code locations
12035
+ - Recommended fixes
12036
+ - Security best practices
12037
+
12038
+ For assistance, please:
12039
+ - Visit our documentation at https://docs.mobb.ai
12040
+ - Contact support at support@mobb.ai`;
12041
+ var noFixesFoundPrompt = `\u{1F50D} **MOBB SECURITY SCAN STATUS**
12042
+
12043
+ ## No Available Fixes Found
12044
+
12045
+ We've analyzed your repository but found no automated fixes available at this time.
12046
+ `;
12047
+ var fixesFoundPrompt = (fixReport) => {
12048
+ if (fixReport.fixes_aggregate.aggregate?.count === 0) {
12049
+ return noFixesFoundPrompt;
12050
+ }
12051
+ const totalFixes = fixReport.fixes_aggregate.aggregate?.count || 0;
12052
+ const criticalFixes = fixReport.CRITICAL?.aggregate?.count || 0;
12053
+ const highFixes = fixReport.HIGH?.aggregate?.count || 0;
12054
+ const mediumFixes = fixReport.MEDIUM?.aggregate?.count || 0;
12055
+ const lowFixes = fixReport.LOW?.aggregate?.count || 0;
12056
+ const scanDate = new Date(
12057
+ fixReport.vulnerabilityReport?.scanDate || ""
12058
+ ).toLocaleString();
12059
+ const vendor = fixReport.vulnerabilityReport?.vendor || "Unknown";
12060
+ const reportUrl = "";
12061
+ return `\u{1F50D} **MOBB SECURITY SCAN RESULTS**
12062
+
12063
+ ## \u{1F4CA} Scan Report Summary
12064
+ - **Scan Date:** ${scanDate}
12065
+ - **Scan Vendor:** ${vendor}
12066
+ ${reportUrl ? `- **Report Link:** ${reportUrl}` : ""}
12067
+
12068
+ ## \u{1F3AF} Issues Detected
12069
+ ${fixReport.issueTypes ? Object.entries(fixReport.issueTypes).map(([type2, count]) => `- ${type2}: ${count} issues`).join("\n") : "No specific issue types reported"}
12070
+
12071
+ ## \u{1F527} Available Fixes
12072
+ Total number of fixes available: **${totalFixes}**
12073
+
12074
+ ### Severity Breakdown
12075
+ - \u{1F534} Critical: ${criticalFixes}
12076
+ - \u{1F7E0} High: ${highFixes}
12077
+ - \u{1F7E1} Medium: ${mediumFixes}
12078
+ - \uFFFD\uFFFD Low: ${lowFixes}
12079
+
12080
+ ${applyFixesPrompt(fixReport.fixes)}`;
12081
+ };
12082
+
12083
+ // src/mcp/tools/checkForAvailableFixes/AvailableFixesService.ts
12084
+ var AvailableFixesService = class {
12085
+ constructor() {
12086
+ __publicField(this, "gqlClient", null);
12087
+ }
12088
+ async initializeGqlClient() {
12089
+ if (!this.gqlClient) {
12090
+ this.gqlClient = await getMcpGQLClient();
12091
+ }
12092
+ return this.gqlClient;
12093
+ }
12094
+ async checkForAvailableFixes(repoUrl, limit) {
12095
+ try {
12096
+ logDebug("Checking for available fixes", { repoUrl, limit });
12097
+ const gqlClient = await this.initializeGqlClient();
12098
+ logDebug("GQL client initialized");
12099
+ logDebug("querying for latest report", { repoUrl, limit });
12100
+ const result = await gqlClient.getLatestReportByRepoUrl(repoUrl, limit);
12101
+ logDebug("received latest report result", { result });
12102
+ if (!result) {
12103
+ logInfo("No report found for repository", { repoUrl });
12104
+ return noReportFoundPrompt;
12105
+ }
12106
+ logInfo("Successfully retrieved available fixes", {
12107
+ reportFound: true
12108
+ });
12109
+ return fixesFoundPrompt(result);
12110
+ } catch (error) {
12111
+ logError("Failed to check for available fixes", {
12112
+ error,
12113
+ repoUrl
12114
+ });
12115
+ throw error;
12116
+ }
12117
+ }
12118
+ };
12119
+
12120
+ // src/mcp/tools/checkForAvailableFixes/AvailableFixesTool.ts
12121
+ var CheckForAvailableFixesTool = class extends BaseTool {
12122
+ constructor() {
12123
+ super(...arguments);
12124
+ __publicField(this, "name", "check_for_available_fixes");
12125
+ __publicField(this, "displayName", "Check for Available Fixes");
12126
+ __publicField(this, "description", "Checks if there are any available fixes for vulnerabilities in the project");
12127
+ __publicField(this, "inputSchema", z32.object({
12128
+ path: z32.string().describe("Path to the project directory to check for available fixes"),
12129
+ files: z32.array(z32.string()).optional().describe("Optional list of specific files to check"),
12130
+ severity: z32.array(z32.string()).optional().describe("Optional list of severity levels to filter by"),
12131
+ issueTypes: z32.array(z32.string()).optional().describe("Optional list of issue types to filter by"),
12132
+ limit: z32.number().optional().describe("Optional maximum number of results to return")
12133
+ }));
12134
+ }
12135
+ getJsonSchema() {
12136
+ return {
12137
+ type: "object",
12138
+ properties: {
12139
+ path: {
12140
+ type: "string",
12141
+ description: "Path to the project directory to check for available fixes"
12142
+ },
12143
+ limit: {
12144
+ type: "number",
12145
+ description: "Optional maximum number of results to return"
12146
+ }
12147
+ },
12148
+ required: ["path"]
12149
+ };
12150
+ }
12151
+ async executeInternal(args) {
12152
+ const pathValidation = new PathValidation();
12153
+ const pathValidationResult = await pathValidation.validatePath(args.path);
12154
+ if (!pathValidationResult.isValid) {
12155
+ throw new Error(
12156
+ `Invalid path: potential security risk detected in path: ${pathValidationResult.error}`
12157
+ );
12158
+ }
12159
+ const gitService = new GitService(args.path, log);
12160
+ const gitValidation = await gitService.validateRepository();
12161
+ if (!gitValidation.isValid) {
12162
+ throw new Error(`Invalid git repository: ${gitValidation.error}`);
12163
+ }
12164
+ const repoUrls = await gitService.getRepoUrls();
12165
+ if (Object.keys(repoUrls).length > 0 && !repoUrls["origin"]) {
12166
+ throw new Error("Repository must have an origin remote");
12167
+ }
12168
+ const originUrl = repoUrls["origin"]?.fetch;
12169
+ if (!originUrl) {
12170
+ throw new Error("No origin URL found for the repository");
12171
+ }
12172
+ const availableFixesService = new AvailableFixesService();
12173
+ const fixResult = await availableFixesService.checkForAvailableFixes(
12174
+ originUrl,
12175
+ args.limit
12176
+ );
12177
+ logInfo("CheckForAvailableFixesTool execution completed successfully", {
12178
+ fixResult
12179
+ });
12180
+ return {
12181
+ content: [
12182
+ {
12183
+ type: "text",
12184
+ text: fixResult
12185
+ }
12186
+ ]
12187
+ };
12188
+ }
12189
+ };
12190
+
11619
12191
  // src/mcp/services/FilePacking.ts
11620
12192
  import fs10 from "fs";
11621
12193
  import path12 from "path";
@@ -11656,13 +12228,8 @@ var FilePacking = class {
11656
12228
  }
11657
12229
  };
11658
12230
 
11659
- // src/mcp/tools/fixVulnerabilities/helpers/LLMResponsePrompts.ts
11660
- function frienlyType(s) {
11661
- const withoutUnderscores = s.replace(/_/g, " ");
11662
- const result = withoutUnderscores.replace(/([a-z])([A-Z])/g, "$1 $2");
11663
- return result.charAt(0).toUpperCase() + result.slice(1);
11664
- }
11665
- var noFixesFoundPrompt = `\u{1F389} **MOBB SECURITY SCAN COMPLETED SUCCESSFULLY** \u{1F389}
12231
+ // src/mcp/tools/fixVulnerabilities/helpers/FixVulnerabilitiesResponsePrompts.ts
12232
+ var noFixesFoundPrompt2 = `\u{1F389} **MOBB SECURITY SCAN COMPLETED SUCCESSFULLY** \u{1F389}
11666
12233
 
11667
12234
  ## Congratulations! No Vulnerabilities Found
11668
12235
 
@@ -11698,87 +12265,11 @@ This scan analyzed your code for common security issues including:
11698
12265
  var fixesPrompt = (fixes) => {
11699
12266
  const fix = fixes[0];
11700
12267
  if (!fix) {
11701
- return noFixesFoundPrompt;
12268
+ return noFixesFoundPrompt2;
11702
12269
  }
11703
- const fixList = fixes.map((fix2) => {
11704
- const vulnerabilityType = frienlyType(fix2.safeIssueType);
11705
- const vulnerabilityDescription = fix2.patchAndQuestions?.__typename === "FixData" ? fix2.patchAndQuestions.extraContext?.fixDescription : void 0;
11706
- const patch = fix2.patchAndQuestions?.__typename === "FixData" ? fix2.patchAndQuestions.patch : void 0;
11707
- return {
11708
- vulnerabilityType,
11709
- vulnerabilityDescription,
11710
- patch
11711
- };
11712
- });
11713
12270
  return `Here are the fixes to the vulnerabilities discovered by Mobb MCP
11714
12271
 
11715
- ## CRITICAL INSTRUCTIONS - READ CAREFULLY
11716
-
11717
- You are an AI code assistant tasked with applying security vulnerability fixes. Follow these instructions EXACTLY:
11718
-
11719
- ### 1. IMMEDIATE ACTION REQUIRED
11720
- - **DO NOT ask for permission** - Apply the patches immediately
11721
- - **DO NOT explain first** - Apply the patch, then explain what you did
11722
- - **DO NOT modify any other code** - Only apply the exact changes shown in each patch
11723
-
11724
- ### 2. HOW TO APPLY EACH PATCH
11725
- For each fix below:
11726
- 1. **Identify the target file** from the patch header (e.g., \`src/database/queries.js\`)
11727
- 2. **Locate the exact lines** shown in the patch context
11728
- 3. **Remove lines** that start with \`-\` (minus sign)
11729
- 4. **Add lines** that start with \`+\` (plus sign)
11730
- 5. **Keep unchanged lines** exactly as they are (lines without +/- prefix)
11731
- 6. **Preserve indentation and formatting** exactly as shown
11732
-
11733
- ### 3. PATCH FORMAT EXPLANATION
11734
- - \`@@\` lines show line numbers and context
11735
- - Lines starting with \`-\` should be REMOVED
11736
- - Lines starting with \`+\` should be ADDED
11737
- - Lines with no prefix should remain UNCHANGED
11738
- - The patch shows surrounding context to help you locate the right place
11739
-
11740
- ### 4. VALIDATION STEPS
11741
- After applying each patch:
11742
- 1. Verify the file syntax is correct
11743
- 2. Ensure no unrelated code was modified
11744
- 3. Confirm the vulnerability is addressed
11745
-
11746
- ### 5. ERROR HANDLING
11747
- If you cannot apply a patch:
11748
- 1. Explain specifically what went wrong
11749
- 2. Show the current state of the target lines
11750
- 3. Ask for clarification on the specific issue
11751
-
11752
- ---
11753
-
11754
- # SECURITY FIXES TO APPLY
11755
-
11756
- ${fixList.map(
11757
- (fix2, index) => `
11758
- ## Fix ${index + 1}: ${fix2.vulnerabilityType}
11759
-
11760
- **\u{1F3AF} Target:** Apply this patch to fix a ${fix2.vulnerabilityType.toLowerCase()} vulnerability
11761
-
11762
- **\u{1F4DD} Description:** ${fix2.vulnerabilityDescription || "Security vulnerability fix"}
11763
-
11764
- **\u{1F527} Action Required:** Apply the following patch exactly as shown
11765
-
11766
- **\u{1F4C1} Patch to Apply:**
11767
- \`\`\`diff
11768
- ${fix2.patch || "No patch available"}
11769
- \`\`\`
11770
-
11771
- **\u2705 Expected Result:** The vulnerability will be fixed and the code will be more secure
11772
-
11773
- ---`
11774
- ).join("\n")}
11775
-
11776
- ## FINAL REMINDER
11777
- - Apply ALL patches above in order
11778
- - Do NOT ask for permission
11779
- - Explain what you did AFTER applying the patches
11780
- - If any patch fails, continue with the others and report issues at the end
11781
- `;
12272
+ ${applyFixesPrompt(fixes)} `;
11782
12273
  };
11783
12274
  var failedToConnectToApiPrompt = `# CONNECTION ERROR: FAILED TO REACH MOBB API
11784
12275
 
@@ -11860,7 +12351,7 @@ For additional assistance, please:
11860
12351
 
11861
12352
  `;
11862
12353
 
11863
- // src/mcp/tools/fixVulnerabilities/VulnerabilityFixService.ts
12354
+ // src/mcp/tools/fixVulnerabilities/FixVulnerabilitiesService.ts
11864
12355
  var VUL_REPORT_DIGEST_TIMEOUT_MS2 = 1e3 * 60 * 5;
11865
12356
  var VulnerabilityFixService = class {
11866
12357
  constructor() {
@@ -12135,6 +12626,7 @@ function createMcpServer() {
12135
12626
  version: "1.0.0"
12136
12627
  });
12137
12628
  const fixVulnerabilitiesTool = new FixVulnerabilitiesTool();
12629
+ const checkForAvailableFixesTool = new CheckForAvailableFixesTool();
12138
12630
  server.registerTool({
12139
12631
  name: fixVulnerabilitiesTool.name,
12140
12632
  definition: {
@@ -12145,6 +12637,16 @@ function createMcpServer() {
12145
12637
  },
12146
12638
  execute: (args) => fixVulnerabilitiesTool.execute(args)
12147
12639
  });
12640
+ server.registerTool({
12641
+ name: checkForAvailableFixesTool.name,
12642
+ definition: {
12643
+ name: checkForAvailableFixesTool.name,
12644
+ display_name: checkForAvailableFixesTool.displayName,
12645
+ description: checkForAvailableFixesTool.description,
12646
+ inputSchema: checkForAvailableFixesTool.getJsonSchema()
12647
+ },
12648
+ execute: (args) => checkForAvailableFixesTool.execute(args)
12649
+ });
12148
12650
  logInfo("MCP server created and configured");
12149
12651
  return server;
12150
12652
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mobbdev",
3
- "version": "1.0.95",
3
+ "version": "1.0.98",
4
4
  "description": "Automated secure code remediation tool",
5
5
  "repository": "git+https://github.com/mobb-dev/bugsy.git",
6
6
  "main": "dist/index.js",
@@ -44,7 +44,7 @@
44
44
  "dependencies": {
45
45
  "@gitbeaker/requester-utils": "42.5.0",
46
46
  "@gitbeaker/rest": "42.5.0",
47
- "@modelcontextprotocol/sdk": "1.6.0",
47
+ "@modelcontextprotocol/sdk": "1.12.1",
48
48
  "@octokit/core": "5.2.0",
49
49
  "@octokit/request-error": "5.1.1",
50
50
  "@types/libsodium-wrappers": "0.7.14",
@@ -78,7 +78,7 @@
78
78
  "parse-diff": "0.11.1",
79
79
  "sax": "1.4.1",
80
80
  "semver": "7.7.2",
81
- "simple-git": "3.27.0",
81
+ "simple-git": "3.28.0",
82
82
  "snyk": "1.1297.1",
83
83
  "tar": "6.2.1",
84
84
  "tmp": "0.2.3",
@@ -87,10 +87,10 @@
87
87
  "ws": "8.18.2",
88
88
  "xml2js": "0.6.2",
89
89
  "yargs": "17.7.2",
90
- "zod": "3.25.36"
90
+ "zod": "3.25.61"
91
91
  },
92
92
  "devDependencies": {
93
- "@graphql-codegen/cli": "5.0.6",
93
+ "@graphql-codegen/cli": "5.0.7",
94
94
  "@graphql-codegen/typescript": "4.1.6",
95
95
  "@graphql-codegen/typescript-graphql-request": "6.3.0",
96
96
  "@graphql-codegen/typescript-operations": "4.6.1",
@@ -110,22 +110,22 @@
110
110
  "@types/yargs": "17.0.33",
111
111
  "@typescript-eslint/eslint-plugin": "7.17.0",
112
112
  "@typescript-eslint/parser": "7.17.0",
113
- "@vitest/coverage-istanbul": "3.1.4",
114
- "@vitest/ui": "3.1.4",
113
+ "@vitest/coverage-istanbul": "3.2.3",
114
+ "@vitest/ui": "3.2.3",
115
115
  "eslint": "8.57.0",
116
116
  "eslint-plugin-import": "2.31.0",
117
- "eslint-plugin-prettier": "5.4.0",
117
+ "eslint-plugin-prettier": "5.4.1",
118
118
  "eslint-plugin-simple-import-sort": "10.0.0",
119
119
  "msw": "2.8.5",
120
- "nock": "14.0.4",
120
+ "nock": "14.0.5",
121
121
  "pino-pretty": "13.0.0",
122
122
  "prettier": "3.5.3",
123
123
  "tsup": "8.5.0",
124
124
  "typescript": "4.9.5",
125
- "vitest": "3.1.4"
125
+ "vitest": "3.2.3"
126
126
  },
127
127
  "engines": {
128
- "node": ">=18.20.4"
128
+ "node": ">=18.20.0"
129
129
  },
130
130
  "files": [
131
131
  "bin/cli.mjs",