mobbdev 1.0.122 → 1.0.126

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 +325 -246
  2. package/package.json +5 -4
package/dist/index.mjs CHANGED
@@ -32,7 +32,7 @@ var init_env = __esm({
32
32
  });
33
33
 
34
34
  // src/mcp/core/configs.ts
35
- var MCP_DEFAULT_API_URL, MCP_API_KEY_HEADER_NAME, MCP_LOGIN_MAX_WAIT, MCP_LOGIN_CHECK_DELAY, MCP_VUL_REPORT_DIGEST_TIMEOUT_MS, MCP_MAX_FILE_SIZE, MCP_PERIODIC_CHECK_INTERVAL, MCP_DEFAULT_MAX_FILES_TO_SCAN, MCP_REPORT_ID_EXPIRATION_MS, MCP_TOOLS_BROWSER_COOLDOWN_MS, MCP_DEFAULT_LIMIT;
35
+ var MCP_DEFAULT_API_URL, MCP_API_KEY_HEADER_NAME, MCP_LOGIN_MAX_WAIT, MCP_LOGIN_CHECK_DELAY, MCP_VUL_REPORT_DIGEST_TIMEOUT_MS, MCP_MAX_FILE_SIZE, MCP_PERIODIC_CHECK_INTERVAL, MCP_DEFAULT_MAX_FILES_TO_SCAN, MCP_REPORT_ID_EXPIRATION_MS, MCP_TOOLS_BROWSER_COOLDOWN_MS, MCP_DEFAULT_LIMIT, isAutoScan;
36
36
  var init_configs = __esm({
37
37
  "src/mcp/core/configs.ts"() {
38
38
  "use strict";
@@ -48,6 +48,7 @@ var init_configs = __esm({
48
48
  MCP_REPORT_ID_EXPIRATION_MS = 2 * 60 * 60 * 1e3;
49
49
  MCP_TOOLS_BROWSER_COOLDOWN_MS = 24 * 60 * 60 * 1e3;
50
50
  MCP_DEFAULT_LIMIT = 3;
51
+ isAutoScan = process.env["AUTO_SCAN"] !== "false";
51
52
  }
52
53
  });
53
54
 
@@ -1440,6 +1441,7 @@ var Language = /* @__PURE__ */ ((Language2) => {
1440
1441
  Language2["Cpp"] = "CPP";
1441
1442
  Language2["Csharp"] = "CSHARP";
1442
1443
  Language2["Default"] = "DEFAULT";
1444
+ Language2["Dockerfile"] = "DOCKERFILE";
1443
1445
  Language2["Go"] = "GO";
1444
1446
  Language2["Java"] = "JAVA";
1445
1447
  Language2["Js"] = "JS";
@@ -1493,6 +1495,7 @@ var IssueLanguage_Enum = /* @__PURE__ */ ((IssueLanguage_Enum2) => {
1493
1495
  IssueLanguage_Enum2["CSharp"] = "CSharp";
1494
1496
  IssueLanguage_Enum2["Cpp"] = "Cpp";
1495
1497
  IssueLanguage_Enum2["Default"] = "Default";
1498
+ IssueLanguage_Enum2["Dockerfile"] = "Dockerfile";
1496
1499
  IssueLanguage_Enum2["Go"] = "Go";
1497
1500
  IssueLanguage_Enum2["Java"] = "Java";
1498
1501
  IssueLanguage_Enum2["JavaScript"] = "JavaScript";
@@ -1549,6 +1552,7 @@ var IssueType_Enum = /* @__PURE__ */ ((IssueType_Enum2) => {
1549
1552
  IssueType_Enum2["InformationExposureViaHeaders"] = "INFORMATION_EXPOSURE_VIA_HEADERS";
1550
1553
  IssueType_Enum2["InsecureBinderConfiguration"] = "INSECURE_BINDER_CONFIGURATION";
1551
1554
  IssueType_Enum2["InsecureCookie"] = "INSECURE_COOKIE";
1555
+ IssueType_Enum2["InsecurePostmessage"] = "INSECURE_POSTMESSAGE";
1552
1556
  IssueType_Enum2["InsecureRandomness"] = "INSECURE_RANDOMNESS";
1553
1557
  IssueType_Enum2["InsecureTmpFile"] = "INSECURE_TMP_FILE";
1554
1558
  IssueType_Enum2["InsecureUuidVersion"] = "INSECURE_UUID_VERSION";
@@ -1563,6 +1567,7 @@ var IssueType_Enum = /* @__PURE__ */ ((IssueType_Enum2) => {
1563
1567
  IssueType_Enum2["MissingEqualsOrHashcode"] = "MISSING_EQUALS_OR_HASHCODE";
1564
1568
  IssueType_Enum2["MissingHstsHeader"] = "MISSING_HSTS_HEADER";
1565
1569
  IssueType_Enum2["MissingSslMinversion"] = "MISSING_SSL_MINVERSION";
1570
+ IssueType_Enum2["MissingUser"] = "MISSING_USER";
1566
1571
  IssueType_Enum2["MissingWhitespace"] = "MISSING_WHITESPACE";
1567
1572
  IssueType_Enum2["ModifiedDefaultParam"] = "MODIFIED_DEFAULT_PARAM";
1568
1573
  IssueType_Enum2["NonFinalPublicStaticField"] = "NON_FINAL_PUBLIC_STATIC_FIELD";
@@ -2255,14 +2260,14 @@ var GetReportFixesDocument = `
2255
2260
  var GetLatestReportByRepoUrlDocument = `
2256
2261
  query GetLatestReportByRepoUrl($repoUrl: String!, $filters: fix_bool_exp = {}, $limit: Int!, $offset: Int!, $currentUserEmail: String!) {
2257
2262
  fixReport(
2258
- where: {_and: [{repo: {originalUrl: {_eq: $repoUrl}}}, {state: {_eq: Finished}}]}
2263
+ where: {_and: [{repo: {originalUrl: {_eq: $repoUrl}}}, {state: {_eq: Finished}}, {vulnerabilityReport: {_or: [{vendor: {_is_null: true}}, {vendor: {_nin: [semgrep, opengrep]}}]}}]}
2259
2264
  order_by: {createdOn: desc}
2260
2265
  limit: 1
2261
2266
  ) {
2262
2267
  ...FixReportSummaryFields
2263
2268
  }
2264
2269
  expiredReport: fixReport(
2265
- where: {_and: [{repo: {originalUrl: {_eq: $repoUrl}}}, {state: {_eq: Expired}}]}
2270
+ where: {_and: [{repo: {originalUrl: {_eq: $repoUrl}}}, {state: {_eq: Expired}}, {_or: [{vulnerabilityReport: {vendor: {_is_null: true}}}, {vulnerabilityReport: {vendor: {_nin: [semgrep, opengrep]}}}]}]}
2266
2271
  order_by: {createdOn: desc}
2267
2272
  limit: 1
2268
2273
  ) {
@@ -2636,7 +2641,12 @@ var fixDetailsData = {
2636
2641
  fixInstructions: "Implement proper input validation and bounds checking to prevent HTTP parameter pollution. Use safe string manipulation functions and ensure that the buffer size is properly managed."
2637
2642
  },
2638
2643
  ["INCOMPLETE_SANITIZATION" /* IncompleteSanitization */]: void 0,
2639
- ["CREDENTIAL_DISCLOSURE" /* CredentialDisclosure */]: void 0
2644
+ ["CREDENTIAL_DISCLOSURE" /* CredentialDisclosure */]: void 0,
2645
+ ["INSECURE_POSTMESSAGE" /* InsecurePostmessage */]: void 0,
2646
+ ["MISSING_USER" /* MissingUser */]: {
2647
+ issueDescription: "Missing User occurs when a user is not specified in the Dockerfile, leading to security vulnerabilities.",
2648
+ fixInstructions: "Specify a user in the Dockerfile to prevent security vulnerabilities."
2649
+ }
2640
2650
  };
2641
2651
 
2642
2652
  // src/features/analysis/scm/shared/src/getIssueType.ts
@@ -2755,7 +2765,9 @@ var issueTypeMap = {
2755
2765
  ["STRING_TERMINATION_ERROR" /* StringTerminationError */]: "String Termination Error",
2756
2766
  ["HTTP_PARAMETER_POLLUTION" /* HttpParameterPollution */]: "HTTP Parameter Pollution",
2757
2767
  ["INCOMPLETE_SANITIZATION" /* IncompleteSanitization */]: "Incomplete Sanitization",
2758
- ["CREDENTIAL_DISCLOSURE" /* CredentialDisclosure */]: "Credential Disclosure"
2768
+ ["CREDENTIAL_DISCLOSURE" /* CredentialDisclosure */]: "Credential Disclosure",
2769
+ ["INSECURE_POSTMESSAGE" /* InsecurePostmessage */]: "Insecure Postmessage",
2770
+ ["MISSING_USER" /* MissingUser */]: "Missing User"
2759
2771
  };
2760
2772
  var issueTypeZ = z.nativeEnum(IssueType_Enum);
2761
2773
  var getIssueTypeFriendlyString = (issueType) => {
@@ -2952,9 +2964,13 @@ var vulnerabilities = {
2952
2964
  };
2953
2965
  var csharp_default = vulnerabilities;
2954
2966
 
2955
- // src/features/analysis/scm/shared/src/storedFixData/go/index.ts
2967
+ // src/features/analysis/scm/shared/src/storedFixData/dockerfile/index.ts
2956
2968
  var vulnerabilities2 = {};
2957
- var go_default = vulnerabilities2;
2969
+ var dockerfile_default = vulnerabilities2;
2970
+
2971
+ // src/features/analysis/scm/shared/src/storedFixData/go/index.ts
2972
+ var vulnerabilities3 = {};
2973
+ var go_default = vulnerabilities3;
2958
2974
 
2959
2975
  // src/features/analysis/scm/shared/src/storedFixData/java/sqlInjection.ts
2960
2976
  var sqlInjection = {
@@ -2981,12 +2997,12 @@ var systemInformationLeak = {
2981
2997
  };
2982
2998
 
2983
2999
  // src/features/analysis/scm/shared/src/storedFixData/java/index.ts
2984
- var vulnerabilities3 = {
3000
+ var vulnerabilities4 = {
2985
3001
  ["PASSWORD_IN_COMMENT" /* PasswordInComment */]: passwordInComment,
2986
3002
  ["SQL_Injection" /* SqlInjection */]: sqlInjection,
2987
3003
  ["SYSTEM_INFORMATION_LEAK" /* SystemInformationLeak */]: systemInformationLeak
2988
3004
  };
2989
- var java_default = vulnerabilities3;
3005
+ var java_default = vulnerabilities4;
2990
3006
 
2991
3007
  // src/features/analysis/scm/shared/src/storedFixData/python/csrf.ts
2992
3008
  var csrf = {
@@ -3029,18 +3045,18 @@ var ssrf = {
3029
3045
  };
3030
3046
 
3031
3047
  // src/features/analysis/scm/shared/src/storedFixData/javascript/index.ts
3032
- var vulnerabilities4 = {
3048
+ var vulnerabilities5 = {
3033
3049
  ["SSRF" /* Ssrf */]: ssrf,
3034
3050
  ["HARDCODED_SECRETS" /* HardcodedSecrets */]: hardcodedSecrets,
3035
3051
  ["PASSWORD_IN_COMMENT" /* PasswordInComment */]: passwordInComment,
3036
3052
  ["NO_LIMITS_OR_THROTTLING" /* NoLimitsOrThrottling */]: noLimitsOrThrottling,
3037
3053
  ["CSRF" /* Csrf */]: csrf
3038
3054
  };
3039
- var javascript_default = vulnerabilities4;
3055
+ var javascript_default = vulnerabilities5;
3040
3056
 
3041
3057
  // src/features/analysis/scm/shared/src/storedFixData/php/index.ts
3042
- var vulnerabilities5 = {};
3043
- var php_default = vulnerabilities5;
3058
+ var vulnerabilities6 = {};
3059
+ var php_default = vulnerabilities6;
3044
3060
 
3045
3061
  // src/features/analysis/scm/shared/src/storedFixData/python/autoEscapeFalse.ts
3046
3062
  var autoEscapeFalse = {
@@ -3062,11 +3078,11 @@ See more information [here](https://jinja.palletsprojects.com/en/3.1.x/templates
3062
3078
  };
3063
3079
 
3064
3080
  // src/features/analysis/scm/shared/src/storedFixData/python/index.ts
3065
- var vulnerabilities6 = {
3081
+ var vulnerabilities7 = {
3066
3082
  ["AUTO_ESCAPE_FALSE" /* AutoEscapeFalse */]: autoEscapeFalse,
3067
3083
  ["CSRF" /* Csrf */]: csrf
3068
3084
  };
3069
- var python_default = vulnerabilities6;
3085
+ var python_default = vulnerabilities7;
3070
3086
 
3071
3087
  // src/features/analysis/scm/shared/src/storedFixData/sql/defaultRightsInObjDefinition.ts
3072
3088
  var defaultRightsInObjDefinition = {
@@ -3074,16 +3090,16 @@ var defaultRightsInObjDefinition = {
3074
3090
  };
3075
3091
 
3076
3092
  // src/features/analysis/scm/shared/src/storedFixData/sql/index.ts
3077
- var vulnerabilities7 = {
3093
+ var vulnerabilities8 = {
3078
3094
  ["DEFAULT_RIGHTS_IN_OBJ_DEFINITION" /* DefaultRightsInObjDefinition */]: defaultRightsInObjDefinition
3079
3095
  };
3080
- var sql_default = vulnerabilities7;
3096
+ var sql_default = vulnerabilities8;
3081
3097
 
3082
3098
  // src/features/analysis/scm/shared/src/storedFixData/xml/index.ts
3083
- var vulnerabilities8 = {
3099
+ var vulnerabilities9 = {
3084
3100
  ["PASSWORD_IN_COMMENT" /* PasswordInComment */]: passwordInComment
3085
3101
  };
3086
- var xml_default = vulnerabilities8;
3102
+ var xml_default = vulnerabilities9;
3087
3103
 
3088
3104
  // src/features/analysis/scm/shared/src/storedFixData/index.ts
3089
3105
  var StoredFixDataItemZ = z3.object({
@@ -3097,7 +3113,8 @@ var languages = {
3097
3113
  ["XML" /* Xml */]: xml_default,
3098
3114
  ["Python" /* Python */]: python_default,
3099
3115
  ["PHP" /* Php */]: php_default,
3100
- ["Go" /* Go */]: go_default
3116
+ ["Go" /* Go */]: go_default,
3117
+ ["Dockerfile" /* Dockerfile */]: dockerfile_default
3101
3118
  };
3102
3119
 
3103
3120
  // src/features/analysis/scm/shared/src/storedQuestionData/index.ts
@@ -3387,7 +3404,7 @@ var xxe = {
3387
3404
  };
3388
3405
 
3389
3406
  // src/features/analysis/scm/shared/src/storedQuestionData/csharp/index.ts
3390
- var vulnerabilities9 = {
3407
+ var vulnerabilities10 = {
3391
3408
  ["LOG_FORGING" /* LogForging */]: logForging,
3392
3409
  ["SSRF" /* Ssrf */]: ssrf2,
3393
3410
  ["XXE" /* Xxe */]: xxe,
@@ -3407,7 +3424,7 @@ var vulnerabilities9 = {
3407
3424
  ["INSUFFICIENT_LOGGING" /* InsufficientLogging */]: insufficientLogging,
3408
3425
  ["SQL_Injection" /* SqlInjection */]: sqlInjection2
3409
3426
  };
3410
- var csharp_default2 = vulnerabilities9;
3427
+ var csharp_default2 = vulnerabilities10;
3411
3428
 
3412
3429
  // src/features/analysis/scm/shared/src/storedQuestionData/go/logForging.ts
3413
3430
  var logForging2 = {
@@ -3437,12 +3454,12 @@ var websocketMissingOriginCheck = {
3437
3454
  };
3438
3455
 
3439
3456
  // src/features/analysis/scm/shared/src/storedQuestionData/go/index.ts
3440
- var vulnerabilities10 = {
3457
+ var vulnerabilities11 = {
3441
3458
  ["LOG_FORGING" /* LogForging */]: logForging2,
3442
3459
  ["MISSING_SSL_MINVERSION" /* MissingSslMinversion */]: missingSslMinversion,
3443
3460
  ["WEBSOCKET_MISSING_ORIGIN_CHECK" /* WebsocketMissingOriginCheck */]: websocketMissingOriginCheck
3444
3461
  };
3445
- var go_default2 = vulnerabilities10;
3462
+ var go_default2 = vulnerabilities11;
3446
3463
 
3447
3464
  // src/features/analysis/scm/shared/src/storedQuestionData/java/commandInjection.ts
3448
3465
  var commandInjection = {
@@ -3896,7 +3913,7 @@ var xxe2 = {
3896
3913
  };
3897
3914
 
3898
3915
  // src/features/analysis/scm/shared/src/storedQuestionData/java/index.ts
3899
- var vulnerabilities11 = {
3916
+ var vulnerabilities12 = {
3900
3917
  ["SQL_Injection" /* SqlInjection */]: sqlInjection3,
3901
3918
  ["CMDi_relative_path_command" /* CmDiRelativePathCommand */]: relativePathCommand,
3902
3919
  ["CMDi" /* CmDi */]: commandInjection,
@@ -3922,7 +3939,7 @@ var vulnerabilities11 = {
3922
3939
  ["ERRONEOUS_STRING_COMPARE" /* ErroneousStringCompare */]: erroneousStringCompare,
3923
3940
  ["DUPLICATED_STRINGS" /* DuplicatedStrings */]: duplicatedStrings
3924
3941
  };
3925
- var java_default2 = vulnerabilities11;
3942
+ var java_default2 = vulnerabilities12;
3926
3943
 
3927
3944
  // src/features/analysis/scm/shared/src/storedQuestionData/python/csrf.ts
3928
3945
  var csrf2 = {
@@ -4230,7 +4247,7 @@ var xss3 = {
4230
4247
  };
4231
4248
 
4232
4249
  // src/features/analysis/scm/shared/src/storedQuestionData/js/index.ts
4233
- var vulnerabilities12 = {
4250
+ var vulnerabilities13 = {
4234
4251
  ["CMDi" /* CmDi */]: commandInjection2,
4235
4252
  ["GRAPHQL_DEPTH_LIMIT" /* GraphqlDepthLimit */]: graphqlDepthLimit,
4236
4253
  ["INSECURE_RANDOMNESS" /* InsecureRandomness */]: insecureRandomness2,
@@ -4252,7 +4269,7 @@ var vulnerabilities12 = {
4252
4269
  ["HARDCODED_DOMAIN_IN_HTML" /* HardcodedDomainInHtml */]: hardcodedDomainInHtml,
4253
4270
  ["CSRF" /* Csrf */]: csrf2
4254
4271
  };
4255
- var js_default = vulnerabilities12;
4272
+ var js_default = vulnerabilities13;
4256
4273
 
4257
4274
  // src/features/analysis/scm/shared/src/storedQuestionData/python/duplicatedStrings.ts
4258
4275
  var duplicatedStrings2 = {
@@ -4303,14 +4320,14 @@ var uncheckedLoopCondition3 = {
4303
4320
  };
4304
4321
 
4305
4322
  // src/features/analysis/scm/shared/src/storedQuestionData/python/index.ts
4306
- var vulnerabilities13 = {
4323
+ var vulnerabilities14 = {
4307
4324
  ["CSRF" /* Csrf */]: csrf2,
4308
4325
  ["LOG_FORGING" /* LogForging */]: logForging5,
4309
4326
  ["OPEN_REDIRECT" /* OpenRedirect */]: openRedirect3,
4310
4327
  ["UNCHECKED_LOOP_CONDITION" /* UncheckedLoopCondition */]: uncheckedLoopCondition3,
4311
4328
  ["DUPLICATED_STRINGS" /* DuplicatedStrings */]: duplicatedStrings2
4312
4329
  };
4313
- var python_default2 = vulnerabilities13;
4330
+ var python_default2 = vulnerabilities14;
4314
4331
 
4315
4332
  // src/features/analysis/scm/shared/src/storedQuestionData/xml/unboundedOccurrences.ts
4316
4333
  var unboundedOccurrences = {
@@ -4324,10 +4341,10 @@ A value too high will cause performance issues up to and including denial of ser
4324
4341
  };
4325
4342
 
4326
4343
  // src/features/analysis/scm/shared/src/storedQuestionData/xml/index.ts
4327
- var vulnerabilities14 = {
4344
+ var vulnerabilities15 = {
4328
4345
  ["WEAK_XML_SCHEMA_UNBOUNDED_OCCURRENCES" /* WeakXmlSchemaUnboundedOccurrences */]: unboundedOccurrences
4329
4346
  };
4330
- var xml_default2 = vulnerabilities14;
4347
+ var xml_default2 = vulnerabilities15;
4331
4348
 
4332
4349
  // src/features/analysis/scm/shared/src/storedQuestionData/index.ts
4333
4350
  var StoredQuestionDataItemZ = z4.object({
@@ -11937,104 +11954,34 @@ import {
11937
11954
  } from "@modelcontextprotocol/sdk/types.js";
11938
11955
 
11939
11956
  // src/mcp/Logger.ts
11940
- var loggerUrl = "http://localhost:4444/log";
11941
- var isTestEnvironment = process.env["VITEST"] || process.env["TEST"];
11942
- var CIRCUIT_BREAKER_TIME = 5e3;
11943
- var URL_CHECK_TIMEOUT = 200;
11944
- var MAX_QUEUE_SIZE = 100;
11957
+ import Configstore3 from "configstore";
11958
+ var MAX_LOGS_SIZE = 1e3;
11945
11959
  var Logger = class {
11946
11960
  constructor() {
11947
- __publicField(this, "queue", []);
11948
- __publicField(this, "isProcessing", false);
11949
- __publicField(this, "isCircuitBroken", false);
11950
- __publicField(this, "circuitBreakerTimer", null);
11961
+ __publicField(this, "mobbConfigStore");
11962
+ __publicField(this, "path");
11963
+ this.path = process.env["WORKSPACE_FOLDER_PATHS"] || "unknown";
11964
+ this.mobbConfigStore = new Configstore3("mobb-logs", {});
11965
+ this.mobbConfigStore.set("version", packageJson.version);
11951
11966
  }
11967
+ /**
11968
+ * Log a message to the console.
11969
+ * @param message - The message to log.
11970
+ * @param level - The level of the message.
11971
+ * @param data - The data to log.
11972
+ */
11952
11973
  log(message, level = "info", data) {
11953
- if (isTestEnvironment) return;
11954
- if (this.queue.length >= MAX_QUEUE_SIZE) {
11955
- this.queue.shift();
11956
- }
11957
- this.queue.push({ message, level, data });
11958
- if (!this.isProcessing && !this.isCircuitBroken) {
11959
- this.processQueue();
11960
- }
11961
- }
11962
- async isUrlReachable(url) {
11963
- try {
11964
- const controller = new AbortController();
11965
- const timeoutId = setTimeout(() => controller.abort(), URL_CHECK_TIMEOUT);
11966
- await fetch(url, {
11967
- method: "HEAD",
11968
- signal: controller.signal
11969
- });
11970
- clearTimeout(timeoutId);
11971
- return true;
11972
- } catch (error) {
11973
- return false;
11974
- }
11975
- }
11976
- async processQueue() {
11977
- if (this.queue.length === 0 || this.isCircuitBroken) {
11978
- this.isProcessing = false;
11979
- return;
11980
- }
11981
- this.isProcessing = true;
11982
- const logEntry = this.queue[0];
11983
- if (!logEntry) {
11984
- this.isProcessing = false;
11985
- return;
11986
- }
11987
- const isReachable = await this.isUrlReachable(loggerUrl);
11988
- if (!isReachable) {
11989
- this.triggerCircuitBreaker();
11990
- return;
11991
- }
11992
- await this.sendLogEntry(logEntry);
11993
- }
11994
- async sendLogEntry(logEntry) {
11995
11974
  const logMessage = {
11996
11975
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
11997
- level: logEntry.level,
11998
- message: logEntry.message,
11999
- data: logEntry.data,
12000
- version: packageJson.version
11976
+ level,
11977
+ message,
11978
+ data
12001
11979
  };
12002
- const controller = new AbortController();
12003
- const timeoutId = setTimeout(() => {
12004
- controller.abort();
12005
- }, 500);
12006
- try {
12007
- await fetch(loggerUrl, {
12008
- method: "POST",
12009
- headers: { "Content-Type": "application/json" },
12010
- body: JSON.stringify(logMessage),
12011
- redirect: "error",
12012
- // do not follow redirects
12013
- signal: controller.signal
12014
- });
12015
- this.queue.shift();
12016
- setTimeout(() => this.processQueue(), 0);
12017
- } catch (error) {
12018
- this.triggerCircuitBreaker();
12019
- logError("Failed to send log entry", error);
12020
- } finally {
12021
- clearTimeout(timeoutId);
11980
+ const logs = this.mobbConfigStore.get(this.path) || [];
11981
+ if (logs.length >= MAX_LOGS_SIZE) {
11982
+ logs.shift();
12022
11983
  }
12023
- }
12024
- triggerCircuitBreaker() {
12025
- this.isCircuitBroken = true;
12026
- this.queue = [];
12027
- this.isProcessing = false;
12028
- if (this.circuitBreakerTimer) {
12029
- clearTimeout(this.circuitBreakerTimer);
12030
- }
12031
- this.circuitBreakerTimer = setTimeout(() => {
12032
- this.isCircuitBroken = false;
12033
- this.circuitBreakerTimer = null;
12034
- if (this.queue.length > 0 && !this.isProcessing) {
12035
- this.processQueue();
12036
- }
12037
- }, CIRCUIT_BREAKER_TIME);
11984
+ this.mobbConfigStore.set(this.path, [...logs, logMessage]);
12038
11985
  }
12039
11986
  };
12040
11987
  var logger = new Logger();
@@ -12045,12 +11992,34 @@ var logDebug = (message, data) => logger.log(message, "debug", data);
12045
11992
  var log = logger.log.bind(logger);
12046
11993
 
12047
11994
  // src/mcp/services/McpGQLClient.ts
12048
- import Configstore3 from "configstore";
12049
11995
  import crypto3 from "crypto";
12050
11996
  import { GraphQLClient as GraphQLClient2 } from "graphql-request";
12051
11997
  import { v4 as uuidv42 } from "uuid";
12052
11998
  init_configs();
12053
11999
 
12000
+ // src/mcp/services/ConfigStoreService.ts
12001
+ init_configs();
12002
+ import Configstore4 from "configstore";
12003
+ function createConfigStore(defaultValues = { apiToken: "" }) {
12004
+ const API_URL2 = process.env["API_URL"] || MCP_DEFAULT_API_URL;
12005
+ let domain = "";
12006
+ try {
12007
+ const url = new URL(API_URL2);
12008
+ domain = url.hostname;
12009
+ } catch (e) {
12010
+ domain = API_URL2.replace(/^https?:\/\//, "").replace(/\/.*$/, "").replace(/:\d+$/, "");
12011
+ }
12012
+ const sanitizedDomain = domain.replace(/\./g, "_");
12013
+ return new Configstore4(
12014
+ `${packageJson.name}-${sanitizedDomain}`,
12015
+ defaultValues
12016
+ );
12017
+ }
12018
+ function getConfigStore() {
12019
+ return createConfigStore();
12020
+ }
12021
+ var configStore = getConfigStore();
12022
+
12054
12023
  // src/mcp/services/McpAuthService.ts
12055
12024
  import crypto2 from "crypto";
12056
12025
  import os2 from "os";
@@ -12131,16 +12100,17 @@ var McpAuthService = class {
12131
12100
  };
12132
12101
 
12133
12102
  // src/mcp/services/McpGQLClient.ts
12134
- var mobbConfigStore = new Configstore3(packageJson.name, { apiToken: "" });
12135
12103
  var McpGQLClient = class {
12136
12104
  constructor(args) {
12137
12105
  __publicField(this, "client");
12138
12106
  __publicField(this, "clientSdk");
12139
12107
  __publicField(this, "_auth");
12108
+ __publicField(this, "currentUser", null);
12109
+ __publicField(this, "apiUrl");
12140
12110
  this._auth = args;
12141
- const API_URL2 = process.env["API_URL"] || MCP_DEFAULT_API_URL;
12142
- logDebug("creating graphql client", { API_URL: API_URL2, args });
12143
- this.client = new GraphQLClient2(API_URL2, {
12111
+ this.apiUrl = process.env["API_URL"] || MCP_DEFAULT_API_URL;
12112
+ logDebug(`creating graphql client with api url ${this.apiUrl}`, { args });
12113
+ this.client = new GraphQLClient2(this.apiUrl, {
12144
12114
  headers: args.type === "apiKey" ? { [MCP_API_KEY_HEADER_NAME]: args.apiKey || "" } : {
12145
12115
  Authorization: `Bearer ${args.token}`
12146
12116
  },
@@ -12159,7 +12129,7 @@ var McpGQLClient = class {
12159
12129
  }
12160
12130
  getErrorContext() {
12161
12131
  return {
12162
- endpoint: process.env["API_URL"] || MCP_DEFAULT_API_URL,
12132
+ endpoint: this.apiUrl,
12163
12133
  apiKey: this._auth.type === "apiKey" ? this._auth.apiKey : "",
12164
12134
  headers: {
12165
12135
  [MCP_API_KEY_HEADER_NAME]: this._auth.type === "apiKey" ? "[REDACTED]" : "undefined",
@@ -12167,10 +12137,10 @@ var McpGQLClient = class {
12167
12137
  }
12168
12138
  };
12169
12139
  }
12170
- async verifyApiConnection() {
12140
+ async isApiEndpointReachable() {
12171
12141
  try {
12172
12142
  logDebug("GraphQL: Calling Me query for API connection verification");
12173
- const result = await this.clientSdk.Me();
12143
+ const result = await this.getUserInfo();
12174
12144
  logDebug("GraphQL: Me query successful", { result });
12175
12145
  return true;
12176
12146
  } catch (e) {
@@ -12183,6 +12153,23 @@ var McpGQLClient = class {
12183
12153
  }
12184
12154
  return true;
12185
12155
  }
12156
+ /**
12157
+ * Verifies both API endpoint reachability and user authentication
12158
+ * @returns true if both API is reachable and user is authenticated
12159
+ */
12160
+ async verifyApiConnection() {
12161
+ const isReachable = await this.isApiEndpointReachable();
12162
+ if (!isReachable) {
12163
+ return false;
12164
+ }
12165
+ try {
12166
+ await this.validateUserToken();
12167
+ return true;
12168
+ } catch (e) {
12169
+ logError("User token validation failed", { error: e });
12170
+ return false;
12171
+ }
12172
+ }
12186
12173
  async uploadS3BucketInfo() {
12187
12174
  try {
12188
12175
  logDebug("GraphQL: Calling uploadS3BucketInfo mutation");
@@ -12237,8 +12224,9 @@ var McpGQLClient = class {
12237
12224
  }
12238
12225
  }
12239
12226
  async subscribeToGetAnalysis(params) {
12227
+ const { scanContext } = params;
12240
12228
  try {
12241
- logDebug("GraphQL: Starting GetAnalysis subscription", {
12229
+ logDebug(`[${scanContext}] GraphQL: Starting GetAnalysis subscription`, {
12242
12230
  params: params.subscribeToAnalysisParams
12243
12231
  });
12244
12232
  const { callbackStates } = params;
@@ -12246,10 +12234,13 @@ var McpGQLClient = class {
12246
12234
  GetAnalysisSubscriptionDocument,
12247
12235
  params.subscribeToAnalysisParams,
12248
12236
  async (resolve, reject, data) => {
12249
- logDebug("GraphQL: GetAnalysis subscription data received", { data });
12237
+ logDebug(
12238
+ `[${scanContext}] GraphQL: GetAnalysis subscription data received ${data.analysis?.state}`,
12239
+ { data }
12240
+ );
12250
12241
  if (!data.analysis?.state || data.analysis?.state === "Failed" /* Failed */) {
12251
12242
  const errorMessage = data.analysis?.failReason || `Analysis failed with id: ${data.analysis?.id}`;
12252
- logError("GraphQL: Analysis failed", {
12243
+ logError(`[${scanContext}] GraphQL: Analysis failed`, {
12253
12244
  analysisId: data.analysis?.id,
12254
12245
  state: data.analysis?.state,
12255
12246
  failReason: data.analysis?.failReason,
@@ -12259,11 +12250,14 @@ var McpGQLClient = class {
12259
12250
  return;
12260
12251
  }
12261
12252
  if (callbackStates.includes(data.analysis?.state)) {
12262
- logDebug("GraphQL: Analysis state matches callback states", {
12263
- analysisId: data.analysis.id,
12264
- state: data.analysis.state,
12265
- callbackStates
12266
- });
12253
+ logDebug(
12254
+ `[${scanContext}] GraphQL: Analysis state matches callback states: ${data.analysis.state}`,
12255
+ {
12256
+ analysisId: data.analysis.id,
12257
+ state: data.analysis.state,
12258
+ callbackStates
12259
+ }
12260
+ );
12267
12261
  await params.callback(data.analysis.id);
12268
12262
  resolve(data);
12269
12263
  }
@@ -12278,10 +12272,12 @@ var McpGQLClient = class {
12278
12272
  timeoutInMs: params.timeoutInMs
12279
12273
  }
12280
12274
  );
12281
- logDebug("GraphQL: GetAnalysis subscription completed", { result });
12275
+ logDebug(`[${scanContext}] GraphQL: GetAnalysis subscription completed`, {
12276
+ result
12277
+ });
12282
12278
  return result;
12283
12279
  } catch (e) {
12284
- logError("GraphQL: GetAnalysis subscription failed", {
12280
+ logError(`[${scanContext}] GraphQL: GetAnalysis subscription failed`, {
12285
12281
  error: e,
12286
12282
  params: params.subscribeToAnalysisParams,
12287
12283
  ...this.getErrorContext()
@@ -12345,8 +12341,12 @@ var McpGQLClient = class {
12345
12341
  }
12346
12342
  async getUserInfo() {
12347
12343
  const { me } = await this.clientSdk.Me();
12344
+ this.currentUser = me;
12348
12345
  return me;
12349
12346
  }
12347
+ getCurrentUser() {
12348
+ return this.currentUser;
12349
+ }
12350
12350
  async validateUserToken() {
12351
12351
  logDebug("validating user token");
12352
12352
  try {
@@ -12539,16 +12539,16 @@ var McpGQLClient = class {
12539
12539
  async function createAuthenticatedMcpGQLClient({
12540
12540
  isBackgoundCall = false
12541
12541
  } = {}) {
12542
- logDebug("getting config", { apiToken: mobbConfigStore.get("apiToken") });
12542
+ logDebug("getting config", { apiToken: configStore.get("apiToken") });
12543
12543
  const initialClient = new McpGQLClient({
12544
12544
  apiKey: process.env["MOBB_API_KEY"] || process.env["API_KEY"] || // fallback for backward compatibility
12545
- mobbConfigStore.get("apiToken") || "",
12545
+ configStore.get("apiToken") || "",
12546
12546
  type: "apiKey"
12547
12547
  });
12548
- const isConnected = await initialClient.verifyApiConnection();
12549
- logDebug("API connection status", { isConnected });
12550
- if (!isConnected) {
12551
- throw new ApiConnectionError("Error: failed to connect to Mobb API");
12548
+ const isApiEndpointReachable = await initialClient.isApiEndpointReachable();
12549
+ logDebug("API connection status", { isApiEndpointReachable });
12550
+ if (!isApiEndpointReachable) {
12551
+ throw new ApiConnectionError("Error: failed to reach Mobb GraphQL endpoint");
12552
12552
  }
12553
12553
  logDebug("validating user token");
12554
12554
  const userVerify = await initialClient.validateUserToken();
@@ -12557,7 +12557,7 @@ async function createAuthenticatedMcpGQLClient({
12557
12557
  }
12558
12558
  const authService = new McpAuthService(initialClient);
12559
12559
  const newApiToken = await authService.authenticate(isBackgoundCall);
12560
- mobbConfigStore.set("apiToken", newApiToken);
12560
+ configStore.set("apiToken", newApiToken);
12561
12561
  return new McpGQLClient({ apiKey: newApiToken, type: "apiKey" });
12562
12562
  }
12563
12563
 
@@ -12566,6 +12566,9 @@ var MCP_TOOL_CHECK_FOR_NEW_AVAILABLE_FIXES = "check_for_new_available_fixes";
12566
12566
  var MCP_TOOL_FETCH_AVAILABLE_FIXES = "fetch_available_fixes";
12567
12567
  var MCP_TOOL_SCAN_AND_FIX_VULNERABILITIES = "scan_and_fix_vulnerabilities";
12568
12568
 
12569
+ // src/mcp/core/McpServer.ts
12570
+ init_configs();
12571
+
12569
12572
  // src/mcp/core/ToolRegistry.ts
12570
12573
  var ToolRegistry = class {
12571
12574
  constructor() {
@@ -12640,6 +12643,18 @@ var McpServer = class {
12640
12643
  } else {
12641
12644
  logWarn(`${message} (exit code: ${exitCode})`, { signal, exitCode });
12642
12645
  }
12646
+ } else if (signal === "unhandledRejection") {
12647
+ const errorDetails = {
12648
+ signal,
12649
+ errorType: error?.constructor?.name || "Unknown",
12650
+ errorMessage: error instanceof Error ? error.message : String(error),
12651
+ errorStack: error instanceof Error ? error.stack : void 0,
12652
+ errorString: error?.toString(),
12653
+ errorJson: JSON.stringify(error, null, 2),
12654
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
12655
+ };
12656
+ logError(`${message} - Enhanced error details`, errorDetails);
12657
+ logError(`${message} - Raw error object`, { error, signal });
12643
12658
  } else if (error) {
12644
12659
  logError(`${message}`, { error, signal });
12645
12660
  } else {
@@ -12684,30 +12699,43 @@ var McpServer = class {
12684
12699
  });
12685
12700
  }
12686
12701
  async triggerScanForNewAvailableFixes() {
12687
- const gqlClient = await createAuthenticatedMcpGQLClient({
12688
- isBackgoundCall: true
12689
- });
12690
- const isConnected = await gqlClient.verifyApiConnection();
12691
- if (!isConnected) {
12692
- logError("Failed to connect to the API, skipping scan");
12693
- return;
12694
- }
12695
- if (process.env["WORKSPACE_FOLDER_PATHS"]) {
12696
- logDebug("WORKSPACE_FOLDER_PATHS is set", {
12697
- WORKSPACE_FOLDER_PATHS: process.env["WORKSPACE_FOLDER_PATHS"]
12702
+ try {
12703
+ const gqlClient = await createAuthenticatedMcpGQLClient({
12704
+ isBackgoundCall: true
12698
12705
  });
12699
- try {
12700
- const checkForNewAvailableFixesTool = this.toolRegistry.getTool(
12701
- MCP_TOOL_CHECK_FOR_NEW_AVAILABLE_FIXES
12702
- );
12703
- logInfo("Triggering periodic scan for new available fixes");
12704
- checkForNewAvailableFixesTool.triggerScan({
12705
- path: process.env["WORKSPACE_FOLDER_PATHS"],
12706
- gqlClient
12706
+ const isConnected = await gqlClient.verifyApiConnection();
12707
+ if (!isConnected) {
12708
+ logError("Failed to connect to the API, skipping background scan");
12709
+ return;
12710
+ }
12711
+ if (process.env["WORKSPACE_FOLDER_PATHS"]) {
12712
+ logDebug("WORKSPACE_FOLDER_PATHS is set", {
12713
+ WORKSPACE_FOLDER_PATHS: process.env["WORKSPACE_FOLDER_PATHS"]
12707
12714
  });
12708
- } catch (error) {
12709
- logError("Error getting workspace folder path tool", { error });
12715
+ try {
12716
+ const checkForNewAvailableFixesTool = this.toolRegistry.getTool(
12717
+ MCP_TOOL_CHECK_FOR_NEW_AVAILABLE_FIXES
12718
+ );
12719
+ logInfo("Triggering periodic scan for new available fixes");
12720
+ checkForNewAvailableFixesTool.triggerScan({
12721
+ path: process.env["WORKSPACE_FOLDER_PATHS"],
12722
+ gqlClient
12723
+ });
12724
+ } catch (error) {
12725
+ logError("Error getting workspace folder path tool", { error });
12726
+ }
12710
12727
  }
12728
+ } catch (error) {
12729
+ if (error instanceof Error && (error.message.includes("Authentication") || error.message.includes("failed to connect to Mobb API"))) {
12730
+ logError(
12731
+ "Background scan skipped due to authentication failure. Please re-authenticate by running a manual scan.",
12732
+ {
12733
+ error: error.message
12734
+ }
12735
+ );
12736
+ return;
12737
+ }
12738
+ logError("Unexpected error during background scan", { error });
12711
12739
  }
12712
12740
  }
12713
12741
  async handleListToolsRequest(request) {
@@ -12721,7 +12749,11 @@ var McpServer = class {
12721
12749
  logDebug("env", {
12722
12750
  env: process.env
12723
12751
  });
12724
- void this.triggerScanForNewAvailableFixes();
12752
+ if (isAutoScan) {
12753
+ void this.triggerScanForNewAvailableFixes();
12754
+ } else {
12755
+ logDebug("Auto scan disabled, skipping triggerScanForNewAvailableFixes");
12756
+ }
12725
12757
  const toolsDefinitions = this.toolRegistry.getAllTools();
12726
12758
  const response = {
12727
12759
  tools: toolsDefinitions.map((tool) => ({
@@ -12931,7 +12963,6 @@ var BaseTool = class {
12931
12963
 
12932
12964
  // src/mcp/tools/checkForNewAvailableFixes/CheckForNewAvailableFixesService.ts
12933
12965
  init_configs();
12934
- import Configstore4 from "configstore";
12935
12966
 
12936
12967
  // src/mcp/core/prompts.ts
12937
12968
  init_configs();
@@ -13550,6 +13581,18 @@ var initializeSecurityReport = async (gqlClient, scanContext) => {
13550
13581
  return repoUploadInfo;
13551
13582
  } catch (error) {
13552
13583
  const message = error.message;
13584
+ if (message.includes("Authentication hook unauthorized") || message.includes("access-denied")) {
13585
+ logError(
13586
+ "Authentication failed during security report initialization. Please re-authenticate.",
13587
+ {
13588
+ error: message
13589
+ }
13590
+ );
13591
+ throw new ReportInitializationError(
13592
+ "Authentication failed. Please re-authenticate and try again."
13593
+ );
13594
+ }
13595
+ logError("Error initializing security report", { error: message });
13553
13596
  throw new ReportInitializationError(
13554
13597
  `Error initializing security report: ${message}`
13555
13598
  );
@@ -13630,7 +13673,8 @@ var executeSecurityScan = async ({
13630
13673
  });
13631
13674
  },
13632
13675
  callbackStates: ["Finished" /* Finished */],
13633
- timeoutInMs: MCP_VUL_REPORT_DIGEST_TIMEOUT_MS
13676
+ timeoutInMs: MCP_VUL_REPORT_DIGEST_TIMEOUT_MS,
13677
+ scanContext
13634
13678
  });
13635
13679
  } catch (error) {
13636
13680
  logError(`[${scanContext}] Security analysis failed or timed out`, {
@@ -13664,6 +13708,8 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
13664
13708
  __publicField(this, "intervalId", null);
13665
13709
  __publicField(this, "isInitialScanComplete", false);
13666
13710
  __publicField(this, "gqlClient", null);
13711
+ __publicField(this, "fullScanPathsScanned", []);
13712
+ this.fullScanPathsScanned = configStore.get("fullScanPathsScanned") || [];
13667
13713
  }
13668
13714
  static getInstance() {
13669
13715
  if (!_CheckForNewAvailableFixesService.instance) {
@@ -13679,6 +13725,7 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
13679
13725
  this.filesLastScanned = {};
13680
13726
  this.freshFixes = [];
13681
13727
  this.reportedFixes = [];
13728
+ this.fullScanPathsScanned = configStore.get("fullScanPathsScanned") || [];
13682
13729
  if (this.intervalId) {
13683
13730
  clearInterval(this.intervalId);
13684
13731
  this.intervalId = null;
@@ -13699,61 +13746,84 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
13699
13746
  });
13700
13747
  if (!this.gqlClient) {
13701
13748
  logInfo(`[${scanContext}] No GQL client found, skipping scan`);
13702
- return;
13703
- }
13704
- const isConnected = await this.gqlClient.verifyApiConnection();
13705
- if (!isConnected) {
13706
- logError(`[${scanContext}] Failed to connect to the API, scan aborted`);
13707
- return;
13749
+ throw new Error("No GQL client found");
13708
13750
  }
13709
- logDebug(
13710
- `[${scanContext}] Connected to the API, assembling list of files to scan`,
13711
- { path: path13 }
13712
- );
13713
- const files = await getLocalFiles({
13714
- path: path13,
13715
- isAllFilesScan
13716
- });
13717
- logDebug(`[${scanContext}] Active files`, { files });
13718
- const filesToScan = files.filter((file) => {
13719
- const lastScannedEditTime = this.filesLastScanned[file.fullPath];
13720
- if (!lastScannedEditTime) {
13721
- return true;
13751
+ try {
13752
+ const isConnected = await this.gqlClient.verifyApiConnection();
13753
+ if (!isConnected) {
13754
+ logError(`[${scanContext}] Failed to connect to the API, scan aborted`);
13755
+ throw new ApiConnectionError();
13722
13756
  }
13723
- return file.lastEdited > lastScannedEditTime;
13724
- });
13725
- if (filesToScan.length === 0) {
13726
- logInfo(`[${scanContext}] No files require scanning`);
13727
- return;
13728
- }
13729
- logDebug(`[${scanContext}] Files requiring security scan`, { filesToScan });
13730
- const { fixReportId, projectId } = await scanFiles({
13731
- fileList: filesToScan.map((file) => file.relativePath),
13732
- repositoryPath: path13,
13733
- gqlClient: this.gqlClient,
13734
- isAllDetectionRulesScan,
13735
- scanContext
13736
- });
13737
- logInfo(
13738
- `[${scanContext}] Security scan completed for ${path13} reportId: ${fixReportId} projectId: ${projectId}`
13739
- );
13740
- if (isAllFilesScan) {
13741
- return;
13757
+ logDebug(
13758
+ `[${scanContext}] Connected to the API, assembling list of files to scan`,
13759
+ { path: path13 }
13760
+ );
13761
+ const files = await getLocalFiles({
13762
+ path: path13,
13763
+ isAllFilesScan
13764
+ });
13765
+ logDebug(`[${scanContext}] Active files`, { files });
13766
+ const filesToScan = files.filter((file) => {
13767
+ const lastScannedEditTime = this.filesLastScanned[file.fullPath];
13768
+ if (!lastScannedEditTime) {
13769
+ return true;
13770
+ }
13771
+ return file.lastEdited > lastScannedEditTime;
13772
+ });
13773
+ if (filesToScan.length === 0) {
13774
+ logInfo(`[${scanContext}] No files require scanning`);
13775
+ return;
13776
+ }
13777
+ logDebug(`[${scanContext}] Files requiring security scan`, {
13778
+ filesToScan
13779
+ });
13780
+ const { fixReportId, projectId } = await scanFiles({
13781
+ fileList: filesToScan.map((file) => file.relativePath),
13782
+ repositoryPath: path13,
13783
+ gqlClient: this.gqlClient,
13784
+ isAllDetectionRulesScan,
13785
+ scanContext
13786
+ });
13787
+ logInfo(
13788
+ `[${scanContext}] Security scan completed for ${path13} reportId: ${fixReportId} projectId: ${projectId}`
13789
+ );
13790
+ if (isAllFilesScan) {
13791
+ return;
13792
+ }
13793
+ const fixes = await this.gqlClient.getReportFixesPaginated({
13794
+ reportId: fixReportId,
13795
+ offset: 0,
13796
+ limit: 1e3
13797
+ });
13798
+ const newFixes = fixes?.fixes?.filter(
13799
+ (fix) => !this.isFixAlreadyReported(fix)
13800
+ );
13801
+ logInfo(
13802
+ `[${scanContext}] Security fixes retrieved, total: ${fixes?.fixes?.length || 0}, new: ${newFixes?.length || 0}`
13803
+ );
13804
+ this.updateFreshFixesCache(newFixes || [], filesToScan);
13805
+ this.updateFilesScanTimestamps(filesToScan);
13806
+ this.isInitialScanComplete = true;
13807
+ } catch (error) {
13808
+ const errorMessage = error.message;
13809
+ if (errorMessage.includes("Authentication failed") || errorMessage.includes("access-denied") || errorMessage.includes("Authentication hook unauthorized")) {
13810
+ logError(
13811
+ "Periodic scan skipped due to authentication failure. Please re-authenticate by running a manual scan.",
13812
+ {
13813
+ error: errorMessage
13814
+ }
13815
+ );
13816
+ return;
13817
+ }
13818
+ if (errorMessage.includes("ReportInitializationError")) {
13819
+ logError("Periodic scan failed during report initialization", {
13820
+ error: errorMessage
13821
+ });
13822
+ return;
13823
+ }
13824
+ logError("Unexpected error during periodic security scan", { error });
13825
+ throw error;
13742
13826
  }
13743
- const fixes = await this.gqlClient.getReportFixesPaginated({
13744
- reportId: fixReportId,
13745
- offset: 0,
13746
- limit: 1e3
13747
- });
13748
- const newFixes = fixes?.fixes?.filter(
13749
- (fix) => !this.isFixAlreadyReported(fix)
13750
- );
13751
- logInfo(
13752
- `[${scanContext}] Security fixes retrieved, total: ${fixes?.fixes?.length || 0}, new: ${newFixes?.length || 0}`
13753
- );
13754
- this.updateFreshFixesCache(newFixes || [], filesToScan);
13755
- this.updateFilesScanTimestamps(filesToScan);
13756
- this.isInitialScanComplete = true;
13757
13827
  }
13758
13828
  updateFreshFixesCache(newFixes, filesToScan) {
13759
13829
  this.freshFixes = this.freshFixes.filter((fix) => !this.isFixFromOldScan(fix, filesToScan)).concat(newFixes).sort((a, b) => {
@@ -13807,7 +13877,7 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
13807
13877
  if (!this.intervalId) {
13808
13878
  this.startPeriodicScanning(path13);
13809
13879
  this.executeInitialScan(path13);
13810
- this.executeInitialFullScan(path13);
13880
+ void this.executeInitialFullScan(path13);
13811
13881
  }
13812
13882
  }
13813
13883
  startPeriodicScanning(path13) {
@@ -13824,37 +13894,46 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
13824
13894
  });
13825
13895
  }, MCP_PERIODIC_CHECK_INTERVAL);
13826
13896
  }
13827
- executeInitialFullScan(path13) {
13828
- logDebug("Triggering initial full security scan", { path: path13 });
13829
- const mobbConfigStore2 = new Configstore4(packageJson.name, { apiToken: "" });
13830
- const fullScanPathsScanned = mobbConfigStore2.get("fullScanPathsScanned") || [];
13831
- logDebug("Full scan paths scanned", { fullScanPathsScanned });
13832
- if (fullScanPathsScanned.includes(path13)) {
13833
- logDebug("Full scan already executed for this path", { path: path13 });
13897
+ async executeInitialFullScan(path13) {
13898
+ const scanContext = "FULL_SCAN";
13899
+ logDebug(`[${scanContext}] Triggering initial full security scan`, { path: path13 });
13900
+ logDebug(`[${scanContext}] Full scan paths scanned`, {
13901
+ fullScanPathsScanned: this.fullScanPathsScanned
13902
+ });
13903
+ if (this.fullScanPathsScanned.includes(path13)) {
13904
+ logDebug(`[${scanContext}] Full scan already executed for this path`, {
13905
+ path: path13
13906
+ });
13834
13907
  return;
13835
13908
  }
13836
- mobbConfigStore2.set("fullScanPathsScanned", [...fullScanPathsScanned, path13]);
13837
- this.scanForSecurityVulnerabilities({
13838
- path: path13,
13839
- isAllFilesScan: true,
13840
- isAllDetectionRulesScan: true,
13841
- scanContext: "FULL_SCAN"
13842
- }).catch((error) => {
13909
+ configStore.set("fullScanPathsScanned", [
13910
+ ...this.fullScanPathsScanned,
13911
+ path13
13912
+ ]);
13913
+ try {
13914
+ await this.scanForSecurityVulnerabilities({
13915
+ path: path13,
13916
+ isAllFilesScan: true,
13917
+ isAllDetectionRulesScan: true,
13918
+ scanContext: "FULL_SCAN"
13919
+ });
13920
+ if (!this.fullScanPathsScanned.includes(path13)) {
13921
+ this.fullScanPathsScanned.push(path13);
13922
+ configStore.set("fullScanPathsScanned", this.fullScanPathsScanned);
13923
+ }
13924
+ logInfo(`[${scanContext}] Full scan completed`, { path: path13 });
13925
+ } catch (error) {
13843
13926
  logError("Error during initial full security scan", { error });
13844
- }).then(() => {
13845
- const fullScanPathsScanned2 = mobbConfigStore2.get("fullScanPathsScanned") || [];
13846
- fullScanPathsScanned2.push(path13);
13847
- mobbConfigStore2.set("fullScanPathsScanned", fullScanPathsScanned2);
13848
- logDebug("Full scan completed", { path: path13 });
13849
- });
13927
+ }
13850
13928
  }
13851
13929
  executeInitialScan(path13) {
13852
- logDebug("Triggering initial security scan", { path: path13 });
13930
+ const scanContext = "BACKGROUND_INITIAL";
13931
+ logDebug(`[${scanContext}] Triggering initial security scan`, { path: path13 });
13853
13932
  this.scanForSecurityVulnerabilities({
13854
13933
  path: path13,
13855
13934
  scanContext: "BACKGROUND_INITIAL"
13856
13935
  }).catch((error) => {
13857
- logError("Error during initial security scan", { error });
13936
+ logError(`[${scanContext}] Error during initial security scan`, { error });
13858
13937
  });
13859
13938
  }
13860
13939
  generateFreshFixesResponse() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mobbdev",
3
- "version": "1.0.122",
3
+ "version": "1.0.126",
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",
@@ -11,13 +11,14 @@
11
11
  "postinstall": "node ./src/post_install/cx_install.mjs",
12
12
  "build": "tsc && tsup-node --env.NODE_ENV production",
13
13
  "build:dev": "tsup-node --env.NODE_ENV development",
14
+ "increment-version": "./src/scripts/increment-version.sh",
14
15
  "test:mcp": "pnpm run build && vitest run __tests__/mcp/",
15
16
  "test:mcp:watch": "vitest watch __tests__/mcp/",
16
17
  "test:mcp:verbose": "pnpm run build && NODE_ENV=test VERBOSE=true vitest run __tests__/mcp/",
17
- "test:mcp:integration": "pnpm run build && GIT_PROXY_HOST=http://tinyproxy:8888 API_URL=http://app-api:8080/v1/graphql TOKEN=$(../../scripts/login_auth0.sh) vitest run __tests__/integration.test.ts -t 'mcp|MCP'",
18
+ "test:mcp:integration": "pnpm run build && GIT_PROXY_HOST=http://tinyproxy:8888 API_URL=http://app-api:8080/v1/graphql TOKEN=$(../../scripts/login_auth0.sh) vitest run --sequence.concurrent=false false __tests__/integration.test.ts -t 'mcp|MCP'",
18
19
  "test:mcp:all": "pnpm run test:mcp && pnpm run test:mcp:integration && cd ./__e2e__ && npm i && npm run test:mcp",
19
20
  "test:unit": "GIT_PROXY_HOST=http://tinyproxy:8888 TOKEN=$(../../scripts/login_auth0.sh) vitest run --exclude='**/__tests__/integration.test.ts' --exclude='**/__tests__/mcp/**'",
20
- "test:integration": "GIT_PROXY_HOST=http://tinyproxy:8888 TOKEN=$(../../scripts/login_auth0.sh) vitest run __tests__/integration.test.ts",
21
+ "test:integration": "GIT_PROXY_HOST=http://tinyproxy:8888 TOKEN=$(../../scripts/login_auth0.sh) vitest run --sequence.concurrent=false false __tests__/integration.test.ts",
21
22
  "test:integration:watch": "GIT_PROXY_HOST=http://tinyproxy:8888 TOKEN=$(../../scripts/login_auth0.sh) vitest watch run __tests__/integration.test.ts",
22
23
  "test": "pnpm run test:unit && pnpm run test:mcp && pnpm run test:integration",
23
24
  "test:ado": "GIT_PROXY_HOST=http://tinyproxy:8888 TOKEN=$(../../scripts/login_auth0.sh) vitest run ado.test",
@@ -27,7 +28,7 @@
27
28
  "test:cli:main": "GIT_PROXY_HOST=http://tinyproxy:8888 TOKEN=$(../../scripts/login_auth0.sh) vitest run cli-main.test",
28
29
  "test:coverage": "GIT_PROXY_HOST=http://tinyproxy:8888 TOKEN=$(../../scripts/login_auth0.sh) vitest run --coverage",
29
30
  "test:watch": "TOKEN=$(../../scripts/login_auth0.sh) vitest",
30
- "test:integration:proxy": "GIT_PROXY_HOST=http://tinyproxy:8888 HTTP_PROXY=http://localhost:8888 API_URL=http://app-api:8080/v1/graphql TOKEN=$(../../scripts/login_auth0.sh) vitest run integration.test.ts",
31
+ "test:integration:proxy": "GIT_PROXY_HOST=http://tinyproxy:8888 HTTP_PROXY=http://localhost:8888 API_URL=http://app-api:8080/v1/graphql TOKEN=$(../../scripts/login_auth0.sh) vitest run --sequence.concurrent=false false integration.test.ts",
31
32
  "lint": "eslint --cache --max-warnings 0 --ignore-path .eslintignore --ext .ts,.tsx,.jsx,.graphql .",
32
33
  "lint:fix": "eslint --fix --cache --max-warnings 0 --ignore-path .eslintignore --ext .js,.ts,.tsx,.jsx,.graphql . && prettier --write \"src/**/*.graphql\"",
33
34
  "lint:fix:files": "eslint --fix --cache --max-warnings 0 --ignore-path .eslintignore --ext .js,.ts,.tsx,.jsx,.graphql",