mobbdev 1.1.19 → 1.1.23

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.
@@ -8,13 +8,12 @@ declare enum AiBlameInferenceType {
8
8
  }
9
9
 
10
10
  type SanitizationCounts = {
11
- pii: {
11
+ detections: {
12
12
  total: number;
13
13
  high: number;
14
14
  medium: number;
15
15
  low: number;
16
16
  };
17
- secrets: number;
18
17
  };
19
18
 
20
19
  declare const PromptItemZ: z.ZodObject<{
@@ -190,9 +189,11 @@ type UploadAiBlameOptions = {
190
189
  model?: string[];
191
190
  toolName?: string[];
192
191
  blameType?: AiBlameInferenceType[];
192
+ sessionId?: string[];
193
193
  'ai-response-at'?: string[];
194
194
  'tool-name'?: string[];
195
195
  'blame-type'?: AiBlameInferenceType[];
196
+ 'session-id'?: string[];
196
197
  };
197
198
  declare function uploadAiBlameBuilder(args: Yargs.Argv<unknown>): Yargs.Argv<UploadAiBlameOptions>;
198
199
  type UploadAiBlameResult = {
@@ -208,6 +209,7 @@ declare function uploadAiBlameHandlerFromExtension(args: {
208
209
  tool: string;
209
210
  responseTime: string;
210
211
  blameType?: AiBlameInferenceType;
212
+ sessionId?: string;
211
213
  }): Promise<UploadAiBlameResult>;
212
214
  declare function uploadAiBlameHandler(args: UploadAiBlameOptions, exitOnError?: boolean): Promise<void>;
213
215
 
@@ -79,7 +79,7 @@ var init_FileUtils = __esm({
79
79
  import fs4 from "fs";
80
80
  import ignore from "ignore";
81
81
  import * as path5 from "path";
82
- import { simpleGit } from "simple-git";
82
+ import { simpleGit as simpleGit2 } from "simple-git";
83
83
  var init_GitService = __esm({
84
84
  "src/features/analysis/scm/services/GitService.ts"() {
85
85
  "use strict";
@@ -2203,6 +2203,7 @@ function getDirName() {
2203
2203
  var debug = Debug("mobbdev:constants");
2204
2204
  dotenv.config({ path: path2.join(getModuleRootDir(), ".env") });
2205
2205
  var DEFAULT_API_URL = "https://api.mobb.ai/v1/graphql";
2206
+ var DEFAULT_WEB_APP_URL = "https://app.mobb.ai";
2206
2207
  var scmFriendlyText = {
2207
2208
  ["Ado" /* Ado */]: "Azure DevOps",
2208
2209
  ["Bitbucket" /* Bitbucket */]: "Bitbucket",
@@ -2229,13 +2230,16 @@ var scannerToVulnerabilityReportVendorEnum = {
2229
2230
  };
2230
2231
  var SupportedScannersZ = z8.enum([SCANNERS.Checkmarx, SCANNERS.Snyk]);
2231
2232
  var envVariablesSchema = z8.object({
2232
- WEB_APP_URL: z8.string(),
2233
- API_URL: z8.string(),
2234
- HASURA_ACCESS_KEY: z8.string(),
2235
- LOCAL_GRAPHQL_ENDPOINT: z8.string(),
2233
+ // These have safe defaults for production - the VS Code extension passes explicit URLs
2234
+ WEB_APP_URL: z8.string().optional().default(DEFAULT_WEB_APP_URL),
2235
+ API_URL: z8.string().optional().default(DEFAULT_API_URL),
2236
+ // These are only needed for local development with Hasura
2237
+ HASURA_ACCESS_KEY: z8.string().optional().default(""),
2238
+ LOCAL_GRAPHQL_ENDPOINT: z8.string().optional().default(""),
2239
+ // Proxy settings
2236
2240
  HTTP_PROXY: z8.string().optional().default(""),
2237
2241
  HTTPS_PROXY: z8.string().optional().default("")
2238
- }).required();
2242
+ });
2239
2243
  var envVariables = envVariablesSchema.parse(process.env);
2240
2244
  debug("config %o", envVariables);
2241
2245
  var WEB_APP_URL = envVariables.WEB_APP_URL;
@@ -2371,6 +2375,9 @@ if (!semver.satisfies(process.version, packageJson.engines.node)) {
2371
2375
  process.exit(1);
2372
2376
  }
2373
2377
 
2378
+ // src/utils/gitUtils.ts
2379
+ import simpleGit from "simple-git";
2380
+
2374
2381
  // src/utils/index.ts
2375
2382
  var sleep = (ms = 2e3) => new Promise((r) => setTimeout(r, ms));
2376
2383
  var CliError = class extends Error {
@@ -4722,10 +4729,12 @@ var GQLClient = class {
4722
4729
  constructor(args) {
4723
4730
  __publicField(this, "_client");
4724
4731
  __publicField(this, "_clientSdk");
4732
+ __publicField(this, "_apiUrl");
4725
4733
  __publicField(this, "_auth");
4726
4734
  debug6(`init with ${args}`);
4727
4735
  this._auth = args;
4728
- this._client = new GraphQLClient(API_URL, {
4736
+ this._apiUrl = args.apiUrl || API_URL;
4737
+ this._client = new GraphQLClient(this._apiUrl, {
4729
4738
  headers: args.type === "apiKey" ? { [API_KEY_HEADER_NAME]: args.apiKey || "" } : {
4730
4739
  Authorization: `Bearer ${args.token}`
4731
4740
  },
@@ -5023,12 +5032,12 @@ var GQLClient = class {
5023
5032
  apiKey: this._auth.apiKey,
5024
5033
  type: "apiKey",
5025
5034
  timeoutInMs: params.timeoutInMs,
5026
- proxyAgent: getProxyAgent(API_URL)
5035
+ proxyAgent: getProxyAgent(this._apiUrl)
5027
5036
  } : {
5028
5037
  token: this._auth.token,
5029
5038
  type: "token",
5030
5039
  timeoutInMs: params.timeoutInMs,
5031
- proxyAgent: getProxyAgent(API_URL)
5040
+ proxyAgent: getProxyAgent(this._apiUrl)
5032
5041
  }
5033
5042
  );
5034
5043
  }
@@ -5114,29 +5123,37 @@ var configStore = getConfigStore();
5114
5123
  var debug7 = Debug6("mobbdev:commands");
5115
5124
  var LOGIN_MAX_WAIT = 10 * 60 * 1e3;
5116
5125
  var LOGIN_CHECK_DELAY = 5 * 1e3;
5117
- var webLoginUrl = `${WEB_APP_URL}/cli-login`;
5118
5126
  var MOBB_LOGIN_REQUIRED_MSG = `\u{1F513} Login to Mobb is Required, you will be redirected to our login page, once the authorization is complete return to this prompt, ${chalk2.bgBlue(
5119
5127
  "press any key to continue"
5120
5128
  )};`;
5121
5129
  async function getAuthenticatedGQLClient({
5122
5130
  inputApiKey = "",
5123
- isSkipPrompts = true
5131
+ isSkipPrompts = true,
5132
+ apiUrl,
5133
+ webAppUrl
5124
5134
  }) {
5125
5135
  let gqlClient = new GQLClient({
5126
5136
  apiKey: inputApiKey || configStore.get("apiToken") || "",
5127
- type: "apiKey"
5137
+ type: "apiKey",
5138
+ apiUrl
5128
5139
  });
5129
5140
  gqlClient = await handleMobbLogin({
5130
5141
  inGqlClient: gqlClient,
5131
- skipPrompts: isSkipPrompts
5142
+ skipPrompts: isSkipPrompts,
5143
+ apiUrl,
5144
+ webAppUrl
5132
5145
  });
5133
5146
  return gqlClient;
5134
5147
  }
5135
5148
  async function handleMobbLogin({
5136
5149
  inGqlClient,
5137
5150
  apiKey,
5138
- skipPrompts
5151
+ skipPrompts,
5152
+ apiUrl,
5153
+ webAppUrl
5139
5154
  }) {
5155
+ const resolvedWebAppUrl = webAppUrl || WEB_APP_URL;
5156
+ const resolvedApiUrl = apiUrl || API_URL;
5140
5157
  const { createSpinner } = Spinner({ ci: skipPrompts });
5141
5158
  const isConnected = await inGqlClient.verifyApiConnection();
5142
5159
  if (!isConnected) {
@@ -5178,7 +5195,7 @@ async function handleMobbLogin({
5178
5195
  const loginId = await inGqlClient.createCliLogin({
5179
5196
  publicKey: publicKey.export({ format: "pem", type: "pkcs1" }).toString()
5180
5197
  });
5181
- const browserUrl = `${webLoginUrl}/${loginId}?hostname=${os.hostname()}`;
5198
+ const browserUrl = `${resolvedWebAppUrl}/cli-login/${loginId}?hostname=${os.hostname()}`;
5182
5199
  !skipPrompts && console.log(
5183
5200
  `If the page does not open automatically, kindly access it through ${browserUrl}.`
5184
5201
  );
@@ -5203,7 +5220,11 @@ async function handleMobbLogin({
5203
5220
  });
5204
5221
  throw new CliError();
5205
5222
  }
5206
- const newGqlClient = new GQLClient({ apiKey: newApiToken, type: "apiKey" });
5223
+ const newGqlClient = new GQLClient({
5224
+ apiKey: newApiToken,
5225
+ type: "apiKey",
5226
+ apiUrl: resolvedApiUrl
5227
+ });
5207
5228
  const loginSuccess = await newGqlClient.validateUserToken();
5208
5229
  if (loginSuccess) {
5209
5230
  debug7(`set api token ${newApiToken}`);
@@ -5272,8 +5293,6 @@ async function uploadFile({
5272
5293
 
5273
5294
  // src/utils/sanitize-sensitive-data.ts
5274
5295
  import { OpenRedaction } from "@openredaction/openredaction";
5275
- import { spawn } from "child_process";
5276
- import { installGitleaks } from "gitleaks-secret-scanner/lib/installer.js";
5277
5296
  var openRedaction = new OpenRedaction({
5278
5297
  patterns: [
5279
5298
  // Core Personal Data
@@ -5291,42 +5310,36 @@ var openRedaction = new OpenRedaction({
5291
5310
  "VISA_NUMBER",
5292
5311
  "VISA_MRZ",
5293
5312
  "TAX_ID",
5294
- // Financial Data
5313
+ // Financial Data (removed SWIFT_BIC - too broad, matches bank code formats in variables)
5295
5314
  "CREDIT_CARD",
5296
5315
  "IBAN",
5297
5316
  "BANK_ACCOUNT_UK",
5298
5317
  "ROUTING_NUMBER_US",
5299
- "SWIFT_BIC",
5300
5318
  "CARD_TRACK1_DATA",
5301
5319
  "CARD_TRACK2_DATA",
5302
5320
  "CARD_EXPIRY",
5303
5321
  "CARD_AUTH_CODE",
5304
- // Cryptocurrency
5305
- "BITCOIN_ADDRESS",
5322
+ // Cryptocurrency (removed BITCOIN_ADDRESS - too broad, matches hash-like strings)
5306
5323
  "ETHEREUM_ADDRESS",
5307
5324
  "LITECOIN_ADDRESS",
5308
5325
  "CARDANO_ADDRESS",
5309
5326
  "SOLANA_ADDRESS",
5310
5327
  "MONERO_ADDRESS",
5311
5328
  "RIPPLE_ADDRESS",
5312
- // Medical Data
5329
+ // Medical Data (removed PRESCRIPTION_NUMBER - too broad, matches words containing "ription")
5313
5330
  "NHS_NUMBER",
5314
5331
  "MEDICAL_RECORD_NUMBER",
5315
5332
  "AUSTRALIAN_MEDICARE",
5316
5333
  "HEALTH_PLAN_NUMBER",
5317
- "PRESCRIPTION_NUMBER",
5318
5334
  "PATIENT_ID",
5319
- // Communications
5335
+ // Communications (removed EMERGENCY_CONTACT, ADDRESS_PO_BOX, ZIP_CODE_US - too broad)
5320
5336
  "PHONE_US",
5321
5337
  "PHONE_UK",
5322
5338
  "PHONE_UK_MOBILE",
5323
5339
  "PHONE_INTERNATIONAL",
5324
5340
  "PHONE_LINE_NUMBER",
5325
- "EMERGENCY_CONTACT",
5326
5341
  "ADDRESS_STREET",
5327
- "ADDRESS_PO_BOX",
5328
5342
  "POSTCODE_UK",
5329
- "ZIP_CODE_US",
5330
5343
  // Network & Technical
5331
5344
  "IPV4",
5332
5345
  "IPV6",
@@ -5367,63 +5380,6 @@ var openRedaction = new OpenRedaction({
5367
5380
  "CLIENT_ID"
5368
5381
  ]
5369
5382
  });
5370
- var gitleaksBinaryPath = null;
5371
- async function initializeGitleaks() {
5372
- try {
5373
- gitleaksBinaryPath = await installGitleaks({ version: "8.27.2" });
5374
- return gitleaksBinaryPath;
5375
- } catch {
5376
- return null;
5377
- }
5378
- }
5379
- var gitleaksInitPromise = initializeGitleaks();
5380
- async function detectSecretsWithGitleaks(text) {
5381
- const secrets = /* @__PURE__ */ new Set();
5382
- const binaryPath = gitleaksBinaryPath || await gitleaksInitPromise;
5383
- if (!binaryPath) {
5384
- return secrets;
5385
- }
5386
- return new Promise((resolve) => {
5387
- const gitleaks = spawn(
5388
- binaryPath,
5389
- [
5390
- "detect",
5391
- "--pipe",
5392
- "--no-banner",
5393
- "--exit-code",
5394
- "0",
5395
- "--report-format",
5396
- "json"
5397
- ],
5398
- {
5399
- stdio: ["pipe", "pipe", "ignore"]
5400
- }
5401
- );
5402
- let output = "";
5403
- gitleaks.stdout.on("data", (data) => {
5404
- output += data.toString();
5405
- });
5406
- gitleaks.on("close", () => {
5407
- try {
5408
- const findings = JSON.parse(output);
5409
- if (Array.isArray(findings)) {
5410
- for (const finding of findings) {
5411
- if (finding.Secret) {
5412
- secrets.add(finding.Secret);
5413
- }
5414
- }
5415
- }
5416
- } catch {
5417
- }
5418
- resolve(secrets);
5419
- });
5420
- gitleaks.on("error", () => {
5421
- resolve(secrets);
5422
- });
5423
- gitleaks.stdin.write(text);
5424
- gitleaks.stdin.end();
5425
- });
5426
- }
5427
5383
  function maskString(str, showStart = 2, showEnd = 2) {
5428
5384
  if (str.length <= showStart + showEnd) {
5429
5385
  return "*".repeat(str.length);
@@ -5432,8 +5388,7 @@ function maskString(str, showStart = 2, showEnd = 2) {
5432
5388
  }
5433
5389
  async function sanitizeDataWithCounts(obj) {
5434
5390
  const counts = {
5435
- pii: { total: 0, high: 0, medium: 0, low: 0 },
5436
- secrets: 0
5391
+ detections: { total: 0, high: 0, medium: 0, low: 0 }
5437
5392
  };
5438
5393
  const sanitizeString = async (str) => {
5439
5394
  let result = str;
@@ -5445,20 +5400,14 @@ async function sanitizeDataWithCounts(obj) {
5445
5400
  ...piiDetections.low
5446
5401
  ];
5447
5402
  for (const detection of allDetections) {
5448
- counts.pii.total++;
5449
- if (detection.severity === "high") counts.pii.high++;
5450
- else if (detection.severity === "medium") counts.pii.medium++;
5451
- else if (detection.severity === "low") counts.pii.low++;
5403
+ counts.detections.total++;
5404
+ if (detection.severity === "high") counts.detections.high++;
5405
+ else if (detection.severity === "medium") counts.detections.medium++;
5406
+ else if (detection.severity === "low") counts.detections.low++;
5452
5407
  const masked = maskString(detection.value);
5453
5408
  result = result.replaceAll(detection.value, masked);
5454
5409
  }
5455
5410
  }
5456
- const secrets = await detectSecretsWithGitleaks(result);
5457
- counts.secrets += secrets.size;
5458
- for (const secret of secrets) {
5459
- const masked = maskString(secret);
5460
- result = result.replaceAll(secret, masked);
5461
- }
5462
5411
  return result;
5463
5412
  };
5464
5413
  const sanitizeRecursive = async (data) => {
@@ -5569,7 +5518,8 @@ async function uploadAiBlameHandlerFromExtension(args) {
5569
5518
  model: [],
5570
5519
  toolName: [],
5571
5520
  aiResponseAt: [],
5572
- blameType: []
5521
+ blameType: [],
5522
+ sessionId: []
5573
5523
  };
5574
5524
  let promptsCounts;
5575
5525
  let inferenceCounts;
@@ -5602,6 +5552,9 @@ async function uploadAiBlameHandlerFromExtension(args) {
5602
5552
  uploadArgs.toolName.push(args.tool);
5603
5553
  uploadArgs.aiResponseAt.push(args.responseTime);
5604
5554
  uploadArgs.blameType.push(args.blameType || "CHAT" /* Chat */);
5555
+ if (args.sessionId) {
5556
+ uploadArgs.sessionId.push(args.sessionId);
5557
+ }
5605
5558
  await uploadAiBlameHandler(uploadArgs, false);
5606
5559
  });
5607
5560
  });
@@ -5619,6 +5572,7 @@ async function uploadAiBlameHandler(args, exitOnError = true) {
5619
5572
  const tools = args.toolName || args["tool-name"] || [];
5620
5573
  const responseTimes = args.aiResponseAt || args["ai-response-at"] || [];
5621
5574
  const blameTypes = args.blameType || args["blame-type"] || [];
5575
+ const sessionIds = args.sessionId || args["session-id"] || [];
5622
5576
  if (prompts.length !== inferences.length) {
5623
5577
  const errorMsg = "prompt and inference must have the same number of entries";
5624
5578
  console.error(chalk3.red(errorMsg));
@@ -5654,14 +5608,18 @@ async function uploadAiBlameHandler(args, exitOnError = true) {
5654
5608
  toolName: tools[i],
5655
5609
  blameType: blameTypes[i] || "CHAT" /* Chat */,
5656
5610
  computerName,
5657
- userName
5611
+ userName,
5612
+ sessionId: sessionIds[i]
5658
5613
  });
5659
5614
  }
5660
5615
  const authenticatedClient = await getAuthenticatedGQLClient({
5661
5616
  isSkipPrompts: true
5662
5617
  });
5618
+ const initSessions = sessions.map(
5619
+ ({ sessionId: _sessionId, ...rest }) => rest
5620
+ );
5663
5621
  const sanitizedSessions = await sanitizeData(
5664
- sessions
5622
+ initSessions
5665
5623
  );
5666
5624
  const initRes = await authenticatedClient.uploadAIBlameInferencesInitRaw({
5667
5625
  sessions: sanitizedSessions
@@ -5707,7 +5665,8 @@ async function uploadAiBlameHandler(args, exitOnError = true) {
5707
5665
  toolName: s.toolName,
5708
5666
  blameType: s.blameType,
5709
5667
  computerName: s.computerName,
5710
- userName: s.userName
5668
+ userName: s.userName,
5669
+ sessionId: s.sessionId
5711
5670
  };
5712
5671
  });
5713
5672
  const sanitizedFinalizeSessions = await sanitizeData(
package/dist/index.mjs CHANGED
@@ -9863,6 +9863,7 @@ var utils_exports = {};
9863
9863
  __export(utils_exports, {
9864
9864
  CliError: () => CliError,
9865
9865
  Spinner: () => Spinner,
9866
+ createGitWithLogging: () => createGitWithLogging,
9866
9867
  getDirName: () => getDirName,
9867
9868
  getModuleRootDir: () => getModuleRootDir,
9868
9869
  getTopLevelDirName: () => getTopLevelDirName,
@@ -9990,6 +9991,53 @@ if (!semver.satisfies(process.version, packageJson.engines.node)) {
9990
9991
  process.exit(1);
9991
9992
  }
9992
9993
 
9994
+ // src/utils/gitUtils.ts
9995
+ import simpleGit2 from "simple-git";
9996
+ var defaultLogger = {
9997
+ info: (data, msg) => {
9998
+ if (msg) {
9999
+ const sanitizedMsg = String(msg).replace(/\n|\r/g, "");
10000
+ console.log(`[GIT] ${sanitizedMsg}`, data);
10001
+ } else {
10002
+ console.log("[GIT]", data);
10003
+ }
10004
+ }
10005
+ };
10006
+ function createGitWithLogging(dirName, logger2 = defaultLogger) {
10007
+ return simpleGit2(dirName, {
10008
+ maxConcurrentProcesses: 6
10009
+ }).outputHandler((bin, stdout2, stderr2) => {
10010
+ const callID = Math.random();
10011
+ logger2.info({ callID, bin }, "Start git CLI call");
10012
+ const errChunks = [];
10013
+ const outChunks = [];
10014
+ let isStdoutClosed = false;
10015
+ let isStderrClosed = false;
10016
+ stderr2.on("data", (data) => errChunks.push(data.toString("utf8")));
10017
+ stdout2.on("data", (data) => outChunks.push(data.toString("utf8")));
10018
+ function logData() {
10019
+ if (!isStderrClosed || !isStdoutClosed) {
10020
+ return;
10021
+ }
10022
+ const logObj = {
10023
+ callID,
10024
+ bin,
10025
+ err: `${errChunks.join("").slice(0, 200)}...`,
10026
+ out: `${outChunks.join("").slice(0, 200)}...`
10027
+ };
10028
+ logger2.info(logObj, "git log output");
10029
+ }
10030
+ stderr2.on("close", () => {
10031
+ isStderrClosed = true;
10032
+ logData();
10033
+ });
10034
+ stdout2.on("close", () => {
10035
+ isStdoutClosed = true;
10036
+ logData();
10037
+ });
10038
+ });
10039
+ }
10040
+
9993
10041
  // src/utils/index.ts
9994
10042
  var sleep = (ms = 2e3) => new Promise((r) => setTimeout(r, ms));
9995
10043
  var CliError = class extends Error {
@@ -10390,6 +10438,7 @@ import { z as z24 } from "zod";
10390
10438
  var debug5 = Debug4("mobbdev:constants");
10391
10439
  dotenv.config({ path: path6.join(getModuleRootDir(), ".env") });
10392
10440
  var DEFAULT_API_URL = "https://api.mobb.ai/v1/graphql";
10441
+ var DEFAULT_WEB_APP_URL = "https://app.mobb.ai";
10393
10442
  var scmFriendlyText = {
10394
10443
  ["Ado" /* Ado */]: "Azure DevOps",
10395
10444
  ["Bitbucket" /* Bitbucket */]: "Bitbucket",
@@ -10416,13 +10465,16 @@ var scannerToVulnerabilityReportVendorEnum = {
10416
10465
  };
10417
10466
  var SupportedScannersZ = z24.enum([SCANNERS.Checkmarx, SCANNERS.Snyk]);
10418
10467
  var envVariablesSchema = z24.object({
10419
- WEB_APP_URL: z24.string(),
10420
- API_URL: z24.string(),
10421
- HASURA_ACCESS_KEY: z24.string(),
10422
- LOCAL_GRAPHQL_ENDPOINT: z24.string(),
10468
+ // These have safe defaults for production - the VS Code extension passes explicit URLs
10469
+ WEB_APP_URL: z24.string().optional().default(DEFAULT_WEB_APP_URL),
10470
+ API_URL: z24.string().optional().default(DEFAULT_API_URL),
10471
+ // These are only needed for local development with Hasura
10472
+ HASURA_ACCESS_KEY: z24.string().optional().default(""),
10473
+ LOCAL_GRAPHQL_ENDPOINT: z24.string().optional().default(""),
10474
+ // Proxy settings
10423
10475
  HTTP_PROXY: z24.string().optional().default(""),
10424
10476
  HTTPS_PROXY: z24.string().optional().default("")
10425
- }).required();
10477
+ });
10426
10478
  var envVariables = envVariablesSchema.parse(process.env);
10427
10479
  debug5("config %o", envVariables);
10428
10480
  var mobbAscii = `
@@ -10475,9 +10527,9 @@ var errorMessages = {
10475
10527
  )} is needed if you're adding an SCM token`
10476
10528
  };
10477
10529
  var progressMassages = {
10478
- processingVulnerabilityReportSuccess: "\u2699\uFE0F Vulnerability report proccessed successfully",
10479
- processingVulnerabilityReport: "\u2699\uFE0F Proccessing vulnerability report",
10480
- processingVulnerabilityReportFailed: "\u2699\uFE0F Error Proccessing vulnerability report"
10530
+ processingVulnerabilityReportSuccess: "\u2699\uFE0F Vulnerability report processed successfully",
10531
+ processingVulnerabilityReport: "\u2699\uFE0F Processing vulnerability report",
10532
+ processingVulnerabilityReportFailed: "\u2699\uFE0F Error Processing vulnerability report"
10481
10533
  };
10482
10534
  var VUL_REPORT_DIGEST_TIMEOUT_MS = 1e3 * 60 * 30;
10483
10535
 
@@ -10977,10 +11029,12 @@ var GQLClient = class {
10977
11029
  constructor(args) {
10978
11030
  __publicField(this, "_client");
10979
11031
  __publicField(this, "_clientSdk");
11032
+ __publicField(this, "_apiUrl");
10980
11033
  __publicField(this, "_auth");
10981
11034
  debug6(`init with ${args}`);
10982
11035
  this._auth = args;
10983
- this._client = new GraphQLClient(API_URL, {
11036
+ this._apiUrl = args.apiUrl || API_URL;
11037
+ this._client = new GraphQLClient(this._apiUrl, {
10984
11038
  headers: args.type === "apiKey" ? { [API_KEY_HEADER_NAME]: args.apiKey || "" } : {
10985
11039
  Authorization: `Bearer ${args.token}`
10986
11040
  },
@@ -11278,12 +11332,12 @@ var GQLClient = class {
11278
11332
  apiKey: this._auth.apiKey,
11279
11333
  type: "apiKey",
11280
11334
  timeoutInMs: params.timeoutInMs,
11281
- proxyAgent: getProxyAgent(API_URL)
11335
+ proxyAgent: getProxyAgent(this._apiUrl)
11282
11336
  } : {
11283
11337
  token: this._auth.token,
11284
11338
  type: "token",
11285
11339
  timeoutInMs: params.timeoutInMs,
11286
- proxyAgent: getProxyAgent(API_URL)
11340
+ proxyAgent: getProxyAgent(this._apiUrl)
11287
11341
  }
11288
11342
  );
11289
11343
  }
@@ -11369,29 +11423,37 @@ var configStore = getConfigStore();
11369
11423
  var debug7 = Debug6("mobbdev:commands");
11370
11424
  var LOGIN_MAX_WAIT = 10 * 60 * 1e3;
11371
11425
  var LOGIN_CHECK_DELAY = 5 * 1e3;
11372
- var webLoginUrl = `${WEB_APP_URL}/cli-login`;
11373
11426
  var MOBB_LOGIN_REQUIRED_MSG = `\u{1F513} Login to Mobb is Required, you will be redirected to our login page, once the authorization is complete return to this prompt, ${chalk3.bgBlue(
11374
11427
  "press any key to continue"
11375
11428
  )};`;
11376
11429
  async function getAuthenticatedGQLClient({
11377
11430
  inputApiKey = "",
11378
- isSkipPrompts = true
11431
+ isSkipPrompts = true,
11432
+ apiUrl,
11433
+ webAppUrl
11379
11434
  }) {
11380
11435
  let gqlClient = new GQLClient({
11381
11436
  apiKey: inputApiKey || configStore.get("apiToken") || "",
11382
- type: "apiKey"
11437
+ type: "apiKey",
11438
+ apiUrl
11383
11439
  });
11384
11440
  gqlClient = await handleMobbLogin({
11385
11441
  inGqlClient: gqlClient,
11386
- skipPrompts: isSkipPrompts
11442
+ skipPrompts: isSkipPrompts,
11443
+ apiUrl,
11444
+ webAppUrl
11387
11445
  });
11388
11446
  return gqlClient;
11389
11447
  }
11390
11448
  async function handleMobbLogin({
11391
11449
  inGqlClient,
11392
11450
  apiKey,
11393
- skipPrompts
11451
+ skipPrompts,
11452
+ apiUrl,
11453
+ webAppUrl
11394
11454
  }) {
11455
+ const resolvedWebAppUrl = webAppUrl || WEB_APP_URL;
11456
+ const resolvedApiUrl = apiUrl || API_URL;
11395
11457
  const { createSpinner: createSpinner5 } = Spinner({ ci: skipPrompts });
11396
11458
  const isConnected = await inGqlClient.verifyApiConnection();
11397
11459
  if (!isConnected) {
@@ -11433,7 +11495,7 @@ async function handleMobbLogin({
11433
11495
  const loginId = await inGqlClient.createCliLogin({
11434
11496
  publicKey: publicKey.export({ format: "pem", type: "pkcs1" }).toString()
11435
11497
  });
11436
- const browserUrl = `${webLoginUrl}/${loginId}?hostname=${os.hostname()}`;
11498
+ const browserUrl = `${resolvedWebAppUrl}/cli-login/${loginId}?hostname=${os.hostname()}`;
11437
11499
  !skipPrompts && console.log(
11438
11500
  `If the page does not open automatically, kindly access it through ${browserUrl}.`
11439
11501
  );
@@ -11458,7 +11520,11 @@ async function handleMobbLogin({
11458
11520
  });
11459
11521
  throw new CliError();
11460
11522
  }
11461
- const newGqlClient = new GQLClient({ apiKey: newApiToken, type: "apiKey" });
11523
+ const newGqlClient = new GQLClient({
11524
+ apiKey: newApiToken,
11525
+ type: "apiKey",
11526
+ apiUrl: resolvedApiUrl
11527
+ });
11462
11528
  const loginSuccess = await newGqlClient.validateUserToken();
11463
11529
  if (loginSuccess) {
11464
11530
  debug7(`set api token ${newApiToken}`);
@@ -12141,7 +12207,7 @@ import AdmZip from "adm-zip";
12141
12207
  import Debug13 from "debug";
12142
12208
  import { globby } from "globby";
12143
12209
  import { isBinary as isBinary2 } from "istextorbinary";
12144
- import { simpleGit as simpleGit2 } from "simple-git";
12210
+ import { simpleGit as simpleGit3 } from "simple-git";
12145
12211
  import { parseStringPromise } from "xml2js";
12146
12212
  import { z as z28 } from "zod";
12147
12213
  var debug14 = Debug13("mobbdev:pack");
@@ -12169,7 +12235,7 @@ async function pack(srcDirPath, vulnFiles, isIncludeAllFiles = false) {
12169
12235
  debug14("pack folder %s", srcDirPath);
12170
12236
  let git = void 0;
12171
12237
  try {
12172
- git = simpleGit2({
12238
+ git = simpleGit3({
12173
12239
  baseDir: srcDirPath,
12174
12240
  maxConcurrentProcesses: 1,
12175
12241
  trimmed: true
@@ -13561,8 +13627,6 @@ import z31 from "zod";
13561
13627
 
13562
13628
  // src/utils/sanitize-sensitive-data.ts
13563
13629
  import { OpenRedaction } from "@openredaction/openredaction";
13564
- import { spawn } from "child_process";
13565
- import { installGitleaks } from "gitleaks-secret-scanner/lib/installer.js";
13566
13630
  var openRedaction = new OpenRedaction({
13567
13631
  patterns: [
13568
13632
  // Core Personal Data
@@ -13580,42 +13644,36 @@ var openRedaction = new OpenRedaction({
13580
13644
  "VISA_NUMBER",
13581
13645
  "VISA_MRZ",
13582
13646
  "TAX_ID",
13583
- // Financial Data
13647
+ // Financial Data (removed SWIFT_BIC - too broad, matches bank code formats in variables)
13584
13648
  "CREDIT_CARD",
13585
13649
  "IBAN",
13586
13650
  "BANK_ACCOUNT_UK",
13587
13651
  "ROUTING_NUMBER_US",
13588
- "SWIFT_BIC",
13589
13652
  "CARD_TRACK1_DATA",
13590
13653
  "CARD_TRACK2_DATA",
13591
13654
  "CARD_EXPIRY",
13592
13655
  "CARD_AUTH_CODE",
13593
- // Cryptocurrency
13594
- "BITCOIN_ADDRESS",
13656
+ // Cryptocurrency (removed BITCOIN_ADDRESS - too broad, matches hash-like strings)
13595
13657
  "ETHEREUM_ADDRESS",
13596
13658
  "LITECOIN_ADDRESS",
13597
13659
  "CARDANO_ADDRESS",
13598
13660
  "SOLANA_ADDRESS",
13599
13661
  "MONERO_ADDRESS",
13600
13662
  "RIPPLE_ADDRESS",
13601
- // Medical Data
13663
+ // Medical Data (removed PRESCRIPTION_NUMBER - too broad, matches words containing "ription")
13602
13664
  "NHS_NUMBER",
13603
13665
  "MEDICAL_RECORD_NUMBER",
13604
13666
  "AUSTRALIAN_MEDICARE",
13605
13667
  "HEALTH_PLAN_NUMBER",
13606
- "PRESCRIPTION_NUMBER",
13607
13668
  "PATIENT_ID",
13608
- // Communications
13669
+ // Communications (removed EMERGENCY_CONTACT, ADDRESS_PO_BOX, ZIP_CODE_US - too broad)
13609
13670
  "PHONE_US",
13610
13671
  "PHONE_UK",
13611
13672
  "PHONE_UK_MOBILE",
13612
13673
  "PHONE_INTERNATIONAL",
13613
13674
  "PHONE_LINE_NUMBER",
13614
- "EMERGENCY_CONTACT",
13615
13675
  "ADDRESS_STREET",
13616
- "ADDRESS_PO_BOX",
13617
13676
  "POSTCODE_UK",
13618
- "ZIP_CODE_US",
13619
13677
  // Network & Technical
13620
13678
  "IPV4",
13621
13679
  "IPV6",
@@ -13656,63 +13714,6 @@ var openRedaction = new OpenRedaction({
13656
13714
  "CLIENT_ID"
13657
13715
  ]
13658
13716
  });
13659
- var gitleaksBinaryPath = null;
13660
- async function initializeGitleaks() {
13661
- try {
13662
- gitleaksBinaryPath = await installGitleaks({ version: "8.27.2" });
13663
- return gitleaksBinaryPath;
13664
- } catch {
13665
- return null;
13666
- }
13667
- }
13668
- var gitleaksInitPromise = initializeGitleaks();
13669
- async function detectSecretsWithGitleaks(text) {
13670
- const secrets = /* @__PURE__ */ new Set();
13671
- const binaryPath = gitleaksBinaryPath || await gitleaksInitPromise;
13672
- if (!binaryPath) {
13673
- return secrets;
13674
- }
13675
- return new Promise((resolve) => {
13676
- const gitleaks = spawn(
13677
- binaryPath,
13678
- [
13679
- "detect",
13680
- "--pipe",
13681
- "--no-banner",
13682
- "--exit-code",
13683
- "0",
13684
- "--report-format",
13685
- "json"
13686
- ],
13687
- {
13688
- stdio: ["pipe", "pipe", "ignore"]
13689
- }
13690
- );
13691
- let output = "";
13692
- gitleaks.stdout.on("data", (data) => {
13693
- output += data.toString();
13694
- });
13695
- gitleaks.on("close", () => {
13696
- try {
13697
- const findings = JSON.parse(output);
13698
- if (Array.isArray(findings)) {
13699
- for (const finding of findings) {
13700
- if (finding.Secret) {
13701
- secrets.add(finding.Secret);
13702
- }
13703
- }
13704
- }
13705
- } catch {
13706
- }
13707
- resolve(secrets);
13708
- });
13709
- gitleaks.on("error", () => {
13710
- resolve(secrets);
13711
- });
13712
- gitleaks.stdin.write(text);
13713
- gitleaks.stdin.end();
13714
- });
13715
- }
13716
13717
  function maskString(str, showStart = 2, showEnd = 2) {
13717
13718
  if (str.length <= showStart + showEnd) {
13718
13719
  return "*".repeat(str.length);
@@ -13721,8 +13722,7 @@ function maskString(str, showStart = 2, showEnd = 2) {
13721
13722
  }
13722
13723
  async function sanitizeDataWithCounts(obj) {
13723
13724
  const counts = {
13724
- pii: { total: 0, high: 0, medium: 0, low: 0 },
13725
- secrets: 0
13725
+ detections: { total: 0, high: 0, medium: 0, low: 0 }
13726
13726
  };
13727
13727
  const sanitizeString = async (str) => {
13728
13728
  let result = str;
@@ -13734,20 +13734,14 @@ async function sanitizeDataWithCounts(obj) {
13734
13734
  ...piiDetections.low
13735
13735
  ];
13736
13736
  for (const detection of allDetections) {
13737
- counts.pii.total++;
13738
- if (detection.severity === "high") counts.pii.high++;
13739
- else if (detection.severity === "medium") counts.pii.medium++;
13740
- else if (detection.severity === "low") counts.pii.low++;
13737
+ counts.detections.total++;
13738
+ if (detection.severity === "high") counts.detections.high++;
13739
+ else if (detection.severity === "medium") counts.detections.medium++;
13740
+ else if (detection.severity === "low") counts.detections.low++;
13741
13741
  const masked = maskString(detection.value);
13742
13742
  result = result.replaceAll(detection.value, masked);
13743
13743
  }
13744
13744
  }
13745
- const secrets = await detectSecretsWithGitleaks(result);
13746
- counts.secrets += secrets.size;
13747
- for (const secret of secrets) {
13748
- const masked = maskString(secret);
13749
- result = result.replaceAll(secret, masked);
13750
- }
13751
13745
  return result;
13752
13746
  };
13753
13747
  const sanitizeRecursive = async (data) => {
@@ -13858,7 +13852,8 @@ async function uploadAiBlameHandlerFromExtension(args) {
13858
13852
  model: [],
13859
13853
  toolName: [],
13860
13854
  aiResponseAt: [],
13861
- blameType: []
13855
+ blameType: [],
13856
+ sessionId: []
13862
13857
  };
13863
13858
  let promptsCounts;
13864
13859
  let inferenceCounts;
@@ -13891,6 +13886,9 @@ async function uploadAiBlameHandlerFromExtension(args) {
13891
13886
  uploadArgs.toolName.push(args.tool);
13892
13887
  uploadArgs.aiResponseAt.push(args.responseTime);
13893
13888
  uploadArgs.blameType.push(args.blameType || "CHAT" /* Chat */);
13889
+ if (args.sessionId) {
13890
+ uploadArgs.sessionId.push(args.sessionId);
13891
+ }
13894
13892
  await uploadAiBlameHandler(uploadArgs, false);
13895
13893
  });
13896
13894
  });
@@ -13908,6 +13906,7 @@ async function uploadAiBlameHandler(args, exitOnError = true) {
13908
13906
  const tools = args.toolName || args["tool-name"] || [];
13909
13907
  const responseTimes = args.aiResponseAt || args["ai-response-at"] || [];
13910
13908
  const blameTypes = args.blameType || args["blame-type"] || [];
13909
+ const sessionIds = args.sessionId || args["session-id"] || [];
13911
13910
  if (prompts.length !== inferences.length) {
13912
13911
  const errorMsg = "prompt and inference must have the same number of entries";
13913
13912
  console.error(chalk9.red(errorMsg));
@@ -13943,14 +13942,18 @@ async function uploadAiBlameHandler(args, exitOnError = true) {
13943
13942
  toolName: tools[i],
13944
13943
  blameType: blameTypes[i] || "CHAT" /* Chat */,
13945
13944
  computerName,
13946
- userName
13945
+ userName,
13946
+ sessionId: sessionIds[i]
13947
13947
  });
13948
13948
  }
13949
13949
  const authenticatedClient = await getAuthenticatedGQLClient({
13950
13950
  isSkipPrompts: true
13951
13951
  });
13952
+ const initSessions = sessions.map(
13953
+ ({ sessionId: _sessionId, ...rest }) => rest
13954
+ );
13952
13955
  const sanitizedSessions = await sanitizeData(
13953
- sessions
13956
+ initSessions
13954
13957
  );
13955
13958
  const initRes = await authenticatedClient.uploadAIBlameInferencesInitRaw({
13956
13959
  sessions: sanitizedSessions
@@ -13996,7 +13999,8 @@ async function uploadAiBlameHandler(args, exitOnError = true) {
13996
13999
  toolName: s.toolName,
13997
14000
  blameType: s.blameType,
13998
14001
  computerName: s.computerName,
13999
- userName: s.userName
14002
+ userName: s.userName,
14003
+ sessionId: s.sessionId
14000
14004
  };
14001
14005
  });
14002
14006
  const sanitizedFinalizeSessions = await sanitizeData(
@@ -14799,8 +14803,8 @@ var McpAuthService = class {
14799
14803
  throw new CliLoginError("Error: createCliLogin failed");
14800
14804
  }
14801
14805
  logDebug(`cli login created ${loginId}`);
14802
- const webLoginUrl2 = `${WEB_APP_URL}/mvs-login`;
14803
- const browserUrl = `${webLoginUrl2}/${loginId}?hostname=${os4.hostname()}`;
14806
+ const webLoginUrl = `${WEB_APP_URL}/mvs-login`;
14807
+ const browserUrl = `${webLoginUrl}/${loginId}?hostname=${os4.hostname()}`;
14804
14808
  await this.openBrowser(browserUrl, isBackgoundCall);
14805
14809
  logDebug(`waiting for login to complete`);
14806
14810
  let newApiToken = null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mobbdev",
3
- "version": "1.1.19",
3
+ "version": "1.1.23",
4
4
  "description": "Automated secure code remediation tool",
5
5
  "repository": "git+https://github.com/mobb-dev/bugsy.git",
6
6
  "main": "dist/index.mjs",
@@ -68,7 +68,6 @@
68
68
  "debug": "4.4.3",
69
69
  "dotenv": "16.6.1",
70
70
  "extract-zip": "2.0.1",
71
- "gitleaks-secret-scanner": "1.2.2",
72
71
  "globby": "14.1.0",
73
72
  "graphql": "16.12.0",
74
73
  "graphql-request": "6.1.0",