mobbdev 1.0.125 → 1.0.127
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 +283 -218
- 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
|
|
|
@@ -2259,14 +2260,14 @@ var GetReportFixesDocument = `
|
|
|
2259
2260
|
var GetLatestReportByRepoUrlDocument = `
|
|
2260
2261
|
query GetLatestReportByRepoUrl($repoUrl: String!, $filters: fix_bool_exp = {}, $limit: Int!, $offset: Int!, $currentUserEmail: String!) {
|
|
2261
2262
|
fixReport(
|
|
2262
|
-
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]}}]}}]}
|
|
2263
2264
|
order_by: {createdOn: desc}
|
|
2264
2265
|
limit: 1
|
|
2265
2266
|
) {
|
|
2266
2267
|
...FixReportSummaryFields
|
|
2267
2268
|
}
|
|
2268
2269
|
expiredReport: fixReport(
|
|
2269
|
-
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]}}}]}]}
|
|
2270
2271
|
order_by: {createdOn: desc}
|
|
2271
2272
|
limit: 1
|
|
2272
2273
|
) {
|
|
@@ -11635,6 +11636,7 @@ async function analyze({
|
|
|
11635
11636
|
mobbProjectName,
|
|
11636
11637
|
organizationId,
|
|
11637
11638
|
autoPr,
|
|
11639
|
+
createOnePr,
|
|
11638
11640
|
commitDirectly,
|
|
11639
11641
|
pullRequest
|
|
11640
11642
|
}, { skipPrompts = false } = {}) {
|
|
@@ -11653,7 +11655,8 @@ async function analyze({
|
|
|
11653
11655
|
command: "analyze",
|
|
11654
11656
|
autoPr,
|
|
11655
11657
|
commitDirectly,
|
|
11656
|
-
pullRequest
|
|
11658
|
+
pullRequest,
|
|
11659
|
+
createOnePr
|
|
11657
11660
|
},
|
|
11658
11661
|
{ skipPrompts }
|
|
11659
11662
|
);
|
|
@@ -11953,104 +11956,34 @@ import {
|
|
|
11953
11956
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
11954
11957
|
|
|
11955
11958
|
// src/mcp/Logger.ts
|
|
11956
|
-
|
|
11957
|
-
var
|
|
11958
|
-
var CIRCUIT_BREAKER_TIME = 5e3;
|
|
11959
|
-
var URL_CHECK_TIMEOUT = 200;
|
|
11960
|
-
var MAX_QUEUE_SIZE = 100;
|
|
11959
|
+
import Configstore3 from "configstore";
|
|
11960
|
+
var MAX_LOGS_SIZE = 1e3;
|
|
11961
11961
|
var Logger = class {
|
|
11962
11962
|
constructor() {
|
|
11963
|
-
__publicField(this, "
|
|
11964
|
-
__publicField(this, "
|
|
11965
|
-
|
|
11966
|
-
|
|
11963
|
+
__publicField(this, "mobbConfigStore");
|
|
11964
|
+
__publicField(this, "path");
|
|
11965
|
+
this.path = process.env["WORKSPACE_FOLDER_PATHS"] || "unknown";
|
|
11966
|
+
this.mobbConfigStore = new Configstore3("mobb-logs", {});
|
|
11967
|
+
this.mobbConfigStore.set("version", packageJson.version);
|
|
11967
11968
|
}
|
|
11969
|
+
/**
|
|
11970
|
+
* Log a message to the console.
|
|
11971
|
+
* @param message - The message to log.
|
|
11972
|
+
* @param level - The level of the message.
|
|
11973
|
+
* @param data - The data to log.
|
|
11974
|
+
*/
|
|
11968
11975
|
log(message, level = "info", data) {
|
|
11969
|
-
if (isTestEnvironment) return;
|
|
11970
|
-
if (this.queue.length >= MAX_QUEUE_SIZE) {
|
|
11971
|
-
this.queue.shift();
|
|
11972
|
-
}
|
|
11973
|
-
this.queue.push({ message, level, data });
|
|
11974
|
-
if (!this.isProcessing && !this.isCircuitBroken) {
|
|
11975
|
-
this.processQueue();
|
|
11976
|
-
}
|
|
11977
|
-
}
|
|
11978
|
-
async isUrlReachable(url) {
|
|
11979
|
-
try {
|
|
11980
|
-
const controller = new AbortController();
|
|
11981
|
-
const timeoutId = setTimeout(() => controller.abort(), URL_CHECK_TIMEOUT);
|
|
11982
|
-
await fetch(url, {
|
|
11983
|
-
method: "HEAD",
|
|
11984
|
-
signal: controller.signal
|
|
11985
|
-
});
|
|
11986
|
-
clearTimeout(timeoutId);
|
|
11987
|
-
return true;
|
|
11988
|
-
} catch (error) {
|
|
11989
|
-
return false;
|
|
11990
|
-
}
|
|
11991
|
-
}
|
|
11992
|
-
async processQueue() {
|
|
11993
|
-
if (this.queue.length === 0 || this.isCircuitBroken) {
|
|
11994
|
-
this.isProcessing = false;
|
|
11995
|
-
return;
|
|
11996
|
-
}
|
|
11997
|
-
this.isProcessing = true;
|
|
11998
|
-
const logEntry = this.queue[0];
|
|
11999
|
-
if (!logEntry) {
|
|
12000
|
-
this.isProcessing = false;
|
|
12001
|
-
return;
|
|
12002
|
-
}
|
|
12003
|
-
const isReachable = await this.isUrlReachable(loggerUrl);
|
|
12004
|
-
if (!isReachable) {
|
|
12005
|
-
this.triggerCircuitBreaker();
|
|
12006
|
-
return;
|
|
12007
|
-
}
|
|
12008
|
-
await this.sendLogEntry(logEntry);
|
|
12009
|
-
}
|
|
12010
|
-
async sendLogEntry(logEntry) {
|
|
12011
11976
|
const logMessage = {
|
|
12012
11977
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
12013
|
-
level
|
|
12014
|
-
message
|
|
12015
|
-
data
|
|
12016
|
-
version: packageJson.version
|
|
11978
|
+
level,
|
|
11979
|
+
message,
|
|
11980
|
+
data
|
|
12017
11981
|
};
|
|
12018
|
-
const
|
|
12019
|
-
|
|
12020
|
-
|
|
12021
|
-
}, 500);
|
|
12022
|
-
try {
|
|
12023
|
-
await fetch(loggerUrl, {
|
|
12024
|
-
method: "POST",
|
|
12025
|
-
headers: { "Content-Type": "application/json" },
|
|
12026
|
-
body: JSON.stringify(logMessage),
|
|
12027
|
-
redirect: "error",
|
|
12028
|
-
// do not follow redirects
|
|
12029
|
-
signal: controller.signal
|
|
12030
|
-
});
|
|
12031
|
-
this.queue.shift();
|
|
12032
|
-
setTimeout(() => this.processQueue(), 0);
|
|
12033
|
-
} catch (error) {
|
|
12034
|
-
this.triggerCircuitBreaker();
|
|
12035
|
-
logError("Failed to send log entry", error);
|
|
12036
|
-
} finally {
|
|
12037
|
-
clearTimeout(timeoutId);
|
|
11982
|
+
const logs = this.mobbConfigStore.get(this.path) || [];
|
|
11983
|
+
if (logs.length >= MAX_LOGS_SIZE) {
|
|
11984
|
+
logs.shift();
|
|
12038
11985
|
}
|
|
12039
|
-
|
|
12040
|
-
triggerCircuitBreaker() {
|
|
12041
|
-
this.isCircuitBroken = true;
|
|
12042
|
-
this.queue = [];
|
|
12043
|
-
this.isProcessing = false;
|
|
12044
|
-
if (this.circuitBreakerTimer) {
|
|
12045
|
-
clearTimeout(this.circuitBreakerTimer);
|
|
12046
|
-
}
|
|
12047
|
-
this.circuitBreakerTimer = setTimeout(() => {
|
|
12048
|
-
this.isCircuitBroken = false;
|
|
12049
|
-
this.circuitBreakerTimer = null;
|
|
12050
|
-
if (this.queue.length > 0 && !this.isProcessing) {
|
|
12051
|
-
this.processQueue();
|
|
12052
|
-
}
|
|
12053
|
-
}, CIRCUIT_BREAKER_TIME);
|
|
11986
|
+
this.mobbConfigStore.set(this.path, [...logs, logMessage]);
|
|
12054
11987
|
}
|
|
12055
11988
|
};
|
|
12056
11989
|
var logger = new Logger();
|
|
@@ -12061,12 +11994,34 @@ var logDebug = (message, data) => logger.log(message, "debug", data);
|
|
|
12061
11994
|
var log = logger.log.bind(logger);
|
|
12062
11995
|
|
|
12063
11996
|
// src/mcp/services/McpGQLClient.ts
|
|
12064
|
-
import Configstore3 from "configstore";
|
|
12065
11997
|
import crypto3 from "crypto";
|
|
12066
11998
|
import { GraphQLClient as GraphQLClient2 } from "graphql-request";
|
|
12067
11999
|
import { v4 as uuidv42 } from "uuid";
|
|
12068
12000
|
init_configs();
|
|
12069
12001
|
|
|
12002
|
+
// src/mcp/services/ConfigStoreService.ts
|
|
12003
|
+
init_configs();
|
|
12004
|
+
import Configstore4 from "configstore";
|
|
12005
|
+
function createConfigStore(defaultValues = { apiToken: "" }) {
|
|
12006
|
+
const API_URL2 = process.env["API_URL"] || MCP_DEFAULT_API_URL;
|
|
12007
|
+
let domain = "";
|
|
12008
|
+
try {
|
|
12009
|
+
const url = new URL(API_URL2);
|
|
12010
|
+
domain = url.hostname;
|
|
12011
|
+
} catch (e) {
|
|
12012
|
+
domain = API_URL2.replace(/^https?:\/\//, "").replace(/\/.*$/, "").replace(/:\d+$/, "");
|
|
12013
|
+
}
|
|
12014
|
+
const sanitizedDomain = domain.replace(/\./g, "_");
|
|
12015
|
+
return new Configstore4(
|
|
12016
|
+
`${packageJson.name}-${sanitizedDomain}`,
|
|
12017
|
+
defaultValues
|
|
12018
|
+
);
|
|
12019
|
+
}
|
|
12020
|
+
function getConfigStore() {
|
|
12021
|
+
return createConfigStore();
|
|
12022
|
+
}
|
|
12023
|
+
var configStore = getConfigStore();
|
|
12024
|
+
|
|
12070
12025
|
// src/mcp/services/McpAuthService.ts
|
|
12071
12026
|
import crypto2 from "crypto";
|
|
12072
12027
|
import os2 from "os";
|
|
@@ -12147,16 +12102,17 @@ var McpAuthService = class {
|
|
|
12147
12102
|
};
|
|
12148
12103
|
|
|
12149
12104
|
// src/mcp/services/McpGQLClient.ts
|
|
12150
|
-
var mobbConfigStore = new Configstore3(packageJson.name, { apiToken: "" });
|
|
12151
12105
|
var McpGQLClient = class {
|
|
12152
12106
|
constructor(args) {
|
|
12153
12107
|
__publicField(this, "client");
|
|
12154
12108
|
__publicField(this, "clientSdk");
|
|
12155
12109
|
__publicField(this, "_auth");
|
|
12110
|
+
__publicField(this, "currentUser", null);
|
|
12111
|
+
__publicField(this, "apiUrl");
|
|
12156
12112
|
this._auth = args;
|
|
12157
|
-
|
|
12158
|
-
logDebug(
|
|
12159
|
-
this.client = new GraphQLClient2(
|
|
12113
|
+
this.apiUrl = process.env["API_URL"] || MCP_DEFAULT_API_URL;
|
|
12114
|
+
logDebug(`creating graphql client with api url ${this.apiUrl}`, { args });
|
|
12115
|
+
this.client = new GraphQLClient2(this.apiUrl, {
|
|
12160
12116
|
headers: args.type === "apiKey" ? { [MCP_API_KEY_HEADER_NAME]: args.apiKey || "" } : {
|
|
12161
12117
|
Authorization: `Bearer ${args.token}`
|
|
12162
12118
|
},
|
|
@@ -12175,7 +12131,7 @@ var McpGQLClient = class {
|
|
|
12175
12131
|
}
|
|
12176
12132
|
getErrorContext() {
|
|
12177
12133
|
return {
|
|
12178
|
-
endpoint:
|
|
12134
|
+
endpoint: this.apiUrl,
|
|
12179
12135
|
apiKey: this._auth.type === "apiKey" ? this._auth.apiKey : "",
|
|
12180
12136
|
headers: {
|
|
12181
12137
|
[MCP_API_KEY_HEADER_NAME]: this._auth.type === "apiKey" ? "[REDACTED]" : "undefined",
|
|
@@ -12183,10 +12139,10 @@ var McpGQLClient = class {
|
|
|
12183
12139
|
}
|
|
12184
12140
|
};
|
|
12185
12141
|
}
|
|
12186
|
-
async
|
|
12142
|
+
async isApiEndpointReachable() {
|
|
12187
12143
|
try {
|
|
12188
12144
|
logDebug("GraphQL: Calling Me query for API connection verification");
|
|
12189
|
-
const result = await this.
|
|
12145
|
+
const result = await this.getUserInfo();
|
|
12190
12146
|
logDebug("GraphQL: Me query successful", { result });
|
|
12191
12147
|
return true;
|
|
12192
12148
|
} catch (e) {
|
|
@@ -12199,6 +12155,23 @@ var McpGQLClient = class {
|
|
|
12199
12155
|
}
|
|
12200
12156
|
return true;
|
|
12201
12157
|
}
|
|
12158
|
+
/**
|
|
12159
|
+
* Verifies both API endpoint reachability and user authentication
|
|
12160
|
+
* @returns true if both API is reachable and user is authenticated
|
|
12161
|
+
*/
|
|
12162
|
+
async verifyApiConnection() {
|
|
12163
|
+
const isReachable = await this.isApiEndpointReachable();
|
|
12164
|
+
if (!isReachable) {
|
|
12165
|
+
return false;
|
|
12166
|
+
}
|
|
12167
|
+
try {
|
|
12168
|
+
await this.validateUserToken();
|
|
12169
|
+
return true;
|
|
12170
|
+
} catch (e) {
|
|
12171
|
+
logError("User token validation failed", { error: e });
|
|
12172
|
+
return false;
|
|
12173
|
+
}
|
|
12174
|
+
}
|
|
12202
12175
|
async uploadS3BucketInfo() {
|
|
12203
12176
|
try {
|
|
12204
12177
|
logDebug("GraphQL: Calling uploadS3BucketInfo mutation");
|
|
@@ -12253,8 +12226,9 @@ var McpGQLClient = class {
|
|
|
12253
12226
|
}
|
|
12254
12227
|
}
|
|
12255
12228
|
async subscribeToGetAnalysis(params) {
|
|
12229
|
+
const { scanContext } = params;
|
|
12256
12230
|
try {
|
|
12257
|
-
logDebug(
|
|
12231
|
+
logDebug(`[${scanContext}] GraphQL: Starting GetAnalysis subscription`, {
|
|
12258
12232
|
params: params.subscribeToAnalysisParams
|
|
12259
12233
|
});
|
|
12260
12234
|
const { callbackStates } = params;
|
|
@@ -12262,10 +12236,13 @@ var McpGQLClient = class {
|
|
|
12262
12236
|
GetAnalysisSubscriptionDocument,
|
|
12263
12237
|
params.subscribeToAnalysisParams,
|
|
12264
12238
|
async (resolve, reject, data) => {
|
|
12265
|
-
logDebug(
|
|
12239
|
+
logDebug(
|
|
12240
|
+
`[${scanContext}] GraphQL: GetAnalysis subscription data received ${data.analysis?.state}`,
|
|
12241
|
+
{ data }
|
|
12242
|
+
);
|
|
12266
12243
|
if (!data.analysis?.state || data.analysis?.state === "Failed" /* Failed */) {
|
|
12267
12244
|
const errorMessage = data.analysis?.failReason || `Analysis failed with id: ${data.analysis?.id}`;
|
|
12268
|
-
logError(
|
|
12245
|
+
logError(`[${scanContext}] GraphQL: Analysis failed`, {
|
|
12269
12246
|
analysisId: data.analysis?.id,
|
|
12270
12247
|
state: data.analysis?.state,
|
|
12271
12248
|
failReason: data.analysis?.failReason,
|
|
@@ -12275,11 +12252,14 @@ var McpGQLClient = class {
|
|
|
12275
12252
|
return;
|
|
12276
12253
|
}
|
|
12277
12254
|
if (callbackStates.includes(data.analysis?.state)) {
|
|
12278
|
-
logDebug(
|
|
12279
|
-
|
|
12280
|
-
|
|
12281
|
-
|
|
12282
|
-
|
|
12255
|
+
logDebug(
|
|
12256
|
+
`[${scanContext}] GraphQL: Analysis state matches callback states: ${data.analysis.state}`,
|
|
12257
|
+
{
|
|
12258
|
+
analysisId: data.analysis.id,
|
|
12259
|
+
state: data.analysis.state,
|
|
12260
|
+
callbackStates
|
|
12261
|
+
}
|
|
12262
|
+
);
|
|
12283
12263
|
await params.callback(data.analysis.id);
|
|
12284
12264
|
resolve(data);
|
|
12285
12265
|
}
|
|
@@ -12294,10 +12274,12 @@ var McpGQLClient = class {
|
|
|
12294
12274
|
timeoutInMs: params.timeoutInMs
|
|
12295
12275
|
}
|
|
12296
12276
|
);
|
|
12297
|
-
logDebug(
|
|
12277
|
+
logDebug(`[${scanContext}] GraphQL: GetAnalysis subscription completed`, {
|
|
12278
|
+
result
|
|
12279
|
+
});
|
|
12298
12280
|
return result;
|
|
12299
12281
|
} catch (e) {
|
|
12300
|
-
logError(
|
|
12282
|
+
logError(`[${scanContext}] GraphQL: GetAnalysis subscription failed`, {
|
|
12301
12283
|
error: e,
|
|
12302
12284
|
params: params.subscribeToAnalysisParams,
|
|
12303
12285
|
...this.getErrorContext()
|
|
@@ -12361,8 +12343,12 @@ var McpGQLClient = class {
|
|
|
12361
12343
|
}
|
|
12362
12344
|
async getUserInfo() {
|
|
12363
12345
|
const { me } = await this.clientSdk.Me();
|
|
12346
|
+
this.currentUser = me;
|
|
12364
12347
|
return me;
|
|
12365
12348
|
}
|
|
12349
|
+
getCurrentUser() {
|
|
12350
|
+
return this.currentUser;
|
|
12351
|
+
}
|
|
12366
12352
|
async validateUserToken() {
|
|
12367
12353
|
logDebug("validating user token");
|
|
12368
12354
|
try {
|
|
@@ -12555,16 +12541,16 @@ var McpGQLClient = class {
|
|
|
12555
12541
|
async function createAuthenticatedMcpGQLClient({
|
|
12556
12542
|
isBackgoundCall = false
|
|
12557
12543
|
} = {}) {
|
|
12558
|
-
logDebug("getting config", { apiToken:
|
|
12544
|
+
logDebug("getting config", { apiToken: configStore.get("apiToken") });
|
|
12559
12545
|
const initialClient = new McpGQLClient({
|
|
12560
12546
|
apiKey: process.env["MOBB_API_KEY"] || process.env["API_KEY"] || // fallback for backward compatibility
|
|
12561
|
-
|
|
12547
|
+
configStore.get("apiToken") || "",
|
|
12562
12548
|
type: "apiKey"
|
|
12563
12549
|
});
|
|
12564
|
-
const
|
|
12565
|
-
logDebug("API connection status", {
|
|
12566
|
-
if (!
|
|
12567
|
-
throw new ApiConnectionError("Error: failed to
|
|
12550
|
+
const isApiEndpointReachable = await initialClient.isApiEndpointReachable();
|
|
12551
|
+
logDebug("API connection status", { isApiEndpointReachable });
|
|
12552
|
+
if (!isApiEndpointReachable) {
|
|
12553
|
+
throw new ApiConnectionError("Error: failed to reach Mobb GraphQL endpoint");
|
|
12568
12554
|
}
|
|
12569
12555
|
logDebug("validating user token");
|
|
12570
12556
|
const userVerify = await initialClient.validateUserToken();
|
|
@@ -12573,7 +12559,7 @@ async function createAuthenticatedMcpGQLClient({
|
|
|
12573
12559
|
}
|
|
12574
12560
|
const authService = new McpAuthService(initialClient);
|
|
12575
12561
|
const newApiToken = await authService.authenticate(isBackgoundCall);
|
|
12576
|
-
|
|
12562
|
+
configStore.set("apiToken", newApiToken);
|
|
12577
12563
|
return new McpGQLClient({ apiKey: newApiToken, type: "apiKey" });
|
|
12578
12564
|
}
|
|
12579
12565
|
|
|
@@ -12582,6 +12568,9 @@ var MCP_TOOL_CHECK_FOR_NEW_AVAILABLE_FIXES = "check_for_new_available_fixes";
|
|
|
12582
12568
|
var MCP_TOOL_FETCH_AVAILABLE_FIXES = "fetch_available_fixes";
|
|
12583
12569
|
var MCP_TOOL_SCAN_AND_FIX_VULNERABILITIES = "scan_and_fix_vulnerabilities";
|
|
12584
12570
|
|
|
12571
|
+
// src/mcp/core/McpServer.ts
|
|
12572
|
+
init_configs();
|
|
12573
|
+
|
|
12585
12574
|
// src/mcp/core/ToolRegistry.ts
|
|
12586
12575
|
var ToolRegistry = class {
|
|
12587
12576
|
constructor() {
|
|
@@ -12656,6 +12645,18 @@ var McpServer = class {
|
|
|
12656
12645
|
} else {
|
|
12657
12646
|
logWarn(`${message} (exit code: ${exitCode})`, { signal, exitCode });
|
|
12658
12647
|
}
|
|
12648
|
+
} else if (signal === "unhandledRejection") {
|
|
12649
|
+
const errorDetails = {
|
|
12650
|
+
signal,
|
|
12651
|
+
errorType: error?.constructor?.name || "Unknown",
|
|
12652
|
+
errorMessage: error instanceof Error ? error.message : String(error),
|
|
12653
|
+
errorStack: error instanceof Error ? error.stack : void 0,
|
|
12654
|
+
errorString: error?.toString(),
|
|
12655
|
+
errorJson: JSON.stringify(error, null, 2),
|
|
12656
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
12657
|
+
};
|
|
12658
|
+
logError(`${message} - Enhanced error details`, errorDetails);
|
|
12659
|
+
logError(`${message} - Raw error object`, { error, signal });
|
|
12659
12660
|
} else if (error) {
|
|
12660
12661
|
logError(`${message}`, { error, signal });
|
|
12661
12662
|
} else {
|
|
@@ -12700,30 +12701,43 @@ var McpServer = class {
|
|
|
12700
12701
|
});
|
|
12701
12702
|
}
|
|
12702
12703
|
async triggerScanForNewAvailableFixes() {
|
|
12703
|
-
|
|
12704
|
-
|
|
12705
|
-
|
|
12706
|
-
const isConnected = await gqlClient.verifyApiConnection();
|
|
12707
|
-
if (!isConnected) {
|
|
12708
|
-
logError("Failed to connect to the API, skipping 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"]
|
|
12704
|
+
try {
|
|
12705
|
+
const gqlClient = await createAuthenticatedMcpGQLClient({
|
|
12706
|
+
isBackgoundCall: true
|
|
12714
12707
|
});
|
|
12715
|
-
|
|
12716
|
-
|
|
12717
|
-
|
|
12718
|
-
|
|
12719
|
-
|
|
12720
|
-
|
|
12721
|
-
|
|
12722
|
-
|
|
12708
|
+
const isConnected = await gqlClient.verifyApiConnection();
|
|
12709
|
+
if (!isConnected) {
|
|
12710
|
+
logError("Failed to connect to the API, skipping background scan");
|
|
12711
|
+
return;
|
|
12712
|
+
}
|
|
12713
|
+
if (process.env["WORKSPACE_FOLDER_PATHS"]) {
|
|
12714
|
+
logDebug("WORKSPACE_FOLDER_PATHS is set", {
|
|
12715
|
+
WORKSPACE_FOLDER_PATHS: process.env["WORKSPACE_FOLDER_PATHS"]
|
|
12723
12716
|
});
|
|
12724
|
-
|
|
12725
|
-
|
|
12717
|
+
try {
|
|
12718
|
+
const checkForNewAvailableFixesTool = this.toolRegistry.getTool(
|
|
12719
|
+
MCP_TOOL_CHECK_FOR_NEW_AVAILABLE_FIXES
|
|
12720
|
+
);
|
|
12721
|
+
logInfo("Triggering periodic scan for new available fixes");
|
|
12722
|
+
checkForNewAvailableFixesTool.triggerScan({
|
|
12723
|
+
path: process.env["WORKSPACE_FOLDER_PATHS"],
|
|
12724
|
+
gqlClient
|
|
12725
|
+
});
|
|
12726
|
+
} catch (error) {
|
|
12727
|
+
logError("Error getting workspace folder path tool", { error });
|
|
12728
|
+
}
|
|
12726
12729
|
}
|
|
12730
|
+
} catch (error) {
|
|
12731
|
+
if (error instanceof Error && (error.message.includes("Authentication") || error.message.includes("failed to connect to Mobb API"))) {
|
|
12732
|
+
logError(
|
|
12733
|
+
"Background scan skipped due to authentication failure. Please re-authenticate by running a manual scan.",
|
|
12734
|
+
{
|
|
12735
|
+
error: error.message
|
|
12736
|
+
}
|
|
12737
|
+
);
|
|
12738
|
+
return;
|
|
12739
|
+
}
|
|
12740
|
+
logError("Unexpected error during background scan", { error });
|
|
12727
12741
|
}
|
|
12728
12742
|
}
|
|
12729
12743
|
async handleListToolsRequest(request) {
|
|
@@ -12737,7 +12751,11 @@ var McpServer = class {
|
|
|
12737
12751
|
logDebug("env", {
|
|
12738
12752
|
env: process.env
|
|
12739
12753
|
});
|
|
12740
|
-
|
|
12754
|
+
if (isAutoScan) {
|
|
12755
|
+
void this.triggerScanForNewAvailableFixes();
|
|
12756
|
+
} else {
|
|
12757
|
+
logDebug("Auto scan disabled, skipping triggerScanForNewAvailableFixes");
|
|
12758
|
+
}
|
|
12741
12759
|
const toolsDefinitions = this.toolRegistry.getAllTools();
|
|
12742
12760
|
const response = {
|
|
12743
12761
|
tools: toolsDefinitions.map((tool) => ({
|
|
@@ -12947,7 +12965,6 @@ var BaseTool = class {
|
|
|
12947
12965
|
|
|
12948
12966
|
// src/mcp/tools/checkForNewAvailableFixes/CheckForNewAvailableFixesService.ts
|
|
12949
12967
|
init_configs();
|
|
12950
|
-
import Configstore4 from "configstore";
|
|
12951
12968
|
|
|
12952
12969
|
// src/mcp/core/prompts.ts
|
|
12953
12970
|
init_configs();
|
|
@@ -13566,6 +13583,18 @@ var initializeSecurityReport = async (gqlClient, scanContext) => {
|
|
|
13566
13583
|
return repoUploadInfo;
|
|
13567
13584
|
} catch (error) {
|
|
13568
13585
|
const message = error.message;
|
|
13586
|
+
if (message.includes("Authentication hook unauthorized") || message.includes("access-denied")) {
|
|
13587
|
+
logError(
|
|
13588
|
+
"Authentication failed during security report initialization. Please re-authenticate.",
|
|
13589
|
+
{
|
|
13590
|
+
error: message
|
|
13591
|
+
}
|
|
13592
|
+
);
|
|
13593
|
+
throw new ReportInitializationError(
|
|
13594
|
+
"Authentication failed. Please re-authenticate and try again."
|
|
13595
|
+
);
|
|
13596
|
+
}
|
|
13597
|
+
logError("Error initializing security report", { error: message });
|
|
13569
13598
|
throw new ReportInitializationError(
|
|
13570
13599
|
`Error initializing security report: ${message}`
|
|
13571
13600
|
);
|
|
@@ -13646,7 +13675,8 @@ var executeSecurityScan = async ({
|
|
|
13646
13675
|
});
|
|
13647
13676
|
},
|
|
13648
13677
|
callbackStates: ["Finished" /* Finished */],
|
|
13649
|
-
timeoutInMs: MCP_VUL_REPORT_DIGEST_TIMEOUT_MS
|
|
13678
|
+
timeoutInMs: MCP_VUL_REPORT_DIGEST_TIMEOUT_MS,
|
|
13679
|
+
scanContext
|
|
13650
13680
|
});
|
|
13651
13681
|
} catch (error) {
|
|
13652
13682
|
logError(`[${scanContext}] Security analysis failed or timed out`, {
|
|
@@ -13680,6 +13710,8 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
13680
13710
|
__publicField(this, "intervalId", null);
|
|
13681
13711
|
__publicField(this, "isInitialScanComplete", false);
|
|
13682
13712
|
__publicField(this, "gqlClient", null);
|
|
13713
|
+
__publicField(this, "fullScanPathsScanned", []);
|
|
13714
|
+
this.fullScanPathsScanned = configStore.get("fullScanPathsScanned") || [];
|
|
13683
13715
|
}
|
|
13684
13716
|
static getInstance() {
|
|
13685
13717
|
if (!_CheckForNewAvailableFixesService.instance) {
|
|
@@ -13695,6 +13727,7 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
13695
13727
|
this.filesLastScanned = {};
|
|
13696
13728
|
this.freshFixes = [];
|
|
13697
13729
|
this.reportedFixes = [];
|
|
13730
|
+
this.fullScanPathsScanned = configStore.get("fullScanPathsScanned") || [];
|
|
13698
13731
|
if (this.intervalId) {
|
|
13699
13732
|
clearInterval(this.intervalId);
|
|
13700
13733
|
this.intervalId = null;
|
|
@@ -13715,61 +13748,84 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
13715
13748
|
});
|
|
13716
13749
|
if (!this.gqlClient) {
|
|
13717
13750
|
logInfo(`[${scanContext}] No GQL client found, skipping scan`);
|
|
13718
|
-
|
|
13719
|
-
}
|
|
13720
|
-
const isConnected = await this.gqlClient.verifyApiConnection();
|
|
13721
|
-
if (!isConnected) {
|
|
13722
|
-
logError(`[${scanContext}] Failed to connect to the API, scan aborted`);
|
|
13723
|
-
return;
|
|
13751
|
+
throw new Error("No GQL client found");
|
|
13724
13752
|
}
|
|
13725
|
-
|
|
13726
|
-
|
|
13727
|
-
|
|
13728
|
-
|
|
13729
|
-
|
|
13730
|
-
path: path13,
|
|
13731
|
-
isAllFilesScan
|
|
13732
|
-
});
|
|
13733
|
-
logDebug(`[${scanContext}] Active files`, { files });
|
|
13734
|
-
const filesToScan = files.filter((file) => {
|
|
13735
|
-
const lastScannedEditTime = this.filesLastScanned[file.fullPath];
|
|
13736
|
-
if (!lastScannedEditTime) {
|
|
13737
|
-
return true;
|
|
13753
|
+
try {
|
|
13754
|
+
const isConnected = await this.gqlClient.verifyApiConnection();
|
|
13755
|
+
if (!isConnected) {
|
|
13756
|
+
logError(`[${scanContext}] Failed to connect to the API, scan aborted`);
|
|
13757
|
+
throw new ApiConnectionError();
|
|
13738
13758
|
}
|
|
13739
|
-
|
|
13740
|
-
|
|
13741
|
-
|
|
13742
|
-
|
|
13743
|
-
|
|
13744
|
-
|
|
13745
|
-
|
|
13746
|
-
|
|
13747
|
-
|
|
13748
|
-
|
|
13749
|
-
|
|
13750
|
-
|
|
13751
|
-
|
|
13752
|
-
|
|
13753
|
-
|
|
13754
|
-
|
|
13755
|
-
|
|
13756
|
-
|
|
13757
|
-
|
|
13759
|
+
logDebug(
|
|
13760
|
+
`[${scanContext}] Connected to the API, assembling list of files to scan`,
|
|
13761
|
+
{ path: path13 }
|
|
13762
|
+
);
|
|
13763
|
+
const files = await getLocalFiles({
|
|
13764
|
+
path: path13,
|
|
13765
|
+
isAllFilesScan
|
|
13766
|
+
});
|
|
13767
|
+
logDebug(`[${scanContext}] Active files`, { files });
|
|
13768
|
+
const filesToScan = files.filter((file) => {
|
|
13769
|
+
const lastScannedEditTime = this.filesLastScanned[file.fullPath];
|
|
13770
|
+
if (!lastScannedEditTime) {
|
|
13771
|
+
return true;
|
|
13772
|
+
}
|
|
13773
|
+
return file.lastEdited > lastScannedEditTime;
|
|
13774
|
+
});
|
|
13775
|
+
if (filesToScan.length === 0) {
|
|
13776
|
+
logInfo(`[${scanContext}] No files require scanning`);
|
|
13777
|
+
return;
|
|
13778
|
+
}
|
|
13779
|
+
logDebug(`[${scanContext}] Files requiring security scan`, {
|
|
13780
|
+
filesToScan
|
|
13781
|
+
});
|
|
13782
|
+
const { fixReportId, projectId } = await scanFiles({
|
|
13783
|
+
fileList: filesToScan.map((file) => file.relativePath),
|
|
13784
|
+
repositoryPath: path13,
|
|
13785
|
+
gqlClient: this.gqlClient,
|
|
13786
|
+
isAllDetectionRulesScan,
|
|
13787
|
+
scanContext
|
|
13788
|
+
});
|
|
13789
|
+
logInfo(
|
|
13790
|
+
`[${scanContext}] Security scan completed for ${path13} reportId: ${fixReportId} projectId: ${projectId}`
|
|
13791
|
+
);
|
|
13792
|
+
if (isAllFilesScan) {
|
|
13793
|
+
return;
|
|
13794
|
+
}
|
|
13795
|
+
const fixes = await this.gqlClient.getReportFixesPaginated({
|
|
13796
|
+
reportId: fixReportId,
|
|
13797
|
+
offset: 0,
|
|
13798
|
+
limit: 1e3
|
|
13799
|
+
});
|
|
13800
|
+
const newFixes = fixes?.fixes?.filter(
|
|
13801
|
+
(fix) => !this.isFixAlreadyReported(fix)
|
|
13802
|
+
);
|
|
13803
|
+
logInfo(
|
|
13804
|
+
`[${scanContext}] Security fixes retrieved, total: ${fixes?.fixes?.length || 0}, new: ${newFixes?.length || 0}`
|
|
13805
|
+
);
|
|
13806
|
+
this.updateFreshFixesCache(newFixes || [], filesToScan);
|
|
13807
|
+
this.updateFilesScanTimestamps(filesToScan);
|
|
13808
|
+
this.isInitialScanComplete = true;
|
|
13809
|
+
} catch (error) {
|
|
13810
|
+
const errorMessage = error.message;
|
|
13811
|
+
if (errorMessage.includes("Authentication failed") || errorMessage.includes("access-denied") || errorMessage.includes("Authentication hook unauthorized")) {
|
|
13812
|
+
logError(
|
|
13813
|
+
"Periodic scan skipped due to authentication failure. Please re-authenticate by running a manual scan.",
|
|
13814
|
+
{
|
|
13815
|
+
error: errorMessage
|
|
13816
|
+
}
|
|
13817
|
+
);
|
|
13818
|
+
return;
|
|
13819
|
+
}
|
|
13820
|
+
if (errorMessage.includes("ReportInitializationError")) {
|
|
13821
|
+
logError("Periodic scan failed during report initialization", {
|
|
13822
|
+
error: errorMessage
|
|
13823
|
+
});
|
|
13824
|
+
return;
|
|
13825
|
+
}
|
|
13826
|
+
logError("Unexpected error during periodic security scan", { error });
|
|
13827
|
+
throw error;
|
|
13758
13828
|
}
|
|
13759
|
-
const fixes = await this.gqlClient.getReportFixesPaginated({
|
|
13760
|
-
reportId: fixReportId,
|
|
13761
|
-
offset: 0,
|
|
13762
|
-
limit: 1e3
|
|
13763
|
-
});
|
|
13764
|
-
const newFixes = fixes?.fixes?.filter(
|
|
13765
|
-
(fix) => !this.isFixAlreadyReported(fix)
|
|
13766
|
-
);
|
|
13767
|
-
logInfo(
|
|
13768
|
-
`[${scanContext}] Security fixes retrieved, total: ${fixes?.fixes?.length || 0}, new: ${newFixes?.length || 0}`
|
|
13769
|
-
);
|
|
13770
|
-
this.updateFreshFixesCache(newFixes || [], filesToScan);
|
|
13771
|
-
this.updateFilesScanTimestamps(filesToScan);
|
|
13772
|
-
this.isInitialScanComplete = true;
|
|
13773
13829
|
}
|
|
13774
13830
|
updateFreshFixesCache(newFixes, filesToScan) {
|
|
13775
13831
|
this.freshFixes = this.freshFixes.filter((fix) => !this.isFixFromOldScan(fix, filesToScan)).concat(newFixes).sort((a, b) => {
|
|
@@ -13823,7 +13879,7 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
13823
13879
|
if (!this.intervalId) {
|
|
13824
13880
|
this.startPeriodicScanning(path13);
|
|
13825
13881
|
this.executeInitialScan(path13);
|
|
13826
|
-
this.executeInitialFullScan(path13);
|
|
13882
|
+
void this.executeInitialFullScan(path13);
|
|
13827
13883
|
}
|
|
13828
13884
|
}
|
|
13829
13885
|
startPeriodicScanning(path13) {
|
|
@@ -13840,37 +13896,46 @@ var _CheckForNewAvailableFixesService = class _CheckForNewAvailableFixesService
|
|
|
13840
13896
|
});
|
|
13841
13897
|
}, MCP_PERIODIC_CHECK_INTERVAL);
|
|
13842
13898
|
}
|
|
13843
|
-
executeInitialFullScan(path13) {
|
|
13844
|
-
|
|
13845
|
-
|
|
13846
|
-
|
|
13847
|
-
|
|
13848
|
-
|
|
13849
|
-
|
|
13899
|
+
async executeInitialFullScan(path13) {
|
|
13900
|
+
const scanContext = "FULL_SCAN";
|
|
13901
|
+
logDebug(`[${scanContext}] Triggering initial full security scan`, { path: path13 });
|
|
13902
|
+
logDebug(`[${scanContext}] Full scan paths scanned`, {
|
|
13903
|
+
fullScanPathsScanned: this.fullScanPathsScanned
|
|
13904
|
+
});
|
|
13905
|
+
if (this.fullScanPathsScanned.includes(path13)) {
|
|
13906
|
+
logDebug(`[${scanContext}] Full scan already executed for this path`, {
|
|
13907
|
+
path: path13
|
|
13908
|
+
});
|
|
13850
13909
|
return;
|
|
13851
13910
|
}
|
|
13852
|
-
|
|
13853
|
-
|
|
13854
|
-
|
|
13855
|
-
|
|
13856
|
-
|
|
13857
|
-
|
|
13858
|
-
|
|
13911
|
+
configStore.set("fullScanPathsScanned", [
|
|
13912
|
+
...this.fullScanPathsScanned,
|
|
13913
|
+
path13
|
|
13914
|
+
]);
|
|
13915
|
+
try {
|
|
13916
|
+
await this.scanForSecurityVulnerabilities({
|
|
13917
|
+
path: path13,
|
|
13918
|
+
isAllFilesScan: true,
|
|
13919
|
+
isAllDetectionRulesScan: true,
|
|
13920
|
+
scanContext: "FULL_SCAN"
|
|
13921
|
+
});
|
|
13922
|
+
if (!this.fullScanPathsScanned.includes(path13)) {
|
|
13923
|
+
this.fullScanPathsScanned.push(path13);
|
|
13924
|
+
configStore.set("fullScanPathsScanned", this.fullScanPathsScanned);
|
|
13925
|
+
}
|
|
13926
|
+
logInfo(`[${scanContext}] Full scan completed`, { path: path13 });
|
|
13927
|
+
} catch (error) {
|
|
13859
13928
|
logError("Error during initial full security scan", { error });
|
|
13860
|
-
}
|
|
13861
|
-
const fullScanPathsScanned2 = mobbConfigStore2.get("fullScanPathsScanned") || [];
|
|
13862
|
-
fullScanPathsScanned2.push(path13);
|
|
13863
|
-
mobbConfigStore2.set("fullScanPathsScanned", fullScanPathsScanned2);
|
|
13864
|
-
logDebug("Full scan completed", { path: path13 });
|
|
13865
|
-
});
|
|
13929
|
+
}
|
|
13866
13930
|
}
|
|
13867
13931
|
executeInitialScan(path13) {
|
|
13868
|
-
|
|
13932
|
+
const scanContext = "BACKGROUND_INITIAL";
|
|
13933
|
+
logDebug(`[${scanContext}] Triggering initial security scan`, { path: path13 });
|
|
13869
13934
|
this.scanForSecurityVulnerabilities({
|
|
13870
13935
|
path: path13,
|
|
13871
13936
|
scanContext: "BACKGROUND_INITIAL"
|
|
13872
13937
|
}).catch((error) => {
|
|
13873
|
-
logError(
|
|
13938
|
+
logError(`[${scanContext}] Error during initial security scan`, { error });
|
|
13874
13939
|
});
|
|
13875
13940
|
}
|
|
13876
13941
|
generateFreshFixesResponse() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mobbdev",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.127",
|
|
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",
|