mobbdev 1.2.33 → 1.2.35
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/args/commands/upload_ai_blame.d.mts +47 -33
- package/dist/args/commands/upload_ai_blame.mjs +304 -218
- package/dist/index.mjs +1479 -1352
- package/package.json +1 -1
|
@@ -73,6 +73,12 @@ function getSdk(client, withWrapper = defaultWrapper) {
|
|
|
73
73
|
FinalizeAIBlameInferencesUpload(variables, requestHeaders, signal) {
|
|
74
74
|
return withWrapper((wrappedRequestHeaders) => client.request({ document: FinalizeAiBlameInferencesUploadDocument, variables, requestHeaders: { ...requestHeaders, ...wrappedRequestHeaders }, signal }), "FinalizeAIBlameInferencesUpload", "mutation", variables);
|
|
75
75
|
},
|
|
76
|
+
UploadTracyRecords(variables, requestHeaders, signal) {
|
|
77
|
+
return withWrapper((wrappedRequestHeaders) => client.request({ document: UploadTracyRecordsDocument, variables, requestHeaders: { ...requestHeaders, ...wrappedRequestHeaders }, signal }), "UploadTracyRecords", "mutation", variables);
|
|
78
|
+
},
|
|
79
|
+
GetTracyRawDataUploadUrls(variables, requestHeaders, signal) {
|
|
80
|
+
return withWrapper((wrappedRequestHeaders) => client.request({ document: GetTracyRawDataUploadUrlsDocument, variables, requestHeaders: { ...requestHeaders, ...wrappedRequestHeaders }, signal }), "GetTracyRawDataUploadUrls", "mutation", variables);
|
|
81
|
+
},
|
|
76
82
|
DigestVulnerabilityReport(variables, requestHeaders, signal) {
|
|
77
83
|
return withWrapper((wrappedRequestHeaders) => client.request({ document: DigestVulnerabilityReportDocument, variables, requestHeaders: { ...requestHeaders, ...wrappedRequestHeaders }, signal }), "DigestVulnerabilityReport", "mutation", variables);
|
|
78
84
|
},
|
|
@@ -126,7 +132,7 @@ function getSdk(client, withWrapper = defaultWrapper) {
|
|
|
126
132
|
}
|
|
127
133
|
};
|
|
128
134
|
}
|
|
129
|
-
var AiBlameInferenceType, FixQuestionInputType, Language, ManifestAction, Effort_To_Apply_Fix_Enum, Fix_Rating_Tag_Enum, Fix_Report_State_Enum, Fix_State_Enum, IssueLanguage_Enum, IssueType_Enum, Pr_Status_Enum, Project_Role_Type_Enum, Vulnerability_Report_Issue_Category_Enum, Vulnerability_Report_Issue_State_Enum, Vulnerability_Report_Issue_Tag_Enum, Vulnerability_Report_Vendor_Enum, Vulnerability_Severity_Enum, FixDetailsFragmentDoc, FixReportSummaryFieldsFragmentDoc, MeDocument, GetLastOrgAndNamedProjectDocument, GetLastOrgDocument, GetEncryptedApiTokenDocument, FixReportStateDocument, GetVulnerabilityReportPathsDocument, GetAnalysisSubscriptionDocument, GetAnalysisDocument, GetFixesDocument, GetVulByNodesMetadataDocument, GetFalsePositiveDocument, UpdateScmTokenDocument, UploadS3BucketInfoDocument, GetTracyDiffUploadUrlDocument, AnalyzeCommitForExtensionAiBlameDocument, GetAiBlameInferenceDocument, GetAiBlameAttributionPromptDocument, GetPromptSummaryDocument, UploadAiBlameInferencesInitDocument, FinalizeAiBlameInferencesUploadDocument, DigestVulnerabilityReportDocument, SubmitVulnerabilityReportDocument, CreateCommunityUserDocument, CreateCliLoginDocument, PerformCliLoginDocument, CreateProjectDocument, ValidateRepoUrlDocument, GitReferenceDocument, AutoPrAnalysisDocument, GetFixReportsByRepoUrlDocument, GetReportFixesDocument, GetLatestReportByRepoUrlDocument, UpdateDownloadedFixDataDocument, GetUserMvsAutoFixDocument, StreamBlameAiAnalysisRequestsDocument, StreamCommitBlameRequestsDocument, ScanSkillDocument, defaultWrapper;
|
|
135
|
+
var AiBlameInferenceType, FixQuestionInputType, Language, ManifestAction, Effort_To_Apply_Fix_Enum, Fix_Rating_Tag_Enum, Fix_Report_State_Enum, Fix_State_Enum, IssueLanguage_Enum, IssueType_Enum, Pr_Status_Enum, Project_Role_Type_Enum, Vulnerability_Report_Issue_Category_Enum, Vulnerability_Report_Issue_State_Enum, Vulnerability_Report_Issue_Tag_Enum, Vulnerability_Report_Vendor_Enum, Vulnerability_Severity_Enum, FixDetailsFragmentDoc, FixReportSummaryFieldsFragmentDoc, MeDocument, GetLastOrgAndNamedProjectDocument, GetLastOrgDocument, GetEncryptedApiTokenDocument, FixReportStateDocument, GetVulnerabilityReportPathsDocument, GetAnalysisSubscriptionDocument, GetAnalysisDocument, GetFixesDocument, GetVulByNodesMetadataDocument, GetFalsePositiveDocument, UpdateScmTokenDocument, UploadS3BucketInfoDocument, GetTracyDiffUploadUrlDocument, AnalyzeCommitForExtensionAiBlameDocument, GetAiBlameInferenceDocument, GetAiBlameAttributionPromptDocument, GetPromptSummaryDocument, UploadAiBlameInferencesInitDocument, FinalizeAiBlameInferencesUploadDocument, UploadTracyRecordsDocument, GetTracyRawDataUploadUrlsDocument, DigestVulnerabilityReportDocument, SubmitVulnerabilityReportDocument, CreateCommunityUserDocument, CreateCliLoginDocument, PerformCliLoginDocument, CreateProjectDocument, ValidateRepoUrlDocument, GitReferenceDocument, AutoPrAnalysisDocument, GetFixReportsByRepoUrlDocument, GetReportFixesDocument, GetLatestReportByRepoUrlDocument, UpdateDownloadedFixDataDocument, GetUserMvsAutoFixDocument, StreamBlameAiAnalysisRequestsDocument, StreamCommitBlameRequestsDocument, ScanSkillDocument, defaultWrapper;
|
|
130
136
|
var init_client_generates = __esm({
|
|
131
137
|
"src/features/analysis/scm/generates/client_generates.ts"() {
|
|
132
138
|
"use strict";
|
|
@@ -962,6 +968,28 @@ var init_client_generates = __esm({
|
|
|
962
968
|
status
|
|
963
969
|
error
|
|
964
970
|
}
|
|
971
|
+
}
|
|
972
|
+
`;
|
|
973
|
+
UploadTracyRecordsDocument = `
|
|
974
|
+
mutation UploadTracyRecords($records: [TracyRecordInput!]!) {
|
|
975
|
+
uploadTracyRecords(records: $records) {
|
|
976
|
+
status
|
|
977
|
+
error
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
`;
|
|
981
|
+
GetTracyRawDataUploadUrlsDocument = `
|
|
982
|
+
mutation GetTracyRawDataUploadUrls($recordIds: [String!]!) {
|
|
983
|
+
getTracyRawDataUploadUrls(recordIds: $recordIds) {
|
|
984
|
+
status
|
|
985
|
+
error
|
|
986
|
+
uploads {
|
|
987
|
+
recordId
|
|
988
|
+
url
|
|
989
|
+
uploadFieldsJSON
|
|
990
|
+
uploadKey
|
|
991
|
+
}
|
|
992
|
+
}
|
|
965
993
|
}
|
|
966
994
|
`;
|
|
967
995
|
DigestVulnerabilityReportDocument = `
|
|
@@ -2227,20 +2255,20 @@ function computeCanonicalUrl(data) {
|
|
|
2227
2255
|
} = data;
|
|
2228
2256
|
switch (scmType) {
|
|
2229
2257
|
case "GitHub" /* GitHub */:
|
|
2230
|
-
return `https://${hostname}/${organization}/${repoName}`;
|
|
2258
|
+
return `https://${hostname}/${organization.toLowerCase()}/${repoName.toLowerCase()}`;
|
|
2231
2259
|
case "GitLab" /* GitLab */:
|
|
2232
|
-
return `https://${hostname}/${projectPath}`;
|
|
2260
|
+
return `https://${hostname}/${projectPath.toLowerCase()}`;
|
|
2233
2261
|
case "Bitbucket" /* Bitbucket */:
|
|
2234
|
-
return `https://${hostname}/${organization}/${repoName}`;
|
|
2262
|
+
return `https://${hostname}/${organization.toLowerCase()}/${repoName.toLowerCase()}`;
|
|
2235
2263
|
case "Ado" /* Ado */: {
|
|
2236
2264
|
const adoHostname = hostname === "ssh.dev.azure.com" ? "dev.azure.com" : hostname;
|
|
2237
2265
|
if (projectName) {
|
|
2238
|
-
return `https://${adoHostname}/${organization}/${projectName}/_git/${repoName}`;
|
|
2266
|
+
return `https://${adoHostname}/${organization.toLowerCase()}/${projectName.toLowerCase()}/_git/${repoName.toLowerCase()}`;
|
|
2239
2267
|
}
|
|
2240
|
-
return `https://${adoHostname}/${organization}/_git/${repoName}`;
|
|
2268
|
+
return `https://${adoHostname}/${organization.toLowerCase()}/_git/${repoName.toLowerCase()}`;
|
|
2241
2269
|
}
|
|
2242
2270
|
default:
|
|
2243
|
-
return `https://${hostname}/${projectPath}`;
|
|
2271
|
+
return `https://${hostname}/${projectPath.toLowerCase()}`;
|
|
2244
2272
|
}
|
|
2245
2273
|
}
|
|
2246
2274
|
function detectAdoUrl(args) {
|
|
@@ -4082,7 +4110,7 @@ import z27 from "zod";
|
|
|
4082
4110
|
|
|
4083
4111
|
// src/commands/handleMobbLogin.ts
|
|
4084
4112
|
import chalk2 from "chalk";
|
|
4085
|
-
import
|
|
4113
|
+
import Debug10 from "debug";
|
|
4086
4114
|
|
|
4087
4115
|
// src/utils/dirname.ts
|
|
4088
4116
|
import fs from "fs";
|
|
@@ -4211,6 +4239,7 @@ var CliError = class extends Error {
|
|
|
4211
4239
|
// src/commands/AuthManager.ts
|
|
4212
4240
|
import crypto from "crypto";
|
|
4213
4241
|
import os from "os";
|
|
4242
|
+
import Debug9 from "debug";
|
|
4214
4243
|
import open from "open";
|
|
4215
4244
|
|
|
4216
4245
|
// src/constants.ts
|
|
@@ -4304,7 +4333,7 @@ var VUL_REPORT_DIGEST_TIMEOUT_MS = 1e3 * 60 * 30;
|
|
|
4304
4333
|
|
|
4305
4334
|
// src/features/analysis/graphql/gql.ts
|
|
4306
4335
|
import Debug6 from "debug";
|
|
4307
|
-
import { GraphQLClient } from "graphql-request";
|
|
4336
|
+
import { ClientError, GraphQLClient } from "graphql-request";
|
|
4308
4337
|
import { v4 as uuidv4 } from "uuid";
|
|
4309
4338
|
|
|
4310
4339
|
// src/mcp/core/Errors.ts
|
|
@@ -4374,8 +4403,7 @@ function getProxyAgent(url) {
|
|
|
4374
4403
|
const isHttps = parsedUrl.protocol === "https:";
|
|
4375
4404
|
const proxy = isHttps ? getHttpProxy() : isHttp ? getHttpProxyOnly() : null;
|
|
4376
4405
|
if (proxy) {
|
|
4377
|
-
debug2("Using proxy %s", proxy);
|
|
4378
|
-
debug2("Proxy agent %o", proxy);
|
|
4406
|
+
debug2("Using proxy %s for %s", proxy, url);
|
|
4379
4407
|
return new HttpsProxyAgent(proxy);
|
|
4380
4408
|
}
|
|
4381
4409
|
} catch (err) {
|
|
@@ -6663,6 +6691,19 @@ var GetVulByNodesMetadataZ = z26.object({
|
|
|
6663
6691
|
|
|
6664
6692
|
// src/features/analysis/graphql/gql.ts
|
|
6665
6693
|
var debug7 = Debug6("mobbdev:gql");
|
|
6694
|
+
function isAuthError(error) {
|
|
6695
|
+
if (error instanceof ClientError) {
|
|
6696
|
+
const gqlErrors = error.response?.errors;
|
|
6697
|
+
return gqlErrors?.some(
|
|
6698
|
+
(e) => e.extensions?.["code"] === "access-denied" || e.message?.includes("Authentication hook unauthorized")
|
|
6699
|
+
) ?? false;
|
|
6700
|
+
}
|
|
6701
|
+
return false;
|
|
6702
|
+
}
|
|
6703
|
+
function isNetworkError(error) {
|
|
6704
|
+
const errorString = error?.toString() ?? "";
|
|
6705
|
+
return errorString.includes("FetchError") || errorString.includes("TypeError") || errorString.includes("ECONNREFUSED") || errorString.includes("ENOTFOUND") || errorString.includes("ETIMEDOUT") || errorString.includes("UND_ERR");
|
|
6706
|
+
}
|
|
6666
6707
|
var API_KEY_HEADER_NAME = "x-mobb-key";
|
|
6667
6708
|
var REPORT_STATE_CHECK_DELAY = 5 * 1e3;
|
|
6668
6709
|
var GQLClient = class {
|
|
@@ -6722,23 +6763,35 @@ var GQLClient = class {
|
|
|
6722
6763
|
try {
|
|
6723
6764
|
await this.getUserInfo();
|
|
6724
6765
|
} catch (e) {
|
|
6725
|
-
if (e
|
|
6726
|
-
debug7("verify connection failed %o", e);
|
|
6766
|
+
if (isNetworkError(e)) {
|
|
6767
|
+
debug7("verify connection failed (network error) %o", e);
|
|
6727
6768
|
return false;
|
|
6728
6769
|
}
|
|
6770
|
+
debug7("verify connection: endpoint reachable but request failed %o", e);
|
|
6729
6771
|
}
|
|
6730
6772
|
return true;
|
|
6731
6773
|
}
|
|
6732
6774
|
async validateUserToken() {
|
|
6733
|
-
await this.createCommunityUser();
|
|
6734
|
-
let info;
|
|
6735
6775
|
try {
|
|
6736
|
-
|
|
6776
|
+
await this.createCommunityUser();
|
|
6777
|
+
const info = await this.getUserInfo();
|
|
6778
|
+
if (!info) {
|
|
6779
|
+
debug7("verify token failed - no user info returned");
|
|
6780
|
+
return false;
|
|
6781
|
+
}
|
|
6782
|
+
return info.email || true;
|
|
6737
6783
|
} catch (e) {
|
|
6738
|
-
|
|
6739
|
-
|
|
6784
|
+
if (isAuthError(e)) {
|
|
6785
|
+
debug7("verify token failed - auth error %o", e);
|
|
6786
|
+
return false;
|
|
6787
|
+
}
|
|
6788
|
+
if (isNetworkError(e)) {
|
|
6789
|
+
debug7("verify token failed - network error, rethrowing %o", e);
|
|
6790
|
+
throw e;
|
|
6791
|
+
}
|
|
6792
|
+
debug7("verify token failed - unexpected error, rethrowing %o", e);
|
|
6793
|
+
throw e;
|
|
6740
6794
|
}
|
|
6741
|
-
return info?.email || true;
|
|
6742
6795
|
}
|
|
6743
6796
|
async getLastOrgAndNamedProject(params) {
|
|
6744
6797
|
const me = await this.getUserInfo();
|
|
@@ -7094,6 +7147,12 @@ var GQLClient = class {
|
|
|
7094
7147
|
async finalizeAIBlameInferencesUploadRaw(variables) {
|
|
7095
7148
|
return await this._clientSdk.FinalizeAIBlameInferencesUpload(variables);
|
|
7096
7149
|
}
|
|
7150
|
+
async uploadTracyRecords(variables) {
|
|
7151
|
+
return await this._clientSdk.UploadTracyRecords(variables);
|
|
7152
|
+
}
|
|
7153
|
+
async getTracyRawDataUploadUrls(variables) {
|
|
7154
|
+
return await this._clientSdk.GetTracyRawDataUploadUrls(variables);
|
|
7155
|
+
}
|
|
7097
7156
|
async analyzeCommitForExtensionAIBlame(variables) {
|
|
7098
7157
|
return await this._clientSdk.AnalyzeCommitForExtensionAIBlame(variables);
|
|
7099
7158
|
}
|
|
@@ -7111,6 +7170,209 @@ var GQLClient = class {
|
|
|
7111
7170
|
}
|
|
7112
7171
|
};
|
|
7113
7172
|
|
|
7173
|
+
// src/features/analysis/graphql/tracy-batch-upload.ts
|
|
7174
|
+
import { promisify } from "util";
|
|
7175
|
+
import { gzip } from "zlib";
|
|
7176
|
+
import Debug8 from "debug";
|
|
7177
|
+
|
|
7178
|
+
// src/utils/sanitize-sensitive-data.ts
|
|
7179
|
+
import { OpenRedaction } from "@openredaction/openredaction";
|
|
7180
|
+
var openRedaction = new OpenRedaction({
|
|
7181
|
+
patterns: [
|
|
7182
|
+
// Core Personal Data
|
|
7183
|
+
// Removed EMAIL - causes false positives in code/test snippets (e.g. --author="Eve Author <eve@example.com>")
|
|
7184
|
+
// Prefer false negatives over false positives for this use case.
|
|
7185
|
+
"SSN",
|
|
7186
|
+
"NATIONAL_INSURANCE_UK",
|
|
7187
|
+
"DATE_OF_BIRTH",
|
|
7188
|
+
// Identity Documents
|
|
7189
|
+
"PASSPORT_UK",
|
|
7190
|
+
"PASSPORT_US",
|
|
7191
|
+
"PASSPORT_MRZ_TD1",
|
|
7192
|
+
"PASSPORT_MRZ_TD3",
|
|
7193
|
+
"DRIVING_LICENSE_UK",
|
|
7194
|
+
"DRIVING_LICENSE_US",
|
|
7195
|
+
"VISA_NUMBER",
|
|
7196
|
+
"VISA_MRZ",
|
|
7197
|
+
"TAX_ID",
|
|
7198
|
+
// Financial Data (removed SWIFT_BIC, CARD_AUTH_CODE - too broad, causing false positives with authentication words)
|
|
7199
|
+
// Removed CREDIT_CARD - causes false positives on zero-filled UUIDs (e.g. '00000000-0000-0000-0000-000000000000')
|
|
7200
|
+
// Prefer false negatives over false positives for this use case.
|
|
7201
|
+
"IBAN",
|
|
7202
|
+
"BANK_ACCOUNT_UK",
|
|
7203
|
+
"ROUTING_NUMBER_US",
|
|
7204
|
+
"CARD_TRACK1_DATA",
|
|
7205
|
+
"CARD_TRACK2_DATA",
|
|
7206
|
+
"CARD_EXPIRY",
|
|
7207
|
+
// Cryptocurrency (removed BITCOIN_ADDRESS - too broad, matches hash-like strings)
|
|
7208
|
+
"ETHEREUM_ADDRESS",
|
|
7209
|
+
"LITECOIN_ADDRESS",
|
|
7210
|
+
"CARDANO_ADDRESS",
|
|
7211
|
+
"SOLANA_ADDRESS",
|
|
7212
|
+
"MONERO_ADDRESS",
|
|
7213
|
+
"RIPPLE_ADDRESS",
|
|
7214
|
+
// Medical Data (removed PRESCRIPTION_NUMBER - too broad, matches words containing "ription")
|
|
7215
|
+
// Removed MEDICAL_RECORD_NUMBER - too broad, "MR" prefix matches "Merge Request" in SCM contexts (e.g. "MR branches" → "MR br****es")
|
|
7216
|
+
"NHS_NUMBER",
|
|
7217
|
+
"AUSTRALIAN_MEDICARE",
|
|
7218
|
+
"HEALTH_PLAN_NUMBER",
|
|
7219
|
+
"PATIENT_ID",
|
|
7220
|
+
// Communications (removed EMERGENCY_CONTACT, ADDRESS_PO_BOX, ZIP_CODE_US, PHONE_US, PHONE_INTERNATIONAL - too broad, causing false positives)
|
|
7221
|
+
"PHONE_UK",
|
|
7222
|
+
"PHONE_UK_MOBILE",
|
|
7223
|
+
"PHONE_LINE_NUMBER",
|
|
7224
|
+
"ADDRESS_STREET",
|
|
7225
|
+
"POSTCODE_UK",
|
|
7226
|
+
// Network & Technical
|
|
7227
|
+
"IPV4",
|
|
7228
|
+
"IPV6",
|
|
7229
|
+
"MAC_ADDRESS",
|
|
7230
|
+
"URL_WITH_AUTH",
|
|
7231
|
+
// Security Keys & Tokens
|
|
7232
|
+
"PRIVATE_KEY",
|
|
7233
|
+
"SSH_PRIVATE_KEY",
|
|
7234
|
+
"AWS_SECRET_KEY",
|
|
7235
|
+
"AWS_ACCESS_KEY",
|
|
7236
|
+
"AZURE_STORAGE_KEY",
|
|
7237
|
+
"GCP_SERVICE_ACCOUNT",
|
|
7238
|
+
"JWT_TOKEN",
|
|
7239
|
+
"OAUTH_TOKEN",
|
|
7240
|
+
"OAUTH_CLIENT_SECRET",
|
|
7241
|
+
"BEARER_TOKEN",
|
|
7242
|
+
"PAYMENT_TOKEN",
|
|
7243
|
+
"GENERIC_SECRET",
|
|
7244
|
+
"GENERIC_API_KEY",
|
|
7245
|
+
// Platform-Specific API Keys
|
|
7246
|
+
"GITHUB_TOKEN",
|
|
7247
|
+
"SLACK_TOKEN",
|
|
7248
|
+
"STRIPE_API_KEY",
|
|
7249
|
+
"GOOGLE_API_KEY",
|
|
7250
|
+
"FIREBASE_API_KEY",
|
|
7251
|
+
"HEROKU_API_KEY",
|
|
7252
|
+
"MAILGUN_API_KEY",
|
|
7253
|
+
"SENDGRID_API_KEY",
|
|
7254
|
+
"TWILIO_API_KEY",
|
|
7255
|
+
"NPM_TOKEN",
|
|
7256
|
+
"PYPI_TOKEN",
|
|
7257
|
+
"DOCKER_AUTH",
|
|
7258
|
+
"KUBERNETES_SECRET",
|
|
7259
|
+
// Government & Legal
|
|
7260
|
+
// Removed CLIENT_ID - too broad, "client" is ubiquitous in code (npm packages like @scope/client-*, class names like ClientSdkOptions)
|
|
7261
|
+
"POLICE_REPORT_NUMBER",
|
|
7262
|
+
"IMMIGRATION_NUMBER",
|
|
7263
|
+
"COURT_REPORTER_LICENSE"
|
|
7264
|
+
]
|
|
7265
|
+
});
|
|
7266
|
+
function maskString(str, showStart = 2, showEnd = 2) {
|
|
7267
|
+
if (str.length <= showStart + showEnd) {
|
|
7268
|
+
return "*".repeat(str.length);
|
|
7269
|
+
}
|
|
7270
|
+
return str.slice(0, showStart) + "*".repeat(str.length - showStart - showEnd) + str.slice(-showEnd);
|
|
7271
|
+
}
|
|
7272
|
+
async function sanitizeDataWithCounts(obj) {
|
|
7273
|
+
const counts = {
|
|
7274
|
+
detections: { total: 0, high: 0, medium: 0, low: 0 }
|
|
7275
|
+
};
|
|
7276
|
+
const sanitizeString = async (str) => {
|
|
7277
|
+
let result = str;
|
|
7278
|
+
const piiDetections = openRedaction.scan(str);
|
|
7279
|
+
if (piiDetections && piiDetections.total > 0) {
|
|
7280
|
+
const allDetections = [
|
|
7281
|
+
...piiDetections.high,
|
|
7282
|
+
...piiDetections.medium,
|
|
7283
|
+
...piiDetections.low
|
|
7284
|
+
];
|
|
7285
|
+
for (const detection of allDetections) {
|
|
7286
|
+
counts.detections.total++;
|
|
7287
|
+
if (detection.severity === "high") counts.detections.high++;
|
|
7288
|
+
else if (detection.severity === "medium") counts.detections.medium++;
|
|
7289
|
+
else if (detection.severity === "low") counts.detections.low++;
|
|
7290
|
+
const masked = maskString(detection.value);
|
|
7291
|
+
result = result.replaceAll(detection.value, masked);
|
|
7292
|
+
}
|
|
7293
|
+
}
|
|
7294
|
+
return result;
|
|
7295
|
+
};
|
|
7296
|
+
const sanitizeRecursive = async (data) => {
|
|
7297
|
+
if (typeof data === "string") {
|
|
7298
|
+
return sanitizeString(data);
|
|
7299
|
+
} else if (Array.isArray(data)) {
|
|
7300
|
+
return Promise.all(data.map((item) => sanitizeRecursive(item)));
|
|
7301
|
+
} else if (data instanceof Error) {
|
|
7302
|
+
return data;
|
|
7303
|
+
} else if (data instanceof Date) {
|
|
7304
|
+
return data;
|
|
7305
|
+
} else if (typeof data === "object" && data !== null) {
|
|
7306
|
+
const sanitized = {};
|
|
7307
|
+
const record = data;
|
|
7308
|
+
for (const key in record) {
|
|
7309
|
+
if (Object.prototype.hasOwnProperty.call(record, key)) {
|
|
7310
|
+
sanitized[key] = await sanitizeRecursive(record[key]);
|
|
7311
|
+
}
|
|
7312
|
+
}
|
|
7313
|
+
return sanitized;
|
|
7314
|
+
}
|
|
7315
|
+
return data;
|
|
7316
|
+
};
|
|
7317
|
+
const sanitizedData = await sanitizeRecursive(obj);
|
|
7318
|
+
return { sanitizedData, counts };
|
|
7319
|
+
}
|
|
7320
|
+
|
|
7321
|
+
// src/features/analysis/upload-file.ts
|
|
7322
|
+
import Debug7 from "debug";
|
|
7323
|
+
import fetch3, { File, fileFrom, FormData } from "node-fetch";
|
|
7324
|
+
var debug8 = Debug7("mobbdev:upload-file");
|
|
7325
|
+
async function uploadFile({
|
|
7326
|
+
file,
|
|
7327
|
+
url,
|
|
7328
|
+
uploadKey,
|
|
7329
|
+
uploadFields,
|
|
7330
|
+
logger
|
|
7331
|
+
}) {
|
|
7332
|
+
const logInfo = logger || ((_message, _data) => {
|
|
7333
|
+
});
|
|
7334
|
+
logInfo(`FileUpload: upload file start ${url}`);
|
|
7335
|
+
logInfo(`FileUpload: upload fields`, uploadFields);
|
|
7336
|
+
logInfo(`FileUpload: upload key ${uploadKey}`);
|
|
7337
|
+
debug8("upload file start %s", url);
|
|
7338
|
+
debug8("upload fields %o", uploadFields);
|
|
7339
|
+
debug8("upload key %s", uploadKey);
|
|
7340
|
+
const form = new FormData();
|
|
7341
|
+
Object.entries(uploadFields).forEach(([key, value]) => {
|
|
7342
|
+
form.append(key, value);
|
|
7343
|
+
});
|
|
7344
|
+
if (!form.has("key")) {
|
|
7345
|
+
form.append("key", uploadKey);
|
|
7346
|
+
}
|
|
7347
|
+
if (typeof file === "string") {
|
|
7348
|
+
debug8("upload file from path %s", file);
|
|
7349
|
+
logInfo(`FileUpload: upload file from path ${file}`);
|
|
7350
|
+
form.append("file", await fileFrom(file));
|
|
7351
|
+
} else {
|
|
7352
|
+
debug8("upload file from buffer");
|
|
7353
|
+
logInfo(`FileUpload: upload file from buffer`);
|
|
7354
|
+
form.append("file", new File([new Uint8Array(file)], "file"));
|
|
7355
|
+
}
|
|
7356
|
+
const agent = getProxyAgent(url);
|
|
7357
|
+
const response = await fetch3(url, {
|
|
7358
|
+
method: "POST",
|
|
7359
|
+
body: form,
|
|
7360
|
+
agent
|
|
7361
|
+
});
|
|
7362
|
+
if (!response.ok) {
|
|
7363
|
+
debug8("error from S3 %s %s", response.body, response.status);
|
|
7364
|
+
logInfo(`FileUpload: error from S3 ${response.body} ${response.status}`);
|
|
7365
|
+
throw new Error(`Failed to upload the file: ${response.status}`);
|
|
7366
|
+
}
|
|
7367
|
+
debug8("upload file done");
|
|
7368
|
+
logInfo(`FileUpload: upload file done`);
|
|
7369
|
+
}
|
|
7370
|
+
|
|
7371
|
+
// src/features/analysis/graphql/tracy-batch-upload.ts
|
|
7372
|
+
var gzipAsync = promisify(gzip);
|
|
7373
|
+
var debug9 = Debug8("mobbdev:tracy-batch-upload");
|
|
7374
|
+
var MAX_BATCH_PAYLOAD_BYTES = 3 * 1024 * 1024;
|
|
7375
|
+
|
|
7114
7376
|
// src/mcp/services/types.ts
|
|
7115
7377
|
function buildLoginUrl(baseUrl, loginId, hostname, context) {
|
|
7116
7378
|
const url = new URL(`${baseUrl}/${loginId}`);
|
|
@@ -7143,9 +7405,10 @@ function getConfigStore() {
|
|
|
7143
7405
|
var configStore = getConfigStore();
|
|
7144
7406
|
|
|
7145
7407
|
// src/commands/AuthManager.ts
|
|
7408
|
+
var debug10 = Debug9("mobbdev:auth");
|
|
7146
7409
|
var LOGIN_MAX_WAIT = 10 * 60 * 1e3;
|
|
7147
7410
|
var LOGIN_CHECK_DELAY = 5 * 1e3;
|
|
7148
|
-
var
|
|
7411
|
+
var _AuthManager = class _AuthManager {
|
|
7149
7412
|
constructor(webAppUrl, apiUrl) {
|
|
7150
7413
|
__publicField(this, "publicKey");
|
|
7151
7414
|
__publicField(this, "privateKey");
|
|
@@ -7167,7 +7430,7 @@ var AuthManager = class {
|
|
|
7167
7430
|
}
|
|
7168
7431
|
async waitForAuthentication() {
|
|
7169
7432
|
let newApiToken = null;
|
|
7170
|
-
for (let i = 0; i <
|
|
7433
|
+
for (let i = 0; i < _AuthManager.loginMaxWait / LOGIN_CHECK_DELAY; i++) {
|
|
7171
7434
|
newApiToken = await this.getApiToken();
|
|
7172
7435
|
if (newApiToken) {
|
|
7173
7436
|
break;
|
|
@@ -7197,6 +7460,9 @@ var AuthManager = class {
|
|
|
7197
7460
|
if (this.authenticated === null) {
|
|
7198
7461
|
const result = await this.checkAuthentication();
|
|
7199
7462
|
this.authenticated = result.isAuthenticated;
|
|
7463
|
+
if (!result.isAuthenticated) {
|
|
7464
|
+
debug10("isAuthenticated: false \u2014 %s", result.message);
|
|
7465
|
+
}
|
|
7200
7466
|
}
|
|
7201
7467
|
return this.authenticated;
|
|
7202
7468
|
}
|
|
@@ -7273,6 +7539,14 @@ var AuthManager = class {
|
|
|
7273
7539
|
}
|
|
7274
7540
|
return null;
|
|
7275
7541
|
}
|
|
7542
|
+
/**
|
|
7543
|
+
* Returns true if a non-empty API token is stored in the configStore.
|
|
7544
|
+
* Used for diagnostics — does NOT validate the token.
|
|
7545
|
+
*/
|
|
7546
|
+
hasStoredToken() {
|
|
7547
|
+
const token = configStore.get("apiToken");
|
|
7548
|
+
return typeof token === "string" && token.length > 0;
|
|
7549
|
+
}
|
|
7276
7550
|
/**
|
|
7277
7551
|
* Gets the current GQL client (if authenticated)
|
|
7278
7552
|
*/
|
|
@@ -7305,9 +7579,12 @@ var AuthManager = class {
|
|
|
7305
7579
|
this.currentBrowserUrl = null;
|
|
7306
7580
|
}
|
|
7307
7581
|
};
|
|
7582
|
+
/** Maximum time (ms) to wait for login authentication. Override in tests for faster failures. */
|
|
7583
|
+
__publicField(_AuthManager, "loginMaxWait", LOGIN_MAX_WAIT);
|
|
7584
|
+
var AuthManager = _AuthManager;
|
|
7308
7585
|
|
|
7309
7586
|
// src/commands/handleMobbLogin.ts
|
|
7310
|
-
var
|
|
7587
|
+
var debug11 = Debug10("mobbdev:commands");
|
|
7311
7588
|
var LOGIN_MAX_WAIT2 = 10 * 60 * 1e3;
|
|
7312
7589
|
var LOGIN_CHECK_DELAY2 = 5 * 1e3;
|
|
7313
7590
|
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(
|
|
@@ -7319,7 +7596,7 @@ async function getAuthenticatedGQLClient({
|
|
|
7319
7596
|
apiUrl,
|
|
7320
7597
|
webAppUrl
|
|
7321
7598
|
}) {
|
|
7322
|
-
|
|
7599
|
+
debug11(
|
|
7323
7600
|
"getAuthenticatedGQLClient called with: apiUrl=%s, webAppUrl=%s",
|
|
7324
7601
|
apiUrl || "undefined",
|
|
7325
7602
|
webAppUrl || "undefined"
|
|
@@ -7342,7 +7619,7 @@ async function handleMobbLogin({
|
|
|
7342
7619
|
webAppUrl,
|
|
7343
7620
|
loginContext
|
|
7344
7621
|
}) {
|
|
7345
|
-
|
|
7622
|
+
debug11(
|
|
7346
7623
|
"handleMobbLogin: resolved URLs - apiUrl=%s (from param: %s), webAppUrl=%s (from param: %s)",
|
|
7347
7624
|
apiUrl || "fallback",
|
|
7348
7625
|
apiUrl || "fallback",
|
|
@@ -7361,7 +7638,7 @@ async function handleMobbLogin({
|
|
|
7361
7638
|
return authManager.getGQLClient();
|
|
7362
7639
|
}
|
|
7363
7640
|
} catch (error) {
|
|
7364
|
-
|
|
7641
|
+
debug11("Authentication check failed:", error);
|
|
7365
7642
|
}
|
|
7366
7643
|
if (apiKey) {
|
|
7367
7644
|
createSpinner().start().error({
|
|
@@ -7412,56 +7689,6 @@ init_client_generates();
|
|
|
7412
7689
|
init_GitService();
|
|
7413
7690
|
init_urlParser2();
|
|
7414
7691
|
|
|
7415
|
-
// src/features/analysis/upload-file.ts
|
|
7416
|
-
import Debug8 from "debug";
|
|
7417
|
-
import fetch3, { File, fileFrom, FormData } from "node-fetch";
|
|
7418
|
-
var debug9 = Debug8("mobbdev:upload-file");
|
|
7419
|
-
async function uploadFile({
|
|
7420
|
-
file,
|
|
7421
|
-
url,
|
|
7422
|
-
uploadKey,
|
|
7423
|
-
uploadFields,
|
|
7424
|
-
logger
|
|
7425
|
-
}) {
|
|
7426
|
-
const logInfo = logger || ((_message, _data) => {
|
|
7427
|
-
});
|
|
7428
|
-
logInfo(`FileUpload: upload file start ${url}`);
|
|
7429
|
-
logInfo(`FileUpload: upload fields`, uploadFields);
|
|
7430
|
-
logInfo(`FileUpload: upload key ${uploadKey}`);
|
|
7431
|
-
debug9("upload file start %s", url);
|
|
7432
|
-
debug9("upload fields %o", uploadFields);
|
|
7433
|
-
debug9("upload key %s", uploadKey);
|
|
7434
|
-
const form = new FormData();
|
|
7435
|
-
Object.entries(uploadFields).forEach(([key, value]) => {
|
|
7436
|
-
form.append(key, value);
|
|
7437
|
-
});
|
|
7438
|
-
if (!form.has("key")) {
|
|
7439
|
-
form.append("key", uploadKey);
|
|
7440
|
-
}
|
|
7441
|
-
if (typeof file === "string") {
|
|
7442
|
-
debug9("upload file from path %s", file);
|
|
7443
|
-
logInfo(`FileUpload: upload file from path ${file}`);
|
|
7444
|
-
form.append("file", await fileFrom(file));
|
|
7445
|
-
} else {
|
|
7446
|
-
debug9("upload file from buffer");
|
|
7447
|
-
logInfo(`FileUpload: upload file from buffer`);
|
|
7448
|
-
form.append("file", new File([new Uint8Array(file)], "file"));
|
|
7449
|
-
}
|
|
7450
|
-
const agent = getProxyAgent(url);
|
|
7451
|
-
const response = await fetch3(url, {
|
|
7452
|
-
method: "POST",
|
|
7453
|
-
body: form,
|
|
7454
|
-
agent
|
|
7455
|
-
});
|
|
7456
|
-
if (!response.ok) {
|
|
7457
|
-
debug9("error from S3 %s %s", response.body, response.status);
|
|
7458
|
-
logInfo(`FileUpload: error from S3 ${response.body} ${response.status}`);
|
|
7459
|
-
throw new Error(`Failed to upload the file: ${response.status}`);
|
|
7460
|
-
}
|
|
7461
|
-
debug9("upload file done");
|
|
7462
|
-
logInfo(`FileUpload: upload file done`);
|
|
7463
|
-
}
|
|
7464
|
-
|
|
7465
7692
|
// src/utils/computerName.ts
|
|
7466
7693
|
import { execSync } from "child_process";
|
|
7467
7694
|
import os2 from "os";
|
|
@@ -7551,149 +7778,6 @@ function getStableComputerName() {
|
|
|
7551
7778
|
return currentName;
|
|
7552
7779
|
}
|
|
7553
7780
|
|
|
7554
|
-
// src/utils/sanitize-sensitive-data.ts
|
|
7555
|
-
import { OpenRedaction } from "@openredaction/openredaction";
|
|
7556
|
-
var openRedaction = new OpenRedaction({
|
|
7557
|
-
patterns: [
|
|
7558
|
-
// Core Personal Data
|
|
7559
|
-
// Removed EMAIL - causes false positives in code/test snippets (e.g. --author="Eve Author <eve@example.com>")
|
|
7560
|
-
// Prefer false negatives over false positives for this use case.
|
|
7561
|
-
"SSN",
|
|
7562
|
-
"NATIONAL_INSURANCE_UK",
|
|
7563
|
-
"DATE_OF_BIRTH",
|
|
7564
|
-
// Identity Documents
|
|
7565
|
-
"PASSPORT_UK",
|
|
7566
|
-
"PASSPORT_US",
|
|
7567
|
-
"PASSPORT_MRZ_TD1",
|
|
7568
|
-
"PASSPORT_MRZ_TD3",
|
|
7569
|
-
"DRIVING_LICENSE_UK",
|
|
7570
|
-
"DRIVING_LICENSE_US",
|
|
7571
|
-
"VISA_NUMBER",
|
|
7572
|
-
"VISA_MRZ",
|
|
7573
|
-
"TAX_ID",
|
|
7574
|
-
// Financial Data (removed SWIFT_BIC, CARD_AUTH_CODE - too broad, causing false positives with authentication words)
|
|
7575
|
-
// Removed CREDIT_CARD - causes false positives on zero-filled UUIDs (e.g. '00000000-0000-0000-0000-000000000000')
|
|
7576
|
-
// Prefer false negatives over false positives for this use case.
|
|
7577
|
-
"IBAN",
|
|
7578
|
-
"BANK_ACCOUNT_UK",
|
|
7579
|
-
"ROUTING_NUMBER_US",
|
|
7580
|
-
"CARD_TRACK1_DATA",
|
|
7581
|
-
"CARD_TRACK2_DATA",
|
|
7582
|
-
"CARD_EXPIRY",
|
|
7583
|
-
// Cryptocurrency (removed BITCOIN_ADDRESS - too broad, matches hash-like strings)
|
|
7584
|
-
"ETHEREUM_ADDRESS",
|
|
7585
|
-
"LITECOIN_ADDRESS",
|
|
7586
|
-
"CARDANO_ADDRESS",
|
|
7587
|
-
"SOLANA_ADDRESS",
|
|
7588
|
-
"MONERO_ADDRESS",
|
|
7589
|
-
"RIPPLE_ADDRESS",
|
|
7590
|
-
// Medical Data (removed PRESCRIPTION_NUMBER - too broad, matches words containing "ription")
|
|
7591
|
-
// Removed MEDICAL_RECORD_NUMBER - too broad, "MR" prefix matches "Merge Request" in SCM contexts (e.g. "MR branches" → "MR br****es")
|
|
7592
|
-
"NHS_NUMBER",
|
|
7593
|
-
"AUSTRALIAN_MEDICARE",
|
|
7594
|
-
"HEALTH_PLAN_NUMBER",
|
|
7595
|
-
"PATIENT_ID",
|
|
7596
|
-
// Communications (removed EMERGENCY_CONTACT, ADDRESS_PO_BOX, ZIP_CODE_US, PHONE_US, PHONE_INTERNATIONAL - too broad, causing false positives)
|
|
7597
|
-
"PHONE_UK",
|
|
7598
|
-
"PHONE_UK_MOBILE",
|
|
7599
|
-
"PHONE_LINE_NUMBER",
|
|
7600
|
-
"ADDRESS_STREET",
|
|
7601
|
-
"POSTCODE_UK",
|
|
7602
|
-
// Network & Technical
|
|
7603
|
-
"IPV4",
|
|
7604
|
-
"IPV6",
|
|
7605
|
-
"MAC_ADDRESS",
|
|
7606
|
-
"URL_WITH_AUTH",
|
|
7607
|
-
// Security Keys & Tokens
|
|
7608
|
-
"PRIVATE_KEY",
|
|
7609
|
-
"SSH_PRIVATE_KEY",
|
|
7610
|
-
"AWS_SECRET_KEY",
|
|
7611
|
-
"AWS_ACCESS_KEY",
|
|
7612
|
-
"AZURE_STORAGE_KEY",
|
|
7613
|
-
"GCP_SERVICE_ACCOUNT",
|
|
7614
|
-
"JWT_TOKEN",
|
|
7615
|
-
"OAUTH_TOKEN",
|
|
7616
|
-
"OAUTH_CLIENT_SECRET",
|
|
7617
|
-
"BEARER_TOKEN",
|
|
7618
|
-
"PAYMENT_TOKEN",
|
|
7619
|
-
"GENERIC_SECRET",
|
|
7620
|
-
"GENERIC_API_KEY",
|
|
7621
|
-
// Platform-Specific API Keys
|
|
7622
|
-
"GITHUB_TOKEN",
|
|
7623
|
-
"SLACK_TOKEN",
|
|
7624
|
-
"STRIPE_API_KEY",
|
|
7625
|
-
"GOOGLE_API_KEY",
|
|
7626
|
-
"FIREBASE_API_KEY",
|
|
7627
|
-
"HEROKU_API_KEY",
|
|
7628
|
-
"MAILGUN_API_KEY",
|
|
7629
|
-
"SENDGRID_API_KEY",
|
|
7630
|
-
"TWILIO_API_KEY",
|
|
7631
|
-
"NPM_TOKEN",
|
|
7632
|
-
"PYPI_TOKEN",
|
|
7633
|
-
"DOCKER_AUTH",
|
|
7634
|
-
"KUBERNETES_SECRET",
|
|
7635
|
-
// Government & Legal
|
|
7636
|
-
// Removed CLIENT_ID - too broad, "client" is ubiquitous in code (npm packages like @scope/client-*, class names like ClientSdkOptions)
|
|
7637
|
-
"POLICE_REPORT_NUMBER",
|
|
7638
|
-
"IMMIGRATION_NUMBER",
|
|
7639
|
-
"COURT_REPORTER_LICENSE"
|
|
7640
|
-
]
|
|
7641
|
-
});
|
|
7642
|
-
function maskString(str, showStart = 2, showEnd = 2) {
|
|
7643
|
-
if (str.length <= showStart + showEnd) {
|
|
7644
|
-
return "*".repeat(str.length);
|
|
7645
|
-
}
|
|
7646
|
-
return str.slice(0, showStart) + "*".repeat(str.length - showStart - showEnd) + str.slice(-showEnd);
|
|
7647
|
-
}
|
|
7648
|
-
async function sanitizeDataWithCounts(obj) {
|
|
7649
|
-
const counts = {
|
|
7650
|
-
detections: { total: 0, high: 0, medium: 0, low: 0 }
|
|
7651
|
-
};
|
|
7652
|
-
const sanitizeString = async (str) => {
|
|
7653
|
-
let result = str;
|
|
7654
|
-
const piiDetections = openRedaction.scan(str);
|
|
7655
|
-
if (piiDetections && piiDetections.total > 0) {
|
|
7656
|
-
const allDetections = [
|
|
7657
|
-
...piiDetections.high,
|
|
7658
|
-
...piiDetections.medium,
|
|
7659
|
-
...piiDetections.low
|
|
7660
|
-
];
|
|
7661
|
-
for (const detection of allDetections) {
|
|
7662
|
-
counts.detections.total++;
|
|
7663
|
-
if (detection.severity === "high") counts.detections.high++;
|
|
7664
|
-
else if (detection.severity === "medium") counts.detections.medium++;
|
|
7665
|
-
else if (detection.severity === "low") counts.detections.low++;
|
|
7666
|
-
const masked = maskString(detection.value);
|
|
7667
|
-
result = result.replaceAll(detection.value, masked);
|
|
7668
|
-
}
|
|
7669
|
-
}
|
|
7670
|
-
return result;
|
|
7671
|
-
};
|
|
7672
|
-
const sanitizeRecursive = async (data) => {
|
|
7673
|
-
if (typeof data === "string") {
|
|
7674
|
-
return sanitizeString(data);
|
|
7675
|
-
} else if (Array.isArray(data)) {
|
|
7676
|
-
return Promise.all(data.map((item) => sanitizeRecursive(item)));
|
|
7677
|
-
} else if (data instanceof Error) {
|
|
7678
|
-
return data;
|
|
7679
|
-
} else if (data instanceof Date) {
|
|
7680
|
-
return data;
|
|
7681
|
-
} else if (typeof data === "object" && data !== null) {
|
|
7682
|
-
const sanitized = {};
|
|
7683
|
-
const record = data;
|
|
7684
|
-
for (const key in record) {
|
|
7685
|
-
if (Object.prototype.hasOwnProperty.call(record, key)) {
|
|
7686
|
-
sanitized[key] = await sanitizeRecursive(record[key]);
|
|
7687
|
-
}
|
|
7688
|
-
}
|
|
7689
|
-
return sanitized;
|
|
7690
|
-
}
|
|
7691
|
-
return data;
|
|
7692
|
-
};
|
|
7693
|
-
const sanitizedData = await sanitizeRecursive(obj);
|
|
7694
|
-
return { sanitizedData, counts };
|
|
7695
|
-
}
|
|
7696
|
-
|
|
7697
7781
|
// src/args/commands/upload_ai_blame.ts
|
|
7698
7782
|
var defaultLogger = {
|
|
7699
7783
|
info: (msg, data) => {
|
|
@@ -8014,6 +8098,8 @@ async function uploadAiBlameCommandHandler(args) {
|
|
|
8014
8098
|
await uploadAiBlameHandler({ args });
|
|
8015
8099
|
}
|
|
8016
8100
|
export {
|
|
8101
|
+
getRepositoryUrl,
|
|
8102
|
+
getSystemInfo,
|
|
8017
8103
|
uploadAiBlameBuilder,
|
|
8018
8104
|
uploadAiBlameCommandHandler,
|
|
8019
8105
|
uploadAiBlameHandler,
|