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.
- package/dist/index.mjs +325 -246
- 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/
|
|
2967
|
+
// src/features/analysis/scm/shared/src/storedFixData/dockerfile/index.ts
|
|
2956
2968
|
var vulnerabilities2 = {};
|
|
2957
|
-
var
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
3055
|
+
var javascript_default = vulnerabilities5;
|
|
3040
3056
|
|
|
3041
3057
|
// src/features/analysis/scm/shared/src/storedFixData/php/index.ts
|
|
3042
|
-
var
|
|
3043
|
-
var php_default =
|
|
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
|
|
3081
|
+
var vulnerabilities7 = {
|
|
3066
3082
|
["AUTO_ESCAPE_FALSE" /* AutoEscapeFalse */]: autoEscapeFalse,
|
|
3067
3083
|
["CSRF" /* Csrf */]: csrf
|
|
3068
3084
|
};
|
|
3069
|
-
var python_default =
|
|
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
|
|
3093
|
+
var vulnerabilities8 = {
|
|
3078
3094
|
["DEFAULT_RIGHTS_IN_OBJ_DEFINITION" /* DefaultRightsInObjDefinition */]: defaultRightsInObjDefinition
|
|
3079
3095
|
};
|
|
3080
|
-
var sql_default =
|
|
3096
|
+
var sql_default = vulnerabilities8;
|
|
3081
3097
|
|
|
3082
3098
|
// src/features/analysis/scm/shared/src/storedFixData/xml/index.ts
|
|
3083
|
-
var
|
|
3099
|
+
var vulnerabilities9 = {
|
|
3084
3100
|
["PASSWORD_IN_COMMENT" /* PasswordInComment */]: passwordInComment
|
|
3085
3101
|
};
|
|
3086
|
-
var xml_default =
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
4344
|
+
var vulnerabilities15 = {
|
|
4328
4345
|
["WEAK_XML_SCHEMA_UNBOUNDED_OCCURRENCES" /* WeakXmlSchemaUnboundedOccurrences */]: unboundedOccurrences
|
|
4329
4346
|
};
|
|
4330
|
-
var xml_default2 =
|
|
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
|
-
|
|
11941
|
-
var
|
|
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, "
|
|
11948
|
-
__publicField(this, "
|
|
11949
|
-
|
|
11950
|
-
|
|
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
|
|
11998
|
-
message
|
|
11999
|
-
data
|
|
12000
|
-
version: packageJson.version
|
|
11976
|
+
level,
|
|
11977
|
+
message,
|
|
11978
|
+
data
|
|
12001
11979
|
};
|
|
12002
|
-
const
|
|
12003
|
-
|
|
12004
|
-
|
|
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
|
-
|
|
12142
|
-
logDebug(
|
|
12143
|
-
this.client = new GraphQLClient2(
|
|
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:
|
|
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
|
|
12140
|
+
async isApiEndpointReachable() {
|
|
12171
12141
|
try {
|
|
12172
12142
|
logDebug("GraphQL: Calling Me query for API connection verification");
|
|
12173
|
-
const result = await this.
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
12263
|
-
|
|
12264
|
-
|
|
12265
|
-
|
|
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(
|
|
12275
|
+
logDebug(`[${scanContext}] GraphQL: GetAnalysis subscription completed`, {
|
|
12276
|
+
result
|
|
12277
|
+
});
|
|
12282
12278
|
return result;
|
|
12283
12279
|
} catch (e) {
|
|
12284
|
-
logError(
|
|
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:
|
|
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
|
-
|
|
12545
|
+
configStore.get("apiToken") || "",
|
|
12546
12546
|
type: "apiKey"
|
|
12547
12547
|
});
|
|
12548
|
-
const
|
|
12549
|
-
logDebug("API connection status", {
|
|
12550
|
-
if (!
|
|
12551
|
-
throw new ApiConnectionError("Error: failed to
|
|
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
|
-
|
|
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
|
-
|
|
12688
|
-
|
|
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
|
-
|
|
12700
|
-
|
|
12701
|
-
|
|
12702
|
-
|
|
12703
|
-
|
|
12704
|
-
|
|
12705
|
-
|
|
12706
|
-
|
|
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
|
-
|
|
12709
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
13710
|
-
|
|
13711
|
-
|
|
13712
|
-
|
|
13713
|
-
|
|
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
|
-
|
|
13724
|
-
|
|
13725
|
-
|
|
13726
|
-
|
|
13727
|
-
|
|
13728
|
-
|
|
13729
|
-
|
|
13730
|
-
|
|
13731
|
-
|
|
13732
|
-
|
|
13733
|
-
|
|
13734
|
-
|
|
13735
|
-
|
|
13736
|
-
|
|
13737
|
-
|
|
13738
|
-
|
|
13739
|
-
|
|
13740
|
-
|
|
13741
|
-
|
|
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
|
-
|
|
13829
|
-
|
|
13830
|
-
|
|
13831
|
-
|
|
13832
|
-
|
|
13833
|
-
|
|
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
|
-
|
|
13837
|
-
|
|
13838
|
-
|
|
13839
|
-
|
|
13840
|
-
|
|
13841
|
-
|
|
13842
|
-
|
|
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
|
-
}
|
|
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
|
-
|
|
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(
|
|
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.
|
|
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",
|